diff options
Diffstat (limited to 'gpxe/src')
426 files changed, 45127 insertions, 13530 deletions
diff --git a/gpxe/src/Makefile b/gpxe/src/Makefile index 6c42da6a..147f6997 100644 --- a/gpxe/src/Makefile +++ b/gpxe/src/Makefile @@ -1,19 +1,17 @@ -# Location to place generated files +############################################################################### # -BIN := bin - -# Initialise variables that get added to throughout the various Makefiles +# Initialise various variables # -MAKEDEPS := Makefile .toolcheck .echocheck -SRCDIRS := -SRCS := -NON_AUTO_SRCS := -DRIVERS := -ROMS := -MEDIA := -NON_AUTO_MEDIA := -# Locations of utilities +CLEANUP := +CFLAGS := +ASFLAGS := +LDFLAGS := +MAKEDEPS := Makefile + +############################################################################### +# +# Locations of tools # HOST_CC := gcc RM := rm -f @@ -35,109 +33,20 @@ NM := $(CROSS_COMPILE)nm OBJDUMP := $(CROSS_COMPILE)objdump PARSEROM := $(PERL) ./util/parserom.pl MAKEROM := $(PERL) ./util/makerom.pl -MKCONFIG := $(PERL) ./util/mkconfig.pl SYMCHECK := $(PERL) ./util/symcheck.pl SORTOBJDUMP := $(PERL) ./util/sortobjdump.pl NRV2B := ./util/nrv2b ZBIN := ./util/zbin +ELF2EFI32 := ./util/elf2efi32 +ELF2EFI64 := ./util/elf2efi64 +EFIROM := ./util/efirom DOXYGEN := doxygen -# If invoked with no build target, print out a helpfully suggestive -# message. -# -noargs : blib $(BIN)/NIC $(BIN)/gpxe.dsk $(BIN)/gpxe.iso $(BIN)/gpxe.usb $(BIN)/undionly.kpxe - @$(ECHO) '===========================================================' - @$(ECHO) - @$(ECHO) 'To create a bootable floppy, type' - @$(ECHO) ' cat $(BIN)/gpxe.dsk > /dev/fd0' - @$(ECHO) 'where /dev/fd0 is your floppy drive. This will erase any' - @$(ECHO) 'data already on the disk.' - @$(ECHO) - @$(ECHO) 'To create a bootable USB key, type' - @$(ECHO) ' cat $(BIN)/gpxe.usb > /dev/sdX' - @$(ECHO) 'where /dev/sdX is your USB key, and is *not* a real hard' - @$(ECHO) 'disk on your system. This will erase any data already on' - @$(ECHO) 'the USB key.' - @$(ECHO) - @$(ECHO) 'To create a bootable CD-ROM, burn the ISO image ' - @$(ECHO) '$(BIN)/gpxe.iso to a blank CD-ROM.' - @$(ECHO) - @$(ECHO) 'These images contain drivers for all supported cards. You' - @$(ECHO) 'can build more customised images, and ROM images, using' - @$(ECHO) ' make bin/<rom-name>.<output-format>' - @$(ECHO) - @$(ECHO) '===========================================================' - -# If no architecture is specified in Config or on the command-line, -# use that of the build machine. -# -ARCH := $(shell uname -m | sed -e 's,i[3456789]86,i386,') - -# handle x86_64 like i386, but set -m32 option for 32bit code only -ifeq ($(ARCH),x86_64) -ARCH := i386 -CFLAGS += -m32 -ASFLAGS += --32 -LDFLAGS += -m elf_i386 -endif - -# Drag in architecture-specific Config -# -MAKEDEPS += arch/$(ARCH)/Config -include arch/$(ARCH)/Config - -# Common flags -# -CFLAGS += -I include -I arch/$(ARCH)/include -I . -DARCH=$(ARCH) -CFLAGS += -Os -ffreestanding -CFLAGS += -Wall -W -CFLAGS += -g -CFLAGS += $(EXTRA_CFLAGS) -ASFLAGS += $(EXTRA_ASFLAGS) -LDFLAGS += $(EXTRA_LDFLAGS) - -# Embedded image, if present +############################################################################### # -EMBEDDED_IMAGE = /dev/null - -ifneq ($(NO_WERROR),1) -CFLAGS += -Werror -endif - -# CFLAGS for specific object types -# -CFLAGS_c += -CFLAGS_S += -DASSEMBLY - -# Base object name of the current target -# -OBJECT = $(firstword $(subst ., ,$(@F))) - -# CFLAGS for specific object files. You can define -# e.g. CFLAGS_rtl8139, and have those flags automatically used when -# compiling bin/rtl8139.o. -# -OBJ_CFLAGS = $(CFLAGS_$(OBJECT)) -DOBJECT=$(subst -,_,$(OBJECT)) -$(BIN)/%.flags : - @$(ECHO) $(OBJ_CFLAGS) - -# Rules for specific object types. -# -COMPILE_c = $(CC) $(CFLAGS) $(CFLAGS_c) $(OBJ_CFLAGS) -RULE_c = $(Q)$(COMPILE_c) -c $< -o $@ -RULE_c_to_dbg%.o = $(Q)$(COMPILE_c) -Ddebug_$(OBJECT)=$* -c $< -o $@ -RULE_c_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_s = $(Q)$(PREPROCESS_S) $< > $@ - -DEBUG_TARGETS += dbg%.o c s - # SRCDIRS lists all directories containing source files. # +SRCDIRS := SRCDIRS += libgcc SRCDIRS += core SRCDIRS += proto @@ -151,7 +60,7 @@ SRCDIRS += drivers/block SRCDIRS += drivers/nvs SRCDIRS += drivers/bitbash SRCDIRS += drivers/infiniband -SRCDIRS += interface/pxe +SRCDIRS += interface/pxe interface/efi interface/smbios SRCDIRS += tests SRCDIRS += crypto crypto/axtls crypto/matrixssl SRCDIRS += hci hci/commands hci/tui @@ -161,25 +70,69 @@ SRCDIRS += usr # NON_AUTO_SRCS lists files that are excluded from the normal # automatic build system. # -NON_AUTO_SRCS += core/elf_loader.c +NON_AUTO_SRCS := NON_AUTO_SRCS += drivers/net/prism2.c -# Rules for finalising files. TGT_MAKEROM_FLAGS is defined as part of -# the automatic build system and varies by target; it includes the -# "-p 0x1234,0x5678" string to set the PCI IDs. +############################################################################### +# +# Default build target: build the most common targets and print out a +# helpfully suggestive message # -FINALISE_rom = $(MAKEROM) $(MAKEROM_FLAGS) $(TGT_MAKEROM_FLAGS) \ - -i$(IDENT) -s 0 $@ +all : bin/blib.a bin/gpxe.dsk bin/gpxe.iso bin/gpxe.usb bin/undionly.kpxe + @$(ECHO) '===========================================================' + @$(ECHO) + @$(ECHO) 'To create a bootable floppy, type' + @$(ECHO) ' cat bin/gpxe.dsk > /dev/fd0' + @$(ECHO) 'where /dev/fd0 is your floppy drive. This will erase any' + @$(ECHO) 'data already on the disk.' + @$(ECHO) + @$(ECHO) 'To create a bootable USB key, type' + @$(ECHO) ' cat bin/gpxe.usb > /dev/sdX' + @$(ECHO) 'where /dev/sdX is your USB key, and is *not* a real hard' + @$(ECHO) 'disk on your system. This will erase any data already on' + @$(ECHO) 'the USB key.' + @$(ECHO) + @$(ECHO) 'To create a bootable CD-ROM, burn the ISO image ' + @$(ECHO) 'bin/gpxe.iso to a blank CD-ROM.' + @$(ECHO) + @$(ECHO) 'These images contain drivers for all supported cards. You' + @$(ECHO) 'can build more customised images, and ROM images, using' + @$(ECHO) ' make bin/<rom-name>.<output-format>' + @$(ECHO) + @$(ECHO) '===========================================================' + +############################################################################### +# +# Build targets that do nothing but might be tried by users +# +configure : + @$(ECHO) "No configuration needed." + +install : + @$(ECHO) "No installation required." -# Some ROMs require specific flags to be passed to makerom.pl +############################################################################### # -MAKEROM_FLAGS_3c503 = -3 +# Version number calculations +# +VERSION_MAJOR = 0 +VERSION_MINOR = 9 +VERSION_PATCH = 6 +EXTRAVERSION = + +MM_VERSION = $(VERSION_MAJOR).$(VERSION_MINOR) +VERSION = $(MM_VERSION).$(VERSION_PATCH)$(EXTRAVERSION) +CFLAGS += -DVERSION_MAJOR=$(VERSION_MAJOR) \ + -DVERSION_MINOR=$(VERSION_MINOR) \ + -DVERSION_PATCH=$(VERSION_PATCH) \ + -DVERSION=\"$(VERSION)\" +IDENT = '$(@F) $(VERSION) (GPL) etherboot.org' +version : + @$(ECHO) $(VERSION) -# Drag in architecture-specific Makefile +############################################################################### +# +# Drag in the bulk of the build system # -MAKEDEPS += arch/$(ARCH)/Makefile -include arch/$(ARCH)/Makefile -# Drag in the automatic build system and other housekeeping functions MAKEDEPS += Makefile.housekeeping include Makefile.housekeeping diff --git a/gpxe/src/Makefile.housekeeping b/gpxe/src/Makefile.housekeeping index 9e11ceb4..2146d9cb 100644 --- a/gpxe/src/Makefile.housekeeping +++ b/gpxe/src/Makefile.housekeeping @@ -1,50 +1,10 @@ # -*- makefile -*- : Force emacs to use Makefile mode - +# # This file contains various boring housekeeping functions that would # otherwise seriously clutter up the main Makefile. -# Objects to be removed by "make clean" -# -CLEANUP := $(BIN)/*.* # *.* to avoid catching the "CVS" directory - -# Version number calculations -# -VERSION_MAJOR = 0 -VERSION_MINOR = 9 -VERSION_PATCH = 5 -EXTRAVERSION = -MM_VERSION = $(VERSION_MAJOR).$(VERSION_MINOR) -VERSION = $(MM_VERSION).$(VERSION_PATCH)$(EXTRAVERSION) -CFLAGS += -DVERSION_MAJOR=$(VERSION_MAJOR) \ - -DVERSION_MINOR=$(VERSION_MINOR) \ - -DVERSION=\"$(VERSION)\" -IDENT = '$(@F) $(VERSION) (GPL) etherboot.org' -version : - @$(ECHO) $(VERSION) - -configure : - @$(ECHO) "No configuration needed." - -install : - @$(ECHO) "No installation required. Generated images will be placed in the" $(BIN) "directory." - -# Check for tools that can cause failed builds +############################################################################### # -.toolcheck : Makefile - @if $(CC) -v 2>&1 | grep -is 'gcc version 2\.96' > /dev/null; then \ - $(ECHO) 'gcc 2.96 is unsuitable for compiling Etherboot'; \ - $(ECHO) 'Use gcc 2.95 or gcc 3.x instead'; \ - exit 1; \ - fi - @if [ `perl -e 'use bytes; print chr(255)' | wc -c` = 2 ]; then \ - $(ECHO) 'Your Perl version has a Unicode handling bug'; \ - $(ECHO) 'Execute this command before compiling Etherboot:'; \ - $(ECHO) 'export LANG=$${LANG%.UTF-8}'; \ - exit 1; \ - fi - @$(TOUCH) $@ -VERYCLEANUP += .toolcheck - # Find a usable "echo -e" substitute. # TAB := $(shell $(PRINTF) '\t') @@ -86,20 +46,51 @@ else @$(ECHO) "No usable \"echo -e\" substitute found" @exit 1 endif +MAKEDEPS += .echocheck VERYCLEANUP += .echocheck echo : @$(ECHO) "Using \"$(ECHO_E)\" for \"echo -e\"" -# Build verbosity +############################################################################### +# +# Determine host OS +# +HOST_OS := $(shell uname -s) +hostos : + @$(ECHO) $(HOST_OS) + +############################################################################### +# +# Check for tools that can cause failed builds +# +.toolcheck : + @if $(CC) -v 2>&1 | grep -is 'gcc version 2\.96' > /dev/null; then \ + $(ECHO) 'gcc 2.96 is unsuitable for compiling Etherboot'; \ + $(ECHO) 'Use gcc 2.95 or gcc 3.x instead'; \ + exit 1; \ + fi + @if [ `perl -e 'use bytes; print chr(255)' | wc -c` = 2 ]; then \ + $(ECHO) 'Your Perl version has a Unicode handling bug'; \ + $(ECHO) 'Execute this command before compiling Etherboot:'; \ + $(ECHO) 'export LANG=$${LANG%.UTF-8}'; \ + exit 1; \ + fi + @$(TOUCH) $@ +MAKEDEPS += .toolcheck +VERYCLEANUP += .toolcheck + +############################################################################### +# +# Check for various tool workarounds # -ifeq ($(V),1) -Q = -QM = @\# -else -Q = @ -QM = @ -endif + +# Make syntax does not allow use of comma or space in certain places. +# This ugly workaround is suggested in the manual. +# +COMMA := , +EMPTY := +SPACE := $(EMPTY) $(EMPTY) # Check for an old version of gas (binutils 2.9.1) # @@ -112,18 +103,154 @@ oldgas : # default, even when -ffreestanding is specified. We therefore need # to disable -fstack-protector if the compiler supports it. # -SP_TEST = $(CC) -fno-stack-protector -x c -E - < /dev/null >/dev/null 2>&1 +SP_TEST = $(CC) -fno-stack-protector -x c -c /dev/null \ + -o /dev/null >/dev/null 2>&1 SP_FLAGS := $(shell $(SP_TEST) && $(ECHO) '-fno-stack-protector') CFLAGS += $(SP_FLAGS) -# compiler.h is needed for our linking and debugging system +############################################################################### +# +# Build verbosity +# +ifeq ($(V),1) +Q := +QM := @\# +else +Q := @ +QM := @ +endif + +############################################################################### +# +# Set BIN according to whatever was specified on the command line as +# the build target. +# + +# Determine how many different BIN directories are mentioned in the +# make goals. +# +BIN_GOALS := $(filter bin/% bin-%,$(MAKECMDGOALS)) +BIN_GOAL_BINS := $(foreach BG,$(BIN_GOALS),$(firstword $(subst /, ,$(BG)))) +NUM_BINS := $(words $(sort $(BIN_GOAL_BINS))) + +ifeq ($(NUM_BINS),0) + +# No BIN directory was specified. Set BIN to "bin" as a sensible +# default. + +BIN := bin + +else # NUM_BINS == 0 + +ifeq ($(NUM_BINS),1) + +# If exactly one BIN directory was specified, set BIN to match this +# directory. +# +BIN := $(firstword $(BIN_GOAL_BINS)) + +else # NUM_BINS == 1 + +# More than one BIN directory was specified. We cannot handle the +# latter case within a single make invocation, so set up recursive +# targets for each BIN directory. +# +# Leave $(BIN) undefined. This has implications for any target that +# depends on $(BIN); such targets should be made conditional upon the +# existence of $(BIN). # -CFLAGS += -include compiler.h +$(BIN_GOALS) : % : BIN_RECURSE + $(Q)$(MAKE) --no-print-directory BIN=$(firstword $(subst /, ,$@)) $@ +.PHONY : BIN_RECURSE + +endif # NUM_BINS == 1 +endif # NUM_BINS == 0 + +ifdef BIN + +# Create $(BIN) directory if it doesn't exist yet +# +ifeq ($(wildcard $(BIN)),) +$(shell $(MKDIR) -p $(BIN)) +endif + +# Target to allow e.g. "make bin-efi arch" +# +$(BIN) : + @# Do nothing, silently +.PHONY : $(BIN) + +# Remove everything in $(BIN) for a "make clean" +# +CLEANUP += $(BIN)/*.* # Avoid picking up directories + +endif # defined(BIN) + +# Determine whether or not we need to include the dependency files +# +NO_DEP_TARGETS := $(BIN) clean veryclean +ifeq ($(MAKECMDGOALS),) +NEED_DEPS := 1 +endif +ifneq ($(strip $(filter-out $(NO_DEP_TARGETS),$(MAKECMDGOALS))),) +NEED_DEPS := 1 +endif + +############################################################################### +# +# Select build architecture and platform based on $(BIN) +# +# BIN has the form bin[-[arch-]platform] + +ARCHS := $(patsubst arch/%,%,$(wildcard arch/*)) +PLATFORMS := $(patsubst config/defaults/%.h,%,\ + $(wildcard config/defaults/*.h)) +archs : + @$(ECHO) $(ARCHS) + +platforms : + @$(ECHO) $(PLATFORMS) + +ifdef BIN + +# Determine architecture portion of $(BIN), if present +BIN_ARCH := $(strip $(foreach A,$(ARCHS),\ + $(patsubst bin-$(A)-%,$(A),\ + $(filter bin-$(A)-%,$(BIN))))) -# config/%.h files are generated from config.h using mkconfig.pl -config/%.h : config*.h - $(MKCONFIG) config.h -CLEANUP += config/*.h +# Determine platform portion of $(BIN), if present +ifeq ($(BIN_ARCH),) +BIN_PLATFORM := $(patsubst bin-%,%,$(filter bin-%,$(BIN))) +else +BIN_PLATFORM := $(patsubst bin-$(BIN_ARCH)-%,%,$(BIN)) +endif + +# Determine build architecture +DEFAULT_ARCH := i386 +ARCH := $(firstword $(BIN_ARCH) $(DEFAULT_ARCH)) +CFLAGS += -DARCH=$(ARCH) +arch : + @$(ECHO) $(ARCH) +.PHONY : arch + +# Determine build platform +DEFAULT_PLATFORM := pcbios +PLATFORM := $(firstword $(BIN_PLATFORM) $(DEFAULT_PLATFORM)) +CFLAGS += -DPLATFORM=$(PLATFORM) +platform : + @$(ECHO) $(PLATFORM) + +endif # defined(BIN) + +# Include architecture-specific Makefile +ifdef ARCH +MAKEDEPS += arch/$(ARCH)/Makefile +include arch/$(ARCH)/Makefile +endif + +############################################################################### +# +# Source file handling # SRCDIRS lists all directories containing source files. srcdirs : @@ -144,6 +271,68 @@ AUTO_SRCS = $(filter-out $(NON_AUTO_SRCS),$(SRCS)) autosrcs : @$(ECHO) $(AUTO_SRCS) +# Just about everything else in this section depends upon having +# $(BIN) set + +ifdef BIN + +# Common flags +# +CFLAGS += -I include -I arch/$(ARCH)/include -I . +CFLAGS += -Os -ffreestanding +CFLAGS += -Wall -W -Wformat-nonliteral +CFLAGS += -g +CFLAGS += $(EXTRA_CFLAGS) +ASFLAGS += $(EXTRA_ASFLAGS) +LDFLAGS += $(EXTRA_LDFLAGS) + +# Embedded image(s), or default if not set +# +EMBEDDED_IMAGE = image/default.gpxe + +# Inhibit -Werror if NO_WERROR is specified on make command line +# +ifneq ($(NO_WERROR),1) +CFLAGS += -Werror +ASFLAGS += --fatal-warnings +endif + +# compiler.h is needed for our linking and debugging system +# +CFLAGS += -include compiler.h + +# CFLAGS for specific object types +# +CFLAGS_c += +CFLAGS_S += -DASSEMBLY + +# Base object name of the current target +# +OBJECT = $(firstword $(subst ., ,$(@F))) + +# CFLAGS for specific object files. You can define +# e.g. CFLAGS_rtl8139, and have those flags automatically used when +# compiling bin/rtl8139.o. +# +OBJ_CFLAGS = $(CFLAGS_$(OBJECT)) -DOBJECT=$(subst -,_,$(OBJECT)) +$(BIN)/%.flags : + @$(ECHO) $(OBJ_CFLAGS) + +# Rules for specific object types. +# +COMPILE_c = $(CC) $(CFLAGS) $(CFLAGS_c) $(OBJ_CFLAGS) +RULE_c = $(Q)$(COMPILE_c) -c $< -o $@ +RULE_c_to_dbg%.o = $(Q)$(COMPILE_c) -Ddebug_$(OBJECT)=$* -c $< -o $@ +RULE_c_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_s = $(Q)$(PREPROCESS_S) $< > $@ + +DEBUG_TARGETS += dbg%.o c s + # 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. @@ -157,7 +346,7 @@ autosrcs : # define src_template - @$(ECHO) "Generating Makefile rules for $(1)" + @$(ECHO) " [DEPS] $(1)" @$(MKDIR) -p $(dir $(2)) @$(RM) $(2) @$(TOUCH) $(2) @@ -182,13 +371,13 @@ define obj_template -Wno-error -MM $(1) -MT "$(4)_DEPS" -MG -MP | \ sed 's/_DEPS\s*:/_DEPS =/' >> $(2) @$(ECHO_E) '\n$$(BIN)/$(4).o : $(1) $$(MAKEDEPS) $$($(4)_DEPS)' \ - '\n\t$$(QM)$(ECHO) " [BUILD] $$@"\n' \ + '\n\t$$(QM)$(ECHO) " [BUILD] $$@"' \ '\n\t$$(RULE_$(3))\n' \ '\nBOBJS += $$(BIN)/$(4).o\n' \ $(foreach TGT,$(DEBUG_TARGETS), \ $(if $(RULE_$(3)_to_$(TGT)), \ '\n$$(BIN)/$(4).$(TGT) : $(1) $$(MAKEDEPS) $$($(4)_DEPS)' \ - '\n\t$$(QM)$(ECHO) " [BUILD] $$@"\n' \ + '\n\t$$(QM)$(ECHO) " [BUILD] $$@"' \ '\n\t$$(RULE_$(3)_to_$(TGT))\n' \ '\n$(TGT)_OBJS += $$(BIN)/$(4).$(TGT)\n' ) ) \ '\n$(2) : $$($(4)_DEPS)\n' \ @@ -205,7 +394,11 @@ $(BIN)/deps/%.d : % $(MAKEDEPS) $(PARSEROM) # Calculate and include the list of Makefile rules files # AUTO_DEPS = $(patsubst %,$(BIN)/deps/%.d,$(AUTO_SRCS)) +ifdef NEED_DEPS +ifneq ($(AUTO_DEPS),) -include $(AUTO_DEPS) +endif +endif autodeps : @$(ECHO) $(AUTO_DEPS) VERYCLEANUP += $(BIN)/deps @@ -220,13 +413,31 @@ drivers : roms : @$(ECHO) $(ROMS) -# Embedded binary -$(BIN)/embedimg.bin: $(EMBEDDED_IMAGE) - $(QM)$(ECHO) " [COPY] $@" - $(Q)$(CP) -f $(EMBEDDED_IMAGE) $@ +# List of embedded images included in the last build of embedded.o. +# This is needed in order to correctly rebuild embedded.o whenever the +# list of objects changes. +# +EMBEDDED_LIST := $(BIN)/.embedded.list +ifeq ($(wildcard $(EMBEDDED_LIST)),) +EMBEDDED_LIST_IMAGE := +else +EMBEDDED_LIST_IMAGE := $(shell cat $(EMBEDDED_LIST)) +endif +ifneq ($(EMBEDDED_LIST_IMAGE),$(EMBEDDED_IMAGE)) +$(shell $(ECHO) "$(EMBEDDED_IMAGE)" > $(EMBEDDED_LIST)) +endif + +$(EMBEDDED_LIST) : + +VERYCLEANUP += $(EMBEDDED_LIST) -$(BIN)/embed.o: $(BIN)/embedimg.bin -CFLAGS_embed = -DEMBEDIMG=\"$(BIN)/embedimg.bin\" +EMBEDDED_FILES := $(subst $(COMMA), ,$(EMBEDDED_IMAGE)) +EMBED_ALL := $(foreach i,$(shell seq 1 $(words $(EMBEDDED_FILES))),\ + EMBED ( $(i), \"$(word $(i), $(EMBEDDED_FILES))\",\ + \"$(notdir $(word $(i),$(EMBEDDED_FILES)))\" )) + +$(BIN)/embedded.o : $(EMBEDDED_FILES) $(EMBEDDED_LIST) +CFLAGS_embedded = -DEMBED_ALL="$(EMBED_ALL)" # Generate the NIC file from the parsed source files. The NIC file is # only for rom-o-matic. @@ -237,7 +448,7 @@ $(BIN)/NIC : $(AUTO_DEPS) 'it is only for rom-o-matic' >> $@ @$(ECHO) >> $@ @perl -ne 'chomp; print "$$1\n" if /\# NIC\t(.*)$$/' $^ >> $@ -CLEANUP += $(BIN)/NIC +CLEANUP += $(BIN)/NIC # Doesn't match the $(BIN)/*.* pattern # Analyse a target name (e.g. "bin/dfe538--prism2_pci.zrom.tmp") and # derive the variables: @@ -305,7 +516,6 @@ TGT_MAKEROM_FLAGS = $(strip $(MAKEROM_FLAGS_$(TGT_ROM_NAME)) \ # Calculate list of debugging versions of objects to be included in # the target. # -COMMA := , DEBUG_LIST = $(subst $(COMMA), ,$(DEBUG)) DEBUG_OBJ_LEVEL = $(firstword $(word 2,$(subst :, ,$(1))) 1) DEBUG_OBJ_BASE = $(word 1,$(subst :, ,$(1))).dbg$(call DEBUG_OBJ_LEVEL,$(1)) @@ -342,8 +552,13 @@ $(BIN)/%.info : # in order to correctly rebuild blib whenever the list of objects # changes. # -BLIB_LIST = $(BIN)/.blib.list -ifneq ($(shell cat $(BLIB_LIST)),$(BLIB_OBJS)) +BLIB_LIST := $(BIN)/.blib.list +ifeq ($(wildcard $(BLIB_LIST)),) +BLIB_LIST_OBJS := +else +BLIB_LIST_OBJS := $(shell cat $(BLIB_LIST)) +endif +ifneq ($(BLIB_LIST_OBJS),$(BLIB_OBJS)) $(shell $(ECHO) "$(BLIB_OBJS)" > $(BLIB_LIST)) endif @@ -396,10 +611,6 @@ $(BIN)/%.zbin : $(BIN)/%.bin $(BIN)/%.zinfo $(ZBIN) $(QM)$(ECHO) " [ZBIN] $@" $(Q)$(ZBIN) $(BIN)/$*.bin $(BIN)/$*.zinfo > $@ -# Build bochs symbol table -$(BIN)/%.bxs : $(BIN)/%.tmp - $(NM) $< | cut -d" " -f1,3 > $@ - # Rules for each media format. These are generated and placed in an # external Makefile fragment. We could do this via $(eval ...), but # that would require make >= 3.80. @@ -435,7 +646,7 @@ automedia : # define media_template - @$(ECHO) "Generating Makefile rules for $(1) media" + @$(ECHO) " [MEDIADEPS] $(1)" @$(MKDIR) -p $(dir $(2)) @$(RM) $(2) @$(TOUCH) $(2) @@ -459,7 +670,20 @@ $(BIN)/deps/%.media.d : $(MAKEDEPS) MEDIA_DEPS = $(patsubst %,$(BIN)/deps/%.media.d,$(AUTO_MEDIA)) mediadeps : @$(ECHO) $(MEDIA_DEPS) +ifdef NEED_DEPS +ifneq ($(MEDIA_DEPS),) -include $(MEDIA_DEPS) +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 # @@ -472,15 +696,23 @@ allpxes allisos alldsks : all%s : $(foreach DRIVER,$(DRIVERS),$(BIN)/$(DRIVER).% $(BIN)/etherboot.% : $(BIN)/gpxe.% ln -sf $(notdir $<) $@ -# Wrap up binary blobs +endif # defined(BIN) + +############################################################################### # -$(BIN)/%.o : payload/%.img - $(QM)echo " [WRAP] $@" - $(Q)$(LD) -b binary -r -o $@ $< --undefined obj_payload \ - --defsym obj_$*=0 +# Rules for finalising files. TGT_MAKEROM_FLAGS is defined as part of +# the automatic build system and varies by target; it includes the +# "-p 0x1234,0x5678" string to set the PCI IDs. +# +FINALISE_rom = $(MAKEROM) $(MAKEROM_FLAGS) $(TGT_MAKEROM_FLAGS) \ + -i$(IDENT) -s 0 $@ -BOBJS += $(patsubst payload/%.img,$(BIN)/%.o,$(wildcard payload/*.img)) +# Some ROMs require specific flags to be passed to makerom.pl +# +MAKEROM_FLAGS_3c503 = -3 +############################################################################### +# # The compression utilities # $(NRV2B) : util/nrv2b.c $(MAKEDEPS) @@ -494,6 +726,29 @@ $(ZBIN) : util/zbin.c util/nrv2b.c $(MAKEDEPS) $(Q)$(HOST_CC) -O2 -o $@ $< CLEANUP += $(ZBIN) +############################################################################### +# +# The EFI image converter +# +$(ELF2EFI32) : util/elf2efi.c $(MAKEDEPS) + $(QM)$(ECHO) " [HOSTCC] $@" + $(Q)$(HOST_CC) -DMDE_CPU_IA32 -idirafter include -O2 \ + -o $@ $< -lbfd -liberty +CLEANUP += $(ELF2EFI32) + +$(ELF2EFI64) : util/elf2efi.c $(MAKEDEPS) + $(QM)$(ECHO) " [HOSTCC] $@" + $(Q)$(HOST_CC) -DMDE_CPU_X64 -idirafter include -O2 \ + -o $@ $< -lbfd -liberty +CLEANUP += $(ELF2EFI64) + +$(EFIROM) : util/efirom.c $(MAKEDEPS) + $(QM)$(ECHO) " [HOSTCC] $@" + $(Q)$(HOST_CC) -idirafter include -O2 -o $@ $< +CLEANUP += $(EFIROM) + +############################################################################### +# # Auto-incrementing build serial number. Append "bs" to your list of # build targets to get a serial number printed at the end of the # build. Enable -DBUILD_SERIAL in order to see it when the code runs. @@ -517,27 +772,30 @@ bs : $(BUILDSERIAL_NOW) @$(ECHO) $$(( $(shell cat $<) + 1 )) > $(BUILDSERIAL_NEXT) @$(ECHO) "Build serial number is $(shell cat $<)" -# List of available architectures +############################################################################### # -ARCHS = $(filter-out CVS,$(patsubst arch/%,%,$(wildcard arch/*))) -archs : - @$(ECHO) $(ARCHS) +# Build the TAGS file(s) for emacs +# +TAGS : + ctags -e -R -f $@ --exclude=bin -OTHER_ARCHS = $(filter-out $(ARCH),$(ARCHS)) -otherarchs : - @$(ECHO) $(OTHER_ARCHS) +CLEANUP += TAGS -# Build the TAGS file for emacs +############################################################################### # -TAGS : TAGS.$(ARCH) - -TAGS.$(ARCH) : - ctags -e -R -f $@ --exclude=bin \ - $(foreach ARCH,$(OTHER_ARCHS),--exclude=arch/$(ARCH)) -CLEANUP += TAGS* +# Force rebuild for any given target +# +%.rebuild : + rm -f $* + $(Q)$(MAKE) $* +############################################################################### +# # Symbol table checks # + +ifdef BIN + SYMTAB = $(BIN)/symtab $(SYMTAB) : $(BLIB) $(OBJDUMP) -w -t $< > $@ @@ -547,14 +805,27 @@ CLEANUP += $(BIN)/symtab symcheck : $(SYMTAB) $(SYMCHECK) $< -# Force rebuild for any given target +endif # defined(BIN) + +############################################################################### +# +# Build bochs symbol table # -$(BIN)/%.rebuild : - rm -f $(BIN)/$* - $(MAKE) $(MAKEFLAGS) $(BIN)/$* +ifdef BIN + +$(BIN)/%.bxs : $(BIN)/%.tmp + $(NM) $< | cut -d" " -f1,3 > $@ + +endif # defined(BIN) + +############################################################################### +# # Documentation # + +ifdef BIN + $(BIN)/doxygen.cfg : doxygen.cfg $(MAKEDEPS) $(PERL) -pe 's{\@SRCDIRS\@}{$(SRCDIRS)}; ' \ -e 's{\@BIN\@}{$(BIN)}; ' \ @@ -578,6 +849,10 @@ docview : $(ECHO) "Documentation index in $(BIN)/doc/html/index.html" ; \ fi +endif # defined(BIN) + +############################################################################### +# # Clean-up # clean : @@ -585,19 +860,3 @@ clean : veryclean : clean $(RM) -r $(VERYCLEANUP) - -# Make clean tarballs for release - -tarball : ../VERSION - ($(ECHO) -n $(VERSION) ''; date -u +'%Y-%m-%d') > ../VERSION - $(RM) -r /tmp/$(USER)/gpxe-$(VERSION) - mkdir -p /tmp/$(USER)/gpxe-$(VERSION) - cp -rP .. /tmp/$(USER)/gpxe-$(VERSION) - ( cd /tmp/$(USER)/gpxe-$(VERSION)/src ; $(MAKE) veryclean ; $(RM) -r bin/deps ) - ( cd /tmp/$(USER); tar cf /tmp/$(USER)/gpxe-$(VERSION).tar --exclude ".git*" --exclude "#*" \ - --exclude "*~" gpxe-$(VERSION) ) - bzip2 -9 < /tmp/$(USER)/gpxe-$(VERSION).tar > /tmp/$(USER)/gpxe-$(VERSION).tar.bz2 - gzip -9 < /tmp/$(USER)/gpxe-$(VERSION).tar > /tmp/$(USER)/gpxe-$(VERSION).tar.gz - $(RM) -r /tmp/$(USER)/gpxe-$(VERSION) - $(RM) /tmp/$(USER)/gpxe-$(VERSION).tar - ( cd /tmp/$(USER) ; tar -zxf /tmp/$(USER)/gpxe-$(VERSION).tar.gz ) diff --git a/gpxe/src/arch/i386/Config b/gpxe/src/arch/i386/Config deleted file mode 100644 index 1c086ecc..00000000 --- a/gpxe/src/arch/i386/Config +++ /dev/null @@ -1,148 +0,0 @@ -# -*- makefile -*- - -############################################################################## -############################################################################## -# -# IMPORTANT! -# -# The use of this file to set options that affect only single object -# files is deprecated, because changing anything in this file results -# in a complete rebuild, which is slow. All options are gradually -# being migrated to config.h, which does not suffer from this problem. -# -# Only options that affect the entire build (e.g. overriding the $(CC) -# Makefile variable) should be placed in here. -# -############################################################################## -############################################################################## - - -# Config for i386 Etherboot -# -# Do not delete the tag OptionDescription and /OptionDescription -# It is used to automatically generate the documentation. -# -# @OptionDescrition@ -# -# BIOS interface options: -# -# -DPCBIOS -# Compile in support for the normal pcbios -# -DLINUXBIOS -# Compile in support for LinuxBIOS -# -DBBS_BUT_NOT_PNP_COMPLIANT -# Some BIOSes claim to be PNP but they don't conform -# to the BBS spec which specifies that ES:DI must -# point to the string $PnP on entry. This option -# works around those. This option must be added to -# LCONFIG. -# -DNO_DELAYED_INT -# Take control as soon as BIOS detects the ROM. -# Normally hooks onto INT18H or INT19H. Use only if you -# have a very non-conformant BIOS as it bypasses -# BIOS initialisation of devices. This only works for -# legacy ROMs, i.e. PCI_PNP_HEADER not defined. -# This option was formerly called NOINT19H. -# -DBOOT_INT18H -# Etherboot normally hooks onto INT19H for legacy ROMs. -# You can choose to hook onto INT18H (BASIC interpreter -# entry point) instead. This entry point is used when -# all boot devices have been exhausted. This option must -# be added to LCONFIG. -# -DCONFIG_PCI_DIRECT -# Define this for PCI BIOSes that do not implement -# BIOS32 or not correctly. Normally not needed. -# Only works for BIOSes of a certain era. -# -DCONFIG_TSC_CURRTICKS -# Uses the processor time stamp counter instead of reading -# the BIOS time counter. This allows Etherboot to work -# even without a BIOS. This only works on late model -# 486s and above. -# -DCONFIG_NO_TIMER2 -# Some systems do not have timer2 implemented. -# If you have a RTC this will allow you to roughly calibrate -# it using outb instructions. -# -# Extended cpu options - -# -DCONFIG_X86_64 -# Compile in support for booting x86_64 64bit binaries. -# -# PXE loader options: -# -# -DPXELOADER_KEEP_ALL -# Prevent PXE loader (prefix) from unloading the -# PXE stack. You will want to use this if, for -# example, you are booting via PXE-on-floppy. -# You may want to use it under certain -# circumstances when using the Etherboot UNDI -# driver; these are complex and best practice is -# not yet established. -# -# Obscure options you probably don't need to touch: -# -# -DIGNORE_E820_MAP -# Ignore the memory map returned by the E820 BIOS -# call. May be necessary on some buggy BIOSes. -# -DT503_AUI -# Use AUI by default on 3c503 cards. -# -DFLATTEN_REAL_MODE -# Use 4GB segment limits when calling out to or -# returning to real-mode code. This is necessary to -# work around some buggy code (e.g. OpenBSD's pxeboot) -# that uses flat real-mode without being sufficiently -# paranoid about the volatility of its segment limits. - -# -# @/OptionDescription@ - -# BIOS select don't change unless you know what you are doing -# CFLAGS+= -DPCBIOS - -# Compile in k8/hammer support -# CFLAGS+= -DCONFIG_X86_64 - -# Options to make a version of Etherboot that will work under linuxBIOS. -# CFLAGS+= -DLINUXBIOS -DCONFIG_TSC_CURRTICKS -DCONSOLE_SERIAL -DCOMCONSOLE=0x3f8 -DCOMPRESERVE -DCONFIG_PCI_DIRECT -DELF_IMAGE - -# These options affect the loader that is prepended to the Etherboot image -# LCONFIG+= -DBBS_BUT_NOT_PNP_COMPLIANT -# LCONFIG+= -DBOOT_INT18H - -# Produce code that will work with OpenBSD's pxeboot -# CFLAGS+= -DFLATTEN_REAL_MODE - -CFLAGS+= -fstrength-reduce -fomit-frame-pointer -march=i386 -# Squeeze the code in as little space as possible. -# gcc3 needs a different syntax to gcc2 if you want to avoid spurious warnings. -GCC_VERSION = $(subst ., ,$(shell $(CC) -dumpversion)) -GCC_MAJORVERSION = $(firstword $(GCC_VERSION)) -ifeq ($(GCC_MAJORVERSION),2) -CFLAGS+= -malign-jumps=1 -malign-loops=1 -malign-functions=1 -else -CFLAGS+= -falign-jumps=1 -falign-loops=1 -falign-functions=1 -endif - -# this is almost always a win. the kernel uses it, too. -CFLAGS+= -mpreferred-stack-boundary=2 - -# use regparm for all functions - C functions called from assembly (or -# vice versa) need __cdecl now -CFLAGS+= -mregparm=3 - -# use -mrtd (same __cdecl requirements as above) -CFLAGS+= -mrtd - -# this is the logical complement to -mregparm=3. -# it doesn't currently buy us anything, but if anything ever tries -# to return small structures, let's be prepared -CFLAGS+= -freg-struct-return - -LDFLAGS+= -N --no-check-sections - -ifeq "$(shell uname -s)" "FreeBSD" -CFLAGS+= -DIMAGE_FREEBSD -DELF_IMAGE -DAOUT_IMAGE -endif - -# An alternate location for isolinux.bin can be set here -# ISOLINUX_BIN=/path/to/isolinux.bin diff --git a/gpxe/src/arch/i386/Makefile b/gpxe/src/arch/i386/Makefile index 97ca0774..1392bbac 100644 --- a/gpxe/src/arch/i386/Makefile +++ b/gpxe/src/arch/i386/Makefile @@ -1,3 +1,59 @@ +# Force i386-only instructions +# +CFLAGS += -march=i386 + +# Code size reduction. +# +CFLAGS += -fstrength-reduce -fomit-frame-pointer + +# Code size reduction. gcc3 needs a different syntax to gcc2 if you +# want to avoid spurious warnings. +# +GCC_VERSION := $(subst ., ,$(shell $(CC) -dumpversion)) +GCC_MAJOR := $(firstword $(GCC_VERSION)) +ifeq ($(GCC_MAJOR),2) +CFLAGS += -malign-jumps=1 -malign-loops=1 -malign-functions=1 +else +CFLAGS += -falign-jumps=1 -falign-loops=1 -falign-functions=1 +endif + +# Code size reduction. This is almost always a win. The kernel uses it, too. +# +CFLAGS += -mpreferred-stack-boundary=2 + +# Code size reduction. Use regparm for all functions - C functions +# called from assembly (or vice versa) need __asmcall now +# +CFLAGS += -mregparm=3 + +# Code size reduction. Use -mrtd (same __asmcall requirements as above) +CFLAGS += -mrtd + +# Code size reduction. This is the logical complement to -mregparm=3. +# It doesn't currently buy us anything, but if anything ever tries to +# return small structures, let's be prepared +# +CFLAGS += -freg-struct-return + +# Force 32-bit code even on an x86-64 machine +# +CFLAGS += -m32 +ASFLAGS += --32 +ifeq ($(HOST_OS),FreeBSD) +LDFLAGS += -m elf_i386_fbsd +else +LDFLAGS += -m elf_i386 +endif + +# EFI requires -fshort-wchar, and nothing else currently uses wchar_t +# +CFLAGS += -fshort-wchar + +# We need to undefine the default macro "i386" when compiling .S +# files, otherwise ".arch i386" translates to ".arch 1"... +# +CFLAGS += -Ui386 + # Locations of utilities # ISOLINUX_BIN = /usr/lib/syslinux/isolinux.bin @@ -22,85 +78,37 @@ NON_AUTO_SRCS += arch/i386/core/wince_loader.c # unnrv2b.S is used to generate a 16-bit as well as a 32-bit object. # -OBJS_unnrv2b = unnrv2b unnrv2b16 -CFLAGS_unnrv2b16 = -DCODE16 +OBJS_unnrv2b = unnrv2b unnrv2b16 +CFLAGS_unnrv2b16 = -DCODE16 -# We need to undefine the default macro "i386" when compiling .S -# files, otherwise ".arch i386" translates to ".arch 1"... +# Include common x86 Makefile +# +MAKEDEPS += arch/x86/Makefile +include arch/x86/Makefile + +# Include platform-specific Makefile # -CFLAGS_S += -Ui386 - -# The i386 linker script -# -LDSCRIPT = arch/i386/scripts/i386.lds - -# Media types. -# -MEDIA += rom -MEDIA += pxe -MEDIA += kpxe -MEDIA += elf -MEDIA += elfd -MEDIA += lmelf -MEDIA += lmelfd -MEDIA += lkrn -MEDIA += bImage -MEDIA += dsk -MEDIA += nbi -MEDIA += hd -MEDIA += raw -MEDIA += com -MEDIA += exe - -# Special target for building Master Boot Record binary -$(BIN)/mbr.bin : $(BIN)/mbr.o - $(OBJCOPY) -O binary $< $@ +MAKEDEPS += arch/i386/Makefile.$(PLATFORM) +include arch/i386/Makefile.$(PLATFORM) # Some suffixes (e.g. %.fd0) are generated directly from other # finished files (e.g. %.dsk), rather than having their own prefix. # rule to write disk images to /dev/fd0 -NON_AUTO_MEDIA += fd0 +NON_AUTO_MEDIA += fd0 %fd0 : %dsk - dd if=$< bs=512 conv=sync of=/dev/fd0 - sync + $(QM)$(ECHO) " [DD] $@" + $(Q)dd if=$< bs=512 conv=sync of=/dev/fd0 + $(Q)sync # rule to create padded disk images -NON_AUTO_MEDIA += pdsk +NON_AUTO_MEDIA += pdsk %pdsk : %dsk - cp $< $@ - $(PERL) ./util/dskpad.pl $@ - -# rule to make a non-emulation ISO boot image -NON_AUTO_MEDIA += iso -%iso: %lkrn util/geniso - ISOLINUX_BIN=$(ISOLINUX_BIN) bash util/geniso $@ $< - -# rule to make a floppy emulation ISO boot image -NON_AUTO_MEDIA += liso -%liso: %lkrn util/genliso - bash util/genliso $@ $< - -# rule to make a USB disk image -$(BIN)/usbdisk.bin : $(BIN)/usbdisk.o - $(OBJCOPY) -O binary $< $@ - -NON_AUTO_MEDIA += usb -%usb: $(BIN)/usbdisk.bin %hd - cat $^ > $@ + $(QM)$(ECHO) " [DSKPAD] $@" + $(Q)cp $< $@ + $(Q)$(PERL) ./util/dskpad.pl $@ # Add NON_AUTO_MEDIA to the media list, so that they show up in the # output of "make" # MEDIA += $(NON_AUTO_MEDIA) - -# Shortcut to allow typing just -# make bin-kir/% -# rather than -# make -f arch/i386/kir-Makefile bin-kir/% -# for building a KEEP_IT_REAL flavour. -# -$(BIN)-kir/% : kir-target - $(MAKE) -f arch/i386/kir-Makefile $(MAKECMDGOALS) - -.PHONY : kir-target diff --git a/gpxe/src/arch/i386/Makefile.efi b/gpxe/src/arch/i386/Makefile.efi new file mode 100644 index 00000000..8d651b04 --- /dev/null +++ b/gpxe/src/arch/i386/Makefile.efi @@ -0,0 +1,10 @@ +# -*- makefile -*- : Force emacs to use Makefile mode + +# Specify EFI image builder +# +ELF2EFI = $(ELF2EFI32) + +# Include generic EFI Makefile +# +MAKEDEPS += arch/x86/Makefile.efi +include arch/x86/Makefile.efi diff --git a/gpxe/src/arch/i386/Makefile.pcbios b/gpxe/src/arch/i386/Makefile.pcbios new file mode 100644 index 00000000..64b3dac2 --- /dev/null +++ b/gpxe/src/arch/i386/Makefile.pcbios @@ -0,0 +1,55 @@ +# -*- makefile -*- : Force emacs to use Makefile mode + +# The i386 linker script +# +LDSCRIPT = arch/i386/scripts/i386.lds + +# Stop ld from complaining about our customised linker script +# +LDFLAGS += -N --no-check-sections + +# Media types. +# +MEDIA += rom +MEDIA += pxe +MEDIA += kpxe +MEDIA += kkpxe +MEDIA += elf +MEDIA += elfd +MEDIA += lmelf +MEDIA += lmelfd +MEDIA += lkrn +MEDIA += bImage +MEDIA += dsk +MEDIA += nbi +MEDIA += hd +MEDIA += raw +MEDIA += com +MEDIA += exe + +# rule to make a non-emulation ISO boot image +NON_AUTO_MEDIA += iso +%iso: %lkrn util/geniso + $(QM)$(ECHO) " [GENISO] $@" + $(Q)ISOLINUX_BIN=$(ISOLINUX_BIN) bash util/geniso $@ $< + +# rule to make a floppy emulation ISO boot image +NON_AUTO_MEDIA += liso +%liso: %lkrn util/genliso + $(QM)$(ECHO) " [GENLISO] $@" + $(Q)bash util/genliso $@ $< + +# Special target for building Master Boot Record binary +$(BIN)/mbr.bin : $(BIN)/mbr.o + $(QM)$(ECHO) " [OBJCOPY] $@" + $(Q)$(OBJCOPY) -O binary $< $@ + +# rule to make a USB disk image +$(BIN)/usbdisk.bin : $(BIN)/usbdisk.o + $(QM)$(ECHO) " [OBJCOPY] $@" + $(Q)$(OBJCOPY) -O binary $< $@ + +NON_AUTO_MEDIA += usb +%usb: $(BIN)/usbdisk.bin %hd + $(QM)$(ECHO) " [FINISH] $@" + $(Q)cat $^ > $@ diff --git a/gpxe/src/arch/i386/core/dumpregs.c b/gpxe/src/arch/i386/core/dumpregs.c index 89426d58..82dc2184 100644 --- a/gpxe/src/arch/i386/core/dumpregs.c +++ b/gpxe/src/arch/i386/core/dumpregs.c @@ -1,7 +1,7 @@ #include <stdio.h> #include <realmode.h> -void __cdecl _dump_regs ( struct i386_all_regs *ix86 ) { +void __asmcall _dump_regs ( struct i386_all_regs *ix86 ) { __asm__ __volatile__ ( TEXT16_CODE ( ".globl dump_regs\n\t" @@ -12,8 +12,8 @@ void __cdecl _dump_regs ( struct i386_all_regs *ix86 ) { "addr32 leal 4(%%esp), %%esp\n\t" "ret\n\t" ) : : ); - printf ( "EAX=%08lx EBX=%08lx ECX=%08lx EDX=%08lx\n" - "ESI=%08lx EDI=%08lx EBP=%08lx ESP=%08lx\n" + printf ( "EAX=%08x EBX=%08x ECX=%08x EDX=%08x\n" + "ESI=%08x EDI=%08x EBP=%08x ESP=%08x\n" "CS=%04x SS=%04x DS=%04x ES=%04x FS=%04x GS=%04x\n", ix86->regs.eax, ix86->regs.ebx, ix86->regs.ecx, ix86->regs.edx, ix86->regs.esi, ix86->regs.edi, diff --git a/gpxe/src/arch/i386/core/gdbidt.S b/gpxe/src/arch/i386/core/gdbidt.S index 860f7b01..cd8b38a9 100644 --- a/gpxe/src/arch/i386/core/gdbidt.S +++ b/gpxe/src/arch/i386/core/gdbidt.S @@ -2,7 +2,7 @@ * Interrupt Descriptor Table (IDT) setup and interrupt handlers for GDB stub. */ -#include <virtaddr.h> +#include <librm.h> #define SIZEOF_I386_REGS 32 #define SIZEOF_I386_FLAGS 4 @@ -11,7 +11,7 @@ * Interrupt Descriptor Table **************************************************************************** */ - .section ".data16" + .section ".data16", "aw", @progbits .globl idtr idtr: idt_limit: @@ -68,7 +68,7 @@ idt_fixed: * Destroys %ax, %bx, and %di. **************************************************************************** */ - .section ".text16" + .section ".text16", "ax", @progbits .code16 .globl idt_init idt_init: @@ -100,7 +100,7 @@ idt_init: * Interrupt handlers **************************************************************************** */ - .section ".text" + .section ".text", "ax", @progbits .code32 /* POSIX signal numbers for reporting traps to GDB */ diff --git a/gpxe/src/arch/i386/core/gdbmach.c b/gpxe/src/arch/i386/core/gdbmach.c index 5e72e4d0..97827ecb 100644 --- a/gpxe/src/arch/i386/core/gdbmach.c +++ b/gpxe/src/arch/i386/core/gdbmach.c @@ -19,7 +19,7 @@ #include <stddef.h> #include <stdio.h> #include <assert.h> -#include <virtaddr.h> +#include <gpxe/uaccess.h> #include <gpxe/gdbstub.h> #include <gdbmach.h> @@ -142,7 +142,7 @@ static void gdbmach_enable_hwbps ( void ) { __asm__ __volatile__ ( "movl %0, %%dr7\n" : : "r" ( dr7 ) ); } -__cdecl void gdbmach_handler ( int signo, gdbreg_t *regs ) { +__asmcall void gdbmach_handler ( int signo, gdbreg_t *regs ) { gdbmach_disable_hwbps(); gdbstub_handler ( signo, regs ); gdbmach_enable_hwbps(); diff --git a/gpxe/src/arch/i386/core/nap.c b/gpxe/src/arch/i386/core/nap.c deleted file mode 100644 index 12bb5699..00000000 --- a/gpxe/src/arch/i386/core/nap.c +++ /dev/null @@ -1,12 +0,0 @@ - -#include <realmode.h> -#include <bios.h> - -/************************************************************************** - * Save power by halting the CPU until the next interrupt - **************************************************************************/ -void cpu_nap ( void ) { - __asm__ __volatile__ ( REAL_CODE ( "sti\n\t" - "hlt\n\t" - "cli\n\t" ) : : ); -} diff --git a/gpxe/src/arch/i386/core/pic8259.c b/gpxe/src/arch/i386/core/pic8259.c index defe2e7d..8a0433dd 100644 --- a/gpxe/src/arch/i386/core/pic8259.c +++ b/gpxe/src/arch/i386/core/pic8259.c @@ -16,6 +16,7 @@ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ +#include <gpxe/io.h> #include <pic8259.h> /** @file diff --git a/gpxe/src/arch/i386/core/rdtsc_timer.c b/gpxe/src/arch/i386/core/rdtsc_timer.c new file mode 100644 index 00000000..443c8ada --- /dev/null +++ b/gpxe/src/arch/i386/core/rdtsc_timer.c @@ -0,0 +1,87 @@ +/* + * 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., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +/** @file + * + * RDTSC timer + * + */ + +#include <assert.h> +#include <gpxe/timer.h> +#include <gpxe/timer2.h> + +/** + * Number of TSC ticks per microsecond + * + * This is calibrated on the first use of the timer. + */ +static unsigned long rdtsc_ticks_per_usec; + +/** + * Delay for a fixed number of microseconds + * + * @v usecs Number of microseconds for which to delay + */ +static void rdtsc_udelay ( unsigned long usecs ) { + unsigned long start; + unsigned long elapsed; + + /* Sanity guard, since we may divide by this */ + if ( ! usecs ) + usecs = 1; + + start = currticks(); + if ( rdtsc_ticks_per_usec ) { + /* Already calibrated; busy-wait until done */ + do { + elapsed = ( currticks() - start ); + } while ( elapsed < ( usecs * rdtsc_ticks_per_usec ) ); + } else { + /* Not yet calibrated; use timer2 and calibrate + * based on result. + */ + timer2_udelay ( usecs ); + elapsed = ( currticks() - start ); + rdtsc_ticks_per_usec = ( elapsed / usecs ); + DBG ( "RDTSC timer calibrated: %ld ticks in %ld usecs " + "(%ld MHz)\n", elapsed, usecs, + ( rdtsc_ticks_per_usec << TSC_SHIFT ) ); + } +} + +/** + * Get number of ticks per second + * + * @ret ticks_per_sec Number of ticks per second + */ +static unsigned long rdtsc_ticks_per_sec ( void ) { + + /* Calibrate timer, if not already done */ + if ( ! rdtsc_ticks_per_usec ) + udelay ( 1 ); + + /* Sanity check */ + assert ( rdtsc_ticks_per_usec != 0 ); + + return ( rdtsc_ticks_per_usec * 1000 * 1000 ); +} + +PROVIDE_TIMER ( rdtsc, udelay, rdtsc_udelay ); +PROVIDE_TIMER_INLINE ( rdtsc, currticks ); +PROVIDE_TIMER ( rdtsc, ticks_per_sec, rdtsc_ticks_per_sec ); diff --git a/gpxe/src/arch/i386/core/relocate.c b/gpxe/src/arch/i386/core/relocate.c index aa58ad65..bdc8498e 100644 --- a/gpxe/src/arch/i386/core/relocate.c +++ b/gpxe/src/arch/i386/core/relocate.c @@ -1,4 +1,4 @@ -#include <io.h> +#include <gpxe/io.h> #include <registers.h> #include <gpxe/memmap.h> @@ -18,8 +18,8 @@ extern char _max_align[]; #define max_align ( ( unsigned int ) _max_align ) /* Linker symbols */ -extern char _text[]; -extern char _end[]; +extern char _textdata[]; +extern char _etextdata[]; /* within 1MB of 4GB is too close. * MAX_ADDR is the maximum address we can easily do DMA to. @@ -39,7 +39,7 @@ extern char _end[]; * address space, and returns the physical address of the new location * to the prefix in %edi. */ -__cdecl void relocate ( struct i386_all_regs *ix86 ) { +__asmcall void relocate ( struct i386_all_regs *ix86 ) { struct memory_map memmap; unsigned long start, end, size, padded_size; unsigned long new_start, new_end; @@ -47,8 +47,8 @@ __cdecl void relocate ( struct i386_all_regs *ix86 ) { /* Get memory map and current location */ get_memmap ( &memmap ); - start = virt_to_phys ( _text ); - end = virt_to_phys ( _end ); + start = virt_to_phys ( _textdata ); + end = virt_to_phys ( _etextdata ); size = ( end - start ); padded_size = ( size + max_align - 1 ); diff --git a/gpxe/src/arch/i386/core/stack.S b/gpxe/src/arch/i386/core/stack.S index c2d138aa..da66d239 100644 --- a/gpxe/src/arch/i386/core/stack.S +++ b/gpxe/src/arch/i386/core/stack.S @@ -4,7 +4,7 @@ * Internal stack **************************************************************************** */ - .section ".stack" + .section ".stack", "aw", @nobits .align 8 .globl _stack _stack: diff --git a/gpxe/src/arch/i386/core/stack16.S b/gpxe/src/arch/i386/core/stack16.S index 3380a083..d1251f06 100644 --- a/gpxe/src/arch/i386/core/stack16.S +++ b/gpxe/src/arch/i386/core/stack16.S @@ -4,7 +4,7 @@ * Internal stack **************************************************************************** */ - .section ".stack16" + .section ".stack16", "aw", @nobits .align 8 .globl _stack16 _stack16: diff --git a/gpxe/src/arch/i386/core/start32.S b/gpxe/src/arch/i386/core/start32.S deleted file mode 100644 index 37ef5eb9..00000000 --- a/gpxe/src/arch/i386/core/start32.S +++ /dev/null @@ -1,325 +0,0 @@ -#include "virtaddr.h" - - .equ MSR_K6_EFER, 0xC0000080 - .equ EFER_LME, 0x00000100 - .equ X86_CR4_PAE, 0x00000020 - .equ CR0_PG, 0x80000000 - -#ifdef GAS291 -#define DATA32 data32; -#define ADDR32 addr32; -#define LJMPI(x) ljmp x -#else -#define DATA32 data32 -#define ADDR32 addr32 -/* newer GAS295 require #define LJMPI(x) ljmp *x */ -#define LJMPI(x) ljmp x -#endif - -/* - * NOTE: if you write a subroutine that is called from C code (gcc/egcs), - * then you only have to take care of %ebx, %esi, %edi and %ebp. These - * registers must not be altered under any circumstance. All other registers - * may be clobbered without any negative side effects. If you don't follow - * this rule then you'll run into strange effects that only occur on some - * gcc versions (because the register allocator may use different registers). - * - * All the data32 prefixes for the ljmp instructions are necessary, because - * the assembler emits code with a relocation address of 0. This means that - * all destinations are initially negative, which the assembler doesn't grok, - * because for some reason negative numbers don't fit into 16 bits. The addr32 - * prefixes are there for the same reasons, because otherwise the memory - * references are only 16 bit wide. Theoretically they are all superfluous. - * One last note about prefixes: the data32 prefixes on all call _real_to_prot - * instructions could be removed if the _real_to_prot function is changed to - * deal correctly with 16 bit return addresses. I tried it, but failed. - */ - - .text - .arch i386 - .code32 - - /* This is a struct os_entry_regs */ - .globl os_regs -os_regs: .space 56 - -/************************************************************************** -XSTART32 - Transfer control to the kernel just loaded -**************************************************************************/ - .globl xstart32 -xstart32: - /* Save the callee save registers */ - movl %ebp, os_regs + 32 - movl %esi, os_regs + 36 - movl %edi, os_regs + 40 - movl %ebx, os_regs + 44 - - /* save the return address */ - popl %eax - movl %eax, os_regs + 48 - - /* save the stack pointer */ - movl %esp, os_regs + 52 - - /* Get the new destination address */ - popl %ecx - - /* Store the physical address of xend on the stack */ - movl $xend32, %ebx - addl virt_offset, %ebx - pushl %ebx - - /* Store the destination address on the stack */ - pushl $PHYSICAL_CS - pushl %ecx - - /* Cache virt_offset */ - movl virt_offset, %ebp - - /* Switch to using physical addresses */ - call _virt_to_phys - - /* Save the target stack pointer */ - movl %esp, os_regs + 12(%ebp) - leal os_regs(%ebp), %esp - - /* Store the pointer to os_regs */ - movl %esp, os_regs_ptr(%ebp) - - /* Load my new registers */ - popal - movl (-32 + 12)(%esp), %esp - - /* Jump to the new kernel - * The lret switches to a flat code segment - */ - lret - - .balign 4 - .globl xend32 -xend32: - /* Fixup %eflags */ - nop - cli - cld - - /* Load %esp with &os_regs + virt_offset */ - .byte 0xbc /* movl $0, %esp */ -os_regs_ptr: - .long 0 - - /* Save the result registers */ - addl $32, %esp - pushal - - /* Compute virt_offset */ - movl %esp, %ebp - subl $os_regs, %ebp - - /* Load the stack pointer and convert it to physical address */ - movl 52(%esp), %esp - addl %ebp, %esp - - /* Enable the virtual addresses */ - leal _phys_to_virt(%ebp), %eax - call *%eax - - /* Restore the callee save registers */ - movl os_regs + 32, %ebp - movl os_regs + 36, %esi - movl os_regs + 40, %edi - movl os_regs + 44, %ebx - movl os_regs + 48, %edx - movl os_regs + 52, %esp - - /* Get the C return value */ - movl os_regs + 28, %eax - - jmpl *%edx - -#ifdef CONFIG_X86_64 - .arch sledgehammer -/************************************************************************** -XSTART_lm - Transfer control to the kernel just loaded in long mode -**************************************************************************/ - .globl xstart_lm -xstart_lm: - /* Save the callee save registers */ - pushl %ebp - pushl %esi - pushl %edi - pushl %ebx - - /* Cache virt_offset && (virt_offset & 0xfffff000) */ - movl virt_offset, %ebp - movl %ebp, %ebx - andl $0xfffff000, %ebx - - /* Switch to using physical addresses */ - call _virt_to_phys - - /* Initialize the page tables */ - /* Level 4 */ - leal 0x23 + pgt_level3(%ebx), %eax - leal pgt_level4(%ebx), %edi - movl %eax, (%edi) - - /* Level 3 */ - leal 0x23 + pgt_level2(%ebx), %eax - leal pgt_level3(%ebx), %edi - movl %eax, 0x00(%edi) - addl $4096, %eax - movl %eax, 0x08(%edi) - addl $4096, %eax - movl %eax, 0x10(%edi) - addl $4096, %eax - movl %eax, 0x18(%edi) - - /* Level 2 */ - movl $0xe3, %eax - leal pgt_level2(%ebx), %edi - leal 16384(%edi), %esi -pgt_level2_loop: - movl %eax, (%edi) - addl $8, %edi - addl $0x200000, %eax - cmp %esi, %edi - jne pgt_level2_loop - - /* Point at the x86_64 page tables */ - leal pgt_level4(%ebx), %edi - movl %edi, %cr3 - - - /* Setup for the return from 64bit mode */ - /* 64bit align the stack */ - movl %esp, %ebx /* original stack pointer + 16 */ - andl $0xfffffff8, %esp - - /* Save original stack pointer + 16 */ - pushl %ebx - - /* Save virt_offset */ - pushl %ebp - - /* Setup for the jmp to 64bit long mode */ - leal start_lm(%ebp), %eax - movl %eax, 0x00 + start_lm_addr(%ebp) - movl $LM_CODE_SEG, %eax - movl %eax, 0x04 + start_lm_addr(%ebp) - - /* Setup for the jump out of 64bit long mode */ - leal end_lm(%ebp), %eax - movl %eax, 0x00 + end_lm_addr(%ebp) - movl $FLAT_CODE_SEG, %eax - movl %eax, 0x04 + end_lm_addr(%ebp) - - /* Enable PAE mode */ - movl %cr4, %eax - orl $X86_CR4_PAE, %eax - movl %eax, %cr4 - - /* Enable long mode */ - movl $MSR_K6_EFER, %ecx - rdmsr - orl $EFER_LME, %eax - wrmsr - - /* Start paging, entering 32bit compatiblity mode */ - movl %cr0, %eax - orl $CR0_PG, %eax - movl %eax, %cr0 - - /* Enter 64bit long mode */ - ljmp *start_lm_addr(%ebp) - .code64 -start_lm: - /* Load 64bit data segments */ - movl $LM_DATA_SEG, %eax - movl %eax, %ds - movl %eax, %es - movl %eax, %ss - - andq $0xffffffff, %rbx - /* Get the address to jump to */ - movl 20(%rbx), %edx - andq $0xffffffff, %rdx - - /* Get the argument pointer */ - movl 24(%rbx), %ebx - andq $0xffffffff, %rbx - - /* Jump to the 64bit code */ - call *%rdx - - /* Preserve the result */ - movl %eax, %edx - - /* Fixup %eflags */ - cli - cld - - /* Switch to 32bit compatibility mode */ - ljmp *end_lm_addr(%rip) - - .code32 -end_lm: - /* Disable paging */ - movl %cr0, %eax - andl $~CR0_PG, %eax - movl %eax, %cr0 - - /* Disable long mode */ - movl $MSR_K6_EFER, %ecx - rdmsr - andl $~EFER_LME, %eax - wrmsr - - /* Disable PAE */ - movl %cr4, %eax - andl $~X86_CR4_PAE, %eax - movl %eax, %cr4 - - /* Compute virt_offset */ - popl %ebp - - /* Compute the original stack pointer + 16 */ - popl %ebx - movl %ebx, %esp - - /* Enable the virtual addresses */ - leal _phys_to_virt(%ebp), %eax - call *%eax - - /* Restore the callee save registers */ - popl %ebx - popl %esi - popl %edi - popl %ebp - - /* Get the C return value */ - movl %edx, %eax - - /* Return */ - ret - - .arch i386 -#endif /* CONFIG_X86_64 */ - -#ifdef CONFIG_X86_64 - .section ".bss" - .p2align 12 - /* Include a dummy space in case we are loaded badly aligned */ - .space 4096 - /* Reserve enough space for a page table convering 4GB with 2MB pages */ -pgt_level4: - .space 4096 -pgt_level3: - .space 4096 -pgt_level2: - .space 16384 -start_lm_addr: - .space 8 -end_lm_addr: - .space 8 -#endif diff --git a/gpxe/src/arch/i386/core/i386_timer.c b/gpxe/src/arch/i386/core/timer2.c index 8f90ae05..bb589ecc 100644 --- a/gpxe/src/arch/i386/core/i386_timer.c +++ b/gpxe/src/arch/i386/core/timer2.c @@ -12,12 +12,11 @@ */ #include <stddef.h> -#include <bits/timer2.h> -#include <gpxe/timer.h> -#include <io.h> +#include <gpxe/timer2.h> +#include <gpxe/io.h> /* Timers tick over at this rate */ -#define TIMER2_TICK_RATE 1193180U +#define TIMER2_TICKS_PER_SEC 1193180U /* Parallel Peripheral Controller Port B */ #define PPC_PORTB 0x61 @@ -52,8 +51,7 @@ #define BINARY_COUNT 0x00 #define BCD_COUNT 0x01 -static void load_timer2(unsigned int ticks) -{ +static void load_timer2 ( unsigned int ticks ) { /* * Now let's take care of PPC channel 2 * @@ -75,15 +73,13 @@ static void load_timer2(unsigned int ticks) outb(ticks >> 8, TIMER2_PORT); } -static int timer2_running(void) -{ +static int timer2_running ( void ) { return ((inb(PPC_PORTB) & PPCB_T2OUT) == 0); } -void i386_timer2_udelay(unsigned int usecs) -{ - load_timer2((usecs * TIMER2_TICK_RATE)/USECS_IN_SEC); - while (timer2_running()) - ; +void timer2_udelay ( unsigned long usecs ) { + load_timer2 ( ( usecs * TIMER2_TICKS_PER_SEC ) / ( 1000 * 1000 ) ); + while (timer2_running()) { + /* Do nothing */ + } } - diff --git a/gpxe/src/arch/i386/core/video_subr.c b/gpxe/src/arch/i386/core/video_subr.c index bf82cc61..c821cd02 100644 --- a/gpxe/src/arch/i386/core/video_subr.c +++ b/gpxe/src/arch/i386/core/video_subr.c @@ -7,7 +7,7 @@ #include "stddef.h" #include "string.h" -#include "io.h" +#include <gpxe/io.h> #include "console.h" #include <gpxe/init.h> #include "vga.h" diff --git a/gpxe/src/arch/i386/core/virtaddr.S b/gpxe/src/arch/i386/core/virtaddr.S index 5d762375..cf6da4f6 100644 --- a/gpxe/src/arch/i386/core/virtaddr.S +++ b/gpxe/src/arch/i386/core/virtaddr.S @@ -4,7 +4,7 @@ * */ -#include "virtaddr.h" +#include "librm.h" .arch i386 .text diff --git a/gpxe/src/arch/i386/core/x86_io.c b/gpxe/src/arch/i386/core/x86_io.c new file mode 100644 index 00000000..424a96cc --- /dev/null +++ b/gpxe/src/arch/i386/core/x86_io.c @@ -0,0 +1,94 @@ +/* + * 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., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +#include <gpxe/io.h> +#include <gpxe/x86_io.h> + +/** @file + * + * gPXE I/O API for x86 + * + */ + +/** + * Read 64-bit qword from memory-mapped device + * + * @v io_addr I/O address + * @ret data Value read + * + * This routine uses MMX instructions. + */ +static uint64_t x86_readq ( volatile uint64_t *io_addr ) { + uint64_t data; + __asm__ __volatile__ ( "pushl %%edx\n\t" + "pushl %%eax\n\t" + "movq (%1), %%mm0\n\t" + "movq %%mm0, (%%esp)\n\t" + "popl %%eax\n\t" + "popl %%edx\n\t" + "emms\n\t" + : "=A" ( data ) : "r" ( io_addr ) ); + return data; +} + +/** + * Write 64-bit qword to memory-mapped device + * + * @v data Value to write + * @v io_addr I/O address + * + * This routine uses MMX instructions. + */ +static void x86_writeq ( uint64_t data, volatile uint64_t *io_addr ) { + __asm__ __volatile__ ( "pushl %%edx\n\t" + "pushl %%eax\n\t" + "movq (%%esp), %%mm0\n\t" + "movq %%mm0, (%1)\n\t" + "popl %%eax\n\t" + "popl %%edx\n\t" + "emms\n\t" + : : "A" ( data ), "r" ( io_addr ) ); +} + +PROVIDE_IOAPI_INLINE ( x86, phys_to_bus ); +PROVIDE_IOAPI_INLINE ( x86, bus_to_phys ); +PROVIDE_IOAPI_INLINE ( x86, ioremap ); +PROVIDE_IOAPI_INLINE ( x86, iounmap ); +PROVIDE_IOAPI_INLINE ( x86, io_to_bus ); +PROVIDE_IOAPI_INLINE ( x86, readb ); +PROVIDE_IOAPI_INLINE ( x86, readw ); +PROVIDE_IOAPI_INLINE ( x86, readl ); +PROVIDE_IOAPI ( x86, readq, x86_readq ); +PROVIDE_IOAPI_INLINE ( x86, writeb ); +PROVIDE_IOAPI_INLINE ( x86, writew ); +PROVIDE_IOAPI_INLINE ( x86, writel ); +PROVIDE_IOAPI ( x86, writeq, x86_writeq ); +PROVIDE_IOAPI_INLINE ( x86, inb ); +PROVIDE_IOAPI_INLINE ( x86, inw ); +PROVIDE_IOAPI_INLINE ( x86, inl ); +PROVIDE_IOAPI_INLINE ( x86, outb ); +PROVIDE_IOAPI_INLINE ( x86, outw ); +PROVIDE_IOAPI_INLINE ( x86, outl ); +PROVIDE_IOAPI_INLINE ( x86, insb ); +PROVIDE_IOAPI_INLINE ( x86, insw ); +PROVIDE_IOAPI_INLINE ( x86, insl ); +PROVIDE_IOAPI_INLINE ( x86, outsb ); +PROVIDE_IOAPI_INLINE ( x86, outsw ); +PROVIDE_IOAPI_INLINE ( x86, outsl ); +PROVIDE_IOAPI_INLINE ( x86, iodelay ); +PROVIDE_IOAPI_INLINE ( x86, mb ); diff --git a/gpxe/src/arch/i386/drivers/net/undiisr.S b/gpxe/src/arch/i386/drivers/net/undiisr.S index a6c6c381..2b31b414 100644 --- a/gpxe/src/arch/i386/drivers/net/undiisr.S +++ b/gpxe/src/arch/i386/drivers/net/undiisr.S @@ -10,11 +10,9 @@ .text .arch i386 - .section ".text16", "ax", @progbits - .section ".data16", "aw", @progbits .code16 - .section ".text16" + .section ".text16", "ax", @progbits .globl undiisr undiisr: @@ -75,7 +73,7 @@ exit: /* Restore registers and return */ popw %ds iret - .section ".data16" + .section ".data16", "aw", @progbits undinet_params: status: .word 0 funcflag: .word 0 diff --git a/gpxe/src/arch/i386/drivers/net/undinet.c b/gpxe/src/arch/i386/drivers/net/undinet.c index 9576ad60..d6db6f7c 100644 --- a/gpxe/src/arch/i386/drivers/net/undinet.c +++ b/gpxe/src/arch/i386/drivers/net/undinet.c @@ -23,6 +23,7 @@ #include <biosint.h> #include <pnpbios.h> #include <basemem_packet.h> +#include <gpxe/io.h> #include <gpxe/iobuf.h> #include <gpxe/netdevice.h> #include <gpxe/if_ether.h> @@ -481,8 +482,7 @@ static void undinet_poll ( struct net_device *netdev ) { undi_isr.Frame.offset, frag_len ); if ( iob_len ( iobuf ) == len ) { /* Whole packet received; deliver it */ - netdev_rx ( netdev, iobuf ); - iobuf = NULL; + netdev_rx ( netdev, iob_disown ( iobuf ) ); /* Etherboot 5.4 fails to return all packets * under mild load; pretend it retriggered. */ @@ -554,7 +554,7 @@ static int undinet_open ( struct net_device *netdev ) { DBGC ( undinic, "UNDINIC %p opened\n", undinic ); return 0; -err: + err: undinet_close ( netdev ); return rc; } @@ -595,10 +595,6 @@ static void undinet_close ( struct net_device *netdev ) { /* Disable interrupt and unhook ISR */ disable_irq ( undinic->irq ); undinet_unhook_isr ( undinic->irq ); -#if 0 - enable_irq ( undinic->irq ); - send_eoi ( undinic->irq ); -#endif DBGC ( undinic, "UNDINIC %p closed\n", undinic ); } @@ -642,9 +638,7 @@ int undinet_probe ( struct undi_device *undi ) { struct s_PXENV_UNDI_GET_IFACE_INFO undi_iface; struct s_PXENV_UNDI_SHUTDOWN undi_shutdown; struct s_PXENV_UNDI_CLEANUP undi_cleanup; -#if 0 struct s_PXENV_STOP_UNDI stop_undi; -#endif int rc; /* Allocate net device */ @@ -671,20 +665,23 @@ int undinet_probe ( struct undi_device *undi ) { &start_undi, sizeof ( start_undi ) ) ) != 0 ) goto err_start_undi; - /* Bring up UNDI stack */ + } + undi->flags |= UNDI_FL_STARTED; + + /* Bring up UNDI stack */ + if ( ! ( undi->flags & UNDI_FL_INITIALIZED ) ) { memset ( &undi_startup, 0, sizeof ( undi_startup ) ); if ( ( rc = undinet_call ( undinic, PXENV_UNDI_STARTUP, &undi_startup, sizeof ( undi_startup ) ) ) != 0 ) - goto err_undi_startup; - + goto err_undi_startup; memset ( &undi_initialize, 0, sizeof ( undi_initialize ) ); if ( ( rc = undinet_call ( undinic, PXENV_UNDI_INITIALIZE, &undi_initialize, - sizeof ( undi_initialize ) ) ) != 0 ) - goto err_undi_initialize; + sizeof ( undi_initialize ))) != 0 ) + goto err_undi_initialize; } - undi->flags |= UNDI_FL_STARTED; + undi->flags |= UNDI_FL_INITIALIZED; /* Get device information */ memset ( &undi_info, 0, sizeof ( undi_info ) ); @@ -707,7 +704,7 @@ int undinet_probe ( struct undi_device *undi ) { &undi_iface, sizeof ( undi_iface ) ) ) != 0 ) goto err_undi_get_iface_info; - DBGC ( undinic, "UNDINIC %p has type %s and link speed %ld\n", + DBGC ( undinic, "UNDINIC %p has type %s and link speed %d\n", undinic, undi_iface.IfaceType, undi_iface.LinkSpeed ); if ( strncmp ( ( ( char * ) undi_iface.IfaceType ), "Etherboot", sizeof ( undi_iface.IfaceType ) ) == 0 ) { @@ -731,7 +728,6 @@ int undinet_probe ( struct undi_device *undi ) { err_bad_irq: err_undi_get_information: err_undi_initialize: - /* Shut down UNDI stack */ memset ( &undi_shutdown, 0, sizeof ( undi_shutdown ) ); undinet_call ( undinic, PXENV_UNDI_SHUTDOWN, &undi_shutdown, @@ -739,13 +735,13 @@ int undinet_probe ( struct undi_device *undi ) { memset ( &undi_cleanup, 0, sizeof ( undi_cleanup ) ); undinet_call ( undinic, PXENV_UNDI_CLEANUP, &undi_cleanup, sizeof ( undi_cleanup ) ); + undi->flags &= ~UNDI_FL_INITIALIZED; err_undi_startup: -#if 0 /* Unhook UNDI stack */ memset ( &stop_undi, 0, sizeof ( stop_undi ) ); undinet_call ( undinic, PXENV_STOP_UNDI, &stop_undi, sizeof ( stop_undi ) ); -#endif + undi->flags &= ~UNDI_FL_STARTED; err_start_undi: netdev_nullify ( netdev ); netdev_put ( netdev ); @@ -761,30 +757,33 @@ int undinet_probe ( struct undi_device *undi ) { void undinet_remove ( struct undi_device *undi ) { struct net_device *netdev = undi_get_drvdata ( undi ); struct undi_nic *undinic = netdev->priv; -#if 0 struct s_PXENV_UNDI_SHUTDOWN undi_shutdown; struct s_PXENV_UNDI_CLEANUP undi_cleanup; struct s_PXENV_STOP_UNDI stop_undi; -#endif /* Unregister net device */ unregister_netdev ( netdev ); - /* Shut down UNDI stack */ -#if 0 - memset ( &undi_shutdown, 0, sizeof ( undi_shutdown ) ); - undinet_call ( undinic, PXENV_UNDI_SHUTDOWN, &undi_shutdown, - sizeof ( undi_shutdown ) ); - memset ( &undi_cleanup, 0, sizeof ( undi_cleanup ) ); - undinet_call ( undinic, PXENV_UNDI_CLEANUP, &undi_cleanup, - sizeof ( undi_cleanup ) ); - - /* Unhook UNDI stack */ - memset ( &stop_undi, 0, sizeof ( stop_undi ) ); - undinet_call ( undinic, PXENV_STOP_UNDI, &stop_undi, - sizeof ( stop_undi ) ); - undi->flags &= ~UNDI_FL_STARTED; -#endif + /* If we are preparing for an OS boot, or if we cannot exit + * via the PXE stack, then shut down the PXE stack. + */ + if ( ! ( undi->flags & UNDI_FL_KEEP_ALL ) ) { + + /* Shut down UNDI stack */ + memset ( &undi_shutdown, 0, sizeof ( undi_shutdown ) ); + undinet_call ( undinic, PXENV_UNDI_SHUTDOWN, &undi_shutdown, + sizeof ( undi_shutdown ) ); + memset ( &undi_cleanup, 0, sizeof ( undi_cleanup ) ); + undinet_call ( undinic, PXENV_UNDI_CLEANUP, &undi_cleanup, + sizeof ( undi_cleanup ) ); + undi->flags &= ~UNDI_FL_INITIALIZED; + + /* Unhook UNDI stack */ + memset ( &stop_undi, 0, sizeof ( stop_undi ) ); + undinet_call ( undinic, PXENV_STOP_UNDI, &stop_undi, + sizeof ( stop_undi ) ); + undi->flags &= ~UNDI_FL_STARTED; + } /* Clear entry point */ memset ( &undinet_entry_point, 0, sizeof ( undinet_entry_point ) ); diff --git a/gpxe/src/arch/i386/drivers/net/undionly.c b/gpxe/src/arch/i386/drivers/net/undionly.c index ee361493..4cdce677 100644 --- a/gpxe/src/arch/i386/drivers/net/undionly.c +++ b/gpxe/src/arch/i386/drivers/net/undionly.c @@ -20,6 +20,7 @@ #include <stdlib.h> #include <string.h> #include <gpxe/device.h> +#include <gpxe/init.h> #include <undi.h> #include <undinet.h> #include <undipreload.h> @@ -107,3 +108,20 @@ struct root_device undi_root_device __root_device = { .dev = { .name = "UNDI" }, .driver = &undi_root_driver, }; + +/** + * Prepare for exit + * + * @v flags Shutdown flags + */ +static void undionly_shutdown ( int flags ) { + /* If we are shutting down to boot an OS, clear the "keep PXE + * stack" flag. + */ + if ( flags & SHUTDOWN_BOOT ) + preloaded_undi.flags &= ~UNDI_FL_KEEP_ALL; +} + +struct startup_fn startup_undionly __startup_fn ( STARTUP_LATE ) = { + .shutdown = undionly_shutdown, +}; diff --git a/gpxe/src/arch/i386/drivers/net/undirom.c b/gpxe/src/arch/i386/drivers/net/undirom.c index d40fcd35..e5782781 100644 --- a/gpxe/src/arch/i386/drivers/net/undirom.c +++ b/gpxe/src/arch/i386/drivers/net/undirom.c @@ -52,7 +52,7 @@ static int undirom_parse_pxeromid ( struct undi_rom *undirom, sizeof ( undi_rom_id ) ); if ( undi_rom_id.Signature != UNDI_ROM_ID_SIGNATURE ) { DBGC ( undirom, "UNDIROM %p has bad PXE ROM ID signature " - "%08lx\n", undirom, undi_rom_id.Signature ); + "%08x\n", undirom, undi_rom_id.Signature ); return -EINVAL; } @@ -94,7 +94,7 @@ static int undirom_parse_pcirheader ( struct undi_rom *undirom, sizeof ( pcir_header ) ); if ( pcir_header.signature != PCIR_SIGNATURE ) { DBGC ( undirom, "UNDIROM %p has bad PCI expansion header " - "signature %08lx\n", undirom, pcir_header.signature ); + "signature %08x\n", undirom, pcir_header.signature ); return -EINVAL; } diff --git a/gpxe/src/arch/i386/drivers/timer_bios.c b/gpxe/src/arch/i386/drivers/timer_bios.c deleted file mode 100644 index f9caf8d9..00000000 --- a/gpxe/src/arch/i386/drivers/timer_bios.c +++ /dev/null @@ -1,57 +0,0 @@ -/* - * Etherboot routines for PCBIOS firmware. - * - * Body of routines taken from old pcbios.S - */ - -#include <gpxe/init.h> -#include <gpxe/timer.h> -#include <stdio.h> -#include <realmode.h> -#include <bios.h> -#include <bits/timer2.h> - -/* A bit faster actually, but we don't care. */ -#define TIMER2_TICKS_PER_SEC 18 - -/* - * Use direct memory access to BIOS variables, longword 0040:006C (ticks - * today) and byte 0040:0070 (midnight crossover flag) instead of calling - * timeofday BIOS interrupt. - */ - -static tick_t bios_currticks ( void ) { - static int days = 0; - uint32_t ticks; - 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" ) : : ); - - get_real ( ticks, BDA_SEG, 0x006c ); - get_real ( midnight, BDA_SEG, 0x0070 ); - - if ( midnight ) { - midnight = 0; - put_real ( midnight, BDA_SEG, 0x0070 ); - days += 0x1800b0; - } - - return ( (days + ticks) * (USECS_IN_SEC / TIMER2_TICKS_PER_SEC) ); -} - -static int bios_ts_init(void) -{ - DBG("BIOS timer installed\n"); - return 0; -} - -struct timer bios_ts __timer ( 02 ) = { - .init = bios_ts_init, - .udelay = i386_timer2_udelay, - .currticks = bios_currticks, -}; - diff --git a/gpxe/src/arch/i386/drivers/timer_rdtsc.c b/gpxe/src/arch/i386/drivers/timer_rdtsc.c deleted file mode 100644 index 09b7df2f..00000000 --- a/gpxe/src/arch/i386/drivers/timer_rdtsc.c +++ /dev/null @@ -1,69 +0,0 @@ - -#include <gpxe/init.h> -#include <gpxe/timer.h> -#include <errno.h> -#include <stdio.h> -#include <bits/cpu.h> -#include <bits/timer2.h> -#include <io.h> - - -#define rdtsc(low,high) \ - __asm__ __volatile__("rdtsc" : "=a" (low), "=d" (high)) - -#define rdtscll(val) \ - __asm__ __volatile__ ("rdtsc" : "=A" (val)) - - -/* Measure how many clocks we get in one microsecond */ -static inline uint64_t calibrate_tsc(void) -{ - - uint64_t rdtsc_start; - uint64_t rdtsc_end; - - rdtscll(rdtsc_start); - i386_timer2_udelay(USECS_IN_MSEC); - rdtscll(rdtsc_end); - - return (rdtsc_end - rdtsc_start) / USECS_IN_MSEC; -} - -static uint32_t clocks_per_usec = 0; - -/* We measure time in microseconds. */ -static tick_t rdtsc_currticks(void) -{ - uint64_t clocks; - - /* Read the Time Stamp Counter */ - rdtscll(clocks); - - return clocks / clocks_per_usec; -} - -static int rdtsc_ts_init(void) -{ - - struct cpuinfo_x86 cpu_info; - - get_cpuinfo(&cpu_info); - if (cpu_info.features & X86_FEATURE_TSC) { - clocks_per_usec= calibrate_tsc(); - if (clocks_per_usec) { - DBG("RDTSC ticksource installed. CPU running at %ld Mhz\n", - clocks_per_usec); - return 0; - } - } - - DBG("RDTSC ticksource not available on this machine.\n"); - return -ENODEV; -} - -struct timer rdtsc_ts __timer (01) = { - .init = rdtsc_ts_init, - .udelay = generic_currticks_udelay, - .currticks = rdtsc_currticks, -}; - diff --git a/gpxe/src/arch/i386/firmware/pcbios/bios_console.c b/gpxe/src/arch/i386/firmware/pcbios/bios_console.c index dcb0462a..91363772 100644 --- a/gpxe/src/arch/i386/firmware/pcbios/bios_console.c +++ b/gpxe/src/arch/i386/firmware/pcbios/bios_console.c @@ -193,13 +193,14 @@ static const char *ansi_input = ""; * dense range, so subtracting a constant and treating them as offsets * into an array works efficiently. */ -#define BIOS_KEY_MIN 0x47 +#define BIOS_KEY_MIN 0x42 /** Offset into list of interesting BIOS scancodes */ #define BIOS_KEY(scancode) ( (scancode) - BIOS_KEY_MIN ) /** Mapping from BIOS scan codes to ANSI escape sequences */ static const char *ansi_sequences[] = { + [ BIOS_KEY ( 0x42 ) ] = "[19~", /* F8 (required for PXE) */ [ BIOS_KEY ( 0x47 ) ] = "[H", /* Home */ [ BIOS_KEY ( 0x48 ) ] = "[A", /* Up arrow */ [ BIOS_KEY ( 0x4b ) ] = "[D", /* Left arrow */ @@ -222,6 +223,7 @@ static const char * scancode_to_ansi_seq ( unsigned int scancode ) { sizeof ( ansi_sequences[0] ) ) ) { return ansi_sequences[bios_key]; } + DBG ( "Unrecognised BIOS scancode %02x\n", scancode ); return NULL; } diff --git a/gpxe/src/arch/i386/firmware/pcbios/e820mangler.S b/gpxe/src/arch/i386/firmware/pcbios/e820mangler.S index 4fbd6563..4ba3fb14 100644 --- a/gpxe/src/arch/i386/firmware/pcbios/e820mangler.S +++ b/gpxe/src/arch/i386/firmware/pcbios/e820mangler.S @@ -18,9 +18,6 @@ .text .arch i386 - .section ".text16", "ax", @progbits - .section ".data16", "aw", @progbits - .section ".text16.data", "aw", @progbits .code16 #define SMAP 0x534d4150 @@ -62,11 +59,11 @@ * **************************************************************************** */ - .section ".data16" + .section ".data16", "aw", @progbits .align 16 .globl hidemem_base .globl hidemem_umalloc - .globl hidemem_text + .globl hidemem_textdata memory_windows: base_memory_window: .long 0x00000000, 0x00000000 /* Start of memory */ @@ -76,7 +73,7 @@ ext_memory_window: .long 0x000a0000, 0x00000000 /* 640kB mark */ hidemem_umalloc: .long 0xffffffff, 0xffffffff /* Changes at runtime */ .long 0xffffffff, 0xffffffff /* Changes at runtime */ -hidemem_text: .long 0xffffffff, 0xffffffff /* Changes at runtime */ +hidemem_textdata: .long 0xffffffff, 0xffffffff /* Changes at runtime */ .long 0xffffffff, 0xffffffff /* Changes at runtime */ .long 0xffffffff, 0xffffffff /* End of memory */ @@ -94,7 +91,7 @@ memory_windows_end: * %ecx:%ebx Length of windowed region **************************************************************************** */ - .section ".text16" + .section ".text16", "ax", @progbits window_region: /* Convert (start,len) to (start, end) */ addl %eax, %ebx @@ -132,7 +129,7 @@ window_region: * %ax Modified memory above 1M in 1kB blocks **************************************************************************** */ - .section ".text16" + .section ".text16", "ax", @progbits patch_1m: pushal /* Convert to (start,len) format and call truncate */ @@ -162,7 +159,7 @@ patch_1m: * %bx Modified memory above 16M in 64kB blocks **************************************************************************** */ - .section ".text16" + .section ".text16", "ax", @progbits patch_16m: pushal /* Convert to (start,len) format and call truncate */ @@ -193,7 +190,7 @@ patch_16m: * %bx Modified memory above 16MB, in 64kB blocks **************************************************************************** */ - .section ".text16" + .section ".text16", "ax", @progbits patch_1m_16m: call patch_1m call patch_16m @@ -219,7 +216,7 @@ patch_1m_16m: * **************************************************************************** */ - .section ".text16" + .section ".text16", "ax", @progbits get_underlying_e820: /* If the requested region is in the cache, return it */ @@ -268,8 +265,10 @@ get_underlying_e820: pushl %ebx pushl %ecx pushl %edx + pushl %esi /* Some implementations corrupt %esi, so we */ + pushl %edi /* preserve %esi, %edi and %ebp to be paranoid */ + pushl %ebp pushw %es - pushw %di pushw %ds popw %es movw $underlying_e820_cache, %di @@ -280,8 +279,10 @@ get_underlying_e820: stc pushfw lcall *%cs:int15_vector - popw %di popw %es + popl %ebp + popl %edi + popl %esi /* Check for error return from underlying e820 call */ jc 2f /* CF set: error */ cmpl $SMAP, %eax @@ -304,22 +305,22 @@ get_underlying_e820: jmp get_underlying_e820 .size get_underlying_e820, . - get_underlying_e820 - .section ".data16" + .section ".data16", "aw", @progbits underlying_e820_index: .word 0xffff /* Initialise to an invalid value */ .size underlying_e820_index, . - underlying_e820_index - .section ".bss16" + .section ".bss16", "aw", @nobits underlying_e820_ebx: .long 0 .size underlying_e820_ebx, . - underlying_e820_ebx - .section ".bss16" + .section ".bss16", "aw", @nobits underlying_e820_cache: .space E820MAXSIZE .size underlying_e820_cache, . - underlying_e820_cache - .section ".bss16" + .section ".bss16", "aw", @nobits underlying_e820_cache_size: .long 0 .size underlying_e820_cache_size, . - underlying_e820_cache_size @@ -338,7 +339,7 @@ underlying_e820_cache_size: * **************************************************************************** */ - .section ".text16" + .section ".text16", "ax", @progbits get_windowed_e820: /* Preserve registers */ @@ -413,7 +414,7 @@ get_windowed_e820: * **************************************************************************** */ - .section ".text16" + .section ".text16", "ax", @progbits get_nonempty_e820: /* Record entry parameters */ @@ -458,7 +459,7 @@ get_nonempty_e820: * **************************************************************************** */ - .section ".text16" + .section ".text16", "ax", @progbits get_mangled_e820: /* Get a nonempty region */ @@ -492,7 +493,7 @@ get_mangled_e820: * INT 15,e820 handler **************************************************************************** */ - .section ".text16" + .section ".text16", "ax", @progbits int15_e820: pushw %ds pushw %cs:rm_ds @@ -506,7 +507,7 @@ int15_e820: * INT 15,e801 handler **************************************************************************** */ - .section ".text16" + .section ".text16", "ax", @progbits int15_e801: /* Call previous handler */ pushfw @@ -532,7 +533,7 @@ int15_e801: * INT 15,88 handler **************************************************************************** */ - .section ".text16" + .section ".text16", "ax", @progbits int15_88: /* Call previous handler */ pushfw @@ -553,7 +554,7 @@ int15_88: * INT 15 handler **************************************************************************** */ - .section ".text16" + .section ".text16", "ax", @progbits .globl int15 int15: /* See if we want to intercept this call */ @@ -576,7 +577,7 @@ int15: ljmp *%cs:int15_vector .size int15, . - int15 - .section ".text16.data" + .section ".text16.data", "aw", @progbits .globl int15_vector int15_vector: .long 0 diff --git a/gpxe/src/arch/i386/firmware/pcbios/gateA20.c b/gpxe/src/arch/i386/firmware/pcbios/gateA20.c index a14e3416..34e3ac52 100644 --- a/gpxe/src/arch/i386/firmware/pcbios/gateA20.c +++ b/gpxe/src/arch/i386/firmware/pcbios/gateA20.c @@ -1,6 +1,7 @@ #include <stdio.h> #include <realmode.h> #include <bios.h> +#include <gpxe/io.h> #include <gpxe/timer.h> #define K_RDWR 0x60 /* keyboard data & cmds (read/write) */ @@ -48,9 +49,9 @@ static void empty_8042 ( void ) { time = currticks() + TICKS_PER_SEC; /* max wait of 1 second */ while ( ( inb ( K_CMD ) & ( K_IBUF_FUL | K_OBUF_FUL ) ) && currticks() < time ) { - SLOW_DOWN_IO; - ( void ) inb ( K_RDWR ); - SLOW_DOWN_IO; + iodelay(); + ( void ) inb_p ( K_RDWR ); + iodelay(); } } @@ -77,7 +78,7 @@ static int gateA20_is_set ( int retries ) { /* Avoid false negatives */ test_pattern++; - SLOW_DOWN_IO; + iodelay(); /* Always retry at least once, to avoid false negatives */ } while ( retries-- >= 0 ); @@ -145,9 +146,9 @@ void gateA20_set ( void ) { scp_a = inb ( SCP_A ); scp_a &= ~0x01; /* Avoid triggering a reset */ scp_a |= 0x02; /* Enable A20 */ - SLOW_DOWN_IO; + iodelay(); outb ( scp_a, SCP_A ); - SLOW_DOWN_IO; + iodelay(); if ( gateA20_is_set ( A20_SCPA_RETRIES ) ) { DBG ( "Enabled gate A20 using " "Fast Gate A20\n" ); diff --git a/gpxe/src/arch/i386/firmware/pcbios/hidemem.c b/gpxe/src/arch/i386/firmware/pcbios/hidemem.c index c9df7bd0..620b62e0 100644 --- a/gpxe/src/arch/i386/firmware/pcbios/hidemem.c +++ b/gpxe/src/arch/i386/firmware/pcbios/hidemem.c @@ -55,8 +55,8 @@ extern struct hidden_region __data16 ( hidemem_umalloc ); #define hidemem_umalloc __use_data16 ( hidemem_umalloc ) /** Hidden text memory */ -extern struct hidden_region __data16 ( hidemem_text ); -#define hidemem_text __use_data16 ( hidemem_text ) +extern struct hidden_region __data16 ( hidemem_textdata ); +#define hidemem_textdata __use_data16 ( hidemem_textdata ) /** Assembly routine in e820mangler.S */ extern void int15(); @@ -66,12 +66,12 @@ extern struct segoff __text16 ( int15_vector ); #define int15_vector __use_text16 ( int15_vector ) /* The linker defines these symbols for us */ -extern char _text[]; -extern char _end[]; -extern char _text16_size[]; -#define _text16_size ( ( unsigned int ) _text16_size ) -extern char _data16_size[]; -#define _data16_size ( ( unsigned int ) _data16_size ) +extern char _textdata[]; +extern char _etextdata[]; +extern char _text16_memsz[]; +#define _text16_memsz ( ( unsigned int ) _text16_memsz ) +extern char _data16_memsz[]; +#define _data16_memsz ( ( unsigned int ) _data16_memsz ) /** * Hide region of memory from system memory map @@ -110,7 +110,7 @@ void hide_basemem ( void ) { * */ void hide_umalloc ( physaddr_t start, physaddr_t end ) { - assert ( end <= virt_to_phys ( _text ) ); + assert ( end <= virt_to_phys ( _textdata ) ); hide_region ( &hidemem_umalloc, start, end ); } @@ -118,9 +118,9 @@ void hide_umalloc ( physaddr_t start, physaddr_t end ) { * Hide .text and .data * */ -void hide_text ( void ) { - hide_region ( &hidemem_text, virt_to_phys ( _text ), - virt_to_phys ( _end ) ); +void hide_textdata ( void ) { + hide_region ( &hidemem_textdata, virt_to_phys ( _textdata ), + virt_to_phys ( _etextdata ) ); } /** @@ -148,8 +148,8 @@ static void hide_etherboot ( void ) { /* Initialise the hidden regions */ hide_basemem(); - hide_umalloc ( virt_to_phys ( _text ), virt_to_phys ( _text ) ); - hide_text(); + hide_umalloc ( virt_to_phys ( _textdata ), virt_to_phys ( _textdata ) ); + hide_textdata(); /* Some really moronic BIOSes bring up the PXE stack via the * UNDI loader entry point and then don't bother to unload it @@ -161,8 +161,8 @@ static void hide_etherboot ( void ) { * We use a heuristic to guess whether or not we are being * loaded sensibly. */ - rm_cs_top = ( ( ( rm_cs << 4 ) + _text16_size + 1024 - 1 ) >> 10 ); - rm_ds_top = ( ( ( rm_ds << 4 ) + _data16_size + 1024 - 1 ) >> 10 ); + rm_cs_top = ( ( ( rm_cs << 4 ) + _text16_memsz + 1024 - 1 ) >> 10 ); + rm_ds_top = ( ( ( rm_ds << 4 ) + _data16_memsz + 1024 - 1 ) >> 10 ); fbms = get_fbms(); if ( ( rm_cs_top < fbms ) && ( rm_ds_top < fbms ) ) { DBG ( "Detected potentially unsafe UNDI load at CS=%04x " diff --git a/gpxe/src/arch/i386/firmware/pcbios/memmap.c b/gpxe/src/arch/i386/firmware/pcbios/memmap.c index 9de10a7a..ff387d93 100644 --- a/gpxe/src/arch/i386/firmware/pcbios/memmap.c +++ b/gpxe/src/arch/i386/firmware/pcbios/memmap.c @@ -158,7 +158,7 @@ static int meme820 ( struct memory_map *memmap ) { uint32_t smap; size_t size; unsigned int flags; - unsigned int discard_d, discard_D; + unsigned int discard_D; /* Clear the E820 buffer. Do this once before starting, * rather than on each call; some BIOSes rely on the contents @@ -167,18 +167,24 @@ static int meme820 ( struct memory_map *memmap ) { memset ( &e820buf, 0, sizeof ( e820buf ) ); do { - __asm__ __volatile__ ( REAL_CODE ( "stc\n\t" + /* Some BIOSes corrupt %esi for fun. Guard against + * this by telling gcc that all non-output registers + * may be corrupted. + */ + __asm__ __volatile__ ( REAL_CODE ( "pushl %%ebp\n\t" + "stc\n\t" "int $0x15\n\t" "pushfw\n\t" - "popw %w0\n\t" ) - : "=r" ( flags ), "=a" ( smap ), - "=b" ( next ), "=D" ( discard_D ), - "=c" ( size ), "=d" ( discard_d ) + "popw %%dx\n\t" + "popl %%ebp\n\t" ) + : "=a" ( smap ), "=b" ( next ), + "=c" ( size ), "=d" ( flags ), + "=D" ( discard_D ) : "a" ( 0xe820 ), "b" ( next ), "D" ( __from_data16 ( &e820buf ) ), "c" ( sizeof ( e820buf ) ), "d" ( SMAP ) - : "memory" ); + : "esi", "memory" ); if ( smap != SMAP ) { DBG ( "INT 15,e820 failed SMAP signature check\n" ); @@ -195,6 +201,13 @@ static int meme820 ( struct memory_map *memmap ) { break; } + /* If first region is not RAM, assume map is invalid */ + if ( ( memmap->count == 0 ) && + ( e820buf.type != E820_TYPE_RAM ) ) { + DBG ( "INT 15,e820 failed, first entry not RAM\n" ); + return -EINVAL; + } + DBG ( "INT 15,e820 region [%llx,%llx) type %d", e820buf.start, ( e820buf.start + e820buf.len ), ( int ) e820buf.type ); @@ -204,7 +217,7 @@ static int meme820 ( struct memory_map *memmap ) { if ( e820buf.attrs & E820_ATTR_NONVOLATILE ) DBG ( ", non-volatile" ); if ( e820buf.attrs & E820_ATTR_UNKNOWN ) - DBG ( ", other [%08lx]", e820buf.attrs ); + DBG ( ", other [%08x]", e820buf.attrs ); DBG ( ")" ); } DBG ( "\n" ); diff --git a/gpxe/src/arch/i386/image/bzimage.c b/gpxe/src/arch/i386/image/bzimage.c index e6fd854f..47d46ca4 100644 --- a/gpxe/src/arch/i386/image/bzimage.c +++ b/gpxe/src/arch/i386/image/bzimage.c @@ -400,7 +400,7 @@ static int bzimage_load_header ( struct image *image, copy_from_user ( bzhdr, image->data, BZI_HDR_OFFSET, sizeof ( *bzhdr ) ); if ( bzhdr->header != BZI_SIGNATURE ) { - DBGC ( image, "bzImage %p bad signature %08lx\n", + DBGC ( image, "bzImage %p bad signature %08x\n", image, bzhdr->header ); return -ENOEXEC; } diff --git a/gpxe/src/arch/i386/image/com32.c b/gpxe/src/arch/i386/image/com32.c index da604625..d1b9a59f 100644 --- a/gpxe/src/arch/i386/image/com32.c +++ b/gpxe/src/arch/i386/image/com32.c @@ -52,7 +52,7 @@ static int com32_exec ( struct image *image ) { int state; uint32_t avail_mem_top; - state = setjmp ( comboot_return ); + state = rmsetjmp ( comboot_return ); switch ( state ) { case 0: /* First time through; invoke COM32 program */ @@ -70,20 +70,20 @@ static int com32_exec ( struct image *image ) { } DBGC ( image, "COM32 %p: available memory top = 0x%x\n", - image, (int)avail_mem_top ); + image, avail_mem_top ); assert ( avail_mem_top != 0 ); com32_external_esp = phys_to_virt ( avail_mem_top ); /* Hook COMBOOT API interrupts */ - hook_comboot_interrupts( ); + hook_comboot_interrupts(); - /* Temporarily de-register image, so that a "boot" command - * doesn't throw us into an execution loop. Hold a reference - * to avoid the image's being freed. + /* Unregister image, so that a "boot" command doesn't + * throw us into an execution loop. We never + * reregister ourselves; COMBOOT images expect to be + * removed on exit. */ - image_get ( image ); unregister_image ( image ); __asm__ __volatile__ ( @@ -111,25 +111,33 @@ static int com32_exec ( struct image *image ) { /* %6 */ "r" ( COM32_START_PHYS ) : "memory" ); + DBGC ( image, "COM32 %p: returned\n", image ); break; - case COMBOOT_RETURN_RUN_KERNEL: - DBGC ( image, "COM32 %p: returned to run kernel...\n", image ); - comboot_run_kernel ( ); + case COMBOOT_EXIT: + DBGC ( image, "COM32 %p: exited\n", image ); break; - case COMBOOT_RETURN_EXIT: + case COMBOOT_EXIT_RUN_KERNEL: + DBGC ( image, "COM32 %p: exited to run kernel %p\n", + image, comboot_replacement_image ); + image->replacement = comboot_replacement_image; + comboot_replacement_image = NULL; + image_autoload ( image->replacement ); break; - } - - comboot_force_text_mode ( ); + case COMBOOT_EXIT_COMMAND: + DBGC ( image, "COM32 %p: exited after executing command\n", + image ); + break; - DBGC ( image, "COM32 %p returned\n", image ); + default: + assert ( 0 ); + break; + } - /* Re-register image and return */ - register_image ( image ); - image_put ( image ); + unhook_comboot_interrupts(); + comboot_force_text_mode(); return 0; } diff --git a/gpxe/src/arch/i386/image/comboot.c b/gpxe/src/arch/i386/image/comboot.c index 63d02c0f..40e32185 100644 --- a/gpxe/src/arch/i386/image/comboot.c +++ b/gpxe/src/arch/i386/image/comboot.c @@ -133,7 +133,7 @@ static int comboot_exec ( struct image *image ) { userptr_t seg_userptr = real_to_user ( COMBOOT_PSP_SEG, 0 ); int state; - state = setjmp ( comboot_return ); + state = rmsetjmp ( comboot_return ); switch ( state ) { case 0: /* First time through; invoke COMBOOT program */ @@ -142,16 +142,16 @@ static int comboot_exec ( struct image *image ) { comboot_init_psp ( image, seg_userptr ); /* Hook COMBOOT API interrupts */ - hook_comboot_interrupts ( ); + hook_comboot_interrupts(); DBGC ( image, "executing 16-bit COMBOOT image at %4x:0100\n", - COMBOOT_PSP_SEG ); + COMBOOT_PSP_SEG ); - /* Temporarily de-register image, so that a "boot" command - * doesn't throw us into an execution loop. Hold a reference - * to avoid the image's being freed. + /* Unregister image, so that a "boot" command doesn't + * throw us into an execution loop. We never + * reregister ourselves; COMBOOT images expect to be + * removed on exit. */ - image_get ( image ); unregister_image ( image ); /* Store stack segment at 0x38 and stack pointer at 0x3A @@ -180,26 +180,34 @@ static int comboot_exec ( struct image *image ) { "xorw %%bp, %%bp\n\t" "lret\n\t" ) : : "r" ( COMBOOT_PSP_SEG ) : "eax" ); + DBGC ( image, "COMBOOT %p: returned\n", image ); break; - case COMBOOT_RETURN_RUN_KERNEL: - DBGC ( image, "COMBOOT %p: returned to run kernel...\n", image ); - comboot_run_kernel ( ); + case COMBOOT_EXIT: + DBGC ( image, "COMBOOT %p: exited\n", image ); break; - case COMBOOT_RETURN_EXIT: + case COMBOOT_EXIT_RUN_KERNEL: + DBGC ( image, "COMBOOT %p: exited to run kernel %p\n", + image, comboot_replacement_image ); + image->replacement = comboot_replacement_image; + comboot_replacement_image = NULL; + image_autoload ( image->replacement ); break; - } + case COMBOOT_EXIT_COMMAND: + DBGC ( image, "COMBOOT %p: exited after executing command\n", + image ); + break; - comboot_force_text_mode ( ); + default: + assert ( 0 ); + break; + } - DBGC ( image, "COMBOOT %p returned\n", image ); + unhook_comboot_interrupts(); + comboot_force_text_mode(); - /* Re-register image and return */ - register_image ( image ); - image_put ( image ); - return 0; } diff --git a/gpxe/src/arch/i386/image/multiboot.c b/gpxe/src/arch/i386/image/multiboot.c index a4a340fd..52bb10f6 100644 --- a/gpxe/src/arch/i386/image/multiboot.c +++ b/gpxe/src/arch/i386/image/multiboot.c @@ -220,7 +220,7 @@ multiboot_build_module_list ( struct image *image, /* Dump module configuration */ for ( i = 0 ; i < count ; i++ ) { - DBGC ( image, "MULTIBOOT %p module %d is [%lx,%lx)\n", + DBGC ( image, "MULTIBOOT %p module %d is [%x,%x)\n", image, i, modules[i].mod_start, modules[i].mod_end ); } @@ -282,11 +282,13 @@ static int multiboot_exec ( struct image *image ) { /* Jump to OS with flat physical addressing */ DBGC ( image, "MULTIBOOT %p starting execution at %lx\n", image, entry ); - __asm__ __volatile__ ( PHYS_CODE ( "call *%%edi\n\t" ) + __asm__ __volatile__ ( PHYS_CODE ( "pushl %%ebp\n\t" + "call *%%edi\n\t" + "popl %%ebp\n\t" ) : : "a" ( MULTIBOOT_BOOTLOADER_MAGIC ), "b" ( virt_to_phys ( &mbinfo ) ), "D" ( entry ) - : "ecx", "edx", "esi", "ebp", "memory" ); + : "ecx", "edx", "esi", "memory" ); DBGC ( image, "MULTIBOOT %p returned\n", image ); @@ -416,7 +418,7 @@ static int multiboot_load ( struct image *image ) { image ); return rc; } - DBGC ( image, "MULTIBOOT %p found header with flags %08lx\n", + DBGC ( image, "MULTIBOOT %p found header with flags %08x\n", image, hdr.mb.flags ); /* This is a multiboot image, valid or otherwise */ @@ -425,7 +427,7 @@ static int multiboot_load ( struct image *image ) { /* Abort if we detect flags that we cannot support */ if ( hdr.mb.flags & MB_UNSUPPORTED_FLAGS ) { - DBGC ( image, "MULTIBOOT %p flags %08lx not supported\n", + DBGC ( image, "MULTIBOOT %p flags %08x not supported\n", image, ( hdr.mb.flags & MB_UNSUPPORTED_FLAGS ) ); return -ENOTSUP; } diff --git a/gpxe/src/arch/i386/image/nbi.c b/gpxe/src/arch/i386/image/nbi.c index e6a0ab0f..a4ee4420 100644 --- a/gpxe/src/arch/i386/image/nbi.c +++ b/gpxe/src/arch/i386/image/nbi.c @@ -367,22 +367,6 @@ static int nbi_boot32 ( struct image *image, struct imgheader *imgheader ) { } /** - * Guess boot network device - * - * @ret netdev Boot network device - */ -static struct net_device * guess_boot_netdev ( void ) { - struct net_device *boot_netdev; - - /* Just use the first network device */ - for_each_netdev ( boot_netdev ) { - return boot_netdev; - } - - return NULL; -} - -/** * Prepare DHCP parameter block for NBI image * * @v image NBI image @@ -392,7 +376,7 @@ static int nbi_prepare_dhcp ( struct image *image ) { struct net_device *boot_netdev; int rc; - boot_netdev = guess_boot_netdev(); + boot_netdev = last_opened_netdev(); if ( ! boot_netdev ) { DBGC ( image, "NBI %p could not identify a network device\n", image ); diff --git a/gpxe/src/arch/i386/image/pxe_image.c b/gpxe/src/arch/i386/image/pxe_image.c index 77fa0469..90550d83 100644 --- a/gpxe/src/arch/i386/image/pxe_image.c +++ b/gpxe/src/arch/i386/image/pxe_image.c @@ -42,18 +42,14 @@ struct image_type pxe_image_type __image_type ( PROBE_PXE ); * @ret rc Return status code */ static int pxe_exec ( struct image *image ) { - struct net_device *netdev; int rc; /* Ensure that PXE stack is ready to use */ pxe_init_structures(); pxe_hook_int1a(); - /* Arbitrarily pick the first open network device to use for PXE */ - for_each_netdev ( netdev ) { - pxe_set_netdev ( netdev ); - break; - } + /* Arbitrarily pick the most recently opened network device */ + pxe_set_netdev ( last_opened_netdev() ); /* Many things will break if pxe_netdev is NULL */ if ( ! pxe_netdev ) { @@ -92,6 +88,12 @@ int pxe_load ( struct image *image ) { if ( filesz > ( 0xa0000 - 0x7c00 ) ) return -ENOEXEC; + /* Rejecting zero-length images is also useful, since these + * end up looking to the user like bugs in gPXE. + */ + if ( ! filesz ) + return -ENOEXEC; + /* There are no signature checks for PXE; we will accept anything */ if ( ! image->type ) image->type = &pxe_image_type; diff --git a/gpxe/src/arch/i386/include/bios.h b/gpxe/src/arch/i386/include/bios.h index 630a898b..979a092c 100644 --- a/gpxe/src/arch/i386/include/bios.h +++ b/gpxe/src/arch/i386/include/bios.h @@ -5,7 +5,4 @@ #define BDA_FBMS 0x0013 #define BDA_NUM_DRIVES 0x0075 -extern unsigned long currticks ( void ); -extern void cpu_nap ( void ); - #endif /* BIOS_H */ diff --git a/gpxe/src/arch/i386/include/biosint.h b/gpxe/src/arch/i386/include/biosint.h index d4e34963..d365cf01 100644 --- a/gpxe/src/arch/i386/include/biosint.h +++ b/gpxe/src/arch/i386/include/biosint.h @@ -6,9 +6,22 @@ * */ +#include <realmode.h> + struct segoff; -extern int hooked_bios_interrupts; +/** + * Hooked interrupt count + * + * At exit, after unhooking all possible interrupts, this counter + * should be examined. If it is non-zero, it means that we failed to + * unhook at least one interrupt vector, and so must not free up the + * memory we are using. (Note that this also implies that we should + * re-hook INT 15 in order to hide ourselves from the memory map). + */ +extern uint16_t __text16 ( hooked_bios_interrupts ); +#define hooked_bios_interrupts __use_text16 ( hooked_bios_interrupts ) + extern void hook_bios_interrupt ( unsigned int interrupt, unsigned int handler, struct segoff *chain_vector ); extern int unhook_bios_interrupt ( unsigned int interrupt, diff --git a/gpxe/src/arch/i386/include/bits/byteswap.h b/gpxe/src/arch/i386/include/bits/byteswap.h index 54b93ab9..98418c29 100644 --- a/gpxe/src/arch/i386/include/bits/byteswap.h +++ b/gpxe/src/arch/i386/include/bits/byteswap.h @@ -2,7 +2,7 @@ #define ETHERBOOT_BITS_BYTESWAP_H static inline __attribute__ ((always_inline, const)) uint16_t -__i386_bswap_16(uint16_t x) +__bswap_variable_16(uint16_t x) { __asm__("xchgb %b0,%h0\n\t" : "=q" (x) @@ -11,7 +11,7 @@ __i386_bswap_16(uint16_t x) } static inline __attribute__ ((always_inline, const)) uint32_t -__i386_bswap_32(uint32_t x) +__bswap_variable_32(uint32_t x) { __asm__("xchgb %b0,%h0\n\t" "rorl $16,%0\n\t" @@ -22,7 +22,7 @@ __i386_bswap_32(uint32_t x) } static inline __attribute__ ((always_inline, const)) uint64_t -__i386_bswap_64(uint64_t x) +__bswap_variable_64(uint64_t x) { union { uint64_t qword; @@ -30,47 +30,12 @@ __i386_bswap_64(uint64_t x) } u; u.qword = x; - u.dword[0] = __i386_bswap_32(u.dword[0]); - u.dword[1] = __i386_bswap_32(u.dword[1]); + u.dword[0] = __bswap_variable_32(u.dword[0]); + u.dword[1] = __bswap_variable_32(u.dword[1]); __asm__("xchgl %0,%1" : "=r" ( u.dword[0] ), "=r" ( u.dword[1] ) : "0" ( u.dword[0] ), "1" ( u.dword[1] ) ); return u.qword; } -#define __bswap_constant_16(x) \ - ((uint16_t)((((uint16_t)(x) & 0x00ff) << 8) | \ - (((uint16_t)(x) & 0xff00) >> 8))) - -#define __bswap_constant_32(x) \ - ((uint32_t)((((uint32_t)(x) & 0x000000ffU) << 24) | \ - (((uint32_t)(x) & 0x0000ff00U) << 8) | \ - (((uint32_t)(x) & 0x00ff0000U) >> 8) | \ - (((uint32_t)(x) & 0xff000000U) >> 24))) - -#define __bswap_constant_64(x) \ - ((uint64_t)((((uint64_t)(x) & 0x00000000000000ffULL) << 56) | \ - (((uint64_t)(x) & 0x000000000000ff00ULL) << 40) | \ - (((uint64_t)(x) & 0x0000000000ff0000ULL) << 24) | \ - (((uint64_t)(x) & 0x00000000ff000000ULL) << 8) | \ - (((uint64_t)(x) & 0x000000ff00000000ULL) >> 8) | \ - (((uint64_t)(x) & 0x0000ff0000000000ULL) >> 24) | \ - (((uint64_t)(x) & 0x00ff000000000000ULL) >> 40) | \ - (((uint64_t)(x) & 0xff00000000000000ULL) >> 56))) - -#define __bswap_16(x) \ - ((uint16_t)(__builtin_constant_p(x) ? \ - __bswap_constant_16(x) : \ - __i386_bswap_16(x))) - -#define __bswap_32(x) \ - ((uint32_t)(__builtin_constant_p(x) ? \ - __bswap_constant_32(x) : \ - __i386_bswap_32(x))) - -#define __bswap_64(x) \ - ((uint64_t)(__builtin_constant_p(x) ? \ - __bswap_constant_64(x) : \ - __i386_bswap_64(x))) - #endif /* ETHERBOOT_BITS_BYTESWAP_H */ diff --git a/gpxe/src/arch/i386/include/bits/compiler.h b/gpxe/src/arch/i386/include/bits/compiler.h new file mode 100644 index 00000000..119a9a21 --- /dev/null +++ b/gpxe/src/arch/i386/include/bits/compiler.h @@ -0,0 +1,25 @@ +#ifndef _BITS_COMPILER_H +#define _BITS_COMPILER_H + +#ifndef ASSEMBLY + +/** Declare a function with standard calling conventions */ +#define __asmcall __attribute__ (( cdecl, regparm(0) )) + +/** + * Declare a function with libgcc implicit linkage + * + * It seems as though gcc expects its implicit arithmetic functions to + * be cdecl, even if -mrtd is specified. This is somewhat + * inconsistent; for example, if -mregparm=3 is used then the implicit + * functions do become regparm(3). + * + * 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. + */ +#define __libgcc __attribute__ (( cdecl )) + +#endif /* ASSEMBLY */ + +#endif /* _BITS_COMPILER_H */ diff --git a/gpxe/src/arch/i386/include/bits/elf.h b/gpxe/src/arch/i386/include/bits/elf.h deleted file mode 100644 index dad9c7b8..00000000 --- a/gpxe/src/arch/i386/include/bits/elf.h +++ /dev/null @@ -1,91 +0,0 @@ -#ifndef I386_BITS_ELF_H -#define I386_BITS_ELF_H - -#include "cpu.h" - -#ifdef CONFIG_X86_64 -/* ELF Defines for the 64bit version of the current architecture */ -#define EM_CURRENT_64 EM_X86_64 -#define EM_CURRENT_64_PRESENT ( \ - CPU_FEATURE_P(cpu_info.x86_capability, LM) && \ - CPU_FEATURE_P(cpu_info.x86_capability, PAE) && \ - CPU_FEATURE_P(cpu_info.x86_capability, PSE)) - -#define ELF_CHECK_X86_64_ARCH(x) \ - (EM_CURRENT_64_PRESENT && ((x).e_machine == EM_X86_64)) -#define __unused_i386 -#else -#define ELF_CHECK_X86_64_ARCH(x) 0 -#define __unused_i386 __unused -#endif - - -/* ELF Defines for the current architecture */ -#define EM_CURRENT EM_386 -#define ELFDATA_CURRENT ELFDATA2LSB - -#define ELF_CHECK_I386_ARCH(x) \ - (((x).e_machine == EM_386) || ((x).e_machine == EM_486)) - -#define ELF_CHECK_ARCH(x) \ - ((ELF_CHECK_I386_ARCH(x) || ELF_CHECK_X86_64_ARCH(x)) && \ - ((x).e_entry <= 0xffffffffUL)) - -#ifdef IMAGE_FREEBSD -/* - * FreeBSD has this rather strange "feature" of its design. - * At some point in its evolution, FreeBSD started to rely - * externally on private/static/debug internal symbol information. - * That is, some of the interfaces that software uses to access - * and work with the FreeBSD kernel are made available not - * via the shared library symbol information (the .DYNAMIC section) - * but rather the debug symbols. This means that any symbol, not - * just publicly defined symbols can be (and are) used by system - * tools to make the system work. (such as top, swapinfo, swapon, - * etc) - * - * Even worse, however, is the fact that standard ELF loaders do - * not know how to load the symbols since they are not within - * an ELF PT_LOAD section. The kernel needs these symbols to - * operate so the following changes/additions to the boot - * loading of EtherBoot have been made to get the kernel to load. - * All of the changes are within IMAGE_FREEBSD such that the - * extra/changed code only compiles when FREEBSD support is - * enabled. - */ - -/* - * Section header for FreeBSD (debug symbol kludge!) support - */ -typedef struct { - Elf32_Word sh_name; /* Section name (index into the - section header string table). */ - Elf32_Word sh_type; /* Section type. */ - Elf32_Word sh_flags; /* Section flags. */ - Elf32_Addr sh_addr; /* Address in memory image. */ - Elf32_Off sh_offset; /* Offset in file. */ - Elf32_Size sh_size; /* Size in bytes. */ - Elf32_Word sh_link; /* Index of a related section. */ - Elf32_Word sh_info; /* Depends on section type. */ - Elf32_Size sh_addralign; /* Alignment in bytes. */ - Elf32_Size sh_entsize; /* Size of each entry in section. */ -} Elf32_Shdr; - -/* sh_type */ -#define SHT_SYMTAB 2 /* symbol table section */ -#define SHT_STRTAB 3 /* string table section */ - -/* - * Module information subtypes (for the metadata that we need to build) - */ -#define MODINFO_END 0x0000 /* End of list */ -#define MODINFO_NAME 0x0001 /* Name of module (string) */ -#define MODINFO_TYPE 0x0002 /* Type of module (string) */ -#define MODINFO_METADATA 0x8000 /* Module-specfic */ - -#define MODINFOMD_SSYM 0x0003 /* start of symbols */ -#define MODINFOMD_ESYM 0x0004 /* end of symbols */ - -#endif /* IMAGE_FREEBSD */ - -#endif /* I386_BITS_ELF_H */ diff --git a/gpxe/src/arch/i386/include/bits/elf_x.h b/gpxe/src/arch/i386/include/bits/elf_x.h deleted file mode 100644 index 86c67250..00000000 --- a/gpxe/src/arch/i386/include/bits/elf_x.h +++ /dev/null @@ -1,5 +0,0 @@ -#define ARCH_ELF_CLASS ELFCLASS32 -#define ARCH_ELF_DATA ELFDATA2LSB -#define ARCH_ELF_MACHINE_OK(x) ((x)==EM_386 || (x)==EM_486) -typedef Elf32_Ehdr Elf_ehdr; -typedef Elf32_Phdr Elf_phdr; diff --git a/gpxe/src/arch/i386/include/bits/errfile.h b/gpxe/src/arch/i386/include/bits/errfile.h index 99927c28..5ea8a318 100644 --- a/gpxe/src/arch/i386/include/bits/errfile.h +++ b/gpxe/src/arch/i386/include/bits/errfile.h @@ -6,13 +6,12 @@ * @{ */ -#define ERRFILE_umalloc ( ERRFILE_ARCH | ERRFILE_CORE | 0x00000000 ) +#define ERRFILE_memtop_umalloc ( ERRFILE_ARCH | ERRFILE_CORE | 0x00000000 ) #define ERRFILE_memmap ( ERRFILE_ARCH | ERRFILE_CORE | 0x00010000 ) #define ERRFILE_pnpbios ( ERRFILE_ARCH | ERRFILE_CORE | 0x00020000 ) -#define ERRFILE_smbios ( ERRFILE_ARCH | ERRFILE_CORE | 0x00030000 ) +#define ERRFILE_bios_smbios ( ERRFILE_ARCH | ERRFILE_CORE | 0x00030000 ) #define ERRFILE_biosint ( ERRFILE_ARCH | ERRFILE_CORE | 0x00040000 ) #define ERRFILE_int13 ( ERRFILE_ARCH | ERRFILE_CORE | 0x00050000 ) -#define ERRFILE_smbios_settings ( ERRFILE_ARCH | ERRFILE_CORE | 0x00060000 ) #define ERRFILE_bootsector ( ERRFILE_ARCH | ERRFILE_IMAGE | 0x00000000 ) #define ERRFILE_bzimage ( ERRFILE_ARCH | ERRFILE_IMAGE | 0x00010000 ) @@ -24,6 +23,7 @@ #define ERRFILE_comboot ( ERRFILE_ARCH | ERRFILE_IMAGE | 0x00070000 ) #define ERRFILE_com32 ( ERRFILE_ARCH | ERRFILE_IMAGE | 0x00080000 ) #define ERRFILE_comboot_resolv ( ERRFILE_ARCH | ERRFILE_IMAGE | 0x00090000 ) +#define ERRFILE_comboot_call ( ERRFILE_ARCH | ERRFILE_IMAGE | 0x000a0000 ) #define ERRFILE_undi ( ERRFILE_ARCH | ERRFILE_NET | 0x00000000 ) #define ERRFILE_undiload ( ERRFILE_ARCH | ERRFILE_NET | 0x00010000 ) diff --git a/gpxe/src/arch/i386/include/bits/io.h b/gpxe/src/arch/i386/include/bits/io.h new file mode 100644 index 00000000..dd0ee444 --- /dev/null +++ b/gpxe/src/arch/i386/include/bits/io.h @@ -0,0 +1,12 @@ +#ifndef _BITS_IO_H +#define _BITS_IO_H + +/** @file + * + * i386-specific I/O API implementations + * + */ + +#include <gpxe/x86_io.h> + +#endif /* _BITS_IO_H */ diff --git a/gpxe/src/arch/i386/include/bits/nap.h b/gpxe/src/arch/i386/include/bits/nap.h new file mode 100644 index 00000000..f8ba7a7c --- /dev/null +++ b/gpxe/src/arch/i386/include/bits/nap.h @@ -0,0 +1,13 @@ +#ifndef _BITS_NAP_H +#define _BITS_NAP_H + +/** @file + * + * i386-specific CPU sleeping API implementations + * + */ + +#include <gpxe/bios_nap.h> +#include <gpxe/efi/efix86_nap.h> + +#endif /* _BITS_MAP_H */ diff --git a/gpxe/src/arch/i386/include/bits/smbios.h b/gpxe/src/arch/i386/include/bits/smbios.h new file mode 100644 index 00000000..647ea19e --- /dev/null +++ b/gpxe/src/arch/i386/include/bits/smbios.h @@ -0,0 +1,12 @@ +#ifndef _BITS_SMBIOS_H +#define _BITS_SMBIOS_H + +/** @file + * + * i386-specific SMBIOS API implementations + * + */ + +#include <gpxe/bios_smbios.h> + +#endif /* _BITS_SMBIOS_H */ diff --git a/gpxe/src/arch/i386/include/bits/stdint.h b/gpxe/src/arch/i386/include/bits/stdint.h index a2947cda..6ccf0971 100644 --- a/gpxe/src/arch/i386/include/bits/stdint.h +++ b/gpxe/src/arch/i386/include/bits/stdint.h @@ -1,18 +1,18 @@ #ifndef _BITS_STDINT_H #define _BITS_STDINT_H -typedef typeof(sizeof(int)) size_t; -typedef signed long ssize_t; +typedef unsigned int size_t; +typedef signed int ssize_t; typedef signed long off_t; typedef unsigned char uint8_t; typedef unsigned short uint16_t; -typedef unsigned long uint32_t; +typedef unsigned int uint32_t; typedef unsigned long long uint64_t; typedef signed char int8_t; typedef signed short int16_t; -typedef signed long int32_t; +typedef signed int int32_t; typedef signed long long int64_t; typedef unsigned long physaddr_t; diff --git a/gpxe/src/arch/i386/include/bits/timer.h b/gpxe/src/arch/i386/include/bits/timer.h new file mode 100644 index 00000000..99666d84 --- /dev/null +++ b/gpxe/src/arch/i386/include/bits/timer.h @@ -0,0 +1,13 @@ +#ifndef _BITS_TIMER_H +#define _BITS_TIMER_H + +/** @file + * + * i386-specific timer API implementations + * + */ + +#include <gpxe/bios_timer.h> +#include <gpxe/rdtsc_timer.h> + +#endif /* _BITS_TIMER_H */ diff --git a/gpxe/src/arch/i386/include/bits/timer2.h b/gpxe/src/arch/i386/include/bits/timer2.h deleted file mode 100644 index 83923b29..00000000 --- a/gpxe/src/arch/i386/include/bits/timer2.h +++ /dev/null @@ -1,8 +0,0 @@ -#ifndef BITS_TIMER2_H -#define BITS_TIMER2_H - -#include <stddef.h> - -void i386_timer2_udelay(unsigned int usecs); - -#endif diff --git a/gpxe/src/arch/i386/include/bits/uaccess.h b/gpxe/src/arch/i386/include/bits/uaccess.h index 9c6d0c21..0ecc5028 100644 --- a/gpxe/src/arch/i386/include/bits/uaccess.h +++ b/gpxe/src/arch/i386/include/bits/uaccess.h @@ -1,6 +1,12 @@ #ifndef _BITS_UACCESS_H #define _BITS_UACCESS_H -#include <realmode.h> +/** @file + * + * i386-specific user access API implementations + * + */ + +#include <librm.h> #endif /* _BITS_UACCESS_H */ diff --git a/gpxe/src/arch/i386/include/bits/umalloc.h b/gpxe/src/arch/i386/include/bits/umalloc.h new file mode 100644 index 00000000..dcbd0a6b --- /dev/null +++ b/gpxe/src/arch/i386/include/bits/umalloc.h @@ -0,0 +1,12 @@ +#ifndef _BITS_UMALLOC_H +#define _BITS_UMALLOC_H + +/** @file + * + * i386-specific user memory allocation API implementations + * + */ + +#include <gpxe/memtop_umalloc.h> + +#endif /* _BITS_UMALLOC_H */ diff --git a/gpxe/src/arch/i386/include/comboot.h b/gpxe/src/arch/i386/include/comboot.h index 1fc3b718..56661a80 100644 --- a/gpxe/src/arch/i386/include/comboot.h +++ b/gpxe/src/arch/i386/include/comboot.h @@ -58,12 +58,47 @@ typedef struct { } com32sys_t; typedef struct { + uint32_t eax; /* Offset 0 */ + uint32_t ecx; /* Offset 4 */ + uint32_t edx; /* Offset 8 */ + uint32_t ebx; /* Offset 12 */ + uint32_t esp; /* Offset 16 */ + uint32_t ebp; /* Offset 20 */ + uint32_t esi; /* Offset 24 */ + uint32_t edi; /* Offset 28 */ + + uint32_t eip; /* Offset 32 */ +} syslinux_pm_regs; + +typedef struct { + uint16_t es; /* Offset 0 */ + uint16_t _unused_cs; /* Offset 2 */ + uint16_t ds; /* Offset 4 */ + uint16_t ss; /* Offset 6 */ + uint16_t fs; /* Offset 8 */ + uint16_t gs; /* Offset 10 */ + + uint32_t eax; /* Offset 12 */ + uint32_t ecx; /* Offset 16 */ + uint32_t edx; /* Offset 20 */ + uint32_t ebx; /* Offset 24 */ + uint32_t esp; /* Offset 28 */ + uint32_t ebp; /* Offset 32 */ + uint32_t esi; /* Offset 36 */ + uint32_t edi; /* Offset 40 */ + + uint16_t ip; /* Offset 44 */ + uint16_t cs; /* Offset 46 */ +} syslinux_rm_regs; + +typedef struct { uint32_t dest; uint32_t src; uint32_t len; } comboot_shuffle_descriptor; extern void hook_comboot_interrupts ( ); +extern void unhook_comboot_interrupts ( ); /* These are not the correct prototypes, but it doens't matter, * as we only ever get the address of these functions; @@ -77,20 +112,16 @@ extern void com32_cfarcall_wrapper ( ); extern int comboot_resolv ( const char *name, struct in_addr *address ); /* setjmp/longjmp context buffer used to return after loading an image */ -extern jmp_buf comboot_return; - -/* Command line to execute when returning via comboot_return - * with COMBOOT_RETURN_RUN_KERNEL - */ -extern char *comboot_kernel_cmdline; +extern rmjmp_buf comboot_return; -/* Execute comboot_image_cmdline */ -extern void comboot_run_kernel ( ); +/* Replacement image when exiting with COMBOOT_EXIT_RUN_KERNEL */ +extern struct image *comboot_replacement_image; extern void *com32_external_esp; -#define COMBOOT_RETURN_EXIT 1 -#define COMBOOT_RETURN_RUN_KERNEL 2 +#define COMBOOT_EXIT 1 +#define COMBOOT_EXIT_RUN_KERNEL 2 +#define COMBOOT_EXIT_COMMAND 3 extern void comboot_force_text_mode ( void ); diff --git a/gpxe/src/arch/i386/include/gdbmach.h b/gpxe/src/arch/i386/include/gdbmach.h index 1a38ccd1..794dab19 100644 --- a/gpxe/src/arch/i386/include/gdbmach.h +++ b/gpxe/src/arch/i386/include/gdbmach.h @@ -12,7 +12,7 @@ #include <stdint.h> -typedef uint32_t gdbreg_t; +typedef unsigned long gdbreg_t; /* The register snapshot, this must be in sync with interrupt handler and the * GDB protocol. */ diff --git a/gpxe/src/include/gpxe/abft.h b/gpxe/src/arch/i386/include/gpxe/abft.h index 1c651ef1..1c651ef1 100644 --- a/gpxe/src/include/gpxe/abft.h +++ b/gpxe/src/arch/i386/include/gpxe/abft.h diff --git a/gpxe/src/arch/i386/include/gpxe/bios_nap.h b/gpxe/src/arch/i386/include/gpxe/bios_nap.h new file mode 100644 index 00000000..f1c721e9 --- /dev/null +++ b/gpxe/src/arch/i386/include/gpxe/bios_nap.h @@ -0,0 +1,16 @@ +#ifndef _GPXE_BIOS_NAP_H +#define _GPXE_BIOS_NAP_H + +/** @file + * + * BIOS CPU sleeping + * + */ + +#ifdef NAP_PCBIOS +#define NAP_PREFIX_pcbios +#else +#define NAP_PREFIX_pcbios __pcbios_ +#endif + +#endif /* _GPXE_BIOS_NAP_H */ diff --git a/gpxe/src/arch/i386/include/gpxe/bios_smbios.h b/gpxe/src/arch/i386/include/gpxe/bios_smbios.h new file mode 100644 index 00000000..0a6f277a --- /dev/null +++ b/gpxe/src/arch/i386/include/gpxe/bios_smbios.h @@ -0,0 +1,16 @@ +#ifndef _GPXE_BIOS_SMBIOS_H +#define _GPXE_BIOS_SMBIOS_H + +/** @file + * + * Standard PC-BIOS SMBIOS interface + * + */ + +#ifdef SMBIOS_PCBIOS +#define SMBIOS_PREFIX_pcbios +#else +#define SMBIOS_PREFIX_pcbios __pcbios_ +#endif + +#endif /* _GPXE_BIOS_SMBIOS_H */ diff --git a/gpxe/src/arch/i386/include/gpxe/bios_timer.h b/gpxe/src/arch/i386/include/gpxe/bios_timer.h new file mode 100644 index 00000000..7e3caa3c --- /dev/null +++ b/gpxe/src/arch/i386/include/gpxe/bios_timer.h @@ -0,0 +1,42 @@ +#ifndef _GPXE_BIOS_TIMER_H +#define _GPXE_BIOS_TIMER_H + +/** @file + * + * BIOS timer + * + */ + +#ifdef TIMER_PCBIOS +#define TIMER_PREFIX_pcbios +#else +#define TIMER_PREFIX_pcbios __pcbios_ +#endif + +#include <gpxe/timer2.h> + +/** + * Delay for a fixed number of microseconds + * + * @v usecs Number of microseconds for which to delay + */ +static inline __always_inline void +TIMER_INLINE ( pcbios, udelay ) ( unsigned long usecs ) { + /* BIOS timer is not high-resolution enough for udelay(), so + * we use timer2 + */ + timer2_udelay ( usecs ); +} + +/** + * Get number of ticks per second + * + * @ret ticks_per_sec Number of ticks per second + */ +static inline __always_inline unsigned long +TIMER_INLINE ( pcbios, ticks_per_sec ) ( void ) { + /* BIOS timer ticks over at 18.2 ticks per second */ + return 18; +} + +#endif /* _GPXE_BIOS_TIMER_H */ diff --git a/gpxe/src/include/gpxe/ibft.h b/gpxe/src/arch/i386/include/gpxe/ibft.h index 5eef547b..5eef547b 100644 --- a/gpxe/src/include/gpxe/ibft.h +++ b/gpxe/src/arch/i386/include/gpxe/ibft.h diff --git a/gpxe/src/arch/i386/include/gpxe/memtop_umalloc.h b/gpxe/src/arch/i386/include/gpxe/memtop_umalloc.h new file mode 100644 index 00000000..a3cd2c01 --- /dev/null +++ b/gpxe/src/arch/i386/include/gpxe/memtop_umalloc.h @@ -0,0 +1,16 @@ +#ifndef _GPXE_MEMTOP_UMALLOC_H +#define _GPXE_MEMTOP_UMALLOC_H + +/** @file + * + * External memory allocation + * + */ + +#ifdef UMALLOC_MEMTOP +#define UMALLOC_PREFIX_memtop +#else +#define UMALLOC_PREFIX_memtop __memtop_ +#endif + +#endif /* _GPXE_MEMTOP_UMALLOC_H */ diff --git a/gpxe/src/arch/i386/include/gpxe/rdtsc_timer.h b/gpxe/src/arch/i386/include/gpxe/rdtsc_timer.h new file mode 100644 index 00000000..0e03d707 --- /dev/null +++ b/gpxe/src/arch/i386/include/gpxe/rdtsc_timer.h @@ -0,0 +1,37 @@ +#ifndef _GPXE_RDTSC_TIMER_H +#define _GPXE_RDTSC_TIMER_H + +/** @file + * + * RDTSC timer + * + */ + +#ifdef TIMER_RDTSC +#define TIMER_PREFIX_rdtsc +#else +#define TIMER_PREFIX_rdtsc __rdtsc_ +#endif + +/** + * RDTSC values can easily overflow an unsigned long. We discard the + * low-order bits in order to obtain sensibly-scaled values. + */ +#define TSC_SHIFT 8 + +/** + * Get current system time in ticks + * + * @ret ticks Current time, in ticks + */ +static inline __always_inline unsigned long +TIMER_INLINE ( rdtsc, currticks ) ( void ) { + unsigned long ticks; + + __asm__ __volatile__ ( "rdtsc\n\t" + "shrdl %1, %%edx, %%eax\n\t" + : "=a" ( ticks ) : "i" ( TSC_SHIFT ) : "edx" ); + return ticks; +} + +#endif /* _GPXE_RDTSC_TIMER_H */ diff --git a/gpxe/src/arch/i386/include/gpxe/timer2.h b/gpxe/src/arch/i386/include/gpxe/timer2.h new file mode 100644 index 00000000..59705fa2 --- /dev/null +++ b/gpxe/src/arch/i386/include/gpxe/timer2.h @@ -0,0 +1,12 @@ +#ifndef _GPXE_TIMER2_H +#define _GPXE_TIMER2_H + +/** @file + * + * Timer chip control + * + */ + +extern void timer2_udelay ( unsigned long usecs ); + +#endif /* _GPXE_TIMER2_H */ diff --git a/gpxe/src/arch/i386/include/gpxe/x86_io.h b/gpxe/src/arch/i386/include/gpxe/x86_io.h new file mode 100644 index 00000000..b1ae3bac --- /dev/null +++ b/gpxe/src/arch/i386/include/gpxe/x86_io.h @@ -0,0 +1,151 @@ +#ifndef _GPXE_X86_IO_H +#define _GPXE_X86_IO_H + +/** @file + * + * gPXE I/O API for x86 + * + * i386 uses direct pointer dereferences for accesses to memory-mapped + * I/O space, and the inX/outX instructions for accesses to + * port-mapped I/O space. + * + * 64-bit atomic accesses (readq() and writeq()) use MMX instructions, + * and will crash original Pentium and earlier CPUs. Fortunately, no + * hardware that requires atomic 64-bit accesses will physically fit + * into a machine with such an old CPU anyway. + */ + +#ifdef IOAPI_X86 +#define IOAPI_PREFIX_x86 +#else +#define IOAPI_PREFIX_x86 __x86_ +#endif + +/* + * Memory space mappings + * + */ + +/* + * Physical<->Bus and Bus<->I/O address mappings + * + */ + +static inline __always_inline unsigned long +IOAPI_INLINE ( x86, phys_to_bus ) ( unsigned long phys_addr ) { + return phys_addr; +} + +static inline __always_inline unsigned long +IOAPI_INLINE ( x86, bus_to_phys ) ( unsigned long bus_addr ) { + return bus_addr; +} + +static inline __always_inline void * +IOAPI_INLINE ( x86, ioremap ) ( unsigned long bus_addr, size_t len __unused ) { + return phys_to_virt ( bus_addr ); +} + +static inline __always_inline void +IOAPI_INLINE ( x86, iounmap ) ( volatile const void *io_addr __unused ) { + /* Nothing to do */ +} + +static inline __always_inline unsigned long +IOAPI_INLINE ( x86, io_to_bus ) ( volatile const void *io_addr ) { + return virt_to_phys ( io_addr ); +} + +/* + * MMIO reads and writes up to 32 bits + * + */ + +#define X86_READX( _api_func, _type ) \ +static inline __always_inline _type \ +IOAPI_INLINE ( x86, _api_func ) ( volatile _type *io_addr ) { \ + return *io_addr; \ +} +X86_READX ( readb, uint8_t ); +X86_READX ( readw, uint16_t ); +X86_READX ( readl, uint32_t ); + +#define X86_WRITEX( _api_func, _type ) \ +static inline __always_inline void \ +IOAPI_INLINE ( x86, _api_func ) ( _type data, \ + volatile _type *io_addr ) { \ + *io_addr = data; \ +} +X86_WRITEX ( writeb, uint8_t ); +X86_WRITEX ( writew, uint16_t ); +X86_WRITEX ( writel, uint32_t ); + +/* + * PIO reads and writes up to 32 bits + * + */ + +#define X86_INX( _insn_suffix, _type, _reg_prefix ) \ +static inline __always_inline _type \ +IOAPI_INLINE ( x86, in ## _insn_suffix ) ( volatile _type *io_addr ) { \ + _type data; \ + __asm__ __volatile__ ( "in" #_insn_suffix " %w1, %" _reg_prefix "0" \ + : "=a" ( data ) : "Nd" ( io_addr ) ); \ + return data; \ +} \ +static inline __always_inline void \ +IOAPI_INLINE ( x86, ins ## _insn_suffix ) ( volatile _type *io_addr, \ + _type *data, \ + unsigned int count ) { \ + unsigned int discard_D; \ + __asm__ __volatile__ ( "rep ins" #_insn_suffix \ + : "=D" ( discard_D ) \ + : "d" ( io_addr ), "c" ( count ), \ + "0" ( data ) ); \ +} +X86_INX ( b, uint8_t, "b" ); +X86_INX ( w, uint16_t, "w" ); +X86_INX ( l, uint32_t, "k" ); + +#define X86_OUTX( _insn_suffix, _type, _reg_prefix ) \ +static inline __always_inline void \ +IOAPI_INLINE ( x86, out ## _insn_suffix ) ( _type data, \ + volatile _type *io_addr ) { \ + __asm__ __volatile__ ( "out" #_insn_suffix " %" _reg_prefix "0, %w1" \ + : : "a" ( data ), "Nd" ( io_addr ) ); \ +} \ +static inline __always_inline void \ +IOAPI_INLINE ( x86, outs ## _insn_suffix ) ( volatile _type *io_addr, \ + const _type *data, \ + unsigned int count ) { \ + unsigned int discard_S; \ + __asm__ __volatile__ ( "rep outs" #_insn_suffix \ + : "=S" ( discard_S ) \ + : "d" ( io_addr ), "c" ( count ), \ + "0" ( data ) ); \ +} +X86_OUTX ( b, uint8_t, "b" ); +X86_OUTX ( w, uint16_t, "w" ); +X86_OUTX ( l, uint32_t, "k" ); + +/* + * Slow down I/O + * + */ + +static inline __always_inline void +IOAPI_INLINE ( x86, iodelay ) ( void ) { + __asm__ __volatile__ ( "outb %al, $0x80" ); +} + +/* + * Memory barrier + * + */ + +static inline __always_inline void +IOAPI_INLINE ( x86, mb ) ( void ) { + __asm__ __volatile__ ( "lock; addl $0, 0(%%esp)" : : : "memory" ); +} + +#endif /* _GPXE_X86_IO_H */ diff --git a/gpxe/src/arch/i386/include/int13.h b/gpxe/src/arch/i386/include/int13.h index 72ca97d7..bf6d0318 100644 --- a/gpxe/src/arch/i386/include/int13.h +++ b/gpxe/src/arch/i386/include/int13.h @@ -9,6 +9,7 @@ #include <stdint.h> #include <gpxe/list.h> +#include <realmode.h> struct block_device; diff --git a/gpxe/src/arch/i386/include/io.h b/gpxe/src/arch/i386/include/io.h deleted file mode 100644 index c26fdf7e..00000000 --- a/gpxe/src/arch/i386/include/io.h +++ /dev/null @@ -1,265 +0,0 @@ -#ifndef ETHERBOOT_IO_H -#define ETHERBOOT_IO_H - -#include <stdint.h> -#include "virtaddr.h" - -/* virt_to_bus converts an addresss inside of etherboot [_start, _end] - * into a memory access cards can use. - */ -#define virt_to_bus virt_to_phys - - -/* bus_to_virt reverses virt_to_bus, the address must be output - * from virt_to_bus to be valid. This function does not work on - * all bus addresses. - */ -#define bus_to_virt phys_to_virt - -/* ioremap converts a random 32bit bus address into something - * etherboot can access. - */ -static inline void *ioremap(unsigned long bus_addr, unsigned long length __unused) -{ - return bus_to_virt(bus_addr); -} - -/* iounmap cleans up anything ioremap had to setup */ -static inline void iounmap(void *virt_addr __unused) -{ - return; -} - -/* - * This file contains the definitions for the x86 IO instructions - * inb/inw/inl/outb/outw/outl and the "string versions" of the same - * (insb/insw/insl/outsb/outsw/outsl). You can also use "pausing" - * versions of the single-IO instructions (inb_p/inw_p/..). - * - * This file is not meant to be obfuscating: it's just complicated - * to (a) handle it all in a way that makes gcc able to optimize it - * as well as possible and (b) trying to avoid writing the same thing - * over and over again with slight variations and possibly making a - * mistake somewhere. - */ - -/* - * Thanks to James van Artsdalen for a better timing-fix than - * the two short jumps: using outb's to a nonexistent port seems - * to guarantee better timings even on fast machines. - * - * On the other hand, I'd like to be sure of a non-existent port: - * I feel a bit unsafe about using 0x80 (should be safe, though) - * - * Linus - */ - -#ifdef SLOW_IO_BY_JUMPING -#define __SLOW_DOWN_IO __asm__ __volatile__("jmp 1f\n1:\tjmp 1f\n1:") -#else -#define __SLOW_DOWN_IO __asm__ __volatile__("outb %al,$0x80") -#endif - -#ifdef REALLY_SLOW_IO -#define SLOW_DOWN_IO { __SLOW_DOWN_IO; __SLOW_DOWN_IO; __SLOW_DOWN_IO; __SLOW_DOWN_IO; } -#else -#define SLOW_DOWN_IO __SLOW_DOWN_IO -#endif - -/* - * readX/writeX() are used to access memory mapped devices. On some - * architectures the memory mapped IO stuff needs to be accessed - * differently. On the x86 architecture, we just read/write the - * memory location directly. - */ -static inline __attribute__ (( always_inline )) unsigned long -_readb ( volatile uint8_t *addr ) { - unsigned long data = *addr; - DBGIO ( "[%08lx] => %02lx\n", virt_to_phys ( addr ), data ); - return data; -} -static inline __attribute__ (( always_inline )) unsigned long -_readw ( volatile uint16_t *addr ) { - unsigned long data = *addr; - DBGIO ( "[%08lx] => %04lx\n", virt_to_phys ( addr ), data ); - return data; -} -static inline __attribute__ (( always_inline )) unsigned long -_readl ( volatile uint32_t *addr ) { - unsigned long data = *addr; - DBGIO ( "[%08lx] => %08lx\n", virt_to_phys ( addr ), data ); - return data; -} -#define readb( addr ) _readb ( ( volatile uint8_t * ) (addr) ) -#define readw( addr ) _readw ( ( volatile uint16_t * ) (addr) ) -#define readl( addr ) _readl ( ( volatile uint32_t * ) (addr) ) - -static inline __attribute__ (( always_inline )) void -_writeb ( unsigned long data, volatile uint8_t *addr ) { - DBGIO ( "[%08lx] <= %02lx\n", virt_to_phys ( addr ), data ); - *addr = data; -} -static inline __attribute__ (( always_inline )) void -_writew ( unsigned long data, volatile uint16_t *addr ) { - DBGIO ( "[%08lx] <= %04lx\n", virt_to_phys ( addr ), data ); - *addr = data; -} -static inline __attribute__ (( always_inline )) void -_writel ( unsigned long data, volatile uint32_t *addr ) { - DBGIO ( "[%08lx] <= %08lx\n", virt_to_phys ( addr ), data ); - *addr = data; -} -#define writeb( b, addr ) _writeb ( (b), ( volatile uint8_t * ) (addr) ) -#define writew( b, addr ) _writew ( (b), ( volatile uint16_t * ) (addr) ) -#define writel( b, addr ) _writel ( (b), ( volatile uint32_t * ) (addr) ) - -#define memcpy_fromio(a,b,c) memcpy((a),(void *)(b),(c)) -#define memcpy_toio(a,b,c) memcpy((void *)(a),(b),(c)) - -/* - * Force strict CPU ordering. - * And yes, this is required on UP too when we're talking - * to devices. - * - * For now, "wmb()" doesn't actually do anything, as all - * Intel CPU's follow what Intel calls a *Processor Order*, - * in which all writes are seen in the program order even - * outside the CPU. - * - * I expect future Intel CPU's to have a weaker ordering, - * but I'd also expect them to finally get their act together - * and add some real memory barriers if so. - * - * Some non intel clones support out of order store. wmb() ceases to be a - * nop for these. - */ - -#define mb() __asm__ __volatile__ ("lock; addl $0,0(%%esp)": : :"memory") -#define rmb() mb() -#define wmb() mb(); - - -/* - * Talk about misusing macros.. - */ - -#define __OUT1(s,x) \ -extern void __out##s(unsigned x value, unsigned short port); \ -extern inline void __out##s(unsigned x value, unsigned short port) { - -#define __OUT2(s,s1,s2) \ -__asm__ __volatile__ ("out" #s " %" s1 "0,%" s2 "1" - -#define __OUT(s,s1,x) \ -__OUT1(s,x) __OUT2(s,s1,"w") : : "a" (value), "d" (port)); } \ -__OUT1(s##c,x) __OUT2(s,s1,"") : : "a" (value), "id" (port)); } \ -__OUT1(s##_p,x) __OUT2(s,s1,"w") : : "a" (value), "d" (port)); SLOW_DOWN_IO; } \ -__OUT1(s##c_p,x) __OUT2(s,s1,"") : : "a" (value), "id" (port)); SLOW_DOWN_IO; } - -#define __IN1(s,x) \ -extern unsigned x __in##s(unsigned short port); \ -extern inline unsigned x __in##s(unsigned short port) { unsigned x _v; - -#define __IN2(s,s1,s2) \ -__asm__ __volatile__ ("in" #s " %" s2 "1,%" s1 "0" - -#define __IN(s,s1,x,i...) \ -__IN1(s,x) __IN2(s,s1,"w") : "=a" (_v) : "d" (port) ,##i ); return _v; } \ -__IN1(s##c,x) __IN2(s,s1,"") : "=a" (_v) : "id" (port) ,##i ); return _v; } \ -__IN1(s##_p,x) __IN2(s,s1,"w") : "=a" (_v) : "d" (port) ,##i ); SLOW_DOWN_IO; return _v; } \ -__IN1(s##c_p,x) __IN2(s,s1,"") : "=a" (_v) : "id" (port) ,##i ); SLOW_DOWN_IO; return _v; } - -#define __INS(s) \ -extern void ins##s(unsigned short port, void * addr, unsigned long count); \ -extern inline void ins##s(unsigned short port, void * addr, unsigned long count) \ -{ __asm__ __volatile__ ("cld ; rep ; ins" #s \ -: "=D" (addr), "=c" (count) : "d" (port),"0" (addr),"1" (count)); } - -#define __OUTS(s) \ -extern void outs##s(unsigned short port, const void * addr, unsigned long count); \ -extern inline void outs##s(unsigned short port, const void * addr, unsigned long count) \ -{ __asm__ __volatile__ ("cld ; rep ; outs" #s \ -: "=S" (addr), "=c" (count) : "d" (port),"0" (addr),"1" (count)); } - -__IN(b,"", char) -__IN(w,"",short) -__IN(l,"", long) - -__OUT(b,"b",char) -__OUT(w,"w",short) -__OUT(l,,int) - -__INS(b) -__INS(w) -__INS(l) - -__OUTS(b) -__OUTS(w) -__OUTS(l) - -/* - * Note that due to the way __builtin_constant_p() works, you - * - can't use it inside a inline function (it will never be true) - * - you don't have to worry about side effects within the __builtin.. - */ -#define outb(val,port) \ -((__builtin_constant_p((port)) && (port) < 256) ? \ - __outbc((val),(port)) : \ - __outb((val),(port))) - -#define inb(port) \ -((__builtin_constant_p((port)) && (port) < 256) ? \ - __inbc(port) : \ - __inb(port)) - -#define outb_p(val,port) \ -((__builtin_constant_p((port)) && (port) < 256) ? \ - __outbc_p((val),(port)) : \ - __outb_p((val),(port))) - -#define inb_p(port) \ -((__builtin_constant_p((port)) && (port) < 256) ? \ - __inbc_p(port) : \ - __inb_p(port)) - -#define outw(val,port) \ -((__builtin_constant_p((port)) && (port) < 256) ? \ - __outwc((val),(port)) : \ - __outw((val),(port))) - -#define inw(port) \ -((__builtin_constant_p((port)) && (port) < 256) ? \ - __inwc(port) : \ - __inw(port)) - -#define outw_p(val,port) \ -((__builtin_constant_p((port)) && (port) < 256) ? \ - __outwc_p((val),(port)) : \ - __outw_p((val),(port))) - -#define inw_p(port) \ -((__builtin_constant_p((port)) && (port) < 256) ? \ - __inwc_p(port) : \ - __inw_p(port)) - -#define outl(val,port) \ -((__builtin_constant_p((port)) && (port) < 256) ? \ - __outlc((val),(port)) : \ - __outl((val),(port))) - -#define inl(port) \ -((__builtin_constant_p((port)) && (port) < 256) ? \ - __inlc(port) : \ - __inl(port)) - -#define outl_p(val,port) \ -((__builtin_constant_p((port)) && (port) < 256) ? \ - __outlc_p((val),(port)) : \ - __outl_p((val),(port))) - -#define inl_p(port) \ -((__builtin_constant_p((port)) && (port) < 256) ? \ - __inlc_p(port) : \ - __inl_p(port)) - -#endif /* ETHERBOOT_IO_H */ diff --git a/gpxe/src/arch/i386/include/librm.h b/gpxe/src/arch/i386/include/librm.h index 07a85c59..9eb2767a 100644..100755 --- a/gpxe/src/arch/i386/include/librm.h +++ b/gpxe/src/arch/i386/include/librm.h @@ -1,21 +1,109 @@ #ifndef LIBRM_H #define LIBRM_H -/* Drag in protected-mode segment selector values */ -#include "virtaddr.h" -#include "realmode.h" +/* Segment selectors as used in our protected-mode GDTs. + * + * Don't change these unless you really know what you're doing. + */ + +#define VIRTUAL_CS 0x08 +#define VIRTUAL_DS 0x10 +#define PHYSICAL_CS 0x18 +#define PHYSICAL_DS 0x20 +#define REAL_CS 0x28 +#define REAL_DS 0x30 +#if 0 +#define LONG_CS 0x38 +#define LONG_DS 0x40 +#endif #ifndef ASSEMBLY -#include "stddef.h" -#include "string.h" +#ifdef UACCESS_LIBRM +#define UACCESS_PREFIX_librm +#else +#define UACCESS_PREFIX_librm __librm_ +#endif + +/* Variables in librm.S */ +extern unsigned long virt_offset; + +/** + * Convert physical address to user pointer + * + * @v phys_addr Physical address + * @ret userptr User pointer + */ +static inline __always_inline userptr_t +UACCESS_INLINE ( librm, phys_to_user ) ( unsigned long phys_addr ) { + return ( phys_addr - virt_offset ); +} -/* - * Data structures and type definitions +/** + * Convert user buffer to physical address + * + * @v userptr User pointer + * @v offset Offset from user pointer + * @ret phys_addr Physical address + */ +static inline __always_inline unsigned long +UACCESS_INLINE ( librm, user_to_phys ) ( userptr_t userptr, off_t offset ) { + return ( userptr + offset + virt_offset ); +} + +static inline __always_inline userptr_t +UACCESS_INLINE ( librm, virt_to_user ) ( volatile const void *addr ) { + return trivial_virt_to_user ( addr ); +} + +static inline __always_inline void * +UACCESS_INLINE ( librm, user_to_virt ) ( userptr_t userptr, off_t offset ) { + return trivial_user_to_virt ( userptr, offset ); +} + +static inline __always_inline userptr_t +UACCESS_INLINE ( librm, userptr_add ) ( userptr_t userptr, off_t offset ) { + return trivial_userptr_add ( userptr, offset ); +} + +static inline __always_inline void +UACCESS_INLINE ( librm, memcpy_user ) ( userptr_t dest, off_t dest_off, + userptr_t src, off_t src_off, + size_t len ) { + trivial_memcpy_user ( dest, dest_off, src, src_off, len ); +} + +static inline __always_inline void +UACCESS_INLINE ( librm, memmove_user ) ( userptr_t dest, off_t dest_off, + userptr_t src, off_t src_off, + size_t len ) { + trivial_memmove_user ( dest, dest_off, src, src_off, len ); +} + +static inline __always_inline void +UACCESS_INLINE ( librm, memset_user ) ( userptr_t buffer, off_t offset, + int c, size_t len ) { + trivial_memset_user ( buffer, offset, c, len ); +} + +static inline __always_inline size_t +UACCESS_INLINE ( librm, strlen_user ) ( userptr_t buffer, off_t offset ) { + return trivial_strlen_user ( buffer, offset ); +} + +static inline __always_inline off_t +UACCESS_INLINE ( librm, memchr_user ) ( userptr_t buffer, off_t offset, + int c, size_t len ) { + return trivial_memchr_user ( buffer, offset, c, len ); +} + + +/****************************************************************************** + * + * Access to variables in .data16 and .text16 * */ -/* Access to variables in .data16 and .text16 */ extern char *data16; extern char *text16; @@ -72,178 +160,6 @@ extern uint16_t __text16 ( rm_ds ); */ extern void gateA20_set ( void ); -/* - * librm_mgmt: functions for manipulating base memory and executing - * real-mode code. - * - * Full API documentation for these functions is in realmode.h. - * - */ - -/* Macro for obtaining a physical address from a segment:offset pair. */ -#define VIRTUAL(x,y) ( phys_to_virt ( ( ( x ) << 4 ) + ( y ) ) ) - -/* Copy to/from base memory */ -static inline __attribute__ (( always_inline )) void -copy_to_real_librm ( unsigned int dest_seg, unsigned int dest_off, - void *src, size_t n ) { - memcpy ( VIRTUAL ( dest_seg, dest_off ), src, n ); -} -static inline __attribute__ (( always_inline )) void -copy_from_real_librm ( void *dest, unsigned int src_seg, - unsigned int src_off, size_t n ) { - memcpy ( dest, VIRTUAL ( src_seg, src_off ), n ); -} -#define put_real_librm( var, dest_seg, dest_off ) \ - do { \ - * ( ( typeof(var) * ) VIRTUAL ( dest_seg, dest_off ) ) = var; \ - } while ( 0 ) -#define get_real_librm( var, src_seg, src_off ) \ - do { \ - var = * ( ( typeof(var) * ) VIRTUAL ( src_seg, src_off ) ); \ - } while ( 0 ) -#define copy_to_real copy_to_real_librm -#define copy_from_real copy_from_real_librm -#define put_real put_real_librm -#define get_real get_real_librm - -/** - * A pointer to a user buffer - * - * Even though we could just use a void *, we use an intptr_t so that - * attempts to use normal pointers show up as compiler warnings. Such - * code is actually valid for librm, but not for libkir (i.e. under - * KEEP_IT_REAL), so it's good to have the warnings even under librm. - */ -typedef intptr_t userptr_t; - -/** - * Add offset to user pointer - * - * @v ptr User pointer - * @v offset Offset - * @ret new_ptr New pointer value - */ -static inline __attribute__ (( always_inline )) userptr_t -userptr_add ( userptr_t ptr, off_t offset ) { - return ( ptr + offset ); -} - -/** - * Copy data to user buffer - * - * @v buffer User buffer - * @v offset Offset within user buffer - * @v src Source - * @v len Length - */ -static inline __attribute__ (( always_inline )) void -copy_to_user ( userptr_t buffer, off_t offset, const void *src, size_t len ) { - memcpy ( ( ( void * ) buffer + offset ), src, len ); -} - -/** - * Copy data from user buffer - * - * @v dest Destination - * @v buffer User buffer - * @v offset Offset within user buffer - * @v len Length - */ -static inline __attribute__ (( always_inline )) void -copy_from_user ( void *dest, userptr_t buffer, off_t offset, size_t len ) { - memcpy ( dest, ( ( void * ) buffer + offset ), len ); -} - -/** - * Copy data between user buffers - * - * @v dest Destination user buffer - * @v dest_off Offset within destination buffer - * @v src Source user buffer - * @v src_off Offset within source buffer - * @v len Length - */ -static inline __attribute__ (( always_inline )) void -memcpy_user ( userptr_t dest, off_t dest_off, userptr_t src, off_t src_off, - size_t len ) { - memcpy ( ( ( void * ) dest + dest_off ), ( ( void * ) src + src_off ), - len ); -} - -/** - * Copy data between user buffers, allowing for overlap - * - * @v dest Destination user buffer - * @v dest_off Offset within destination buffer - * @v src Source user buffer - * @v src_off Offset within source buffer - * @v len Length - */ -static inline __attribute__ (( always_inline )) void -memmove_user ( userptr_t dest, off_t dest_off, userptr_t src, off_t src_off, - size_t len ) { - memmove ( ( ( void * ) dest + dest_off ), ( ( void * ) src + src_off ), - len ); -} - -/** - * Fill user buffer with a constant byte - * - * @v buffer User buffer - * @v offset Offset within buffer - * @v c Constant byte with which to fill - * @v len Length - */ -static inline __attribute__ (( always_inline )) void -memset_user ( userptr_t buffer, off_t offset, int c, size_t len ) { - memset ( ( ( void * ) buffer + offset ), c, len ); -} - -/** - * Find length of NUL-terminated string in user buffer - * - * @v buffer User buffer - * @v offset Offset within buffer - * @ret len Length of string (excluding NUL) - */ -static inline __attribute__ (( always_inline )) size_t -strlen_user ( userptr_t buffer, off_t offset ) { - return strlen ( ( void * ) buffer + offset ); -} - -/** - * Find character in user buffer - * - * @v buffer User buffer - * @v offset Starting offset within buffer - * @v c Character to search for - * @v len Length of user buffer - * @ret offset Offset of character, or <0 if not found - */ -static inline __attribute__ (( always_inline )) off_t -memchr_user ( userptr_t buffer, off_t offset, int c, size_t len ) { - void *found; - - found = memchr ( ( ( void * ) buffer + offset ), c, len ); - return ( found ? ( found - ( void * ) buffer ) : -1 ); -} - -/** - * Convert virtual address to user buffer - * - * @v virtual Virtual address - * @ret buffer User buffer - * - * This constructs a user buffer from an ordinary pointer. Use it - * when you need to pass a pointer to an internal buffer to a function - * that expects a @c userptr_t. - */ -static inline __attribute__ (( always_inline )) userptr_t -virt_to_user ( void * virtual ) { - return ( ( intptr_t ) virtual ); -} - /** * Convert segment:offset address to user buffer * @@ -251,32 +167,9 @@ virt_to_user ( void * virtual ) { * @v offset Real-mode offset * @ret buffer User buffer */ -static inline __attribute__ (( always_inline )) userptr_t +static inline __always_inline userptr_t real_to_user ( unsigned int segment, unsigned int offset ) { - return virt_to_user ( VIRTUAL ( segment, offset ) ); -} - -/** - * Convert physical address to user buffer - * - * @v physical Physical address - * @ret buffer User buffer - */ -static inline __attribute__ (( always_inline )) userptr_t -phys_to_user ( physaddr_t physical ) { - return virt_to_user ( phys_to_virt ( physical ) ); -} - -/** - * Convert user buffer to physical address - * - * @v buffer User buffer - * @v offset Offset within user buffer - * @ret physical Physical address - */ -static inline __attribute__ (( always_inline )) physaddr_t -user_to_phys ( userptr_t buffer, off_t offset ) { - return virt_to_phys ( ( void * ) buffer + offset ); + return ( phys_to_user ( ( segment << 4 ) + offset ) ); } extern uint16_t copy_user_to_rm_stack ( userptr_t data, size_t size ); diff --git a/gpxe/src/arch/i386/include/pci_io.h b/gpxe/src/arch/i386/include/pci_io.h deleted file mode 100644 index 4888d557..00000000 --- a/gpxe/src/arch/i386/include/pci_io.h +++ /dev/null @@ -1,35 +0,0 @@ -#ifndef _PCI_IO_H -#define _PCI_IO_H - -#include <pcibios.h> -#include <pcidirect.h> - -/** @file - * - * i386 PCI configuration space access - * - * We have two methods of PCI configuration space access: the PCI BIOS - * and direct Type 1 accesses. Selecting between them is via the - * compile-time switch -DCONFIG_PCI_DIRECT. - * - */ - -#if CONFIG_PCI_DIRECT -#define pci_max_bus pcidirect_max_bus -#define pci_read_config_byte pcidirect_read_config_byte -#define pci_read_config_word pcidirect_read_config_word -#define pci_read_config_dword pcidirect_read_config_dword -#define pci_write_config_byte pcidirect_write_config_byte -#define pci_write_config_word pcidirect_write_config_word -#define pci_write_config_dword pcidirect_write_config_dword -#else /* CONFIG_PCI_DIRECT */ -#define pci_max_bus pcibios_max_bus -#define pci_read_config_byte pcibios_read_config_byte -#define pci_read_config_word pcibios_read_config_word -#define pci_read_config_dword pcibios_read_config_dword -#define pci_write_config_byte pcibios_write_config_byte -#define pci_write_config_word pcibios_write_config_word -#define pci_write_config_dword pcibios_write_config_dword -#endif /* CONFIG_PCI_DIRECT */ - -#endif /* _PCI_IO_H */ diff --git a/gpxe/src/include/pxe.h b/gpxe/src/arch/i386/include/pxe.h index 6d332ac7..6d332ac7 100644 --- a/gpxe/src/include/pxe.h +++ b/gpxe/src/arch/i386/include/pxe.h diff --git a/gpxe/src/arch/i386/include/pxe_addr.h b/gpxe/src/arch/i386/include/pxe_addr.h deleted file mode 100644 index 954551e8..00000000 --- a/gpxe/src/arch/i386/include/pxe_addr.h +++ /dev/null @@ -1,17 +0,0 @@ -/* - * Architecture-specific portion of pxe.h for Etherboot - * - * This file has to define the types SEGOFF16_t, SEGDESC_t and - * SEGSEL_t for use in other PXE structures. See pxe.h for details. - */ - -#ifndef PXE_ADDR_H -#define PXE_ADDR_H - -#define IS_NULL_SEGOFF16(x) ( ( (x).segment == 0 ) && ( (x).offset == 0 ) ) -#define SEGOFF16_TO_PTR(x) ( VIRTUAL( (x).segment, (x).offset ) ) -#define PTR_TO_SEGOFF16(ptr,segoff16) \ - (segoff16).segment = SEGMENT(ptr); \ - (segoff16).offset = OFFSET(ptr); - -#endif /* PXE_ADDR_H */ diff --git a/gpxe/src/include/pxe_api.h b/gpxe/src/arch/i386/include/pxe_api.h index b3d4bca8..b3d4bca8 100644 --- a/gpxe/src/include/pxe_api.h +++ b/gpxe/src/arch/i386/include/pxe_api.h diff --git a/gpxe/src/arch/i386/include/pxe_call.h b/gpxe/src/arch/i386/include/pxe_call.h index 7a38d314..2f3ea15a 100644 --- a/gpxe/src/arch/i386/include/pxe_call.h +++ b/gpxe/src/arch/i386/include/pxe_call.h @@ -30,6 +30,6 @@ extern void pxe_hook_int1a ( void ); extern int pxe_unhook_int1a ( void ); extern void pxe_init_structures ( void ); extern int pxe_start_nbp ( void ); -extern __cdecl void pxe_api_call ( struct i386_all_regs *ix86 ); +extern __asmcall void pxe_api_call ( struct i386_all_regs *ix86 ); #endif /* _PXE_CALL_H */ diff --git a/gpxe/src/include/pxe_types.h b/gpxe/src/arch/i386/include/pxe_types.h index e31af062..dd9092ef 100644 --- a/gpxe/src/include/pxe_types.h +++ b/gpxe/src/arch/i386/include/pxe_types.h @@ -7,9 +7,8 @@ * */ -#include "stdint.h" -#include "pxe_addr.h" /* Architecture-specific PXE definitions */ -#include "errno.h" /* PXE status codes */ +#include <stdint.h> +#include <errno.h> /* PXE status codes */ /** @addtogroup pxe Preboot eXecution Environment (PXE) API * @{ diff --git a/gpxe/src/arch/i386/include/realmode.h b/gpxe/src/arch/i386/include/realmode.h index 5d3ddf50..26e6dd77 100644 --- a/gpxe/src/arch/i386/include/realmode.h +++ b/gpxe/src/arch/i386/include/realmode.h @@ -1,45 +1,15 @@ #ifndef REALMODE_H #define REALMODE_H -#ifndef ASSEMBLY - -#include "stdint.h" -#include "registers.h" -#include "io.h" +#include <stdint.h> +#include <registers.h> +#include <gpxe/uaccess.h> /* * Data structures and type definitions * */ -/* Segment:offset structure. Note that the order within the structure - * is offset:segment. - */ -struct segoff { - uint16_t offset; - uint16_t segment; -} __attribute__ (( packed )); - -typedef struct segoff segoff_t; - -/* Macro hackery needed to stringify bits of inline assembly */ -#define RM_XSTR(x) #x -#define RM_STR(x) RM_XSTR(x) - -/* Drag in the selected real-mode transition library header */ -#ifdef KEEP_IT_REAL -#include "libkir.h" -#else -#include "librm.h" -#endif - -/* - * The API to some functions is identical between librm and libkir, so - * they are documented here, even though the prototypes are in librm.h - * and libkir.h. - * - */ - /* * Declaration of variables in .data16 * @@ -92,24 +62,53 @@ typedef struct segoff segoff_t; * assembler output to make sure that it's doing the right thing. */ -/* - * void copy_to_real ( uint16_t dest_seg, uint16_t dest_off, - * void *src, size_t n ) - * void copy_from_real ( void *dest, uint16_t src_seg, uint16_t src_off, - * size_t n ) +/** + * Copy data to base memory * - * These functions can be used to copy data to and from arbitrary - * locations in base memory. + * @v dest_seg Destination segment + * @v dest_off Destination offset + * @v src Source + * @v len Length */ +static inline __always_inline void +copy_to_real ( unsigned int dest_seg, unsigned int dest_off, + void *src, size_t n ) { + copy_to_user ( real_to_user ( dest_seg, dest_off ), 0, src, n ); +} -/* - * put_real ( variable, uint16_t dest_seg, uint16_t dest_off ) - * get_real ( variable, uint16_t src_seg, uint16_t src_off ) +/** + * Copy data to base memory + * + * @v dest Destination + * @v src_seg Source segment + * @v src_off Source offset + * @v len Length + */ +static inline __always_inline void +copy_from_real ( void *dest, unsigned int src_seg, + unsigned int src_off, size_t n ) { + copy_from_user ( dest, real_to_user ( src_seg, src_off ), 0, n ); +} + +/** + * Write a single variable to base memory * - * These macros can be used to read or write single variables to and - * from arbitrary locations in base memory. "variable" must be a - * variable of either 1, 2 or 4 bytes in length. + * @v var Variable to write + * @v dest_seg Destination segment + * @v dest_off Destination offset */ +#define put_real( var, dest_seg, dest_off ) \ + copy_to_real ( (dest_seg), (dest_off), &(var), sizeof (var) ) + +/** + * Read a single variable from base memory + * + * @v var Variable to read + * @v src_seg Source segment + * @v src_off Source offset + */ +#define get_real( var, src_seg, src_off ) \ + copy_from_real ( &(var), (src_seg), (src_off), sizeof (var) ) /* * REAL_CODE ( asm_code_str ) @@ -123,6 +122,4 @@ typedef struct segoff segoff_t; * */ -#endif /* ASSEMBLY */ - #endif /* REALMODE_H */ diff --git a/gpxe/src/arch/i386/include/registers.h b/gpxe/src/arch/i386/include/registers.h index 2b9b2b43..e68fa85a 100644 --- a/gpxe/src/arch/i386/include/registers.h +++ b/gpxe/src/arch/i386/include/registers.h @@ -10,8 +10,7 @@ * */ -#include "compiler.h" /* for doxygen */ -#include "stdint.h" +#include <stdint.h> /** * A 16-bit general register. @@ -184,4 +183,14 @@ struct i386_all_regs { #define SF ( 1 << 7 ) #define OF ( 1 << 11 ) +/* Segment:offset structure. Note that the order within the structure + * is offset:segment. + */ +struct segoff { + uint16_t offset; + uint16_t segment; +} PACKED; + +typedef struct segoff segoff_t; + #endif /* REGISTERS_H */ diff --git a/gpxe/src/arch/i386/include/setjmp.h b/gpxe/src/arch/i386/include/setjmp.h index bb0a100d..c18d03e1 100644 --- a/gpxe/src/arch/i386/include/setjmp.h +++ b/gpxe/src/arch/i386/include/setjmp.h @@ -1,12 +1,38 @@ #ifndef ETHERBOOT_SETJMP_H #define ETHERBOOT_SETJMP_H +#include <stdint.h> +#include <realmode.h> -/* Define a type for use by setjmp and longjmp */ -#define JBLEN 6 -typedef unsigned long jmp_buf[JBLEN]; +/** A jump buffer */ +typedef struct { + uint32_t retaddr; + uint32_t ebx; + uint32_t esp; + uint32_t ebp; + uint32_t esi; + uint32_t edi; +} jmp_buf[1]; -extern int __cdecl setjmp (jmp_buf env); -extern void __cdecl longjmp (jmp_buf env, int val); +/** A real-mode-extended jump buffer */ +typedef struct { + jmp_buf env; + uint16_t rm_ss; + uint16_t rm_sp; +} rmjmp_buf[1]; + +extern int __asmcall setjmp ( jmp_buf env ); +extern void __asmcall longjmp ( jmp_buf env, int val ); + +#define rmsetjmp( _env ) ( { \ + (_env)->rm_ss = rm_ss; \ + (_env)->rm_sp = rm_sp; \ + setjmp ( (_env)->env ); } ) \ + +#define rmlongjmp( _env, _val ) do { \ + rm_ss = (_env)->rm_ss; \ + rm_sp = (_env)->rm_sp; \ + longjmp ( (_env)->env, (_val) ); \ + } while ( 0 ) #endif /* ETHERBOOT_SETJMP_H */ diff --git a/gpxe/src/arch/i386/include/smbios.h b/gpxe/src/arch/i386/include/smbios.h deleted file mode 100644 index f2736dc3..00000000 --- a/gpxe/src/arch/i386/include/smbios.h +++ /dev/null @@ -1,60 +0,0 @@ -#ifndef _SMBIOS_H -#define _SMBIOS_H - -/** @file - * - * System Management BIOS - */ - -#include <stdint.h> - -/** An SMBIOS structure header */ -struct smbios_header { - /** Type */ - uint8_t type; - /** Length */ - uint8_t len; - /** Handle */ - uint16_t handle; -} __attribute__ (( packed )); - -/** SMBIOS structure descriptor */ -struct smbios_structure { - /** Copy of SMBIOS structure header */ - struct smbios_header header; - /** Offset of structure within SMBIOS */ - size_t offset; - /** Length of strings section */ - size_t strings_len; -}; - -/** SMBIOS system information structure */ -struct smbios_system_information { - /** SMBIOS structure header */ - struct smbios_header header; - /** Manufacturer string */ - uint8_t manufacturer; - /** Product string */ - uint8_t product; - /** Version string */ - uint8_t version; - /** Serial number string */ - uint8_t serial; - /** UUID */ - uint8_t uuid[16]; - /** Wake-up type */ - uint8_t wakeup; -} __attribute__ (( packed )); - -/** SMBIOS system information structure type */ -#define SMBIOS_TYPE_SYSTEM_INFORMATION 1 - -extern int find_smbios_structure ( unsigned int type, - 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 ); - -#endif /* _SMBIOS_H */ diff --git a/gpxe/src/arch/i386/include/undi.h b/gpxe/src/arch/i386/include/undi.h index 9936e17f..c6253d0a 100644 --- a/gpxe/src/arch/i386/include/undi.h +++ b/gpxe/src/arch/i386/include/undi.h @@ -24,10 +24,6 @@ struct undi_device { SEGOFF16_t ppxe; /** Entry point */ SEGOFF16_t entry; - /** Return stack */ - UINT16_t return_stack[3]; - /** Return type */ - UINT16_t return_type; /** Free base memory after load */ UINT16_t fbms; /** Free base memory prior to load */ @@ -99,4 +95,10 @@ static inline void * undi_get_drvdata ( struct undi_device *undi ) { /** UNDI flag: START_UNDI has been called */ #define UNDI_FL_STARTED 0x0001 +/** UNDI flag: UNDI_STARTUP and UNDI_INITIALIZE have been called */ +#define UNDI_FL_INITIALIZED 0x0002 + +/** UNDI flag: keep stack resident */ +#define UNDI_FL_KEEP_ALL 0x0004 + #endif /* _UNDI_H */ diff --git a/gpxe/src/arch/i386/include/virtaddr.h b/gpxe/src/arch/i386/include/virtaddr.h deleted file mode 100644 index f2ffa2a1..00000000 --- a/gpxe/src/arch/i386/include/virtaddr.h +++ /dev/null @@ -1,105 +0,0 @@ -#ifndef VIRTADDR_H -#define VIRTADDR_H - -/* Segment selectors as used in our protected-mode GDTs. - * - * Don't change these unless you really know what you're doing. - */ - -#define VIRTUAL_CS 0x08 -#define VIRTUAL_DS 0x10 -#define PHYSICAL_CS 0x18 -#define PHYSICAL_DS 0x20 -#define REAL_CS 0x28 -#define REAL_DS 0x30 -#if 0 -#define LONG_CS 0x38 -#define LONG_DS 0x40 -#endif - -#ifndef ASSEMBLY - -#include "stdint.h" -#include "string.h" - -#ifndef KEEP_IT_REAL - -/* - * Without -DKEEP_IT_REAL, we are in 32-bit protected mode with a - * fixed link address but an unknown physical start address. Our GDT - * sets up code and data segments with an offset of virt_offset, so - * that link-time addresses can still work. - * - */ - -/* C-callable function prototypes */ - -extern void relocate_to ( uint32_t new_phys_addr ); - -/* Variables in virtaddr.S */ -extern unsigned long virt_offset; - -/* - * Convert between virtual and physical addresses - * - */ -static inline unsigned long virt_to_phys ( volatile const void *virt_addr ) { - return ( ( unsigned long ) virt_addr ) + virt_offset; -} - -static inline void * phys_to_virt ( unsigned long phys_addr ) { - return ( void * ) ( phys_addr - virt_offset ); -} - -static inline void copy_to_phys ( physaddr_t dest, const void *src, - size_t len ) { - memcpy ( phys_to_virt ( dest ), src, len ); -} - -static inline void copy_from_phys ( void *dest, physaddr_t src, size_t len ) { - memcpy ( dest, phys_to_virt ( src ), len ); -} - -static inline void copy_phys_to_phys ( physaddr_t dest, physaddr_t src, - size_t len ) { - memcpy ( phys_to_virt ( dest ), phys_to_virt ( src ), len ); -} - -#else /* KEEP_IT_REAL */ - -/* - * With -DKEEP_IT_REAL, we are in 16-bit real mode with fixed link - * addresses and a segmented memory model. We have separate code and - * data segments. - * - * Because we may be called in 16-bit protected mode (damn PXE spec), - * we cannot simply assume that physical = segment * 16 + offset. - * Instead, we have to look up the physical start address of the - * segment in the !PXE structure. We have to assume that - * virt_to_phys() is called only on pointers within the data segment, - * because nothing passes segment information to us. - * - * We don't implement phys_to_virt at all, because there will be many - * addresses that simply cannot be reached via a virtual address when - * the virtual address space is limited to 64kB! - */ - -static inline unsigned long virt_to_phys ( volatile const void *virt_addr ) { - /* Cheat: just for now, do the segment*16+offset calculation */ - uint16_t ds; - - __asm__ ( "movw %%ds, %%ax" : "=a" ( ds ) : ); - return ( 16 * ds + ( ( unsigned long ) virt_addr ) ); -} - -/* Define it as a deprecated function so that we get compile-time - * warnings, rather than just the link-time errors. - */ -extern void * phys_to_virt ( unsigned long phys_addr ) - __attribute__ ((deprecated)); - -#endif /* KEEP_IT_REAL */ - -#endif /* ASSEMBLY */ - -#endif /* VIRTADDR_H */ diff --git a/gpxe/src/core/abft.c b/gpxe/src/arch/i386/interface/pcbios/abft.c index af28bbcf..af28bbcf 100644 --- a/gpxe/src/core/abft.c +++ b/gpxe/src/arch/i386/interface/pcbios/abft.c diff --git a/gpxe/src/usr/aoeboot.c b/gpxe/src/arch/i386/interface/pcbios/aoeboot.c index f0e481bd..6e1e51cb 100644 --- a/gpxe/src/usr/aoeboot.c +++ b/gpxe/src/arch/i386/interface/pcbios/aoeboot.c @@ -6,27 +6,11 @@ #include <gpxe/ata.h> #include <gpxe/netdevice.h> #include <gpxe/settings.h> +#include <gpxe/sanboot.h> #include <gpxe/abft.h> #include <int13.h> -#include <usr/aoeboot.h> -/** - * Guess boot network device - * - * @ret netdev Boot network device - */ -static struct net_device * guess_boot_netdev ( void ) { - struct net_device *boot_netdev; - - /* Just use the first network device */ - for_each_netdev ( boot_netdev ) { - return boot_netdev; - } - - return NULL; -} - -int aoeboot ( const char *root_path ) { +static int aoeboot ( const char *root_path ) { struct ata_device ata; struct int13_drive drive; int rc; @@ -37,7 +21,7 @@ int aoeboot ( const char *root_path ) { printf ( "AoE booting from %s\n", root_path ); /* FIXME: ugly, ugly hack */ - struct net_device *netdev = guess_boot_netdev(); + struct net_device *netdev = last_opened_netdev(); if ( ( rc = aoe_attach ( &ata, netdev, root_path ) ) != 0 ) { printf ( "Could not attach AoE device: %s\n", @@ -71,3 +55,8 @@ int aoeboot ( const char *root_path ) { error_attach: return rc; } + +struct sanboot_protocol aoe_sanboot_protocol __sanboot_protocol = { + .prefix = "aoe:", + .boot = aoeboot, +}; diff --git a/gpxe/src/arch/i386/interface/pcbios/bios_nap.c b/gpxe/src/arch/i386/interface/pcbios/bios_nap.c new file mode 100644 index 00000000..2f4a0513 --- /dev/null +++ b/gpxe/src/arch/i386/interface/pcbios/bios_nap.c @@ -0,0 +1,14 @@ +#include <gpxe/nap.h> +#include <realmode.h> + +/** + * Save power by halting the CPU until the next interrupt + * + */ +static void bios_cpu_nap ( void ) { + __asm__ __volatile__ ( REAL_CODE ( "sti\n\t" + "hlt\n\t" + "cli\n\t" ) : : ); +} + +PROVIDE_NAP ( pcbios, cpu_nap, bios_cpu_nap ); diff --git a/gpxe/src/arch/i386/interface/pcbios/bios_smbios.c b/gpxe/src/arch/i386/interface/pcbios/bios_smbios.c new file mode 100644 index 00000000..efaaef0d --- /dev/null +++ b/gpxe/src/arch/i386/interface/pcbios/bios_smbios.c @@ -0,0 +1,84 @@ +/* + * Copyright (C) 2007 Michael Brown <mbrown@fensystems.co.uk>. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of the + * License, or any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +#include <stdint.h> +#include <string.h> +#include <errno.h> +#include <assert.h> +#include <gpxe/uaccess.h> +#include <gpxe/smbios.h> +#include <realmode.h> +#include <pnpbios.h> + +/** @file + * + * System Management BIOS + * + */ + +/** + * Find SMBIOS + * + * @v smbios SMBIOS entry point descriptor structure to fill in + * @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; + + /* Try to find SMBIOS */ + for ( ; offset < 0x10000 ; offset += 0x10 ) { + + /* 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; + + /* 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; +} + +PROVIDE_SMBIOS ( pcbios, find_smbios, bios_find_smbios ); diff --git a/gpxe/src/arch/i386/interface/pcbios/bios_timer.c b/gpxe/src/arch/i386/interface/pcbios/bios_timer.c new file mode 100644 index 00000000..0b475ea3 --- /dev/null +++ b/gpxe/src/arch/i386/interface/pcbios/bios_timer.c @@ -0,0 +1,63 @@ +/* + * 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., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +/** @file + * + * BIOS timer + * + */ + +#include <gpxe/timer.h> +#include <realmode.h> +#include <bios.h> + +/** + * Get current system time in ticks + * + * @ret ticks Current time, in ticks + * + * Use direct memory access to BIOS variables, longword 0040:006C + * (ticks today) and byte 0040:0070 (midnight crossover flag) instead + * of calling timeofday BIOS interrupt. + */ +static unsigned long bios_currticks ( void ) { + static int days = 0; + uint32_t ticks; + 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" ) : : ); + + get_real ( ticks, BDA_SEG, 0x006c ); + get_real ( midnight, BDA_SEG, 0x0070 ); + + if ( midnight ) { + midnight = 0; + put_real ( midnight, BDA_SEG, 0x0070 ); + days += 0x1800b0; + } + + return ( days + ticks ); +} + +PROVIDE_TIMER_INLINE ( pcbios, udelay ); +PROVIDE_TIMER ( pcbios, currticks, bios_currticks ); +PROVIDE_TIMER_INLINE ( pcbios, ticks_per_sec ); diff --git a/gpxe/src/arch/i386/interface/pcbios/biosint.c b/gpxe/src/arch/i386/interface/pcbios/biosint.c index 8ef2d7ab..1306f918 100644 --- a/gpxe/src/arch/i386/interface/pcbios/biosint.c +++ b/gpxe/src/arch/i386/interface/pcbios/biosint.c @@ -8,17 +8,6 @@ */ /** - * Hooked interrupt count - * - * At exit, after unhooking all possible interrupts, this counter - * should be examined. If it is non-zero, it means that we failed to - * unhook at least one interrupt vector, and so must not free up the - * memory we are using. (Note that this also implies that we should - * re-hook INT 15 in order to hide ourselves from the memory map). - */ -int hooked_bios_interrupts = 0; - -/** * Hook INT vector * * @v interrupt INT number diff --git a/gpxe/src/core/ibft.c b/gpxe/src/arch/i386/interface/pcbios/ibft.c index ffa65964..ffa65964 100644 --- a/gpxe/src/core/ibft.c +++ b/gpxe/src/arch/i386/interface/pcbios/ibft.c diff --git a/gpxe/src/arch/i386/interface/pcbios/int13.c b/gpxe/src/arch/i386/interface/pcbios/int13.c index 6f61e4a1..2e9de5cb 100644 --- a/gpxe/src/arch/i386/interface/pcbios/int13.c +++ b/gpxe/src/arch/i386/interface/pcbios/int13.c @@ -144,7 +144,7 @@ static int int13_rw_sectors ( struct int13_drive *drive, static int int13_read_sectors ( struct int13_drive *drive, struct i386_all_regs *ix86 ) { DBG ( "Read: " ); - return int13_rw_sectors ( drive, ix86, drive->blockdev->read ); + return int13_rw_sectors ( drive, ix86, drive->blockdev->op->read ); } /** @@ -163,7 +163,7 @@ static int int13_read_sectors ( struct int13_drive *drive, static int int13_write_sectors ( struct int13_drive *drive, struct i386_all_regs *ix86 ) { DBG ( "Write: " ); - return int13_rw_sectors ( drive, ix86, drive->blockdev->write ); + return int13_rw_sectors ( drive, ix86, drive->blockdev->op->write ); } /** @@ -275,7 +275,7 @@ static int int13_extended_rw ( struct int13_drive *drive, static int int13_extended_read ( struct int13_drive *drive, struct i386_all_regs *ix86 ) { DBG ( "Extended read: " ); - return int13_extended_rw ( drive, ix86, drive->blockdev->read ); + return int13_extended_rw ( drive, ix86, drive->blockdev->op->read ); } /** @@ -288,7 +288,7 @@ static int int13_extended_read ( struct int13_drive *drive, static int int13_extended_write ( struct int13_drive *drive, struct i386_all_regs *ix86 ) { DBG ( "Extended write: " ); - return int13_extended_rw ( drive, ix86, drive->blockdev->write ); + return int13_extended_rw ( drive, ix86, drive->blockdev->op->write ); } /** @@ -322,7 +322,7 @@ static int int13_get_extended_parameters ( struct int13_drive *drive, * INT 13 handler * */ -static __cdecl void int13 ( struct i386_all_regs *ix86 ) { +static __asmcall void int13 ( struct i386_all_regs *ix86 ) { int command = ix86->regs.ah; unsigned int bios_drive = ix86->regs.dl; struct int13_drive *drive; @@ -488,8 +488,8 @@ static void guess_int13_geometry ( struct int13_drive *drive ) { /* Scan through partition table and modify guesses for heads * and sectors_per_track if we find any used partitions. */ - if ( drive->blockdev->read ( drive->blockdev, 0, 1, - virt_to_user ( &mbr ) ) == 0 ) { + if ( drive->blockdev->op->read ( drive->blockdev, 0, 1, + virt_to_user ( &mbr ) ) == 0 ) { for ( i = 0 ; i < 4 ; i++ ) { partition = &mbr.partitions[i]; if ( ! partition->type ) diff --git a/gpxe/src/usr/iscsiboot.c b/gpxe/src/arch/i386/interface/pcbios/iscsiboot.c index 84d77c45..02aec4ba 100644 --- a/gpxe/src/usr/iscsiboot.c +++ b/gpxe/src/arch/i386/interface/pcbios/iscsiboot.c @@ -9,9 +9,9 @@ #include <gpxe/netdevice.h> #include <gpxe/ibft.h> #include <gpxe/init.h> +#include <gpxe/sanboot.h> #include <int13.h> #include <usr/autoboot.h> -#include <usr/iscsiboot.h> struct setting keep_san_setting __setting = { .name = "keep-san", @@ -20,23 +20,7 @@ struct setting keep_san_setting __setting = { .type = &setting_type_int8, }; -/** - * Guess boot network device - * - * @ret netdev Boot network device - */ -static struct net_device * guess_boot_netdev ( void ) { - struct net_device *boot_netdev; - - /* Just use the first network device */ - for_each_netdev ( boot_netdev ) { - return boot_netdev; - } - - return NULL; -} - -int iscsiboot ( const char *root_path ) { +static int iscsiboot ( const char *root_path ) { struct scsi_device *scsi; struct int13_drive *drive; int keep_san; @@ -69,7 +53,7 @@ int iscsiboot ( const char *root_path ) { drive->blockdev = &scsi->blockdev; /* FIXME: ugly, ugly hack */ - struct net_device *netdev = guess_boot_netdev(); + struct net_device *netdev = last_opened_netdev(); struct iscsi_session *iscsi = container_of ( scsi->backend, struct iscsi_session, refcnt ); ibft_fill_data ( netdev, iscsi ); @@ -100,3 +84,8 @@ int iscsiboot ( const char *root_path ) { err_alloc_scsi: return rc; } + +struct sanboot_protocol iscsi_sanboot_protocol __sanboot_protocol = { + .prefix = "iscsi:", + .boot = iscsiboot, +}; diff --git a/gpxe/src/arch/i386/core/umalloc.c b/gpxe/src/arch/i386/interface/pcbios/memtop_umalloc.c index 3990488c..744d8e30 100644 --- a/gpxe/src/arch/i386/core/umalloc.c +++ b/gpxe/src/arch/i386/interface/pcbios/memtop_umalloc.c @@ -36,9 +36,6 @@ /** Equivalent of NOWHERE for user pointers */ #define UNOWHERE ( ~UNULL ) -/** Start of Etherboot text, as defined by the linker */ -extern char _text[]; - /** An external memory block */ struct external_memory { /** Size of this memory block (excluding this header) */ @@ -95,7 +92,7 @@ static int init_eheap ( void ) { } } - if ( ! top ) { + if ( ! heap_size ) { DBG ( "No external heap available\n" ); return -ENOMEM; } @@ -135,16 +132,16 @@ static void ecollect_free ( void ) { * Calling realloc() with a new size of zero is a valid way to free a * memory block. */ -userptr_t urealloc ( userptr_t ptr, size_t new_size ) { +static userptr_t memtop_urealloc ( userptr_t ptr, size_t new_size ) { struct external_memory extmem; userptr_t new = ptr; size_t align; int rc; /* Initialise external memory allocator if necessary */ - if ( ! top ) { + if ( bottom == top ) { if ( ( rc = init_eheap() ) != 0 ) - return rc; + return UNULL; } /* Get block properties into extmem */ @@ -200,25 +197,4 @@ userptr_t urealloc ( userptr_t ptr, size_t new_size ) { return ( new_size ? new : UNOWHERE ); } -/** - * Allocate external memory - * - * @v size Requested size - * @ret ptr Memory, or UNULL - * - * Memory is guaranteed to be aligned to a page boundary. - */ -userptr_t umalloc ( size_t size ) { - return urealloc ( UNULL, size ); -} - -/** - * Free external memory - * - * @v ptr Memory allocated by umalloc(), or UNULL - * - * If @c ptr is UNULL, no action is taken. - */ -void ufree ( userptr_t ptr ) { - urealloc ( ptr, 0 ); -} +PROVIDE_UMALLOC ( memtop, urealloc, memtop_urealloc ); diff --git a/gpxe/src/arch/i386/core/pcibios.c b/gpxe/src/arch/i386/interface/pcbios/pcibios.c index 1c93e4be..81b4fd3c 100644 --- a/gpxe/src/arch/i386/core/pcibios.c +++ b/gpxe/src/arch/i386/interface/pcbios/pcibios.c @@ -18,7 +18,6 @@ #include <stdint.h> #include <gpxe/pci.h> -#include <pcibios.h> #include <realmode.h> /** @file @@ -32,7 +31,7 @@ * * @ret max_bus Maximum bus number */ -int pcibios_max_bus ( void ) { +static int pcibios_max_bus ( void ) { int discard_a, discard_D; uint8_t max_bus; @@ -104,3 +103,11 @@ int pcibios_write ( struct pci_device *pci, uint32_t command, uint32_t value ){ return ( ( status >> 8 ) & 0xff ); } + +PROVIDE_PCIAPI ( pcbios, pci_max_bus, pcibios_max_bus ); +PROVIDE_PCIAPI_INLINE ( pcbios, pci_read_config_byte ); +PROVIDE_PCIAPI_INLINE ( pcbios, pci_read_config_word ); +PROVIDE_PCIAPI_INLINE ( pcbios, pci_read_config_dword ); +PROVIDE_PCIAPI_INLINE ( pcbios, pci_write_config_byte ); +PROVIDE_PCIAPI_INLINE ( pcbios, pci_write_config_word ); +PROVIDE_PCIAPI_INLINE ( pcbios, pci_write_config_dword ); diff --git a/gpxe/src/arch/i386/interface/pxe/pxe_call.c b/gpxe/src/arch/i386/interface/pxe/pxe_call.c index 7122c4eb..04aaf3b2 100644 --- a/gpxe/src/arch/i386/interface/pxe/pxe_call.c +++ b/gpxe/src/arch/i386/interface/pxe/pxe_call.c @@ -119,7 +119,7 @@ static PXENV_EXIT_t pxenv_unknown ( struct s_PXENV_UNKNOWN *pxenv_unknown ) { * @v es:di Address of PXE parameter block * @ret ax PXE exit code */ -__cdecl void pxe_api_call ( struct i386_all_regs *ix86 ) { +__asmcall void pxe_api_call ( struct i386_all_regs *ix86 ) { int opcode = ix86->regs.bx; userptr_t parameters = real_to_user ( ix86->segs.es, ix86->regs.di ); size_t param_len; @@ -339,7 +339,7 @@ __cdecl void pxe_api_call ( struct i386_all_regs *ix86 ) { * @v es:di Address of PXE parameter block * @ret ax PXE exit code */ -__cdecl void pxe_loader_call ( struct i386_all_regs *ix86 ) { +__asmcall void pxe_loader_call ( struct i386_all_regs *ix86 ) { userptr_t uparams = real_to_user ( ix86->segs.es, ix86->regs.di ); struct s_UNDI_LOADER params; PXENV_EXIT_t ret; diff --git a/gpxe/src/arch/i386/interface/pxe/pxe_entry.S b/gpxe/src/arch/i386/interface/pxe/pxe_entry.S index e5d327a5..68b7374f 100644 --- a/gpxe/src/arch/i386/interface/pxe/pxe_entry.S +++ b/gpxe/src/arch/i386/interface/pxe/pxe_entry.S @@ -18,15 +18,12 @@ */ .arch i386 - .section ".text16", "awx", @progbits - .section ".text16.data", "aw", @progbits - .section ".data16", "aw", @progbits /**************************************************************************** * !PXE structure **************************************************************************** */ - .section ".text16.data" + .section ".text16.data", "aw", @progbits .globl ppxe .align 16 ppxe: @@ -44,10 +41,10 @@ ppxe: .byte SegDescCnt /* SegDescCnt */ .word 0 /* FirstSelector */ pxe_segments: - .word 0, 0, 0, _data16_size /* Stack */ - .word 0, 0, 0, _data16_size /* UNDIData */ - .word 0, 0, 0, _text16_size /* UNDICode */ - .word 0, 0, 0, _text16_size /* UNDICodeWrite */ + .word 0, 0, 0, _data16_memsz /* Stack */ + .word 0, 0, 0, _data16_memsz /* UNDIData */ + .word 0, 0, 0, _text16_memsz /* UNDICode */ + .word 0, 0, 0, _text16_memsz /* UNDICodeWrite */ .word 0, 0, 0, 0 /* BC_Data */ .word 0, 0, 0, 0 /* BC_Code */ .word 0, 0, 0, 0 /* BC_CodeWrite */ @@ -56,7 +53,7 @@ pxe_segments: .size ppxe, . - ppxe /* Define undiheader=0 as a weak symbol for non-ROM builds */ - .section ".weak" + .section ".weak", "a", @nobits .weak undiheader undiheader: @@ -64,7 +61,7 @@ undiheader: * PXENV+ structure **************************************************************************** */ - .section ".text16.data" + .section ".text16.data", "aw", @progbits .globl pxenv .align 16 pxenv: @@ -76,15 +73,15 @@ pxenv: .long 0 /* PMEntry */ .word 0 /* PMSelector */ .word 0 /* StackSeg */ - .word _data16_size /* StackSize */ + .word _data16_memsz /* StackSize */ .word 0 /* BC_CodeSeg */ .word 0 /* BC_CodeSize */ .word 0 /* BC_DataSeg */ .word 0 /* BC_DataSize */ .word 0 /* UNDIDataSeg */ - .word _data16_size /* UNDIDataSize */ + .word _data16_memsz /* UNDIDataSize */ .word 0 /* UNDICodeSeg */ - .word _text16_size /* UNDICodeSize */ + .word _text16_memsz /* UNDICodeSize */ .word ppxe, 0 /* PXEPtr */ .equ pxenv_length, . - pxenv .size pxenv, . - pxenv @@ -108,12 +105,12 @@ pxenv: * somebody at Wyse has difficulty distinguishing between the * words "may" and "must"... */ - .section ".text16.null" + .section ".text16.null", "ax", @progbits .code16 pxenv_null_entry: jmp pxenv_entry - .section ".text16" + .section ".text16", "ax", @progbits .code16 pxenv_entry: pushl $pxe_api_call @@ -137,7 +134,7 @@ pxenv_entry: * none **************************************************************************** */ - .section ".text16" + .section ".text16", "ax", @progbits .code16 pxe_entry: pxe_entry_sp: @@ -186,7 +183,7 @@ pxe_entry_common: * none **************************************************************************** */ - .section ".text16" + .section ".text16", "ax", @progbits .code16 .globl pxe_int_1a pxe_int_1a: @@ -205,6 +202,6 @@ pxe_int_1a: popfw ljmp *%cs:pxe_int_1a_vector - .section ".text16.data" + .section ".text16.data", "aw", @progbits .globl pxe_int_1a_vector pxe_int_1a_vector: .long 0 diff --git a/gpxe/src/interface/pxe/pxe_errors.c b/gpxe/src/arch/i386/interface/pxe/pxe_errors.c index f884ef8a..f884ef8a 100644 --- a/gpxe/src/interface/pxe/pxe_errors.c +++ b/gpxe/src/arch/i386/interface/pxe/pxe_errors.c diff --git a/gpxe/src/interface/pxe/pxe_file.c b/gpxe/src/arch/i386/interface/pxe/pxe_file.c index 41674588..41674588 100644 --- a/gpxe/src/interface/pxe/pxe_file.c +++ b/gpxe/src/arch/i386/interface/pxe/pxe_file.c diff --git a/gpxe/src/interface/pxe/pxe_loader.c b/gpxe/src/arch/i386/interface/pxe/pxe_loader.c index d228a36d..d228a36d 100644 --- a/gpxe/src/interface/pxe/pxe_loader.c +++ b/gpxe/src/arch/i386/interface/pxe/pxe_loader.c diff --git a/gpxe/src/interface/pxe/pxe_preboot.c b/gpxe/src/arch/i386/interface/pxe/pxe_preboot.c index 8220d1f2..193abc3d 100644 --- a/gpxe/src/interface/pxe/pxe_preboot.c +++ b/gpxe/src/arch/i386/interface/pxe/pxe_preboot.c @@ -82,7 +82,7 @@ struct pxe_dhcp_packet_creator { static struct pxe_dhcp_packet_creator pxe_dhcp_packet_creators[] = { [CACHED_INFO_DHCPDISCOVER] = { create_fakedhcpdiscover }, [CACHED_INFO_DHCPACK] = { create_fakedhcpack }, - [CACHED_INFO_BINL] = { create_fakeproxydhcpack }, + [CACHED_INFO_BINL] = { create_fakepxebsack }, }; /* The case in which the caller doesn't supply a buffer is really diff --git a/gpxe/src/interface/pxe/pxe_tftp.c b/gpxe/src/arch/i386/interface/pxe/pxe_tftp.c index f5e76206..715a0b61 100644 --- a/gpxe/src/interface/pxe/pxe_tftp.c +++ b/gpxe/src/arch/i386/interface/pxe/pxe_tftp.c @@ -113,12 +113,6 @@ static int pxe_tftp_xfer_deliver_iob ( struct xfer_interface *xfer __unused, /* Calculate new buffer position */ pxe_tftp.offset += len; - /* Mildly ugly hack; assume that the first non-zero seek - * indicates the block size. - */ - if ( pxe_tftp.blksize == 0 ) - pxe_tftp.blksize = pxe_tftp.offset; - /* Record maximum offset as the file size */ if ( pxe_tftp.max_offset < pxe_tftp.offset ) pxe_tftp.max_offset = pxe_tftp.offset; @@ -265,10 +259,12 @@ PXENV_EXIT_t pxenv_tftp_open ( struct s_PXENV_TFTP_OPEN *tftp_open ) { /* Wait for OACK to arrive so that we have the block size */ while ( ( ( rc = pxe_tftp.rc ) == -EINPROGRESS ) && - ( pxe_tftp.blksize == 0 ) ) { + ( pxe_tftp.max_offset == 0 ) ) { step(); } + pxe_tftp.blksize = xfer_window ( &pxe_tftp.xfer ); tftp_open->PacketSize = pxe_tftp.blksize; + DBG ( " blksize=%d", tftp_open->PacketSize ); /* EINPROGRESS is normal; we don't wait for the whole transfer */ if ( rc == -EINPROGRESS ) @@ -485,7 +481,7 @@ PXENV_EXIT_t pxenv_tftp_read_file ( struct s_PXENV_TFTP_READ_FILE *tftp_read_file ) { int rc; - DBG ( "PXENV_TFTP_READ_FILE to %08lx+%lx", tftp_read_file->Buffer, + DBG ( "PXENV_TFTP_READ_FILE to %08x+%x", tftp_read_file->Buffer, tftp_read_file->BufferSize ); /* Open TFTP file */ @@ -571,6 +567,7 @@ PXENV_EXIT_t pxenv_tftp_get_fsize ( struct s_PXENV_TFTP_GET_FSIZE step(); } tftp_get_fsize->FileSize = pxe_tftp.max_offset; + DBG ( " fsize=%d", tftp_get_fsize->FileSize ); /* EINPROGRESS is normal; we don't wait for the whole transfer */ if ( rc == -EINPROGRESS ) diff --git a/gpxe/src/interface/pxe/pxe_udp.c b/gpxe/src/arch/i386/interface/pxe/pxe_udp.c index 033b1ad9..033b1ad9 100644 --- a/gpxe/src/interface/pxe/pxe_udp.c +++ b/gpxe/src/arch/i386/interface/pxe/pxe_udp.c diff --git a/gpxe/src/interface/pxe/pxe_undi.c b/gpxe/src/arch/i386/interface/pxe/pxe_undi.c index 5d06f2d8..4e4a3da0 100644 --- a/gpxe/src/interface/pxe/pxe_undi.c +++ b/gpxe/src/arch/i386/interface/pxe/pxe_undi.c @@ -199,9 +199,10 @@ PXENV_EXIT_t pxenv_undi_transmit ( struct s_PXENV_UNDI_TRANSMIT struct DataBlk *datablk; struct io_buffer *iobuf; struct net_protocol *net_protocol; + struct ll_protocol *ll_protocol = pxe_netdev->ll_protocol; char destaddr[MAX_LL_ADDR_LEN]; const void *ll_dest; - size_t ll_hlen = pxe_netdev->ll_protocol->ll_header_len; + size_t ll_hlen = ll_protocol->ll_header_len; size_t len; unsigned int i; int rc; @@ -259,17 +260,17 @@ PXENV_EXIT_t pxenv_undi_transmit ( struct s_PXENV_UNDI_TRANSMIT copy_from_real ( destaddr, undi_transmit->DestAddr.segment, undi_transmit->DestAddr.offset, - pxe_netdev->ll_protocol->ll_addr_len ); + ll_protocol->ll_addr_len ); ll_dest = destaddr; } else { DBG ( " BCAST" ); - ll_dest = pxe_netdev->ll_protocol->ll_broadcast; + ll_dest = ll_protocol->ll_broadcast; } /* Add link-layer header */ - if ( ( rc = pxe_netdev->ll_protocol->push ( iobuf, pxe_netdev, - net_protocol, - ll_dest )) != 0 ){ + if ( ( rc = ll_protocol->push ( iobuf, ll_dest, + pxe_netdev->ll_addr, + net_protocol->net_proto ))!=0){ free_iob ( iobuf ); undi_transmit->Status = PXENV_STATUS ( rc ); return PXENV_EXIT_FAILURE; @@ -391,10 +392,10 @@ PXENV_EXIT_t pxenv_undi_get_statistics ( struct s_PXENV_UNDI_GET_STATISTICS *undi_get_statistics ) { DBG ( "PXENV_UNDI_GET_STATISTICS" ); - undi_get_statistics->XmtGoodFrames = pxe_netdev->stats.tx_ok; - undi_get_statistics->RcvGoodFrames = pxe_netdev->stats.rx_ok; - undi_get_statistics->RcvCRCErrors = pxe_netdev->stats.rx_err; - undi_get_statistics->RcvResourceErrors = pxe_netdev->stats.rx_err; + undi_get_statistics->XmtGoodFrames = pxe_netdev->tx_stats.good; + undi_get_statistics->RcvGoodFrames = pxe_netdev->rx_stats.good; + undi_get_statistics->RcvCRCErrors = pxe_netdev->rx_stats.bad; + undi_get_statistics->RcvResourceErrors = pxe_netdev->rx_stats.bad; undi_get_statistics->Status = PXENV_STATUS_SUCCESS; return PXENV_EXIT_SUCCESS; @@ -408,7 +409,8 @@ PXENV_EXIT_t pxenv_undi_clear_statistics ( struct s_PXENV_UNDI_CLEAR_STATISTICS *undi_clear_statistics ) { DBG ( "PXENV_UNDI_CLEAR_STATISTICS" ); - memset ( &pxe_netdev->stats, 0, sizeof ( pxe_netdev->stats ) ); + memset ( &pxe_netdev->tx_stats, 0, sizeof ( pxe_netdev->tx_stats ) ); + memset ( &pxe_netdev->rx_stats, 0, sizeof ( pxe_netdev->rx_stats ) ); undi_clear_statistics->Status = PXENV_STATUS_SUCCESS; return PXENV_EXIT_SUCCESS; @@ -545,6 +547,7 @@ PXENV_EXIT_t pxenv_undi_isr ( struct s_PXENV_UNDI_ISR *undi_isr ) { struct io_buffer *iobuf; size_t len; struct ll_protocol *ll_protocol; + const void *ll_dest; const void *ll_source; uint16_t net_proto; size_t ll_hlen; @@ -625,9 +628,8 @@ PXENV_EXIT_t pxenv_undi_isr ( struct s_PXENV_UNDI_ISR *undi_isr ) { /* Strip link-layer header */ ll_protocol = pxe_netdev->ll_protocol; - if ( ( rc = ll_protocol->pull ( iobuf, pxe_netdev, - &net_proto, - &ll_source ) ) != 0 ) { + if ( ( rc = ll_protocol->pull ( iobuf, &ll_dest, &ll_source, + &net_proto ) ) != 0 ) { /* Assume unknown net_proto and no ll_source */ net_proto = 0; ll_source = NULL; diff --git a/gpxe/src/arch/i386/interface/syslinux/com32_call.c b/gpxe/src/arch/i386/interface/syslinux/com32_call.c index 586730cf..4a782dce 100644 --- a/gpxe/src/arch/i386/interface/syslinux/com32_call.c +++ b/gpxe/src/arch/i386/interface/syslinux/com32_call.c @@ -41,7 +41,7 @@ uint16_t __bss16 ( com32_saved_sp ); /** * Interrupt call helper */ -void __cdecl com32_intcall ( uint8_t interrupt, physaddr_t inregs_phys, physaddr_t outregs_phys ) { +void __asmcall com32_intcall ( uint8_t interrupt, physaddr_t inregs_phys, physaddr_t outregs_phys ) { memcpy_user ( virt_to_user( &com32_regs ), 0, phys_to_user ( inregs_phys ), 0, @@ -111,7 +111,7 @@ void __cdecl com32_intcall ( uint8_t interrupt, physaddr_t inregs_phys, physaddr /** * Farcall helper */ -void __cdecl com32_farcall ( uint32_t proc, physaddr_t inregs_phys, physaddr_t outregs_phys ) { +void __asmcall com32_farcall ( uint32_t proc, physaddr_t inregs_phys, physaddr_t outregs_phys ) { memcpy_user ( virt_to_user( &com32_regs ), 0, phys_to_user ( inregs_phys ), 0, @@ -170,7 +170,7 @@ void __cdecl com32_farcall ( uint32_t proc, physaddr_t inregs_phys, physaddr_t o /** * CDECL farcall helper */ -int __cdecl com32_cfarcall ( uint32_t proc, physaddr_t stack, size_t stacksz ) { +int __asmcall com32_cfarcall ( uint32_t proc, physaddr_t stack, size_t stacksz ) { int32_t eax; copy_user_to_rm_stack ( phys_to_user ( stack ), stacksz ); diff --git a/gpxe/src/arch/i386/interface/syslinux/comboot_call.c b/gpxe/src/arch/i386/interface/syslinux/comboot_call.c index 5a400ede..bf6c4c66 100644 --- a/gpxe/src/arch/i386/interface/syslinux/comboot_call.c +++ b/gpxe/src/arch/i386/interface/syslinux/comboot_call.c @@ -35,6 +35,8 @@ #include <gpxe/process.h> #include <gpxe/serial.h> #include <gpxe/init.h> +#include <gpxe/image.h> +#include <usr/imgmgmt.h> /** The "SYSLINUX" version string */ static char __data16_array ( syslinux_version, [] ) = "gPXE " VERSION; @@ -51,6 +53,14 @@ static char __data16_array ( syslinux_configuration_file, [] ) = ""; static uint8_t __data16 ( comboot_feature_flags ) = COMBOOT_FEATURE_IDLE_LOOP; #define comboot_feature_flags __use_data16 ( comboot_feature_flags ) +typedef union { + syslinux_pm_regs pm; syslinux_rm_regs rm; +} syslinux_regs; + +/** Initial register values for INT 22h AX=1Ah and 1Bh */ +static syslinux_regs __text16 ( comboot_initial_regs ); +#define comboot_initial_regs __use_text16 ( comboot_initial_regs ) + static struct segoff __text16 ( int20_vector ); #define int20_vector __use_text16 ( int20_vector ) @@ -65,12 +75,10 @@ extern void int21_wrapper ( void ); extern void int22_wrapper ( void ); /* setjmp/longjmp context buffer used to return after loading an image */ -jmp_buf comboot_return; +rmjmp_buf comboot_return; -/* Command line to execute when returning via comboot_return - * with COMBOOT_RETURN_RUN_KERNEL - */ -char *comboot_kernel_cmdline; +/* Replacement image when exiting with COMBOOT_EXIT_RUN_KERNEL */ +struct image *comboot_replacement_image; /* Mode flags set by INT 22h AX=0017h */ static uint16_t comboot_graphics_mode = 0; @@ -154,79 +162,101 @@ void comboot_force_text_mode ( void ) { /** - * Run the kernel specified in comboot_kernel_cmdline + * Fetch kernel and optional initrd */ -void comboot_run_kernel ( ) -{ - char *initrd; - - comboot_force_text_mode ( ); - - DBG ( "COMBOOT: executing image '%s'\n", comboot_kernel_cmdline ); +static int comboot_fetch_kernel ( char *kernel_file, char *cmdline ) { + struct image *kernel = NULL; + struct image *initrd = NULL; + char *initrd_file; + int rc; /* Find initrd= parameter, if any */ - if ( ( initrd = strstr ( comboot_kernel_cmdline, "initrd=" ) ) ) { - char old_char = '\0'; - char *initrd_end = strchr( initrd, ' ' ); - - /* Replace space after end of parameter - * with a nul terminator if this is not - * the last parameter - */ - if ( initrd_end ) { - old_char = *initrd_end; - *initrd_end = '\0'; - } + if ( ( initrd_file = strstr ( cmdline, "initrd=" ) ) != NULL ) { + char *initrd_end; - /* Replace = with space to get 'initrd filename' - * command suitable for system() - */ - initrd[6] = ' '; + /* skip "initrd=" */ + initrd_file += 7; - DBG( "COMBOOT: loading initrd '%s'\n", initrd ); + /* Find terminating space, if any, and replace with NUL */ + initrd_end = strchr ( initrd_file, ' ' ); + if ( initrd_end ) + *initrd_end = '\0'; - system ( initrd ); + DBG ( "COMBOOT: fetching initrd '%s'\n", initrd_file ); - /* Restore space after parameter */ - if ( initrd_end ) { - *initrd_end = old_char; + /* Allocate and fetch initrd */ + initrd = alloc_image(); + if ( ! initrd ) { + DBG ( "COMBOOT: could not allocate initrd\n" ); + rc = -ENOMEM; + goto out; + } + if ( ( rc = imgfetch ( initrd, initrd_file, + register_image ) ) != 0 ) { + DBG ( "COMBOOT: could not fetch initrd: %s\n", + strerror ( rc ) ); + goto out; } - /* Restore = */ - initrd[6] = '='; + /* Restore space after initrd name, if applicable */ + if ( initrd_end ) + *initrd_end = ' '; } - /* Load kernel */ - DBG ( "COMBOOT: loading kernel '%s'\n", comboot_kernel_cmdline ); - system ( comboot_kernel_cmdline ); - - free ( comboot_kernel_cmdline ); + DBG ( "COMBOOT: fetching kernel '%s'\n", kernel_file ); - /* Boot */ - system ( "boot" ); + /* Allocate and fetch kernel */ + kernel = alloc_image(); + if ( ! kernel ) { + DBG ( "COMBOOT: could not allocate kernel\n" ); + rc = -ENOMEM; + goto out; + } + if ( ( rc = imgfetch ( kernel, kernel_file, + register_image ) ) != 0 ) { + DBG ( "COMBOOT: could not fetch kernel: %s\n", + strerror ( rc ) ); + goto out; + } + if ( ( rc = image_set_cmdline ( kernel, cmdline ) ) != 0 ) { + DBG ( "COMBOOT: could not set kernel command line: %s\n", + strerror ( rc ) ); + goto out; + } - DBG ( "COMBOOT: back from executing command\n" ); + /* Store kernel as replacement image */ + assert ( comboot_replacement_image == NULL ); + comboot_replacement_image = image_get ( kernel ); + + out: + /* Drop image references unconditionally; either we want to + * discard them, or they have been registered and we should + * drop out local reference. + */ + image_put ( kernel ); + image_put ( initrd ); + return rc; } /** * Terminate program interrupt handler */ -static __cdecl void int20 ( struct i386_all_regs *ix86 __unused ) { - longjmp ( comboot_return, COMBOOT_RETURN_EXIT ); +static __asmcall void int20 ( struct i386_all_regs *ix86 __unused ) { + rmlongjmp ( comboot_return, COMBOOT_EXIT ); } /** * DOS-compatible API */ -static __cdecl void int21 ( struct i386_all_regs *ix86 ) { +static __asmcall void int21 ( struct i386_all_regs *ix86 ) { ix86->flags |= CF; switch ( ix86->regs.ah ) { case 0x00: case 0x4C: /* Terminate program */ - longjmp ( comboot_return, COMBOOT_RETURN_EXIT ); + rmlongjmp ( comboot_return, COMBOOT_EXIT ); break; case 0x01: /* Get Key with Echo */ @@ -287,14 +317,14 @@ static __cdecl void int21 ( struct i386_all_regs *ix86 ) { /** * SYSLINUX API */ -static __cdecl void int22 ( struct i386_all_regs *ix86 ) { +static __asmcall void int22 ( struct i386_all_regs *ix86 ) { ix86->flags |= CF; switch ( ix86->regs.ax ) { case 0x0001: /* Get Version */ /* Number of INT 22h API functions available */ - ix86->regs.ax = 0x0018; + ix86->regs.ax = 0x001B; /* SYSLINUX version number */ ix86->regs.ch = 0; /* major */ @@ -323,17 +353,15 @@ static __cdecl void int22 ( struct i386_all_regs *ix86 ) { char cmd[len + 1]; copy_from_user ( cmd, cmd_u, 0, len + 1 ); DBG ( "COMBOOT: executing command '%s'\n", cmd ); - - comboot_kernel_cmdline = strdup ( cmd ); - - DBG ( "COMBOOT: returning to run image...\n" ); - longjmp ( comboot_return, COMBOOT_RETURN_RUN_KERNEL ); + system ( cmd ); + DBG ( "COMBOOT: exiting after executing command...\n" ); + rmlongjmp ( comboot_return, COMBOOT_EXIT_COMMAND ); } break; case 0x0004: /* Run default command */ /* FIXME: just exit for now */ - longjmp ( comboot_return, COMBOOT_RETURN_EXIT ); + rmlongjmp ( comboot_return, COMBOOT_EXIT_COMMAND ); break; case 0x0005: /* Force text mode */ @@ -518,21 +546,21 @@ static __cdecl void int22 ( struct i386_all_regs *ix86 ) { userptr_t cmd_u = real_to_user ( ix86->segs.es, ix86->regs.bx ); int file_len = strlen_user ( file_u, 0 ); int cmd_len = strlen_user ( cmd_u, 0 ); - char file[file_len + 1 + cmd_len + 7 + 1]; + char file[file_len + 1]; char cmd[cmd_len + 1]; - memcpy( file, "kernel ", 7 ); - copy_from_user ( file + 7, file_u, 0, file_len + 1 ); + copy_from_user ( file, file_u, 0, file_len + 1 ); copy_from_user ( cmd, cmd_u, 0, cmd_len + 1 ); - strcat ( file, " " ); - strcat ( file, cmd ); - - DBG ( "COMBOOT: run kernel image '%s'\n", file ); - comboot_kernel_cmdline = strdup ( file ); - - DBG ( "COMBOOT: returning to run image...\n" ); - longjmp ( comboot_return, COMBOOT_RETURN_RUN_KERNEL ); + DBG ( "COMBOOT: run kernel %s %s\n", file, cmd ); + comboot_fetch_kernel ( file, cmd ); + /* Technically, we should return if we + * couldn't load the kernel, but it's not safe + * to do that since we have just overwritten + * part of the COMBOOT program's memory space. + */ + DBG ( "COMBOOT: exiting to run kernel...\n" ); + rmlongjmp ( comboot_return, COMBOOT_EXIT_RUN_KERNEL ); } break; @@ -549,6 +577,58 @@ static __cdecl void int22 ( struct i386_all_regs *ix86 ) { ix86->flags &= ~CF; break; + case 0x001B: /* Cleanup, shuffle and boot to real mode */ + if ( ix86->regs.cx > COMBOOT_MAX_SHUFFLE_DESCRIPTORS ) + break; + + /* Perform final cleanup */ + shutdown ( SHUTDOWN_BOOT ); + + /* Perform sequence of copies */ + shuffle ( ix86->segs.es, ix86->regs.di, ix86->regs.cx ); + + /* Copy initial register values to .text16 */ + memcpy_user ( real_to_user ( rm_cs, (unsigned) __from_text16 ( &comboot_initial_regs ) ), 0, + real_to_user ( ix86->segs.ds, ix86->regs.si ), 0, + sizeof(syslinux_rm_regs) ); + + /* Load initial register values */ + __asm__ __volatile__ ( + REAL_CODE ( + /* Point SS:SP at the register value structure */ + "pushw %%cs\n\t" + "popw %%ss\n\t" + "movw $comboot_initial_regs, %%sp\n\t" + + /* Segment registers */ + "popw %%es\n\t" + "popw %%ax\n\t" /* Skip CS */ + "popw %%ds\n\t" + "popw %%ax\n\t" /* Skip SS for now */ + "popw %%fs\n\t" + "popw %%gs\n\t" + + /* GP registers */ + "popl %%eax\n\t" + "popl %%ecx\n\t" + "popl %%edx\n\t" + "popl %%ebx\n\t" + "popl %%ebp\n\t" /* Skip ESP for now */ + "popl %%ebp\n\t" + "popl %%esi\n\t" + "popl %%edi\n\t" + + /* Load correct SS:ESP */ + "movw $(comboot_initial_regs + 6), %%sp\n\t" + "popw %%ss\n\t" + "movl %%cs:(comboot_initial_regs + 28), %%esp\n\t" + + "ljmp *%%cs:(comboot_initial_regs + 44)\n\t" + ) + : : ); + + break; + default: DBG ( "COMBOOT unknown int22 function %04x\n", ix86->regs.ax ); break; @@ -596,3 +676,18 @@ void hook_comboot_interrupts ( ) { hook_bios_interrupt ( 0x22, ( unsigned int ) int22_wrapper, &int22_vector ); } + +/** + * Unhook BIOS interrupts related to COMBOOT API (INT 20h, 21h, 22h) + */ +void unhook_comboot_interrupts ( ) { + + unhook_bios_interrupt ( 0x20, ( unsigned int ) int20_wrapper, + &int20_vector ); + + unhook_bios_interrupt ( 0x21, ( unsigned int ) int21_wrapper, + &int21_vector ); + + unhook_bios_interrupt ( 0x22, ( unsigned int ) int22_wrapper, + &int22_vector ); +} diff --git a/gpxe/src/arch/i386/prefix/boot1a.S b/gpxe/src/arch/i386/prefix/boot1a.S new file mode 100644 index 00000000..557462f1 --- /dev/null +++ b/gpxe/src/arch/i386/prefix/boot1a.S @@ -0,0 +1,410 @@ +# This code is no longer used in Etherboot. It is not maintained and +# may not work. + + +# +# Copyright (c) 1998 Robert Nordier +# All rights reserved. +# Very small bootrom changes by Luigi Rizzo +# <comment author="Luigi Rizzo"> +# I recently had the problem of downloading the etherboot code +# from a hard disk partition instead of a floppy, and noticed that +# floppyload.S does not do the job. With a bit of hacking to +# the FreeBSD's boot1.s code, I managed to obtain a boot sector +# which works both for floppies and hard disks -- basically you +# do something like +# +# cat boot1a bin32/<yourcard>.lzrom > /dev/ad0s4 +# +# (or whatever is the HD partition you are using, I am using slice +# 4 on FreeBSD) and you are up and running. +# Then with "fdisk" you have to mark your partition as having type "1" +# (which is listed as DOS-- but basically it must be something matching +# the variable PRT_BSD in the assembly source below). +# </comment> +# +# Redistribution and use in source and binary forms are freely +# permitted provided that the above copyright notice and this +# paragraph and the following disclaimer are duplicated in all +# such forms. +# +# This software is provided "AS IS" and without any express or +# implied warranties, including, without limitation, the implied +# warranties of merchantability and fitness for a particular +# purpose. +# +# Makefile: +#boot1a: boot1a.out +# objcopy -S -O binary boot1a.out boot1a +# +#boot1a.out: boot1a.o +# ld -nostdlib -static -N -e start -Ttext 0x7c00 -o boot1a.out boot1a.o +# +#boot1a.o: boot1a.s +# as --defsym FLAGS=0x80 boot1a.s -o boot1a.o +# +# + +# $FreeBSD: src/sys/boot/i386/boot2/boot1.s,v 1.10.2.2 2000/07/07 21:12:32 jhb Exp $ + +# Memory Locations + .set MEM_REL,0x700 # Relocation address + .set MEM_ARG,0x900 # Arguments + .set MEM_ORG,0x7c00 # Origin + .set MEM_BUF,0x8c00 # Load area + .set MEM_BTX,0x9000 # BTX start + .set MEM_JMP,0x9010 # BTX entry point + .set MEM_USR,0xa000 # Client start + .set BDA_BOOT,0x472 # Boot howto flag + +# Partition Constants + .set PRT_OFF,0x1be # Partition offset + .set PRT_NUM,0x4 # Partitions + .set PRT_BSD,0x1 # Partition type + +# Flag Bits + .set FL_PACKET,0x80 # Packet mode + +# Misc. Constants + .set SIZ_PAG,0x1000 # Page size + .set SIZ_SEC,0x200 # Sector size + + .globl start + .globl xread + .code16 + +start: jmp main # Start recognizably + + .org 0x4,0x90 +# +# Trampoline used by boot2 to call read to read data from the disk via +# the BIOS. Call with: +# +# %cx:%ax - long - LBA to read in +# %es:(%bx) - caddr_t - buffer to read data into +# %dl - byte - drive to read from +# %dh - byte - num sectors to read +# + +xread: push %ss # Address + pop %ds # data +# +# Setup an EDD disk packet and pass it to read +# +xread.1: # Starting + pushl $0x0 # absolute + push %cx # block + push %ax # number + push %es # Address of + push %bx # transfer buffer + xor %ax,%ax # Number of + movb %dh,%al # blocks to + push %ax # transfer + push $0x10 # Size of packet + mov %sp,%bp # Packet pointer + callw read # Read from disk + lea 0x10(%bp),%sp # Clear stack + lret # To far caller +# +# Load the rest of boot2 and BTX up, copy the parts to the right locations, +# and start it all up. +# + +# +# Setup the segment registers to flat addressing (segment 0) and setup the +# stack to end just below the start of our code. +# +main: cld # String ops inc + xor %cx,%cx # Zero + mov %cx,%es # Address + mov %cx,%ds # data + mov %cx,%ss # Set up + mov $start,%sp # stack +# +# Relocate ourself to MEM_REL. Since %cx == 0, the inc %ch sets +# %cx == 0x100. +# + mov %sp,%si # Source + mov $MEM_REL,%di # Destination + incb %ch # Word count + rep # Copy + movsw # code +# +# If we are on a hard drive, then load the MBR and look for the first +# FreeBSD slice. We use the fake partition entry below that points to +# the MBR when we call nread. The first pass looks for the first active +# FreeBSD slice. The second pass looks for the first non-active FreeBSD +# slice if the first one fails. +# + mov $part4,%si # Partition + cmpb $0x80,%dl # Hard drive? + jb main.4 # No + movb $0x1,%dh # Block count + callw nread # Read MBR + mov $0x1,%cx # Two passes +main.1: mov $MEM_BUF+PRT_OFF,%si # Partition table + movb $0x1,%dh # Partition +main.2: cmpb $PRT_BSD,0x4(%si) # Our partition type? + jne main.3 # No + jcxz main.5 # If second pass + testb $0x80,(%si) # Active? + jnz main.5 # Yes +main.3: add $0x10,%si # Next entry + incb %dh # Partition + cmpb $0x1+PRT_NUM,%dh # In table? + jb main.2 # Yes + dec %cx # Do two + jcxz main.1 # passes +# +# If we get here, we didn't find any FreeBSD slices at all, so print an +# error message and die. +# +booterror: mov $msg_part,%si # Message + jmp error # Error +# +# Floppies use partition 0 of drive 0. +# +main.4: xor %dx,%dx # Partition:drive +# +# Ok, we have a slice and drive in %dx now, so use that to locate and load +# boot2. %si references the start of the slice we are looking for, so go +# ahead and load up the first 16 sectors (boot1 + boot2) from that. When +# we read it in, we conveniently use 0x8c00 as our transfer buffer. Thus, +# boot1 ends up at 0x8c00, and boot2 starts at 0x8c00 + 0x200 = 0x8e00. +# The first part of boot2 is the disklabel, which is 0x200 bytes long. +# The second part is BTX, which is thus loaded into 0x9000, which is where +# it also runs from. The boot2.bin binary starts right after the end of +# BTX, so we have to figure out where the start of it is and then move the +# binary to 0xb000. Normally, BTX clients start at MEM_USR, or 0xa000, but +# when we use btxld create boot2, we use an entry point of 0x1000. That +# entry point is relative to MEM_USR; thus boot2.bin starts at 0xb000. +# +main.5: mov %dx,MEM_ARG # Save args + movb $0x2,%dh # Sector count + mov $0x7e00, %bx + callw nreadbx # Read disk + movb $0x40,%dh # Sector count + movb %dh, %al + callw puthex + mov $0x7e00, %bx + callw nreadbx # Read disk + push %si + mov $msg_r1,%si + callw putstr + pop %si + lcall $0x800,$0 # enter the rom code + int $0x19 + +msg_r1: .asciz " done\r\n" + +.if 0 + mov $MEM_BTX,%bx # BTX + mov 0xa(%bx),%si # Get BTX length and set + add %bx,%si # %si to start of boot2.bin + mov $MEM_USR+SIZ_PAG,%di # Client page 1 + mov $MEM_BTX+0xe*SIZ_SEC,%cx # Byte + sub %si,%cx # count + rep # Relocate + movsb # client + sub %di,%cx # Byte count + xorb %al,%al # Zero assumed bss from + rep # the end of boot2.bin + stosb # up to 0x10000 + callw seta20 # Enable A20 + jmp start+MEM_JMP-MEM_ORG # Start BTX +# +# Enable A20 so we can access memory above 1 meg. +# +seta20: cli # Disable interrupts +seta20.1: inb $0x64,%al # Get status + testb $0x2,%al # Busy? + jnz seta20.1 # Yes + movb $0xd1,%al # Command: Write + outb %al,$0x64 # output port +seta20.2: inb $0x64,%al # Get status + testb $0x2,%al # Busy? + jnz seta20.2 # Yes + movb $0xdf,%al # Enable + outb %al,$0x60 # A20 + sti # Enable interrupts + retw # To caller +.endif +# +# Trampoline used to call read from within boot1. +# +nread: mov $MEM_BUF,%bx # Transfer buffer +nreadbx: # same but address is in bx + mov 0x8(%si),%ax # Get + mov 0xa(%si),%cx # LBA + push %bx + push %ax + callw putword + pop %ax + pop %bx + push %cs # Read from + callw xread.1 # disk + jnc return # If success, return + mov $msg_read,%si # Otherwise, set the error + # message and fall through to + # the error routine +# +# Print out the error message pointed to by %ds:(%si) followed +# by a prompt, wait for a keypress, and then reboot the machine. +# +error: callw putstr # Display message + mov $prompt,%si # Display + callw putstr # prompt + xorb %ah,%ah # BIOS: Get + int $0x16 # keypress + movw $0x1234, BDA_BOOT # Do a warm boot + ljmp $0xffff,$0x0 # reboot the machine +# +# Display a null-terminated string using the BIOS output. +# +putstr.0: call putchar +putstr: lodsb # Get char + testb %al,%al # End of string? + jne putstr.0 # No + retw + +putword: push %ax + movb $'.', %al + callw putchar + movb %ah, %al + callw puthex + pop %ax +puthex: push %ax + shr $4, %al + callw putdigit + pop %ax +putdigit: + andb $0xf, %al + addb $0x30, %al + cmpb $0x39, %al + jbe putchar + addb $7, %al +putchar: push %ax + mov $0x7,%bx + movb $0xe,%ah + int $0x10 + pop %ax + retw + +# +# Overused return code. ereturn is used to return an error from the +# read function. Since we assume putstr succeeds, we (ab)use the +# same code when we return from putstr. +# +ereturn: movb $0x1,%ah # Invalid + stc # argument +return: retw # To caller +# +# Reads sectors from the disk. If EDD is enabled, then check if it is +# installed and use it if it is. If it is not installed or not enabled, then +# fall back to using CHS. Since we use a LBA, if we are using CHS, we have to +# fetch the drive parameters from the BIOS and divide it out ourselves. +# Call with: +# +# %dl - byte - drive number +# stack - 10 bytes - EDD Packet +# +read: push %dx # Save + movb $0x8,%ah # BIOS: Get drive + int $0x13 # parameters + movb %dh,%ch # Max head number + pop %dx # Restore + jc return # If error + andb $0x3f,%cl # Sectors per track + jz ereturn # If zero + cli # Disable interrupts + mov 0x8(%bp),%eax # Get LBA + push %dx # Save + movzbl %cl,%ebx # Divide by + xor %edx,%edx # sectors + div %ebx # per track + movb %ch,%bl # Max head number + movb %dl,%ch # Sector number + inc %bx # Divide by + xorb %dl,%dl # number + div %ebx # of heads + movb %dl,%bh # Head number + pop %dx # Restore + cmpl $0x3ff,%eax # Cylinder number supportable? + sti # Enable interrupts + ja read.7 # No, try EDD + xchgb %al,%ah # Set up cylinder + rorb $0x2,%al # number + orb %ch,%al # Merge + inc %ax # sector + xchg %ax,%cx # number + movb %bh,%dh # Head number + subb %ah,%al # Sectors this track + mov 0x2(%bp),%ah # Blocks to read + cmpb %ah,%al # To read + jb read.2 # this + movb %ah,%al # track +read.2: mov $0x5,%di # Try count +read.3: les 0x4(%bp),%bx # Transfer buffer + push %ax # Save + movb $0x2,%ah # BIOS: Read + int $0x13 # from disk + pop %bx # Restore + jnc read.4 # If success + dec %di # Retry? + jz read.6 # No + xorb %ah,%ah # BIOS: Reset + int $0x13 # disk system + xchg %bx,%ax # Block count + jmp read.3 # Continue +read.4: movzbw %bl,%ax # Sectors read + add %ax,0x8(%bp) # Adjust + jnc read.5 # LBA, + incw 0xa(%bp) # transfer +read.5: shlb %bl # buffer + add %bl,0x5(%bp) # pointer, + sub %al,0x2(%bp) # block count + ja read # If not done +read.6: retw # To caller +read.7: testb $FL_PACKET,%cs:MEM_REL+flags-start # LBA support enabled? + jz ereturn # No, so return an error + mov $0x55aa,%bx # Magic + push %dx # Save + movb $0x41,%ah # BIOS: Check + int $0x13 # extensions present + pop %dx # Restore + jc return # If error, return an error + cmp $0xaa55,%bx # Magic? + jne ereturn # No, so return an error + testb $0x1,%cl # Packet interface? + jz ereturn # No, so return an error + mov %bp,%si # Disk packet + movb $0x42,%ah # BIOS: Extended + int $0x13 # read + retw # To caller + +# Messages + +msg_read: .asciz "Rd" +msg_part: .asciz "Boot" + +prompt: .asciz " err\r\n" + +flags: .byte FLAGS # Flags + + .org PRT_OFF,0x90 + +# Partition table + + .fill 0x30,0x1,0x0 +part4: .byte 0x80 + .byte 0x00 # start head + .byte 0x01 # start sector (6 bits) + start cyl (2 bit) + .byte 0x00 # start cyl (low 8 bits) + .byte 0x1 # part.type + .byte 0xff # end head + .byte 0xff # end sect (6) + end_cyl(2) + .byte 0xff # end cyl + .byte 0x00, 0x00, 0x00, 0x00 # explicit start + .byte 0x50, 0xc3, 0x00, 0x00 # 50000 sectors long, bleh + + .word 0xaa55 # Magic number diff --git a/gpxe/src/arch/i386/prefix/dskprefix.S b/gpxe/src/arch/i386/prefix/dskprefix.S index cdc43b37..0156812a 100644 --- a/gpxe/src/arch/i386/prefix/dskprefix.S +++ b/gpxe/src/arch/i386/prefix/dskprefix.S @@ -144,8 +144,8 @@ got_sectors: /* Jump to loaded copy */ ljmp $SYSSEG, $start_runtime -endseg: .word SYSSEG + _load_size_pgh - .section ".zinfo.fixup", "a" /* Compressor fixup information */ +endseg: .word SYSSEG + _filesz_pgh + .section ".zinfo.fixup", "a", @progbits /* Compressor fixups */ .ascii "SUBW" .long endseg .long 16 @@ -353,6 +353,7 @@ msg1end: .word 0xAA55 start_runtime: + /* Install gPXE */ call install /* Set up real-mode stack */ @@ -368,7 +369,10 @@ start_runtime: pushl $main pushw %cs call prot_call - popl %eax /* discard */ + popl %ecx /* discard */ + + /* Uninstall gPXE */ + call uninstall /* Boot next device */ int $0x18 diff --git a/gpxe/src/arch/i386/prefix/hdprefix.S b/gpxe/src/arch/i386/prefix/hdprefix.S index 56fcb36d..086d7f45 100644 --- a/gpxe/src/arch/i386/prefix/hdprefix.S +++ b/gpxe/src/arch/i386/prefix/hdprefix.S @@ -63,9 +63,9 @@ max_sector: max_head: .byte 0 load_length: - .long _load_size_sect + .long _filesz_sect - .section ".zinfo.fixup", "a" /* Compressor fixup information */ + .section ".zinfo.fixup", "a", @progbits /* Compressor fixups */ .ascii "SUBL" .long load_length .long 512 @@ -82,6 +82,7 @@ load_failed: .byte 0x55, 0xaa start_image: + /* Install gPXE */ call install /* Set up real-mode stack */ @@ -97,7 +98,10 @@ start_image: pushl $main pushw %cs call prot_call - popl %eax /* discard */ + popl %ecx /* discard */ + + /* Uninstall gPXE */ + call uninstall /* Boot next device */ int $0x18 diff --git a/gpxe/src/arch/i386/prefix/kkpxeprefix.S b/gpxe/src/arch/i386/prefix/kkpxeprefix.S new file mode 100644 index 00000000..e0bea0cd --- /dev/null +++ b/gpxe/src/arch/i386/prefix/kkpxeprefix.S @@ -0,0 +1,8 @@ +/***************************************************************************** + * PXE prefix that keeps the whole PXE stack present + ***************************************************************************** + */ + +#define PXELOADER_KEEP_UNDI +#define PXELOADER_KEEP_PXE +#include "pxeprefix.S" diff --git a/gpxe/src/arch/i386/prefix/libprefix.S b/gpxe/src/arch/i386/prefix/libprefix.S index ae2a491f..42189135 100644 --- a/gpxe/src/arch/i386/prefix/libprefix.S +++ b/gpxe/src/arch/i386/prefix/libprefix.S @@ -18,8 +18,6 @@ */ .arch i386 - .section ".prefix.lib", "awx", @progbits - .section ".data16", "aw", @progbits /** * High memory temporary load address @@ -53,7 +51,7 @@ * %ds:di : next character in output buffer (if applicable) ***************************************************************************** */ - .section ".prefix.lib" + .section ".prefix.lib", "awx", @progbits .code16 .globl print_character print_character: @@ -93,7 +91,7 @@ print_character: * %ds:di : next character in output buffer (if applicable) ***************************************************************************** */ - .section ".prefix.lib" + .section ".prefix.lib", "awx", @progbits .code16 .globl print_message print_message: @@ -123,7 +121,7 @@ print_message: * %ds:di : next character in output buffer (if applicable) ***************************************************************************** */ - .section ".prefix.lib" + .section ".prefix.lib", "awx", @progbits .code16 .globl print_hex_dword print_hex_dword: @@ -171,7 +169,7 @@ print_hex_nibble: * %ds:di : next character in output buffer (if applicable) ***************************************************************************** */ - .section ".prefix.lib" + .section ".prefix.lib", "awx", @progbits .code16 .globl print_pci_busdevfn print_pci_busdevfn: @@ -181,14 +179,14 @@ print_pci_busdevfn: xchgb %al, %ah call print_hex_byte /* Print ":" */ - movb $':', %al + movb $( ':' ), %al call print_character /* Print device */ movb %ah, %al shrb $3, %al call print_hex_byte /* Print "." */ - movb $'.', %al + movb $( '.' ), %al call print_character /* Print function */ movb %ah, %al @@ -199,6 +197,39 @@ print_pci_busdevfn: ret .size print_pci_busdevfn, . - print_pci_busdevfn +/***************************************************************************** + * Utility function: clear current line + * + * Parameters: + * %ds:di : output buffer (or %di=0 to print to console) + * Returns: + * %ds:di : next character in output buffer (if applicable) + ***************************************************************************** + */ + .section ".prefix.lib", "awx", @progbits + .code16 + .globl print_kill_line +print_kill_line: + /* Preserve registers */ + pushw %ax + pushw %cx + /* Print CR */ + movb $( '\r' ), %al + call print_character + /* Print 79 spaces */ + movb $( ' ' ), %al + movw $79, %cx +1: call print_character + loop 1b + /* Print CR */ + movb $( '\r' ), %al + call print_character + /* Restore registers and return */ + popw %cx + popw %ax + ret + .size print_kill_line, . - print_kill_line + /**************************************************************************** * pm_call (real-mode near call) * @@ -223,7 +254,7 @@ print_pci_busdevfn: #ifndef KEEP_IT_REAL /* GDT for protected-mode calls */ - .section ".prefix.lib" + .section ".prefix.lib", "awx", @progbits .align 16 pm_call_vars: gdt: @@ -246,7 +277,7 @@ gdt_end: .equ gdt_length, . - gdt .size gdt, . - gdt - .section ".prefix.lib" + .section ".prefix.lib", "awx", @progbits .align 16 pm_saved_gdt: .long 0, 0 @@ -255,7 +286,7 @@ pm_saved_gdt: .equ pm_call_vars_size, . - pm_call_vars #define PM_CALL_VAR(x) ( -pm_call_vars_size + ( (x) - pm_call_vars ) ) - .section ".prefix.lib" + .section ".prefix.lib", "awx", @progbits .code16 pm_call: /* Preserve registers, flags, and RM return point */ @@ -308,7 +339,7 @@ pm_call: /* Switch CPU to protected mode and load up segment registers */ pushl %eax cli - lgdt PM_CALL_VAR(gdt)(%bp) + data32 lgdt PM_CALL_VAR(gdt)(%bp) movl %cr0, %eax orb $CR0_PE, %al movl %eax, %cr0 @@ -344,7 +375,7 @@ pm_call: popw %es popw %fs popw %gs - lgdt PM_CALL_VAR(pm_saved_gdt)(%bp) + data32 lgdt PM_CALL_VAR(pm_saved_gdt)(%bp) popfl movw %bp, %sp popw %bp @@ -378,7 +409,7 @@ set_seg_base: * None **************************************************************************** */ - .section ".prefix.lib" + .section ".prefix.lib", "awx", @progbits .code16 copy_bytes: pushl %ecx @@ -403,7 +434,7 @@ copy_bytes: * none **************************************************************************** */ - .section ".prefix.lib" + .section ".prefix.lib", "awx", @progbits .code16 install_block: @@ -500,35 +531,93 @@ install_block: * none **************************************************************************** */ - .section ".prefix.lib" + .section ".prefix.lib", "awx", @progbits .code16 .globl alloc_basemem alloc_basemem: + /* Preserve registers */ + pushw %fs + /* FBMS => %ax as segment address */ - movw $0x40, %ax - movw %ax, %fs + pushw $0x40 + popw %fs movw %fs:0x13, %ax shlw $6, %ax - /* .data16 segment address */ - subw $_data16_size_pgh, %ax + /* Calculate .data16 segment address */ + subw $_data16_memsz_pgh, %ax pushw %ax - /* .text16 segment address */ - subw $_text16_size_pgh, %ax + /* Calculate .text16 segment address */ + subw $_text16_memsz_pgh, %ax pushw %ax /* Update FBMS */ shrw $6, %ax movw %ax, %fs:0x13 - /* Return */ + /* Retrieve .text16 and .data16 segment addresses */ popw %ax popw %bx + + /* Restore registers and return */ + popw %fs ret .size alloc_basemem, . - alloc_basemem /**************************************************************************** + * free_basemem (real-mode near call) + * + * Free space allocated with alloc_basemem. + * + * Parameters: + * %ax : .text16 segment address + * %bx : .data16 segment address + * Returns: + * %ax : 0 if successfully freed + * Corrupts: + * none + **************************************************************************** + */ + .section ".text16", "ax", @progbits + .code16 + .globl free_basemem +free_basemem: + /* Preserve registers */ + pushw %fs + + /* Check FBMS counter */ + pushw %ax + shrw $6, %ax + pushw $0x40 + popw %fs + cmpw %ax, %fs:0x13 + popw %ax + jne 1f + + /* Check hooked interrupt count */ + cmpw $0, %cs:hooked_bios_interrupts + jne 1f + + /* OK to free memory */ + addw $_text16_memsz_pgh, %ax + addw $_data16_memsz_pgh, %ax + shrw $6, %ax + movw %ax, %fs:0x13 + xorw %ax, %ax + +1: /* Restore registers and return */ + popw %fs + ret + .size free_basemem, . - free_basemem + + .section ".text16.data", "aw", @progbits + .globl hooked_bios_interrupts +hooked_bios_interrupts: + .word 0 + .size hooked_bios_interrupts, . - hooked_bios_interrupts + +/**************************************************************************** * install (real-mode near call) * * Install all text and data segments. @@ -542,7 +631,7 @@ alloc_basemem: * none **************************************************************************** */ - .section ".prefix.lib" + .section ".prefix.lib", "awx", @progbits .code16 .globl install install: @@ -577,7 +666,7 @@ install: * none **************************************************************************** */ - .section ".prefix.lib" + .section ".prefix.lib", "awx", @progbits .code16 .globl install_prealloc install_prealloc: @@ -594,19 +683,19 @@ install_prealloc: jnz 1f movw %cs, %si shll $4, %esi -1: addl $_payload_offset, %esi +1: addl $_payload_lma, %esi /* Install .text16 and .data16 */ pushl %edi movzwl %ax, %edi shll $4, %edi - movl $_text16_size, %ecx + movl $_text16_memsz, %ecx movl %ecx, %edx call install_block /* .text16 */ movzwl %bx, %edi shll $4, %edi - movl $_data16_progbits_size, %ecx - movl $_data16_size, %edx + movl $_data16_filesz, %ecx + movl $_data16_memsz, %edx call install_block /* .data16 */ popl %edi @@ -622,8 +711,8 @@ install_prealloc: * prior to reading the E820 memory map and relocating * properly. */ - movl $_textdata_progbits_size, %ecx - movl $_textdata_size, %edx + movl $_textdata_filesz, %ecx + movl $_textdata_memsz, %edx call install_block /* Initialise librm at current location */ @@ -659,7 +748,7 @@ install_prealloc: .size install_prealloc, . - install_prealloc /* Vectors for far calls to .text16 functions */ - .section ".data16" + .section ".data16", "aw", @progbits #ifdef KEEP_IT_REAL init_libkir_vector: .word init_libkir @@ -676,30 +765,53 @@ prot_call_vector: .size prot_call_vector, . - prot_call_vector #endif +/**************************************************************************** + * uninstall (real-mode near call) + * + * Uninstall all text and data segments. + * + * Parameters: + * %ax : .text16 segment address + * %bx : .data16 segment address + * Returns: + * none + * Corrupts: + * none + **************************************************************************** + */ + .section ".text16", "ax", @progbits + .code16 + .globl uninstall +uninstall: + call free_basemem + ret + .size uninstall, . - uninstall + + /* File split information for the compressor */ #if COMPRESS - .section ".zinfo", "a" + .section ".zinfo", "a", @progbits .ascii "COPY" - .long _prefix_load_offset - .long _prefix_progbits_size + .long _prefix_lma + .long _prefix_filesz .long _max_align .ascii "PACK" - .long _text16_load_offset - .long _text16_progbits_size + .long _text16_lma + .long _text16_filesz .long _max_align .ascii "PACK" - .long _data16_load_offset - .long _data16_progbits_size + .long _data16_lma + .long _data16_filesz .long _max_align .ascii "PACK" - .long _textdata_load_offset - .long _textdata_progbits_size + .long _textdata_lma + .long _textdata_filesz .long _max_align #else /* COMPRESS */ - .section ".zinfo", "a" + .section ".zinfo", "a", @progbits .ascii "COPY" - .long _prefix_load_offset - .long _load_size + .long _prefix_lma + .long _filesz .long _max_align #endif /* COMPRESS */ diff --git a/gpxe/src/arch/i386/prefix/lkrnprefix.S b/gpxe/src/arch/i386/prefix/lkrnprefix.S index c1e92f57..094263d2 100644 --- a/gpxe/src/arch/i386/prefix/lkrnprefix.S +++ b/gpxe/src/arch/i386/prefix/lkrnprefix.S @@ -92,9 +92,9 @@ setup_sects: root_flags: .word 0 syssize: - .long _load_size_pgh - PREFIXPGH + .long _filesz_pgh - PREFIXPGH - .section ".zinfo.fixup", "a" /* Compressor fixup information */ + .section ".zinfo.fixup", "a", @progbits /* Compressor fixups */ .ascii "SUBL" .long syssize .long 16 @@ -189,6 +189,7 @@ run_gpxe: movw %ax, %ss movw $0x7c00, %sp + /* Install gPXE */ call install /* Set up real-mode stack */ @@ -204,7 +205,10 @@ run_gpxe: pushl $main pushw %cs call prot_call - popl %eax /* discard */ + popl %ecx /* discard */ + + /* Uninstall gPXE */ + call uninstall /* Boot next device */ int $0x18 diff --git a/gpxe/src/arch/i386/prefix/nbiprefix.S b/gpxe/src/arch/i386/prefix/nbiprefix.S index d4904b73..4fb4acb1 100644 --- a/gpxe/src/arch/i386/prefix/nbiprefix.S +++ b/gpxe/src/arch/i386/prefix/nbiprefix.S @@ -1,9 +1,7 @@ .text .arch i386 - .section ".prefix", "ax", @progbits - .section ".prefix.data", "aw", @progbits .code16 - .section ".prefix" + .section ".prefix", "ax", @progbits .org 0 nbi_header: @@ -32,11 +30,11 @@ segment_header: .byte 0 .byte 0x04 /* Last segment */ .long 0x00007e00 -imglen: .long _load_size - 512 -memlen: .long _load_size - 512 +imglen: .long _filesz - 512 +memlen: .long _filesz - 512 .size segment_header, . - segment_header - .section ".zinfo.fixup", "a" /* Compressor fixup information */ + .section ".zinfo.fixup", "a", @progbits /* Compressor fixups */ .ascii "SUBL" .long imglen .long 1 @@ -52,7 +50,7 @@ memlen: .long _load_size - 512 ***************************************************************************** */ entry: - /* Install low and high memory regions */ + /* Install gPXE */ call install /* Jump to .text16 segment */ @@ -64,7 +62,10 @@ entry: pushl $main pushw %cs call prot_call - popl %eax /* discard */ + popl %ecx /* discard */ + + /* Uninstall gPXE */ + call uninstall /* Reboot system */ int $0x19 diff --git a/gpxe/src/arch/i386/prefix/pxeprefix.S b/gpxe/src/arch/i386/prefix/pxeprefix.S index 302f8e5d..ee0f4d94 100644 --- a/gpxe/src/arch/i386/prefix/pxeprefix.S +++ b/gpxe/src/arch/i386/prefix/pxeprefix.S @@ -2,57 +2,60 @@ #define PXENV_UNDI_GET_NIC_TYPE 0x0012 #define PXENV_STOP_UNDI 0x0015 #define PXENV_UNLOAD_STACK 0x0070 - + .text .arch i386 .org 0 - .section ".prefix", "ax", @progbits - .section ".prefix.data", "aw", @progbits .code16 #include <undi.h> +#define STACK_MAGIC ( 'L' + ( 'R' << 8 ) + ( 'E' << 16 ) + ( 'T' << 24 ) ) + /***************************************************************************** * Entry point: set operating context, print welcome message ***************************************************************************** */ - .section ".prefix" - /* Set up our non-stack segment registers */ + .section ".prefix", "ax", @progbits jmp $0x7c0, $1f -1: pushfl - /* %ax here is the default return type... */ - movw $5, %ax /* Keep PXE+UNDI */ +1: + /* Preserve registers for possible return to PXE */ + pushfl pushal - pushw %ds - pushw %es - pushw %fs pushw %gs + pushw %fs + pushw %es + pushw %ds + + /* Store magic word on PXE stack and remember PXE %ss:esp */ + pushl $STACK_MAGIC + movw %ss, %cs:pxe_ss + movl %esp, %cs:pxe_esp + movw %sp, %bp + movl (10*4+4*2+4)(%bp),%ebp /* !PXE address */ + + /* Set up %ds */ movw %cs, %ax movw %ax, %ds - - movw $0x40, %ax /* BIOS data segment access */ - movw %ax, %fs - - pushw %fs:0x13 /* Record PXENV+ and !PXE nominal addresses */ - movw %es, pxenv_segment + movw %es, pxenv_segment /* PXENV+ address */ movw %bx, pxenv_offset - movw %sp, %bp - movw %ss, return_stack_segment - movl %esp, return_stack_offset - movl 50(%bp), %eax - movl %eax, ppxe_segoff /* !PXE address */ + movl %ebp, ppxe_segoff /* !PXE address */ + /* Set up %es and %fs */ + movw %ax, %es + movw $0x40, %ax /* BIOS data segment access */ + movw %ax, %fs /* Set up stack just below 0x7c00 */ xorw %ax, %ax movw %ax, %ss - movw $0x7c00, %sp + movl $0x7c00, %esp /* Clear direction flag, for the sake of sanity */ cld /* Print welcome message */ movw $10f, %si xorw %di, %di call print_message - .section ".prefix.data" + .section ".prefix.data", "aw", @progbits 10: .asciz "PXE->EB:" .previous @@ -80,10 +83,10 @@ detect_pxenv: movw $10f, %si call print_message call print_segoff - movb $',', %al + movb $( ',' ), %al call print_character jmp 99f - .section ".prefix.data" + .section ".prefix.data", "aw", @progbits 10: .asciz " PXENV+ at " .previous @@ -118,10 +121,10 @@ detect_ppxe: movw $10f, %si call print_message call print_segoff - movb $',', %al + movb $( ',' ), %al call print_character jmp 99f - .section ".prefix.data" + .section ".prefix.data", "aw", @progbits 10: .asciz " !PXE at " .previous @@ -144,7 +147,7 @@ check_have_stack: movw $10f, %si call print_message jmp finished - .section ".prefix.data" + .section ".prefix.data", "aw", @progbits 10: .asciz " No PXE stack found!\n" .previous 99: @@ -182,7 +185,7 @@ print_structure_information: call print_message les entry_segoff, %bx call print_segoff - .section ".prefix.data" + .section ".prefix.data", "aw", @progbits 10: .asciz " entry point at " .previous /* Print UNDI code segment */ @@ -190,7 +193,7 @@ print_structure_information: call print_message les undi_code_segoff, %bx call print_segoff - .section ".prefix.data" + .section ".prefix.data", "aw", @progbits 10: .asciz "\n UNDI code segment " .previous /* Print UNDI data segment */ @@ -198,7 +201,7 @@ print_structure_information: call print_message les undi_data_segoff, %bx call print_segoff - .section ".prefix.data" + .section ".prefix.data", "aw", @progbits 10: .asciz ", data segment " .previous /* Print UNDI memory usage */ @@ -206,13 +209,13 @@ print_structure_information: call print_message movw undi_fbms_start, %ax call print_word - movb $'-', %al + movb $( '-' ), %al call print_character movw undi_fbms_end, %ax call print_word movw $20f, %si call print_message - .section ".prefix.data" + .section ".prefix.data", "aw", @progbits 10: .asciz " (" 20: .asciz "kB)\n" .previous @@ -246,7 +249,7 @@ pci_physical_device: movb $0x0a, %al call print_character jmp 99f - .section ".prefix.data" + .section ".prefix.data", "aw", @progbits 10: .asciz " UNDI device is PCI " .previous @@ -254,7 +257,7 @@ no_physical_device: /* No device found, or device type not understood */ movw $10f, %si call print_message - .section ".prefix.data" + .section ".prefix.data", "aw", @progbits 10: .asciz " Unable to determine UNDI physical device\n" .previous @@ -264,7 +267,7 @@ no_physical_device: * Leave NIC in a safe state ***************************************************************************** */ -#ifndef PXELOADER_KEEP_UNDI +#ifndef PXELOADER_KEEP_PXE shutdown_nic: /* Issue PXENV_UNDI_SHUTDOWN */ movw $PXENV_UNDI_SHUTDOWN, %bx @@ -272,11 +275,6 @@ shutdown_nic: jnc 1f call print_pxe_error 1: - -/***************************************************************************** - * Unload PXE base code - ***************************************************************************** - */ unload_base_code: /* Issue PXENV_UNLOAD_STACK */ movw $PXENV_UNLOAD_STACK, %bx @@ -289,12 +287,14 @@ unload_base_code: movw %fs:(0x13), %bx call free_basemem 99: + andw $~( UNDI_FL_INITIALIZED | UNDI_FL_KEEP_ALL ), flags +#endif /* PXELOADER_KEEP_PXE */ /***************************************************************************** * Unload UNDI driver ***************************************************************************** */ - +#ifndef PXELOADER_KEEP_UNDI unload_undi: /* Issue PXENV_STOP_UNDI */ movw $PXENV_STOP_UNDI, %bx @@ -309,6 +309,7 @@ unload_undi: /* Clear UNDI_FL_STARTED */ andw $~UNDI_FL_STARTED, flags 99: +#endif /* PXELOADER_KEEP_UNDI */ /***************************************************************************** * Print remaining free base memory @@ -321,19 +322,18 @@ print_free_basemem: call print_word movw $20f, %si call print_message - .section ".prefix.data" + .section ".prefix.data", "aw", @progbits 10: .asciz " " 20: .asciz "kB free base memory after PXE unload\n" .previous -#endif /* PXELOADER_KEEP_UNDI */ /***************************************************************************** * Exit point ***************************************************************************** */ finished: - jmp run_etherboot - + jmp run_gpxe + /***************************************************************************** * Subroutine: print segment:offset address * @@ -350,7 +350,7 @@ print_segoff: /* Print "<segment>:offset" */ movw %es, %ax call print_hex_word - movb $':', %al + movb $( ':' ), %al call print_character movw %bx, %ax call print_hex_word @@ -517,7 +517,7 @@ print_pxe_error: call print_message popw %si ret - .section ".prefix.data" + .section ".prefix.data", "aw", @progbits 10: .asciz " UNDI API call " 20: .asciz " failed: status code " 30: .asciz "\n" @@ -527,6 +527,10 @@ print_pxe_error: * PXE data structures ***************************************************************************** */ + .section ".prefix.data" + +pxe_ss: .word 0 +pxe_esp: .long 0 pxe_parameter_structure: .fill 20 @@ -554,12 +558,6 @@ entry_segoff: entry_offset: .word 0 entry_segment: .word 0 -return_stack_segoff: -return_stack_offset: .long 0 -return_stack_segment: .word 0 - -return_type: .word 0 /* Default: unload PXE and boot next */ - undi_fbms_start: .word 0 undi_fbms_end: .word 0 @@ -569,16 +567,18 @@ isapnp_read_port: .word UNDI_NO_ISAPNP_READ_PORT pci_vendor: .word 0 pci_device: .word 0 -flags: .word UNDI_FL_STARTED +flags: + .word ( UNDI_FL_INITIALIZED | UNDI_FL_STARTED | UNDI_FL_KEEP_ALL ) .equ undi_device_size, ( . - undi_device ) /***************************************************************************** - * Run Etherboot main code + * Run gPXE main code ***************************************************************************** - */ -run_etherboot: - /* Install Etherboot */ + */ + .section ".prefix" +run_gpxe: + /* Install gPXE */ call install /* Set up real-mode stack */ @@ -594,6 +594,10 @@ run_etherboot: rep movsb #endif + /* Retrieve PXE %ss:esp */ + movw pxe_ss, %di + movl pxe_esp, %ebp + /* Jump to .text16 segment with %ds pointing to .data16 */ movw %bx, %ds pushw %ax @@ -605,29 +609,30 @@ run_etherboot: pushl $main pushw %cs call prot_call - popl %eax /* discard */ + popl %ecx /* discard */ -#ifdef PXELOADER_KEEP_UNDI - /* Boot next device */ - movw $0x40, %ax - movw %ax, %fs - movw $preloaded_undi,%bx - - cli - movw %ss:return_type-undi_device(%bx),%ax - lssl %ss:return_stack_segoff-undi_device(%bx), %esp - movw %sp,%bp - movw %ax,38(%bp) /* Overwrite return AX value */ - popw %fs:0x13 /* 0 */ - popw %gs /* 2 */ - popw %fs /* 4 */ - popw %es /* 6 */ - popw %ds /* 8 */ - popal /* 10, 14, 18, 22, 26, 30, 34, 38 */ - popfl /* 42 */ - lret /* 46 */ -#else - int $0x18 -#endif + /* Uninstall gPXE */ + call uninstall + + /* Restore PXE stack */ + movw %di, %ss + movl %ebp, %esp + + /* Check PXE stack magic */ + popl %eax + cmpl $STACK_MAGIC, %eax + jne 1f + /* PXE stack OK: return to caller */ + popw %ds + popw %es + popw %fs + popw %gs + popal + popfl + xorw %ax, %ax /* Return success */ + lret + +1: /* PXE stack corrupt or removed: use INT 18 */ + int $0x18 .previous diff --git a/gpxe/src/arch/i386/prefix/romprefix.S b/gpxe/src/arch/i386/prefix/romprefix.S index 92a931cd..7d532375 100644 --- a/gpxe/src/arch/i386/prefix/romprefix.S +++ b/gpxe/src/arch/i386/prefix/romprefix.S @@ -14,6 +14,7 @@ #define STACK_MAGIC ( 'L' + ( 'R' << 8 ) + ( 'E' << 16 ) + ( 'T' << 24 ) ) #define PNP_GET_BBS_VERSION 0x60 #define PMM_ALLOCATE 0x0000 +#define PMM_DEALLOCATE 0x0002 /* ROM banner timeout. Based on the configurable BANNER_TIMEOUT in * config.h, but converted to a number of (18Hz) timer ticks, and @@ -30,7 +31,7 @@ .org 0x00 romheader: .word 0xAA55 /* BIOS extension signature */ -romheader_size: .byte _load_size_sect /* Size in 512-byte blocks */ +romheader_size: .byte _filesz_sect /* Size in 512-byte blocks */ jmp init /* Initialisation vector */ checksum: .byte 0 @@ -42,7 +43,7 @@ checksum: .word pnpheader .size romheader, . - romheader - .section ".zinfo.fixup", "a" /* Compressor fixup information */ + .section ".zinfo.fixup", "a", @progbits /* Compressor fixups */ .ascii "SUBB" .long romheader_size .long 512 @@ -58,18 +59,18 @@ pciheader: .byte 0x03 /* PCI data structure revision */ .byte 0x02, 0x00, 0x00 /* Class code */ pciheader_image_length: - .word _load_size_sect /* Image length */ + .word _filesz_sect /* Image length */ .word 0x0001 /* Revision level */ .byte 0x00 /* Code type */ .byte 0x80 /* Last image indicator */ pciheader_runtime_length: - .word _load_size_sect /* Maximum run-time image length */ + .word _filesz_sect /* Maximum run-time image length */ .word 0x0000 /* Configuration utility code header */ .word 0x0000 /* DMTF CLP entry point */ .equ pciheader_len, . - pciheader .size pciheader, . - pciheader - .section ".zinfo.fixup", "a" /* Compressor fixup information */ + .section ".zinfo.fixup", "a", @progbits /* Compressor fixups */ .ascii "SUBW" .long pciheader_image_length .long 512 @@ -109,12 +110,12 @@ mfgstr: /* Product string * - * Defaults to "gPXE". If the ROM image is writable at initialisation - * time, it will be filled in to include the PCI bus:dev.fn number of - * the card as well. + * Defaults to PRODUCT_SHORT_NAME. If the ROM image is writable at + * initialisation time, it will be filled in to include the PCI + * bus:dev.fn number of the card as well. */ prodstr: - .ascii "gPXE" + .ascii PRODUCT_SHORT_NAME prodstr_separator: .byte 0 .ascii "(PCI " @@ -130,9 +131,9 @@ undiheader: .byte 0 /* Structure revision */ .byte 0,1,2 /* PXE version: 2.1.0 */ .word undiloader /* Offset to loader routine */ - .word _data16_size /* Stack segment size */ - .word _data16_size /* Data segment size */ - .word _text16_size /* Code segment size */ + .word _data16_memsz /* Stack segment size */ + .word _data16_memsz /* Data segment size */ + .word _text16_memsz /* Code segment size */ .ascii "PCIR" /* Bus type */ .equ undiheader_len, . - undiheader .size undiheader, . - undiheader @@ -174,10 +175,10 @@ init: /* Fill in product name string, if possible */ movw $prodstr_pci_id, %di call print_pci_busdevfn - movb $' ', prodstr_separator + movb $( ' ' ), prodstr_separator /* Print segment address */ - movb $' ', %al + movb $( ' ' ), %al xorw %di, %di call print_character movw %cs, %ax @@ -190,26 +191,48 @@ init: stc movw $0xb101, %ax int $0x1a - jc 1f + jc no_pci3 cmpl $PCI_SIGNATURE, %edx - jne 1f + jne no_pci3 testb %ah, %ah - jnz 1f + jnz no_pci3 movw $init_message_pci, %si xorw %di, %di call print_message movb %bh, %al call print_hex_nibble - movb $'.', %al + movb $( '.' ), %al call print_character movb %bl, %al call print_hex_byte cmpb $3, %bh - jae 2f -1: /* PCI <3.0: set %gs (runtime segment) = %cs (init-time segment) */ + jb no_pci3 + /* PCI >=3.0: leave %gs as-is if sane */ + movw %gs, %ax + cmpw $0xa000, %ax /* Insane if %gs < 0xa000 */ + jb pci3_insane + movw %cs, %bx /* Sane if %cs == %gs */ + cmpw %bx, %ax + je 1f + movzbw romheader_size, %cx /* Sane if %cs+len <= %gs */ + shlw $5, %cx + addw %cx, %bx + cmpw %bx, %ax + jae 1f + movw %cs, %bx /* Sane if %gs+len <= %cs */ + addw %cx, %ax + cmpw %bx, %ax + jbe 1f +pci3_insane: /* PCI 3.0 with insane %gs value: print error and ignore %gs */ + movb $( '!' ), %al + call print_character + movw %gs, %ax + call print_hex_word +no_pci3: + /* PCI <3.0: set %gs (runtime segment) = %cs (init-time segment) */ pushw %cs popw %gs -2: popl %edi +1: popl %edi popl %edx popl %ebx @@ -268,21 +291,52 @@ pmm_scan: movw $init_message_pmm, %si xorw %di, %di call print_message - /* Try to allocate 2MB block via PMM */ + /* We have PMM and so a 1kB stack: preserve upper register halves */ + pushal + /* Calculate required allocation size in %esi */ + movzbl romheader_size, %eax + shll $9, %eax + addl $_textdata_memsz, %eax + orw $0xffff, %ax /* Ensure allocation size is at least 64kB */ + bsrl %eax, %ecx + subw $15, %cx /* Round up and convert to 64kB count */ + movw $1, %si + shlw %cl, %si +pmm_loop: + /* Try to allocate block via PMM */ pushw $0x0006 /* Aligned, extended memory */ pushl $0xffffffff /* No handle */ - pushl $( 0x00200000 / 16 ) /* 2MB in paragraphs */ + movzwl %si, %eax + shll $12, %eax + pushl %eax /* Allocation size in paragraphs */ pushw $PMM_ALLOCATE lcall *%es:7 addw $12, %sp + /* Abort if allocation fails */ + testw %dx, %dx /* %ax==0 even on success, since align>=64kB */ + jz pmm_fail + /* If block has A20==1, free block and try again with twice + * the allocation size (and hence alignment). + */ + testw $0x0010, %dx + jz got_pmm + pushw %dx + pushw $0 + pushw $PMM_DEALLOCATE + lcall *%es:7 + addw $6, %sp + addw %si, %si + jmp pmm_loop +got_pmm: /* PMM allocation succeeded */ + movw %dx, ( image_source + 2 ) movw %dx, %ax xorw %di, %di call print_hex_word - movw %dx, ( image_source + 2 ) - testw %dx, %dx /* %ax==0 even on success, since align=2MB */ - jz no_pmm - /* PMM allocation succeeded: copy ROM to PMM block */ - pushal /* PMM presence implies 1kB stack */ + movb $( '@' ), %al + call print_character + movw %si, %ax + call print_hex_byte + /* Copy ROM to PMM block */ xorw %ax, %ax movw %ax, %es movl image_source, %edi @@ -291,24 +345,28 @@ pmm_scan: shll $9, %ecx addr32 rep movsb /* PMM presence implies flat real mode */ movl %edi, decompress_to - /* Shrink ROM and update checksum */ + /* Shrink ROM */ + movb $_prefix_memsz_sect, romheader_size +pmm_fail: + /* Restore upper register halves */ + popal +no_pmm: + + /* Update checksum */ xorw %bx, %bx xorw %si, %si - movw $_prefix_size_sect, %cx - movb %cl, romheader_size + movzbw romheader_size, %cx shlw $9, %cx 1: lodsb addb %al, %bl loop 1b subb %bl, checksum - popal -no_pmm: /* Copy self to option ROM space. Required for PCI3.0, which * loads us to a temporary location in low memory. Will be a * no-op for lower PCI versions. */ - movb $' ', %al + movb $( ' ' ), %al xorw %di, %di call print_character movw %gs, %ax @@ -324,23 +382,28 @@ no_pmm: movw $init_message_prompt, %si xorw %di, %di call print_message + movw $prodstr, %si + call print_message + movw $init_message_dots, %si + call print_message /* Wait for Ctrl-B */ movw $0xff02, %bx call wait_for_key /* Clear prompt */ pushf - movw $clear_message, %si xorw %di, %di + call print_kill_line + movw $init_message_done, %si call print_message popf - jnz 1f + jnz 2f /* Ctrl-B was pressed: invoke gPXE. The keypress will be * picked up by the initial shell prompt, and we will drop * into a shell. */ pushw %cs call exec -1: +2: /* Restore registers */ popw %gs popw %fs @@ -353,7 +416,26 @@ no_pmm: lret .size init, . - init +/* + * Note to hardware vendors: + * + * If you wish to brand this boot ROM, please do so by defining the + * strings PRODUCT_NAME and PRODUCT_SHORT_NAME in config/general.h. + * + * While nothing in the GPL prevents you from removing all references + * to gPXE or http://etherboot.org, we prefer you not to do so. + * + * If you have an OEM-mandated branding requirement that cannot be + * satisfied simply by defining PRODUCT_NAME and PRODUCT_SHORT_NAME, + * please contact us. + * + * [ Including an ASCII NUL in PRODUCT_NAME is considered to be + * bypassing the spirit of this request! ] + */ init_message: + .ascii "\n" + .ascii PRODUCT_NAME + .ascii "\n" .asciz "gPXE (http://etherboot.org) - " .size init_message, . - init_message init_message_pci: @@ -372,11 +454,14 @@ init_message_int19: .asciz " INT19" .size init_message_int19, . - init_message_int19 init_message_prompt: - .asciz "\nPress Ctrl-B to configure gPXE..." + .asciz "\nPress Ctrl-B to configure " .size init_message_prompt, . - init_message_prompt -clear_message: - .asciz "\r \n\n" - .size clear_message, . - clear_message +init_message_dots: + .asciz "..." + .size init_message_dots, . - init_message_dots +init_message_done: + .asciz "\n\n" + .size init_message_done, . - init_message_done /* ROM image location * @@ -429,14 +514,15 @@ int19_entry: call print_message movw $int19_message_dots, %si call print_message - movw $0xdf42, %bx + movw $0xdf4e, %bx call wait_for_key pushf - movw $clear_message, %si xorw %di, %di + call print_kill_line + movw $int19_message_done, %si call print_message popf - jnz 1f + jz 1f /* Leave keypress in buffer and start gPXE. The keypress will * cause the usual initial Ctrl-B prompt to be skipped. */ @@ -455,11 +541,14 @@ orig_int19: .size orig_int19, . - orig_int19 int19_message_prompt: - .asciz "Press B to boot from " + .asciz "Press N to skip booting from " .size int19_message_prompt, . - int19_message_prompt int19_message_dots: .asciz "..." .size int19_message_dots, . - int19_message_dots +int19_message_done: + .asciz "\n\n" + .size int19_message_done, . - int19_message_done /* Execute as a boot device * @@ -504,8 +593,11 @@ exec: /* Set %ds = %cs */ pushl $main pushw %cs call prot_call - /* No need to clean up stack; we are about to reload %ss:sp */ - + popl %ecx /* discard */ + + /* Uninstall gPXE */ + call uninstall + /* Restore BIOS stack */ movw %dx, %ss movw %bp, %sp diff --git a/gpxe/src/arch/i386/scripts/i386.lds b/gpxe/src/arch/i386/scripts/i386.lds index 729ad30a..8a0c6733 100644 --- a/gpxe/src/arch/i386/scripts/i386.lds +++ b/gpxe/src/arch/i386/scripts/i386.lds @@ -5,15 +5,9 @@ * */ -OUTPUT_FORMAT ( "elf32-i386", "elf32-i386", "elf32-i386" ) -OUTPUT_ARCH ( i386 ) -ENTRY ( _entry ) - SECTIONS { - /* All sections in the resulting file have consecutive load - * addresses, but may have individual link addresses depending on - * the memory model being used. + /* Each section starts at a virtual address of zero. * * We guarantee alignment of virtual addresses to any alignment * specified by the constituent object files (e.g. via @@ -31,254 +25,185 @@ SECTIONS { */ /* - * Weak symbols that need zero values if not otherwise defined - */ - - . = 0; - .weak : AT ( 0 ) { - *(.weak) - } - _assert = ASSERT ( ( . == 0 ), ".weak is non-zero length" ); - - /* * The prefix + * */ - _prefix_link_addr = 0; - . = _prefix_link_addr; - _prefix = .; - - .prefix : AT ( _prefix_load_offset + __prefix ) { - __prefix = .; - _entry = .; + .prefix 0x0 : AT ( _prefix_lma ) { + _prefix = .; *(.prefix) *(.prefix.*) - _eprefix_progbits = .; + _mprefix = .; + } .bss.prefix (NOLOAD) : AT ( _end_lma ) { + _eprefix = .; } - - _eprefix = .; + _prefix_filesz = ABSOLUTE ( _mprefix - _prefix ); + _prefix_memsz = ABSOLUTE ( _eprefix - _prefix ); /* - * The 16-bit sections, if present + * The 16-bit (real-mode) code section + * */ - _text16_link_addr = 0; - . = _text16_link_addr; - _text16 = .; - - /* We need to allow code at the NULL address in .text16 */ - - .text16 : AT ( _text16_load_offset + __text16 ) { - __text16 = .; + .text16 0x0 : AT ( _text16_lma ) { + _text16 = .; *(.text16.null) - . += 1; /* Prevent NULL being valid */ + . += 1; /* Prevent NULL being valid */ *(.text16) *(.text16.*) - _etext16_progbits = .; - } = 0x9090 - - _etext16 = .; - - _data16_link_addr = 0; - . = _data16_link_addr; - _data16 = .; + _mtext16 = .; + } .bss.text16 (NOLOAD) : AT ( _end_lma ) { + _etext16 = .; + } + _text16_filesz = ABSOLUTE ( _mtext16 - _text16 ); + _text16_memsz = ABSOLUTE ( _etext16 - _text16 ); - . += 1; /* Prevent NULL being valid */ + /* + * The 16-bit (real-mode) data section + * + */ - .rodata16 : AT ( _data16_load_offset + __rodata16 ) { - __rodata16 = .; + .data16 0x0 : AT ( _data16_lma ) { + _data16 = .; + . += 1; /* Prevent NULL being valid */ *(.rodata16) *(.rodata16.*) - } - .data16 : AT ( _data16_load_offset + __data16 ) { - __data16 = .; *(.data16) *(.data16.*) - _edata16_progbits = .; - } - .bss16 : AT ( _data16_load_offset + __bss16 ) { - __bss16 = .; - _bss16 = .; + _mdata16 = .; + } .bss.data16 (NOLOAD) : AT ( _end_lma ) { *(.bss16) *(.bss16.*) - _ebss16 = .; - } - .stack16 : AT ( _data16_load_offset + __stack16 ) { - __stack16 = .; *(.stack16) *(.stack16.*) + _edata16 = .; } - - _edata16 = .; + _data16_filesz = ABSOLUTE ( _mdata16 - _data16 ); + _data16_memsz = ABSOLUTE ( _edata16 - _data16 ); /* * The 32-bit sections + * */ - _textdata_link_addr = 0; - . = _textdata_link_addr; - _textdata = .; - - _text = .; - - . += 1; /* Prevent NULL being valid */ - - .text : AT ( _textdata_load_offset + __text ) { - __text = .; + .textdata 0x0 : AT ( _textdata_lma ) { + _textdata = .; *(.text.null_trap) + . += 1; /* Prevent NULL being valid */ *(.text) *(.text.*) - } = 0x9090 - - _etext = .; - - _data = .; - - .rodata : AT ( _textdata_load_offset + __rodata ) { - __rodata = .; *(.rodata) *(.rodata.*) - } - .data : AT ( _textdata_load_offset + __data ) { - __data = .; *(.data) *(.data.*) *(SORT(.tbl.*)) /* Various tables. See include/tables.h */ - _etextdata_progbits = .; - } - .bss : AT ( _textdata_load_offset + __bss ) { - __bss = .; - _bss = .; + _mtextdata = .; + } .bss.textdata (NOLOAD) : AT ( _end_lma ) { *(.bss) *(.bss.*) *(COMMON) - _ebss = .; - } - .stack : AT ( _textdata_load_offset + __stack ) { - __stack = .; *(.stack) *(.stack.*) + _etextdata = .; } - - _edata = .; - - _etextdata = .; - - _end = .; + _textdata_filesz = ABSOLUTE ( _mtextdata - _textdata ); + _textdata_memsz = ABSOLUTE ( _etextdata - _textdata ); /* * Compressor information block + * */ - _zinfo_link_addr = 0; - . = _zinfo_link_addr; - _zinfo = .; - - .zinfo : AT ( _zinfo_load_offset + __zinfo ) { - __zinfo = .; - _entry = .; + .zinfo 0x0 : AT ( _zinfo_lma ) { + _zinfo = .; *(.zinfo) *(.zinfo.*) - _ezinfo_progbits = .; + _mzinfo = .; + } .bss.zinfo (NOLOAD) : AT ( _end_lma ) { + _ezinfo = .; } - - _ezinfo = .; + _zinfo_filesz = ABSOLUTE ( _mzinfo - _zinfo ); + _zinfo_memsz = ABSOLUTE ( _ezinfo - _zinfo ); + + /* + * Weak symbols that need zero values if not otherwise defined + * + */ + + .weak 0x0 : AT ( _end_lma ) { + _weak = .; + *(.weak) + _eweak = .; + } + _assert = ASSERT ( ( _weak == _eweak ), ".weak is non-zero length" ); /* * Dispose of the comment and note sections to make the link map * easier to read + * */ /DISCARD/ : { *(.comment) + *(.comment.*) *(.note) + *(.note.*) + *(.eh_frame) + *(.eh_frame.*) + *(.rel) + *(.rel.*) } /* - * Load address calculations. The slightly obscure nature of the - * calculations is because ALIGN(x) can only operate on the - * location counter. + * Load address calculations. In older versions of ld, ALIGN() + * can operate only on the location counter, so we use that. + * */ - _max_align = 16; - _load_addr = 0; - - . = _load_addr; - - . -= _prefix_link_addr; - _prefix_load_offset = ALIGN ( _max_align ); - _prefix_load_addr = _prefix_link_addr + _prefix_load_offset; - _prefix_size = _eprefix - _prefix; - _prefix_progbits_size = _eprefix_progbits - _prefix; - . = _prefix_load_addr + _prefix_progbits_size; - - . -= _text16_link_addr; - _text16_load_offset = ALIGN ( _max_align ); - _text16_load_addr = _text16_link_addr + _text16_load_offset; - _text16_size = _etext16 - _text16; - _text16_progbits_size = _etext16_progbits - _text16; - . = _text16_load_addr + _text16_progbits_size; + PROVIDE ( _max_align = 16 ); + . = 0; - . -= _data16_link_addr; - _data16_load_offset = ALIGN ( _max_align ); - _data16_load_addr = _data16_link_addr + _data16_load_offset; - _data16_size = _edata16 - _data16; - _data16_progbits_size = _edata16_progbits - _data16; - . = _data16_load_addr + _data16_progbits_size; + . = ALIGN ( _max_align ); + _prefix_lma = .; + . += _prefix_filesz; - . -= _textdata_link_addr; - _textdata_load_offset = ALIGN ( _max_align ); - _textdata_load_addr = _textdata_link_addr + _textdata_load_offset; - _textdata_size = _etextdata - _textdata; - _textdata_progbits_size = _etextdata_progbits - _textdata; - . = _textdata_load_addr + _textdata_progbits_size; + . = ALIGN ( _max_align ); + _payload_lma = .; + _text16_lma = .; + . += _text16_filesz; - _load_size = . - _load_addr; + . = ALIGN ( _max_align ); + _data16_lma = .; + . += _data16_filesz; - . -= _zinfo_link_addr; - _zinfo_load_offset = ALIGN ( _max_align ); - _zinfo_load_addr = _zinfo_link_addr + _zinfo_load_offset; - _zinfo_size = _ezinfo - _zinfo; - _zinfo_progbits_size = _ezinfo_progbits - _zinfo; - . = _zinfo_load_addr + _zinfo_progbits_size; + . = ALIGN ( _max_align ); + _textdata_lma = .; + . += _textdata_filesz; - _payload_offset = _text16_load_offset; + _filesz = .; /* Do not include zinfo block in file size */ - /* - * Alignment checks. ALIGN() can only operate on the location - * counter, so we set the location counter to each value we want - * to check. - */ - - . = _prefix_load_addr - _prefix_link_addr; - _assert = ASSERT ( ( . == ALIGN ( _max_align ) ), - "_prefix is badly aligned" ); - - . = _text16_load_addr - _text16_link_addr; - _assert = ASSERT ( ( . == ALIGN ( _max_align ) ), - "_text16 is badly aligned" ); + . = ALIGN ( _max_align ); + _zinfo_lma = .; + . += _zinfo_filesz; - . = _data16_load_addr - _data16_link_addr; - _assert = ASSERT ( ( . == ALIGN ( _max_align ) ), - "_data16 is badly aligned" ); - - . = _textdata_load_addr - _textdata_link_addr; - _assert = ASSERT ( ( . == ALIGN ( _max_align ) ), - "_text is badly aligned" ); + . = ALIGN ( _max_align ); + _end_lma = .; /* * Values calculated to save code from doing it + * */ - _prefix_size_pgh = ( ( _prefix_size + 15 ) / 16 ); - _prefix_size_sect = ( ( _prefix_size + 511 ) / 512 ); - _text16_size_pgh = ( ( _text16_size + 15 ) / 16 ); - _data16_size_pgh = ( ( _data16_size + 15 ) / 16 ); + _prefix_memsz_pgh = ( ( _prefix_memsz + 15 ) / 16 ); + _prefix_memsz_sect = ( ( _prefix_memsz + 511 ) / 512 ); + _text16_memsz_pgh = ( ( _text16_memsz + 15 ) / 16 ); + _data16_memsz_pgh = ( ( _data16_memsz + 15 ) / 16 ); /* - * Load sizes in paragraphs and sectors. Note that wherever the - * _load_size variables are used, there must be a corresponding + * File size in paragraphs and sectors. Note that wherever the + * _filesz variables are used, there must be a corresponding * .zinfo.fixup section. + * */ - _load_size_pgh = ( ( _load_size + 15 ) / 16 ); - _load_size_sect = ( ( _load_size + 511 ) / 512 ); + _filesz_pgh = ( ( _filesz + 15 ) / 16 ); + _filesz_sect = ( ( _filesz + 511 ) / 512 ); } diff --git a/gpxe/src/arch/i386/transitions/librm.S b/gpxe/src/arch/i386/transitions/librm.S index ff4b1d97..8cf1f7f5 100644..100755 --- a/gpxe/src/arch/i386/transitions/librm.S +++ b/gpxe/src/arch/i386/transitions/librm.S @@ -19,9 +19,6 @@ #define SIZEOF_I386_ALL_REGS ( SIZEOF_REAL_MODE_REGS + SIZEOF_I386_FLAGS ) .arch i386 - .section ".text16", "ax", @progbits - .section ".text16.data", "aw", @progbits - .section ".data16", "aw", @progbits /**************************************************************************** * Global descriptor table @@ -47,7 +44,7 @@ #else #define RM_LIMIT_16_19__AVL__SIZE__GRANULARITY 0x00 #endif - .section ".data16" + .section ".data16", "aw", @progbits .align 16 gdt: gdtr: /* The first GDT entry is unused, the GDTR can fit here. */ @@ -99,7 +96,7 @@ gdt_end: * %edi : Physical base of protected-mode code (virt_offset) **************************************************************************** */ - .section ".text16" + .section ".text16", "ax", @progbits .code16 .globl init_librm init_librm: @@ -149,7 +146,7 @@ init_librm: popl %eax lret - .section ".text16" + .section ".text16", "ax", @progbits .code16 .weak idt_init set_seg_base: @@ -177,7 +174,7 @@ idt_init: /* Reuse the return opcode here */ * **************************************************************************** */ - .section ".text16" + .section ".text16", "ax", @progbits .code16 real_to_prot: /* Make sure we have our data segment available */ @@ -203,13 +200,13 @@ real_to_prot: /* Switch to protected mode */ cli - data32 lgdt gdtr - data32 lidt idtr + data32 lgdt gdtr + data32 lidt idtr movl %cr0, %eax orb $CR0_PE, %al movl %eax, %cr0 data32 ljmp $VIRTUAL_CS, $1f - .section ".text" + .section ".text", "ax", @progbits .code32 1: /* Set up protected-mode data segments and stack pointer */ @@ -240,7 +237,7 @@ real_to_prot: ret /* Default IDTR with no interrupts */ - .section ".data16" + .section ".data16", "aw", @progbits .weak idtr idtr: rm_idtr: @@ -266,7 +263,7 @@ rm_idtr: * **************************************************************************** */ - .section ".text" + .section ".text", "ax", @progbits .code32 prot_to_real: /* Add return address to data to be moved to RM stack */ @@ -296,7 +293,7 @@ prot_to_real: movw %ax, %gs movw %ax, %ss ljmp $REAL_CS, $1f - .section ".text16" + .section ".text16", "ax", @progbits .code16 1: /* Switch to real mode */ @@ -316,7 +313,7 @@ p2r_jump_target: movl %edx, %esp /* Reset IDTR to the real-mode defaults */ - lidt rm_idtr + data32 lidt rm_idtr /* Return to real-mode address */ data32 ret @@ -328,13 +325,13 @@ p2r_jump_target: * rather than .data16 because code needs to be able to locate * the data segment. */ - .section ".data16" + .section ".data16", "aw", @progbits p2r_jump_vector: .word p2r_jump_target .globl rm_cs rm_cs: .word 0 .globl rm_ds - .section ".text16.data" + .section ".text16.data", "aw", @progbits rm_ds: .word 0 /**************************************************************************** @@ -378,7 +375,7 @@ rm_ds: .word 0 #define PC_OFFSET_FUNCTION ( PC_OFFSET_RETADDR + 4 ) #define PC_OFFSET_END ( PC_OFFSET_FUNCTION + 4 ) - .section ".text16" + .section ".text16", "ax", @progbits .code16 .globl prot_call prot_call: @@ -403,7 +400,7 @@ prot_call: movl $PC_OFFSET_END, %ecx pushl $1f jmp real_to_prot - .section ".text" + .section ".text", "ax", @progbits .code32 1: /* Set up environment expected by C code */ @@ -419,13 +416,13 @@ prot_call: movl $PC_OFFSET_END, %ecx pushl $1f jmp prot_to_real - .section ".text16" + .section ".text16", "ax", @progbits .code16 1: /* Reload GDT and IDT, restore registers and flags and return */ movw %sp, %bp - lgdt (%bp) - lidt 8(%bp) + data32 lgdt (%bp) + data32 lidt 8(%bp) addw $20, %sp /* also skip %cs and %ss */ popw %ds popw %es @@ -475,7 +472,7 @@ prot_call: #define RC_OFFSET_FUNCTION ( RC_OFFSET_RETADDR + 4 ) #define RC_OFFSET_END ( RC_OFFSET_FUNCTION + 4 ) - .section ".text" + .section ".text", "ax", @progbits .code32 .globl real_call real_call: @@ -487,7 +484,7 @@ real_call: movl $( RC_OFFSET_RETADDR + 4 /* function pointer copy */ ), %ecx pushl $1f jmp prot_to_real - .section ".text16" + .section ".text16", "ax", @progbits .code16 1: /* Call real-mode function */ @@ -503,7 +500,7 @@ real_call: movl $RC_OFFSET_RETADDR, %ecx pushl $1f jmp real_to_prot - .section ".text" + .section ".text", "ax", @progbits .code32 1: /* Restore registers and return */ @@ -514,7 +511,7 @@ real_call: /* Function vector, used because "call xx(%sp)" is not a valid * 16-bit expression. */ - .section ".data16" + .section ".data16", "aw", @progbits rc_function: .word 0, 0 /**************************************************************************** @@ -551,7 +548,7 @@ rc_function: .word 0, 0 * to us. **************************************************************************** */ - .section ".data" + .section ".data", "aw", @progbits .globl rm_sp rm_sp: .word 0 .globl rm_ss @@ -567,13 +564,13 @@ pm_esp: .long _estack **************************************************************************** */ /* Internal copies, created by init_librm (which runs in real mode) */ - .section ".data16" + .section ".data16", "aw", @progbits _virt_offset: .long 0 _text16: .long 0 _data16: .long 0 /* Externally-visible copies, created by real_to_prot */ - .section ".data" + .section ".data", "aw", @progbits .globl virt_offset virt_offset: .long 0 .globl text16 diff --git a/gpxe/src/arch/i386/transitions/librm_mgmt.c b/gpxe/src/arch/i386/transitions/librm_mgmt.c index 59b2eabc..50569f8e 100644..100755 --- a/gpxe/src/arch/i386/transitions/librm_mgmt.c +++ b/gpxe/src/arch/i386/transitions/librm_mgmt.c @@ -1,45 +1,56 @@ -/*
- * librm: a library for interfacing to real-mode code
- *
- * Michael Brown <mbrown@fensystems.co.uk>
- *
- */
-
-#include <stdint.h>
-#include <librm.h>
-
-/*
- * This file provides functions for managing librm.
- *
- */
-
-/**
- * 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
- */
-uint16_t copy_user_to_rm_stack ( userptr_t data, size_t size ) {
- userptr_t rm_stack;
- rm_sp -= size;
- rm_stack = real_to_user ( rm_ss, rm_sp );
- memcpy_user ( rm_stack, 0, data, 0, size );
- return rm_sp;
-};
-
-/**
- * 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
- */
-void remove_user_from_rm_stack ( userptr_t data, size_t size ) {
- if ( data ) {
- userptr_t rm_stack = real_to_user ( rm_ss, rm_sp );
- memcpy_user ( rm_stack, 0, data, 0, size );
- }
- rm_sp += size;
-};
+/* + * librm: a library for interfacing to real-mode code + * + * Michael Brown <mbrown@fensystems.co.uk> + * + */ + +#include <stdint.h> +#include <realmode.h> + +/* + * This file provides functions for managing librm. + * + */ + +/** + * 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 + */ +uint16_t copy_user_to_rm_stack ( userptr_t data, size_t size ) { + userptr_t rm_stack; + rm_sp -= size; + rm_stack = real_to_user ( rm_ss, rm_sp ); + memcpy_user ( rm_stack, 0, data, 0, size ); + return rm_sp; +}; + +/** + * 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 + */ +void remove_user_from_rm_stack ( userptr_t data, size_t size ) { + if ( data ) { + userptr_t rm_stack = real_to_user ( rm_ss, rm_sp ); + memcpy_user ( rm_stack, 0, data, 0, size ); + } + rm_sp += size; +}; + +PROVIDE_UACCESS_INLINE ( librm, phys_to_user ); +PROVIDE_UACCESS_INLINE ( librm, user_to_phys ); +PROVIDE_UACCESS_INLINE ( librm, virt_to_user ); +PROVIDE_UACCESS_INLINE ( librm, user_to_virt ); +PROVIDE_UACCESS_INLINE ( librm, userptr_add ); +PROVIDE_UACCESS_INLINE ( librm, memcpy_user ); +PROVIDE_UACCESS_INLINE ( librm, memmove_user ); +PROVIDE_UACCESS_INLINE ( librm, memset_user ); +PROVIDE_UACCESS_INLINE ( librm, strlen_user ); +PROVIDE_UACCESS_INLINE ( librm, memchr_user ); diff --git a/gpxe/src/arch/x86/Makefile b/gpxe/src/arch/x86/Makefile new file mode 100644 index 00000000..a7c4bc0e --- /dev/null +++ b/gpxe/src/arch/x86/Makefile @@ -0,0 +1,9 @@ +# Include common x86 headers +# +CFLAGS += -Iarch/x86/include + +# x86-specific directories containing source files +# +SRCDIRS += arch/x86/core +SRCDIRS += arch/x86/interface/efi +SRCDIRS += arch/x86/prefix diff --git a/gpxe/src/arch/x86/Makefile.efi b/gpxe/src/arch/x86/Makefile.efi new file mode 100644 index 00000000..bef8d59d --- /dev/null +++ b/gpxe/src/arch/x86/Makefile.efi @@ -0,0 +1,28 @@ +# -*- makefile -*- : Force emacs to use Makefile mode + +# The EFI linker script +# +LDSCRIPT = arch/x86/scripts/efi.lds + +# Retain relocation information for elf2efi +# +LDFLAGS += -q -S + +# Media types. +# +NON_AUTO_MEDIA += efi +NON_AUTO_MEDIA += efidrv + +# Rules for building EFI files +# +$(BIN)/%.efi : $(BIN)/%.efi.tmp $(ELF2EFI) + $(QM)$(ECHO) " [FINISH] $@" + $(Q)$(ELF2EFI) --subsystem=10 $< $@ + +$(BIN)/%.efidrv : $(BIN)/%.efidrv.tmp $(ELF2EFI) + $(QM)$(ECHO) " [FINISH] $@" + $(Q)$(ELF2EFI) --subsystem=11 $< $@ + +$(BIN)/%.efirom : $(BIN)/%.efidrv $(EFIROM) + $(QM)$(ECHO) " [FINISH] $@" + $(Q)$(EFIROM) -v $(TGT_PCI_VENDOR) -d $(TGT_PCI_DEVICE) $< $@ diff --git a/gpxe/src/arch/i386/core/pcidirect.c b/gpxe/src/arch/x86/core/pcidirect.c index 2ed8c2ad..db17215e 100644 --- a/gpxe/src/arch/i386/core/pcidirect.c +++ b/gpxe/src/arch/x86/core/pcidirect.c @@ -16,8 +16,8 @@ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ +#include <gpxe/io.h> #include <gpxe/pci.h> -#include <pcidirect.h> /** @file * @@ -36,3 +36,10 @@ void pcidirect_prepare ( struct pci_device *pci, int where ) { ( where & ~3 ) ), PCIDIRECT_CONFIG_ADDRESS ); } +PROVIDE_PCIAPI_INLINE ( direct, pci_max_bus ); +PROVIDE_PCIAPI_INLINE ( direct, pci_read_config_byte ); +PROVIDE_PCIAPI_INLINE ( direct, pci_read_config_word ); +PROVIDE_PCIAPI_INLINE ( direct, pci_read_config_dword ); +PROVIDE_PCIAPI_INLINE ( direct, pci_write_config_byte ); +PROVIDE_PCIAPI_INLINE ( direct, pci_write_config_word ); +PROVIDE_PCIAPI_INLINE ( direct, pci_write_config_dword ); diff --git a/gpxe/src/arch/i386/core/i386_string.c b/gpxe/src/arch/x86/core/x86_string.c index 9917363a..c0224c7a 100644 --- a/gpxe/src/arch/i386/core/i386_string.c +++ b/gpxe/src/arch/x86/core/x86_string.c @@ -32,9 +32,7 @@ * @v len Length * @ret dest Destination address */ -__attribute__ (( regparm ( 3 ) )) void * __memcpy ( void *dest, - const void *src, - size_t len ) { +void * __memcpy ( void *dest, const void *src, size_t len ) { void *edi = dest; const void *esi = src; int discard_ecx; diff --git a/gpxe/src/arch/x86/include/bits/pci_io.h b/gpxe/src/arch/x86/include/bits/pci_io.h new file mode 100644 index 00000000..0fbb439d --- /dev/null +++ b/gpxe/src/arch/x86/include/bits/pci_io.h @@ -0,0 +1,13 @@ +#ifndef _BITS_PCI_IO_H +#define _BITS_PCI_IO_H + +/** @file + * + * i386-specific PCI I/O API implementations + * + */ + +#include <gpxe/pcibios.h> +#include <gpxe/pcidirect.h> + +#endif /* _BITS_PCI_IO_H */ diff --git a/gpxe/src/arch/i386/include/bits/string.h b/gpxe/src/arch/x86/include/bits/string.h index c05a7df8..42ddeddf 100644 --- a/gpxe/src/arch/i386/include/bits/string.h +++ b/gpxe/src/arch/x86/include/bits/string.h @@ -23,9 +23,7 @@ #define __HAVE_ARCH_MEMCPY -extern __attribute__ (( regparm ( 3 ) )) void * __memcpy ( void *dest, - const void *src, - size_t len ); +extern void * __memcpy ( void *dest, const void *src, size_t len ); #if 0 static inline __attribute__ (( always_inline )) void * diff --git a/gpxe/src/arch/x86/include/gpxe/efi/efix86_nap.h b/gpxe/src/arch/x86/include/gpxe/efi/efix86_nap.h new file mode 100644 index 00000000..91424c54 --- /dev/null +++ b/gpxe/src/arch/x86/include/gpxe/efi/efix86_nap.h @@ -0,0 +1,16 @@ +#ifndef _GPXE_EFIX86_NAP_H +#define _GPXE_EFIX86_NAP_H + +/** @file + * + * EFI CPU sleeping + * + */ + +#ifdef NAP_EFIX86 +#define NAP_PREFIX_efix86 +#else +#define NAP_PREFIX_efix86 __efix86_ +#endif + +#endif /* _GPXE_EFIX86_NAP_H */ diff --git a/gpxe/src/arch/i386/include/pcibios.h b/gpxe/src/arch/x86/include/gpxe/pcibios.h index 3d08d135..b86f5abd 100644 --- a/gpxe/src/arch/i386/include/pcibios.h +++ b/gpxe/src/arch/x86/include/gpxe/pcibios.h @@ -1,5 +1,5 @@ -#ifndef _PCIBIOS_H -#define _PCIBIOS_H +#ifndef _GPXE_PCIBIOS_H +#define _GPXE_PCIBIOS_H #include <stdint.h> @@ -9,6 +9,12 @@ * */ +#ifdef PCIAPI_PCBIOS +#define PCIAPI_PREFIX_pcbios +#else +#define PCIAPI_PREFIX_pcbios __pcbios_ +#endif + struct pci_device; #define PCIBIOS_INSTALLATION_CHECK 0xb1010000 @@ -19,7 +25,6 @@ struct pci_device; #define PCIBIOS_WRITE_CONFIG_WORD 0xb10c0000 #define PCIBIOS_WRITE_CONFIG_DWORD 0xb10d0000 -extern int pcibios_max_bus ( void ); extern int pcibios_read ( struct pci_device *pci, uint32_t command, uint32_t *value ); extern int pcibios_write ( struct pci_device *pci, uint32_t command, @@ -33,9 +38,10 @@ extern int pcibios_write ( struct pci_device *pci, uint32_t command, * @v value Value read * @ret rc Return status code */ -static inline __attribute__ (( always_inline )) int -pcibios_read_config_byte ( struct pci_device *pci, unsigned int where, - uint8_t *value ) { +static inline __always_inline int +PCIAPI_INLINE ( pcbios, pci_read_config_byte ) ( struct pci_device *pci, + unsigned int where, + uint8_t *value ) { uint32_t tmp; int rc; @@ -52,9 +58,10 @@ pcibios_read_config_byte ( struct pci_device *pci, unsigned int where, * @v value Value read * @ret rc Return status code */ -static inline __attribute__ (( always_inline )) int -pcibios_read_config_word ( struct pci_device *pci, unsigned int where, - uint16_t *value ) { +static inline __always_inline int +PCIAPI_INLINE ( pcbios, pci_read_config_word ) ( struct pci_device *pci, + unsigned int where, + uint16_t *value ) { uint32_t tmp; int rc; @@ -71,9 +78,10 @@ pcibios_read_config_word ( struct pci_device *pci, unsigned int where, * @v value Value read * @ret rc Return status code */ -static inline __attribute__ (( always_inline )) int -pcibios_read_config_dword ( struct pci_device *pci, unsigned int where, - uint32_t *value ) { +static inline __always_inline int +PCIAPI_INLINE ( pcbios, pci_read_config_dword ) ( struct pci_device *pci, + unsigned int where, + uint32_t *value ) { return pcibios_read ( pci, PCIBIOS_READ_CONFIG_DWORD | where, value ); } @@ -85,9 +93,10 @@ pcibios_read_config_dword ( struct pci_device *pci, unsigned int where, * @v value Value to be written * @ret rc Return status code */ -static inline __attribute__ (( always_inline )) int -pcibios_write_config_byte ( struct pci_device *pci, unsigned int where, - uint8_t value ) { +static inline __always_inline int +PCIAPI_INLINE ( pcbios, pci_write_config_byte ) ( struct pci_device *pci, + unsigned int where, + uint8_t value ) { return pcibios_write ( pci, PCIBIOS_WRITE_CONFIG_BYTE | where, value ); } @@ -99,9 +108,10 @@ pcibios_write_config_byte ( struct pci_device *pci, unsigned int where, * @v value Value to be written * @ret rc Return status code */ -static inline __attribute__ (( always_inline )) int -pcibios_write_config_word ( struct pci_device *pci, unsigned int where, - uint16_t value ) { +static inline __always_inline int +PCIAPI_INLINE ( pcbios, pci_write_config_word ) ( struct pci_device *pci, + unsigned int where, + uint16_t value ) { return pcibios_write ( pci, PCIBIOS_WRITE_CONFIG_WORD | where, value ); } @@ -113,10 +123,11 @@ pcibios_write_config_word ( struct pci_device *pci, unsigned int where, * @v value Value to be written * @ret rc Return status code */ -static inline __attribute__ (( always_inline )) int -pcibios_write_config_dword ( struct pci_device *pci, unsigned int where, - uint32_t value ) { +static inline __always_inline int +PCIAPI_INLINE ( pcbios, pci_write_config_dword ) ( struct pci_device *pci, + unsigned int where, + uint32_t value ) { return pcibios_write ( pci, PCIBIOS_WRITE_CONFIG_DWORD | where, value); } -#endif /* _PCIBIOS_H */ +#endif /* _GPXE_PCIBIOS_H */ diff --git a/gpxe/src/arch/i386/include/pcidirect.h b/gpxe/src/arch/x86/include/gpxe/pcidirect.h index 4e2e9d12..fe433c6f 100644 --- a/gpxe/src/arch/i386/include/pcidirect.h +++ b/gpxe/src/arch/x86/include/gpxe/pcidirect.h @@ -2,7 +2,13 @@ #define _PCIDIRECT_H #include <stdint.h> -#include <io.h> +#include <gpxe/io.h> + +#ifdef PCIAPI_DIRECT +#define PCIAPI_PREFIX_direct +#else +#define PCIAPI_PREFIX_direct __direct_ +#endif /** @file * @@ -22,7 +28,8 @@ extern void pcidirect_prepare ( struct pci_device *pci, int where ); * * @ret max_bus Maximum bus number */ -static inline int pcidirect_max_bus ( void ) { +static inline __always_inline int +PCIAPI_INLINE ( direct, pci_max_bus ) ( void ) { /* No way to work this out via Type 1 accesses */ return 0xff; } @@ -35,9 +42,10 @@ static inline int pcidirect_max_bus ( void ) { * @v value Value read * @ret rc Return status code */ -static inline __attribute__ (( always_inline )) int -pcidirect_read_config_byte ( struct pci_device *pci, unsigned int where, - uint8_t *value ) { +static inline __always_inline int +PCIAPI_INLINE ( direct, pci_read_config_byte ) ( struct pci_device *pci, + unsigned int where, + uint8_t *value ) { pcidirect_prepare ( pci, where ); *value = inb ( PCIDIRECT_CONFIG_DATA + ( where & 3 ) ); return 0; @@ -51,9 +59,10 @@ pcidirect_read_config_byte ( struct pci_device *pci, unsigned int where, * @v value Value read * @ret rc Return status code */ -static inline __attribute__ (( always_inline )) int -pcidirect_read_config_word ( struct pci_device *pci, unsigned int where, - uint16_t *value ) { +static inline __always_inline int +PCIAPI_INLINE ( direct, pci_read_config_word ) ( struct pci_device *pci, + unsigned int where, + uint16_t *value ) { pcidirect_prepare ( pci, where ); *value = inw ( PCIDIRECT_CONFIG_DATA + ( where & 2 ) ); return 0; @@ -67,9 +76,10 @@ pcidirect_read_config_word ( struct pci_device *pci, unsigned int where, * @v value Value read * @ret rc Return status code */ -static inline __attribute__ (( always_inline )) int -pcidirect_read_config_dword ( struct pci_device *pci, unsigned int where, - uint32_t *value ) { +static inline __always_inline int +PCIAPI_INLINE ( direct, pci_read_config_dword ) ( struct pci_device *pci, + unsigned int where, + uint32_t *value ) { pcidirect_prepare ( pci, where ); *value = inl ( PCIDIRECT_CONFIG_DATA ); return 0; @@ -83,9 +93,10 @@ pcidirect_read_config_dword ( struct pci_device *pci, unsigned int where, * @v value Value to be written * @ret rc Return status code */ -static inline __attribute__ (( always_inline )) int -pcidirect_write_config_byte ( struct pci_device *pci, unsigned int where, - uint8_t value ) { +static inline __always_inline int +PCIAPI_INLINE ( direct, pci_write_config_byte ) ( struct pci_device *pci, + unsigned int where, + uint8_t value ) { pcidirect_prepare ( pci, where ); outb ( value, PCIDIRECT_CONFIG_DATA + ( where & 3 ) ); return 0; @@ -99,9 +110,10 @@ pcidirect_write_config_byte ( struct pci_device *pci, unsigned int where, * @v value Value to be written * @ret rc Return status code */ -static inline __attribute__ (( always_inline )) int -pcidirect_write_config_word ( struct pci_device *pci, unsigned int where, - uint16_t value ) { +static inline __always_inline int +PCIAPI_INLINE ( direct, pci_write_config_word ) ( struct pci_device *pci, + unsigned int where, + uint16_t value ) { pcidirect_prepare ( pci, where ); outw ( value, PCIDIRECT_CONFIG_DATA + ( where & 2 ) ); return 0; @@ -115,9 +127,10 @@ pcidirect_write_config_word ( struct pci_device *pci, unsigned int where, * @v value Value to be written * @ret rc Return status code */ -static inline __attribute__ (( always_inline )) int -pcidirect_write_config_dword ( struct pci_device *pci, unsigned int where, - uint32_t value ) { +static inline __always_inline int +PCIAPI_INLINE ( direct, pci_write_config_dword ) ( struct pci_device *pci, + unsigned int where, + uint32_t value ) { pcidirect_prepare ( pci, where ); outl ( value, PCIDIRECT_CONFIG_DATA ); return 0; diff --git a/gpxe/src/arch/x86/interface/efi/efix86_nap.c b/gpxe/src/arch/x86/interface/efi/efix86_nap.c new file mode 100644 index 00000000..45e99a68 --- /dev/null +++ b/gpxe/src/arch/x86/interface/efi/efix86_nap.c @@ -0,0 +1,46 @@ +/* + * 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., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +#include <gpxe/nap.h> +#include <gpxe/efi/efi.h> + +/** @file + * + * gPXE CPU sleeping API for EFI + * + */ + +/** + * Sleep until next interrupt + * + */ +static void efix86_cpu_nap ( void ) { + /* + * I can't find any EFI API that allows us to put the CPU to + * sleep. The CpuSleep() function is defined in CpuLib.h, but + * isn't part of any exposed protocol so we have no way to + * call it. + * + * The EFI shell doesn't seem to bother sleeping the CPU; it + * just sits there idly burning power. + * + */ + __asm__ __volatile__ ( "hlt" ); +} + +PROVIDE_NAP ( efix86, cpu_nap, efix86_cpu_nap ); diff --git a/gpxe/src/arch/x86/prefix/efidrvprefix.c b/gpxe/src/arch/x86/prefix/efidrvprefix.c new file mode 100644 index 00000000..5f631588 --- /dev/null +++ b/gpxe/src/arch/x86/prefix/efidrvprefix.c @@ -0,0 +1,44 @@ +/* + * Copyright (C) 2009 Michael Brown <mbrown@fensystems.co.uk>. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of the + * License, or any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +#include <stdlib.h> +#include <gpxe/init.h> +#include <gpxe/efi/efi.h> + +/** + * EFI entry point + * + * @v image_handle Image handle + * @v systab System table + * @ret efirc EFI return status code + */ +EFI_STATUS EFIAPI _start ( EFI_HANDLE image_handle, + EFI_SYSTEM_TABLE *systab ) { + EFI_STATUS efirc; + + /* Initialise EFI environment */ + if ( ( efirc = efi_init ( image_handle, systab ) ) != 0 ) + return efirc; + + /* Initialise gPXE environment */ + initialise(); + startup(); + + /* Install SNP driver and return */ + return RC_TO_EFIRC ( efi_snp_install () ); +} diff --git a/gpxe/src/arch/x86/prefix/efiprefix.c b/gpxe/src/arch/x86/prefix/efiprefix.c new file mode 100644 index 00000000..b05b744d --- /dev/null +++ b/gpxe/src/arch/x86/prefix/efiprefix.c @@ -0,0 +1,39 @@ +/* + * Copyright (C) 2009 Michael Brown <mbrown@fensystems.co.uk>. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of the + * License, or any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +#include <stdlib.h> +#include <gpxe/efi/efi.h> + +/** + * EFI entry point + * + * @v image_handle Image handle + * @v systab System table + * @ret efirc EFI return status code + */ +EFI_STATUS EFIAPI _start ( EFI_HANDLE image_handle, + EFI_SYSTEM_TABLE *systab ) { + EFI_STATUS efirc; + + /* Initialise EFI environment */ + if ( ( efirc = efi_init ( image_handle, systab ) ) != 0 ) + return efirc; + + /* Call to main() */ + return RC_TO_EFIRC ( main () ); +} diff --git a/gpxe/src/arch/x86/scripts/efi.lds b/gpxe/src/arch/x86/scripts/efi.lds new file mode 100644 index 00000000..aac31056 --- /dev/null +++ b/gpxe/src/arch/x86/scripts/efi.lds @@ -0,0 +1,105 @@ +/* -*- sh -*- */ + +/* + * Linker script for EFI images + * + */ + +ENTRY ( _start ) + +SECTIONS { + + /* The file starts at a virtual address of zero, and sections are + * contiguous. Each section is aligned to at least _max_align, + * which defaults to 32. Load addresses are equal to virtual + * addresses. + */ + + _max_align = 32; + + /* Allow plenty of space for file headers */ + . = 0x1000; + + /* + * The text section + * + */ + + . = ALIGN ( _max_align ); + .text : { + _text = .; + *(.text) + *(.text.*) + _etext = .; + } + + /* + * The rodata section + * + */ + + . = ALIGN ( _max_align ); + .rodata : { + _rodata = .; + *(.rodata) + *(.rodata.*) + _erodata = .; + } + + /* + * The data section + * + */ + + . = ALIGN ( _max_align ); + .data : { + _data = .; + *(.data) + *(.data.*) + *(SORT(.tbl.*)) /* Various tables. See include/tables.h */ + _edata = .; + } + + /* + * The bss section + * + */ + + . = ALIGN ( _max_align ); + .bss : { + _bss = .; + *(.bss) + *(.bss.*) + *(COMMON) + _ebss = .; + } + + /* + * Weak symbols that need zero values if not otherwise defined + * + */ + + .weak 0x0 : { + _weak = .; + *(.weak) + _eweak = .; + } + _assert = ASSERT ( ( _weak == _eweak ), ".weak is non-zero length" ); + + /* + * Dispose of the comment and note sections to make the link map + * easier to read + * + */ + + /DISCARD/ : { + *(.comment) + *(.comment.*) + *(.note) + *(.note.*) + *(.eh_frame) + *(.eh_frame.*) + *(.rel) + *(.rel.*) + } +} diff --git a/gpxe/src/arch/x86_64/Makefile b/gpxe/src/arch/x86_64/Makefile new file mode 100644 index 00000000..d2c2ff53 --- /dev/null +++ b/gpxe/src/arch/x86_64/Makefile @@ -0,0 +1,41 @@ +# Code size reduction. +# +CFLAGS += -fstrength-reduce -fomit-frame-pointer + +# Code size reduction. gcc3 needs a different syntax to gcc2 if you +# want to avoid spurious warnings. +# +CFLAGS += -falign-jumps=1 -falign-loops=1 -falign-functions=1 + +# Use %rip-relative addressing wherever possible. +# +CFLAGS += -fpie + +# Force 64-bit code +# +CFLAGS += -m64 +ASFLAGS += --64 +LDFLAGS += -m elf_x86_64 + +# EFI requires -fshort-wchar, and nothing else currently uses wchar_t +# +CFLAGS += -fshort-wchar + +# We need to undefine the default macro "i386" when compiling .S +# files, otherwise ".arch i386" translates to ".arch 1"... +# +CFLAGS += -Ui386 + +# x86_64-specific directories containing source files +# +SRCDIRS += arch/x86_64/prefix + +# Include common x86 Makefile +# +MAKEDEPS += arch/x86/Makefile +include arch/x86/Makefile + +# Include platform-specific Makefile +# +MAKEDEPS += arch/x86_64/Makefile.$(PLATFORM) +include arch/x86_64/Makefile.$(PLATFORM) diff --git a/gpxe/src/arch/x86_64/Makefile.efi b/gpxe/src/arch/x86_64/Makefile.efi new file mode 100644 index 00000000..26b71278 --- /dev/null +++ b/gpxe/src/arch/x86_64/Makefile.efi @@ -0,0 +1,14 @@ +# -*- makefile -*- : Force emacs to use Makefile mode + +# EFI probably doesn't guarantee us a red zone, so let's not rely on it. +# +CFLAGS += -mno-red-zone + +# Specify EFI image builder +# +ELF2EFI = $(ELF2EFI64) + +# Include generic EFI Makefile +# +MAKEDEPS += arch/x86/Makefile.efi +include arch/x86/Makefile.efi diff --git a/gpxe/src/arch/x86_64/include/bits/byteswap.h b/gpxe/src/arch/x86_64/include/bits/byteswap.h new file mode 100644 index 00000000..9ed85e8f --- /dev/null +++ b/gpxe/src/arch/x86_64/include/bits/byteswap.h @@ -0,0 +1,22 @@ +#ifndef _BITS_BYTESWAP_H +#define _BITS_BYTESWAP_H + +static inline __attribute__ (( always_inline, const )) uint16_t +__bswap_variable_16 ( uint16_t x ) { + __asm__ ( "xchgb %b0,%h0" : "=Q" ( x ) : "0" ( x ) ); + return x; +} + +static inline __attribute__ (( always_inline, const )) uint32_t +__bswap_variable_32 ( uint32_t x ) { + __asm__ ( "bswapl %k0" : "=r" ( x ) : "0" ( x ) ); + return x; +} + +static inline __attribute__ (( always_inline, const )) uint64_t +__bswap_variable_64 ( uint64_t x ) { + __asm__ ( "bswapq %q0" : "=r" ( x ) : "0" ( x ) ); + return x; +} + +#endif /* _BITS_BYTESWAP_H */ diff --git a/gpxe/src/arch/x86_64/include/bits/compiler.h b/gpxe/src/arch/x86_64/include/bits/compiler.h new file mode 100644 index 00000000..51a7eaae --- /dev/null +++ b/gpxe/src/arch/x86_64/include/bits/compiler.h @@ -0,0 +1,14 @@ +#ifndef _BITS_COMPILER_H +#define _BITS_COMPILER_H + +#ifndef ASSEMBLY + +/** Declare a function with standard calling conventions */ +#define __asmcall __attribute__ (( regparm(0) )) + +/** Declare a function with libgcc implicit linkage */ +#define __libgcc + +#endif /* ASSEMBLY */ + +#endif /* _BITS_COMPILER_H */ diff --git a/gpxe/src/arch/x86_64/include/bits/endian.h b/gpxe/src/arch/x86_64/include/bits/endian.h new file mode 100644 index 00000000..413e702d --- /dev/null +++ b/gpxe/src/arch/x86_64/include/bits/endian.h @@ -0,0 +1,6 @@ +#ifndef ETHERBOOT_BITS_ENDIAN_H +#define ETHERBOOT_BITS_ENDIAN_H + +#define __BYTE_ORDER __LITTLE_ENDIAN + +#endif /* ETHERBOOT_BITS_ENDIAN_H */ diff --git a/gpxe/src/arch/x86_64/include/bits/errfile.h b/gpxe/src/arch/x86_64/include/bits/errfile.h new file mode 100644 index 00000000..dcda26ba --- /dev/null +++ b/gpxe/src/arch/x86_64/include/bits/errfile.h @@ -0,0 +1,11 @@ +#ifndef _BITS_ERRFILE_H +#define _BITS_ERRFILE_H + +/** + * @addtogroup errfile Error file identifiers + * @{ + */ + +/** @} */ + +#endif /* _BITS_ERRFILE_H */ diff --git a/gpxe/src/arch/x86_64/include/bits/io.h b/gpxe/src/arch/x86_64/include/bits/io.h new file mode 100644 index 00000000..921fdcc0 --- /dev/null +++ b/gpxe/src/arch/x86_64/include/bits/io.h @@ -0,0 +1,10 @@ +#ifndef _BITS_IO_H +#define _BITS_IO_H + +/** @file + * + * x86_64-specific I/O API implementations + * + */ + +#endif /* _BITS_IO_H */ diff --git a/gpxe/src/arch/x86_64/include/bits/nap.h b/gpxe/src/arch/x86_64/include/bits/nap.h new file mode 100644 index 00000000..0a0c8a24 --- /dev/null +++ b/gpxe/src/arch/x86_64/include/bits/nap.h @@ -0,0 +1,12 @@ +#ifndef _BITS_NAP_H +#define _BITS_NAP_H + +/** @file + * + * x86_64-specific CPU sleeping API implementations + * + */ + +#include <gpxe/efi/efix86_nap.h> + +#endif /* _BITS_MAP_H */ diff --git a/gpxe/src/arch/x86_64/include/bits/smbios.h b/gpxe/src/arch/x86_64/include/bits/smbios.h new file mode 100644 index 00000000..2f0118d0 --- /dev/null +++ b/gpxe/src/arch/x86_64/include/bits/smbios.h @@ -0,0 +1,10 @@ +#ifndef _BITS_SMBIOS_H +#define _BITS_SMBIOS_H + +/** @file + * + * i386-specific SMBIOS API implementations + * + */ + +#endif /* _BITS_SMBIOS_H */ diff --git a/gpxe/src/arch/x86_64/include/bits/stdint.h b/gpxe/src/arch/x86_64/include/bits/stdint.h new file mode 100644 index 00000000..23bae9c4 --- /dev/null +++ b/gpxe/src/arch/x86_64/include/bits/stdint.h @@ -0,0 +1,21 @@ +#ifndef _BITS_STDINT_H +#define _BITS_STDINT_H + +typedef unsigned long size_t; +typedef signed long ssize_t; +typedef signed long off_t; + +typedef unsigned char uint8_t; +typedef unsigned short uint16_t; +typedef unsigned int uint32_t; +typedef unsigned long long uint64_t; + +typedef signed char int8_t; +typedef signed short int16_t; +typedef signed int int32_t; +typedef signed long long int64_t; + +typedef unsigned long physaddr_t; +typedef unsigned long intptr_t; + +#endif /* _BITS_STDINT_H */ diff --git a/gpxe/src/arch/x86_64/include/bits/timer.h b/gpxe/src/arch/x86_64/include/bits/timer.h new file mode 100644 index 00000000..dfa6c270 --- /dev/null +++ b/gpxe/src/arch/x86_64/include/bits/timer.h @@ -0,0 +1,10 @@ +#ifndef _BITS_TIMER_H +#define _BITS_TIMER_H + +/** @file + * + * x86_64-specific timer API implementations + * + */ + +#endif /* _BITS_TIMER_H */ diff --git a/gpxe/src/arch/x86_64/include/bits/uaccess.h b/gpxe/src/arch/x86_64/include/bits/uaccess.h new file mode 100644 index 00000000..45582924 --- /dev/null +++ b/gpxe/src/arch/x86_64/include/bits/uaccess.h @@ -0,0 +1,10 @@ +#ifndef _BITS_UACCESS_H +#define _BITS_UACCESS_H + +/** @file + * + * x86_64-specific user access API implementations + * + */ + +#endif /* _BITS_UACCESS_H */ diff --git a/gpxe/src/arch/x86_64/include/bits/umalloc.h b/gpxe/src/arch/x86_64/include/bits/umalloc.h new file mode 100644 index 00000000..12bf949d --- /dev/null +++ b/gpxe/src/arch/x86_64/include/bits/umalloc.h @@ -0,0 +1,10 @@ +#ifndef _BITS_UMALLOC_H +#define _BITS_UMALLOC_H + +/** @file + * + * x86_64-specific user memory allocation API implementations + * + */ + +#endif /* _BITS_UMALLOC_H */ diff --git a/gpxe/src/arch/x86_64/include/gdbmach.h b/gpxe/src/arch/x86_64/include/gdbmach.h new file mode 100644 index 00000000..fcf8e94e --- /dev/null +++ b/gpxe/src/arch/x86_64/include/gdbmach.h @@ -0,0 +1,51 @@ +#ifndef GDBMACH_H +#define GDBMACH_H + +/** @file + * + * GDB architecture specifics + * + * This file declares functions for manipulating the machine state and + * debugging context. + * + */ + +#include <stdint.h> + +typedef unsigned long gdbreg_t; + +/* The register snapshot, this must be in sync with interrupt handler and the + * GDB protocol. */ +enum { + // STUB: don't expect this to work! + GDBMACH_EIP, + GDBMACH_EFLAGS, + GDBMACH_NREGS, + GDBMACH_SIZEOF_REGS = GDBMACH_NREGS * sizeof ( gdbreg_t ) +}; + +/* Breakpoint types */ +enum { + GDBMACH_BPMEM, + GDBMACH_BPHW, + GDBMACH_WATCH, + GDBMACH_RWATCH, + GDBMACH_AWATCH, +}; + +static inline void gdbmach_set_pc ( gdbreg_t *regs, gdbreg_t pc ) { + regs [ GDBMACH_EIP ] = pc; +} + +static inline void gdbmach_set_single_step ( gdbreg_t *regs, int step ) { + regs [ GDBMACH_EFLAGS ] &= ~( 1 << 8 ); /* Trace Flag (TF) */ + regs [ GDBMACH_EFLAGS ] |= ( step << 8 ); +} + +static inline void gdbmach_breakpoint ( void ) { + __asm__ __volatile__ ( "int $3\n" ); +} + +extern int gdbmach_set_breakpoint ( int type, unsigned long addr, size_t len, int enable ); + +#endif /* GDBMACH_H */ diff --git a/gpxe/src/arch/x86_64/include/limits.h b/gpxe/src/arch/x86_64/include/limits.h new file mode 100644 index 00000000..8cf87b47 --- /dev/null +++ b/gpxe/src/arch/x86_64/include/limits.h @@ -0,0 +1,59 @@ +#ifndef LIMITS_H +#define LIMITS_H 1 + +/* Number of bits in a `char' */ +#define CHAR_BIT 8 + +/* Minimum and maximum values a `signed char' can hold */ +#define SCHAR_MIN (-128) +#define SCHAR_MAX 127 + +/* Maximum value an `unsigned char' can hold. (Minimum is 0.) */ +#define UCHAR_MAX 255 + +/* Minimum and maximum values a `char' can hold */ +#define CHAR_MIN SCHAR_MIN +#define CHAR_MAX SCHAR_MAX + +/* Minimum and maximum values a `signed short int' can hold */ +#define SHRT_MIN (-32768) +#define SHRT_MAX 32767 + +/* Maximum value an `unsigned short' can hold. (Minimum is 0.) */ +#define USHRT_MAX 65535 + + +/* Minimum and maximum values a `signed int' can hold */ +#define INT_MIN (-INT_MAX - 1) +#define INT_MAX 2147483647 + +/* Maximum value an `unsigned int' can hold. (Minimum is 0.) */ +#define UINT_MAX 4294967295U + + +/* Minimum and maximum values a `signed int' can hold */ +#define INT_MAX 2147483647 +#define INT_MIN (-INT_MAX - 1) + + +/* Maximum value an `unsigned int' can hold. (Minimum is 0.) */ +#define UINT_MAX 4294967295U + + +/* Minimum and maximum values a `signed long' can hold */ +#define LONG_MAX 9223372036854775807L +#define LONG_MIN (-LONG_MAX - 1L) + +/* Maximum value an `unsigned long' can hold. (Minimum is 0.) */ +#define ULONG_MAX 18446744073709551615UL + +/* Minimum and maximum values a `signed long long' can hold */ +#define LLONG_MAX 9223372036854775807LL +#define LLONG_MIN (-LONG_MAX - 1LL) + + +/* Maximum value an `unsigned long long' can hold. (Minimum is 0.) */ +#define ULLONG_MAX 18446744073709551615ULL + + +#endif /* LIMITS_H */ diff --git a/gpxe/src/config.h b/gpxe/src/config.h deleted file mode 100644 index 603604ab..00000000 --- a/gpxe/src/config.h +++ /dev/null @@ -1,175 +0,0 @@ -/* - * This file defines the configuration for Etherboot. - * - * The build system splits this file into several individual header - * files of the form config/%.h, so that changing one option doesn't - * necessitate a rebuild of every single object. For this reason, it - * is important to maintain the strict formatting in this file. - * - */ - -/* @BEGIN general.h - * - * Console configuration - * - * These options specify the console types that Etherboot will use for - * interaction with the user. - * - */ - -#define CONSOLE_FIRMWARE /* Default BIOS console */ -#undef CONSOLE_SERIAL /* Serial port */ -#undef CONSOLE_DIRECT_VGA /* Direct access to VGA card */ -#undef CONSOLE_BTEXT /* Who knows what this does? */ -#undef CONSOLE_PC_KBD /* Direct access to PC keyboard */ - -/* @END general.h */ - -/* @BEGIN serial.h - * - * Serial port configuration - * - * These options affect the operation of the serial console. They - * take effect only if the serial console is included using the - * CONSOLE_SERIAL option. - * - */ - -#define COMCONSOLE 0x3f8 /* I/O port address */ - -/* Keep settings from a previous user of the serial port (e.g. lilo or - * LinuxBIOS), ignoring COMSPEED, COMDATA, COMPARITY and COMSTOP. - */ -#undef COMPRESERVE - -#ifndef COMPRESERVE -#define COMSPEED 115200 /* Baud rate */ -#define COMDATA 8 /* Data bits */ -#define COMPARITY 0 /* Parity: 0=None, 1=Odd, 2=Even */ -#define COMSTOP 1 /* Stop bits */ -#endif - -/* @END serial.h */ - -/* @BEGIN general.h - * - * Timer configuration - * - */ -#define TIMER_BIOS /* 18Hz BIOS timer */ -#define TIMER_RDTSC /* CPU TimeStamp Counter timer */ -#define BANNER_TIMEOUT 20 /* Tenths of a second for which the shell - banner should appear */ - -/* @END general.h */ - -/* @BEGIN isa.h - * - * ISA probe address configuration - * - * You can override the list of addresses that will be probed by any - * ISA drivers. - * - */ -#undef ISA_PROBE_ADDRS /* e.g. 0x200, 0x300 */ -#undef ISA_PROBE_ONLY /* Do not probe any other addresses */ - -/* @END isa.h */ - -/* @BEGIN general.h - * - * Network protocols - * - */ - -#define NET_PROTO_IPV4 /* IPv4 protocol */ - -/* @END general.h */ - -/* @BEGIN general.h - * - * Download protocols - * - */ - -#define DOWNLOAD_PROTO_TFTP /* Trivial File Transfer Protocol */ -#define DOWNLOAD_PROTO_NFS /* Network File System */ -#define DOWNLOAD_PROTO_HTTP /* Hypertext Transfer Protocol */ -#define DOWNLOAD_PROTO_HTTPS /* Secure Hypertext Transfer Protocol */ -#define DOWNLOAD_PROTO_FTP /* File Transfer Protocol */ -#undef DOWNLOAD_PROTO_TFTM /* Multicast Trivial File Transfer Protocol */ -#undef DOWNLOAD_PROTO_SLAM /* Scalable Local Area Multicast */ -#undef DOWNLOAD_PROTO_FSP /* FSP? */ - -/* @END general.h */ - -/* @BEGIN general.h - * - * Name resolution modules - * - */ - -#define DNS_RESOLVER /* DNS resolver */ -#undef NMB_RESOLVER /* NMB resolver */ - -/* @END general.h */ - -/* @BEGIN general.h - * - * Image types - * - * Etherboot supports various image formats. Select whichever ones - * you want to use. - * - */ -#undef IMAGE_NBI /* NBI image support */ -#define IMAGE_ELF /* ELF image support */ -#undef IMAGE_FREEBSD /* FreeBSD kernel image support */ -#define IMAGE_MULTIBOOT /* MultiBoot image support */ -#undef IMAGE_AOUT /* a.out image support */ -#undef IMAGE_WINCE /* WinCE image support */ -#define IMAGE_PXE /* PXE image support */ -#define IMAGE_SCRIPT /* gPXE script image support */ -#define IMAGE_BZIMAGE /* Linux bzImage image support */ -#define IMAGE_COMBOOT /* SYSLINUX COMBOOT image support */ - -/* @END general.h */ - -/* @BEGIN general.h - * - * Command-line commands to include - * - */ -#define AUTOBOOT_CMD /* Automatic booting */ -#define NVO_CMD /* Non-volatile option storage commands */ -#define CONFIG_CMD /* Option configuration console */ -#define IFMGMT_CMD /* Interface management commands */ -#define ROUTE_CMD /* Routing table management commands */ -#define IMAGE_CMD /* Image management commands */ -#define DHCP_CMD /* DHCP management commands */ -#define SANBOOT_CMD /* SAN boot commands */ - -/* @END general.h */ - -/* @BEGIN general.h - * - * Obscure configuration options - * - * You probably don't need to touch these. - * - */ - -#undef BUILD_SERIAL /* Include an automatic build serial - * number. Add "bs" to the list of - * make targets. For example: - * "make bin/rtl8139.dsk bs" */ -#undef BUILD_ID /* Include a custom build ID string, - * e.g "test-foo" */ -#undef NULL_TRAP /* Attempt to catch NULL function calls */ -#undef GDBSERIAL /* Remote GDB debugging over serial */ -#undef GDBUDP /* Remote GDB debugging over UDP - * (both may be set) */ - -/* @END general.h */ - -/* @TRYSOURCE config-local.h */ diff --git a/gpxe/src/config/.gitignore b/gpxe/src/config/.gitignore index 499ae122..8e94f32f 100644 --- a/gpxe/src/config/.gitignore +++ b/gpxe/src/config/.gitignore @@ -1,2 +1 @@ -*.h .buildserial.* diff --git a/gpxe/src/config/console.h b/gpxe/src/config/console.h new file mode 100644 index 00000000..b4ea1dda --- /dev/null +++ b/gpxe/src/config/console.h @@ -0,0 +1,21 @@ +#ifndef CONFIG_CONSOLE_H +#define CONFIG_CONSOLE_H + +/** @file + * + * Console configuration + * + * These options specify the console types that Etherboot will use for + * interaction with the user. + * + */ + +#include <config/defaults.h> + +//#define CONSOLE_PCBIOS /* Default BIOS console */ +//#define CONSOLE_SERIAL /* Serial port */ +//#define CONSOLE_DIRECT_VGA /* Direct access to VGA card */ +//#define CONSOLE_BTEXT /* Who knows what this does? */ +//#define CONSOLE_PC_KBD /* Direct access to PC keyboard */ + +#endif /* CONFIG_CONSOLE_H */ diff --git a/gpxe/src/config/defaults.h b/gpxe/src/config/defaults.h new file mode 100644 index 00000000..1f55ef3c --- /dev/null +++ b/gpxe/src/config/defaults.h @@ -0,0 +1,8 @@ +#ifndef CONFIG_DEFAULTS_H +#define CONFIG_DEFAULTS_H + +#define CONFIG_DEFAULTS(_platform) <config/defaults/_platform.h> + +#include CONFIG_DEFAULTS(PLATFORM) + +#endif /* CONFIG_DEFAULTS_H */ diff --git a/gpxe/src/config/defaults/efi.h b/gpxe/src/config/defaults/efi.h new file mode 100644 index 00000000..fe38fd03 --- /dev/null +++ b/gpxe/src/config/defaults/efi.h @@ -0,0 +1,21 @@ +#ifndef CONFIG_DEFAULTS_EFI_H +#define CONFIG_DEFAULTS_EFI_H + +/** @file + * + * Configuration defaults for EFI + * + */ + +#define UACCESS_EFI +#define IOAPI_EFI +#define PCIAPI_EFI +#define CONSOLE_EFI +#define TIMER_EFI +#define NAP_EFIX86 +#define UMALLOC_EFI +#define SMBIOS_EFI + +#define IMAGE_EFI /* EFI image support */ + +#endif /* CONFIG_DEFAULTS_EFI_H */ diff --git a/gpxe/src/config/defaults/pcbios.h b/gpxe/src/config/defaults/pcbios.h new file mode 100644 index 00000000..4359e1a4 --- /dev/null +++ b/gpxe/src/config/defaults/pcbios.h @@ -0,0 +1,29 @@ +#ifndef CONFIG_DEFAULTS_PCBIOS_H +#define CONFIG_DEFAULTS_PCBIOS_H + +/** @file + * + * Configuration defaults for PCBIOS + * + */ + +#define UACCESS_LIBRM +#define IOAPI_X86 +#define PCIAPI_PCBIOS +#define TIMER_PCBIOS +#define CONSOLE_PCBIOS +#define NAP_PCBIOS +#define UMALLOC_MEMTOP +#define SMBIOS_PCBIOS + +#define IMAGE_ELF /* ELF image support */ +#define IMAGE_MULTIBOOT /* MultiBoot image support */ +#define IMAGE_PXE /* PXE image support */ +#define IMAGE_SCRIPT /* gPXE script image support */ +#define IMAGE_BZIMAGE /* Linux bzImage image support */ +#define IMAGE_COMBOOT /* SYSLINUX COMBOOT image support */ + +#define SANBOOT_PROTO_ISCSI /* iSCSI protocol */ +#define SANBOOT_PROTO_AOE /* AoE protocol */ + +#endif /* CONFIG_DEFAULTS_PCBIOS_H */ diff --git a/gpxe/src/config/general.h b/gpxe/src/config/general.h new file mode 100644 index 00000000..a3d563c2 --- /dev/null +++ b/gpxe/src/config/general.h @@ -0,0 +1,123 @@ +#ifndef CONFIG_GENERAL_H +#define CONFIG_GENERAL_H + +/** @file + * + * General configuration + * + */ + +#include <config/defaults.h> + +/* + * Branding + * + * Vendors may use these strings to add their own branding to gPXE. + * PRODUCT_NAME is displayed prior to any gPXE branding in startup + * messages, and PRODUCT_SHORT_NAME is used where a brief product + * label is required (e.g. in BIOS boot selection menus). + * + * To minimise end-user confusion, it's probably a good idea to either + * make PRODUCT_SHORT_NAME a substring of PRODUCT_NAME or leave it as + * "gPXE". + * + */ +#define PRODUCT_NAME "" +#define PRODUCT_SHORT_NAME "gPXE" + +/* + * Timer configuration + * + */ +#define BANNER_TIMEOUT 20 /* Tenths of a second for which the shell + banner should appear */ + +/* + * Network protocols + * + */ + +#define NET_PROTO_IPV4 /* IPv4 protocol */ + +/* + * Download protocols + * + */ + +#define DOWNLOAD_PROTO_TFTP /* Trivial File Transfer Protocol */ +#define DOWNLOAD_PROTO_NFS /* Network File System */ +#define DOWNLOAD_PROTO_HTTP /* Hypertext Transfer Protocol */ +#define DOWNLOAD_PROTO_HTTPS /* Secure Hypertext Transfer Protocol */ +#define DOWNLOAD_PROTO_FTP /* File Transfer Protocol */ +#undef DOWNLOAD_PROTO_TFTM /* Multicast Trivial File Transfer Protocol */ +#undef DOWNLOAD_PROTO_SLAM /* Scalable Local Area Multicast */ +#undef DOWNLOAD_PROTO_FSP /* FSP? */ + +/* + * SAN boot protocols + * + */ + +//#undef SANBOOT_PROTO_ISCSI /* iSCSI protocol */ +//#undef SANBOOT_PROTO_AOE /* AoE protocol */ + +/* + * Name resolution modules + * + */ + +#define DNS_RESOLVER /* DNS resolver */ +#undef NMB_RESOLVER /* NMB resolver */ + +/* + * Image types + * + * Etherboot supports various image formats. Select whichever ones + * you want to use. + * + */ +//#define IMAGE_NBI /* NBI image support */ +//#define IMAGE_ELF /* ELF image support */ +//#define IMAGE_FREEBSD /* FreeBSD kernel image support */ +//#define IMAGE_MULTIBOOT /* MultiBoot image support */ +//#define IMAGE_AOUT /* a.out image support */ +//#define IMAGE_WINCE /* WinCE image support */ +//#define IMAGE_PXE /* PXE image support */ +//#define IMAGE_SCRIPT /* gPXE script image support */ +//#define IMAGE_BZIMAGE /* Linux bzImage image support */ +//#define IMAGE_COMBOOT /* SYSLINUX COMBOOT image support */ +//#define IMAGE_EFI /* EFI image support */ + +/* + * Command-line commands to include + * + */ +#define AUTOBOOT_CMD /* Automatic booting */ +#define NVO_CMD /* Non-volatile option storage commands */ +#define CONFIG_CMD /* Option configuration console */ +#define IFMGMT_CMD /* Interface management commands */ +#define ROUTE_CMD /* Routing table management commands */ +#define IMAGE_CMD /* Image management commands */ +#define DHCP_CMD /* DHCP management commands */ +#define SANBOOT_CMD /* SAN boot commands */ +#define LOGIN_CMD /* Login command */ + +/* + * Obscure configuration options + * + * You probably don't need to touch these. + * + */ + +#undef BUILD_SERIAL /* Include an automatic build serial + * number. Add "bs" to the list of + * make targets. For example: + * "make bin/rtl8139.dsk bs" */ +#undef BUILD_ID /* Include a custom build ID string, + * e.g "test-foo" */ +#undef NULL_TRAP /* Attempt to catch NULL function calls */ +#undef GDBSERIAL /* Remote GDB debugging over serial */ +#undef GDBUDP /* Remote GDB debugging over UDP + * (both may be set) */ + +#endif /* CONFIG_GENERAL_H */ diff --git a/gpxe/src/config/ioapi.h b/gpxe/src/config/ioapi.h new file mode 100644 index 00000000..7726a0f0 --- /dev/null +++ b/gpxe/src/config/ioapi.h @@ -0,0 +1,15 @@ +#ifndef CONFIG_IOAPI_H +#define CONFIG_IOAPI_H + +/** @file + * + * I/O API configuration + * + */ + +#include <config/defaults.h> + +//#undef PCIAPI_PCBIOS /* Access via PCI BIOS */ +//#define PCIAPI_DIRECT /* Direct access via Type 1 accesses */ + +#endif /* CONFIG_IOAPI_H */ diff --git a/gpxe/src/config/isa.h b/gpxe/src/config/isa.h new file mode 100644 index 00000000..523be1c0 --- /dev/null +++ b/gpxe/src/config/isa.h @@ -0,0 +1,15 @@ +#ifndef CONFIG_ISA_H +#define CONFIG_ISA_H + +/** @file + * + * ISA probe address configuration + * + * You can override the list of addresses that will be probed by any + * ISA drivers. + * + */ +#undef ISA_PROBE_ADDRS /* e.g. 0x200, 0x300 */ +#undef ISA_PROBE_ONLY /* Do not probe any other addresses */ + +#endif /* CONFIG_ISA_H */ diff --git a/gpxe/src/config/nap.h b/gpxe/src/config/nap.h new file mode 100644 index 00000000..8648d925 --- /dev/null +++ b/gpxe/src/config/nap.h @@ -0,0 +1,15 @@ +#ifndef CONFIG_NAP_H +#define CONFIG_NAP_H + +/** @file + * + * CPU sleeping + * + */ + +#include <config/defaults.h> + +//#undef NAP_PCBIOS +//#define NAP_NULL + +#endif /* CONFIG_NAP_H */ diff --git a/gpxe/src/config/serial.h b/gpxe/src/config/serial.h new file mode 100644 index 00000000..984a7a9c --- /dev/null +++ b/gpxe/src/config/serial.h @@ -0,0 +1,28 @@ +#ifndef CONFIG_SERIAL_H +#define CONFIG_SERIAL_H + +/** @file + * + * Serial port configuration + * + * These options affect the operation of the serial console. They + * take effect only if the serial console is included using the + * CONSOLE_SERIAL option. + * + */ + +#define COMCONSOLE 0x3f8 /* I/O port address */ + +/* Keep settings from a previous user of the serial port (e.g. lilo or + * LinuxBIOS), ignoring COMSPEED, COMDATA, COMPARITY and COMSTOP. + */ +#undef COMPRESERVE + +#ifndef COMPRESERVE +#define COMSPEED 115200 /* Baud rate */ +#define COMDATA 8 /* Data bits */ +#define COMPARITY 0 /* Parity: 0=None, 1=Odd, 2=Even */ +#define COMSTOP 1 /* Stop bits */ +#endif + +#endif /* CONFIG_SERIAL_H */ diff --git a/gpxe/src/config/timer.h b/gpxe/src/config/timer.h new file mode 100644 index 00000000..7c3f3521 --- /dev/null +++ b/gpxe/src/config/timer.h @@ -0,0 +1,15 @@ +#ifndef CONFIG_TIMER_H +#define CONFIG_TIMER_H + +/** @file + * + * Timer configuration. + * + */ + +#include <config/defaults.h> + +//#undef TIMER_PCBIOS +//#define TIMER_RDTSC + +#endif /* CONFIG_TIMER_H */ diff --git a/gpxe/src/config/umalloc.h b/gpxe/src/config/umalloc.h new file mode 100644 index 00000000..de4019e5 --- /dev/null +++ b/gpxe/src/config/umalloc.h @@ -0,0 +1,12 @@ +#ifndef CONFIG_UMALLOC_H +#define CONFIG_UMALLOC_H + +/** @file + * + * User memory allocation API configuration + * + */ + +#include <config/defaults.h> + +#endif /* CONFIG_UMALLOC_H */ diff --git a/gpxe/src/core/base64.c b/gpxe/src/core/base64.c new file mode 100644 index 00000000..e54821e3 --- /dev/null +++ b/gpxe/src/core/base64.c @@ -0,0 +1,66 @@ +/* + * Copyright (C) 2009 Michael Brown <mbrown@fensystems.co.uk>. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of the + * License, or any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +#include <stdint.h> +#include <string.h> +#include <assert.h> +#include <gpxe/base64.h> + +/** @file + * + * Base64 encoding + * + */ + +static const char base64[64] = + "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"; + +/** + * Base64-encode a string + * + * @v raw Raw string + * @v encoded Buffer for encoded string + * + * The buffer must be the correct length for the encoded string. Use + * something like + * + * char buf[ base64_encoded_len ( strlen ( raw ) ) + 1 ]; + * + * (the +1 is for the terminating NUL) to provide a buffer of the + * correct size. + */ +void base64_encode ( const char *raw, char *encoded ) { + const uint8_t *raw_bytes = ( ( const uint8_t * ) raw ); + uint8_t *encoded_bytes = ( ( uint8_t * ) encoded ); + size_t raw_bit_len = ( 8 * strlen ( raw ) ); + unsigned int bit; + unsigned int tmp; + + for ( bit = 0 ; bit < raw_bit_len ; bit += 6 ) { + tmp = ( ( raw_bytes[ bit / 8 ] << ( bit % 8 ) ) | + ( raw_bytes[ bit / 8 + 1 ] >> ( 8 - ( bit % 8 ) ) ) ); + tmp = ( ( tmp >> 2 ) & 0x3f ); + *(encoded_bytes++) = base64[tmp]; + } + for ( ; ( bit % 8 ) != 0 ; bit += 6 ) + *(encoded_bytes++) = '='; + *(encoded_bytes++) = '\0'; + + DBG ( "Base64-encoded \"%s\" as \"%s\"\n", raw, encoded ); + assert ( strlen ( encoded ) == base64_encoded_len ( strlen ( raw ) ) ); +} diff --git a/gpxe/src/core/config.c b/gpxe/src/core/config.c index b5624fae..bd0d66ec 100644 --- a/gpxe/src/core/config.c +++ b/gpxe/src/core/config.c @@ -5,7 +5,8 @@ * your option) any later version. */ -#include "config/general.h" +#include <config/general.h> +#include <config/console.h> /* * Build ID string calculations @@ -38,19 +39,9 @@ /* * Drag in all requested console types * - * CONSOLE_DUAL sets both CONSOLE_FIRMWARE and CONSOLE_SERIAL for - * legacy compatibility. - * */ -#ifdef CONSOLE_DUAL -#undef CONSOLE_FIRMWARE -#define CONSOLE_FIRMWARE 1 -#undef CONSOLE_SERIAL -#define CONSOLE_SERIAL 1 -#endif - -#ifdef CONSOLE_FIRMWARE +#ifdef CONSOLE_PCBIOS REQUIRE_OBJECT ( bios_console ); #endif #ifdef CONSOLE_SERIAL @@ -68,15 +59,8 @@ REQUIRE_OBJECT ( pc_kbd ); #ifdef CONSOLE_SYSLOG REQUIRE_OBJECT ( syslog ); #endif - -/* - * Drag in all requested timers - */ -#ifdef TIMER_BIOS -REQUIRE_OBJECT ( timer_bios ); -#endif -#ifdef TIMER_RDTSC -REQUIRE_OBJECT ( timer_rdtsc ); +#ifdef CONSOLE_EFI +REQUIRE_OBJECT ( efi_console ); #endif /* @@ -114,6 +98,17 @@ REQUIRE_OBJECT ( slam ); #endif /* + * Drag in all requested SAN boot protocols + * + */ +#ifdef SANBOOT_PROTO_ISCSI +REQUIRE_OBJECT ( iscsiboot ); +#endif +#ifdef SANBOOT_PROTO_AOE +REQUIRE_OBJECT ( aoeboot ); +#endif + +/* * Drag in all requested resolvers * */ @@ -166,6 +161,9 @@ REQUIRE_OBJECT ( com32_call ); REQUIRE_OBJECT ( com32_wrapper ); REQUIRE_OBJECT ( comboot_resolv ); #endif +#ifdef IMAGE_EFI +REQUIRE_OBJECT ( efi_image ); +#endif /* * Drag in all requested commands @@ -195,6 +193,9 @@ REQUIRE_OBJECT ( dhcp_cmd ); #ifdef SANBOOT_CMD REQUIRE_OBJECT ( sanboot_cmd ); #endif +#ifdef LOGIN_CMD +REQUIRE_OBJECT ( login_cmd ); +#endif /* * Drag in miscellaneous objects @@ -220,3 +221,4 @@ REQUIRE_OBJECT ( gdbstub_cmd ); * */ REQUIRE_OBJECT ( device ); +REQUIRE_OBJECT ( embedded ); diff --git a/gpxe/src/core/console.c b/gpxe/src/core/console.c index 653f689d..c9773f71 100644 --- a/gpxe/src/core/console.c +++ b/gpxe/src/core/console.c @@ -1,11 +1,10 @@ #include "stddef.h" #include "console.h" #include <gpxe/process.h> +#include <gpxe/nap.h> /** @file */ -#include "bios.h" - static struct console_driver console_drivers[0] __table_start ( struct console_driver, console ); static struct console_driver console_drivers_end[0] @@ -82,9 +81,6 @@ static struct console_driver * has_input ( void ) { * * The character read will not be echoed back to any console. * - * @bug We need a cleaner way to pick up cpu_nap(). It makes a - * real-mode call, and so we don't want to use it with LinuxBIOS. - * */ int getchar ( void ) { struct console_driver *console; diff --git a/gpxe/src/core/cwuri.c b/gpxe/src/core/cwuri.c index c7f01386..81fd900e 100644 --- a/gpxe/src/core/cwuri.c +++ b/gpxe/src/core/cwuri.c @@ -36,6 +36,9 @@ struct uri *cwuri = NULL; * @v uri New working URI, or NULL */ void churi ( struct uri *uri ) { + struct uri *new_uri; + + new_uri = resolve_uri ( cwuri, uri ); uri_put ( cwuri ); - cwuri = uri_get ( uri ); + cwuri = new_uri; } diff --git a/gpxe/src/core/debug.c b/gpxe/src/core/debug.c index 09830420..500a7ac0 100644 --- a/gpxe/src/core/debug.c +++ b/gpxe/src/core/debug.c @@ -1,7 +1,7 @@ #include <stdio.h> #include <stdint.h> #include <stdarg.h> -#include <io.h> +#include <gpxe/io.h> #include <console.h> void pause ( void ) { @@ -106,12 +106,12 @@ int check_region ( void *region, size_t len ) { virt_to_phys ( region + len ) ); } in_corruption = 1; - printf ( "--- offset %#lx ", offset ); + printf ( "--- offset %#x ", offset ); } else if ( ( in_corruption != 0 ) && ( test == GUARD_SYMBOL ) ) { /* End of corruption */ in_corruption = 0; - printf ( "to offset %#lx", offset ); + printf ( "to offset %#x", offset ); } } diff --git a/gpxe/src/core/gdbudp.c b/gpxe/src/core/gdbudp.c index c49a1bca..26feb38a 100644 --- a/gpxe/src/core/gdbudp.c +++ b/gpxe/src/core/gdbudp.c @@ -19,7 +19,6 @@ #include <stdio.h> #include <string.h> #include <byteswap.h> -#include <bios.h> #include <gpxe/iobuf.h> #include <gpxe/in.h> #include <gpxe/if_arp.h> @@ -27,6 +26,7 @@ #include <gpxe/ip.h> #include <gpxe/udp.h> #include <gpxe/netdevice.h> +#include <gpxe/nap.h> #include <gpxe/gdbstub.h> #include <gpxe/gdbudp.h> diff --git a/gpxe/src/core/getkey.c b/gpxe/src/core/getkey.c index 1551cf37..787c9027 100644 --- a/gpxe/src/core/getkey.c +++ b/gpxe/src/core/getkey.c @@ -16,6 +16,7 @@ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ +#include <ctype.h> #include <console.h> #include <gpxe/process.h> #include <gpxe/keys.h> @@ -59,21 +60,22 @@ static int getchar_timeout ( unsigned long timeout ) { */ int getkey ( void ) { int character; - int key; + unsigned int n = 0; character = getchar(); if ( character != ESC ) return character; - key = 0; while ( ( character = getchar_timeout ( GETKEY_TIMEOUT ) ) >= 0 ) { if ( character == '[' ) continue; - if ( ! key ) - key = KEY_ANSI ( character ); + if ( isdigit ( character ) ) { + n = ( ( n * 10 ) + ( character - '0' ) ); + continue; + } if ( character >= 0x40 ) - break; + return KEY_ANSI ( n, character ); } - return ( key ? key : ESC ); + return ESC; } diff --git a/gpxe/src/core/image.c b/gpxe/src/core/image.c index 440a68c9..277d09a9 100644 --- a/gpxe/src/core/image.c +++ b/gpxe/src/core/image.c @@ -53,6 +53,7 @@ static void free_image ( struct refcnt *refcnt ) { uri_put ( image->uri ); ufree ( image->data ); + image_put ( image->replacement ); free ( image ); DBGC ( image, "IMAGE %p freed\n", image ); } @@ -142,9 +143,9 @@ int register_image ( struct image *image ) { * @v image Executable/loadable image */ void unregister_image ( struct image *image ) { + DBGC ( image, "IMAGE %p unregistered\n", image ); list_del ( &image->list ); image_put ( image ); - DBGC ( image, "IMAGE %p unregistered\n", image ); } /** @@ -237,6 +238,7 @@ int image_autoload ( struct image *image ) { * @ret rc Return status code */ int image_exec ( struct image *image ) { + struct image *replacement; struct uri *old_cwuri; int rc; @@ -257,18 +259,39 @@ int image_exec ( struct image *image ) { old_cwuri = uri_get ( cwuri ); churi ( image->uri ); + /* Take out a temporary reference to the image. This allows + * the image to unregister itself if necessary, without + * automatically freeing itself. + */ + image_get ( image ); + /* Try executing the image */ if ( ( rc = image->type->exec ( image ) ) != 0 ) { DBGC ( image, "IMAGE %p could not execute: %s\n", image, strerror ( rc ) ); - goto done; + /* Do not return yet; we still have clean-up to do */ } - done: + /* Pick up replacement image before we drop the original + * image's temporary reference. + */ + replacement = image->replacement; + + /* Drop temporary reference to the original image */ + image_put ( image ); + /* Reset current working directory */ churi ( old_cwuri ); uri_put ( old_cwuri ); + /* Tail-recurse into replacement image, if one exists */ + if ( replacement ) { + DBGC ( image, "IMAGE %p replacing self with IMAGE %p\n", + image, replacement ); + if ( ( rc = image_exec ( replacement ) ) != 0 ) + return rc; + } + return rc; } diff --git a/gpxe/src/core/main.c b/gpxe/src/core/main.c index d5892261..8d360c42 100644 --- a/gpxe/src/core/main.c +++ b/gpxe/src/core/main.c @@ -19,7 +19,9 @@ Literature dealing with the network protocols: #include <gpxe/features.h> #include <gpxe/shell.h> #include <gpxe/shell_banner.h> +#include <gpxe/image.h> #include <usr/autoboot.h> +#include <config/general.h> #define NORMAL "\033[0m" #define BOLD "\033[1m" @@ -33,14 +35,29 @@ static struct feature features_end[0] __table_end ( struct feature, features ); * * @ret rc Return status code */ -__cdecl int main ( void ) { +__asmcall int main ( void ) { struct feature *feature; + struct image *image; + + /* Some devices take an unreasonably long time to initialise */ + printf ( PRODUCT_SHORT_NAME " initialising devices...\n" ); initialise(); startup(); - /* Print welcome banner */ - printf ( NORMAL "\n\n\n" BOLD "gPXE " VERSION + /* + * Print welcome banner + * + * + * If you wish to brand this build of gPXE, 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 gPXE or http://etherboot.org, we prefer you + * not to do so. + * + */ + printf ( NORMAL "\n\n" PRODUCT_NAME "\n" BOLD "gPXE " VERSION NORMAL " -- Open Source Boot Firmware -- " CYAN "http://etherboot.org" NORMAL "\n" "Features:" ); @@ -53,11 +70,16 @@ __cdecl int main ( void ) { /* User wants shell; just give them a shell */ shell(); } else { - /* User doesn't want shell; try booting. If booting - * fails, offer a second chance to enter the shell for - * diagnostics. + /* User doesn't want shell; load and execute the first + * image. If booting fails (i.e. if the image + * returns, or fails to execute), offer a second + * chance to enter the shell for diagnostics. */ - autoboot(); + for_each_image ( image ) { + image_exec ( image ); + break; + } + if ( shell_banner() ) shell(); } diff --git a/gpxe/src/core/malloc.c b/gpxe/src/core/malloc.c index 2d892f42..db7f1bed 100644 --- a/gpxe/src/core/malloc.c +++ b/gpxe/src/core/malloc.c @@ -20,7 +20,7 @@ #include <stdint.h> #include <string.h> #include <strings.h> -#include <io.h> +#include <gpxe/io.h> #include <gpxe/list.h> #include <gpxe/init.h> #include <gpxe/malloc.h> diff --git a/gpxe/src/core/monojob.c b/gpxe/src/core/monojob.c index 2c91e132..657bfd7a 100644 --- a/gpxe/src/core/monojob.c +++ b/gpxe/src/core/monojob.c @@ -63,7 +63,8 @@ struct job_interface monojob = { int monojob_wait ( const char *string ) { int key; int rc; - tick_t last_progress_dot; + unsigned long last_progress_dot; + unsigned long elapsed; printf ( "%s.", string ); monojob_rc = -EINPROGRESS; @@ -81,7 +82,8 @@ int monojob_wait ( const char *string ) { break; } } - if ( ( currticks() - last_progress_dot ) > TICKS_PER_SEC ) { + elapsed = ( currticks() - last_progress_dot ); + if ( elapsed >= TICKS_PER_SEC ) { printf ( "." ); last_progress_dot = currticks(); } @@ -89,6 +91,7 @@ int monojob_wait ( const char *string ) { rc = monojob_rc; done: + job_done ( &monojob, rc ); if ( rc ) { printf ( " %s\n", strerror ( rc ) ); } else { diff --git a/gpxe/src/core/null_nap.c b/gpxe/src/core/null_nap.c new file mode 100644 index 00000000..a3b01eb1 --- /dev/null +++ b/gpxe/src/core/null_nap.c @@ -0,0 +1,3 @@ +#include <gpxe/nap.h> + +PROVIDE_NAP_INLINE ( null, cpu_nap ); diff --git a/gpxe/src/core/nvo.c b/gpxe/src/core/nvo.c index 13078022..e5c07d98 100644 --- a/gpxe/src/core/nvo.c +++ b/gpxe/src/core/nvo.c @@ -203,7 +203,7 @@ void nvo_init ( struct nvo_block *nvo, struct nvs_device *nvs, nvo->nvs = nvs; nvo->fragments = fragments; settings_init ( &nvo->settings, &nvo_settings_operations, refcnt, - "nvo" ); + "nvo", 0 ); } /** diff --git a/gpxe/src/core/pc_kbd.c b/gpxe/src/core/pc_kbd.c index d43357fe..799c8beb 100644 --- a/gpxe/src/core/pc_kbd.c +++ b/gpxe/src/core/pc_kbd.c @@ -10,7 +10,7 @@ * yhlu@tyan.com */ -#include "io.h" +#include <gpxe/io.h> #include "console.h" static char key_map[][128] = { diff --git a/gpxe/src/core/process.c b/gpxe/src/core/process.c index cf931acf..6a687140 100644 --- a/gpxe/src/core/process.c +++ b/gpxe/src/core/process.c @@ -79,7 +79,9 @@ void step ( void ) { list_for_each_entry ( process, &run_queue, list ) { list_del ( &process->list ); list_add_tail ( &process->list, &run_queue ); + DBGC2 ( process, "PROCESS %p executing\n", process ); process->step ( process ); + DBGC2 ( process, "PROCESS %p finished executing\n", process ); break; } } diff --git a/gpxe/src/core/serial.c b/gpxe/src/core/serial.c index 97640f93..5b3be39c 100644 --- a/gpxe/src/core/serial.c +++ b/gpxe/src/core/serial.c @@ -13,7 +13,7 @@ #include "stddef.h" #include <gpxe/init.h> -#include "io.h" +#include <gpxe/io.h> #include <unistd.h> #include <gpxe/serial.h> #include "config/serial.h" diff --git a/gpxe/src/core/settings.c b/gpxe/src/core/settings.c index 3e9eb18a..f34eb664 100644 --- a/gpxe/src/core/settings.c +++ b/gpxe/src/core/settings.c @@ -183,12 +183,17 @@ static void reprioritise_settings ( struct settings *settings ) { * @ret rc Return status code */ int register_settings ( struct settings *settings, struct settings *parent ) { + struct settings *old_settings; /* NULL parent => add to settings root */ assert ( settings != NULL ); if ( parent == NULL ) parent = &settings_root; + /* Remove any existing settings with the same name */ + if ( ( old_settings = find_child_settings ( parent, settings->name ) )) + unregister_settings ( old_settings ); + /* Add to list of settings */ ref_get ( settings->refcnt ); ref_get ( parent->refcnt ); @@ -279,7 +284,7 @@ struct settings * find_settings ( const char *name ) { /** * Store value of setting * - * @v settings Settings block + * @v settings Settings block, or NULL * @v setting Setting to store * @v data Setting data, or NULL to clear setting * @v len Length of setting data @@ -289,9 +294,9 @@ int store_setting ( struct settings *settings, struct setting *setting, const void *data, size_t len ) { int rc; - /* Sanity check */ + /* NULL settings implies storing into the global settings root */ if ( ! settings ) - return -ENODEV; + settings = &settings_root; /* Store setting */ if ( ( rc = settings->op->store ( settings, setting, @@ -333,6 +338,9 @@ int fetch_setting ( struct settings *settings, struct setting *setting, struct settings *child; int ret; + /* Avoid returning uninitialised data on error */ + memset ( data, 0, len ); + /* NULL settings implies starting at the global settings root */ if ( ! settings ) settings = &settings_root; @@ -387,6 +395,38 @@ int fetch_string_setting ( struct settings *settings, struct setting *setting, } /** + * Fetch value of string setting + * + * @v settings Settings block, or NULL to search all blocks + * @v setting Setting to fetch + * @v data Buffer to allocate and fill with setting string data + * @ret len Length of string setting, or negative error + * + * The resulting string is guaranteed to be correctly NUL-terminated. + * The returned length will be the length of the underlying setting + * data. The caller is responsible for eventually freeing the + * allocated buffer. + */ +int fetch_string_setting_copy ( struct settings *settings, + struct setting *setting, + char **data ) { + int len; + int check_len; + + len = fetch_setting_len ( settings, setting ); + if ( len < 0 ) + return len; + + *data = malloc ( len + 1 ); + if ( ! *data ) + return -ENOMEM; + + fetch_string_setting ( settings, setting, *data, ( len + 1 ) ); + assert ( check_len == len ); + return len; +} + +/** * Fetch value of IPv4 address setting * * @v settings Settings block, or NULL to search all blocks @@ -417,20 +457,23 @@ int fetch_ipv4_setting ( struct settings *settings, struct setting *setting, int fetch_int_setting ( struct settings *settings, struct setting *setting, long *value ) { union { - long value; uint8_t u8[ sizeof ( long ) ]; int8_t s8[ sizeof ( long ) ]; } buf; int len; int i; - buf.value = 0; + /* Avoid returning uninitialised data on error */ + *value = 0; + + /* Fetch raw (network-ordered, variable-length) setting */ len = fetch_setting ( settings, setting, &buf, sizeof ( buf ) ); if ( len < 0 ) return len; if ( len > ( int ) sizeof ( buf ) ) return -ERANGE; + /* Convert to host-ordered signed long */ *value = ( ( buf.s8[0] >= 0 ) ? 0 : -1L ); for ( i = 0 ; i < len ; i++ ) { *value = ( ( *value << 8 ) | buf.u8[i] ); @@ -452,10 +495,15 @@ int fetch_uint_setting ( struct settings *settings, struct setting *setting, long svalue; int len; + /* Avoid returning uninitialised data on error */ + *value = 0; + + /* Fetch as a signed long */ len = fetch_int_setting ( settings, setting, &svalue ); if ( len < 0 ) return len; + /* Mask off sign-extended bits */ *value = ( svalue & ( -1UL >> ( sizeof ( long ) - len ) ) ); return len; @@ -469,7 +517,7 @@ int fetch_uint_setting ( struct settings *settings, struct setting *setting, * @ret value Setting value, or zero */ long fetch_intz_setting ( struct settings *settings, struct setting *setting ){ - long value = 0; + long value; fetch_int_setting ( settings, setting, &value ); return value; @@ -484,7 +532,7 @@ long fetch_intz_setting ( struct settings *settings, struct setting *setting ){ */ unsigned long fetch_uintz_setting ( struct settings *settings, struct setting *setting ) { - unsigned long value = 0; + unsigned long value; fetch_uint_setting ( settings, setting, &value ); return value; @@ -655,6 +703,7 @@ static int parse_setting_name ( const char *name, struct settings **settings, } tmp++; } + setting->tag |= (*settings)->tag_magic; } /* Identify setting type, if specified */ @@ -776,12 +825,15 @@ static int storef_uristring ( struct settings *settings, static int fetchf_uristring ( struct settings *settings, struct setting *setting, char *buf, size_t len ) { - size_t raw_len; + ssize_t raw_len; /* We need to always retrieve the full raw string to know the * length of the encoded string. */ raw_len = fetch_setting ( settings, setting, NULL, 0 ); + if ( raw_len < 0 ) + return raw_len; + { char raw_buf[ raw_len + 1 ]; diff --git a/gpxe/src/core/timer.c b/gpxe/src/core/timer.c index 4e047ea7..d71e3da1 100644 --- a/gpxe/src/core/timer.c +++ b/gpxe/src/core/timer.c @@ -1,7 +1,5 @@ /* - * core/timer.c - * - * Copyright (C) 2007 Alexey Zaytsev <alexey.zaytsev@gmail.com> + * 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 @@ -18,96 +16,25 @@ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ -#include <stddef.h> -#include <assert.h> -#include <gpxe/timer.h> - -static struct timer ts_table[0] - __table_start ( struct timer, timers ); -static struct timer ts_table_end[0] - __table_end ( struct timer, timers ); - -/* - * This function may be used in custom timer driver. - * - * This udelay implementation works well if you've got a - * fast currticks(). - */ -void generic_currticks_udelay ( unsigned int usecs ) { - tick_t start; - tick_t elapsed; - - start = currticks(); - do { - /* xxx: Relax the cpu some way. */ - elapsed = ( currticks() - start ); - } while ( elapsed < usecs ); -} - -/** - * Identify timer source - * - * @ret timer Timer source - */ -static struct timer * timer ( void ) { - static struct timer *ts = NULL; - - /* If we have a timer, use it */ - if ( ts ) - return ts; - - /* Scan for a usable timer */ - for ( ts = ts_table ; ts < ts_table_end ; ts++ ) { - if ( ts->init() == 0 ) - return ts; - } - - /* No timer found; we cannot continue */ - assert ( 0 ); - while ( 1 ) {}; -} - -/** - * Read current time - * - * @ret ticks Current time, in ticks - */ -tick_t currticks ( void ) { - tick_t ct; - - ct = timer()->currticks(); - DBG ( "currticks: %ld.%06ld seconds\n", - ct / USECS_IN_SEC, ct % USECS_IN_SEC ); - - return ct; -} - -/** - * Delay - * - * @v usecs Time to delay, in microseconds - */ -void udelay ( unsigned int usecs ) { - timer()->udelay ( usecs ); -} +#include <unistd.h> /** - * Delay + * Delay for a fixed number of milliseconds * - * @v msecs Time to delay, in milliseconds + * @v msecs Number of milliseconds for which to delay */ -void mdelay ( unsigned int msecs ) { +void mdelay ( unsigned long msecs ) { while ( msecs-- ) - udelay ( USECS_IN_MSEC ); + udelay ( 1000 ); } /** - * Delay + * Delay for a fixed number of seconds * - * @v secs Time to delay, in seconds + * @v secs Number of seconds for which to delay */ unsigned int sleep ( unsigned int secs ) { while ( secs-- ) - mdelay ( MSECS_IN_SEC ); + mdelay ( 1000 ); return 0; } diff --git a/gpxe/src/core/uri.c b/gpxe/src/core/uri.c index cf2b071d..7bb46da0 100644 --- a/gpxe/src/core/uri.c +++ b/gpxe/src/core/uri.c @@ -92,8 +92,12 @@ struct uri * parse_uri ( const char *uri_string ) { uri->fragment = tmp; } - /* Identify absolute/relative URI */ - if ( ( tmp = strchr ( raw, ':' ) ) ) { + /* 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 ) ) ) { /* Absolute URI: identify hierarchical/opaque */ uri->scheme = raw; *(tmp++) = '\0'; diff --git a/gpxe/src/core/uuid.c b/gpxe/src/core/uuid.c index c6e7f5d5..a3a82c68 100644 --- a/gpxe/src/core/uuid.c +++ b/gpxe/src/core/uuid.c @@ -36,7 +36,7 @@ char * uuid_ntoa ( union uuid *uuid ) { static char buf[37]; /* "00000000-0000-0000-0000-000000000000" */ - sprintf ( buf, "%08lx-%04x-%04x-%04x-%02x%02x%02x%02x%02x%02x", + sprintf ( buf, "%08x-%04x-%04x-%04x-%02x%02x%02x%02x%02x%02x", be32_to_cpu ( uuid->canonical.a ), be16_to_cpu ( uuid->canonical.b ), be16_to_cpu ( uuid->canonical.c ), diff --git a/gpxe/src/core/xfer.c b/gpxe/src/core/xfer.c index 14c77d64..9ed19da2 100644 --- a/gpxe/src/core/xfer.c +++ b/gpxe/src/core/xfer.c @@ -28,6 +28,14 @@ */ /** + * Dummy transfer metadata + * + * This gets passed to xfer_interface::deliver_iob() and equivalents + * when no metadata is available. + */ +static struct xfer_metadata dummy_metadata; + +/** * Close data transfer interface * * @v xfer Data transfer interface @@ -159,7 +167,6 @@ int xfer_deliver_iob_meta ( struct xfer_interface *xfer, */ int xfer_deliver_iob ( struct xfer_interface *xfer, struct io_buffer *iobuf ) { - static struct xfer_metadata dummy_metadata; return xfer_deliver_iob_meta ( xfer, iobuf, &dummy_metadata ); } @@ -366,7 +373,7 @@ int xfer_deliver_as_iob ( struct xfer_interface *xfer, return -ENOMEM; memcpy ( iob_put ( iobuf, len ), data, len ); - return xfer->op->deliver_iob ( xfer, iobuf, NULL ); + return xfer->op->deliver_iob ( xfer, iobuf, &dummy_metadata ); } /** diff --git a/gpxe/src/crypto/asn1.c b/gpxe/src/crypto/asn1.c index 0a69162a..25e7495b 100644 --- a/gpxe/src/crypto/asn1.c +++ b/gpxe/src/crypto/asn1.c @@ -32,7 +32,7 @@ * * @v cursor ASN.1 object cursor * @v type Expected type - * @ret len Length of object body, or -1 on error + * @ret len Length of object body, or negative error * * The object cursor will be updated to point to the start of the * object body (i.e. the first byte following the length byte(s)), and @@ -44,29 +44,32 @@ * the cursor will be invalidated and a negative value will be * returned. */ -static int asn1_start_object ( struct asn1_cursor *cursor, +static int asn1_start ( struct asn1_cursor *cursor, unsigned int type ) { unsigned int len_len; unsigned int len; + int rc; /* Sanity check */ if ( cursor->len < 2 /* Tag byte and first length byte */ ) { if ( cursor->len ) DBGC ( cursor, "ASN1 %p too short\n", cursor ); + rc = -EINVAL; goto notfound; } /* Check the tag byte */ - if ( cursor->data[0] != type ) { + if ( *( ( uint8_t * ) cursor->data ) != type ) { DBGC ( cursor, "ASN1 %p type mismatch (expected %d, got %d)\n", - cursor, type, cursor->data[0] ); + cursor, type, *( ( uint8_t * ) cursor->data ) ); + rc = -ENXIO; goto notfound; } cursor->data++; cursor->len--; /* Extract length of the length field and sanity check */ - len_len = cursor->data[0]; + len_len = *( ( uint8_t * ) cursor->data ); if ( len_len & 0x80 ) { len_len = ( len_len & 0x7f ); cursor->data++; @@ -77,19 +80,21 @@ static int asn1_start_object ( struct asn1_cursor *cursor, if ( cursor->len < len_len ) { DBGC ( cursor, "ASN1 %p bad length field length %d (max " "%zd)\n", cursor, len_len, cursor->len ); + rc = -EINVAL; goto notfound; } /* Extract the length and sanity check */ for ( len = 0 ; len_len ; len_len-- ) { len <<= 8; - len |= cursor->data[0]; + len |= *( ( uint8_t * ) cursor->data ); cursor->data++; cursor->len--; } if ( cursor->len < len ) { DBGC ( cursor, "ASN1 %p bad length %d (max %zd)\n", cursor, len, cursor->len ); + rc = -EINVAL; goto notfound; } @@ -98,7 +103,7 @@ static int asn1_start_object ( struct asn1_cursor *cursor, notfound: cursor->data = NULL; cursor->len = 0; - return -1; + return rc; } /** @@ -112,12 +117,12 @@ static int asn1_start_object ( struct asn1_cursor *cursor, * current ASN.1 object. If any error occurs, the object cursor will * be invalidated. */ -int asn1_enter_object ( struct asn1_cursor *cursor, unsigned int type ) { +int asn1_enter ( struct asn1_cursor *cursor, unsigned int type ) { int len; - len = asn1_start_object ( cursor, type ); + len = asn1_start ( cursor, type ); if ( len < 0 ) - return -ENOENT; + return len; cursor->len = len; DBGC ( cursor, "ASN1 %p entered object type %02x (len %x)\n", @@ -137,12 +142,12 @@ int asn1_enter_object ( struct asn1_cursor *cursor, unsigned int type ) { * object. If any error occurs, the object cursor will be * invalidated. */ -int asn1_skip_object ( struct asn1_cursor *cursor, unsigned int type ) { +int asn1_skip ( struct asn1_cursor *cursor, unsigned int type ) { int len; - len = asn1_start_object ( cursor, type ); + len = asn1_start ( cursor, type ); if ( len < 0 ) - return -ENOENT; + return len; cursor->data += len; cursor->len -= len; diff --git a/gpxe/src/crypto/axtls/axtls_asn1.c b/gpxe/src/crypto/axtls/axtls_asn1.c deleted file mode 100644 index 74411c70..00000000 --- a/gpxe/src/crypto/axtls/axtls_asn1.c +++ /dev/null @@ -1,867 +0,0 @@ -/* - * Copyright(C) 2006 Cameron Rich - * - * This library is free software; you can redistribute it and/or modify - * it under the terms of the GNU Lesser General Public License as published by - * the Free Software Foundation; either version 2.1 of the License, or - * (at your option) any later version. - * - * This library 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 Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public License - * along with this library; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ - -/** - * @file asn1.c - * - * Some primitive asn methods for extraction rsa modulus information. It also - * is used for retrieving information from X.509 certificates. - */ - -#include <stdio.h> -#include <stdlib.h> -#include <string.h> -#include <time.h> -#include "crypto.h" - -#define SIG_OID_PREFIX_SIZE 8 - -#define SIG_TYPE_MD2 0x02 -#define SIG_TYPE_MD5 0x04 -#define SIG_TYPE_SHA1 0x05 - -/* Must be an RSA algorithm with either SHA1 or MD5 for verifying to work */ -static const uint8_t sig_oid_prefix[SIG_OID_PREFIX_SIZE] = -{ - 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01 -}; - -/* CN, O, OU */ -static const uint8_t g_dn_types[] = { 3, 10, 11 }; - -static int get_asn1_length(const uint8_t *buf, int *offset) -{ - int len, i; - - if (!(buf[*offset] & 0x80)) /* short form */ - { - len = buf[(*offset)++]; - } - else /* long form */ - { - int length_bytes = buf[(*offset)++]&0x7f; - len = 0; - for (i = 0; i < length_bytes; i++) - { - len <<= 8; - len += buf[(*offset)++]; - } - } - - return len; -} - -/** - * Skip the ASN1.1 object type and its length. Get ready to read the object's - * data. - */ -int asn1_next_obj(const uint8_t *buf, int *offset, int obj_type) -{ - if (buf[*offset] != obj_type) - return X509_NOT_OK; - (*offset)++; - return get_asn1_length(buf, offset); -} - -/** - * Skip over an ASN.1 object type completely. Get ready to read the next - * object. - */ -int asn1_skip_obj(const uint8_t *buf, int *offset, int obj_type) -{ - int len; - - if (buf[*offset] != obj_type) - return X509_NOT_OK; - (*offset)++; - len = get_asn1_length(buf, offset); - *offset += len; - return 0; -} - -/** - * Read an integer value for ASN.1 data - * Note: This function allocates memory which must be freed by the user. - */ -int asn1_get_int(const uint8_t *buf, int *offset, uint8_t **object) -{ - int len; - - if ((len = asn1_next_obj(buf, offset, ASN1_INTEGER)) < 0) - goto end_int_array; - - *object = (uint8_t *)malloc(len); - memcpy(*object, &buf[*offset], len); - *offset += len; - -end_int_array: - return len; -} - -#if 0 - -/** - * Get all the RSA private key specifics from an ASN.1 encoded file - */ -int asn1_get_private_key(const uint8_t *buf, int len, RSA_CTX **rsa_ctx) -{ - int offset = 7; - uint8_t *modulus, *priv_exp, *pub_exp; - int mod_len, priv_len, pub_len; -#ifdef CONFIG_BIGINT_CRT - uint8_t *p, *q, *dP, *dQ, *qInv; - int p_len, q_len, dP_len, dQ_len, qInv_len; -#endif - - /* not in der format */ - if (buf[0] != ASN1_SEQUENCE) /* basic sanity check */ - { -#ifdef CONFIG_SSL_FULL_MODE - printf("Error: This is not a valid ASN.1 file\n"); -#endif - return X509_INVALID_PRIV_KEY; - } - - /* initialise the RNG */ - RNG_initialize(buf, len); - - mod_len = asn1_get_int(buf, &offset, &modulus); - pub_len = asn1_get_int(buf, &offset, &pub_exp); - priv_len = asn1_get_int(buf, &offset, &priv_exp); - - if (mod_len <= 0 || pub_len <= 0 || priv_len <= 0) - return X509_INVALID_PRIV_KEY; - -#ifdef CONFIG_BIGINT_CRT - p_len = asn1_get_int(buf, &offset, &p); - q_len = asn1_get_int(buf, &offset, &q); - dP_len = asn1_get_int(buf, &offset, &dP); - dQ_len = asn1_get_int(buf, &offset, &dQ); - qInv_len = asn1_get_int(buf, &offset, &qInv); - - if (p_len <= 0 || q_len <= 0 || dP_len <= 0 || dQ_len <= 0 || qInv_len <= 0) - return X509_INVALID_PRIV_KEY; - - RSA_priv_key_new(rsa_ctx, - modulus, mod_len, pub_exp, pub_len, priv_exp, priv_len, - p, p_len, q, p_len, dP, dP_len, dQ, dQ_len, qInv, qInv_len); - - free(p); - free(q); - free(dP); - free(dQ); - free(qInv); -#else - RSA_priv_key_new(rsa_ctx, - modulus, mod_len, pub_exp, pub_len, priv_exp, priv_len); -#endif - - free(modulus); - free(priv_exp); - free(pub_exp); - return X509_OK; -} - -/** - * Get the time of a certificate. Ignore hours/minutes/seconds. - */ -static int asn1_get_utc_time(const uint8_t *buf, int *offset, time_t *t) -{ - int ret = X509_NOT_OK, len, t_offset; - struct tm tm; - - if (buf[(*offset)++] != ASN1_UTC_TIME) - goto end_utc_time; - len = get_asn1_length(buf, offset); - t_offset = *offset; - - memset(&tm, 0, sizeof(struct tm)); - tm.tm_year = (buf[t_offset] - '0')*10 + (buf[t_offset+1] - '0'); - - if (tm.tm_year <= 50) /* 1951-2050 thing */ - { - tm.tm_year += 100; - } - - tm.tm_mon = (buf[t_offset+2] - '0')*10 + (buf[t_offset+3] - '0') - 1; - tm.tm_mday = (buf[t_offset+4] - '0')*10 + (buf[t_offset+5] - '0'); - *t = mktime(&tm); - *offset += len; - ret = X509_OK; - -end_utc_time: - return ret; -} - -/** - * Get the version type of a certificate (which we don't actually care about) - */ -static int asn1_version(const uint8_t *cert, int *offset, X509_CTX *x509_ctx) -{ - int ret = X509_NOT_OK; - - (*offset) += 2; /* get past explicit tag */ - if (asn1_skip_obj(cert, offset, ASN1_INTEGER)) - goto end_version; - - ret = X509_OK; -end_version: - return ret; -} - -/** - * Retrieve the notbefore and notafter certificate times. - */ -static int asn1_validity(const uint8_t *cert, int *offset, X509_CTX *x509_ctx) -{ - return (asn1_next_obj(cert, offset, ASN1_SEQUENCE) < 0 || - asn1_get_utc_time(cert, offset, &x509_ctx->not_before) || - asn1_get_utc_time(cert, offset, &x509_ctx->not_after)); -} - -/** - * Get the components of a distinguished name - */ -static int asn1_get_oid_x520(const uint8_t *buf, int *offset) -{ - int dn_type = 0; - int len; - - if ((len = asn1_next_obj(buf, offset, ASN1_OID)) < 0) - goto end_oid; - - /* expect a sequence of 2.5.4.[x] where x is a one of distinguished name - components we are interested in. */ - if (len == 3 && buf[(*offset)++] == 0x55 && buf[(*offset)++] == 0x04) - dn_type = buf[(*offset)++]; - else - { - *offset += len; /* skip over it */ - } - -end_oid: - return dn_type; -} - -/** - * Obtain an ASN.1 printable string type. - */ -static int asn1_get_printable_str(const uint8_t *buf, int *offset, char **str) -{ - int len = X509_NOT_OK; - - /* some certs have this awful crud in them for some reason */ - if (buf[*offset] != ASN1_PRINTABLE_STR && - buf[*offset] != ASN1_TELETEX_STR && buf[*offset] != ASN1_IA5_STR) - goto end_pnt_str; - - (*offset)++; - len = get_asn1_length(buf, offset); - *str = (char *)malloc(len+1); /* allow for null */ - memcpy(*str, &buf[*offset], len); - (*str)[len] = 0; /* null terminate */ - *offset += len; -end_pnt_str: - return len; -} - -/** - * Get the subject name (or the issuer) of a certificate. - */ -static int asn1_name(const uint8_t *cert, int *offset, char *dn[]) -{ - int ret = X509_NOT_OK; - int dn_type; - char *tmp = NULL; - - if (asn1_next_obj(cert, offset, ASN1_SEQUENCE) < 0) - goto end_name; - - while (asn1_next_obj(cert, offset, ASN1_SET) >= 0) - { - int i, found = 0; - - if (asn1_next_obj(cert, offset, ASN1_SEQUENCE) < 0 || - (dn_type = asn1_get_oid_x520(cert, offset)) < 0) - goto end_name; - - if (asn1_get_printable_str(cert, offset, &tmp) < 0) - { - free(tmp); - goto end_name; - } - - /* find the distinguished named type */ - for (i = 0; i < X509_NUM_DN_TYPES; i++) - { - if (dn_type == g_dn_types[i]) - { - if (dn[i] == NULL) - { - dn[i] = tmp; - found = 1; - break; - } - } - } - - if (found == 0) /* not found so get rid of it */ - { - free(tmp); - } - } - - ret = X509_OK; -end_name: - return ret; -} - -/** - * Read the modulus and public exponent of a certificate. - */ -static int asn1_public_key(const uint8_t *cert, int *offset, X509_CTX *x509_ctx) -{ - int ret = X509_NOT_OK, mod_len, pub_len; - uint8_t *modulus, *pub_exp; - - if (asn1_next_obj(cert, offset, ASN1_SEQUENCE) < 0 || - asn1_skip_obj(cert, offset, ASN1_SEQUENCE) || - asn1_next_obj(cert, offset, ASN1_BIT_STRING) < 0) - goto end_pub_key; - - (*offset)++; - - if (asn1_next_obj(cert, offset, ASN1_SEQUENCE) < 0) - goto end_pub_key; - - mod_len = asn1_get_int(cert, offset, &modulus); - pub_len = asn1_get_int(cert, offset, &pub_exp); - - RSA_pub_key_new(&x509_ctx->rsa_ctx, modulus, mod_len, pub_exp, pub_len); - - free(modulus); - free(pub_exp); - ret = X509_OK; - -end_pub_key: - return ret; -} - -#ifdef CONFIG_SSL_CERT_VERIFICATION -/** - * Read the signature of the certificate. - */ -static int asn1_signature(const uint8_t *cert, int *offset, X509_CTX *x509_ctx) -{ - int ret = X509_NOT_OK; - - if (cert[(*offset)++] != ASN1_BIT_STRING) - goto end_sig; - - x509_ctx->sig_len = get_asn1_length(cert, offset); - x509_ctx->signature = (uint8_t *)malloc(x509_ctx->sig_len); - memcpy(x509_ctx->signature, &cert[*offset], x509_ctx->sig_len); - *offset += x509_ctx->sig_len; - ret = X509_OK; - -end_sig: - return ret; -} - -/* - * Compare 2 distinguished name components for equality - * @return 0 if a match - */ -static int asn1_compare_dn_comp(const char *dn1, const char *dn2) -{ - int ret = 1; - - if ((dn1 && dn2 == NULL) || (dn1 == NULL && dn2)) goto err_no_match; - - ret = (dn1 && dn2) ? strcmp(dn1, dn2) : 0; - -err_no_match: - return ret; -} - -/** - * Clean up all of the CA certificates. - */ -void remove_ca_certs(CA_CERT_CTX *ca_cert_ctx) -{ - int i = 0; - - while (i < CONFIG_X509_MAX_CA_CERTS && ca_cert_ctx->cert[i]) - { - x509_free(ca_cert_ctx->cert[i]); - ca_cert_ctx->cert[i++] = NULL; - } - - free(ca_cert_ctx); -} - -/* - * Compare 2 distinguished names for equality - * @return 0 if a match - */ -static int asn1_compare_dn(char * const dn1[], char * const dn2[]) -{ - int i; - - for (i = 0; i < X509_NUM_DN_TYPES; i++) - { - if (asn1_compare_dn_comp(dn1[i], dn2[i])) - { - return 1; - } - } - - return 0; /* all good */ -} - -/** - * Retrieve the signature from a certificate. - */ -const uint8_t *x509_get_signature(const uint8_t *asn1_sig, int *len) -{ - int offset = 0; - const uint8_t *ptr = NULL; - - if (asn1_next_obj(asn1_sig, &offset, ASN1_SEQUENCE) < 0 || - asn1_skip_obj(asn1_sig, &offset, ASN1_SEQUENCE)) - goto end_get_sig; - - if (asn1_sig[offset++] != ASN1_OCTET_STRING) - goto end_get_sig; - *len = get_asn1_length(asn1_sig, &offset); - ptr = &asn1_sig[offset]; /* all ok */ - -end_get_sig: - return ptr; -} - -#endif - -/** - * Read the signature type of the certificate. We only support RSA-MD5 and - * RSA-SHA1 signature types. - */ -static int asn1_signature_type(const uint8_t *cert, - int *offset, X509_CTX *x509_ctx) -{ - int ret = X509_NOT_OK, len; - - if (cert[(*offset)++] != ASN1_OID) - goto end_check_sig; - - len = get_asn1_length(cert, offset); - - if (memcmp(sig_oid_prefix, &cert[*offset], SIG_OID_PREFIX_SIZE)) - goto end_check_sig; /* unrecognised cert type */ - - x509_ctx->sig_type = cert[*offset + SIG_OID_PREFIX_SIZE]; - - *offset += len; - if (asn1_skip_obj(cert, offset, ASN1_NULL)) - goto end_check_sig; - ret = X509_OK; - -end_check_sig: - return ret; -} - -/** - * Construct a new x509 object. - * @return 0 if ok. < 0 if there was a problem. - */ -int x509_new(const uint8_t *cert, int *len, X509_CTX **ctx) -{ - int begin_tbs, end_tbs; - int ret = X509_NOT_OK, offset = 0, cert_size = 0; - X509_CTX *x509_ctx; - BI_CTX *bi_ctx; - - *ctx = (X509_CTX *)calloc(1, sizeof(X509_CTX)); - x509_ctx = *ctx; - - /* get the certificate size */ - asn1_skip_obj(cert, &cert_size, ASN1_SEQUENCE); - - if (asn1_next_obj(cert, &offset, ASN1_SEQUENCE) < 0) - goto end_cert; - - begin_tbs = offset; /* start of the tbs */ - end_tbs = begin_tbs; /* work out the end of the tbs */ - asn1_skip_obj(cert, &end_tbs, ASN1_SEQUENCE); - - if (asn1_next_obj(cert, &offset, ASN1_SEQUENCE) < 0) - goto end_cert; - - if (cert[offset] == ASN1_EXPLICIT_TAG) /* optional version */ - { - if (asn1_version(cert, &offset, x509_ctx)) - goto end_cert; - } - - if (asn1_skip_obj(cert, &offset, ASN1_INTEGER) || /* serial number */ - asn1_next_obj(cert, &offset, ASN1_SEQUENCE) < 0) - goto end_cert; - - /* make sure the signature is ok */ - if (asn1_signature_type(cert, &offset, x509_ctx)) - { - ret = X509_VFY_ERROR_UNSUPPORTED_DIGEST; - goto end_cert; - } - - if (asn1_name(cert, &offset, x509_ctx->ca_cert_dn) || - asn1_validity(cert, &offset, x509_ctx) || - asn1_name(cert, &offset, x509_ctx->cert_dn) || - asn1_public_key(cert, &offset, x509_ctx)) - goto end_cert; - - bi_ctx = x509_ctx->rsa_ctx->bi_ctx; - -#ifdef CONFIG_SSL_CERT_VERIFICATION /* only care if doing verification */ - /* use the appropriate signature algorithm (either SHA1 or MD5) */ - if (x509_ctx->sig_type == SIG_TYPE_MD5) - { - MD5_CTX md5_ctx; - uint8_t md5_dgst[MD5_SIZE]; - MD5Init(&md5_ctx); - MD5Update(&md5_ctx, &cert[begin_tbs], end_tbs-begin_tbs); - MD5Final(&md5_ctx, md5_dgst); - x509_ctx->digest = bi_import(bi_ctx, md5_dgst, MD5_SIZE); - } - else if (x509_ctx->sig_type == SIG_TYPE_SHA1) - { - SHA1_CTX sha_ctx; - uint8_t sha_dgst[SHA1_SIZE]; - SHA1Init(&sha_ctx); - SHA1Update(&sha_ctx, &cert[begin_tbs], end_tbs-begin_tbs); - SHA1Final(&sha_ctx, sha_dgst); - x509_ctx->digest = bi_import(bi_ctx, sha_dgst, SHA1_SIZE); - } - - offset = end_tbs; /* skip the v3 data */ - if (asn1_skip_obj(cert, &offset, ASN1_SEQUENCE) || - asn1_signature(cert, &offset, x509_ctx)) - goto end_cert; -#endif - - if (len) - { - *len = cert_size; - } - - ret = X509_OK; -end_cert: - -#ifdef CONFIG_SSL_FULL_MODE - if (ret) - { - printf("Error: Invalid X509 ASN.1 file\n"); - } -#endif - - return ret; -} - -/** - * Free an X.509 object's resources. - */ -void x509_free(X509_CTX *x509_ctx) -{ - X509_CTX *next; - int i; - - if (x509_ctx == NULL) /* if already null, then don't bother */ - return; - - for (i = 0; i < X509_NUM_DN_TYPES; i++) - { - free(x509_ctx->ca_cert_dn[i]); - free(x509_ctx->cert_dn[i]); - } - - free(x509_ctx->signature); - -#ifdef CONFIG_SSL_CERT_VERIFICATION - if (x509_ctx->digest) - { - bi_free(x509_ctx->rsa_ctx->bi_ctx, x509_ctx->digest); - } -#endif - - RSA_free(x509_ctx->rsa_ctx); - - next = x509_ctx->next; - free(x509_ctx); - x509_free(next); /* clear the chain */ -} - -#ifdef CONFIG_SSL_CERT_VERIFICATION -/** - * Do some basic checks on the certificate chain. - * - * Certificate verification consists of a number of checks: - * - A root certificate exists in the certificate store. - * - The date of the certificate is after the start date. - * - The date of the certificate is before the finish date. - * - The certificate chain is valid. - * - That the certificate(s) are not self-signed. - * - The signature of the certificate is valid. - */ -int x509_verify(const CA_CERT_CTX *ca_cert_ctx, const X509_CTX *cert) -{ - int ret = X509_OK, i = 0; - bigint *cert_sig; - X509_CTX *next_cert = NULL; - BI_CTX *ctx; - bigint *mod, *expn; - struct timeval tv; - int match_ca_cert = 0; - - if (cert == NULL || ca_cert_ctx == NULL) - { - ret = X509_VFY_ERROR_NO_TRUSTED_CERT; - goto end_verify; - } - - /* last cert in the chain - look for a trusted cert */ - if (cert->next == NULL) - { - while (i < CONFIG_X509_MAX_CA_CERTS && ca_cert_ctx->cert[i]) - { - if (asn1_compare_dn(cert->ca_cert_dn, - ca_cert_ctx->cert[i]->cert_dn) == 0) - { - match_ca_cert = 1; - break; - } - - i++; - } - - if (i < CONFIG_X509_MAX_CA_CERTS && ca_cert_ctx->cert[i]) - { - next_cert = ca_cert_ctx->cert[i]; - } - else /* trusted cert not found */ - { - ret = X509_VFY_ERROR_NO_TRUSTED_CERT; - goto end_verify; - } - } - else - { - next_cert = cert->next; - } - - gettimeofday(&tv, NULL); - - /* check the not before date */ - if (tv.tv_sec < cert->not_before) - { - ret = X509_VFY_ERROR_NOT_YET_VALID; - goto end_verify; - } - - /* check the not after date */ - if (tv.tv_sec > cert->not_after) - { - ret = X509_VFY_ERROR_EXPIRED; - goto end_verify; - } - - /* check the chain integrity */ - if (asn1_compare_dn(cert->ca_cert_dn, next_cert->cert_dn)) - { - ret = X509_VFY_ERROR_INVALID_CHAIN; - goto end_verify; - } - - /* check for self-signing */ - if (!match_ca_cert && asn1_compare_dn(cert->ca_cert_dn, cert->cert_dn) == 0) - { - ret = X509_VFY_ERROR_SELF_SIGNED; - goto end_verify; - } - - /* check the signature */ - ctx = cert->rsa_ctx->bi_ctx; - mod = next_cert->rsa_ctx->m; - expn = next_cert->rsa_ctx->e; - cert_sig = RSA_sign_verify(ctx, cert->signature, cert->sig_len, - bi_clone(ctx, mod), bi_clone(ctx, expn)); - - if (cert_sig) - { - ret = cert->digest ? /* check the signature */ - bi_compare(cert_sig, cert->digest) : - X509_VFY_ERROR_UNSUPPORTED_DIGEST; - bi_free(ctx, cert_sig); - - if (ret) - goto end_verify; - } - else - { - ret = X509_VFY_ERROR_BAD_SIGNATURE; - goto end_verify; - } - - /* go down the certificate chain using recursion. */ - if (ret == 0 && cert->next) - { - ret = x509_verify(ca_cert_ctx, next_cert); - } - -end_verify: - return ret; -} -#endif - -#if defined (CONFIG_SSL_FULL_MODE) -/** - * Used for diagnostics. - */ -void x509_print(CA_CERT_CTX *ca_cert_ctx, const X509_CTX *cert) -{ - if (cert == NULL) - return; - - printf("---------------- CERT DEBUG ----------------\n"); - printf("* CA Cert Distinguished Name\n"); - if (cert->ca_cert_dn[X509_COMMON_NAME]) - { - printf("Common Name (CN):\t%s\n", cert->ca_cert_dn[X509_COMMON_NAME]); - } - - if (cert->ca_cert_dn[X509_ORGANIZATION]) - { - printf("Organization (O):\t%s\n", cert->ca_cert_dn[X509_ORGANIZATION]); - } - - if (cert->ca_cert_dn[X509_ORGANIZATIONAL_TYPE]) - { - printf("Organizational Unit (OU): %s\n", - cert->ca_cert_dn[X509_ORGANIZATIONAL_TYPE]); - } - - printf("* Cert Distinguished Name\n"); - if (cert->cert_dn[X509_COMMON_NAME]) - { - printf("Common Name (CN):\t%s\n", cert->cert_dn[X509_COMMON_NAME]); - } - - if (cert->cert_dn[X509_ORGANIZATION]) - { - printf("Organization (O):\t%s\n", cert->cert_dn[X509_ORGANIZATION]); - } - - if (cert->cert_dn[X509_ORGANIZATIONAL_TYPE]) - { - printf("Organizational Unit (OU): %s\n", - cert->cert_dn[X509_ORGANIZATIONAL_TYPE]); - } - - printf("Not Before:\t\t%s", ctime(&cert->not_before)); - printf("Not After:\t\t%s", ctime(&cert->not_after)); - printf("RSA bitsize:\t\t%d\n", cert->rsa_ctx->num_octets*8); - printf("Sig Type:\t\t"); - switch (cert->sig_type) - { - case SIG_TYPE_MD5: - printf("MD5\n"); - break; - case SIG_TYPE_SHA1: - printf("SHA1\n"); - break; - case SIG_TYPE_MD2: - printf("MD2\n"); - break; - default: - printf("Unrecognized: %d\n", cert->sig_type); - break; - } - - printf("Verify:\t\t\t"); - - if (ca_cert_ctx) - { - x509_display_error(x509_verify(ca_cert_ctx, cert)); - } - - printf("\n"); -#if 0 - print_blob("Signature", cert->signature, cert->sig_len); - bi_print("Modulus", cert->rsa_ctx->m); - bi_print("Pub Exp", cert->rsa_ctx->e); -#endif - - if (ca_cert_ctx) - { - x509_print(ca_cert_ctx, cert->next); - } -} - -void x509_display_error(int error) -{ - switch (error) - { - case X509_NOT_OK: - printf("X509 not ok"); - break; - - case X509_VFY_ERROR_NO_TRUSTED_CERT: - printf("No trusted cert is available"); - break; - - case X509_VFY_ERROR_BAD_SIGNATURE: - printf("Bad signature"); - break; - - case X509_VFY_ERROR_NOT_YET_VALID: - printf("Cert is not yet valid"); - break; - - case X509_VFY_ERROR_EXPIRED: - printf("Cert has expired"); - break; - - case X509_VFY_ERROR_SELF_SIGNED: - printf("Cert is self-signed"); - break; - - case X509_VFY_ERROR_INVALID_CHAIN: - printf("Chain is invalid (check order of certs)"); - break; - - case X509_VFY_ERROR_UNSUPPORTED_DIGEST: - printf("Unsupported digest"); - break; - - case X509_INVALID_PRIV_KEY: - printf("Invalid private key"); - break; - } -} -#endif /* CONFIG_SSL_FULL_MODE */ - -#endif diff --git a/gpxe/src/crypto/cryptoLayer.h b/gpxe/src/crypto/cryptoLayer.h deleted file mode 100644 index 28ce97bc..00000000 --- a/gpxe/src/crypto/cryptoLayer.h +++ /dev/null @@ -1,120 +0,0 @@ -#ifndef _MATRIXSSL_CRYPTOLAYER_H -#define _MATRIXSSL_CRYPTOLAYER_H - -/** @file - * - * Compatibility layer for MatrixSSL - * - */ - -#include <stdint.h> -#include <stddef.h> -#include <stdlib.h> -#include <string.h> -#include <ctype.h> -#include <assert.h> -#include <byteswap.h> -#include <gpxe/bitops.h> -#include <gpxe/crypto.h> - -/* Drag in pscrypto.h */ -typedef uint64_t ulong64; -typedef void psPool_t; -#define SMALL_CODE -#define USE_INT64 -#define USE_RSA -#define USE_RSA_PUBLIC_ENCRYPT -#define CRYPT -#include "matrixssl/pscrypto.h" -#define SMALL_CODE -#undef CLEAN_STACK - -#define sslAssert( ... ) assert ( __VA_ARGS__ ) - -static inline __attribute__ (( always_inline )) void * __malloc -psMalloc ( psPool_t *pool __unused, size_t len ) { - return malloc ( len ); -} - -static inline __attribute__ (( always_inline )) void * -psRealloc ( void *ptr, size_t len ) { - return realloc ( ptr, len ); -} - -static inline __attribute__ (( always_inline )) void psFree ( void *ptr ) { - free ( ptr ); -} - -#define matrixStrDebugMsg( ... ) DBG ( __VA_ARGS__ ) -#define matrixIntDebugMsg( ... ) DBG ( __VA_ARGS__ ) - -/* Use our standard cpu_to_leXX etc. macros */ - -#undef LOAD32L -#define LOAD32L( cpu32, ptr ) do { \ - uint32_t *le32 = ( ( uint32_t * ) ptr ); \ - cpu32 = le32_to_cpu ( *le32 ); \ - } while ( 0 ) - -#undef LOAD32H -#define LOAD32H( cpu32, ptr ) do { \ - uint32_t *be32 = ( ( uint32_t * ) ptr ); \ - cpu32 = be32_to_cpu ( *be32 ); \ - } while ( 0 ) - -#undef LOAD64L -#define LOAD64L( cpu64, ptr ) do { \ - uint64_t *le64 = ( ( uint64_t * ) ptr ); \ - cpu64 = le64_to_cpu ( *le64 ); \ - } while ( 0 ) - -#undef LOAD64H -#define LOAD64H( cpu64, ptr ) do { \ - uint64_t *be64 = ( ( uint64_t * ) ptr ); \ - cpu64 = be64_to_cpu ( *be64 ); \ - } while ( 0 ) - -#undef STORE32L -#define STORE32L( cpu32, ptr ) do { \ - uint32_t *le32 = ( ( uint32_t * ) ptr ); \ - *le32 = cpu_to_le32 ( cpu32 ); \ - } while ( 0 ) - -#undef STORE32H -#define STORE32H( cpu32, ptr ) do { \ - uint32_t *be32 = ( ( uint32_t * ) ptr ); \ - *be32 = cpu_to_be32 ( cpu32 ); \ - } while ( 0 ) - -#undef STORE64L -#define STORE64L( cpu64, ptr ) do { \ - uint64_t *le64 = ( ( uint64_t * ) ptr ); \ - *le64 = cpu_to_le64 ( cpu64 ); \ - } while ( 0 ) - -#undef STORE64H -#define STORE64H( cpu64, ptr ) do { \ - uint64_t *be64 = ( ( uint64_t * ) ptr ); \ - *be64 = cpu_to_be64 ( cpu64 ); \ - } while ( 0 ) - -/* Use rolXX etc. from bitops.h */ - -#undef ROL -#define ROL( data, rotation ) rol32 ( (data), (rotation) ) -#undef ROLc -#define ROLc( data, rotation ) rol32 ( (data), (rotation) ) -#undef ROR -#define ROR( data, rotation ) ror32 ( (data), (rotation) ) -#undef RORc -#define RORc( data, rotation ) ror32 ( (data), (rotation) ) -#undef ROL64 -#define ROL64( data, rotation ) rol64 ( (data), (rotation) ) -#undef ROL64c -#define ROL64c( data, rotation ) rol64 ( (data), (rotation) ) -#undef ROR64 -#define ROR64( data, rotation ) ror64 ( (data), (rotation) ) -#undef ROR64c -#define ROR64c( data, rotation ) ror64 ( (data), (rotation) ) - -#endif /* _MATRIXSSL_CRYPTOLAYER_H */ diff --git a/gpxe/src/crypto/framework.c b/gpxe/src/crypto/framework.c deleted file mode 100644 index 0da2cbe3..00000000 --- a/gpxe/src/crypto/framework.c +++ /dev/null @@ -1,86 +0,0 @@ -/* mcb - this file breaks the build process; temporarily deactivating */ -#if 0 - -#include <stdlib.h> -#include <sys/types.h> -#include <sys/socket.h> -#include <netinet/in.h> -#include <netdb.h> -#include "ssl.h" - -int main(int argc, char *argv[]) -{ - SSL_t ssl; - int sockfd, portno, rc; - struct sockaddr_in serv_addr; - struct hostent *server; - - portno = 443; - sockfd = socket(AF_INET,SOCK_STREAM,0); - if(sockfd<0){ - fprintf(stderr,"Error creating socket\n"); - exit(sockfd); - } - - server = gethostbyname(argv[1]); - if(server==NULL){ - fprintf(stderr,"Error looking up host %s\n",argv[1]); - exit(1); - } - - /** - *matrixSslOpen() - *matrixSslReadKeys() - **/ - printf("Calling CreateSSLHello()\n"); - rc = CreateSSLHello(&ssl); - printf("Finished calling CreateSSLHello()\n"); - - bzero((char *) &serv_addr, sizeof(serv_addr)); - serv_addr.sin_family = AF_INET; - bcopy((char *)server->h_addr,(char *)&serv_addr.sin_addr.s_addr,server->h_length); - serv_addr.sin_port = htons(portno); - if(connect(sockfd,(struct sockaddr *) &serv_addr, sizeof(serv_addr)) < 0){ - fprintf(stderr,"ERROR connecting to server\n"); - exit(1); - } - - PrintSSLPacket(&ssl); - - printf("Write ssl.buffer\n"); - write(sockfd,ssl.buffer,ssl.length); - printf("Finished writing\n"); - ssl.length = read(sockfd,ssl.buffer,ssl.max_size); - ReadSSLHello(&ssl); - - /** - *matrixSslNewSession() - *matrixSslSetCetValidator() - *encodeSslHandshake() - - *write handshake buffer - - *readSslResponse() <-+ - | - *read return code |-- similar/same function?? - | - *sslEncode() | - *sslDecode() <-------+ - - *encodeSslCloseAlert() - - *write close alert buffer - **/ - close(sockfd); - - /** - *sslClose() - * -free connection - * -free keys - * -close pki interface - **/ - - return 0; -} - -#endif diff --git a/gpxe/src/crypto/matrixssl/mpi.h b/gpxe/src/crypto/matrixssl/mpi.h deleted file mode 100644 index bb2c9c57..00000000 --- a/gpxe/src/crypto/matrixssl/mpi.h +++ /dev/null @@ -1,487 +0,0 @@ -/*
- * mpi.h
- * Release $Name$
- *
- * multiple-precision integer library
- */
-/*
- * Copyright (c) PeerSec Networks, 2002-2006. All Rights Reserved.
- * The latest version of this code is available at http://www.matrixssl.org
- *
- * This software is open source; 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 General Public License does NOT permit incorporating this software
- * into proprietary programs. If you are unable to comply with the GPL, a
- * commercial license for this software may be purchased from PeerSec Networks
- * at http://www.peersec.com
- *
- * This program is distributed in 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
- * http://www.gnu.org/copyleft/gpl.html
- */
-/******************************************************************************/
-
-#ifndef _h_MPI
-#define _h_MPI
-
-#include <stdio.h>
-#include <string.h>
-#include <stdlib.h>
-#include <ctype.h>
-#include <limits.h>
-
-#undef MIN
-#define MIN(x,y) ((x)<(y)?(x):(y))
-#undef MAX
-#define MAX(x,y) ((x)>(y)?(x):(y))
-
-#ifdef __cplusplus
-extern "C" {
-
-
-/*
- C++ compilers don't like assigning void * to mp_digit *
- */
-#define OPT_CAST(x) (x *)
-
-#else
-
-/*
- C on the other hand doesn't care
- */
-#define OPT_CAST(x)
-
-#endif /* __cplusplus */
-
-/******************************************************************************/
-/*
- some default configurations.
-
- A "mp_digit" must be able to hold DIGIT_BIT + 1 bits
- A "mp_word" must be able to hold 2*DIGIT_BIT + 1 bits
-
- At the very least a mp_digit must be able to hold 7 bits
- [any size beyond that is ok provided it doesn't overflow the data type]
- */
-#ifdef MP_8BIT
- typedef unsigned char mp_digit;
- typedef unsigned short mp_word;
-#elif defined(MP_16BIT)
- typedef unsigned short mp_digit;
- typedef unsigned long mp_word;
-#elif defined(MP_64BIT)
-/*
- for GCC only on supported platforms
- */
- #ifndef CRYPT
- typedef unsigned long long ulong64;
- typedef signed long long long64;
- #endif /* CRYPT */
-
- typedef ulong64 mp_digit;
- typedef unsigned long mp_word __attribute__ ((mode(TI)));
-
- #define DIGIT_BIT 60
-#else /* MP_8BIT */
-/*
- this is the default case, 28-bit digits
- */
- #ifndef CRYPT
- #if defined(_MSC_VER) || defined(__BORLANDC__)
- typedef unsigned __int64 ulong64;
- typedef signed __int64 long64;
- #else
- typedef unsigned long long ulong64;
- typedef signed long long long64;
- #endif
- #endif /* CRYPT */
-
- typedef unsigned long mp_digit;
- typedef ulong64 mp_word;
-
- #ifdef MP_31BIT
-/*
- this is an extension that uses 31-bit digits
- */
- #define DIGIT_BIT 31
- #else /* MP_31BIT */
-/*
- default case is 28-bit digits, defines MP_28BIT as a handy macro to test
- */
- #define DIGIT_BIT 28
- #define MP_28BIT
- #endif /* MP_31BIT */
-#endif /* MP_8BIT */
-
-/*
- otherwise the bits per digit is calculated automatically from the size of
- a mp_digit
- */
-#ifndef DIGIT_BIT
- #define DIGIT_BIT ((int32)((CHAR_BIT * sizeof(mp_digit) - 1))) /* bits per digit */
-#endif /* DIGIT_BIT */
-
-#define MP_DIGIT_BIT DIGIT_BIT
-#define MP_MASK ((((mp_digit)1)<<((mp_digit)DIGIT_BIT))-((mp_digit)1))
-#define MP_DIGIT_MAX MP_MASK
-
-/******************************************************************************/
-/*
- equalities
- */
-#define MP_LT -1 /* less than */
-#define MP_EQ 0 /* equal to */
-#define MP_GT 1 /* greater than */
-
-#define MP_ZPOS 0 /* positive integer */
-#define MP_NEG 1 /* negative */
-
-#define MP_OKAY 0 /* ok result */
-#define MP_MEM -2 /* out of mem */
-#define MP_VAL -3 /* invalid input */
-#define MP_RANGE MP_VAL
-
-#define MP_YES 1 /* yes response */
-#define MP_NO 0 /* no response */
-
-typedef int32 mp_err;
-
-/******************************************************************************/
-/*
- various build options
- */
-#define MP_PREC 64 /* default digits of precision */
-
-/*
- define this to use lower memory usage routines (exptmods mostly)
- */
-#define MP_LOW_MEM
-
-/*
- size of comba arrays, should be at least
- 2 * 2**(BITS_PER_WORD - BITS_PER_DIGIT*2)
- */
-#define MP_WARRAY (1 << (sizeof(mp_word) * CHAR_BIT - 2 * DIGIT_BIT + 1))
-
-typedef struct {
- int32 used, alloc, sign;
- mp_digit *dp;
-} mp_int;
-
-#define USED(m) ((m)->used)
-#define DIGIT(m,k) ((m)->dp[(k)])
-#define SIGN(m) ((m)->sign)
-
-/******************************************************************************/
-/*
- init and deinit bignum functions
- */
-
-/*
- init a bignum
- */
-extern int32 mp_init(psPool_t *pool, mp_int *a);
-
-/*
- free a bignum
- */
-extern void mp_clear(mp_int *a);
-
-/*
- init a series of arguments
- */
-extern int32 _mp_init_multi(psPool_t *pool, mp_int *mp0, mp_int *mp1, mp_int *mp2,
- mp_int *mp3, mp_int *mp4, mp_int *mp5, mp_int *mp6,
- mp_int *mp7);
-
-/*
- clear a series of arguments
- */
-extern void _mp_clear_multi(mp_int *mp0, mp_int *mp1, mp_int *mp2, mp_int *mp3,
- mp_int *mp4, mp_int *mp5, mp_int *mp6, mp_int *mp7);
-
-/*
- exchange two ints
- */
-extern void mp_exch(mp_int *a, mp_int *b);
-
-/*
- shrink ram required for a bignum
- */
-extern int32 mp_shrink(mp_int *a);
-
-/*
- grow an int32 to a given size
- */
-extern int32 mp_grow(mp_int *a, int32 size);
-
-/*
- init to a given number of digits
- */
-extern int32 mp_init_size(psPool_t *pool, mp_int *a, int32 size);
-
-/******************************************************************************/
-/*
- Basic Manipulations
- */
-#define mp_iszero(a) (((a)->used == 0) ? MP_YES : MP_NO)
-#define mp_iseven(a) (((a)->used > 0 && (((a)->dp[0] & 1) == 0)) ? MP_YES : MP_NO)
-#define mp_isodd(a) (((a)->used > 0 && (((a)->dp[0] & 1) == 1)) ? MP_YES : MP_NO)
-
-extern int32 mp_add_d (mp_int * a, mp_digit b, mp_int * c);
-extern int32 mp_sub_d (mp_int * a, mp_digit b, mp_int * c);
-/*
- set to zero
- */
-extern void mp_zero(mp_int *a);
-
-/*
- set to a digit
- */
-extern void mp_set(mp_int *a, mp_digit b);
-
-/*
- copy, b = a
- */
-extern int32 mp_copy(mp_int *a, mp_int *b);
-
-/*
- inits and copies, a = b
- */
-extern int32 mp_init_copy(psPool_t *pool, mp_int *a, mp_int *b);
-
-/*
- trim unused digits
- */
-extern void mp_clamp(mp_int *a);
-
-/******************************************************************************/
-/*
- digit manipulation
-*/
-
-/*
- right shift by "b" digits
- */
-extern void mp_rshd(mp_int *a, int32 b);
-
-/*
- left shift by "b" digits
- */
-extern int32 mp_lshd(mp_int *a, int32 b);
-
-/*
- c = a / 2**b
- */
-extern int32 mp_div_2d(psPool_t *pool, mp_int *a, int32 b, mp_int *c, mp_int *d);
-
-/*
- b = a/2
- */
-extern int32 mp_div_2(mp_int *a, mp_int *b);
-
-/*
- c = a * 2**b
- */
-extern int32 mp_mul_2d(mp_int *a, int32 b, mp_int *c);
-
-/*
- c = a mod 2**d
- */
-extern int32 mp_mod_2d(mp_int *a, int32 b, mp_int *c);
-
-/*
- computes a = 2**b
- */
-extern int32 mp_2expt(mp_int *a, int32 b);
-
-/******************************************************************************/
-/*
- Basic arithmetic
- */
-
-/*
- b = |a|
- */
-extern int32 mp_abs(mp_int *a, mp_int *b);
-
-/*
- compare a to b
- */
-extern int32 mp_cmp(mp_int *a, mp_int *b);
-
-/*
- compare |a| to |b|
- */
-extern int32 mp_cmp_mag(mp_int *a, mp_int *b);
-
-/*
- c = a + b
- */
-extern int32 mp_add(mp_int *a, mp_int *b, mp_int *c);
-
-/*
- c = a - b
- */
-extern int32 mp_sub(mp_int *a, mp_int *b, mp_int *c);
-
-/*
- c = a * b
- b = a*a
- */
-/* STEVE - moved mp_mul out of SLOW case */
-extern int32 mp_mul(psPool_t *pool, mp_int *a, mp_int *b, mp_int *c);
-#ifdef USE_SMALL_WORD
-extern int32 mp_sqr(psPool_t *pool, mp_int *a, mp_int *b);
-#endif
-
-/*
- a/b => cb + d == a
- */
-extern int32 mp_div(psPool_t *pool, mp_int *a, mp_int *b, mp_int *c, mp_int *d);
-
-/*
- c = a mod b, 0 <= c < b
- */
-extern int32 mp_mod(psPool_t *pool, mp_int *a, mp_int *b, mp_int *c);
-
-/******************************************************************************/
-/*
- single digit functions
- */
-
-/*
- compare against a single digit
- */
-extern int32 mp_cmp_d(mp_int *a, mp_digit b);
-
-/*
- c = a * b
- */
-extern int32 mp_mul_d(mp_int *a, mp_digit b, mp_int *c);
-
-/******************************************************************************/
-/*
- number theory
- */
-
-/*
- d = a + b (mod c)
- */
-extern int32 mp_addmod(psPool_t *pool, mp_int *a, mp_int *b, mp_int *c, mp_int *d);
-
-/*
- d = a * b (mod c)
- */
-extern int32 mp_mulmod(psPool_t *pool, mp_int *a, mp_int *b, mp_int *c, mp_int *d);
-
-/*
- c = 1/a (mod b)
- */
-#ifdef USE_SMALL_WORD
-extern int32 mp_invmod(psPool_t *pool, mp_int *a, mp_int *b, mp_int *c);
-#endif
-
-/*
- setups the montgomery reduction
- */
-extern int32 mp_montgomery_setup(mp_int *a, mp_digit *mp);
-
-/*
- computes a = B**n mod b without division or multiplication useful for
- normalizing numbers in a Montgomery system.
- */
-extern int32 mp_montgomery_calc_normalization(mp_int *a, mp_int *b);
-
-/*
- computes x/R == x (mod N) via Montgomery Reduction
- */
-#ifdef USE_SMALL_WORD
-extern int32 mp_montgomery_reduce(mp_int *a, mp_int *m, mp_digit mp);
-#endif
-
-/*
- d = a**b (mod c)
- */
-/* TODO - we never define this */
-extern int32 mp_exptmod(psPool_t *pool, mp_int *a, mp_int *b, mp_int *c, mp_int *d);
-
-/******************************************************************************/
-/*
- If we're using 1024 or 2048 bit keys and 28 bit digits, we only need the
- fast_ versions of these functions, removing the others to save space.
- Otherwise, we include the slow versions as well and which version to use
- is done at runtime.
-*/
-#ifdef USE_SMALL_WORD
-extern int32 s_mp_mul_digs(psPool_t *pool, mp_int *a, mp_int *b, mp_int *c,
- int32 digs);
-extern int32 s_mp_sqr(psPool_t *pool, mp_int *a, mp_int *b);
-#else
-#define mp_montgomery_reduce fast_mp_montgomery_reduce
-#define mp_sqr fast_s_mp_sqr
-#if STEVE
-#define mp_mul(P, A, B, C) fast_s_mp_mul_digs(P, A, B, C, (A)->used + (B)->used + 1)
-#endif
-#define s_mp_mul_digs fast_s_mp_mul_digs
-#define mp_invmod fast_mp_invmod
-#endif
-
-/******************************************************************************/
-/*
- radix conversion
- */
-extern int32 mp_count_bits(mp_int *a);
-
-extern int32 mp_unsigned_bin_size(mp_int *a);
-extern int32 mp_read_unsigned_bin(mp_int *a, unsigned char *b, int32 c);
-extern int32 mp_to_unsigned_bin(psPool_t *pool, mp_int *a, unsigned char *b);
-
-extern int32 mp_signed_bin_size(mp_int *a);
-
-/*
- lowlevel functions, do not call!
- */
-#if STEVE
-#ifdef USE_SMALL_WORD
-#define s_mp_mul(P, A, B, C) s_mp_mul_digs(P, A, B, C, (A)->used + (B)->used + 1)
-#else
-#define s_mp_mul(P, A, B, C) sslAssert();
-#endif
-#endif /* STEVE */
-/* define this in all cases for now STEVE */
-#define s_mp_mul(P, A, B, C) s_mp_mul_digs(P, A, B, C, (A)->used + (B)->used + 1)
-
-
-/*
- b = a*2
- */
-extern int32 mp_mul_2(mp_int *a, mp_int *b);
-
-extern int32 s_mp_add(mp_int *a, mp_int *b, mp_int *c);
-extern int32 s_mp_sub(mp_int *a, mp_int *b, mp_int *c);
-
-extern int32 fast_s_mp_mul_digs(psPool_t *pool, mp_int *a, mp_int *b, mp_int *c,
- int32 digs);
-extern int32 fast_s_mp_sqr(psPool_t *pool, mp_int *a, mp_int *b);
-
-extern int32 fast_mp_invmod(psPool_t *pool, mp_int *a, mp_int *b, mp_int *c);
-extern int32 fast_mp_montgomery_reduce(mp_int *a, mp_int *m, mp_digit mp);
-
-extern void bn_reverse(unsigned char *s, int32 len);
-
-
-#ifdef __cplusplus
- }
-#endif /* __cplusplus */
-
-#endif /* _h_MPI */
-
diff --git a/gpxe/src/crypto/matrixssl/pscrypto.h b/gpxe/src/crypto/matrixssl/pscrypto.h deleted file mode 100644 index 4d684327..00000000 --- a/gpxe/src/crypto/matrixssl/pscrypto.h +++ /dev/null @@ -1,661 +0,0 @@ -/*
- * pscrypto.h
- * Release $Name$
- *
- * Internal definitions for PeerSec Networks MatrixSSL cryptography provider
- */
-/*
- * Copyright (c) PeerSec Networks, 2002-2006. All Rights Reserved.
- * The latest version of this code is available at http://www.matrixssl.org
- *
- * This software is open source; 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 General Public License does NOT permit incorporating this software
- * into proprietary programs. If you are unable to comply with the GPL, a
- * commercial license for this software may be purchased from PeerSec Networks
- * at http://www.peersec.com
- *
- * This program is distributed in 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
- * http://www.gnu.org/copyleft/gpl.html
- */
-/******************************************************************************/
-
-#ifndef _h_PSCRYPTO
-#define _h_PSCRYPTO
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-/*
- PeerSec crypto-specific defines.
- */
-#define SMALL_CODE
-#define CLEAN_STACK
-/*
- If Native 64 bit integers are not supported, we must set the 16 bit flag
- to produce 32 bit mp_words in mpi.h
- We must also include the slow MPI functions because the fast ones only
- work with larger (28 bit) digit sizes.
-*/
-#ifndef USE_INT64
-#define MP_16BIT
-#define USE_SMALL_WORD
-#endif /* USE_INT64 */
-
-/******************************************************************************/
-
-#ifdef USE_RSA
-
-#include "mpi.h"
-
-#if LINUX
- #define _stat stat
-#endif
-
-/* this is the "32-bit at least" data type
- * Re-define it to suit your platform but it must be at least 32-bits
- */
-typedef unsigned long ulong32;
-
-/*
- Primary RSA Key struct. Define here for crypto
-*/
-typedef struct {
- mp_int e, d, N, qP, dP, dQ, p, q;
- int32 size; /* Size of the key in bytes */
- int32 optimized; /* 1 for optimized */
-} sslRsaKey_t;
-
-#endif /* USE_RSA */
-
-
-/*
- * Private
- */
-extern int32 ps_base64_decode(const unsigned char *in, uint32 len,
- unsigned char *out, uint32 *outlen);
-
-/*
- * Memory routines
- */
-extern void psZeromem(void *dst, size_t len);
-extern void psBurnStack(unsigned long len);
-
-
-/* max size of either a cipher/hash block or symmetric key [largest of the two] */
-#define MAXBLOCKSIZE 24
-
-/* ch1-01-1 */
-/* error codes [will be expanded in future releases] */
-enum {
- CRYPT_OK=0, /* Result OK */
- CRYPT_ERROR, /* Generic Error */
- CRYPT_NOP, /* Not a failure but no operation was performed */
-
- CRYPT_INVALID_KEYSIZE, /* Invalid key size given */
- CRYPT_INVALID_ROUNDS, /* Invalid number of rounds */
- CRYPT_FAIL_TESTVECTOR, /* Algorithm failed test vectors */
-
- CRYPT_BUFFER_OVERFLOW, /* Not enough space for output */
- CRYPT_INVALID_PACKET, /* Invalid input packet given */
-
- CRYPT_INVALID_PRNGSIZE, /* Invalid number of bits for a PRNG */
- CRYPT_ERROR_READPRNG, /* Could not read enough from PRNG */
-
- CRYPT_INVALID_CIPHER, /* Invalid cipher specified */
- CRYPT_INVALID_HASH, /* Invalid hash specified */
- CRYPT_INVALID_PRNG, /* Invalid PRNG specified */
-
- CRYPT_MEM, /* Out of memory */
-
- CRYPT_PK_TYPE_MISMATCH, /* Not equivalent types of PK keys */
- CRYPT_PK_NOT_PRIVATE, /* Requires a private PK key */
-
- CRYPT_INVALID_ARG, /* Generic invalid argument */
- CRYPT_FILE_NOTFOUND, /* File Not Found */
-
- CRYPT_PK_INVALID_TYPE, /* Invalid type of PK key */
- CRYPT_PK_INVALID_SYSTEM, /* Invalid PK system specified */
- CRYPT_PK_DUP, /* Duplicate key already in key ring */
- CRYPT_PK_NOT_FOUND, /* Key not found in keyring */
- CRYPT_PK_INVALID_SIZE, /* Invalid size input for PK parameters */
-
- CRYPT_INVALID_PRIME_SIZE /* Invalid size of prime requested */
-};
-
-/******************************************************************************/
-/*
- hash defines
- */
-struct sha1_state {
-#ifdef USE_INT64
- ulong64 length;
-#else
- ulong32 lengthHi;
- ulong32 lengthLo;
-#endif /* USE_INT64 */
- ulong32 state[5], curlen;
- unsigned char buf[64];
-};
-
-struct md5_state {
-#ifdef USE_INT64
- ulong64 length;
-#else
- ulong32 lengthHi;
- ulong32 lengthLo;
-#endif /* USE_INT64 */
- ulong32 state[4], curlen;
- unsigned char buf[64];
-};
-
-#ifdef USE_MD2
-struct md2_state {
- unsigned char chksum[16], X[48], buf[16];
- unsigned long curlen;
-};
-#endif /* USE_MD2 */
-
-#ifdef USE_SHA256
-struct sha256_state {
- ulong64 length;
- ulong32 state[8], curlen;
- unsigned char buf[64];
-};
-#endif /* USE_SHA256 */
-
-typedef union {
- struct sha1_state sha1;
- struct md5_state md5;
-#ifdef USE_MD2
- struct md2_state md2;
-#endif /* USE_MD2 */
-#ifdef USE_SHA256
- struct sha256_state sha256;
-#endif
-} hash_state;
-
-typedef hash_state sslSha1Context_t;
-typedef hash_state sslMd5Context_t;
-#ifdef USE_MD2
-typedef hash_state sslMd2Context_t;
-#endif /* USE_MD2 */
-#ifdef USE_SHA256
-typedef hash_state sslSha256Context_t;
-#endif /* USE_SHA256 */
-
-typedef struct {
- unsigned char pad[64];
- union {
- sslMd5Context_t md5;
- sslSha1Context_t sha1;
- } u;
-} sslHmacContext_t;
-
-/******************************************************************************/
-/*
- RC4
- */
-#ifdef USE_ARC4
-typedef struct {
- unsigned char state[256];
- uint32 byteCount;
- unsigned char x;
- unsigned char y;
-} rc4_key;
-#endif /* USE_ARC4 */
-
-#define SSL_DES3_KEY_LEN 24
-#define SSL_DES3_IV_LEN 8
-#ifdef USE_3DES
-
-typedef struct {
- ulong32 ek[3][32], dk[3][32];
-} des3_key;
-
-/*
- A block cipher CBC structure
- */
-typedef struct {
- int32 blocklen;
- unsigned char IV[8];
- des3_key key;
- int32 explicitIV; /* 1 if yes */
-} des3_CBC;
-
-extern int32 des3_setup(const unsigned char *key, int32 keylen, int32 num_rounds,
- des3_CBC *skey);
-extern void des3_ecb_encrypt(const unsigned char *pt, unsigned char *ct,
- des3_CBC *key);
-extern void des3_ecb_decrypt(const unsigned char *ct, unsigned char *pt,
- des3_CBC *key);
-extern int32 des3_keysize(int32 *desired_keysize);
-
-extern int32 des_setup(const unsigned char *key, int32 keylen, int32 num_rounds,
- des3_CBC *skey);
-extern void des_ecb_encrypt(const unsigned char *pt, unsigned char *ct,
- des3_CBC *key);
-extern void des_ecb_decrypt(const unsigned char *ct, unsigned char *pt,
- des3_CBC *key);
-
-#endif /* USE_3DES */
-
-
-typedef union {
-#ifdef USE_ARC4
- rc4_key arc4;
-#endif
-#ifdef USE_3DES
- des3_CBC des3;
-#endif
-} sslCipherContext_t;
-
-
-/*
- Controls endianess and size of registers. Leave uncommented to get
- platform neutral [slower] code detect x86-32 machines somewhat
- */
-#if (defined(_MSC_VER) && defined(WIN32)) || (defined(__GNUC__) && (defined(__DJGPP__) || defined(__CYGWIN__) || defined(__MINGW32__) || defined(__i386__)))
- #define ENDIAN_LITTLE
- #define ENDIAN_32BITWORD
-#endif
-
-
-/* #define ENDIAN_LITTLE */
-/* #define ENDIAN_BIG */
-
-/* #define ENDIAN_32BITWORD */
-/* #define ENDIAN_64BITWORD */
-
-#if (defined(ENDIAN_BIG) || defined(ENDIAN_LITTLE)) && !(defined(ENDIAN_32BITWORD) || defined(ENDIAN_64BITWORD))
- #error You must specify a word size as well as endianess
-#endif
-
-#if !(defined(ENDIAN_BIG) || defined(ENDIAN_LITTLE))
- #define ENDIAN_NEUTRAL
-#endif
-
-/*
- helper macros
- */
-#if defined (ENDIAN_NEUTRAL)
-
-#define STORE32L(x, y) \
- { (y)[3] = (unsigned char)(((x)>>24)&255); (y)[2] = (unsigned char)(((x)>>16)&255); \
- (y)[1] = (unsigned char)(((x)>>8)&255); (y)[0] = (unsigned char)((x)&255); }
-
-#define LOAD32L(x, y) \
- { x = ((unsigned long)((y)[3] & 255)<<24) | \
- ((unsigned long)((y)[2] & 255)<<16) | \
- ((unsigned long)((y)[1] & 255)<<8) | \
- ((unsigned long)((y)[0] & 255)); }
-
-#define STORE64L(x, y) \
- { (y)[7] = (unsigned char)(((x)>>56)&255); (y)[6] = (unsigned char)(((x)>>48)&255); \
- (y)[5] = (unsigned char)(((x)>>40)&255); (y)[4] = (unsigned char)(((x)>>32)&255); \
- (y)[3] = (unsigned char)(((x)>>24)&255); (y)[2] = (unsigned char)(((x)>>16)&255); \
- (y)[1] = (unsigned char)(((x)>>8)&255); (y)[0] = (unsigned char)((x)&255); }
-
-#define LOAD64L(x, y) \
- { x = (((ulong64)((y)[7] & 255))<<56)|(((ulong64)((y)[6] & 255))<<48)| \
- (((ulong64)((y)[5] & 255))<<40)|(((ulong64)((y)[4] & 255))<<32)| \
- (((ulong64)((y)[3] & 255))<<24)|(((ulong64)((y)[2] & 255))<<16)| \
- (((ulong64)((y)[1] & 255))<<8)|(((ulong64)((y)[0] & 255))); }
-
-#define STORE32H(x, y) \
- { (y)[0] = (unsigned char)(((x)>>24)&255); (y)[1] = (unsigned char)(((x)>>16)&255); \
- (y)[2] = (unsigned char)(((x)>>8)&255); (y)[3] = (unsigned char)((x)&255); }
-
-#define LOAD32H(x, y) \
- { x = ((unsigned long)((y)[0] & 255)<<24) | \
- ((unsigned long)((y)[1] & 255)<<16) | \
- ((unsigned long)((y)[2] & 255)<<8) | \
- ((unsigned long)((y)[3] & 255)); }
-
-#define STORE64H(x, y) \
- { (y)[0] = (unsigned char)(((x)>>56)&255); (y)[1] = (unsigned char)(((x)>>48)&255); \
- (y)[2] = (unsigned char)(((x)>>40)&255); (y)[3] = (unsigned char)(((x)>>32)&255); \
- (y)[4] = (unsigned char)(((x)>>24)&255); (y)[5] = (unsigned char)(((x)>>16)&255); \
- (y)[6] = (unsigned char)(((x)>>8)&255); (y)[7] = (unsigned char)((x)&255); }
-
-#define LOAD64H(x, y) \
- { x = (((ulong64)((y)[0] & 255))<<56)|(((ulong64)((y)[1] & 255))<<48) | \
- (((ulong64)((y)[2] & 255))<<40)|(((ulong64)((y)[3] & 255))<<32) | \
- (((ulong64)((y)[4] & 255))<<24)|(((ulong64)((y)[5] & 255))<<16) | \
- (((ulong64)((y)[6] & 255))<<8)|(((ulong64)((y)[7] & 255))); }
-
-#endif /* ENDIAN_NEUTRAL */
-
-#ifdef ENDIAN_LITTLE
-
-#define STORE32H(x, y) \
- { (y)[0] = (unsigned char)(((x)>>24)&255); (y)[1] = (unsigned char)(((x)>>16)&255); \
- (y)[2] = (unsigned char)(((x)>>8)&255); (y)[3] = (unsigned char)((x)&255); }
-
-#define LOAD32H(x, y) \
- { x = ((unsigned long)((y)[0] & 255)<<24) | \
- ((unsigned long)((y)[1] & 255)<<16) | \
- ((unsigned long)((y)[2] & 255)<<8) | \
- ((unsigned long)((y)[3] & 255)); }
-
-#define STORE64H(x, y) \
- { (y)[0] = (unsigned char)(((x)>>56)&255); (y)[1] = (unsigned char)(((x)>>48)&255); \
- (y)[2] = (unsigned char)(((x)>>40)&255); (y)[3] = (unsigned char)(((x)>>32)&255); \
- (y)[4] = (unsigned char)(((x)>>24)&255); (y)[5] = (unsigned char)(((x)>>16)&255); \
- (y)[6] = (unsigned char)(((x)>>8)&255); (y)[7] = (unsigned char)((x)&255); }
-
-#define LOAD64H(x, y) \
- { x = (((ulong64)((y)[0] & 255))<<56)|(((ulong64)((y)[1] & 255))<<48) | \
- (((ulong64)((y)[2] & 255))<<40)|(((ulong64)((y)[3] & 255))<<32) | \
- (((ulong64)((y)[4] & 255))<<24)|(((ulong64)((y)[5] & 255))<<16) | \
- (((ulong64)((y)[6] & 255))<<8)|(((ulong64)((y)[7] & 255))); }
-
-#ifdef ENDIAN_32BITWORD
-
-#define STORE32L(x, y) \
- { unsigned long __t = (x); memcpy(y, &__t, 4); }
-
-#define LOAD32L(x, y) \
- memcpy(&(x), y, 4);
-
-#define STORE64L(x, y) \
- { (y)[7] = (unsigned char)(((x)>>56)&255); (y)[6] = (unsigned char)(((x)>>48)&255); \
- (y)[5] = (unsigned char)(((x)>>40)&255); (y)[4] = (unsigned char)(((x)>>32)&255); \
- (y)[3] = (unsigned char)(((x)>>24)&255); (y)[2] = (unsigned char)(((x)>>16)&255); \
- (y)[1] = (unsigned char)(((x)>>8)&255); (y)[0] = (unsigned char)((x)&255); }
-
-#define LOAD64L(x, y) \
- { x = (((ulong64)((y)[7] & 255))<<56)|(((ulong64)((y)[6] & 255))<<48)| \
- (((ulong64)((y)[5] & 255))<<40)|(((ulong64)((y)[4] & 255))<<32)| \
- (((ulong64)((y)[3] & 255))<<24)|(((ulong64)((y)[2] & 255))<<16)| \
- (((ulong64)((y)[1] & 255))<<8)|(((ulong64)((y)[0] & 255))); }
-
-#else /* 64-bit words then */
-
-#define STORE32L(x, y) \
- { unsigned long __t = (x); memcpy(y, &__t, 4); }
-
-#define LOAD32L(x, y) \
- { memcpy(&(x), y, 4); x &= 0xFFFFFFFF; }
-
-#define STORE64L(x, y) \
- { ulong64 __t = (x); memcpy(y, &__t, 8); }
-
-#define LOAD64L(x, y) \
- { memcpy(&(x), y, 8); }
-
-#endif /* ENDIAN_64BITWORD */
-#endif /* ENDIAN_LITTLE */
-
-#ifdef ENDIAN_BIG
-#define STORE32L(x, y) \
- { (y)[3] = (unsigned char)(((x)>>24)&255); (y)[2] = (unsigned char)(((x)>>16)&255); \
- (y)[1] = (unsigned char)(((x)>>8)&255); (y)[0] = (unsigned char)((x)&255); }
-
-#define LOAD32L(x, y) \
- { x = ((unsigned long)((y)[3] & 255)<<24) | \
- ((unsigned long)((y)[2] & 255)<<16) | \
- ((unsigned long)((y)[1] & 255)<<8) | \
- ((unsigned long)((y)[0] & 255)); }
-
-#define STORE64L(x, y) \
- { (y)[7] = (unsigned char)(((x)>>56)&255); (y)[6] = (unsigned char)(((x)>>48)&255); \
- (y)[5] = (unsigned char)(((x)>>40)&255); (y)[4] = (unsigned char)(((x)>>32)&255); \
- (y)[3] = (unsigned char)(((x)>>24)&255); (y)[2] = (unsigned char)(((x)>>16)&255); \
- (y)[1] = (unsigned char)(((x)>>8)&255); (y)[0] = (unsigned char)((x)&255); }
-
-#define LOAD64L(x, y) \
- { x = (((ulong64)((y)[7] & 255))<<56)|(((ulong64)((y)[6] & 255))<<48) | \
- (((ulong64)((y)[5] & 255))<<40)|(((ulong64)((y)[4] & 255))<<32) | \
- (((ulong64)((y)[3] & 255))<<24)|(((ulong64)((y)[2] & 255))<<16) | \
- (((ulong64)((y)[1] & 255))<<8)|(((ulong64)((y)[0] & 255))); }
-
-#ifdef ENDIAN_32BITWORD
-
-#define STORE32H(x, y) \
- { unsigned long __t = (x); memcpy(y, &__t, 4); }
-
-#define LOAD32H(x, y) \
- memcpy(&(x), y, 4);
-
-#define STORE64H(x, y) \
- { (y)[0] = (unsigned char)(((x)>>56)&255); (y)[1] = (unsigned char)(((x)>>48)&255); \
- (y)[2] = (unsigned char)(((x)>>40)&255); (y)[3] = (unsigned char)(((x)>>32)&255); \
- (y)[4] = (unsigned char)(((x)>>24)&255); (y)[5] = (unsigned char)(((x)>>16)&255); \
- (y)[6] = (unsigned char)(((x)>>8)&255); (y)[7] = (unsigned char)((x)&255); }
-
-#define LOAD64H(x, y) \
- { x = (((ulong64)((y)[0] & 255))<<56)|(((ulong64)((y)[1] & 255))<<48)| \
- (((ulong64)((y)[2] & 255))<<40)|(((ulong64)((y)[3] & 255))<<32)| \
- (((ulong64)((y)[4] & 255))<<24)|(((ulong64)((y)[5] & 255))<<16)| \
- (((ulong64)((y)[6] & 255))<<8)| (((ulong64)((y)[7] & 255))); }
-
-#else /* 64-bit words then */
-
-#define STORE32H(x, y) \
- { unsigned long __t = (x); memcpy(y, &__t, 4); }
-
-#define LOAD32H(x, y) \
- { memcpy(&(x), y, 4); x &= 0xFFFFFFFF; }
-
-#define STORE64H(x, y) \
- { ulong64 __t = (x); memcpy(y, &__t, 8); }
-
-#define LOAD64H(x, y) \
- { memcpy(&(x), y, 8); }
-
-#endif /* ENDIAN_64BITWORD */
-#endif /* ENDIAN_BIG */
-
-/*
- packet code */
-#if defined(USE_RSA) || defined(MDH) || defined(MECC)
- #define PACKET
-
-/*
- size of a packet header in bytes */
- #define PACKET_SIZE 4
-
-/*
- Section tags
- */
- #define PACKET_SECT_RSA 0
- #define PACKET_SECT_DH 1
- #define PACKET_SECT_ECC 2
- #define PACKET_SECT_DSA 3
-
-/*
- Subsection Tags for the first three sections
- */
- #define PACKET_SUB_KEY 0
- #define PACKET_SUB_ENCRYPTED 1
- #define PACKET_SUB_SIGNED 2
- #define PACKET_SUB_ENC_KEY 3
-#endif
-
-/*
- fix for MSVC ...evil!
- */
-#ifdef WIN32
-#ifdef _MSC_VER
- #define CONST64(n) n ## ui64
- typedef unsigned __int64 ulong64;
-#else
- #define CONST64(n) n ## ULL
- typedef unsigned long long ulong64;
-#endif
-#endif /* WIN32 */
-
-
-#define BSWAP(x) ( ((x>>24)&0x000000FFUL) | ((x<<24)&0xFF000000UL) | \
- ((x>>8)&0x0000FF00UL) | ((x<<8)&0x00FF0000UL) )
-
-#ifdef _MSC_VER
-
-/*
- instrinsic rotate
- */
-#include <stdlib.h>
-#pragma intrinsic(_lrotr,_lrotl)
-#define ROR(x,n) _lrotr(x,n)
-#define ROL(x,n) _lrotl(x,n)
-#define RORc(x,n) _lrotr(x,n)
-#define ROLc(x,n) _lrotl(x,n)
-
-/*
-#elif defined(__GNUC__) && (defined(__i386__) || defined(__x86_64__)) && !defined(INTEL_CC) && !defined(PS_NO_ASM)
-
-static inline unsigned ROL(unsigned word, int32 i)
-{
- asm ("roll %%cl,%0"
- :"0" (word),"c" (i));
- return word;
-}
-
-static inline unsigned ROR(unsigned word, int32 i)
-{
- asm ("rorl %%cl,%0"
- :"=r" (word)
- :"0" (word),"c" (i));
- return word;
-}
-*/
-/*
-#ifndef PS_NO_ROLC
-
-static inline unsigned ROLc(unsigned word, const int32 i)
-{
- asm ("roll %2,%0"
- :"=r" (word)
- :"0" (word),"I" (i));
- return word;
-}
-
-static inline unsigned RORc(unsigned word, const int32 i)
-{
- asm ("rorl %2,%0"
- :"=r" (word)
- :"0" (word),"I" (i));
- return word;
-}
-
-#else
-
-#define ROLc ROL
-#define RORc ROR
-
-#endif
-*/
-
-#else /* _MSC_VER */
-
-/*
- rotates the hard way
- */
-#define ROL(x, y) ( (((unsigned long)(x)<<(unsigned long)((y)&31)) | (((unsigned long)(x)&0xFFFFFFFFUL)>>(unsigned long)(32-((y)&31)))) & 0xFFFFFFFFUL)
-#define ROR(x, y) ( ((((unsigned long)(x)&0xFFFFFFFFUL)>>(unsigned long)((y)&31)) | ((unsigned long)(x)<<(unsigned long)(32-((y)&31)))) & 0xFFFFFFFFUL)
-#define ROLc(x, y) ( (((unsigned long)(x)<<(unsigned long)((y)&31)) | (((unsigned long)(x)&0xFFFFFFFFUL)>>(unsigned long)(32-((y)&31)))) & 0xFFFFFFFFUL)
-#define RORc(x, y) ( ((((unsigned long)(x)&0xFFFFFFFFUL)>>(unsigned long)((y)&31)) | ((unsigned long)(x)<<(unsigned long)(32-((y)&31)))) & 0xFFFFFFFFUL)
-
-#endif /* _MSC_VER */
-
-/* 64-bit Rotates */
-#if 0
-
-#if defined(__GNUC__) && defined(__x86_64__) && !defined(PS_NO_ASM)
-
-static inline unsigned long ROL64(unsigned long word, int32 i)
-{
- asm("rolq %%cl,%0"
- :"=r" (word)
- :"0" (word),"c" (i));
- return word;
-}
-
-static inline unsigned long ROR64(unsigned long word, int32 i)
-{
- asm("rorq %%cl,%0"
- :"=r" (word)
- :"0" (word),"c" (i));
- return word;
-}
-
-#ifndef PS_NO_ROLC
-
-static inline unsigned long ROL64c(unsigned long word, const int32 i)
-{
- asm("rolq %2,%0"
- :"=r" (word)
- :"0" (word),"J" (i));
- return word;
-}
-
-static inline unsigned long ROR64c(unsigned long word, const int32 i)
-{
- asm("rorq %2,%0"
- :"=r" (word)
- :"0" (word),"J" (i));
- return word;
-}
-
-#else /* PS_NO_ROLC */
-
-#define ROL64c ROL
-#define ROR64c ROR
-
-#endif /* PS_NO_ROLC */
-#endif
-#endif /* commented out */
-
-#define ROL64(x, y) \
- ( (((x)<<((ulong64)(y)&63)) | \
- (((x)&CONST64(0xFFFFFFFFFFFFFFFF))>>((ulong64)64-((y)&63)))) & CONST64(0xFFFFFFFFFFFFFFFF))
-
-#define ROR64(x, y) \
- ( ((((x)&CONST64(0xFFFFFFFFFFFFFFFF))>>((ulong64)(y)&CONST64(63))) | \
- ((x)<<((ulong64)(64-((y)&CONST64(63)))))) & CONST64(0xFFFFFFFFFFFFFFFF))
-
-#define ROL64c(x, y) \
- ( (((x)<<((ulong64)(y)&63)) | \
- (((x)&CONST64(0xFFFFFFFFFFFFFFFF))>>((ulong64)64-((y)&63)))) & CONST64(0xFFFFFFFFFFFFFFFF))
-
-#define ROR64c(x, y) \
- ( ((((x)&CONST64(0xFFFFFFFFFFFFFFFF))>>((ulong64)(y)&CONST64(63))) | \
- ((x)<<((ulong64)(64-((y)&CONST64(63)))))) & CONST64(0xFFFFFFFFFFFFFFFF))
-
-#undef MAX
-#undef MIN
-#define MAX(x, y) ( ((x)>(y))?(x):(y) )
-#define MIN(x, y) ( ((x)<(y))?(x):(y) )
-
-/*
- extract a byte portably This MSC code causes runtime errors in VS.NET,
- always use the other
- */
-/*
-#ifdef _MSC_VER
- #define byte(x, n) ((unsigned char)((x) >> (8 * (n))))
-#else
-*/
- #define byte(x, n) (((x) >> (8 * (n))) & 255)
-/*
-#endif
-*/
-#ifdef __cplusplus
- }
-#endif /* __cplusplus */
-
-#endif /* _h_PSCRYPTO */
-
-/******************************************************************************/
-
diff --git a/gpxe/src/crypto/ssl.c b/gpxe/src/crypto/ssl.c deleted file mode 100644 index 8abd7af8..00000000 --- a/gpxe/src/crypto/ssl.c +++ /dev/null @@ -1,136 +0,0 @@ -#if 0 - -#include "ssl.h" -#include "ssl_constructs.h" -#include <string.h> // for bcopy() -#include <time.h> // for time() -#include <stdlib.h> // for rand(), htons?, htonl? -// note net byte order is big-endian -// Need to set error codes - -int CreateSSLHello(SSL_t *ssl) -{ - printf("In CreateSSLHello()\n",ssl); - - // Initalize the structure - bzero(ssl,sizeof(SSL_t)); - //ssl->max_size = sizeof(ssl->buffer); - ssl->max_size = 18456; - - // Declare variables - int i; void *ptr; - - // Set pointers into buffer - SSLPlaintext *record = (SSLPlaintext *)ssl->buffer; - Handshake *handshake = (Handshake *)record->fragment; - // the body starts right after the handshake - printf("sizeof(Handshake) = %d\n",sizeof(Handshake)); - ClientHello *hello = (ClientHello *)(handshake + 1); - - printf("record->%#x, handshake->%#x, hello->%#x\n",record,handshake,hello); - - // Construct ClientHello Message - hello->client_version = version; - i = htonl(time(NULL)); - bcopy(&i,hello->random.gmt_unix_time,4); - for(i=0;i<28;i++){ hello->random.random_bytes[i] = (uint8)rand(); } - hello->session_id_length = 0; - hello->session_id = &hello->session_id_length; - hello->session_id_end = hello->session_id; - hello->cipher_suites_length = (CipherSuiteLength *)(hello->session_id_end + 1); - hello->cipher_suites = (hello->cipher_suites_length + 1); - hello->cipher_suites_end = hello->cipher_suites; - i = htons(2*5); // 2 bytes per Suite * 5 Suites - bcopy(&i,hello->cipher_suites_length,2); - bcopy(SSL_NULL_WITH_NULL_NULL,hello->cipher_suites_end,sizeof(CipherSuite)); - *hello->cipher_suites_end++; - bcopy(SSL_DH_DSS_EXPORT_WITH_DES40_CBC_SHA,hello->cipher_suites_end,sizeof(CipherSuite)); - *hello->cipher_suites_end++; - bcopy(SSL_DH_DSS_WITH_DES_CBC_SHA,hello->cipher_suites_end,sizeof(CipherSuite)); - *hello->cipher_suites_end++; - bcopy(SSL_DHE_DSS_EXPORT_WITH_DES40_CBC_SHA,hello->cipher_suites_end,sizeof(CipherSuite)); - *hello->cipher_suites_end++; - bcopy(SSL_DH_anon_WITH_RC4_128_MD5,hello->cipher_suites_end,sizeof(CipherSuite)); - hello->compression_methods_length = (CompressionMethodLength *)(hello->cipher_suites_end + 1); - hello->compression_methods = (hello->compression_methods_length + 1); - hello->compression_methods_end = hello->compression_methods; - *hello->compression_methods_length = 1; - *hello->compression_methods_end = compression_method_null; - - // Construct Handshake Message - handshake->msg_type = handshake_type_client_hello; - i = (void *)(hello->compression_methods_end + 1) - (void *)hello; - printf("Handshake.length = %d\n", i); - handshake->length[0] = (char)*(&i+8); - handshake->length[1] = (char)*(&i+8); - handshake->length[2] = (char)i; - //bcopy((&i+1),handshake->length,3); // +1 so we copy 3 bytes - - // Construct SSL Record - printf("sizeof(ContentType)=%d\n",sizeof(ContentType)); - printf("sizeof(uint8)=%d\n",sizeof(uint8)); - record->type = content_type_handshake; - record->version = version; - i += sizeof(Handshake); - printf("SSLPlaintext.length = %d\n",i); - record->length[0] = (char)*(&i+8); - record->length[1] = (char)i; - //bcopy(&i,record->length,4); // length of handshake - - // Set total size of message - i += sizeof(ContentType) + sizeof(ProtocolVersion) + sizeof(uint16); - ssl->length = i; - printf("End of CreateSSLHello\n"); - return 0; -} - -void PrintSSLPacket(SSL_t *ssl) -{ - printf("Printing packet with length:%d\n", ssl->length); - char *ptr = ssl->buffer; - char *begin = ptr; - char *tmp; - char *end = ssl->buffer + ssl->length; - printf("Record Layer:\n"); - printf("\tContentType: %2hhX\n",(char)*ptr++); - printf("\tVersion: %2hhX %2hhX\n", (char)*ptr++, (char)*ptr++); - printf("\tLength: %2hhX %2hhX\n", (char)*ptr++, (char)*ptr++); - - printf("Handshake:\n"); - printf("\tType: %2hhX\n", (char)*ptr++); - printf("\tLength: %2hhX %2hhX %2hhX\n", (char)*ptr++, (char)*ptr++, (char)*ptr++); - printf("\tVersion: %2hhX %2hhX\n", (char)*ptr++, (char)*ptr++); - printf("\tgmt_unix_time: %2hhX %2hhX %2hhX %2hhX\n", (char)*ptr++, (char)*ptr++, (char)*ptr++, (char)*ptr++); - printf("\trandom: "); - tmp = ptr + 28; - for(;ptr<tmp;ptr++){printf("%2hhX ", (char)*ptr);} - - printf("\n\nHexDump:\n"); - - int ctr = 0; - for(;begin<end;begin++){printf("%2hhX ",(char)*begin);if(++ctr%10==0){printf("\n");}} - printf("\n\n"); -} - -int ReadSSLHello(SSL_t *ssl) -{ - SSLCiphertext *ct = (SSLCiphertext *)ssl->buffer; - - if(ct->type == content_type_alert){ - // assuming text is still plaintext - Alert *a = (Alert *)&ct->fragment; - if(a->level == alert_level_fatal){ - printf("Fatal Alert %d, connection terminated\n",a->description); - return (1); - }else if(a->level == alert_level_warning){ - printf("Warning Alert %d\n", a->description); - }else{ - printf("Unknown alert level %d\n", a->level); - } - }else{ - printf("SSL type %d\n",ct->type); - } - return (0); -} - -#endif diff --git a/gpxe/src/crypto/ssl.h b/gpxe/src/crypto/ssl.h deleted file mode 100644 index 06d43008..00000000 --- a/gpxe/src/crypto/ssl.h +++ /dev/null @@ -1,19 +0,0 @@ -// At the moment I have hard coded one buffer. The size -// is the max size of SSLCiphertext.length (so, actually it should -// be increased to include the other information in the struct) -// I might need to make a new, or split the current, buffer because -// I have to have space to read in and write out, as well as keep -// any data that has not been translated. -// It works for now. -typedef struct _ssl_t{ - char buffer[18456]; - int length; - int max_size; // can't define const here - // Current CipherSuite - // Client random / Server random ??? - // pointers to different crypto functions -} SSL_t; - -int CreateSSLHello(SSL_t *ssl); -int ReadSSLHello(SSL_t *ssl); -void PrintSSLPacket(SSL_t *ssl); diff --git a/gpxe/src/crypto/ssl_constructs.h b/gpxe/src/crypto/ssl_constructs.h deleted file mode 100644 index ab3aa703..00000000 --- a/gpxe/src/crypto/ssl_constructs.h +++ /dev/null @@ -1,342 +0,0 @@ -// Note: This file still needs some work. -// Note: I had to redefine the enums to a set of const values, -// so that the size of the variable would be correct. - -// Typedefs -// (As defined by the SSL v3.0 RFC Draft) -// URL: http://wp.netscape.com/eng/ssl3/draft302.txt -typedef unsigned char uint8; -typedef uint8 uint16[2]; -typedef uint8 uint24[3]; -typedef uint8 uint32[4]; -typedef uint8 uint64[8]; - -// Record layers -typedef struct _ProtocolVersion{ - uint8 major, minor; -} ProtocolVersion; - -const ProtocolVersion version = { 3, 0 }; - -typedef uint8 ContentType; -const ContentType content_type_change_cipher_spec_type = 20; -const ContentType content_type_alert = 21; -const ContentType content_type_handshake = 22; -const ContentType content_type_application_data = 23; - -typedef struct _SSLPlaintext{ - ContentType type; - ProtocolVersion version; - uint16 length; // can not exceed 2^14 bytes - uint8 fragment[16384]; // 2^14 = 16,384 bytes -} SSLPlaintext; - -typedef struct _SSLCompressed{ - ContentType type; - ProtocolVersion version; - uint16 length; // can not exceed 2^14 + 1024 - uint8 fragment[17408]; // SSLCompressed.length -} SSLCompressed; - -typedef struct _SSLCiphertext{ - ContentType type; - ProtocolVersion version; - uint16 length; - uint8 fragment; // so we have a pointer to the data, and don't have to do math - // fragment; type GenericStreamCipher or GenericBlockCipher -} SSLCiphertext; // recast to get fragment - -typedef struct _GenericStreamCipher{ - uint8 content[17408]; // SSLCompressed.length - uint8 MAC[]; // CipherSpec.hash_size -} GenericStreamCipher; - -typedef struct _SSLStreamCiphertext{ - ContentType type; - ProtocolVersion version; - uint16 length; // can not exceed 2^14 + 2048 = 18,456 - GenericStreamCipher fragment; -} SSLStreamCiphertext; - -typedef struct _GenericBlockCipher{ - uint8 content[17408]; // SSLConpressed.length - uint8 MAC[0]; // CipherSpec.hash_size - // padding is used to bring the plaintext to - // a multiple of the block cipher's block length. - uint8 padding[0]; // GenericBlockCipher.padding_length - uint8 padding_length; -} GenericBlockCipher; - -typedef struct _SSLBlockCiphertext{ - ContentType type; - ProtocolVersion version; - uint16 length; // can not exceed 2^14 + 2048 = 18,456 - GenericBlockCipher fragment; -} SSLBlockCiphertext; - -// Change cipher specs message -typedef struct _ChangeCipherSpec{ - enum { type_change_cipher_spec=1, type_size=255 } type; -} ChangeCipherSpec; - -// Alert messages -typedef uint8 AlertLevel; -const AlertLevel alert_level_warning = 1; -const AlertLevel alert_level_fatal=2; - -typedef uint8 AlertDescription; -const AlertDescription alert_description_close_notify = 0; -const AlertDescription alert_description_unexpected_message = 10; -const AlertDescription alert_description_bad_record_mac = 20; -const AlertDescription alert_description_decompression_failure = 30; -const AlertDescription alert_description_handshake_failure = 40; -const AlertDescription alert_description_no_certificate = 41; -const AlertDescription alert_description_bad_certificate = 42; -const AlertDescription alert_description_unsupported_certificate = 43; -const AlertDescription alert_description_certificate_revoked = 44; -const AlertDescription alert_description_certificate_expired = 45; -const AlertDescription alert_description_certificate_unknown = 46; -const AlertDescription alert_description_illegal_parameter = 47; - -typedef struct _Alert{ - AlertLevel level; - AlertDescription description; -} Alert; - -// Handshake protocol -// What is the best way to have a generic pointer to the body struct?? -typedef uint8 HandshakeType; -const HandshakeType handshake_type_hello_request = 0; -const HandshakeType handshake_type_client_hello = 1; -const HandshakeType handshake_type_server_hello = 2; -const HandshakeType handshake_type_certificate = 11; -const HandshakeType handshake_type_server_key_exchange = 12; -const HandshakeType handshake_type_certificate_request = 13; -const HandshakeType handshake_type_server_done = 14; -const HandshakeType handshake_type_certificate_verify = 15; -const HandshakeType handshake_type_client_key_exchange = 16; -const HandshakeType handshake_type_finished = 20; - -typedef struct _Handshake{ - HandshakeType msg_type; - uint24 length; - // body; // one of HandshakeType structs -} Handshake; // generic Handshake, need to recast to get body - -// Hello messages -typedef struct _HelloRequest{} HelloRequest; - -typedef struct _HelloRequestHandshake{ - HandshakeType msg_type; - uint24 length; - HelloRequest body; -} HelloRequestHandshake; - -typedef struct _Random{ - uint32 gmt_unix_time; - uint8 random_bytes[28]; -} Random; - -//typedef uint8 SessionID[32]; // <0..32> -typedef uint8 SessionIDLength; -typedef uint8 SessionID; - -typedef uint16 CipherSuiteLength; -typedef uint8 CipherSuite[2]; - -typedef uint8 CompressionMethodLength; -typedef uint8 CompressionMethod; -const CompressionMethod compression_method_null = 0; - - -typedef struct _ClientHello{ - ProtocolVersion client_version; - Random random; - SessionIDLength session_id_length; - SessionID *session_id; - SessionID *session_id_end; - CipherSuiteLength *cipher_suites_length; - CipherSuite *cipher_suites; // min size is one entry - CipherSuite *cipher_suites_end; - //CipherSuite cipher_suites[32768]; // <2..2^16-1> = 65,536 bytes and CipherSuite is 2 bytes - CompressionMethodLength *compression_methods_length; - CompressionMethod *compression_methods; - CompressionMethod *compression_methods_end; - //CompressionMethod *compression_methods; // min size is zero - //CompressionMethod compression_methods[256]; // <0..2^8-1> = 256 bytes and CompressionMethod is 1 byte -} ClientHello; - -typedef struct _ClientHelloHandshake{ - //HandshakeType msg_type; - uint8 msg_type; - uint24 length; - ClientHello body; -} ClientHelloHandshake; - -typedef struct _ServerHello{ - ProtocolVersion server_version; - Random random; - SessionID session_id; - CipherSuite cipher_suite; - CompressionMethod compression_method; -} ServerHello; - -typedef struct _ServerHelloHandshake{ - HandshakeType msg_type; - uint24 length; - ServerHello body; -} ServerHelloHandshake; - -// Server authentication and key exchange messages -typedef uint8 ASN1Cert[16777216]; // <1..2^24-1> = 16,777,216 bytes - -typedef struct _Certificate{ - ASN1Cert certificate_list[1]; // <1..2^24-1> / ANS1Cert = 1 - // for some reason the size of certificate_list and ASN1Cert is the same, so only one certificate in the list -} Certificate; - -typedef uint8 KeyExchangeAlgorithm; -const KeyExchangeAlgorithm key_exchange_algorithm_rsa = 0; -const KeyExchangeAlgorithm key_exchange_algorithm_diffie_hellman = 1; -const KeyExchangeAlgorithm key_exchange_algorithm_fortezza_kea = 2; - -typedef struct _AnonSignature{ - struct {}; -} AnonSignature; - -typedef struct _RSASignature{ - uint8 md5_hash[16]; - uint8 sha_hash[20]; -} RSASignature; - -typedef struct _DSASignature{ - uint8 sha_hash[20]; -} DSASignature; - -// use union??, make a mess to reference, but easy to make Signature type. -typedef union _Signature{ AnonSignature anon; RSASignature rsa; DSASignature dsa; } Signature; - -typedef struct _ServerRSAParams{ - uint8 RSA_modulus[65536]; // <1..2^16-1> = 65,536 - uint8 RSA_exponent[65536]; // <1..2^16-1> = 65,536 -} ServerRSAParams; - -typedef struct _ServerDHParams{ - uint8 DH_p[65536]; // <1..2^16-1> - uint8 DH_g[65536]; // <1..2^16-1> - uint8 DH_Ys[65536]; // <1..2^16-1> -} ServerDHParams; - -typedef struct _ServerDHKeyExchange{ - ServerDHParams params; - Signature signed_params; -} ServerDHKeyExchange; - -typedef struct _ServerRSAKeyExchange{ - ServerRSAParams params; - Signature signed_params; -} ServerRSAKeyExchange; - -typedef uint8 SignatureAlgorithm; -const SignatureAlgorithm signature_algorithm_anonymous = 0; -const SignatureAlgorithm signature_algorithm_rsa = 1; -const SignatureAlgorithm signature_algorithm_dsa = 2; - -typedef uint8 CertificateType; -const CertificateType certificate_type_RSA_sign = 1; -const CertificateType certificate_type_DSS_sign = 2; -const CertificateType certificate_type_RSA_fixed_DH = 3; -const CertificateType certificate_type_DSS_fixed_DH = 4; -const CertificateType certificate_type_RSA_ephemeral_DH = 5; -const CertificateType certificate_type_DSS_ephemeral_DH = 6; -const CertificateType certificate_type_FORTEZZA_MISSI = 20; - -typedef uint8 DistinguishedName[65536]; // <1..2^16-1> = 65,536 - -typedef struct _CertificateRequest{ - CertificateType certificate_types[256]; // <1..2^8-1> - DistinguishedName certificate_authorities[1]; // <3...2^16-1> / DistinguishedName - // this is another one that is odd with a list size of 1 -} CertificateRequest; - -typedef struct _ServerHelloDone{} ServerHelloDone; - -// Client authentication and key exchange messages -typedef struct _PreMasterSecret{ - ProtocolVersion client_version; - uint8 random[46]; -} PreMasterSecret; - -typedef struct _EncryptedPreMasterSecret{ - PreMasterSecret pre_master_secret; -} EncryptedPreMasterSecret; - -typedef struct _RSAClientKeyExchange{ - EncryptedPreMasterSecret exchange_keys; -} RSAClientKeyExchange; - -typedef uint8 PublicValueEncoding; -const PublicValueEncoding public_value_encoding_implicit = 0; -const PublicValueEncoding public_value_encoding_explicit = 1; - -typedef struct _ClientDiffieHellmanPublic{ - // This is a select on PublicValueEncoding, and I chose the larger size - uint8 dh_public[65536]; // DH_Yc<1..2^16-1>, the dh public value -} ClientDiffieHellmanPublic; - -typedef struct _DHClientKeyExhange{ - ClientDiffieHellmanPublic exchange_keys; -} DHClientKeyExchange; - -typedef struct _CertificateVerify{ - Signature signature; -} CertificateVerify; - -// Handshake finalization message -typedef struct _Finished{ - uint8 md5_hash[16]; - uint8 sha_hash[20]; -} Finished; - -// The CipherSuite -CipherSuite SSL_NULL_WITH_NULL_NULL = { 0x00, 0x13 }; -CipherSuite SSL_DH_DSS_EXPORT_WITH_DES40_CBC_SHA = { 0x00, 0x0B }; -CipherSuite SSL_DH_DSS_WITH_DES_CBC_SHA = { 0x00, 0x0C }; -CipherSuite SSL_DHE_DSS_EXPORT_WITH_DES40_CBC_SHA = { 0x00, 0x11 }; -CipherSuite SSL_DH_anon_EXPORT_WITH_RC4_40_MD5 = { 0x00, 0x17 }; -CipherSuite SSL_DH_anon_WITH_RC4_128_MD5 = { 0x00, 0x18 }; - -// The CipherSpec -typedef uint8 CipherType; -const CipherType cipher_type_stream = 0; -const CipherType cipher_type_block = 1; - -typedef uint8 IsExportable; -const IsExportable is_exportable_true = 0; -const IsExportable is_exportable_false = 1; - -typedef uint8 BulkCipherAlgorithm; -const BulkCipherAlgorithm bulk_cipher_algorithm_null = 0; -const BulkCipherAlgorithm bulk_cipher_algorithm_rc4 = 1; -const BulkCipherAlgorithm bulk_cipher_algorithm_rc2 = 2; -const BulkCipherAlgorithm bulk_cipher_algorithm_des = 3; -const BulkCipherAlgorithm bulk_cipher_algorithm_3des = 4; -const BulkCipherAlgorithm bulk_cipher_algorithm_des40 = 5; -const BulkCipherAlgorithm bulk_cipher_algorithm_fortezza = 6; - -typedef uint8 MACAlgorithm; -const MACAlgorithm mac_algorithm_null = 0; -const MACAlgorithm mac_algorithm_md5 = 1; -const MACAlgorithm mac_algorithm_sha = 2; - -typedef struct _CipherSpec{ - BulkCipherAlgorithm bulk_cipher_algorithm; - MACAlgorithm mac_algorithm; - CipherType cipher_type; - IsExportable is_exportable; - uint8 hash_size; - uint8 key_material; - uint8 IV_size; -} CipherSpec; - - diff --git a/gpxe/src/crypto/x509.c b/gpxe/src/crypto/x509.c new file mode 100644 index 00000000..35adfa38 --- /dev/null +++ b/gpxe/src/crypto/x509.c @@ -0,0 +1,181 @@ +/* + * Copyright (C) 2007 Michael Brown <mbrown@fensystems.co.uk>. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of the + * License, or any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +#include <stdlib.h> +#include <string.h> +#include <errno.h> +#include <gpxe/asn1.h> +#include <gpxe/x509.h> + +/** @file + * + * X.509 certificates + * + * The structure of X.509v3 certificates is concisely documented in + * RFC5280 section 4.1. The structure of RSA public keys is + * documented in RFC2313. + */ + +/** Object Identifier for "rsaEncryption" (1.2.840.113549.1.1.1) */ +static const uint8_t oid_rsa_encryption[] = { 0x2a, 0x86, 0x48, 0x86, 0xf7, + 0x0d, 0x01, 0x01, 0x01 }; + +/** + * Identify X.509 certificate public key + * + * @v certificate Certificate + * @v algorithm Public key algorithm to fill in + * @v pubkey Public key value to fill in + * @ret rc Return status code + */ +static int x509_public_key ( const struct asn1_cursor *certificate, + struct asn1_cursor *algorithm, + struct asn1_cursor *pubkey ) { + struct asn1_cursor cursor; + int rc; + + /* Locate subjectPublicKeyInfo */ + memcpy ( &cursor, certificate, sizeof ( cursor ) ); + rc = ( asn1_enter ( &cursor, ASN1_SEQUENCE ), /* Certificate */ + asn1_enter ( &cursor, ASN1_SEQUENCE ), /* tbsCertificate */ + asn1_skip ( &cursor, ASN1_EXPLICIT_TAG ), /* version */ + asn1_skip ( &cursor, ASN1_INTEGER ), /* serialNumber */ + asn1_skip ( &cursor, ASN1_SEQUENCE ), /* signature */ + asn1_skip ( &cursor, ASN1_SEQUENCE ), /* issuer */ + asn1_skip ( &cursor, ASN1_SEQUENCE ), /* validity */ + asn1_skip ( &cursor, ASN1_SEQUENCE ), /* name */ + asn1_enter ( &cursor, ASN1_SEQUENCE )/* subjectPublicKeyInfo*/); + if ( rc != 0 ) { + DBG ( "Cannot locate subjectPublicKeyInfo in:\n" ); + DBG_HDA ( 0, certificate->data, certificate->len ); + return rc; + } + + /* Locate algorithm */ + memcpy ( algorithm, &cursor, sizeof ( *algorithm ) ); + rc = ( asn1_enter ( algorithm, ASN1_SEQUENCE ) /* algorithm */ ); + if ( rc != 0 ) { + DBG ( "Cannot locate algorithm in:\n" ); + DBG_HDA ( 0, certificate->data, certificate->len ); + return rc; + } + + /* Locate subjectPublicKey */ + memcpy ( pubkey, &cursor, sizeof ( *pubkey ) ); + rc = ( asn1_skip ( pubkey, ASN1_SEQUENCE ), /* algorithm */ + asn1_enter ( pubkey, ASN1_BIT_STRING ) /* subjectPublicKey*/ ); + if ( rc != 0 ) { + DBG ( "Cannot locate subjectPublicKey in:\n" ); + DBG_HDA ( 0, certificate->data, certificate->len ); + return rc; + } + + return 0; +} + +/** + * Identify X.509 certificate RSA modulus and public exponent + * + * @v certificate Certificate + * @v rsa RSA public key to fill in + * @ret rc Return status code + * + * The caller is responsible for eventually calling + * x509_free_rsa_public_key() to free the storage allocated to hold + * the RSA modulus and exponent. + */ +int x509_rsa_public_key ( const struct asn1_cursor *certificate, + struct x509_rsa_public_key *rsa_pubkey ) { + struct asn1_cursor algorithm; + struct asn1_cursor pubkey; + struct asn1_cursor modulus; + struct asn1_cursor exponent; + int rc; + + /* First, extract the public key algorithm and key data */ + if ( ( rc = x509_public_key ( certificate, &algorithm, + &pubkey ) ) != 0 ) + return rc; + + /* Check that algorithm is RSA */ + rc = ( asn1_enter ( &algorithm, ASN1_OID ) /* algorithm */ ); + if ( rc != 0 ) { + DBG ( "Cannot locate algorithm:\n" ); + DBG_HDA ( 0, certificate->data, certificate->len ); + return rc; + } + if ( ( algorithm.len != sizeof ( oid_rsa_encryption ) ) || + ( memcmp ( algorithm.data, &oid_rsa_encryption, + sizeof ( oid_rsa_encryption ) ) != 0 ) ) { + DBG ( "algorithm is not rsaEncryption in:\n" ); + DBG_HDA ( 0, certificate->data, certificate->len ); + return -ENOTSUP; + } + + /* Check that public key is a byte string, i.e. that the + * "unused bits" byte contains zero. + */ + if ( ( pubkey.len < 1 ) || + ( ( *( uint8_t * ) pubkey.data ) != 0 ) ) { + DBG ( "subjectPublicKey is not a byte string in:\n" ); + DBG_HDA ( 0, certificate->data, certificate->len ); + return -ENOTSUP; + } + pubkey.data++; + pubkey.len--; + + /* Pick out the modulus and exponent */ + rc = ( asn1_enter ( &pubkey, ASN1_SEQUENCE ) /* RSAPublicKey */ ); + if ( rc != 0 ) { + DBG ( "Cannot locate RSAPublicKey in:\n" ); + DBG_HDA ( 0, certificate->data, certificate->len ); + return -ENOTSUP; + } + memcpy ( &modulus, &pubkey, sizeof ( modulus ) ); + rc = ( asn1_enter ( &modulus, ASN1_INTEGER ) /* modulus */ ); + if ( rc != 0 ) { + DBG ( "Cannot locate modulus in:\n" ); + DBG_HDA ( 0, certificate->data, certificate->len ); + return -ENOTSUP; + } + memcpy ( &exponent, &pubkey, sizeof ( exponent ) ); + rc = ( asn1_skip ( &exponent, ASN1_INTEGER ), /* modulus */ + asn1_enter ( &exponent, ASN1_INTEGER ) /* publicExponent */ ); + if ( rc != 0 ) { + DBG ( "Cannot locate publicExponent in:\n" ); + DBG_HDA ( 0, certificate->data, certificate->len ); + return -ENOTSUP; + } + + /* Allocate space and copy out modulus and exponent */ + rsa_pubkey->modulus = malloc ( modulus.len + exponent.len ); + if ( ! rsa_pubkey->modulus ) + return -ENOMEM; + rsa_pubkey->exponent = ( rsa_pubkey->modulus + modulus.len ); + memcpy ( rsa_pubkey->modulus, modulus.data, modulus.len ); + rsa_pubkey->modulus_len = modulus.len; + memcpy ( rsa_pubkey->exponent, exponent.data, exponent.len ); + rsa_pubkey->exponent_len = exponent.len; + + DBG2 ( "RSA modulus:\n" ); + DBG2_HDA ( 0, rsa_pubkey->modulus, rsa_pubkey->modulus_len ); + DBG2 ( "RSA exponent:\n" ); + DBG2_HDA ( 0, rsa_pubkey->exponent, rsa_pubkey->exponent_len ); + + return 0; +} diff --git a/gpxe/src/dl360.gpxe b/gpxe/src/dl360.gpxe new file mode 100644 index 00000000..237555b7 --- /dev/null +++ b/gpxe/src/dl360.gpxe @@ -0,0 +1,4 @@ +#!gpxe +kernel http://www.zytor.com/dl360/pxelinux.0 +set filename http://www.zytor.com/dl360/pxelinux.0 +boot diff --git a/gpxe/src/drivers/bitbash/i2c_bit.c b/gpxe/src/drivers/bitbash/i2c_bit.c index a3af610b..b85057af 100644 --- a/gpxe/src/drivers/bitbash/i2c_bit.c +++ b/gpxe/src/drivers/bitbash/i2c_bit.c @@ -19,6 +19,7 @@ #include <stddef.h> #include <stdint.h> #include <errno.h> +#include <string.h> #include <assert.h> #include <unistd.h> #include <gpxe/bitbash.h> @@ -49,6 +50,7 @@ static void i2c_delay ( void ) { * @v state New state of SCL */ static void setscl ( struct bit_basher *basher, int state ) { + DBG2 ( "%c", ( state ? '/' : '\\' ) ); write_bit ( basher, I2C_BIT_SCL, state ); i2c_delay(); } @@ -60,6 +62,7 @@ static void setscl ( struct bit_basher *basher, int state ) { * @v state New state of SDA */ static void setsda ( struct bit_basher *basher, int state ) { + DBG2 ( "%c", ( state ? '1' : '0' ) ); write_bit ( basher, I2C_BIT_SDA, state ); i2c_delay(); } @@ -71,7 +74,10 @@ static void setsda ( struct bit_basher *basher, int state ) { * @ret state State of SDA */ static int getsda ( struct bit_basher *basher ) { - return read_bit ( basher, I2C_BIT_SDA ); + int state; + state = read_bit ( basher, I2C_BIT_SDA ); + DBG2 ( "%c", ( state ? '+' : '-' ) ); + return state; } /** @@ -137,15 +143,20 @@ static void i2c_stop ( struct bit_basher *basher ) { */ static int i2c_send_byte ( struct bit_basher *basher, uint8_t byte ) { int i; - + int ack; + /* Send byte */ + DBG2 ( "[send %02x]", byte ); for ( i = 8 ; i ; i-- ) { i2c_send_bit ( basher, byte & 0x80 ); byte <<= 1; } /* Check for acknowledgement from slave */ - return ( i2c_recv_bit ( basher ) == 0 ? 0 : -EIO ); + ack = ( i2c_recv_bit ( basher ) == 0 ); + DBG2 ( "%s", ( ack ? "[acked]" : "[not acked]" ) ); + + return ( ack ? 0 : -EIO ); } /** @@ -157,19 +168,20 @@ static int i2c_send_byte ( struct bit_basher *basher, uint8_t byte ) { * Receives a byte via the I2C bus and sends NACK to the slave device. */ static uint8_t i2c_recv_byte ( struct bit_basher *basher ) { - uint8_t value = 0; + uint8_t byte = 0; int i; /* Receive byte */ for ( i = 8 ; i ; i-- ) { - value <<= 1; - value |= ( i2c_recv_bit ( basher ) & 0x1 ); + byte <<= 1; + byte |= ( i2c_recv_bit ( basher ) & 0x1 ); } /* Send NACK */ i2c_send_bit ( basher, 1 ); - return value; + DBG2 ( "[rcvd %02x]", byte ); + return byte; } /** @@ -177,30 +189,29 @@ static uint8_t i2c_recv_byte ( struct bit_basher *basher ) { * * @v basher Bit-bashing interface * @v i2cdev I2C device + * @v offset Starting offset within the device * @v direction I2C_READ or I2C_WRITE * @ret rc Return status code */ static int i2c_select ( struct bit_basher *basher, struct i2c_device *i2cdev, - unsigned int direction ) { + unsigned int offset, unsigned int direction ) { unsigned int address; + int shift; + unsigned int byte; int rc; i2c_start ( basher ); - /* First byte of the address */ - address = i2cdev->address; - if ( i2cdev->tenbit ) { - address |= I2C_TENBIT_ADDRESS; - address >>= 8; - } - if ( ( rc = i2c_send_byte ( basher, - ( ( address << 1 ) | direction ) ) ) != 0 ) - return rc; + /* Calculate address to appear on bus */ + address = ( ( ( i2cdev->dev_addr | + ( offset >> ( 8 * i2cdev->word_addr_len ) ) ) << 1 ) + | direction ); - /* Second byte of the address (10-bit addresses only) */ - if ( i2cdev->tenbit ) { - if ( ( rc = i2c_send_byte ( basher, - ( i2cdev->address & 0xff ) ) ) !=0) + /* Send address a byte at a time */ + for ( shift = ( 8 * ( i2cdev->dev_addr_len - 1 ) ) ; + shift >= 0 ; shift -= 8 ) { + byte = ( ( address >> shift ) & 0xff ); + if ( ( rc = i2c_send_byte ( basher, byte ) ) != 0 ) return rc; } @@ -208,6 +219,46 @@ static int i2c_select ( struct bit_basher *basher, struct i2c_device *i2cdev, } /** + * Reset I2C bus + * + * @v basher Bit-bashing interface + * @ret rc Return status code + * + * i2c devices often don't have a reset line, so even a reboot or + * system power cycle is sometimes not enough to bring them back to a + * known state. + */ +static int i2c_reset ( struct bit_basher *basher ) { + unsigned int i; + int sda; + + /* Clock through several cycles, waiting for an opportunity to + * pull SDA low while SCL is high (which creates a start + * condition). + */ + setscl ( basher, 0 ); + setsda ( basher, 1 ); + for ( i = 0 ; i < I2C_RESET_MAX_CYCLES ; i++ ) { + setscl ( basher, 1 ); + sda = getsda ( basher ); + if ( sda ) { + /* Now that the device will see a start, issue it */ + i2c_start ( basher ); + /* Stop the bus to leave it in a known good state */ + i2c_stop ( basher ); + DBGC ( basher, "I2CBIT %p reset after %d attempts\n", + basher, ( i + 1 ) ); + return 0; + } + setscl ( basher, 0 ); + } + + DBGC ( basher, "I2CBIT %p could not reset after %d attempts\n", + basher, i ); + return -ETIMEDOUT; +} + +/** * Read data from I2C device via bit-bashing interface * * @v i2c I2C interface @@ -228,12 +279,14 @@ static int i2c_bit_read ( struct i2c_interface *i2c, struct bit_basher *basher = &i2cbit->basher; int rc = 0; - DBG ( "Reading from I2C device %x: ", i2cdev->address ); + DBGC ( basher, "I2CBIT %p reading from device %x: ", + basher, i2cdev->dev_addr ); - while ( 1 ) { + for ( ; ; data++, offset++ ) { /* Select device for writing */ - if ( ( rc = i2c_select ( basher, i2cdev, I2C_WRITE ) ) != 0 ) + if ( ( rc = i2c_select ( basher, i2cdev, offset, + I2C_WRITE ) ) != 0 ) break; /* Abort at end of data */ @@ -241,19 +294,20 @@ static int i2c_bit_read ( struct i2c_interface *i2c, break; /* Select offset */ - if ( ( rc = i2c_send_byte ( basher, offset++ ) ) != 0 ) + if ( ( rc = i2c_send_byte ( basher, offset ) ) != 0 ) break; /* Select device for reading */ - if ( ( rc = i2c_select ( basher, i2cdev, I2C_READ ) ) != 0 ) + if ( ( rc = i2c_select ( basher, i2cdev, offset, + I2C_READ ) ) != 0 ) break; /* Read byte */ - *data++ = i2c_recv_byte ( basher ); - DBG ( "%02x ", *(data - 1) ); + *data = i2c_recv_byte ( basher ); + DBGC ( basher, "%02x ", *data ); } - DBG ( "%s\n", ( rc ? "failed" : "" ) ); + DBGC ( basher, "%s\n", ( rc ? "failed" : "" ) ); i2c_stop ( basher ); return rc; } @@ -279,12 +333,14 @@ static int i2c_bit_write ( struct i2c_interface *i2c, struct bit_basher *basher = &i2cbit->basher; int rc = 0; - DBG ( "Writing to I2C device %x: ", i2cdev->address ); + DBGC ( basher, "I2CBIT %p writing to device %x: ", + basher, i2cdev->dev_addr ); - while ( 1 ) { + for ( ; ; data++, offset++ ) { /* Select device for writing */ - if ( ( rc = i2c_select ( basher, i2cdev, I2C_WRITE ) ) != 0 ) + if ( ( rc = i2c_select ( basher, i2cdev, offset, + I2C_WRITE ) ) != 0 ) break; /* Abort at end of data */ @@ -292,16 +348,16 @@ static int i2c_bit_write ( struct i2c_interface *i2c, break; /* Select offset */ - if ( ( rc = i2c_send_byte ( basher, offset++ ) ) != 0 ) + if ( ( rc = i2c_send_byte ( basher, offset ) ) != 0 ) break; /* Write data to device */ - DBG ( "%02x ", *data ); - if ( ( rc = i2c_send_byte ( basher, *data++ ) ) != 0 ) + DBGC ( basher, "%02x ", *data ); + if ( ( rc = i2c_send_byte ( basher, *data ) ) != 0 ) break; } - DBG ( "%s\n", ( rc ? "failed" : "" ) ); + DBGC ( basher, "%s\n", ( rc ? "failed" : "" ) ); i2c_stop ( basher ); return rc; } @@ -310,13 +366,26 @@ static int i2c_bit_write ( struct i2c_interface *i2c, * Initialise I2C bit-bashing interface * * @v i2cbit I2C bit-bashing interface + * @v bash_op Bit-basher operations */ -void init_i2c_bit_basher ( struct i2c_bit_basher *i2cbit ) { +int init_i2c_bit_basher ( struct i2c_bit_basher *i2cbit, + struct bit_basher_operations *bash_op ) { struct bit_basher *basher = &i2cbit->basher; - + int rc; + + /* Initialise data structures */ + basher->op = bash_op; assert ( basher->op->read != NULL ); assert ( basher->op->write != NULL ); i2cbit->i2c.read = i2c_bit_read; i2cbit->i2c.write = i2c_bit_write; - i2c_stop ( basher ); + + /* Reset I2C bus */ + if ( ( rc = i2c_reset ( basher ) ) != 0 ) { + DBGC ( basher, "I2CBIT %p could not reset I2C bus: %s\n", + basher, strerror ( rc ) ); + return rc; + } + + return 0; } diff --git a/gpxe/src/drivers/block/ata.c b/gpxe/src/drivers/block/ata.c index 555a5f6e..c21d2f65 100644 --- a/gpxe/src/drivers/block/ata.c +++ b/gpxe/src/drivers/block/ata.c @@ -139,6 +139,11 @@ static int ata_identify ( struct block_device *blockdev ) { return 0; } +static struct block_device_operations ata_operations = { + .read = ata_read, + .write = ata_write +}; + /** * Initialise ATA device * @@ -153,7 +158,6 @@ static int ata_identify ( struct block_device *blockdev ) { */ int init_atadev ( struct ata_device *ata ) { /** Fill in read and write methods, and get device capacity */ - ata->blockdev.read = ata_read; - ata->blockdev.write = ata_write; + ata->blockdev.op = &ata_operations; return ata_identify ( &ata->blockdev ); } diff --git a/gpxe/src/drivers/block/ramdisk.c b/gpxe/src/drivers/block/ramdisk.c index b5324bf1..50911994 100644 --- a/gpxe/src/drivers/block/ramdisk.c +++ b/gpxe/src/drivers/block/ramdisk.c @@ -75,6 +75,11 @@ static int ramdisk_write ( struct block_device *blockdev, uint64_t block, return 0; } +static struct block_device_operations ramdisk_operations = { + .read = ramdisk_read, + .write = ramdisk_write +}; + int init_ramdisk ( struct ramdisk *ramdisk, userptr_t data, size_t len, unsigned int blksize ) { @@ -82,8 +87,7 @@ int init_ramdisk ( struct ramdisk *ramdisk, userptr_t data, size_t len, blksize = 512; ramdisk->data = data; - ramdisk->blockdev.read = ramdisk_read; - ramdisk->blockdev.write = ramdisk_write; + ramdisk->blockdev.op = &ramdisk_operations; ramdisk->blockdev.blksize = blksize; ramdisk->blockdev.blocks = ( len / blksize ); diff --git a/gpxe/src/drivers/block/scsi.c b/gpxe/src/drivers/block/scsi.c index 9651583a..71d22040 100644 --- a/gpxe/src/drivers/block/scsi.c +++ b/gpxe/src/drivers/block/scsi.c @@ -29,6 +29,13 @@ * */ +/** Maximum number of dummy "read capacity (10)" operations + * + * These are issued at connection setup to draw out various useless + * power-on messages. + */ +#define SCSI_MAX_DUMMY_READ_CAP 10 + static inline __attribute__ (( always_inline )) struct scsi_device * block_to_scsi ( struct block_device *blockdev ) { return container_of ( blockdev, struct scsi_device, blockdev ); @@ -228,6 +235,16 @@ static int scsi_read_capacity_16 ( struct block_device *blockdev ) { return 0; } +static struct block_device_operations scsi_operations_16 = { + .read = scsi_read_16, + .write = scsi_write_16, +}; + +static struct block_device_operations scsi_operations_10 = { + .read = scsi_read_10, + .write = scsi_write_10, +}; + /** * Initialise SCSI device * @@ -240,18 +257,24 @@ static int scsi_read_capacity_16 ( struct block_device *blockdev ) { * CAPACITY call to determine the block size and total device size. */ int init_scsidev ( struct scsi_device *scsi ) { + unsigned int i; int rc; - /* Issue a theoretically extraneous READ CAPACITY (10) - * command, solely in order to draw out the "CHECK CONDITION - * (power-on occurred)" that some dumb targets insist on - * sending as an error at start of day. + /* Issue some theoretically extraneous READ CAPACITY (10) + * commands, solely in order to draw out the "CHECK CONDITION + * (power-on occurred)", "CHECK CONDITION (reported LUNs data + * has changed)" etc. that some dumb targets insist on sending + * as an error at start of day. The precise command that we + * use is unimportant; we just need to provide the target with + * an opportunity to send its responses. */ - scsi_read_capacity_10 ( &scsi->blockdev ); + for ( i = 0 ; i < SCSI_MAX_DUMMY_READ_CAP ; i++ ) { + if ( ( rc = scsi_read_capacity_10 ( &scsi->blockdev ) ) == 0 ) + break; + } /* Try READ CAPACITY (10), which is a mandatory command, first. */ - scsi->blockdev.read = scsi_read_10; - scsi->blockdev.write = scsi_write_10; + scsi->blockdev.op = &scsi_operations_10; if ( ( rc = scsi_read_capacity_10 ( &scsi->blockdev ) ) != 0 ) return rc; @@ -261,8 +284,7 @@ int init_scsidev ( struct scsi_device *scsi ) { * mandatory, so we can't just use it straight off. */ if ( scsi->blockdev.blocks == 0 ) { - scsi->blockdev.read = scsi_read_16; - scsi->blockdev.write = scsi_write_16; + scsi->blockdev.op = &scsi_operations_16; if ( ( rc = scsi_read_capacity_16 ( &scsi->blockdev ) ) != 0 ) return rc; } diff --git a/gpxe/src/drivers/bus/eisa.c b/gpxe/src/drivers/bus/eisa.c index ee03df3a..d9e42359 100644 --- a/gpxe/src/drivers/bus/eisa.c +++ b/gpxe/src/drivers/bus/eisa.c @@ -3,7 +3,7 @@ #include <stdlib.h> #include <stdio.h> #include <errno.h> -#include <io.h> +#include <gpxe/io.h> #include <unistd.h> #include <gpxe/eisa.h> diff --git a/gpxe/src/drivers/bus/isa.c b/gpxe/src/drivers/bus/isa.c index a4105fd0..fa5def54 100644 --- a/gpxe/src/drivers/bus/isa.c +++ b/gpxe/src/drivers/bus/isa.c @@ -3,7 +3,7 @@ #include <stdlib.h> #include <stdio.h> #include <errno.h> -#include <io.h> +#include <gpxe/io.h> #include <gpxe/isa.h> /* @@ -49,9 +49,9 @@ static isa_probe_addr_t isa_extra_probe_addrs[] = { (driver)->probe_addrs[(ioidx)] ) static struct isa_driver isa_drivers[0] - __table_start ( struct isa_driver, isa_driver ); + __table_start ( struct isa_driver, isa_drivers ); static struct isa_driver isa_drivers_end[0] - __table_end ( struct isa_driver, isa_driver ); + __table_end ( struct isa_driver, isa_drivers ); static void isabus_remove ( struct root_device *rootdev ); diff --git a/gpxe/src/drivers/bus/isapnp.c b/gpxe/src/drivers/bus/isapnp.c index f4968eb1..8f812df8 100644 --- a/gpxe/src/drivers/bus/isapnp.c +++ b/gpxe/src/drivers/bus/isapnp.c @@ -60,7 +60,7 @@ #include <string.h> #include <stdio.h> #include <errno.h> -#include <io.h> +#include <gpxe/io.h> #include <unistd.h> #include <gpxe/isapnp.h> @@ -84,7 +84,7 @@ static void isapnpbus_remove ( struct root_device *rootdev ); * */ -#define ISAPNP_CARD_ID_FMT "ID %04x:%04x (\"%s\") serial %lx" +#define ISAPNP_CARD_ID_FMT "ID %04x:%04x (\"%s\") serial %x" #define ISAPNP_CARD_ID_DATA(identifier) \ (identifier)->vendor_id, (identifier)->prod_id, \ isa_id_string ( (identifier)->vendor_id, (identifier)->prod_id ), \ diff --git a/gpxe/src/drivers/bus/mca.c b/gpxe/src/drivers/bus/mca.c index eb7b7e39..e9233813 100644 --- a/gpxe/src/drivers/bus/mca.c +++ b/gpxe/src/drivers/bus/mca.c @@ -10,7 +10,7 @@ #include <stdlib.h> #include <stdio.h> #include <errno.h> -#include <io.h> +#include <gpxe/io.h> #include <gpxe/mca.h> static struct mca_driver mca_drivers[0] diff --git a/gpxe/src/drivers/bus/pci.c b/gpxe/src/drivers/bus/pci.c index 967441ac..2dc9d43a 100644 --- a/gpxe/src/drivers/bus/pci.c +++ b/gpxe/src/drivers/bus/pci.c @@ -67,7 +67,7 @@ static unsigned long pci_bar ( struct pci_device *pci, unsigned int reg ) { if ( sizeof ( unsigned long ) > sizeof ( uint32_t ) ) { return ( ( ( uint64_t ) high << 32 ) | low ); } else { - DBG ( "Unhandled 64-bit BAR %08lx%08lx\n", + DBG ( "Unhandled 64-bit BAR %08x%08x\n", high, low ); return PCI_BASE_ADDRESS_MEM_TYPE_64; } @@ -148,7 +148,8 @@ void adjust_pci_device ( struct pci_device *pci ) { unsigned char pci_latency; pci_read_config_word ( pci, PCI_COMMAND, &pci_command ); - new_command = pci_command | PCI_COMMAND_MASTER | PCI_COMMAND_IO; + new_command = ( pci_command | PCI_COMMAND_MASTER | + PCI_COMMAND_MEM | PCI_COMMAND_IO ); if ( pci_command != new_command ) { DBG ( "PCI BIOS has not enabled device %02x:%02x.%x! " "Updating PCI command %04x->%04x\n", pci->bus, diff --git a/gpxe/src/drivers/bus/virtio-pci.c b/gpxe/src/drivers/bus/virtio-pci.c new file mode 100644 index 00000000..34acce2d --- /dev/null +++ b/gpxe/src/drivers/bus/virtio-pci.c @@ -0,0 +1,64 @@ +/* virtio-pci.c - pci interface for virtio interface + * + * (c) Copyright 2008 Bull S.A.S. + * + * Author: Laurent Vivier <Laurent.Vivier@bull.net> + * + * some parts from Linux Virtio PCI driver + * + * Copyright IBM Corp. 2007 + * Authors: Anthony Liguori <aliguori@us.ibm.com> + * + */ + +#include "etherboot.h" +#include "gpxe/io.h" +#include "gpxe/virtio-ring.h" +#include "gpxe/virtio-pci.h" + +int vp_find_vq(unsigned int ioaddr, int queue_index, + struct vring_virtqueue *vq) +{ + struct vring * vr = &vq->vring; + u16 num; + + /* select the queue */ + + outw(queue_index, ioaddr + VIRTIO_PCI_QUEUE_SEL); + + /* check if the queue is available */ + + num = inw(ioaddr + VIRTIO_PCI_QUEUE_NUM); + if (!num) { + printf("ERROR: queue size is 0\n"); + return -1; + } + + if (num > MAX_QUEUE_NUM) { + printf("ERROR: queue size %d > %d\n", num, MAX_QUEUE_NUM); + return -1; + } + + /* check if the queue is already active */ + + if (inl(ioaddr + VIRTIO_PCI_QUEUE_PFN)) { + printf("ERROR: queue already active\n"); + return -1; + } + + vq->queue_index = queue_index; + + /* initialize the queue */ + + vring_init(vr, num, (unsigned char*)&vq->queue); + + /* activate the queue + * + * NOTE: vr->desc is initialized by vring_init() + */ + + outl((unsigned long)virt_to_phys(vr->desc) >> PAGE_SHIFT, + ioaddr + VIRTIO_PCI_QUEUE_PFN); + + return num; +} diff --git a/gpxe/src/drivers/bus/virtio-ring.c b/gpxe/src/drivers/bus/virtio-ring.c new file mode 100644 index 00000000..6415f626 --- /dev/null +++ b/gpxe/src/drivers/bus/virtio-ring.c @@ -0,0 +1,134 @@ +/* virtio-pci.c - virtio ring management + * + * (c) Copyright 2008 Bull S.A.S. + * + * Author: Laurent Vivier <Laurent.Vivier@bull.net> + * + * some parts from Linux Virtio Ring + * + * Copyright Rusty Russell IBM Corporation 2007 + * + * This work is licensed under the terms of the GNU GPL, version 2 or later. + * See the COPYING file in the top-level directory. + * + * + */ + +#include "etherboot.h" +#include "gpxe/io.h" +#include "gpxe/virtio-ring.h" +#include "gpxe/virtio-pci.h" + +#define BUG() do { \ + printf("BUG: failure at %s:%d/%s()!\n", \ + __FILE__, __LINE__, __FUNCTION__); \ + while(1); \ +} while (0) +#define BUG_ON(condition) do { if (condition) BUG(); } while (0) + +/* + * vring_free + * + * put at the begin of the free list the current desc[head] + */ + +void vring_detach(struct vring_virtqueue *vq, unsigned int head) +{ + struct vring *vr = &vq->vring; + unsigned int i; + + /* find end of given descriptor */ + + i = head; + while (vr->desc[i].flags & VRING_DESC_F_NEXT) + i = vr->desc[i].next; + + /* link it with free list and point to it */ + + vr->desc[i].next = vq->free_head; + wmb(); + vq->free_head = head; +} + +/* + * vring_get_buf + * + * get a buffer from the used list + * + */ + +int vring_get_buf(struct vring_virtqueue *vq, unsigned int *len) +{ + struct vring *vr = &vq->vring; + struct vring_used_elem *elem; + u32 id; + int ret; + + BUG_ON(!vring_more_used(vq)); + + elem = &vr->used->ring[vq->last_used_idx % vr->num]; + wmb(); + id = elem->id; + if (len != NULL) + *len = elem->len; + + ret = vq->vdata[id]; + + vring_detach(vq, id); + + vq->last_used_idx++; + + return ret; +} + +void vring_add_buf(struct vring_virtqueue *vq, + struct vring_list list[], + unsigned int out, unsigned int in, + int index, int num_added) +{ + struct vring *vr = &vq->vring; + int i, avail, head, prev; + + BUG_ON(out + in == 0); + + prev = 0; + head = vq->free_head; + for (i = head; out; i = vr->desc[i].next, out--) { + + vr->desc[i].flags = VRING_DESC_F_NEXT; + vr->desc[i].addr = (u64)virt_to_phys(list->addr); + vr->desc[i].len = list->length; + prev = i; + list++; + } + for ( ; in; i = vr->desc[i].next, in--) { + + vr->desc[i].flags = VRING_DESC_F_NEXT|VRING_DESC_F_WRITE; + vr->desc[i].addr = (u64)virt_to_phys(list->addr); + vr->desc[i].len = list->length; + prev = i; + list++; + } + vr->desc[prev].flags &= ~VRING_DESC_F_NEXT; + + vq->free_head = i; + + vq->vdata[head] = index; + + avail = (vr->avail->idx + num_added) % vr->num; + vr->avail->ring[avail] = head; + wmb(); +} + +void vring_kick(unsigned int ioaddr, struct vring_virtqueue *vq, int num_added) +{ + struct vring *vr = &vq->vring; + + wmb(); + vr->avail->idx += num_added; + + mb(); + if (!(vr->used->flags & VRING_USED_F_NO_NOTIFY)) + vp_notify(ioaddr, vq->queue_index); +} + diff --git a/gpxe/src/drivers/infiniband/arbel.c b/gpxe/src/drivers/infiniband/arbel.c index 1b55131b..1756a6e2 100644 --- a/gpxe/src/drivers/infiniband/arbel.c +++ b/gpxe/src/drivers/infiniband/arbel.c @@ -27,12 +27,14 @@ #include <unistd.h> #include <errno.h> #include <byteswap.h> +#include <gpxe/io.h> #include <gpxe/pci.h> #include <gpxe/malloc.h> #include <gpxe/umalloc.h> #include <gpxe/iobuf.h> #include <gpxe/netdevice.h> #include <gpxe/infiniband.h> +#include <gpxe/ib_smc.h> #include "arbel.h" /** @@ -484,6 +486,50 @@ arbel_cmd_map_fa ( struct arbel *arbel, /*************************************************************************** * + * MAD operations + * + *************************************************************************** + */ + +/** + * Issue management datagram + * + * @v ibdev Infiniband device + * @v mad Management datagram + * @ret rc Return status code + */ +static int arbel_mad ( struct ib_device *ibdev, union ib_mad *mad ) { + struct arbel *arbel = ib_get_drvdata ( ibdev ); + union arbelprm_mad mad_ifc; + int rc; + + linker_assert ( sizeof ( *mad ) == sizeof ( mad_ifc.mad ), + mad_size_mismatch ); + + /* Copy in request packet */ + memcpy ( &mad_ifc.mad, mad, sizeof ( mad_ifc.mad ) ); + + /* Issue MAD */ + if ( ( rc = arbel_cmd_mad_ifc ( arbel, ibdev->port, + &mad_ifc ) ) != 0 ) { + DBGC ( arbel, "Arbel %p could not issue MAD IFC: %s\n", + arbel, strerror ( rc ) ); + return rc; + } + + /* Copy out reply packet */ + memcpy ( mad, &mad_ifc.mad, sizeof ( *mad ) ); + + if ( mad->hdr.status != 0 ) { + DBGC ( arbel, "Arbel %p MAD IFC status %04x\n", + arbel, ntohs ( mad->hdr.status ) ); + return -EIO; + } + return 0; +} + +/*************************************************************************** + * * Completion queue operations * *************************************************************************** @@ -947,7 +993,7 @@ static void arbel_ring_doorbell ( struct arbel *arbel, union arbelprm_doorbell_register *db_reg, unsigned int offset ) { - DBGC2 ( arbel, "Arbel %p ringing doorbell %08lx:%08lx at %lx\n", + DBGC2 ( arbel, "Arbel %p ringing doorbell %08x:%08x at %lx\n", arbel, db_reg->dword[0], db_reg->dword[1], virt_to_phys ( arbel->uar + offset ) ); @@ -1006,7 +1052,7 @@ static int arbel_post_send ( struct ib_device *ibdev, ud_address_vector.pd, ARBEL_GLOBAL_PD, ud_address_vector.port_number, ibdev->port ); MLX_FILL_2 ( &wqe->ud, 1, - ud_address_vector.rlid, av->dlid, + ud_address_vector.rlid, av->lid, ud_address_vector.g, av->gid_present ); MLX_FILL_2 ( &wqe->ud, 2, ud_address_vector.max_stat_rate, @@ -1015,7 +1061,7 @@ static int arbel_post_send ( struct ib_device *ibdev, MLX_FILL_1 ( &wqe->ud, 3, ud_address_vector.sl, av->sl ); gid = ( av->gid_present ? &av->gid : &arbel_no_gid ); memcpy ( &wqe->ud.u.dwords[4], gid, sizeof ( *gid ) ); - MLX_FILL_1 ( &wqe->ud, 8, destination_qp, av->dest_qp ); + MLX_FILL_1 ( &wqe->ud, 8, destination_qp, av->qpn ); MLX_FILL_1 ( &wqe->ud, 9, q_key, av->qkey ); MLX_FILL_1 ( &wqe->data[0], 0, byte_count, iob_len ( iobuf ) ); MLX_FILL_1 ( &wqe->data[0], 1, l_key, arbel->reserved_lkey ); @@ -1106,17 +1152,12 @@ static int arbel_post_recv ( struct ib_device *ibdev, * @v ibdev Infiniband device * @v cq Completion queue * @v cqe Hardware completion queue entry - * @v complete_send Send completion handler - * @v complete_recv Receive completion handler * @ret rc Return status code */ static int arbel_complete ( struct ib_device *ibdev, struct ib_completion_queue *cq, - union arbelprm_completion_entry *cqe, - ib_completer_t complete_send, - ib_completer_t complete_recv ) { + union arbelprm_completion_entry *cqe ) { struct arbel *arbel = ib_get_drvdata ( ibdev ); - struct ib_completion completion; struct ib_work_queue *wq; struct ib_queue_pair *qp; struct arbel_queue_pair *arbel_qp; @@ -1124,16 +1165,17 @@ static int arbel_complete ( struct ib_device *ibdev, struct arbel_recv_work_queue *arbel_recv_wq; struct arbelprm_recv_wqe *recv_wqe; struct io_buffer *iobuf; - ib_completer_t complete; + struct ib_address_vector av; + struct ib_global_route_header *grh; unsigned int opcode; unsigned long qpn; int is_send; unsigned long wqe_adr; unsigned int wqe_idx; + size_t len; int rc = 0; /* Parse completion */ - memset ( &completion, 0, sizeof ( completion ) ); qpn = MLX_GET ( &cqe->normal, my_qpn ); is_send = MLX_GET ( &cqe->normal, s ); wqe_adr = ( MLX_GET ( &cqe->normal, wqe_adr ) << 6 ); @@ -1141,9 +1183,8 @@ static int arbel_complete ( struct ib_device *ibdev, if ( opcode >= ARBEL_OPCODE_RECV_ERROR ) { /* "s" field is not valid for error opcodes */ is_send = ( opcode == ARBEL_OPCODE_SEND_ERROR ); - completion.syndrome = MLX_GET ( &cqe->error, syndrome ); - DBGC ( arbel, "Arbel %p CPN %lx syndrome %x vendor %lx\n", - arbel, cq->cqn, completion.syndrome, + DBGC ( arbel, "Arbel %p CPN %lx syndrome %x vendor %x\n", + arbel, cq->cqn, MLX_GET ( &cqe->error, syndrome ), MLX_GET ( &cqe->error, vendor_code ) ); rc = -EIO; /* Don't return immediately; propagate error to completer */ @@ -1181,9 +1222,12 @@ static int arbel_complete ( struct ib_device *ibdev, } wq->iobufs[wqe_idx] = NULL; - /* Fill in length for received packets */ - if ( ! is_send ) { - completion.len = MLX_GET ( &cqe->normal, byte_cnt ); + if ( is_send ) { + /* Hand off to completion handler */ + ib_complete_send ( ibdev, qp, iobuf, rc ); + } else { + /* Set received length */ + len = MLX_GET ( &cqe->normal, byte_cnt ); recv_wqe = &arbel_recv_wq->wqe[wqe_idx].recv; assert ( MLX_GET ( &recv_wqe->data[0], local_address_l ) == virt_to_bus ( iobuf->data ) ); @@ -1192,18 +1236,22 @@ static int arbel_complete ( struct ib_device *ibdev, MLX_FILL_1 ( &recv_wqe->data[0], 0, byte_count, 0 ); MLX_FILL_1 ( &recv_wqe->data[0], 1, l_key, ARBEL_INVALID_LKEY ); - if ( completion.len > iob_tailroom ( iobuf ) ) { - DBGC ( arbel, "Arbel %p CQN %lx QPN %lx IDX %x " - "overlength received packet length %zd\n", - arbel, cq->cqn, qpn, wqe_idx, completion.len ); - return -EIO; - } + assert ( len <= iob_tailroom ( iobuf ) ); + iob_put ( iobuf, len ); + assert ( iob_len ( iobuf ) >= sizeof ( *grh ) ); + grh = iobuf->data; + iob_pull ( iobuf, sizeof ( *grh ) ); + /* Construct address vector */ + memset ( &av, 0, sizeof ( av ) ); + av.qpn = MLX_GET ( &cqe->normal, rqpn ); + av.lid = MLX_GET ( &cqe->normal, rlid ); + av.sl = MLX_GET ( &cqe->normal, sl ); + av.gid_present = MLX_GET ( &cqe->normal, g ); + memcpy ( &av.gid, &grh->sgid, sizeof ( av.gid ) ); + /* Hand off to completion handler */ + ib_complete_recv ( ibdev, qp, &av, iobuf, rc ); } - /* Pass off to caller's completion handler */ - complete = ( is_send ? complete_send : complete_recv ); - complete ( ibdev, qp, &completion, iobuf ); - return rc; } @@ -1212,13 +1260,9 @@ static int arbel_complete ( struct ib_device *ibdev, * * @v ibdev Infiniband device * @v cq Completion queue - * @v complete_send Send completion handler - * @v complete_recv Receive completion handler */ static void arbel_poll_cq ( struct ib_device *ibdev, - struct ib_completion_queue *cq, - ib_completer_t complete_send, - ib_completer_t complete_recv ) { + struct ib_completion_queue *cq ) { struct arbel *arbel = ib_get_drvdata ( ibdev ); struct arbel_completion_queue *arbel_cq = ib_cq_get_drvdata ( cq ); struct arbelprm_cq_ci_db_record *ci_db_rec; @@ -1236,8 +1280,7 @@ static void arbel_poll_cq ( struct ib_device *ibdev, } /* Handle completion */ - if ( ( rc = arbel_complete ( ibdev, cq, cqe, complete_send, - complete_recv ) ) != 0 ) { + if ( ( rc = arbel_complete ( ibdev, cq, cqe ) ) != 0 ) { DBGC ( arbel, "Arbel %p failed to complete: %s\n", arbel, strerror ( rc ) ); DBGC_HD ( arbel, cqe, sizeof ( *cqe ) ); @@ -1397,6 +1440,9 @@ static void arbel_event_port_state_change ( struct arbel *arbel, return; } + /* Update MAD parameters */ + ib_smc_update ( arbel->ibdev[port], arbel_mad ); + /* Notify Infiniband core of link state change */ ib_link_state_changed ( arbel->ibdev[port] ); } @@ -1447,7 +1493,7 @@ static void arbel_poll_eq ( struct ib_device *ibdev ) { /* Ring doorbell */ MLX_FILL_1 ( &db_reg.ci, 0, ci, arbel_eq->next_idx ); - DBGCP ( arbel, "Ringing doorbell %08lx with %08lx\n", + DBGCP ( arbel, "Ringing doorbell %08lx with %08x\n", virt_to_phys ( arbel_eq->doorbell ), db_reg.dword[0] ); writel ( db_reg.dword[0], arbel_eq->doorbell ); @@ -1486,6 +1532,9 @@ static int arbel_open ( struct ib_device *ibdev ) { return rc; } + /* Update MAD parameters */ + ib_smc_update ( ibdev, arbel_mad ); + return 0; } @@ -1601,51 +1650,6 @@ static void arbel_mcast_detach ( struct ib_device *ibdev, } } -/*************************************************************************** - * - * MAD operations - * - *************************************************************************** - */ - -/** - * Issue management datagram - * - * @v ibdev Infiniband device - * @v mad Management datagram - * @v len Length of management datagram - * @ret rc Return status code - */ -static int arbel_mad ( struct ib_device *ibdev, struct ib_mad_hdr *mad, - size_t len ) { - struct arbel *arbel = ib_get_drvdata ( ibdev ); - union arbelprm_mad mad_ifc; - int rc; - - /* Copy in request packet */ - memset ( &mad_ifc, 0, sizeof ( mad_ifc ) ); - assert ( len <= sizeof ( mad_ifc.mad ) ); - memcpy ( &mad_ifc.mad, mad, len ); - - /* Issue MAD */ - if ( ( rc = arbel_cmd_mad_ifc ( arbel, ibdev->port, - &mad_ifc ) ) != 0 ) { - DBGC ( arbel, "Arbel %p could not issue MAD IFC: %s\n", - arbel, strerror ( rc ) ); - return rc; - } - - /* Copy out reply packet */ - memcpy ( mad, &mad_ifc.mad, len ); - - if ( mad->status != 0 ) { - DBGC ( arbel, "Arbel %p MAD IFC status %04x\n", - arbel, ntohs ( mad->status ) ); - return -EIO; - } - return 0; -} - /** Arbel Infiniband operations */ static struct ib_device_operations arbel_ib_operations = { .create_cq = arbel_create_cq, @@ -1661,7 +1665,6 @@ static struct ib_device_operations arbel_ib_operations = { .close = arbel_close, .mcast_attach = arbel_mcast_attach, .mcast_detach = arbel_mcast_detach, - .mad = arbel_mad, }; /*************************************************************************** @@ -1694,7 +1697,7 @@ static int arbel_start_firmware ( struct arbel *arbel ) { arbel, strerror ( rc ) ); goto err_query_fw; } - DBGC ( arbel, "Arbel %p firmware version %ld.%ld.%ld\n", arbel, + DBGC ( arbel, "Arbel %p firmware version %d.%d.%d\n", arbel, MLX_GET ( &fw, fw_rev_major ), MLX_GET ( &fw, fw_rev_minor ), MLX_GET ( &fw, fw_rev_subminor ) ); fw_pages = MLX_GET ( &fw, fw_pages ); @@ -2172,6 +2175,10 @@ static int arbel_probe ( struct pci_device *pci, if ( ( rc = arbel_create_eq ( arbel ) ) != 0 ) goto err_create_eq; + /* Update MAD parameters */ + for ( i = 0 ; i < ARBEL_NUM_PORTS ; i++ ) + ib_smc_update ( arbel->ibdev[i], arbel_mad ); + /* Register Infiniband devices */ for ( i = 0 ; i < ARBEL_NUM_PORTS ; i++ ) { if ( ( rc = register_ibdev ( arbel->ibdev[i] ) ) != 0 ) { diff --git a/gpxe/src/drivers/infiniband/hermon.c b/gpxe/src/drivers/infiniband/hermon.c index 3ca60033..40add28a 100644 --- a/gpxe/src/drivers/infiniband/hermon.c +++ b/gpxe/src/drivers/infiniband/hermon.c @@ -25,12 +25,14 @@ #include <unistd.h> #include <errno.h> #include <byteswap.h> +#include <gpxe/io.h> #include <gpxe/pci.h> #include <gpxe/malloc.h> #include <gpxe/umalloc.h> #include <gpxe/iobuf.h> #include <gpxe/netdevice.h> #include <gpxe/infiniband.h> +#include <gpxe/ib_smc.h> #include "hermon.h" /** @@ -610,6 +612,50 @@ static void hermon_free_mtt ( struct hermon *hermon, /*************************************************************************** * + * MAD operations + * + *************************************************************************** + */ + +/** + * Issue management datagram + * + * @v ibdev Infiniband device + * @v mad Management datagram + * @ret rc Return status code + */ +static int hermon_mad ( struct ib_device *ibdev, union ib_mad *mad ) { + struct hermon *hermon = ib_get_drvdata ( ibdev ); + union hermonprm_mad mad_ifc; + int rc; + + linker_assert ( sizeof ( *mad ) == sizeof ( mad_ifc.mad ), + mad_size_mismatch ); + + /* Copy in request packet */ + memcpy ( &mad_ifc.mad, mad, sizeof ( mad_ifc.mad ) ); + + /* Issue MAD */ + if ( ( rc = hermon_cmd_mad_ifc ( hermon, ibdev->port, + &mad_ifc ) ) != 0 ) { + DBGC ( hermon, "Hermon %p could not issue MAD IFC: %s\n", + hermon, strerror ( rc ) ); + return rc; + } + + /* Copy out reply packet */ + memcpy ( mad, &mad_ifc.mad, sizeof ( *mad ) ); + + if ( mad->hdr.status != 0 ) { + DBGC ( hermon, "Hermon %p MAD IFC status %04x\n", + hermon, ntohs ( mad->hdr.status ) ); + return -EIO; + } + return 0; +} + +/*************************************************************************** + * * Completion queue operations * *************************************************************************** @@ -1015,7 +1061,7 @@ static int hermon_post_send ( struct ib_device *ibdev, ud_address_vector.pd, HERMON_GLOBAL_PD, ud_address_vector.port_number, ibdev->port ); MLX_FILL_2 ( &wqe->ud, 1, - ud_address_vector.rlid, av->dlid, + ud_address_vector.rlid, av->lid, ud_address_vector.g, av->gid_present ); MLX_FILL_1 ( &wqe->ud, 2, ud_address_vector.max_stat_rate, @@ -1024,7 +1070,7 @@ static int hermon_post_send ( struct ib_device *ibdev, MLX_FILL_1 ( &wqe->ud, 3, ud_address_vector.sl, av->sl ); gid = ( av->gid_present ? &av->gid : &hermon_no_gid ); memcpy ( &wqe->ud.u.dwords[4], gid, sizeof ( *gid ) ); - MLX_FILL_1 ( &wqe->ud, 8, destination_qp, av->dest_qp ); + MLX_FILL_1 ( &wqe->ud, 8, destination_qp, av->qpn ); MLX_FILL_1 ( &wqe->ud, 9, q_key, av->qkey ); MLX_FILL_1 ( &wqe->data[0], 0, byte_count, iob_len ( iobuf ) ); MLX_FILL_1 ( &wqe->data[0], 1, l_key, hermon->reserved_lkey ); @@ -1041,7 +1087,7 @@ static int hermon_post_send ( struct ib_device *ibdev, /* Ring doorbell register */ MLX_FILL_1 ( &db_reg.send, 0, qn, qp->qpn ); - DBGCP ( hermon, "Ringing doorbell %08lx with %08lx\n", + DBGCP ( hermon, "Ringing doorbell %08lx with %08x\n", virt_to_phys ( hermon_send_wq->doorbell ), db_reg.dword[0] ); writel ( db_reg.dword[0], ( hermon_send_wq->doorbell ) ); @@ -1101,39 +1147,34 @@ static int hermon_post_recv ( struct ib_device *ibdev, * @v ibdev Infiniband device * @v cq Completion queue * @v cqe Hardware completion queue entry - * @v complete_send Send completion handler - * @v complete_recv Receive completion handler * @ret rc Return status code */ static int hermon_complete ( struct ib_device *ibdev, struct ib_completion_queue *cq, - union hermonprm_completion_entry *cqe, - ib_completer_t complete_send, - ib_completer_t complete_recv ) { + union hermonprm_completion_entry *cqe ) { struct hermon *hermon = ib_get_drvdata ( ibdev ); - struct ib_completion completion; struct ib_work_queue *wq; struct ib_queue_pair *qp; struct hermon_queue_pair *hermon_qp; struct io_buffer *iobuf; - ib_completer_t complete; + struct ib_address_vector av; + struct ib_global_route_header *grh; unsigned int opcode; unsigned long qpn; int is_send; unsigned int wqe_idx; + size_t len; int rc = 0; /* Parse completion */ - memset ( &completion, 0, sizeof ( completion ) ); qpn = MLX_GET ( &cqe->normal, qpn ); is_send = MLX_GET ( &cqe->normal, s_r ); opcode = MLX_GET ( &cqe->normal, opcode ); if ( opcode >= HERMON_OPCODE_RECV_ERROR ) { /* "s" field is not valid for error opcodes */ is_send = ( opcode == HERMON_OPCODE_SEND_ERROR ); - completion.syndrome = MLX_GET ( &cqe->error, syndrome ); - DBGC ( hermon, "Hermon %p CQN %lx syndrome %x vendor %lx\n", - hermon, cq->cqn, completion.syndrome, + DBGC ( hermon, "Hermon %p CQN %lx syndrome %x vendor %x\n", + hermon, cq->cqn, MLX_GET ( &cqe->error, syndrome ), MLX_GET ( &cqe->error, vendor_error_syndrome ) ); rc = -EIO; /* Don't return immediately; propagate error to completer */ @@ -1160,21 +1201,28 @@ static int hermon_complete ( struct ib_device *ibdev, } wq->iobufs[wqe_idx] = NULL; - /* Fill in length for received packets */ - if ( ! is_send ) { - completion.len = MLX_GET ( &cqe->normal, byte_cnt ); - if ( completion.len > iob_tailroom ( iobuf ) ) { - DBGC ( hermon, "Hermon %p CQN %lx QPN %lx IDX %x " - "overlength received packet length %zd\n", - hermon, cq->cqn, qpn, wqe_idx, completion.len ); - return -EIO; - } + if ( is_send ) { + /* Hand off to completion handler */ + ib_complete_send ( ibdev, qp, iobuf, rc ); + } else { + /* Set received length */ + len = MLX_GET ( &cqe->normal, byte_cnt ); + assert ( len <= iob_tailroom ( iobuf ) ); + iob_put ( iobuf, len ); + assert ( iob_len ( iobuf ) >= sizeof ( *grh ) ); + grh = iobuf->data; + iob_pull ( iobuf, sizeof ( *grh ) ); + /* Construct address vector */ + memset ( &av, 0, sizeof ( av ) ); + av.qpn = MLX_GET ( &cqe->normal, srq_rqpn ); + av.lid = MLX_GET ( &cqe->normal, slid_smac47_32 ); + av.sl = MLX_GET ( &cqe->normal, sl ); + av.gid_present = MLX_GET ( &cqe->normal, g ); + memcpy ( &av.gid, &grh->sgid, sizeof ( av.gid ) ); + /* Hand off to completion handler */ + ib_complete_recv ( ibdev, qp, &av, iobuf, rc ); } - /* Pass off to caller's completion handler */ - complete = ( is_send ? complete_send : complete_recv ); - complete ( ibdev, qp, &completion, iobuf ); - return rc; } @@ -1183,13 +1231,9 @@ static int hermon_complete ( struct ib_device *ibdev, * * @v ibdev Infiniband device * @v cq Completion queue - * @v complete_send Send completion handler - * @v complete_recv Receive completion handler */ static void hermon_poll_cq ( struct ib_device *ibdev, - struct ib_completion_queue *cq, - ib_completer_t complete_send, - ib_completer_t complete_recv ) { + struct ib_completion_queue *cq ) { struct hermon *hermon = ib_get_drvdata ( ibdev ); struct hermon_completion_queue *hermon_cq = ib_cq_get_drvdata ( cq ); union hermonprm_completion_entry *cqe; @@ -1209,8 +1253,7 @@ static void hermon_poll_cq ( struct ib_device *ibdev, DBGCP_HD ( hermon, cqe, sizeof ( *cqe ) ); /* Handle completion */ - if ( ( rc = hermon_complete ( ibdev, cq, cqe, complete_send, - complete_recv ) ) != 0 ) { + if ( ( rc = hermon_complete ( ibdev, cq, cqe ) ) != 0 ) { DBGC ( hermon, "Hermon %p failed to complete: %s\n", hermon, strerror ( rc ) ); DBGC_HD ( hermon, cqe, sizeof ( *cqe ) ); @@ -1380,6 +1423,9 @@ static void hermon_event_port_state_change ( struct hermon *hermon, return; } + /* Update MAD parameters */ + ib_smc_update ( hermon->ibdev[port], hermon_mad ); + /* Notify Infiniband core of link state change */ ib_link_state_changed ( hermon->ibdev[port] ); } @@ -1428,7 +1474,7 @@ static void hermon_poll_eq ( struct ib_device *ibdev ) { /* Ring doorbell */ MLX_FILL_1 ( &db_reg.event, 0, ci, ( hermon_eq->next_idx & 0x00ffffffUL ) ); - DBGCP ( hermon, "Ringing doorbell %08lx with %08lx\n", + DBGCP ( hermon, "Ringing doorbell %08lx with %08x\n", virt_to_phys ( hermon_eq->doorbell ), db_reg.dword[0] ); writel ( db_reg.dword[0], hermon_eq->doorbell ); @@ -1468,6 +1514,9 @@ static int hermon_open ( struct ib_device *ibdev ) { return rc; } + /* Update MAD parameters */ + ib_smc_update ( ibdev, hermon_mad ); + return 0; } @@ -1582,51 +1631,6 @@ static void hermon_mcast_detach ( struct ib_device *ibdev, } } -/*************************************************************************** - * - * MAD operations - * - *************************************************************************** - */ - -/** - * Issue management datagram - * - * @v ibdev Infiniband device - * @v mad Management datagram - * @v len Length of management datagram - * @ret rc Return status code - */ -static int hermon_mad ( struct ib_device *ibdev, struct ib_mad_hdr *mad, - size_t len ) { - struct hermon *hermon = ib_get_drvdata ( ibdev ); - union hermonprm_mad mad_ifc; - int rc; - - /* Copy in request packet */ - memset ( &mad_ifc, 0, sizeof ( mad_ifc ) ); - assert ( len <= sizeof ( mad_ifc.mad ) ); - memcpy ( &mad_ifc.mad, mad, len ); - - /* Issue MAD */ - if ( ( rc = hermon_cmd_mad_ifc ( hermon, ibdev->port, - &mad_ifc ) ) != 0 ) { - DBGC ( hermon, "Hermon %p could not issue MAD IFC: %s\n", - hermon, strerror ( rc ) ); - return rc; - } - - /* Copy out reply packet */ - memcpy ( mad, &mad_ifc.mad, len ); - - if ( mad->status != 0 ) { - DBGC ( hermon, "Hermon %p MAD IFC status %04x\n", - hermon, ntohs ( mad->status ) ); - return -EIO; - } - return 0; -} - /** Hermon Infiniband operations */ static struct ib_device_operations hermon_ib_operations = { .create_cq = hermon_create_cq, @@ -1642,7 +1646,6 @@ static struct ib_device_operations hermon_ib_operations = { .close = hermon_close, .mcast_attach = hermon_mcast_attach, .mcast_detach = hermon_mcast_detach, - .mad = hermon_mad, }; /*************************************************************************** @@ -1712,7 +1715,7 @@ static int hermon_start_firmware ( struct hermon *hermon ) { hermon, strerror ( rc ) ); goto err_query_fw; } - DBGC ( hermon, "Hermon %p firmware version %ld.%ld.%ld\n", hermon, + DBGC ( hermon, "Hermon %p firmware version %d.%d.%d\n", hermon, MLX_GET ( &fw, fw_rev_major ), MLX_GET ( &fw, fw_rev_minor ), MLX_GET ( &fw, fw_rev_subminor ) ); fw_pages = MLX_GET ( &fw, fw_pages ); @@ -2241,6 +2244,10 @@ static int hermon_probe ( struct pci_device *pci, if ( ( rc = hermon_create_eq ( hermon ) ) != 0 ) goto err_create_eq; + /* Update MAD parameters */ + for ( i = 0 ; i < HERMON_NUM_PORTS ; i++ ) + ib_smc_update ( hermon->ibdev[i], hermon_mad ); + /* Register Infiniband devices */ for ( i = 0 ; i < HERMON_NUM_PORTS ; i++ ) { if ( ( rc = register_ibdev ( hermon->ibdev[i] ) ) != 0 ) { @@ -2306,6 +2313,7 @@ static struct pci_device_id hermon_nics[] = { PCI_ROM ( 0x15b3, 0x6340, "mt25408", "MT25408 HCA driver" ), PCI_ROM ( 0x15b3, 0x634a, "mt25418", "MT25418 HCA driver" ), PCI_ROM ( 0x15b3, 0x6732, "mt26418", "MT26418 HCA driver" ), + PCI_ROM ( 0x15b3, 0x673c, "mt26428", "MT26428 HCA driver" ), }; struct pci_driver hermon_driver __pci_driver = { diff --git a/gpxe/src/drivers/infiniband/ib_packet.c b/gpxe/src/drivers/infiniband/ib_packet.c new file mode 100644 index 00000000..0f21617f --- /dev/null +++ b/gpxe/src/drivers/infiniband/ib_packet.c @@ -0,0 +1,234 @@ +/* + * 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., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +#include <stdint.h> +#include <stdlib.h> +#include <string.h> +#include <errno.h> +#include <byteswap.h> +#include <gpxe/iobuf.h> +#include <gpxe/infiniband.h> +#include <gpxe/ib_packet.h> + +/** + * @file + * + * Infiniband Packet Formats + * + */ + +/** + * Add IB headers + * + * @v ibdev Infiniband device + * @v iobuf I/O buffer to contain headers + * @v qp Queue pair + * @v payload_len Payload length + * @v av Address vector + */ +int ib_push ( struct ib_device *ibdev, struct io_buffer *iobuf, + struct ib_queue_pair *qp, size_t payload_len, + const struct ib_address_vector *av ) { + struct ib_local_route_header *lrh; + struct ib_global_route_header *grh; + struct ib_base_transport_header *bth; + struct ib_datagram_extended_transport_header *deth; + size_t orig_iob_len = iob_len ( iobuf ); + size_t pad_len; + size_t lrh_len; + size_t grh_len; + unsigned int vl; + unsigned int lnh; + + DBGC2 ( ibdev, "IBDEV %p TX %04x:%08lx => %04x:%08lx (key %08lx)\n", + ibdev, ibdev->lid, qp->qpn, av->lid, av->qpn, av->qkey ); + + /* Calculate packet length */ + pad_len = ( (-payload_len) & 0x3 ); + payload_len += pad_len; + payload_len += 4; /* ICRC */ + + /* Reserve space for headers */ + orig_iob_len = iob_len ( iobuf ); + deth = iob_push ( iobuf, sizeof ( *deth ) ); + bth = iob_push ( iobuf, sizeof ( *bth ) ); + grh_len = ( payload_len + iob_len ( iobuf ) - orig_iob_len ); + grh = ( av->gid_present ? + iob_push ( iobuf, sizeof ( *grh ) ) : NULL ); + lrh = iob_push ( iobuf, sizeof ( *lrh ) ); + lrh_len = ( payload_len + iob_len ( iobuf ) - orig_iob_len ); + + /* Construct LRH */ + vl = ( ( av->qpn == IB_QPN_SMP ) ? IB_VL_SMP : IB_VL_DEFAULT ); + lrh->vl__lver = ( vl << 4 ); + lnh = ( grh ? IB_LNH_GRH : IB_LNH_BTH ); + lrh->sl__lnh = ( ( av->sl << 4 ) | lnh ); + lrh->dlid = htons ( av->lid ); + lrh->length = htons ( lrh_len >> 2 ); + lrh->slid = htons ( ibdev->lid ); + + /* Construct GRH, if required */ + if ( grh ) { + grh->ipver__tclass__flowlabel = + htonl ( IB_GRH_IPVER_IPv6 << 28 ); + grh->paylen = htons ( grh_len ); + grh->nxthdr = IB_GRH_NXTHDR_IBA; + grh->hoplmt = 0; + memcpy ( &grh->sgid, &ibdev->gid, sizeof ( grh->sgid ) ); + memcpy ( &grh->dgid, &av->gid, sizeof ( grh->dgid ) ); + } + + /* Construct BTH */ + bth->opcode = BTH_OPCODE_UD_SEND; + bth->se__m__padcnt__tver = ( pad_len << 4 ); + bth->pkey = htons ( ibdev->pkey ); + bth->dest_qp = htonl ( av->qpn ); + bth->ack__psn = htonl ( ( ibdev->psn++ ) & 0xffffffUL ); + + /* Construct DETH */ + deth->qkey = htonl ( av->qkey ); + deth->src_qp = htonl ( qp->qpn ); + + DBGCP_HDA ( ibdev, 0, iobuf->data, + ( iob_len ( iobuf ) - orig_iob_len ) ); + + return 0; +} + +/** + * Remove IB headers + * + * @v ibdev Infiniband device + * @v iobuf I/O buffer containing headers + * @v qp Queue pair to fill in, or NULL + * @v payload_len Payload length to fill in, or NULL + * @v av Address vector to fill in + */ +int ib_pull ( struct ib_device *ibdev, struct io_buffer *iobuf, + struct ib_queue_pair **qp, size_t *payload_len, + struct ib_address_vector *av ) { + struct ib_local_route_header *lrh; + struct ib_global_route_header *grh; + struct ib_base_transport_header *bth; + struct ib_datagram_extended_transport_header *deth; + size_t orig_iob_len = iob_len ( iobuf ); + unsigned int lnh; + size_t pad_len; + unsigned long qpn; + unsigned int lid; + + /* Clear return values */ + if ( qp ) + *qp = NULL; + if ( payload_len ) + *payload_len = 0; + memset ( av, 0, sizeof ( *av ) ); + + /* Extract LRH */ + if ( iob_len ( iobuf ) < sizeof ( *lrh ) ) { + DBGC ( ibdev, "IBDEV %p RX too short (%zd bytes) for LRH\n", + ibdev, iob_len ( iobuf ) ); + return -EINVAL; + } + lrh = iobuf->data; + iob_pull ( iobuf, sizeof ( *lrh ) ); + av->lid = ntohs ( lrh->slid ); + av->sl = ( lrh->sl__lnh >> 4 ); + lnh = ( lrh->sl__lnh & 0x3 ); + lid = ntohs ( lrh->dlid ); + + /* Reject unsupported packets */ + if ( ! ( ( lnh == IB_LNH_BTH ) || ( lnh == IB_LNH_GRH ) ) ) { + DBGC ( ibdev, "IBDEV %p RX unsupported LNH %x\n", + ibdev, lnh ); + return -ENOTSUP; + } + + /* Extract GRH, if present */ + if ( lnh == IB_LNH_GRH ) { + if ( iob_len ( iobuf ) < sizeof ( *grh ) ) { + DBGC ( ibdev, "IBDEV %p RX too short (%zd bytes) " + "for GRH\n", ibdev, iob_len ( iobuf ) ); + return -EINVAL; + } + grh = iobuf->data; + iob_pull ( iobuf, sizeof ( *grh ) ); + av->gid_present = 1; + memcpy ( &av->gid, &grh->sgid, sizeof ( av->gid ) ); + } else { + grh = NULL; + } + + /* Extract BTH */ + if ( iob_len ( iobuf ) < sizeof ( *bth ) ) { + DBGC ( ibdev, "IBDEV %p RX too short (%zd bytes) for BTH\n", + ibdev, iob_len ( iobuf ) ); + return -EINVAL; + } + bth = iobuf->data; + iob_pull ( iobuf, sizeof ( *bth ) ); + if ( bth->opcode != BTH_OPCODE_UD_SEND ) { + DBGC ( ibdev, "IBDEV %p unsupported BTH opcode %x\n", + ibdev, bth->opcode ); + return -ENOTSUP; + } + qpn = ntohl ( bth->dest_qp ); + + /* Extract DETH */ + if ( iob_len ( iobuf ) < sizeof ( *deth ) ) { + DBGC ( ibdev, "IBDEV %p RX too short (%zd bytes) for DETH\n", + ibdev, iob_len ( iobuf ) ); + return -EINVAL; + } + deth = iobuf->data; + iob_pull ( iobuf, sizeof ( *deth ) ); + av->qpn = ntohl ( deth->src_qp ); + av->qkey = ntohl ( deth->qkey ); + + /* Calculate payload length, if applicable */ + if ( payload_len ) { + pad_len = ( ( bth->se__m__padcnt__tver >> 4 ) & 0x3 ); + *payload_len = ( ( ntohs ( lrh->length ) << 2 ) + - ( orig_iob_len - iob_len ( iobuf ) ) + - pad_len - 4 /* ICRC */ ); + } + + /* Determine destination QP, if applicable */ + if ( qp ) { + if ( IB_LID_MULTICAST ( lid ) && grh ) { + *qp = ib_find_qp_mgid ( ibdev, &grh->dgid ); + } else { + *qp = ib_find_qp_qpn ( ibdev, qpn ); + } + if ( ! *qp ) { + DBGC ( ibdev, "IBDEV %p RX for nonexistent QP\n", + ibdev ); + return -ENODEV; + } + } + + DBGC2 ( ibdev, "IBDEV %p RX %04x:%08lx <= %04x:%08lx (key %08x)\n", + ibdev, lid, + ( IB_LID_MULTICAST( lid ) ? ( qp ? (*qp)->qpn : -1UL ) : qpn ), + av->lid, av->qpn, ntohl ( deth->qkey ) ); + DBGCP_HDA ( ibdev, 0, + ( iobuf->data - ( orig_iob_len - iob_len ( iobuf ) ) ), + ( orig_iob_len - iob_len ( iobuf ) ) ); + + return 0; +} diff --git a/gpxe/src/drivers/infiniband/ib_sma.c b/gpxe/src/drivers/infiniband/ib_sma.c new file mode 100644 index 00000000..2bd3a9e8 --- /dev/null +++ b/gpxe/src/drivers/infiniband/ib_sma.c @@ -0,0 +1,553 @@ +/* + * 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., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +#include <stdint.h> +#include <stdlib.h> +#include <string.h> +#include <errno.h> +#include <stdio.h> +#include <unistd.h> +#include <byteswap.h> +#include <gpxe/infiniband.h> +#include <gpxe/iobuf.h> +#include <gpxe/process.h> +#include <gpxe/ib_sma.h> + +/** + * @file + * + * Infiniband Subnet Management Agent + * + */ + +/** + * Get node information + * + * @v sma Subnet management agent + * @v get Attribute to get + */ +static void ib_sma_get_node_info ( struct ib_sma *sma, + union ib_smp_data *get ) { + struct ib_device *ibdev = sma->ibdev; + struct ib_node_info *node_info = &get->node_info; + struct ib_device *tmp; + + memset ( node_info, 0, sizeof ( *node_info ) ); + node_info->base_version = IB_MGMT_BASE_VERSION; + node_info->class_version = IB_SMP_CLASS_VERSION; + node_info->node_type = IB_NODE_TYPE_HCA; + /* Search for IB devices with the same physical device to + * identify port count and a suitable Node GUID. + */ + for_each_ibdev ( tmp ) { + if ( tmp->dev != ibdev->dev ) + continue; + if ( node_info->num_ports == 0 ) { + memcpy ( node_info->sys_guid, &tmp->gid.u.half[1], + sizeof ( node_info->sys_guid ) ); + memcpy ( node_info->node_guid, &tmp->gid.u.half[1], + sizeof ( node_info->node_guid ) ); + } + node_info->num_ports++; + } + memcpy ( node_info->port_guid, &ibdev->gid.u.half[1], + sizeof ( node_info->port_guid ) ); + node_info->partition_cap = htons ( 1 ); + node_info->local_port_num = ibdev->port; +} + +/** + * Get node description + * + * @v sma Subnet management agent + * @v get Attribute to get + */ +static void ib_sma_get_node_desc ( struct ib_sma *sma, + union ib_smp_data *get ) { + struct ib_device *ibdev = sma->ibdev; + struct ib_node_desc *node_desc = &get->node_desc; + struct ib_gid_half *guid = &ibdev->gid.u.half[1]; + + memset ( node_desc, 0, sizeof ( *node_desc ) ); + snprintf ( node_desc->node_string, sizeof ( node_desc->node_string ), + "gPXE %02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x (%s)", + guid->bytes[0], guid->bytes[1], guid->bytes[2], + guid->bytes[3], guid->bytes[4], guid->bytes[5], + guid->bytes[6], guid->bytes[7], ibdev->dev->name ); +} + +/** + * Get GUID information + * + * @v sma Subnet management agent + * @v get Attribute to get + */ +static void ib_sma_get_guid_info ( struct ib_sma *sma, + union ib_smp_data *get ) { + struct ib_device *ibdev = sma->ibdev; + struct ib_guid_info *guid_info = &get->guid_info; + + memset ( guid_info, 0, sizeof ( *guid_info ) ); + memcpy ( guid_info->guid[0], &ibdev->gid.u.half[1], + sizeof ( guid_info->guid[0] ) ); +} + +/** + * Get port information + * + * @v sma Subnet management agent + * @v get Attribute to get + */ +static void ib_sma_get_port_info ( struct ib_sma *sma, + union ib_smp_data *get ) { + struct ib_device *ibdev = sma->ibdev; + struct ib_port_info *port_info = &get->port_info; + + memset ( port_info, 0, sizeof ( *port_info ) ); + memcpy ( port_info->gid_prefix, &ibdev->gid.u.half[0], + sizeof ( port_info->gid_prefix ) ); + port_info->lid = ntohs ( ibdev->lid ); + port_info->mastersm_lid = ntohs ( ibdev->sm_lid ); + port_info->local_port_num = ibdev->port; + port_info->link_width_enabled = ibdev->link_width; + port_info->link_width_supported = ibdev->link_width; + port_info->link_width_active = ibdev->link_width; + port_info->link_speed_supported__port_state = + ( ( ibdev->link_speed << 4 ) | ibdev->port_state ); + port_info->port_phys_state__link_down_def_state = + ( ( IB_PORT_PHYS_STATE_POLLING << 4 ) | + IB_PORT_PHYS_STATE_POLLING ); + port_info->link_speed_active__link_speed_enabled = + ( ( ibdev->link_speed << 4 ) | ibdev->link_speed ); + port_info->neighbour_mtu__mastersm_sl = + ( ( IB_MTU_2048 << 4 ) | ibdev->sm_sl ); + port_info->vl_cap__init_type = ( IB_VL_0 << 4 ); + port_info->init_type_reply__mtu_cap = IB_MTU_2048; + port_info->operational_vls__enforcement = ( IB_VL_0 << 4 ); + port_info->guid_cap = 1; +} + +/** + * Set port information + * + * @v sma Subnet management agent + * @v set Attribute to set + * @ret rc Return status code + */ +static int ib_sma_set_port_info ( struct ib_sma *sma, + const union ib_smp_data *set ) { + struct ib_device *ibdev = sma->ibdev; + const struct ib_port_info *port_info = &set->port_info; + + memcpy ( &ibdev->gid.u.half[0], port_info->gid_prefix, + sizeof ( ibdev->gid.u.half[0] ) ); + ibdev->lid = ntohs ( port_info->lid ); + ibdev->sm_lid = ntohs ( port_info->mastersm_lid ); + ibdev->sm_sl = ( port_info->neighbour_mtu__mastersm_sl & 0xf ); + + if ( ! sma->op->set_port_info ) { + /* Not an error; we just ignore all other settings */ + return 0; + } + + return sma->op->set_port_info ( ibdev, port_info ); +} + +/** + * Get partition key table + * + * @v sma Subnet management agent + * @v get Attribute to get + */ +static void ib_sma_get_pkey_table ( struct ib_sma *sma, + union ib_smp_data *get ) { + struct ib_device *ibdev = sma->ibdev; + struct ib_pkey_table *pkey_table = &get->pkey_table; + + memset ( pkey_table, 0, sizeof ( *pkey_table ) ); + pkey_table->pkey[0] = htons ( ibdev->pkey ); +} + +/** + * Set partition key table + * + * @v sma Subnet management agent + * @v set Attribute to set + */ +static int ib_sma_set_pkey_table ( struct ib_sma *sma, + const union ib_smp_data *get ) { + struct ib_device *ibdev = sma->ibdev; + const struct ib_pkey_table *pkey_table = &get->pkey_table; + + ibdev->pkey = ntohs ( pkey_table->pkey[0] ); + return 0; +} + +/** An attribute handler */ +struct ib_sma_handler { + /** Attribute (in network byte order) */ + uint16_t attr_id; + /** Get attribute + * + * @v sma Subnet management agent + * @v get Attribute to get + * @ret rc Return status code + */ + void ( * get ) ( struct ib_sma *sma, union ib_smp_data *get ); + /** Set attribute + * + * @v sma Subnet management agent + * @v set Attribute to set + * @ret rc Return status code + */ + int ( * set ) ( struct ib_sma *sma, const union ib_smp_data *set ); +}; + +/** List of attribute handlers */ +static struct ib_sma_handler ib_sma_handlers[] = { + { htons ( IB_SMP_ATTR_NODE_DESC ), + ib_sma_get_node_desc, NULL }, + { htons ( IB_SMP_ATTR_NODE_INFO ), + ib_sma_get_node_info, NULL }, + { htons ( IB_SMP_ATTR_GUID_INFO ), + ib_sma_get_guid_info, NULL }, + { htons ( IB_SMP_ATTR_PORT_INFO ), + ib_sma_get_port_info, ib_sma_set_port_info }, + { htons ( IB_SMP_ATTR_PKEY_TABLE ), + ib_sma_get_pkey_table, ib_sma_set_pkey_table }, +}; + +/** + * Identify attribute handler + * + * @v attr_id Attribute ID (in network byte order) + * @ret handler Attribute handler (or NULL) + */ +static struct ib_sma_handler * ib_sma_handler ( uint16_t attr_id ) { + struct ib_sma_handler *handler; + unsigned int i; + + for ( i = 0 ; i < ( sizeof ( ib_sma_handlers ) / + sizeof ( ib_sma_handlers[0] ) ) ; i++ ) { + handler = &ib_sma_handlers[i]; + if ( handler->attr_id == attr_id ) + return handler; + } + + return NULL; +} + +/** + * Respond to management datagram + * + * @v sma Subnet management agent + * @v mad Management datagram + * @ret rc Return status code + */ +static int ib_sma_mad ( struct ib_sma *sma, union ib_mad *mad ) { + struct ib_device *ibdev = sma->ibdev; + struct ib_mad_hdr *hdr = &mad->hdr; + struct ib_mad_smp *smp = &mad->smp; + struct ib_sma_handler *handler = NULL; + unsigned int hop_pointer; + unsigned int hop_count; + int rc; + + DBGC ( sma, "SMA %p received SMP with bv=%02x mc=%02x cv=%02x " + "meth=%02x attr=%04x mod=%08x\n", sma, hdr->base_version, + hdr->mgmt_class, hdr->class_version, hdr->method, + ntohs ( hdr->attr_id ), ntohl ( hdr->attr_mod ) ); + DBGC2_HDA ( sma, 0, mad, sizeof ( *mad ) ); + + /* Sanity checks */ + if ( hdr->base_version != IB_MGMT_BASE_VERSION ) { + DBGC ( sma, "SMA %p unsupported base version %x\n", + sma, hdr->base_version ); + return -ENOTSUP; + } + if ( ( hdr->mgmt_class != IB_MGMT_CLASS_SUBN_DIRECTED_ROUTE ) && + ( hdr->mgmt_class != IB_MGMT_CLASS_SUBN_LID_ROUTED ) ) { + DBGC ( sma, "SMA %p unsupported management class %x\n", + sma, hdr->mgmt_class ); + return -ENOTSUP; + } + if ( hdr->class_version != IB_SMP_CLASS_VERSION ) { + DBGC ( sma, "SMA %p unsupported class version %x\n", + sma, hdr->class_version ); + return -ENOTSUP; + } + if ( ( hdr->method != IB_MGMT_METHOD_GET ) && + ( hdr->method != IB_MGMT_METHOD_SET ) ) { + DBGC ( sma, "SMA %p unsupported method %x\n", + sma, hdr->method ); + return -ENOTSUP; + } + + /* Identify handler */ + if ( ! ( handler = ib_sma_handler ( hdr->attr_id ) ) ) { + DBGC ( sma, "SMA %p unsupported attribute %x\n", + sma, ntohs ( hdr->attr_id ) ); + hdr->status = htons ( IB_MGMT_STATUS_UNSUPPORTED_METHOD_ATTR ); + goto respond_without_data; + } + + /* Set attribute (if applicable) */ + if ( hdr->method != IB_MGMT_METHOD_SET ) { + hdr->status = htons ( IB_MGMT_STATUS_OK ); + goto respond; + } + if ( ! handler->set ) { + DBGC ( sma, "SMA %p attribute %x is unsettable\n", + sma, ntohs ( hdr->attr_id ) ); + hdr->status = htons ( IB_MGMT_STATUS_UNSUPPORTED_METHOD_ATTR ); + goto respond; + } + if ( ( rc = handler->set ( sma, &smp->smp_data ) ) != 0 ) { + DBGC ( sma, "SMA %p could not set attribute %x: %s\n", + sma, ntohs ( hdr->attr_id ), strerror ( rc ) ); + hdr->status = htons ( IB_MGMT_STATUS_UNSUPPORTED_METHOD_ATTR ); + goto respond; + } + + hdr->status = htons ( IB_MGMT_STATUS_OK ); + + respond: + /* Get attribute */ + handler->get ( sma, &smp->smp_data ); + + respond_without_data: + + /* Set method to "Get Response" */ + hdr->method = IB_MGMT_METHOD_GET_RESP; + + /* Set response fields for directed route SMPs */ + if ( hdr->mgmt_class == IB_MGMT_CLASS_SUBN_DIRECTED_ROUTE ) { + hdr->status |= htons ( IB_SMP_STATUS_D_INBOUND ); + hop_pointer = smp->mad_hdr.class_specific.smp.hop_pointer; + hop_count = smp->mad_hdr.class_specific.smp.hop_count; + assert ( hop_count == hop_pointer ); + if ( hop_pointer < ( sizeof ( smp->return_path.hops ) / + sizeof ( smp->return_path.hops[0] ) ) ) { + smp->return_path.hops[hop_pointer] = ibdev->port; + } else { + DBGC ( sma, "SMA %p invalid hop pointer %d\n", + sma, hop_pointer ); + return -EINVAL; + } + } + + DBGC ( sma, "SMA %p responding with status=%04x\n", + sma, ntohs ( hdr->status ) ); + DBGC2_HDA ( sma, 0, mad, sizeof ( *mad ) ); + + return 0; +} + +/** + * Refill SMA receive ring + * + * @v sma Subnet management agent + */ +static void ib_sma_refill_recv ( struct ib_sma *sma ) { + struct ib_device *ibdev = sma->ibdev; + struct io_buffer *iobuf; + int rc; + + while ( sma->qp->recv.fill < IB_SMA_NUM_RECV_WQES ) { + + /* Allocate I/O buffer */ + iobuf = alloc_iob ( IB_SMA_PAYLOAD_LEN ); + if ( ! iobuf ) { + /* Non-fatal; we will refill on next attempt */ + return; + } + + /* Post I/O buffer */ + if ( ( rc = ib_post_recv ( ibdev, sma->qp, iobuf ) ) != 0 ) { + DBGC ( sma, "SMA %p could not refill: %s\n", + sma, strerror ( rc ) ); + free_iob ( iobuf ); + /* Give up */ + return; + } + } +} + +/** + * Complete SMA send + * + * + * @v ibdev Infiniband device + * @v qp Queue pair + * @v iobuf I/O buffer + * @v rc Completion status code + */ +static void ib_sma_complete_send ( struct ib_device *ibdev __unused, + struct ib_queue_pair *qp, + struct io_buffer *iobuf, int rc ) { + struct ib_sma *sma = ib_qp_get_ownerdata ( qp ); + + if ( rc != 0 ) { + DBGC ( sma, "SMA %p send completion error: %s\n", + sma, strerror ( rc ) ); + } + free_iob ( iobuf ); +} + +/** + * Complete SMA receive + * + * + * @v ibdev Infiniband device + * @v qp Queue pair + * @v av Address vector + * @v iobuf I/O buffer + * @v rc Completion status code + */ +static void ib_sma_complete_recv ( struct ib_device *ibdev, + struct ib_queue_pair *qp, + struct ib_address_vector *av, + struct io_buffer *iobuf, int rc ) { + struct ib_sma *sma = ib_qp_get_ownerdata ( qp ); + union ib_mad *mad; + + /* Ignore errors */ + if ( rc != 0 ) { + DBGC ( sma, "SMA %p RX error: %s\n", sma, strerror ( rc ) ); + goto err; + } + + /* Sanity check */ + if ( iob_len ( iobuf ) != sizeof ( *mad ) ) { + DBGC ( sma, "SMA %p RX bad size (%zd bytes)\n", + sma, iob_len ( iobuf ) ); + goto err; + } + mad = iobuf->data; + + /* Construct MAD response */ + if ( ( rc = ib_sma_mad ( sma, mad ) ) != 0 ) { + DBGC ( sma, "SMA %p could not construct MAD response: %s\n", + sma, strerror ( rc ) ); + goto err; + } + + /* Send MAD response */ + if ( ( rc = ib_post_send ( ibdev, qp, av, iobuf ) ) != 0 ) { + DBGC ( sma, "SMA %p could not send MAD response: %s\n", + sma, strerror ( rc ) ); + goto err; + } + + return; + + err: + free_iob ( iobuf ); +} + +/** SMA completion operations */ +static struct ib_completion_queue_operations ib_sma_completion_ops = { + .complete_send = ib_sma_complete_send, + .complete_recv = ib_sma_complete_recv, +}; + +/** + * Poll SMA + * + * @v process Process + */ +static void ib_sma_step ( struct process *process ) { + struct ib_sma *sma = + container_of ( process, struct ib_sma, poll ); + struct ib_device *ibdev = sma->ibdev; + + /* Poll the kernel completion queue */ + ib_poll_cq ( ibdev, sma->cq ); + + /* Refill the receive ring */ + ib_sma_refill_recv ( sma ); +} + +/** + * Create SMA + * + * @v sma Subnet management agent + * @v ibdev Infiniband device + * @v op Subnet management operations + * @ret rc Return status code + */ +int ib_create_sma ( struct ib_sma *sma, struct ib_device *ibdev, + struct ib_sma_operations *op ) { + int rc; + + /* Initialise fields */ + memset ( sma, 0, sizeof ( *sma ) ); + sma->ibdev = ibdev; + sma->op = op; + process_init ( &sma->poll, ib_sma_step, &ibdev->refcnt ); + + /* Create completion queue */ + sma->cq = ib_create_cq ( ibdev, IB_SMA_NUM_CQES, + &ib_sma_completion_ops ); + if ( ! sma->cq ) { + rc = -ENOMEM; + goto err_create_cq; + } + + /* Create queue pair */ + sma->qp = ib_create_qp ( ibdev, IB_SMA_NUM_SEND_WQES, sma->cq, + IB_SMA_NUM_RECV_WQES, sma->cq, 0 ); + if ( ! sma->qp ) { + rc = -ENOMEM; + goto err_create_qp; + } + ib_qp_set_ownerdata ( sma->qp, sma ); + + /* If we don't get QP0, we can't function */ + if ( sma->qp->qpn != IB_QPN_SMP ) { + DBGC ( sma, "SMA %p on QPN %lx, needs to be on QPN 0\n", + sma, sma->qp->qpn ); + rc = -ENOTSUP; + goto err_not_qp0; + } + + /* Fill receive ring */ + ib_sma_refill_recv ( sma ); + return 0; + + err_not_qp0: + ib_destroy_qp ( ibdev, sma->qp ); + err_create_qp: + ib_destroy_cq ( ibdev, sma->cq ); + err_create_cq: + process_del ( &sma->poll ); + return rc; +} + +/** + * Destroy SMA + * + * @v sma Subnet management agent + */ +void ib_destroy_sma ( struct ib_sma *sma ) { + struct ib_device *ibdev = sma->ibdev; + + ib_destroy_qp ( ibdev, sma->qp ); + ib_destroy_cq ( ibdev, sma->cq ); + process_del ( &sma->poll ); +} diff --git a/gpxe/src/drivers/infiniband/ib_smc.c b/gpxe/src/drivers/infiniband/ib_smc.c new file mode 100644 index 00000000..af0c4ab9 --- /dev/null +++ b/gpxe/src/drivers/infiniband/ib_smc.c @@ -0,0 +1,166 @@ +/* + * 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., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +#include <stdint.h> +#include <stdlib.h> +#include <string.h> +#include <errno.h> +#include <unistd.h> +#include <byteswap.h> +#include <gpxe/infiniband.h> +#include <gpxe/ib_smc.h> + +/** + * @file + * + * Infiniband Subnet Management Client + * + */ + +/** + * Get port information + * + * @v ibdev Infiniband device + * @v local_mad Method for issuing local MADs + * @v mad Management datagram to fill in + * @ret rc Return status code + */ +static int ib_smc_get_port_info ( struct ib_device *ibdev, + ib_local_mad_t local_mad, + union ib_mad *mad ) { + int rc; + + /* Construct MAD */ + memset ( mad, 0, sizeof ( *mad ) ); + mad->hdr.base_version = IB_MGMT_BASE_VERSION; + mad->hdr.mgmt_class = IB_MGMT_CLASS_SUBN_LID_ROUTED; + mad->hdr.class_version = 1; + mad->hdr.method = IB_MGMT_METHOD_GET; + mad->hdr.attr_id = htons ( IB_SMP_ATTR_PORT_INFO ); + mad->hdr.attr_mod = htonl ( ibdev->port ); + + if ( ( rc = local_mad ( ibdev, mad ) ) != 0 ) { + DBGC ( ibdev, "IBDEV %p could not get port info: %s\n", + ibdev, strerror ( rc ) ); + return rc; + } + return 0; +} + +/** + * Get GUID information + * + * @v ibdev Infiniband device + * @v local_mad Method for issuing local MADs + * @v mad Management datagram to fill in + * @ret rc Return status code + */ +static int ib_smc_get_guid_info ( struct ib_device *ibdev, + ib_local_mad_t local_mad, + union ib_mad *mad ) { + int rc; + + /* Construct MAD */ + memset ( mad, 0, sizeof ( *mad ) ); + mad->hdr.base_version = IB_MGMT_BASE_VERSION; + mad->hdr.mgmt_class = IB_MGMT_CLASS_SUBN_LID_ROUTED; + mad->hdr.class_version = 1; + mad->hdr.method = IB_MGMT_METHOD_GET; + mad->hdr.attr_id = htons ( IB_SMP_ATTR_GUID_INFO ); + + if ( ( rc = local_mad ( ibdev, mad ) ) != 0 ) { + DBGC ( ibdev, "IBDEV %p could not get GUID info: %s\n", + ibdev, strerror ( rc ) ); + return rc; + } + return 0; +} + +/** + * Get partition key table + * + * @v ibdev Infiniband device + * @v local_mad Method for issuing local MADs + * @v mad Management datagram to fill in + * @ret rc Return status code + */ +static int ib_smc_get_pkey_table ( struct ib_device *ibdev, + ib_local_mad_t local_mad, + union ib_mad *mad ) { + int rc; + + /* Construct MAD */ + memset ( mad, 0, sizeof ( *mad ) ); + mad->hdr.base_version = IB_MGMT_BASE_VERSION; + mad->hdr.mgmt_class = IB_MGMT_CLASS_SUBN_LID_ROUTED; + mad->hdr.class_version = 1; + mad->hdr.method = IB_MGMT_METHOD_GET; + mad->hdr.attr_id = htons ( IB_SMP_ATTR_PKEY_TABLE ); + + if ( ( rc = local_mad ( ibdev, mad ) ) != 0 ) { + DBGC ( ibdev, "IBDEV %p could not get pkey table: %s\n", + ibdev, strerror ( rc ) ); + return rc; + } + return 0; +} + +/** + * Get MAD parameters + * + * @v ibdev Infiniband device + * @v local_mad Method for issuing local MADs + * @ret rc Return status code + */ +int ib_smc_update ( struct ib_device *ibdev, ib_local_mad_t local_mad ) { + union ib_mad mad; + union ib_smp_data *smp = &mad.smp.smp_data; + int rc; + + /* Port info gives us the link state, the first half of the + * port GID and the SM LID. + */ + if ( ( rc = ib_smc_get_port_info ( ibdev, local_mad, &mad ) ) != 0 ) + return rc; + ibdev->port_state = + ( smp->port_info.link_speed_supported__port_state & 0x0f ); + memcpy ( &ibdev->gid.u.half[0], smp->port_info.gid_prefix, + sizeof ( ibdev->gid.u.half[0] ) ); + ibdev->lid = ntohs ( smp->port_info.lid ); + ibdev->sm_lid = ntohs ( smp->port_info.mastersm_lid ); + ibdev->sm_sl = ( smp->port_info.neighbour_mtu__mastersm_sl & 0xf ); + + /* GUID info gives us the second half of the port GID */ + if ( ( rc = ib_smc_get_guid_info ( ibdev, local_mad, &mad ) ) != 0 ) + return rc; + memcpy ( &ibdev->gid.u.half[1], smp->guid_info.guid[0], + sizeof ( ibdev->gid.u.half[1] ) ); + + /* Get partition key */ + if ( ( rc = ib_smc_get_pkey_table ( ibdev, local_mad, &mad ) ) != 0 ) + return rc; + ibdev->pkey = ntohs ( smp->pkey_table.pkey[0] ); + + DBGC ( ibdev, "IBDEV %p port GID is %08x:%08x:%08x:%08x\n", ibdev, + htonl ( ibdev->gid.u.dwords[0] ), + htonl ( ibdev->gid.u.dwords[1] ), + htonl ( ibdev->gid.u.dwords[2] ), + htonl ( ibdev->gid.u.dwords[3] ) ); + + return 0; +} diff --git a/gpxe/src/drivers/infiniband/linda.c b/gpxe/src/drivers/infiniband/linda.c new file mode 100644 index 00000000..c5d13177 --- /dev/null +++ b/gpxe/src/drivers/infiniband/linda.c @@ -0,0 +1,2397 @@ +/* + * 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., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +#include <stdint.h> +#include <stdlib.h> +#include <errno.h> +#include <unistd.h> +#include <assert.h> +#include <gpxe/io.h> +#include <gpxe/pci.h> +#include <gpxe/infiniband.h> +#include <gpxe/i2c.h> +#include <gpxe/bitbash.h> +#include <gpxe/malloc.h> +#include <gpxe/iobuf.h> +#include <gpxe/ib_sma.h> +#include "linda.h" + +/** + * @file + * + * QLogic Linda Infiniband HCA + * + */ + +/** A Linda send work queue */ +struct linda_send_work_queue { + /** Send buffer usage */ + uint8_t *send_buf; + /** Producer index */ + unsigned int prod; + /** Consumer index */ + unsigned int cons; +}; + +/** A Linda receive work queue */ +struct linda_recv_work_queue { + /** Receive header ring */ + void *header; + /** Receive header producer offset (written by hardware) */ + struct QIB_7220_scalar header_prod; + /** Receive header consumer offset */ + unsigned int header_cons; + /** Offset within register space of the eager array */ + unsigned long eager_array; + /** Number of entries in eager array */ + unsigned int eager_entries; + /** Eager array producer index */ + unsigned int eager_prod; + /** Eager array consumer index */ + unsigned int eager_cons; +}; + +/** A Linda HCA */ +struct linda { + /** Registers */ + void *regs; + + /** In-use contexts */ + uint8_t used_ctx[LINDA_NUM_CONTEXTS]; + /** Send work queues */ + struct linda_send_work_queue send_wq[LINDA_NUM_CONTEXTS]; + /** Receive work queues */ + struct linda_recv_work_queue recv_wq[LINDA_NUM_CONTEXTS]; + + /** Offset within register space of the first send buffer */ + unsigned long send_buffer_base; + /** Send buffer availability (reported by hardware) */ + struct QIB_7220_SendBufAvail *sendbufavail; + /** Send buffer availability (maintained by software) */ + uint8_t send_buf[LINDA_MAX_SEND_BUFS]; + /** Send buffer availability producer counter */ + unsigned int send_buf_prod; + /** Send buffer availability consumer counter */ + unsigned int send_buf_cons; + /** Number of reserved send buffers (across all QPs) */ + unsigned int reserved_send_bufs; + + /** I2C bit-bashing interface */ + struct i2c_bit_basher i2c; + /** I2C serial EEPROM */ + struct i2c_device eeprom; + + /** Subnet management agent */ + struct ib_sma sma; +}; + +/*************************************************************************** + * + * Linda register access + * + *************************************************************************** + * + * This card requires atomic 64-bit accesses. Strange things happen + * if you try to use 32-bit accesses; sometimes they work, sometimes + * they don't, sometimes you get random data. + * + * These accessors use the "movq" MMX instruction, and so won't work + * on really old Pentiums (which won't have PCIe anyway, so this is + * something of a moot point). + */ + +/** + * Read Linda qword register + * + * @v linda Linda device + * @v dwords Register buffer to read into + * @v offset Register offset + */ +static void linda_readq ( struct linda *linda, uint32_t *dwords, + unsigned long offset ) { + void *addr = ( linda->regs + offset ); + + __asm__ __volatile__ ( "movq (%1), %%mm0\n\t" + "movq %%mm0, (%0)\n\t" + : : "r" ( dwords ), "r" ( addr ) : "memory" ); + + DBGIO ( "[%08lx] => %08x%08x\n", + virt_to_phys ( addr ), dwords[1], dwords[0] ); +} +#define linda_readq( _linda, _ptr, _offset ) \ + linda_readq ( (_linda), (_ptr)->u.dwords, (_offset) ) +#define linda_readq_array8b( _linda, _ptr, _offset, _idx ) \ + linda_readq ( (_linda), (_ptr), ( (_offset) + ( (_idx) * 8 ) ) ) +#define linda_readq_array64k( _linda, _ptr, _offset, _idx ) \ + linda_readq ( (_linda), (_ptr), ( (_offset) + ( (_idx) * 65536 ) ) ) + +/** + * Write Linda qword register + * + * @v linda Linda device + * @v dwords Register buffer to write + * @v offset Register offset + */ +static void linda_writeq ( struct linda *linda, const uint32_t *dwords, + unsigned long offset ) { + void *addr = ( linda->regs + offset ); + + DBGIO ( "[%08lx] <= %08x%08x\n", + virt_to_phys ( addr ), dwords[1], dwords[0] ); + + __asm__ __volatile__ ( "movq (%0), %%mm0\n\t" + "movq %%mm0, (%1)\n\t" + : : "r" ( dwords ), "r" ( addr ) : "memory" ); +} +#define linda_writeq( _linda, _ptr, _offset ) \ + linda_writeq ( (_linda), (_ptr)->u.dwords, (_offset) ) +#define linda_writeq_array8b( _linda, _ptr, _offset, _idx ) \ + linda_writeq ( (_linda), (_ptr), ( (_offset) + ( (_idx) * 8 ) ) ) +#define linda_writeq_array64k( _linda, _ptr, _offset, _idx ) \ + linda_writeq ( (_linda), (_ptr), ( (_offset) + ( (_idx) * 65536 ) ) ) + +/** + * Write Linda dword register + * + * @v linda Linda device + * @v dword Value to write + * @v offset Register offset + */ +static void linda_writel ( struct linda *linda, uint32_t dword, + unsigned long offset ) { + writel ( dword, ( linda->regs + offset ) ); +} + +/*************************************************************************** + * + * Link state management + * + *************************************************************************** + */ + +/** + * Textual representation of link state + * + * @v link_state Link state + * @ret link_text Link state text + */ +static const char * linda_link_state_text ( unsigned int link_state ) { + switch ( link_state ) { + case LINDA_LINK_STATE_DOWN: return "DOWN"; + case LINDA_LINK_STATE_INIT: return "INIT"; + case LINDA_LINK_STATE_ARM: return "ARM"; + case LINDA_LINK_STATE_ACTIVE: return "ACTIVE"; + case LINDA_LINK_STATE_ACT_DEFER:return "ACT_DEFER"; + default: return "UNKNOWN"; + } +} + +/** + * Handle link state change + * + * @v linda Linda device + */ +static void linda_link_state_changed ( struct ib_device *ibdev ) { + struct linda *linda = ib_get_drvdata ( ibdev ); + struct QIB_7220_IBCStatus ibcstatus; + struct QIB_7220_EXTCtrl extctrl; + unsigned int link_state; + unsigned int link_width; + unsigned int link_speed; + + /* Read link state */ + linda_readq ( linda, &ibcstatus, QIB_7220_IBCStatus_offset ); + link_state = BIT_GET ( &ibcstatus, LinkState ); + link_width = BIT_GET ( &ibcstatus, LinkWidthActive ); + link_speed = BIT_GET ( &ibcstatus, LinkSpeedActive ); + DBGC ( linda, "Linda %p link state %s (%s %s)\n", linda, + linda_link_state_text ( link_state ), + ( link_speed ? "DDR" : "SDR" ), ( link_width ? "x4" : "x1" ) ); + + /* Set LEDs according to link state */ + linda_readq ( linda, &extctrl, QIB_7220_EXTCtrl_offset ); + BIT_SET ( &extctrl, LEDPriPortGreenOn, + ( ( link_state >= LINDA_LINK_STATE_INIT ) ? 1 : 0 ) ); + BIT_SET ( &extctrl, LEDPriPortYellowOn, + ( ( link_state >= LINDA_LINK_STATE_ACTIVE ) ? 1 : 0 ) ); + linda_writeq ( linda, &extctrl, QIB_7220_EXTCtrl_offset ); + + /* Notify Infiniband core of link state change */ + ibdev->port_state = ( link_state + 1 ); + ibdev->link_width = + ( link_width ? IB_LINK_WIDTH_4X : IB_LINK_WIDTH_1X ); + ibdev->link_speed = + ( link_speed ? IB_LINK_SPEED_DDR : IB_LINK_SPEED_SDR ); + ib_link_state_changed ( ibdev ); +} + +/** + * Set port information + * + * @v ibdev Infiniband device + * @v port_info New port information + */ +static int linda_set_port_info ( struct ib_device *ibdev, + const struct ib_port_info *port_info ) { + struct linda *linda = ib_get_drvdata ( ibdev ); + struct QIB_7220_IBCCtrl ibcctrl; + unsigned int port_state; + unsigned int link_state; + + /* Set new link state */ + port_state = ( port_info->link_speed_supported__port_state & 0xf ); + if ( port_state ) { + link_state = ( port_state - 1 ); + DBGC ( linda, "Linda %p set link state to %s (%x)\n", linda, + linda_link_state_text ( link_state ), link_state ); + linda_readq ( linda, &ibcctrl, QIB_7220_IBCCtrl_offset ); + BIT_SET ( &ibcctrl, LinkCmd, link_state ); + linda_writeq ( linda, &ibcctrl, QIB_7220_IBCCtrl_offset ); + } + + /* Detect and report link state change */ + linda_link_state_changed ( ibdev ); + + return 0; +} + +/** Linda subnet management operations */ +static struct ib_sma_operations linda_sma_operations = { + .set_port_info = linda_set_port_info, +}; + +/*************************************************************************** + * + * Context allocation + * + *************************************************************************** + */ + +/** + * Map context number to QPN + * + * @v ctx Context index + * @ret qpn Queue pair number + */ +static int linda_ctx_to_qpn ( unsigned int ctx ) { + /* This mapping is fixed by hardware */ + return ( ctx * 2 ); +} + +/** + * Map QPN to context number + * + * @v qpn Queue pair number + * @ret ctx Context index + */ +static int linda_qpn_to_ctx ( unsigned int qpn ) { + /* This mapping is fixed by hardware */ + return ( qpn / 2 ); +} + +/** + * Allocate a context + * + * @v linda Linda device + * @ret ctx Context index, or negative error + */ +static int linda_alloc_ctx ( struct linda *linda ) { + unsigned int ctx; + + for ( ctx = 0 ; ctx < LINDA_NUM_CONTEXTS ; ctx++ ) { + + if ( ! linda->used_ctx[ctx] ) { + linda->used_ctx[ctx ] = 1; + DBGC2 ( linda, "Linda %p CTX %d allocated\n", + linda, ctx ); + return ctx; + } + } + + DBGC ( linda, "Linda %p out of available contexts\n", linda ); + return -ENOENT; +} + +/** + * Free a context + * + * @v linda Linda device + * @v ctx Context index + */ +static void linda_free_ctx ( struct linda *linda, unsigned int ctx ) { + + linda->used_ctx[ctx] = 0; + DBGC2 ( linda, "Linda %p CTX %d freed\n", linda, ctx ); +} + +/*************************************************************************** + * + * Send datapath + * + *************************************************************************** + */ + +/** Send buffer toggle bit + * + * We encode send buffers as 7 bits of send buffer index plus a single + * bit which should match the "check" bit in the SendBufAvail array. + */ +#define LINDA_SEND_BUF_TOGGLE 0x80 + +/** + * Allocate a send buffer + * + * @v linda Linda device + * @ret send_buf Send buffer + * + * You must guarantee that a send buffer is available. This is done + * by refusing to allocate more TX WQEs in total than the number of + * available send buffers. + */ +static unsigned int linda_alloc_send_buf ( struct linda *linda ) { + unsigned int send_buf; + + send_buf = linda->send_buf[linda->send_buf_cons]; + send_buf ^= LINDA_SEND_BUF_TOGGLE; + linda->send_buf_cons = ( ( linda->send_buf_cons + 1 ) % + LINDA_MAX_SEND_BUFS ); + return send_buf; +} + +/** + * Free a send buffer + * + * @v linda Linda device + * @v send_buf Send buffer + */ +static void linda_free_send_buf ( struct linda *linda, + unsigned int send_buf ) { + linda->send_buf[linda->send_buf_prod] = send_buf; + linda->send_buf_prod = ( ( linda->send_buf_prod + 1 ) % + LINDA_MAX_SEND_BUFS ); +} + +/** + * Check to see if send buffer is in use + * + * @v linda Linda device + * @v send_buf Send buffer + * @ret in_use Send buffer is in use + */ +static int linda_send_buf_in_use ( struct linda *linda, + unsigned int send_buf ) { + unsigned int send_idx; + unsigned int send_check; + unsigned int inusecheck; + unsigned int inuse; + unsigned int check; + + send_idx = ( send_buf & ~LINDA_SEND_BUF_TOGGLE ); + send_check = ( !! ( send_buf & LINDA_SEND_BUF_TOGGLE ) ); + inusecheck = BIT_GET ( linda->sendbufavail, InUseCheck[send_idx] ); + inuse = ( !! ( inusecheck & 0x02 ) ); + check = ( !! ( inusecheck & 0x01 ) ); + return ( inuse || ( check != send_check ) ); +} + +/** + * Calculate starting offset for send buffer + * + * @v linda Linda device + * @v send_buf Send buffer + * @ret offset Starting offset + */ +static unsigned long linda_send_buffer_offset ( struct linda *linda, + unsigned int send_buf ) { + return ( linda->send_buffer_base + + ( ( send_buf & ~LINDA_SEND_BUF_TOGGLE ) * + LINDA_SEND_BUF_SIZE ) ); +} + +/** + * Create send work queue + * + * @v linda Linda device + * @v qp Queue pair + */ +static int linda_create_send_wq ( struct linda *linda, + struct ib_queue_pair *qp ) { + struct ib_work_queue *wq = &qp->send; + struct linda_send_work_queue *linda_wq = ib_wq_get_drvdata ( wq ); + int rc; + + /* Reserve send buffers */ + if ( ( linda->reserved_send_bufs + qp->send.num_wqes ) > + LINDA_MAX_SEND_BUFS ) { + DBGC ( linda, "Linda %p out of send buffers (have %d, used " + "%d, need %d)\n", linda, LINDA_MAX_SEND_BUFS, + linda->reserved_send_bufs, qp->send.num_wqes ); + rc = -ENOBUFS; + goto err_reserve_bufs; + } + linda->reserved_send_bufs += qp->send.num_wqes; + + /* Reset work queue */ + linda_wq->prod = 0; + linda_wq->cons = 0; + + /* Allocate space for send buffer uasge list */ + linda_wq->send_buf = zalloc ( qp->send.num_wqes * + sizeof ( linda_wq->send_buf[0] ) ); + if ( ! linda_wq->send_buf ) { + rc = -ENOBUFS; + goto err_alloc_send_buf; + } + + return 0; + + free ( linda_wq->send_buf ); + err_alloc_send_buf: + linda->reserved_send_bufs -= qp->send.num_wqes; + err_reserve_bufs: + return rc; +} + +/** + * Destroy send work queue + * + * @v linda Linda device + * @v qp Queue pair + */ +static void linda_destroy_send_wq ( struct linda *linda, + struct ib_queue_pair *qp ) { + struct ib_work_queue *wq = &qp->send; + struct linda_send_work_queue *linda_wq = ib_wq_get_drvdata ( wq ); + + free ( linda_wq->send_buf ); + linda->reserved_send_bufs -= qp->send.num_wqes; +} + +/** + * Initialise send datapath + * + * @v linda Linda device + * @ret rc Return status code + */ +static int linda_init_send ( struct linda *linda ) { + struct QIB_7220_SendBufBase sendbufbase; + struct QIB_7220_SendBufAvailAddr sendbufavailaddr; + struct QIB_7220_SendCtrl sendctrl; + unsigned int i; + int rc; + + /* Retrieve SendBufBase */ + linda_readq ( linda, &sendbufbase, QIB_7220_SendBufBase_offset ); + linda->send_buffer_base = BIT_GET ( &sendbufbase, + BaseAddr_SmallPIO ); + DBGC ( linda, "Linda %p send buffers at %lx\n", + linda, linda->send_buffer_base ); + + /* Initialise the send_buf[] array */ + for ( i = 0 ; i < LINDA_MAX_SEND_BUFS ; i++ ) + linda->send_buf[i] = i; + + /* Allocate space for the SendBufAvail array */ + linda->sendbufavail = malloc_dma ( sizeof ( *linda->sendbufavail ), + LINDA_SENDBUFAVAIL_ALIGN ); + if ( ! linda->sendbufavail ) { + rc = -ENOMEM; + goto err_alloc_sendbufavail; + } + memset ( linda->sendbufavail, 0, sizeof ( linda->sendbufavail ) ); + + /* Program SendBufAvailAddr into the hardware */ + memset ( &sendbufavailaddr, 0, sizeof ( sendbufavailaddr ) ); + BIT_FILL_1 ( &sendbufavailaddr, SendBufAvailAddr, + ( virt_to_bus ( linda->sendbufavail ) >> 6 ) ); + linda_writeq ( linda, &sendbufavailaddr, + QIB_7220_SendBufAvailAddr_offset ); + + /* Enable sending and DMA of SendBufAvail */ + memset ( &sendctrl, 0, sizeof ( sendctrl ) ); + BIT_FILL_2 ( &sendctrl, + SendBufAvailUpd, 1, + SPioEnable, 1 ); + linda_writeq ( linda, &sendctrl, QIB_7220_SendCtrl_offset ); + + return 0; + + free_dma ( linda->sendbufavail, sizeof ( *linda->sendbufavail ) ); + err_alloc_sendbufavail: + return rc; +} + +/** + * Shut down send datapath + * + * @v linda Linda device + */ +static void linda_fini_send ( struct linda *linda ) { + struct QIB_7220_SendCtrl sendctrl; + + /* Disable sending and DMA of SendBufAvail */ + memset ( &sendctrl, 0, sizeof ( sendctrl ) ); + linda_writeq ( linda, &sendctrl, QIB_7220_SendCtrl_offset ); + mb(); + + /* Ensure hardware has seen this disable */ + linda_readq ( linda, &sendctrl, QIB_7220_SendCtrl_offset ); + + free_dma ( linda->sendbufavail, sizeof ( *linda->sendbufavail ) ); +} + +/*************************************************************************** + * + * Receive datapath + * + *************************************************************************** + */ + +/** + * Create receive work queue + * + * @v linda Linda device + * @v qp Queue pair + * @ret rc Return status code + */ +static int linda_create_recv_wq ( struct linda *linda, + struct ib_queue_pair *qp ) { + struct ib_work_queue *wq = &qp->recv; + struct linda_recv_work_queue *linda_wq = ib_wq_get_drvdata ( wq ); + struct QIB_7220_RcvHdrAddr0 rcvhdraddr; + struct QIB_7220_RcvHdrTailAddr0 rcvhdrtailaddr; + struct QIB_7220_RcvHdrHead0 rcvhdrhead; + struct QIB_7220_scalar rcvegrindexhead; + struct QIB_7220_RcvCtrl rcvctrl; + unsigned int ctx = linda_qpn_to_ctx ( qp->qpn ); + int rc; + + /* Reset context information */ + memset ( &linda_wq->header_prod, 0, + sizeof ( linda_wq->header_prod ) ); + linda_wq->header_cons = 0; + linda_wq->eager_prod = 0; + linda_wq->eager_cons = 0; + + /* Allocate receive header buffer */ + linda_wq->header = malloc_dma ( LINDA_RECV_HEADERS_SIZE, + LINDA_RECV_HEADERS_ALIGN ); + if ( ! linda_wq->header ) { + rc = -ENOMEM; + goto err_alloc_header; + } + + /* Enable context in hardware */ + memset ( &rcvhdraddr, 0, sizeof ( rcvhdraddr ) ); + BIT_FILL_1 ( &rcvhdraddr, RcvHdrAddr0, + ( virt_to_bus ( linda_wq->header ) >> 2 ) ); + linda_writeq_array8b ( linda, &rcvhdraddr, + QIB_7220_RcvHdrAddr0_offset, ctx ); + memset ( &rcvhdrtailaddr, 0, sizeof ( rcvhdrtailaddr ) ); + BIT_FILL_1 ( &rcvhdrtailaddr, RcvHdrTailAddr0, + ( virt_to_bus ( &linda_wq->header_prod ) >> 2 ) ); + linda_writeq_array8b ( linda, &rcvhdrtailaddr, + QIB_7220_RcvHdrTailAddr0_offset, ctx ); + memset ( &rcvhdrhead, 0, sizeof ( rcvhdrhead ) ); + BIT_FILL_1 ( &rcvhdrhead, counter, 1 ); + linda_writeq_array64k ( linda, &rcvhdrhead, + QIB_7220_RcvHdrHead0_offset, ctx ); + memset ( &rcvegrindexhead, 0, sizeof ( rcvegrindexhead ) ); + BIT_FILL_1 ( &rcvegrindexhead, Value, 1 ); + linda_writeq_array64k ( linda, &rcvegrindexhead, + QIB_7220_RcvEgrIndexHead0_offset, ctx ); + linda_readq ( linda, &rcvctrl, QIB_7220_RcvCtrl_offset ); + BIT_SET ( &rcvctrl, PortEnable[ctx], 1 ); + BIT_SET ( &rcvctrl, IntrAvail[ctx], 1 ); + linda_writeq ( linda, &rcvctrl, QIB_7220_RcvCtrl_offset ); + + DBGC ( linda, "Linda %p QPN %ld CTX %d hdrs [%lx,%lx) prod %lx\n", + linda, qp->qpn, ctx, virt_to_bus ( linda_wq->header ), + ( virt_to_bus ( linda_wq->header ) + LINDA_RECV_HEADERS_SIZE ), + virt_to_bus ( &linda_wq->header_prod ) ); + return 0; + + free_dma ( linda_wq->header, LINDA_RECV_HEADERS_SIZE ); + err_alloc_header: + return rc; +} + +/** + * Destroy receive work queue + * + * @v linda Linda device + * @v qp Queue pair + */ +static void linda_destroy_recv_wq ( struct linda *linda, + struct ib_queue_pair *qp ) { + struct ib_work_queue *wq = &qp->recv; + struct linda_recv_work_queue *linda_wq = ib_wq_get_drvdata ( wq ); + struct QIB_7220_RcvCtrl rcvctrl; + unsigned int ctx = linda_qpn_to_ctx ( qp->qpn ); + + /* Disable context in hardware */ + linda_readq ( linda, &rcvctrl, QIB_7220_RcvCtrl_offset ); + BIT_SET ( &rcvctrl, PortEnable[ctx], 0 ); + BIT_SET ( &rcvctrl, IntrAvail[ctx], 0 ); + linda_writeq ( linda, &rcvctrl, QIB_7220_RcvCtrl_offset ); + + /* Make sure the hardware has seen that the context is disabled */ + linda_readq ( linda, &rcvctrl, QIB_7220_RcvCtrl_offset ); + mb(); + + /* Free headers ring */ + free_dma ( linda_wq->header, LINDA_RECV_HEADERS_SIZE ); + + /* Free context */ + linda_free_ctx ( linda, ctx ); +} + +/** + * Initialise receive datapath + * + * @v linda Linda device + * @ret rc Return status code + */ +static int linda_init_recv ( struct linda *linda ) { + struct QIB_7220_RcvCtrl rcvctrl; + struct QIB_7220_scalar rcvegrbase; + struct QIB_7220_scalar rcvhdrentsize; + struct QIB_7220_scalar rcvhdrcnt; + struct QIB_7220_RcvBTHQP rcvbthqp; + unsigned int portcfg; + unsigned long egrbase; + unsigned int eager_array_size_0; + unsigned int eager_array_size_other; + unsigned int ctx; + + /* Select configuration based on number of contexts */ + switch ( LINDA_NUM_CONTEXTS ) { + case 5: + portcfg = LINDA_PORTCFG_5CTX; + eager_array_size_0 = LINDA_EAGER_ARRAY_SIZE_5CTX_0; + eager_array_size_other = LINDA_EAGER_ARRAY_SIZE_5CTX_OTHER; + break; + case 9: + portcfg = LINDA_PORTCFG_9CTX; + eager_array_size_0 = LINDA_EAGER_ARRAY_SIZE_9CTX_0; + eager_array_size_other = LINDA_EAGER_ARRAY_SIZE_9CTX_OTHER; + break; + case 17: + portcfg = LINDA_PORTCFG_17CTX; + eager_array_size_0 = LINDA_EAGER_ARRAY_SIZE_17CTX_0; + eager_array_size_other = LINDA_EAGER_ARRAY_SIZE_17CTX_OTHER; + break; + default: + linker_assert ( 0, invalid_LINDA_NUM_CONTEXTS ); + return -EINVAL; + } + + /* Configure number of contexts */ + memset ( &rcvctrl, 0, sizeof ( rcvctrl ) ); + BIT_FILL_3 ( &rcvctrl, + TailUpd, 1, + PortCfg, portcfg, + RcvQPMapEnable, 1 ); + linda_writeq ( linda, &rcvctrl, QIB_7220_RcvCtrl_offset ); + + /* Configure receive header buffer sizes */ + memset ( &rcvhdrcnt, 0, sizeof ( rcvhdrcnt ) ); + BIT_FILL_1 ( &rcvhdrcnt, Value, LINDA_RECV_HEADER_COUNT ); + linda_writeq ( linda, &rcvhdrcnt, QIB_7220_RcvHdrCnt_offset ); + memset ( &rcvhdrentsize, 0, sizeof ( rcvhdrentsize ) ); + BIT_FILL_1 ( &rcvhdrentsize, Value, ( LINDA_RECV_HEADER_SIZE >> 2 ) ); + linda_writeq ( linda, &rcvhdrentsize, QIB_7220_RcvHdrEntSize_offset ); + + /* Calculate eager array start addresses for each context */ + linda_readq ( linda, &rcvegrbase, QIB_7220_RcvEgrBase_offset ); + egrbase = BIT_GET ( &rcvegrbase, Value ); + linda->recv_wq[0].eager_array = egrbase; + linda->recv_wq[0].eager_entries = eager_array_size_0; + egrbase += ( eager_array_size_0 * sizeof ( struct QIB_7220_RcvEgr ) ); + for ( ctx = 1 ; ctx < LINDA_NUM_CONTEXTS ; ctx++ ) { + linda->recv_wq[ctx].eager_array = egrbase; + linda->recv_wq[ctx].eager_entries = eager_array_size_other; + egrbase += ( eager_array_size_other * + sizeof ( struct QIB_7220_RcvEgr ) ); + } + for ( ctx = 0 ; ctx < LINDA_NUM_CONTEXTS ; ctx++ ) { + DBGC ( linda, "Linda %p CTX %d eager array at %lx (%d " + "entries)\n", linda, ctx, + linda->recv_wq[ctx].eager_array, + linda->recv_wq[ctx].eager_entries ); + } + + /* Set the BTH QP for Infinipath packets to an unused value */ + memset ( &rcvbthqp, 0, sizeof ( rcvbthqp ) ); + BIT_FILL_1 ( &rcvbthqp, RcvBTHQP, LINDA_QP_IDETH ); + linda_writeq ( linda, &rcvbthqp, QIB_7220_RcvBTHQP_offset ); + + return 0; +} + +/** + * Shut down receive datapath + * + * @v linda Linda device + */ +static void linda_fini_recv ( struct linda *linda __unused ) { + /* Nothing to do; all contexts were already disabled when the + * queue pairs were destroyed + */ +} + +/*************************************************************************** + * + * Completion queue operations + * + *************************************************************************** + */ + +/** + * Create completion queue + * + * @v ibdev Infiniband device + * @v cq Completion queue + * @ret rc Return status code + */ +static int linda_create_cq ( struct ib_device *ibdev, + struct ib_completion_queue *cq ) { + struct linda *linda = ib_get_drvdata ( ibdev ); + static int cqn; + + /* The hardware has no concept of completion queues. We + * simply use the association between CQs and WQs (already + * handled by the IB core) to decide which WQs to poll. + * + * We do set a CQN, just to avoid confusing debug messages + * from the IB core. + */ + cq->cqn = ++cqn; + DBGC ( linda, "Linda %p CQN %ld created\n", linda, cq->cqn ); + + return 0; +} + +/** + * Destroy completion queue + * + * @v ibdev Infiniband device + * @v cq Completion queue + */ +static void linda_destroy_cq ( struct ib_device *ibdev, + struct ib_completion_queue *cq ) { + struct linda *linda = ib_get_drvdata ( ibdev ); + + /* Nothing to do */ + DBGC ( linda, "Linda %p CQN %ld destroyed\n", linda, cq->cqn ); +} + +/*************************************************************************** + * + * Queue pair operations + * + *************************************************************************** + */ + +/** + * Create queue pair + * + * @v ibdev Infiniband device + * @v qp Queue pair + * @ret rc Return status code + */ +static int linda_create_qp ( struct ib_device *ibdev, + struct ib_queue_pair *qp ) { + struct linda *linda = ib_get_drvdata ( ibdev ); + int ctx; + int rc; + + /* Locate an available context */ + ctx = linda_alloc_ctx ( linda ); + if ( ctx < 0 ) { + rc = ctx; + goto err_alloc_ctx; + } + + /* Set queue pair number based on context index */ + qp->qpn = linda_ctx_to_qpn ( ctx ); + + /* Set work-queue private data pointers */ + ib_wq_set_drvdata ( &qp->send, &linda->send_wq[ctx] ); + ib_wq_set_drvdata ( &qp->recv, &linda->recv_wq[ctx] ); + + /* Create receive work queue */ + if ( ( rc = linda_create_recv_wq ( linda, qp ) ) != 0 ) + goto err_create_recv_wq; + + /* Create send work queue */ + if ( ( rc = linda_create_send_wq ( linda, qp ) ) != 0 ) + goto err_create_send_wq; + + return 0; + + linda_destroy_send_wq ( linda, qp ); + err_create_send_wq: + linda_destroy_recv_wq ( linda, qp ); + err_create_recv_wq: + linda_free_ctx ( linda, ctx ); + err_alloc_ctx: + return rc; +} + +/** + * Modify queue pair + * + * @v ibdev Infiniband device + * @v qp Queue pair + * @v mod_list Modification list + * @ret rc Return status code + */ +static int linda_modify_qp ( struct ib_device *ibdev, + struct ib_queue_pair *qp, + unsigned long mod_list __unused ) { + struct linda *linda = ib_get_drvdata ( ibdev ); + + /* Nothing to do; the hardware doesn't have a notion of queue + * keys + */ + DBGC ( linda, "Linda %p QPN %ld modified\n", linda, qp->qpn ); + return 0; +} + +/** + * Destroy queue pair + * + * @v ibdev Infiniband device + * @v qp Queue pair + */ +static void linda_destroy_qp ( struct ib_device *ibdev, + struct ib_queue_pair *qp ) { + struct linda *linda = ib_get_drvdata ( ibdev ); + + linda_destroy_send_wq ( linda, qp ); + linda_destroy_recv_wq ( linda, qp ); +} + +/*************************************************************************** + * + * Work request operations + * + *************************************************************************** + */ + +/** + * Post send work queue entry + * + * @v ibdev Infiniband device + * @v qp Queue pair + * @v av Address vector + * @v iobuf I/O buffer + * @ret rc Return status code + */ +static int linda_post_send ( struct ib_device *ibdev, + struct ib_queue_pair *qp, + struct ib_address_vector *av, + struct io_buffer *iobuf ) { + struct linda *linda = ib_get_drvdata ( ibdev ); + struct ib_work_queue *wq = &qp->send; + struct linda_send_work_queue *linda_wq = ib_wq_get_drvdata ( wq ); + struct QIB_7220_SendPbc sendpbc; + uint8_t header_buf[IB_MAX_HEADER_SIZE]; + struct io_buffer headers; + unsigned int send_buf; + unsigned long start_offset; + unsigned long offset; + size_t len; + ssize_t frag_len; + uint32_t *data; + + /* Allocate send buffer and calculate offset */ + send_buf = linda_alloc_send_buf ( linda ); + start_offset = offset = linda_send_buffer_offset ( linda, send_buf ); + + /* Store I/O buffer and send buffer index */ + assert ( wq->iobufs[linda_wq->prod] == NULL ); + wq->iobufs[linda_wq->prod] = iobuf; + linda_wq->send_buf[linda_wq->prod] = send_buf; + + /* Construct headers */ + iob_populate ( &headers, header_buf, 0, sizeof ( header_buf ) ); + iob_reserve ( &headers, sizeof ( header_buf ) ); + ib_push ( ibdev, &headers, qp, iob_len ( iobuf ), av ); + + /* Calculate packet length */ + len = ( ( sizeof ( sendpbc ) + iob_len ( &headers ) + + iob_len ( iobuf ) + 3 ) & ~3 ); + + /* Construct send per-buffer control word */ + memset ( &sendpbc, 0, sizeof ( sendpbc ) ); + BIT_FILL_2 ( &sendpbc, + LengthP1_toibc, ( ( len >> 2 ) - 1 ), + VL15, 1 ); + + /* Write SendPbc */ + DBG_DISABLE ( DBGLVL_IO ); + linda_writeq ( linda, &sendpbc, offset ); + offset += sizeof ( sendpbc ); + + /* Write headers */ + for ( data = headers.data, frag_len = iob_len ( &headers ) ; + frag_len > 0 ; data++, offset += 4, frag_len -= 4 ) { + linda_writel ( linda, *data, offset ); + } + + /* Write data */ + for ( data = iobuf->data, frag_len = iob_len ( iobuf ) ; + frag_len > 0 ; data++, offset += 4, frag_len -= 4 ) { + linda_writel ( linda, *data, offset ); + } + DBG_ENABLE ( DBGLVL_IO ); + + assert ( ( start_offset + len ) == offset ); + DBGC2 ( linda, "Linda %p QPN %ld TX %d(%d) posted [%lx,%lx)\n", + linda, qp->qpn, send_buf, linda_wq->prod, + start_offset, offset ); + + /* Increment producer counter */ + linda_wq->prod = ( ( linda_wq->prod + 1 ) & ( wq->num_wqes - 1 ) ); + + return 0; +} + +/** + * Complete send work queue entry + * + * @v ibdev Infiniband device + * @v qp Queue pair + * @v wqe_idx Work queue entry index + */ +static void linda_complete_send ( struct ib_device *ibdev, + struct ib_queue_pair *qp, + unsigned int wqe_idx ) { + struct linda *linda = ib_get_drvdata ( ibdev ); + struct ib_work_queue *wq = &qp->send; + struct linda_send_work_queue *linda_wq = ib_wq_get_drvdata ( wq ); + struct io_buffer *iobuf; + unsigned int send_buf; + + /* Parse completion */ + send_buf = linda_wq->send_buf[wqe_idx]; + DBGC2 ( linda, "Linda %p QPN %ld TX %d(%d) complete\n", + linda, qp->qpn, send_buf, wqe_idx ); + + /* Complete work queue entry */ + iobuf = wq->iobufs[wqe_idx]; + assert ( iobuf != NULL ); + ib_complete_send ( ibdev, qp, iobuf, 0 ); + wq->iobufs[wqe_idx] = NULL; + + /* Free send buffer */ + linda_free_send_buf ( linda, send_buf ); +} + +/** + * Poll send work queue + * + * @v ibdev Infiniband device + * @v qp Queue pair + */ +static void linda_poll_send_wq ( struct ib_device *ibdev, + struct ib_queue_pair *qp ) { + struct linda *linda = ib_get_drvdata ( ibdev ); + struct ib_work_queue *wq = &qp->send; + struct linda_send_work_queue *linda_wq = ib_wq_get_drvdata ( wq ); + unsigned int send_buf; + + /* Look for completions */ + while ( wq->fill ) { + + /* Check to see if send buffer has completed */ + send_buf = linda_wq->send_buf[linda_wq->cons]; + if ( linda_send_buf_in_use ( linda, send_buf ) ) + break; + + /* Complete this buffer */ + linda_complete_send ( ibdev, qp, linda_wq->cons ); + + /* Increment consumer counter */ + linda_wq->cons = ( ( linda_wq->cons + 1 ) & + ( wq->num_wqes - 1 ) ); + } +} + +/** + * Post receive work queue entry + * + * @v ibdev Infiniband device + * @v qp Queue pair + * @v iobuf I/O buffer + * @ret rc Return status code + */ +static int linda_post_recv ( struct ib_device *ibdev, + struct ib_queue_pair *qp, + struct io_buffer *iobuf ) { + struct linda *linda = ib_get_drvdata ( ibdev ); + struct ib_work_queue *wq = &qp->recv; + struct linda_recv_work_queue *linda_wq = ib_wq_get_drvdata ( wq ); + struct QIB_7220_RcvEgr rcvegr; + struct QIB_7220_scalar rcvegrindexhead; + unsigned int ctx = linda_qpn_to_ctx ( qp->qpn ); + physaddr_t addr; + size_t len; + unsigned int wqe_idx; + unsigned int bufsize; + + /* Sanity checks */ + addr = virt_to_bus ( iobuf->data ); + len = iob_tailroom ( iobuf ); + if ( addr & ( LINDA_EAGER_BUFFER_ALIGN - 1 ) ) { + DBGC ( linda, "Linda %p QPN %ld misaligned RX buffer " + "(%08lx)\n", linda, qp->qpn, addr ); + return -EINVAL; + } + if ( len != LINDA_RECV_PAYLOAD_SIZE ) { + DBGC ( linda, "Linda %p QPN %ld wrong RX buffer size (%zd)\n", + linda, qp->qpn, len ); + return -EINVAL; + } + + /* Calculate eager producer index and WQE index */ + wqe_idx = ( linda_wq->eager_prod & ( wq->num_wqes - 1 ) ); + assert ( wq->iobufs[wqe_idx] == NULL ); + + /* Store I/O buffer */ + wq->iobufs[wqe_idx] = iobuf; + + /* Calculate buffer size */ + switch ( LINDA_RECV_PAYLOAD_SIZE ) { + case 2048: bufsize = LINDA_EAGER_BUFFER_2K; break; + case 4096: bufsize = LINDA_EAGER_BUFFER_4K; break; + case 8192: bufsize = LINDA_EAGER_BUFFER_8K; break; + case 16384: bufsize = LINDA_EAGER_BUFFER_16K; break; + case 32768: bufsize = LINDA_EAGER_BUFFER_32K; break; + case 65536: bufsize = LINDA_EAGER_BUFFER_64K; break; + default: linker_assert ( 0, invalid_rx_payload_size ); + bufsize = LINDA_EAGER_BUFFER_NONE; + } + + /* Post eager buffer */ + memset ( &rcvegr, 0, sizeof ( rcvegr ) ); + BIT_FILL_2 ( &rcvegr, + Addr, ( addr >> 11 ), + BufSize, bufsize ); + linda_writeq_array8b ( linda, &rcvegr, + linda_wq->eager_array, linda_wq->eager_prod ); + DBGC2 ( linda, "Linda %p QPN %ld RX egr %d(%d) posted [%lx,%lx)\n", + linda, qp->qpn, linda_wq->eager_prod, wqe_idx, + addr, ( addr + len ) ); + + /* Increment producer index */ + linda_wq->eager_prod = ( ( linda_wq->eager_prod + 1 ) & + ( linda_wq->eager_entries - 1 ) ); + + /* Update head index */ + memset ( &rcvegrindexhead, 0, sizeof ( rcvegrindexhead ) ); + BIT_FILL_1 ( &rcvegrindexhead, + Value, ( ( linda_wq->eager_prod + 1 ) & + ( linda_wq->eager_entries - 1 ) ) ); + linda_writeq_array64k ( linda, &rcvegrindexhead, + QIB_7220_RcvEgrIndexHead0_offset, ctx ); + + return 0; +} + +/** + * Complete receive work queue entry + * + * @v ibdev Infiniband device + * @v qp Queue pair + * @v header_offs Header offset + */ +static void linda_complete_recv ( struct ib_device *ibdev, + struct ib_queue_pair *qp, + unsigned int header_offs ) { + struct linda *linda = ib_get_drvdata ( ibdev ); + struct ib_work_queue *wq = &qp->recv; + struct linda_recv_work_queue *linda_wq = ib_wq_get_drvdata ( wq ); + struct QIB_7220_RcvHdrFlags *rcvhdrflags; + struct QIB_7220_RcvEgr rcvegr; + struct io_buffer headers; + struct io_buffer *iobuf; + struct ib_queue_pair *intended_qp; + struct ib_address_vector av; + unsigned int rcvtype; + unsigned int pktlen; + unsigned int egrindex; + unsigned int useegrbfr; + unsigned int iberr, mkerr, tiderr, khdrerr, mtuerr; + unsigned int lenerr, parityerr, vcrcerr, icrcerr; + unsigned int err; + unsigned int hdrqoffset; + unsigned int header_len; + unsigned int padded_payload_len; + unsigned int wqe_idx; + size_t payload_len; + int qp0; + int rc; + + /* RcvHdrFlags are at the end of the header entry */ + rcvhdrflags = ( linda_wq->header + header_offs + + LINDA_RECV_HEADER_SIZE - sizeof ( *rcvhdrflags ) ); + rcvtype = BIT_GET ( rcvhdrflags, RcvType ); + pktlen = ( BIT_GET ( rcvhdrflags, PktLen ) << 2 ); + egrindex = BIT_GET ( rcvhdrflags, EgrIndex ); + useegrbfr = BIT_GET ( rcvhdrflags, UseEgrBfr ); + hdrqoffset = ( BIT_GET ( rcvhdrflags, HdrqOffset ) << 2 ); + iberr = BIT_GET ( rcvhdrflags, IBErr ); + mkerr = BIT_GET ( rcvhdrflags, MKErr ); + tiderr = BIT_GET ( rcvhdrflags, TIDErr ); + khdrerr = BIT_GET ( rcvhdrflags, KHdrErr ); + mtuerr = BIT_GET ( rcvhdrflags, MTUErr ); + lenerr = BIT_GET ( rcvhdrflags, LenErr ); + parityerr = BIT_GET ( rcvhdrflags, ParityErr ); + vcrcerr = BIT_GET ( rcvhdrflags, VCRCErr ); + icrcerr = BIT_GET ( rcvhdrflags, ICRCErr ); + header_len = ( LINDA_RECV_HEADER_SIZE - hdrqoffset - + sizeof ( *rcvhdrflags ) ); + padded_payload_len = ( pktlen - header_len - 4 /* ICRC */ ); + err = ( iberr | mkerr | tiderr | khdrerr | mtuerr | + lenerr | parityerr | vcrcerr | icrcerr ); + /* IB header is placed immediately before RcvHdrFlags */ + iob_populate ( &headers, ( ( ( void * ) rcvhdrflags ) - header_len ), + header_len, header_len ); + + /* Dump diagnostic information */ + if ( err || ( ! useegrbfr ) ) { + DBGC ( linda, "Linda %p QPN %ld RX egr %d%s hdr %d type %d " + "len %d(%d+%d+4)%s%s%s%s%s%s%s%s%s%s%s\n", linda, + qp->qpn, egrindex, ( useegrbfr ? "" : "(unused)" ), + ( header_offs / LINDA_RECV_HEADER_SIZE ), rcvtype, + pktlen, header_len, padded_payload_len, + ( err ? " [Err" : "" ), ( iberr ? " IB" : "" ), + ( mkerr ? " MK" : "" ), ( tiderr ? " TID" : "" ), + ( khdrerr ? " KHdr" : "" ), ( mtuerr ? " MTU" : "" ), + ( lenerr ? " Len" : "" ), ( parityerr ? " Parity" : ""), + ( vcrcerr ? " VCRC" : "" ), ( icrcerr ? " ICRC" : "" ), + ( err ? "]" : "" ) ); + } else { + DBGC2 ( linda, "Linda %p QPN %ld RX egr %d hdr %d type %d " + "len %d(%d+%d+4)\n", linda, qp->qpn, egrindex, + ( header_offs / LINDA_RECV_HEADER_SIZE ), rcvtype, + pktlen, header_len, padded_payload_len ); + } + DBGCP_HDA ( linda, hdrqoffset, headers.data, + ( header_len + sizeof ( *rcvhdrflags ) ) ); + + /* Parse header to generate address vector */ + qp0 = ( qp->qpn == 0 ); + intended_qp = NULL; + if ( ( rc = ib_pull ( ibdev, &headers, ( qp0 ? &intended_qp : NULL ), + &payload_len, &av ) ) != 0 ) { + DBGC ( linda, "Linda %p could not parse headers: %s\n", + linda, strerror ( rc ) ); + err = 1; + } + if ( ! intended_qp ) + intended_qp = qp; + + /* Complete this buffer and any skipped buffers. Note that + * when the hardware runs out of buffers, it will repeatedly + * report the same buffer (the tail) as a TID error, and that + * it also has a habit of sometimes skipping over several + * buffers at once. + */ + while ( 1 ) { + + /* If we have caught up to the producer counter, stop. + * This will happen when the hardware first runs out + * of buffers and starts reporting TID errors against + * the eager buffer it wants to use next. + */ + if ( linda_wq->eager_cons == linda_wq->eager_prod ) + break; + + /* If we have caught up to where we should be after + * completing this egrindex, stop. We phrase the test + * this way to avoid completing the entire ring when + * we receive the same egrindex twice in a row. + */ + if ( ( linda_wq->eager_cons == + ( ( egrindex + 1 ) & ( linda_wq->eager_entries - 1 ) ))) + break; + + /* Identify work queue entry and corresponding I/O + * buffer. + */ + wqe_idx = ( linda_wq->eager_cons & ( wq->num_wqes - 1 ) ); + iobuf = wq->iobufs[wqe_idx]; + assert ( iobuf != NULL ); + wq->iobufs[wqe_idx] = NULL; + + /* Complete the eager buffer */ + if ( linda_wq->eager_cons == egrindex ) { + /* Completing the eager buffer described in + * this header entry. + */ + iob_put ( iobuf, payload_len ); + rc = ( err ? -EIO : ( useegrbfr ? 0 : -ECANCELED ) ); + /* Redirect to target QP if necessary */ + if ( qp != intended_qp ) { + DBGC ( linda, "Linda %p redirecting QPN %ld " + "=> %ld\n", + linda, qp->qpn, intended_qp->qpn ); + /* Compensate for incorrect fill levels */ + qp->recv.fill--; + intended_qp->recv.fill++; + } + ib_complete_recv ( ibdev, intended_qp, &av, iobuf, rc); + } else { + /* Completing on a skipped-over eager buffer */ + ib_complete_recv ( ibdev, qp, &av, iobuf, -ECANCELED ); + } + + /* Clear eager buffer */ + memset ( &rcvegr, 0, sizeof ( rcvegr ) ); + linda_writeq_array8b ( linda, &rcvegr, linda_wq->eager_array, + linda_wq->eager_cons ); + + /* Increment consumer index */ + linda_wq->eager_cons = ( ( linda_wq->eager_cons + 1 ) & + ( linda_wq->eager_entries - 1 ) ); + } +} + +/** + * Poll receive work queue + * + * @v ibdev Infiniband device + * @v qp Queue pair + */ +static void linda_poll_recv_wq ( struct ib_device *ibdev, + struct ib_queue_pair *qp ) { + struct linda *linda = ib_get_drvdata ( ibdev ); + struct ib_work_queue *wq = &qp->recv; + struct linda_recv_work_queue *linda_wq = ib_wq_get_drvdata ( wq ); + struct QIB_7220_RcvHdrHead0 rcvhdrhead; + unsigned int ctx = linda_qpn_to_ctx ( qp->qpn ); + unsigned int header_prod; + + /* Check for received packets */ + header_prod = ( BIT_GET ( &linda_wq->header_prod, Value ) << 2 ); + if ( header_prod == linda_wq->header_cons ) + return; + + /* Process all received packets */ + while ( linda_wq->header_cons != header_prod ) { + + /* Complete the receive */ + linda_complete_recv ( ibdev, qp, linda_wq->header_cons ); + + /* Increment the consumer offset */ + linda_wq->header_cons += LINDA_RECV_HEADER_SIZE; + linda_wq->header_cons %= LINDA_RECV_HEADERS_SIZE; + } + + /* Update consumer offset */ + memset ( &rcvhdrhead, 0, sizeof ( rcvhdrhead ) ); + BIT_FILL_2 ( &rcvhdrhead, + RcvHeadPointer, ( linda_wq->header_cons >> 2 ), + counter, 1 ); + linda_writeq_array64k ( linda, &rcvhdrhead, + QIB_7220_RcvHdrHead0_offset, ctx ); +} + +/** + * Poll completion queue + * + * @v ibdev Infiniband device + * @v cq Completion queue + */ +static void linda_poll_cq ( struct ib_device *ibdev, + struct ib_completion_queue *cq ) { + struct ib_work_queue *wq; + + /* Poll associated send and receive queues */ + list_for_each_entry ( wq, &cq->work_queues, list ) { + if ( wq->is_send ) { + linda_poll_send_wq ( ibdev, wq->qp ); + } else { + linda_poll_recv_wq ( ibdev, wq->qp ); + } + } +} + +/*************************************************************************** + * + * Event queues + * + *************************************************************************** + */ + +/** + * Poll event queue + * + * @v ibdev Infiniband device + */ +static void linda_poll_eq ( struct ib_device *ibdev ) { + struct linda *linda = ib_get_drvdata ( ibdev ); + struct QIB_7220_ErrStatus errstatus; + struct QIB_7220_ErrClear errclear; + + /* Check for link status changes */ + DBG_DISABLE ( DBGLVL_IO ); + linda_readq ( linda, &errstatus, QIB_7220_ErrStatus_offset ); + DBG_ENABLE ( DBGLVL_IO ); + if ( BIT_GET ( &errstatus, IBStatusChanged ) ) { + linda_link_state_changed ( ibdev ); + memset ( &errclear, 0, sizeof ( errclear ) ); + BIT_FILL_1 ( &errclear, IBStatusChangedClear, 1 ); + linda_writeq ( linda, &errclear, QIB_7220_ErrClear_offset ); + } +} + +/*************************************************************************** + * + * Infiniband link-layer operations + * + *************************************************************************** + */ + +/** + * Initialise Infiniband link + * + * @v ibdev Infiniband device + * @ret rc Return status code + */ +static int linda_open ( struct ib_device *ibdev ) { + struct linda *linda = ib_get_drvdata ( ibdev ); + struct QIB_7220_Control control; + + /* Disable link */ + linda_readq ( linda, &control, QIB_7220_Control_offset ); + BIT_SET ( &control, LinkEn, 1 ); + linda_writeq ( linda, &control, QIB_7220_Control_offset ); + return 0; +} + +/** + * Close Infiniband link + * + * @v ibdev Infiniband device + */ +static void linda_close ( struct ib_device *ibdev ) { + struct linda *linda = ib_get_drvdata ( ibdev ); + struct QIB_7220_Control control; + + /* Disable link */ + linda_readq ( linda, &control, QIB_7220_Control_offset ); + BIT_SET ( &control, LinkEn, 0 ); + linda_writeq ( linda, &control, QIB_7220_Control_offset ); +} + +/*************************************************************************** + * + * Multicast group operations + * + *************************************************************************** + */ + +/** + * Attach to multicast group + * + * @v ibdev Infiniband device + * @v qp Queue pair + * @v gid Multicast GID + * @ret rc Return status code + */ +static int linda_mcast_attach ( struct ib_device *ibdev, + struct ib_queue_pair *qp, + struct ib_gid *gid ) { + struct linda *linda = ib_get_drvdata ( ibdev ); + + ( void ) linda; + ( void ) qp; + ( void ) gid; + return 0; +} + +/** + * Detach from multicast group + * + * @v ibdev Infiniband device + * @v qp Queue pair + * @v gid Multicast GID + */ +static void linda_mcast_detach ( struct ib_device *ibdev, + struct ib_queue_pair *qp, + struct ib_gid *gid ) { + struct linda *linda = ib_get_drvdata ( ibdev ); + + ( void ) linda; + ( void ) qp; + ( void ) gid; +} + +/** Linda Infiniband operations */ +static struct ib_device_operations linda_ib_operations = { + .create_cq = linda_create_cq, + .destroy_cq = linda_destroy_cq, + .create_qp = linda_create_qp, + .modify_qp = linda_modify_qp, + .destroy_qp = linda_destroy_qp, + .post_send = linda_post_send, + .post_recv = linda_post_recv, + .poll_cq = linda_poll_cq, + .poll_eq = linda_poll_eq, + .open = linda_open, + .close = linda_close, + .mcast_attach = linda_mcast_attach, + .mcast_detach = linda_mcast_detach, +}; + +/*************************************************************************** + * + * I2C bus operations + * + *************************************************************************** + */ + +/** Linda I2C bit to GPIO mappings */ +static unsigned int linda_i2c_bits[] = { + [I2C_BIT_SCL] = ( 1 << LINDA_GPIO_SCL ), + [I2C_BIT_SDA] = ( 1 << LINDA_GPIO_SDA ), +}; + +/** + * Read Linda I2C line status + * + * @v basher Bit-bashing interface + * @v bit_id Bit number + * @ret zero Input is a logic 0 + * @ret non-zero Input is a logic 1 + */ +static int linda_i2c_read_bit ( struct bit_basher *basher, + unsigned int bit_id ) { + struct linda *linda = + container_of ( basher, struct linda, i2c.basher ); + struct QIB_7220_EXTStatus extstatus; + unsigned int status; + + DBG_DISABLE ( DBGLVL_IO ); + + linda_readq ( linda, &extstatus, QIB_7220_EXTStatus_offset ); + status = ( BIT_GET ( &extstatus, GPIOIn ) & linda_i2c_bits[bit_id] ); + + DBG_ENABLE ( DBGLVL_IO ); + + return status; +} + +/** + * Write Linda I2C line status + * + * @v basher Bit-bashing interface + * @v bit_id Bit number + * @v data Value to write + */ +static void linda_i2c_write_bit ( struct bit_basher *basher, + unsigned int bit_id, unsigned long data ) { + struct linda *linda = + container_of ( basher, struct linda, i2c.basher ); + struct QIB_7220_EXTCtrl extctrl; + struct QIB_7220_GPIO gpioout; + unsigned int bit = linda_i2c_bits[bit_id]; + unsigned int outputs = 0; + unsigned int output_enables = 0; + + DBG_DISABLE ( DBGLVL_IO ); + + /* Read current GPIO mask and outputs */ + linda_readq ( linda, &extctrl, QIB_7220_EXTCtrl_offset ); + linda_readq ( linda, &gpioout, QIB_7220_GPIOOut_offset ); + + /* Update outputs and output enables. I2C lines are tied + * high, so we always set the output to 0 and use the output + * enable to control the line. + */ + output_enables = BIT_GET ( &extctrl, GPIOOe ); + output_enables = ( ( output_enables & ~bit ) | ( ~data & bit ) ); + outputs = BIT_GET ( &gpioout, GPIO ); + outputs = ( outputs & ~bit ); + BIT_SET ( &extctrl, GPIOOe, output_enables ); + BIT_SET ( &gpioout, GPIO, outputs ); + + /* Write the output enable first; that way we avoid logic + * hazards. + */ + linda_writeq ( linda, &extctrl, QIB_7220_EXTCtrl_offset ); + linda_writeq ( linda, &gpioout, QIB_7220_GPIOOut_offset ); + mb(); + + DBG_ENABLE ( DBGLVL_IO ); +} + +/** Linda I2C bit-bashing interface operations */ +static struct bit_basher_operations linda_i2c_basher_ops = { + .read = linda_i2c_read_bit, + .write = linda_i2c_write_bit, +}; + +/** + * Initialise Linda I2C subsystem + * + * @v linda Linda device + * @ret rc Return status code + */ +static int linda_init_i2c ( struct linda *linda ) { + static int try_eeprom_address[] = { 0x51, 0x50 }; + unsigned int i; + int rc; + + /* Initialise bus */ + if ( ( rc = init_i2c_bit_basher ( &linda->i2c, + &linda_i2c_basher_ops ) ) != 0 ) { + DBGC ( linda, "Linda %p could not initialise I2C bus: %s\n", + linda, strerror ( rc ) ); + return rc; + } + + /* Probe for devices */ + for ( i = 0 ; i < ( sizeof ( try_eeprom_address ) / + sizeof ( try_eeprom_address[0] ) ) ; i++ ) { + init_i2c_eeprom ( &linda->eeprom, try_eeprom_address[i] ); + if ( ( rc = i2c_check_presence ( &linda->i2c.i2c, + &linda->eeprom ) ) == 0 ) { + DBGC2 ( linda, "Linda %p found EEPROM at %02x\n", + linda, try_eeprom_address[i] ); + return 0; + } + } + + DBGC ( linda, "Linda %p could not find EEPROM\n", linda ); + return -ENODEV; +} + +/** + * Read EEPROM parameters + * + * @v linda Linda device + * @v guid GUID to fill in + * @ret rc Return status code + */ +static int linda_read_eeprom ( struct linda *linda, + struct ib_gid_half *guid ) { + struct i2c_interface *i2c = &linda->i2c.i2c; + int rc; + + /* Read GUID */ + if ( ( rc = i2c->read ( i2c, &linda->eeprom, LINDA_EEPROM_GUID_OFFSET, + guid->bytes, sizeof ( *guid ) ) ) != 0 ) { + DBGC ( linda, "Linda %p could not read GUID: %s\n", + linda, strerror ( rc ) ); + return rc; + } + DBGC2 ( linda, "Linda %p has GUID %02x:%02x:%02x:%02x:%02x:%02x:" + "%02x:%02x\n", linda, guid->bytes[0], guid->bytes[1], + guid->bytes[2], guid->bytes[3], guid->bytes[4], + guid->bytes[5], guid->bytes[6], guid->bytes[7] ); + + /* Read serial number (debug only) */ + if ( DBG_LOG ) { + uint8_t serial[LINDA_EEPROM_SERIAL_SIZE + 1]; + + serial[ sizeof ( serial ) - 1 ] = '\0'; + if ( ( rc = i2c->read ( i2c, &linda->eeprom, + LINDA_EEPROM_SERIAL_OFFSET, serial, + ( sizeof ( serial ) - 1 ) ) ) != 0 ) { + DBGC ( linda, "Linda %p could not read serial: %s\n", + linda, strerror ( rc ) ); + return rc; + } + DBGC2 ( linda, "Linda %p has serial number \"%s\"\n", + linda, serial ); + } + + return 0; +} + +/*************************************************************************** + * + * External parallel bus access + * + *************************************************************************** + */ + +/** + * Request ownership of the IB external parallel bus + * + * @v linda Linda device + * @ret rc Return status code + */ +static int linda_ib_epb_request ( struct linda *linda ) { + struct QIB_7220_ibsd_epb_access_ctrl access; + unsigned int i; + + /* Request ownership */ + memset ( &access, 0, sizeof ( access ) ); + BIT_FILL_1 ( &access, sw_ib_epb_req, 1 ); + linda_writeq ( linda, &access, QIB_7220_ibsd_epb_access_ctrl_offset ); + + /* Wait for ownership to be granted */ + for ( i = 0 ; i < LINDA_EPB_REQUEST_MAX_WAIT_US ; i++ ) { + linda_readq ( linda, &access, + QIB_7220_ibsd_epb_access_ctrl_offset ); + if ( BIT_GET ( &access, sw_ib_epb_req_granted ) ) + return 0; + udelay ( 1 ); + } + + DBGC ( linda, "Linda %p timed out waiting for IB EPB request\n", + linda ); + return -ETIMEDOUT; +} + +/** + * Wait for IB external parallel bus transaction to complete + * + * @v linda Linda device + * @v xact Buffer to hold transaction result + * @ret rc Return status code + */ +static int linda_ib_epb_wait ( struct linda *linda, + struct QIB_7220_ibsd_epb_transaction_reg *xact ) { + unsigned int i; + + /* Discard first read to allow for signals crossing clock domains */ + linda_readq ( linda, xact, QIB_7220_ibsd_epb_transaction_reg_offset ); + + for ( i = 0 ; i < LINDA_EPB_XACT_MAX_WAIT_US ; i++ ) { + linda_readq ( linda, xact, + QIB_7220_ibsd_epb_transaction_reg_offset ); + if ( BIT_GET ( xact, ib_epb_rdy ) ) { + if ( BIT_GET ( xact, ib_epb_req_error ) ) { + DBGC ( linda, "Linda %p EPB transaction " + "failed\n", linda ); + return -EIO; + } else { + return 0; + } + } + udelay ( 1 ); + } + + DBGC ( linda, "Linda %p timed out waiting for IB EPB transaction\n", + linda ); + return -ETIMEDOUT; +} + +/** + * Release ownership of the IB external parallel bus + * + * @v linda Linda device + */ +static void linda_ib_epb_release ( struct linda *linda ) { + struct QIB_7220_ibsd_epb_access_ctrl access; + + memset ( &access, 0, sizeof ( access ) ); + BIT_FILL_1 ( &access, sw_ib_epb_req, 0 ); + linda_writeq ( linda, &access, QIB_7220_ibsd_epb_access_ctrl_offset ); +} + +/** + * Read data via IB external parallel bus + * + * @v linda Linda device + * @v location EPB location + * @ret data Data read, or negative error + * + * You must have already acquired ownership of the IB external + * parallel bus. + */ +static int linda_ib_epb_read ( struct linda *linda, unsigned int location ) { + struct QIB_7220_ibsd_epb_transaction_reg xact; + unsigned int data; + int rc; + + /* Ensure no transaction is currently in progress */ + if ( ( rc = linda_ib_epb_wait ( linda, &xact ) ) != 0 ) + return rc; + + /* Process data */ + memset ( &xact, 0, sizeof ( xact ) ); + BIT_FILL_3 ( &xact, + ib_epb_address, LINDA_EPB_LOC_ADDRESS ( location ), + ib_epb_read_write, LINDA_EPB_READ, + ib_epb_cs, LINDA_EPB_LOC_CS ( location ) ); + linda_writeq ( linda, &xact, + QIB_7220_ibsd_epb_transaction_reg_offset ); + + /* Wait for transaction to complete */ + if ( ( rc = linda_ib_epb_wait ( linda, &xact ) ) != 0 ) + return rc; + + data = BIT_GET ( &xact, ib_epb_data ); + return data; +} + +/** + * Write data via IB external parallel bus + * + * @v linda Linda device + * @v location EPB location + * @v data Data to write + * @ret rc Return status code + * + * You must have already acquired ownership of the IB external + * parallel bus. + */ +static int linda_ib_epb_write ( struct linda *linda, unsigned int location, + unsigned int data ) { + struct QIB_7220_ibsd_epb_transaction_reg xact; + int rc; + + /* Ensure no transaction is currently in progress */ + if ( ( rc = linda_ib_epb_wait ( linda, &xact ) ) != 0 ) + return rc; + + /* Process data */ + memset ( &xact, 0, sizeof ( xact ) ); + BIT_FILL_4 ( &xact, + ib_epb_data, data, + ib_epb_address, LINDA_EPB_LOC_ADDRESS ( location ), + ib_epb_read_write, LINDA_EPB_WRITE, + ib_epb_cs, LINDA_EPB_LOC_CS ( location ) ); + linda_writeq ( linda, &xact, + QIB_7220_ibsd_epb_transaction_reg_offset ); + + /* Wait for transaction to complete */ + if ( ( rc = linda_ib_epb_wait ( linda, &xact ) ) != 0 ) + return rc; + + return 0; +} + +/** + * Read/modify/write EPB register + * + * @v linda Linda device + * @v cs Chip select + * @v channel Channel + * @v element Element + * @v reg Register + * @v value Value to set + * @v mask Mask to apply to old value + * @ret rc Return status code + */ +static int linda_ib_epb_mod_reg ( struct linda *linda, unsigned int cs, + unsigned int channel, unsigned int element, + unsigned int reg, unsigned int value, + unsigned int mask ) { + unsigned int location; + int old_value; + int rc; + + DBG_DISABLE ( DBGLVL_IO ); + + /* Sanity check */ + assert ( ( value & mask ) == value ); + + /* Acquire bus ownership */ + if ( ( rc = linda_ib_epb_request ( linda ) ) != 0 ) + goto out; + + /* Read existing value, if necessary */ + location = LINDA_EPB_LOC ( cs, channel, element, reg ); + if ( (~mask) & 0xff ) { + old_value = linda_ib_epb_read ( linda, location ); + if ( old_value < 0 ) { + rc = old_value; + goto out_release; + } + } else { + old_value = 0; + } + + /* Update value */ + value = ( ( old_value & ~mask ) | value ); + DBGCP ( linda, "Linda %p CS %d EPB(%d,%d,%#02x) %#02x => %#02x\n", + linda, cs, channel, element, reg, old_value, value ); + if ( ( rc = linda_ib_epb_write ( linda, location, value ) ) != 0 ) + goto out_release; + + out_release: + /* Release bus */ + linda_ib_epb_release ( linda ); + out: + DBG_ENABLE ( DBGLVL_IO ); + return rc; +} + +/** + * Transfer data to/from microcontroller RAM + * + * @v linda Linda device + * @v address Starting address + * @v write Data to write, or NULL + * @v read Data to read, or NULL + * @v len Length of data + * @ret rc Return status code + */ +static int linda_ib_epb_ram_xfer ( struct linda *linda, unsigned int address, + const void *write, void *read, + size_t len ) { + unsigned int control; + unsigned int address_hi; + unsigned int address_lo; + int data; + int rc; + + DBG_DISABLE ( DBGLVL_IO ); + + assert ( ! ( write && read ) ); + assert ( ( address % LINDA_EPB_UC_CHUNK_SIZE ) == 0 ); + assert ( ( len % LINDA_EPB_UC_CHUNK_SIZE ) == 0 ); + + /* Acquire bus ownership */ + if ( ( rc = linda_ib_epb_request ( linda ) ) != 0 ) + goto out; + + /* Process data */ + while ( len ) { + + /* Reset the address for each new chunk */ + if ( ( address % LINDA_EPB_UC_CHUNK_SIZE ) == 0 ) { + + /* Write the control register */ + control = ( read ? LINDA_EPB_UC_CTL_READ : + LINDA_EPB_UC_CTL_WRITE ); + if ( ( rc = linda_ib_epb_write ( linda, + LINDA_EPB_UC_CTL, + control ) ) != 0 ) + break; + + /* Write the address registers */ + address_hi = ( address >> 8 ); + if ( ( rc = linda_ib_epb_write ( linda, + LINDA_EPB_UC_ADDR_HI, + address_hi ) ) != 0 ) + break; + address_lo = ( address & 0xff ); + if ( ( rc = linda_ib_epb_write ( linda, + LINDA_EPB_UC_ADDR_LO, + address_lo ) ) != 0 ) + break; + } + + /* Read or write the data */ + if ( read ) { + data = linda_ib_epb_read ( linda, LINDA_EPB_UC_DATA ); + if ( data < 0 ) { + rc = data; + break; + } + *( ( uint8_t * ) read++ ) = data; + } else { + data = *( ( uint8_t * ) write++ ); + if ( ( rc = linda_ib_epb_write ( linda, + LINDA_EPB_UC_DATA, + data ) ) != 0 ) + break; + } + address++; + len--; + + /* Reset the control byte after each chunk */ + if ( ( address % LINDA_EPB_UC_CHUNK_SIZE ) == 0 ) { + if ( ( rc = linda_ib_epb_write ( linda, + LINDA_EPB_UC_CTL, + 0 ) ) != 0 ) + break; + } + } + + /* Release bus */ + linda_ib_epb_release ( linda ); + + out: + DBG_ENABLE ( DBGLVL_IO ); + return rc; +} + +/*************************************************************************** + * + * Infiniband SerDes initialisation + * + *************************************************************************** + */ + +/** A Linda SerDes parameter */ +struct linda_serdes_param { + /** EPB address as constructed by LINDA_EPB_ADDRESS() */ + uint16_t address; + /** Value to set */ + uint8_t value; + /** Mask to apply to old value */ + uint8_t mask; +} __packed; + +/** Magic "all channels" channel number */ +#define LINDA_EPB_ALL_CHANNELS 31 + +/** End of SerDes parameter list marker */ +#define LINDA_SERDES_PARAM_END { 0, 0, 0 } + +/** + * Program IB SerDes register(s) + * + * @v linda Linda device + * @v param SerDes parameter + * @ret rc Return status code + */ +static int linda_set_serdes_param ( struct linda *linda, + struct linda_serdes_param *param ) { + unsigned int channel; + unsigned int channel_start; + unsigned int channel_end; + unsigned int element; + unsigned int reg; + int rc; + + /* Break down the EPB address and determine channels */ + channel = LINDA_EPB_ADDRESS_CHANNEL ( param->address ); + element = LINDA_EPB_ADDRESS_ELEMENT ( param->address ); + reg = LINDA_EPB_ADDRESS_REG ( param->address ); + if ( channel == LINDA_EPB_ALL_CHANNELS ) { + channel_start = 0; + channel_end = 3; + } else { + channel_start = channel_end = channel; + } + + /* Modify register for each specified channel */ + for ( channel = channel_start ; channel <= channel_end ; channel++ ) { + if ( ( rc = linda_ib_epb_mod_reg ( linda, LINDA_EPB_CS_SERDES, + channel, element, reg, + param->value, + param->mask ) ) != 0 ) + return rc; + } + + return 0; +} + +/** + * Program IB SerDes registers + * + * @v linda Linda device + * @v param SerDes parameters + * @v count Number of parameters + * @ret rc Return status code + */ +static int linda_set_serdes_params ( struct linda *linda, + struct linda_serdes_param *params ) { + int rc; + + for ( ; params->mask != 0 ; params++ ){ + if ( ( rc = linda_set_serdes_param ( linda, + params ) ) != 0 ) + return rc; + } + + return 0; +} + +#define LINDA_DDS_VAL( amp_d, main_d, ipst_d, ipre_d, \ + amp_s, main_s, ipst_s, ipre_s ) \ + { LINDA_EPB_ADDRESS ( LINDA_EPB_ALL_CHANNELS, 9, 0x00 ), \ + ( ( ( amp_d & 0x1f ) << 1 ) | 1 ), 0xff }, \ + { LINDA_EPB_ADDRESS ( LINDA_EPB_ALL_CHANNELS, 9, 0x01 ), \ + ( ( ( amp_s & 0x1f ) << 1 ) | 1 ), 0xff }, \ + { LINDA_EPB_ADDRESS ( LINDA_EPB_ALL_CHANNELS, 9, 0x09 ), \ + ( ( main_d << 3 ) | 4 | ( ipre_d >> 2 ) ), 0xff }, \ + { LINDA_EPB_ADDRESS ( LINDA_EPB_ALL_CHANNELS, 9, 0x0a ), \ + ( ( main_s << 3 ) | 4 | ( ipre_s >> 2 ) ), 0xff }, \ + { LINDA_EPB_ADDRESS ( LINDA_EPB_ALL_CHANNELS, 9, 0x06 ), \ + ( ( ( ipst_d & 0xf ) << 1 ) | \ + ( ( ipre_d & 3 ) << 6 ) | 0x21 ), 0xff }, \ + { LINDA_EPB_ADDRESS ( LINDA_EPB_ALL_CHANNELS, 9, 0x07 ), \ + ( ( ( ipst_s & 0xf ) << 1 ) | \ + ( ( ipre_s & 3 ) << 6) | 0x21 ), 0xff } + +/** + * Linda SerDes default parameters + * + * These magic start-of-day values are taken from the Linux driver. + */ +static struct linda_serdes_param linda_serdes_defaults1[] = { + /* RXHSCTRL0 */ + { LINDA_EPB_ADDRESS ( LINDA_EPB_ALL_CHANNELS, 6, 0x00 ), 0xd4, 0xff }, + /* VCDL_DAC2 */ + { LINDA_EPB_ADDRESS ( LINDA_EPB_ALL_CHANNELS, 6, 0x05 ), 0x2d, 0xff }, + /* VCDL_CTRL2 */ + { LINDA_EPB_ADDRESS ( LINDA_EPB_ALL_CHANNELS, 6, 0x08 ), 0x03, 0x0f }, + /* START_EQ1 */ + { LINDA_EPB_ADDRESS ( LINDA_EPB_ALL_CHANNELS, 7, 0x27 ), 0x10, 0xff }, + /* START_EQ2 */ + { LINDA_EPB_ADDRESS ( LINDA_EPB_ALL_CHANNELS, 7, 0x28 ), 0x30, 0xff }, + /* BACTRL */ + { LINDA_EPB_ADDRESS ( LINDA_EPB_ALL_CHANNELS, 6, 0x0e ), 0x40, 0xff }, + /* LDOUTCTRL1 */ + { LINDA_EPB_ADDRESS ( LINDA_EPB_ALL_CHANNELS, 7, 0x06 ), 0x04, 0xff }, + /* RXHSSTATUS */ + { LINDA_EPB_ADDRESS ( LINDA_EPB_ALL_CHANNELS, 6, 0x0f ), 0x04, 0xff }, + /* End of this block */ + LINDA_SERDES_PARAM_END +}; +static struct linda_serdes_param linda_serdes_defaults2[] = { + /* LDOUTCTRL1 */ + { LINDA_EPB_ADDRESS ( LINDA_EPB_ALL_CHANNELS, 7, 0x06 ), 0x00, 0xff }, + /* DDS values */ + LINDA_DDS_VAL ( 31, 19, 12, 0, 29, 22, 9, 0 ), + /* Set Rcv Eq. to Preset node */ + { LINDA_EPB_ADDRESS ( LINDA_EPB_ALL_CHANNELS, 7, 0x27 ), 0x10, 0xff }, + /* DFELTHFDR */ + { LINDA_EPB_ADDRESS ( LINDA_EPB_ALL_CHANNELS, 7, 0x08 ), 0x00, 0xff }, + /* DFELTHHDR */ + { LINDA_EPB_ADDRESS ( LINDA_EPB_ALL_CHANNELS, 7, 0x21 ), 0x00, 0xff }, + /* TLTHFDR */ + { LINDA_EPB_ADDRESS ( LINDA_EPB_ALL_CHANNELS, 7, 0x09 ), 0x02, 0xff }, + /* TLTHHDR */ + { LINDA_EPB_ADDRESS ( LINDA_EPB_ALL_CHANNELS, 7, 0x23 ), 0x02, 0xff }, + /* ZFR */ + { LINDA_EPB_ADDRESS ( LINDA_EPB_ALL_CHANNELS, 7, 0x1b ), 0x0c, 0xff }, + /* ZCNT) */ + { LINDA_EPB_ADDRESS ( LINDA_EPB_ALL_CHANNELS, 7, 0x1c ), 0x0c, 0xff }, + /* GFR */ + { LINDA_EPB_ADDRESS ( LINDA_EPB_ALL_CHANNELS, 7, 0x1e ), 0x10, 0xff }, + /* GHR */ + { LINDA_EPB_ADDRESS ( LINDA_EPB_ALL_CHANNELS, 7, 0x1f ), 0x10, 0xff }, + /* VCDL_CTRL0 toggle */ + { LINDA_EPB_ADDRESS ( LINDA_EPB_ALL_CHANNELS, 6, 0x06 ), 0x20, 0xff }, + { LINDA_EPB_ADDRESS ( LINDA_EPB_ALL_CHANNELS, 6, 0x06 ), 0x00, 0xff }, + /* CMUCTRL5 */ + { LINDA_EPB_ADDRESS ( 7, 0, 0x15 ), 0x80, 0xff }, + /* End of this block */ + LINDA_SERDES_PARAM_END +}; +static struct linda_serdes_param linda_serdes_defaults3[] = { + /* START_EQ1 */ + { LINDA_EPB_ADDRESS ( LINDA_EPB_ALL_CHANNELS, 7, 0x27 ), 0x00, 0x38 }, + /* End of this block */ + LINDA_SERDES_PARAM_END +}; + +/** + * Program the microcontroller RAM + * + * @v linda Linda device + * @ret rc Return status code + */ +static int linda_program_uc_ram ( struct linda *linda ) { + int rc; + + if ( ( rc = linda_ib_epb_ram_xfer ( linda, 0, linda_ib_fw, NULL, + sizeof ( linda_ib_fw ) ) ) != 0 ){ + DBGC ( linda, "Linda %p could not load IB firmware: %s\n", + linda, strerror ( rc ) ); + return rc; + } + + return 0; +} + +/** + * Verify the microcontroller RAM + * + * @v linda Linda device + * @ret rc Return status code + */ +static int linda_verify_uc_ram ( struct linda *linda ) { + uint8_t verify[LINDA_EPB_UC_CHUNK_SIZE]; + unsigned int offset; + int rc; + + for ( offset = 0 ; offset < sizeof ( linda_ib_fw ); + offset += sizeof ( verify ) ) { + if ( ( rc = linda_ib_epb_ram_xfer ( linda, offset, + NULL, verify, + sizeof (verify) )) != 0 ){ + DBGC ( linda, "Linda %p could not read back IB " + "firmware: %s\n", linda, strerror ( rc ) ); + return rc; + } + if ( memcmp ( ( linda_ib_fw + offset ), verify, + sizeof ( verify ) ) != 0 ) { + DBGC ( linda, "Linda %p firmware verification failed " + "at offset %#x\n", linda, offset ); + DBGC_HDA ( linda, offset, ( linda_ib_fw + offset ), + sizeof ( verify ) ); + DBGC_HDA ( linda, offset, verify, sizeof ( verify ) ); + return -EIO; + } + } + + DBGC2 ( linda, "Linda %p firmware verified ok\n", linda ); + return 0; +} + +/** + * Use the microcontroller to trim the IB link + * + * @v linda Linda device + * @ret rc Return status code + */ +static int linda_trim_ib ( struct linda *linda ) { + struct QIB_7220_IBSerDesCtrl ctrl; + struct QIB_7220_IntStatus intstatus; + unsigned int i; + int rc; + + /* Bring the microcontroller out of reset */ + linda_readq ( linda, &ctrl, QIB_7220_IBSerDesCtrl_offset ); + BIT_SET ( &ctrl, ResetIB_uC_Core, 0 ); + linda_writeq ( linda, &ctrl, QIB_7220_IBSerDesCtrl_offset ); + + /* Wait for the "trim done" signal */ + for ( i = 0 ; i < LINDA_TRIM_DONE_MAX_WAIT_MS ; i++ ) { + linda_readq ( linda, &intstatus, QIB_7220_IntStatus_offset ); + if ( BIT_GET ( &intstatus, IBSerdesTrimDone ) ) { + rc = 0; + goto out_reset; + } + mdelay ( 1 ); + } + + DBGC ( linda, "Linda %p timed out waiting for trim done\n", linda ); + rc = -ETIMEDOUT; + out_reset: + /* Put the microcontroller back into reset */ + BIT_SET ( &ctrl, ResetIB_uC_Core, 1 ); + linda_writeq ( linda, &ctrl, QIB_7220_IBSerDesCtrl_offset ); + + return rc; +} + +/** + * Initialise the IB SerDes + * + * @v linda Linda device + * @ret rc Return status code + */ +static int linda_init_ib_serdes ( struct linda *linda ) { + struct QIB_7220_Control control; + struct QIB_7220_IBCCtrl ibcctrl; + struct QIB_7220_IBCDDRCtrl ibcddrctrl; + struct QIB_7220_XGXSCfg xgxscfg; + int rc; + + /* Disable link */ + linda_readq ( linda, &control, QIB_7220_Control_offset ); + BIT_SET ( &control, LinkEn, 0 ); + linda_writeq ( linda, &control, QIB_7220_Control_offset ); + + /* Configure sensible defaults for IBC */ + memset ( &ibcctrl, 0, sizeof ( ibcctrl ) ); + BIT_FILL_6 ( &ibcctrl, /* Tuning values taken from Linux driver */ + FlowCtrlPeriod, 0x03, + FlowCtrlWaterMark, 0x05, + MaxPktLen, ( ( LINDA_RECV_HEADER_SIZE + + LINDA_RECV_PAYLOAD_SIZE + + 4 /* ICRC */ ) >> 2 ), + PhyerrThreshold, 0xf, + OverrunThreshold, 0xf, + CreditScale, 0x4 ); + linda_writeq ( linda, &ibcctrl, QIB_7220_IBCCtrl_offset ); + + /* Force SDR only to avoid needing all the DDR tuning, + * Mellanox compatibiltiy hacks etc. SDR is plenty for + * boot-time operation. + */ + linda_readq ( linda, &ibcddrctrl, QIB_7220_IBCDDRCtrl_offset ); + BIT_SET ( &ibcddrctrl, IB_ENHANCED_MODE, 0 ); + BIT_SET ( &ibcddrctrl, SD_SPEED_SDR, 1 ); + BIT_SET ( &ibcddrctrl, SD_SPEED_DDR, 0 ); + BIT_SET ( &ibcddrctrl, SD_SPEED_QDR, 0 ); + BIT_SET ( &ibcddrctrl, HRTBT_ENB, 0 ); + BIT_SET ( &ibcddrctrl, HRTBT_AUTO, 0 ); + linda_writeq ( linda, &ibcddrctrl, QIB_7220_IBCDDRCtrl_offset ); + + /* Set default SerDes parameters */ + if ( ( rc = linda_set_serdes_params ( linda, + linda_serdes_defaults1 ) ) != 0 ) + return rc; + udelay ( 415 ); /* Magic delay while SerDes sorts itself out */ + if ( ( rc = linda_set_serdes_params ( linda, + linda_serdes_defaults2 ) ) != 0 ) + return rc; + + /* Program the microcontroller RAM */ + if ( ( rc = linda_program_uc_ram ( linda ) ) != 0 ) + return rc; + + /* Verify the microcontroller RAM contents */ + if ( DBGLVL_LOG ) { + if ( ( rc = linda_verify_uc_ram ( linda ) ) != 0 ) + return rc; + } + + /* More SerDes tuning */ + if ( ( rc = linda_set_serdes_params ( linda, + linda_serdes_defaults3 ) ) != 0 ) + return rc; + + /* Use the microcontroller to trim the IB link */ + if ( ( rc = linda_trim_ib ( linda ) ) != 0 ) + return rc; + + /* Bring XGXS out of reset */ + linda_readq ( linda, &xgxscfg, QIB_7220_XGXSCfg_offset ); + BIT_SET ( &xgxscfg, tx_rx_reset, 0 ); + BIT_SET ( &xgxscfg, xcv_reset, 0 ); + linda_writeq ( linda, &xgxscfg, QIB_7220_XGXSCfg_offset ); + + return rc; +} + +/*************************************************************************** + * + * PCI layer interface + * + *************************************************************************** + */ + +/** + * Probe PCI device + * + * @v pci PCI device + * @v id PCI ID + * @ret rc Return status code + */ +static int linda_probe ( struct pci_device *pci, + const struct pci_device_id *id __unused ) { + struct ib_device *ibdev; + struct linda *linda; + struct QIB_7220_Revision revision; + int rc; + + /* Allocate Infiniband device */ + ibdev = alloc_ibdev ( sizeof ( *linda ) ); + if ( ! ibdev ) { + rc = -ENOMEM; + goto err_alloc_ibdev; + } + pci_set_drvdata ( pci, ibdev ); + linda = ib_get_drvdata ( ibdev ); + ibdev->op = &linda_ib_operations; + ibdev->dev = &pci->dev; + ibdev->port = 1; + + /* Fix up PCI device */ + adjust_pci_device ( pci ); + + /* Get PCI BARs */ + linda->regs = ioremap ( pci->membase, LINDA_BAR0_SIZE ); + DBGC2 ( linda, "Linda %p has BAR at %08lx\n", linda, pci->membase ); + + /* Print some general data */ + linda_readq ( linda, &revision, QIB_7220_Revision_offset ); + DBGC2 ( linda, "Linda %p board %02lx v%ld.%ld.%ld.%ld\n", linda, + BIT_GET ( &revision, BoardID ), + BIT_GET ( &revision, R_SW ), + BIT_GET ( &revision, R_Arch ), + BIT_GET ( &revision, R_ChipRevMajor ), + BIT_GET ( &revision, R_ChipRevMinor ) ); + + /* Initialise I2C subsystem */ + if ( ( rc = linda_init_i2c ( linda ) ) != 0 ) + goto err_init_i2c; + + /* Read EEPROM parameters */ + if ( ( rc = linda_read_eeprom ( linda, &ibdev->gid.u.half[1] ) ) != 0 ) + goto err_read_eeprom; + + /* Initialise send datapath */ + if ( ( rc = linda_init_send ( linda ) ) != 0 ) + goto err_init_send; + + /* Initialise receive datapath */ + if ( ( rc = linda_init_recv ( linda ) ) != 0 ) + goto err_init_recv; + + /* Initialise the IB SerDes */ + if ( ( rc = linda_init_ib_serdes ( linda ) ) != 0 ) + goto err_init_ib_serdes; + + /* Create the SMA */ + if ( ( rc = ib_create_sma ( &linda->sma, ibdev, + &linda_sma_operations ) ) != 0 ) + goto err_create_sma; + /* If the SMA doesn't get context 0, we're screwed */ + assert ( linda_qpn_to_ctx ( linda->sma.qp->qpn ) == 0 ); + + /* Register Infiniband device */ + if ( ( rc = register_ibdev ( ibdev ) ) != 0 ) { + DBGC ( linda, "Linda %p could not register IB " + "device: %s\n", linda, strerror ( rc ) ); + goto err_register_ibdev; + } + + return 0; + + unregister_ibdev ( ibdev ); + err_register_ibdev: + ib_destroy_sma ( &linda->sma ); + err_create_sma: + linda_fini_recv ( linda ); + err_init_recv: + linda_fini_send ( linda ); + err_init_send: + err_init_ib_serdes: + err_read_eeprom: + err_init_i2c: + ibdev_put ( ibdev ); + err_alloc_ibdev: + return rc; +} + +/** + * Remove PCI device + * + * @v pci PCI device + */ +static void linda_remove ( struct pci_device *pci ) { + struct ib_device *ibdev = pci_get_drvdata ( pci ); + struct linda *linda = ib_get_drvdata ( ibdev ); + + unregister_ibdev ( ibdev ); + ib_destroy_sma ( &linda->sma ); + linda_fini_recv ( linda ); + linda_fini_send ( linda ); + ibdev_put ( ibdev ); +} + +static struct pci_device_id linda_nics[] = { + PCI_ROM ( 0x1077, 0x7220, "iba7220", "QLE7240/7280 HCA driver" ), +}; + +struct pci_driver linda_driver __pci_driver = { + .ids = linda_nics, + .id_count = ( sizeof ( linda_nics ) / sizeof ( linda_nics[0] ) ), + .probe = linda_probe, + .remove = linda_remove, +}; diff --git a/gpxe/src/drivers/infiniband/linda.h b/gpxe/src/drivers/infiniband/linda.h new file mode 100644 index 00000000..dd1737a6 --- /dev/null +++ b/gpxe/src/drivers/infiniband/linda.h @@ -0,0 +1,271 @@ +#ifndef _LINDA_H +#define _LINDA_H + +/* + * 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., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +/** + * @file + * + * QLogic Linda Infiniband HCA + * + */ + +#define BITOPS_LITTLE_ENDIAN +#include <gpxe/bitops.h> +#include "qib_7220_regs.h" + +struct ib_device; + +/** A Linda GPIO register */ +struct QIB_7220_GPIO_pb { + pseudo_bit_t GPIO[16]; + pseudo_bit_t Reserved[48]; +}; +struct QIB_7220_GPIO { + PSEUDO_BIT_STRUCT ( struct QIB_7220_GPIO_pb ); +}; + +/** A Linda general scalar register */ +struct QIB_7220_scalar_pb { + pseudo_bit_t Value[64]; +}; +struct QIB_7220_scalar { + PSEUDO_BIT_STRUCT ( struct QIB_7220_scalar_pb ); +}; + +/** Linda send per-buffer control word */ +struct QIB_7220_SendPbc_pb { + pseudo_bit_t LengthP1_toibc[11]; + pseudo_bit_t Reserved1[4]; + pseudo_bit_t LengthP1_trigger[11]; + pseudo_bit_t Reserved2[3]; + pseudo_bit_t TestEbp[1]; + pseudo_bit_t Test[1]; + pseudo_bit_t Intr[1]; + pseudo_bit_t Reserved3[31]; + pseudo_bit_t VL15[1]; +}; +struct QIB_7220_SendPbc { + PSEUDO_BIT_STRUCT ( struct QIB_7220_SendPbc_pb ); +}; + +/** Linda send buffer availability */ +struct QIB_7220_SendBufAvail_pb { + pseudo_bit_t InUseCheck[144][2]; + pseudo_bit_t Reserved[32]; +}; +struct QIB_7220_SendBufAvail { + PSEUDO_BIT_STRUCT ( struct QIB_7220_SendBufAvail_pb ); +}; + +/** DMA alignment for send buffer availability */ +#define LINDA_SENDBUFAVAIL_ALIGN 64 + +/** A Linda eager receive descriptor */ +struct QIB_7220_RcvEgr_pb { + pseudo_bit_t Addr[37]; + pseudo_bit_t BufSize[3]; + pseudo_bit_t Reserved[24]; +}; +struct QIB_7220_RcvEgr { + PSEUDO_BIT_STRUCT ( struct QIB_7220_RcvEgr_pb ); +}; + +/** Linda receive header flags */ +struct QIB_7220_RcvHdrFlags_pb { + pseudo_bit_t PktLen[11]; + pseudo_bit_t RcvType[3]; + pseudo_bit_t SoftB[1]; + pseudo_bit_t SoftA[1]; + pseudo_bit_t EgrIndex[12]; + pseudo_bit_t Reserved1[3]; + pseudo_bit_t UseEgrBfr[1]; + pseudo_bit_t RcvSeq[4]; + pseudo_bit_t HdrqOffset[11]; + pseudo_bit_t Reserved2[8]; + pseudo_bit_t IBErr[1]; + pseudo_bit_t MKErr[1]; + pseudo_bit_t TIDErr[1]; + pseudo_bit_t KHdrErr[1]; + pseudo_bit_t MTUErr[1]; + pseudo_bit_t LenErr[1]; + pseudo_bit_t ParityErr[1]; + pseudo_bit_t VCRCErr[1]; + pseudo_bit_t ICRCErr[1]; +}; +struct QIB_7220_RcvHdrFlags { + PSEUDO_BIT_STRUCT ( struct QIB_7220_RcvHdrFlags_pb ); +}; + +/** Linda memory BAR size */ +#define LINDA_BAR0_SIZE 0x400000 + +/** Linda I2C SCL line GPIO number */ +#define LINDA_GPIO_SCL 0 + +/** Linda I2C SDA line GPIO number */ +#define LINDA_GPIO_SDA 1 + +/** GUID offset within EEPROM */ +#define LINDA_EEPROM_GUID_OFFSET 3 + +/** GUID size within EEPROM */ +#define LINDA_EEPROM_GUID_SIZE 8 + +/** Board serial number offset within EEPROM */ +#define LINDA_EEPROM_SERIAL_OFFSET 12 + +/** Board serial number size within EEPROM */ +#define LINDA_EEPROM_SERIAL_SIZE 12 + +/** Maximum number of send buffers used + * + * This is a policy decision. Must be less than or equal to the total + * number of send buffers supported by the hardware (128). + */ +#define LINDA_MAX_SEND_BUFS 32 + +/** Linda send buffer size */ +#define LINDA_SEND_BUF_SIZE 4096 + +/** Number of contexts (including kernel context) + * + * This is a policy decision. Must be 5, 9 or 17. + */ +#define LINDA_NUM_CONTEXTS 5 + +/** PortCfg values for different numbers of contexts */ +enum linda_portcfg { + LINDA_PORTCFG_5CTX = 0, + LINDA_PORTCFG_9CTX = 1, + LINDA_PORTCFG_17CTX = 2, +}; + +/** PortCfg values for different numbers of contexts */ +#define LINDA_EAGER_ARRAY_SIZE_5CTX_0 2048 +#define LINDA_EAGER_ARRAY_SIZE_5CTX_OTHER 4096 +#define LINDA_EAGER_ARRAY_SIZE_9CTX_0 2048 +#define LINDA_EAGER_ARRAY_SIZE_9CTX_OTHER 2048 +#define LINDA_EAGER_ARRAY_SIZE_17CTX_0 2048 +#define LINDA_EAGER_ARRAY_SIZE_17CTX_OTHER 1024 + +/** Eager buffer required alignment */ +#define LINDA_EAGER_BUFFER_ALIGN 2048 + +/** Eager buffer size encodings */ +enum linda_eager_buffer_size { + LINDA_EAGER_BUFFER_NONE = 0, + LINDA_EAGER_BUFFER_2K = 1, + LINDA_EAGER_BUFFER_4K = 2, + LINDA_EAGER_BUFFER_8K = 3, + LINDA_EAGER_BUFFER_16K = 4, + LINDA_EAGER_BUFFER_32K = 5, + LINDA_EAGER_BUFFER_64K = 6, +}; + +/** Number of RX headers per context + * + * This is a policy decision. + */ +#define LINDA_RECV_HEADER_COUNT 8 + +/** Maximum size of each RX header + * + * This is a policy decision. Must be divisible by 4. + */ +#define LINDA_RECV_HEADER_SIZE 96 + +/** Total size of an RX header ring */ +#define LINDA_RECV_HEADERS_SIZE \ + ( LINDA_RECV_HEADER_SIZE * LINDA_RECV_HEADER_COUNT ) + +/** RX header alignment */ +#define LINDA_RECV_HEADERS_ALIGN 64 + +/** RX payload size + * + * This is a policy decision. Must be a valid eager buffer size. + */ +#define LINDA_RECV_PAYLOAD_SIZE 2048 + +/** QPN used for Infinipath Packets + * + * This is a policy decision. Must have bit 0 clear. Must not be a + * QPN that we will use. + */ +#define LINDA_QP_IDETH 0xdead0 + +/** Maximum time for wait for external parallel bus request, in us */ +#define LINDA_EPB_REQUEST_MAX_WAIT_US 500 + +/** Maximum time for wait for external parallel bus transaction, in us */ +#define LINDA_EPB_XACT_MAX_WAIT_US 500 + +/** Linda external parallel bus chip selects */ +#define LINDA_EPB_CS_SERDES 1 +#define LINDA_EPB_CS_UC 2 + +/** Linda external parallel bus read/write operations */ +#define LINDA_EPB_WRITE 0 +#define LINDA_EPB_READ 1 + +/** Linda external parallel bus register addresses */ +#define LINDA_EPB_ADDRESS( _channel, _element, _reg ) \ + ( (_element) | ( (_channel) << 4 ) | ( (_reg) << 9 ) ) +#define LINDA_EPB_ADDRESS_CHANNEL( _address ) ( ( (_address) >> 4 ) & 0x1f ) +#define LINDA_EPB_ADDRESS_ELEMENT( _address ) ( ( (_address) >> 0 ) & 0x0f ) +#define LINDA_EPB_ADDRESS_REG( _address ) ( ( (_address) >> 9 ) & 0x3f ) + +/** Linda external parallel bus locations + * + * The location is used by the driver to encode both the chip select + * and the EPB address. + */ +#define LINDA_EPB_LOC( _cs, _channel, _element, _reg) \ + ( ( (_cs) << 16 ) | LINDA_EPB_ADDRESS ( _channel, _element, _reg ) ) +#define LINDA_EPB_LOC_ADDRESS( _loc ) ( (_loc) & 0xffff ) +#define LINDA_EPB_LOC_CS( _loc ) ( (_loc) >> 16 ) + +/** Linda external parallel bus microcontroller register addresses */ +#define LINDA_EPB_UC_CHANNEL 6 +#define LINDA_EPB_UC_LOC( _reg ) \ + LINDA_EPB_LOC ( LINDA_EPB_CS_UC, LINDA_EPB_UC_CHANNEL, 0, (_reg) ) +#define LINDA_EPB_UC_CTL LINDA_EPB_UC_LOC ( 0 ) +#define LINDA_EPB_UC_CTL_WRITE 1 +#define LINDA_EPB_UC_CTL_READ 2 +#define LINDA_EPB_UC_ADDR_LO LINDA_EPB_UC_LOC ( 2 ) +#define LINDA_EPB_UC_ADDR_HI LINDA_EPB_UC_LOC ( 3 ) +#define LINDA_EPB_UC_DATA LINDA_EPB_UC_LOC ( 4 ) +#define LINDA_EPB_UC_CHUNK_SIZE 64 + +extern uint8_t linda_ib_fw[8192]; + +/** Maximum time to wait for "trim done" signal, in ms */ +#define LINDA_TRIM_DONE_MAX_WAIT_MS 1000 + +/** Linda link states */ +enum linda_link_state { + LINDA_LINK_STATE_DOWN = 0, + LINDA_LINK_STATE_INIT = 1, + LINDA_LINK_STATE_ARM = 2, + LINDA_LINK_STATE_ACTIVE = 3, + LINDA_LINK_STATE_ACT_DEFER = 4, +}; + +#endif /* _LINDA_H */ diff --git a/gpxe/src/drivers/infiniband/linda_fw.c b/gpxe/src/drivers/infiniband/linda_fw.c new file mode 100644 index 00000000..fc5ea077 --- /dev/null +++ b/gpxe/src/drivers/infiniband/linda_fw.c @@ -0,0 +1,1067 @@ +/* + * Copyright (c) 2007, 2008 QLogic Corporation. All rights reserved. + * + * This software is available to you under a choice of one of two + * licenses. You may choose to be licensed under the terms of the GNU + * General Public License (GPL) Version 2, available from the file + * COPYING in the main directory of this source tree, or the + * OpenIB.org BSD license below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +/* + * This file contains the memory image from the vendor, to be copied into + * the IB SERDES of the IBA7220 during initialization. + * The file also includes the two functions which use this image. + */ + +#include <stdint.h> +#include "linda.h" + +uint8_t linda_ib_fw[8192] = { +/*0000*/0x02, 0x0A, 0x29, 0x02, 0x0A, 0x87, 0xE5, 0xE6, + 0x30, 0xE6, 0x04, 0x7F, 0x01, 0x80, 0x02, 0x7F, +/*0010*/0x00, 0xE5, 0xE2, 0x30, 0xE4, 0x04, 0x7E, 0x01, + 0x80, 0x02, 0x7E, 0x00, 0xEE, 0x5F, 0x60, 0x08, +/*0020*/0x53, 0xF9, 0xF7, 0xE4, 0xF5, 0xFE, 0x80, 0x08, + 0x7F, 0x0A, 0x12, 0x17, 0x31, 0x12, 0x0E, 0xA2, +/*0030*/0x75, 0xFC, 0x08, 0xE4, 0xF5, 0xFD, 0xE5, 0xE7, + 0x20, 0xE7, 0x03, 0x43, 0xF9, 0x08, 0x22, 0x00, +/*0040*/0x01, 0x20, 0x11, 0x00, 0x04, 0x20, 0x00, 0x75, + 0x51, 0x01, 0xE4, 0xF5, 0x52, 0xF5, 0x53, 0xF5, +/*0050*/0x52, 0xF5, 0x7E, 0x7F, 0x04, 0x02, 0x04, 0x38, + 0xC2, 0x36, 0x05, 0x52, 0xE5, 0x52, 0xD3, 0x94, +/*0060*/0x0C, 0x40, 0x05, 0x75, 0x52, 0x01, 0xD2, 0x36, + 0x90, 0x07, 0x0C, 0x74, 0x07, 0xF0, 0xA3, 0x74, +/*0070*/0xFF, 0xF0, 0xE4, 0xF5, 0x0C, 0xA3, 0xF0, 0x90, + 0x07, 0x14, 0xF0, 0xA3, 0xF0, 0x75, 0x0B, 0x20, +/*0080*/0xF5, 0x09, 0xE4, 0xF5, 0x08, 0xE5, 0x08, 0xD3, + 0x94, 0x30, 0x40, 0x03, 0x02, 0x04, 0x04, 0x12, +/*0090*/0x00, 0x06, 0x15, 0x0B, 0xE5, 0x08, 0x70, 0x04, + 0x7F, 0x01, 0x80, 0x02, 0x7F, 0x00, 0xE5, 0x09, +/*00A0*/0x70, 0x04, 0x7E, 0x01, 0x80, 0x02, 0x7E, 0x00, + 0xEE, 0x5F, 0x60, 0x05, 0x12, 0x18, 0x71, 0xD2, +/*00B0*/0x35, 0x53, 0xE1, 0xF7, 0xE5, 0x08, 0x45, 0x09, + 0xFF, 0xE5, 0x0B, 0x25, 0xE0, 0x25, 0xE0, 0x24, +/*00C0*/0x83, 0xF5, 0x82, 0xE4, 0x34, 0x07, 0xF5, 0x83, + 0xEF, 0xF0, 0x85, 0xE2, 0x20, 0xE5, 0x52, 0xD3, +/*00D0*/0x94, 0x01, 0x40, 0x0D, 0x12, 0x19, 0xF3, 0xE0, + 0x54, 0xA0, 0x64, 0x40, 0x70, 0x03, 0x02, 0x03, +/*00E0*/0xFB, 0x53, 0xF9, 0xF8, 0x90, 0x94, 0x70, 0xE4, + 0xF0, 0xE0, 0xF5, 0x10, 0xAF, 0x09, 0x12, 0x1E, +/*00F0*/0xB3, 0xAF, 0x08, 0xEF, 0x44, 0x08, 0xF5, 0x82, + 0x75, 0x83, 0x80, 0xE0, 0xF5, 0x29, 0xEF, 0x44, +/*0100*/0x07, 0x12, 0x1A, 0x3C, 0xF5, 0x22, 0x54, 0x40, + 0xD3, 0x94, 0x00, 0x40, 0x1E, 0xE5, 0x29, 0x54, +/*0110*/0xF0, 0x70, 0x21, 0x12, 0x19, 0xF3, 0xE0, 0x44, + 0x80, 0xF0, 0xE5, 0x22, 0x54, 0x30, 0x65, 0x08, +/*0120*/0x70, 0x09, 0x12, 0x19, 0xF3, 0xE0, 0x54, 0xBF, + 0xF0, 0x80, 0x09, 0x12, 0x19, 0xF3, 0x74, 0x40, +/*0130*/0xF0, 0x02, 0x03, 0xFB, 0x12, 0x1A, 0x12, 0x75, + 0x83, 0xAE, 0x74, 0xFF, 0xF0, 0xAF, 0x08, 0x7E, +/*0140*/0x00, 0xEF, 0x44, 0x07, 0xF5, 0x82, 0xE0, 0xFD, + 0xE5, 0x0B, 0x25, 0xE0, 0x25, 0xE0, 0x24, 0x81, +/*0150*/0xF5, 0x82, 0xE4, 0x34, 0x07, 0xF5, 0x83, 0xED, + 0xF0, 0x90, 0x07, 0x0E, 0xE0, 0x04, 0xF0, 0xEF, +/*0160*/0x44, 0x07, 0xF5, 0x82, 0x75, 0x83, 0x98, 0xE0, + 0xF5, 0x28, 0x12, 0x1A, 0x23, 0x40, 0x0C, 0x12, +/*0170*/0x19, 0xF3, 0xE0, 0x44, 0x01, 0x12, 0x1A, 0x32, + 0x02, 0x03, 0xF6, 0xAF, 0x08, 0x7E, 0x00, 0x74, +/*0180*/0x80, 0xCD, 0xEF, 0xCD, 0x8D, 0x82, 0xF5, 0x83, + 0xE0, 0x30, 0xE0, 0x0A, 0x12, 0x19, 0xF3, 0xE0, +/*0190*/0x44, 0x20, 0xF0, 0x02, 0x03, 0xFB, 0x12, 0x19, + 0xF3, 0xE0, 0x54, 0xDF, 0xF0, 0xEE, 0x44, 0xAE, +/*01A0*/0x12, 0x1A, 0x43, 0x30, 0xE4, 0x03, 0x02, 0x03, + 0xFB, 0x74, 0x9E, 0x12, 0x1A, 0x05, 0x20, 0xE0, +/*01B0*/0x03, 0x02, 0x03, 0xFB, 0x8F, 0x82, 0x8E, 0x83, + 0xE0, 0x20, 0xE0, 0x03, 0x02, 0x03, 0xFB, 0x12, +/*01C0*/0x19, 0xF3, 0xE0, 0x44, 0x10, 0xF0, 0xE5, 0xE3, + 0x20, 0xE7, 0x08, 0xE5, 0x08, 0x12, 0x1A, 0x3A, +/*01D0*/0x44, 0x04, 0xF0, 0xAF, 0x08, 0x7E, 0x00, 0xEF, + 0x12, 0x1A, 0x3A, 0x20, 0xE2, 0x34, 0x12, 0x19, +/*01E0*/0xF3, 0xE0, 0x44, 0x08, 0xF0, 0xE5, 0xE4, 0x30, + 0xE6, 0x04, 0x7D, 0x01, 0x80, 0x02, 0x7D, 0x00, +/*01F0*/0xE5, 0x7E, 0xC3, 0x94, 0x04, 0x50, 0x04, 0x7C, + 0x01, 0x80, 0x02, 0x7C, 0x00, 0xEC, 0x4D, 0x60, +/*0200*/0x05, 0xC2, 0x35, 0x02, 0x03, 0xFB, 0xEE, 0x44, + 0xD2, 0x12, 0x1A, 0x43, 0x44, 0x40, 0xF0, 0x02, +/*0210*/0x03, 0xFB, 0x12, 0x19, 0xF3, 0xE0, 0x54, 0xF7, + 0xF0, 0x12, 0x1A, 0x12, 0x75, 0x83, 0xD2, 0xE0, +/*0220*/0x54, 0xBF, 0xF0, 0x90, 0x07, 0x14, 0xE0, 0x04, + 0xF0, 0xE5, 0x7E, 0x70, 0x03, 0x75, 0x7E, 0x01, +/*0230*/0xAF, 0x08, 0x7E, 0x00, 0x12, 0x1A, 0x23, 0x40, + 0x12, 0x12, 0x19, 0xF3, 0xE0, 0x44, 0x01, 0x12, +/*0240*/0x19, 0xF2, 0xE0, 0x54, 0x02, 0x12, 0x1A, 0x32, + 0x02, 0x03, 0xFB, 0x12, 0x19, 0xF3, 0xE0, 0x44, +/*0250*/0x02, 0x12, 0x19, 0xF2, 0xE0, 0x54, 0xFE, 0xF0, + 0xC2, 0x35, 0xEE, 0x44, 0x8A, 0x8F, 0x82, 0xF5, +/*0260*/0x83, 0xE0, 0xF5, 0x17, 0x54, 0x8F, 0x44, 0x40, + 0xF0, 0x74, 0x90, 0xFC, 0xE5, 0x08, 0x44, 0x07, +/*0270*/0xFD, 0xF5, 0x82, 0x8C, 0x83, 0xE0, 0x54, 0x3F, + 0x90, 0x07, 0x02, 0xF0, 0xE0, 0x54, 0xC0, 0x8D, +/*0280*/0x82, 0x8C, 0x83, 0xF0, 0x74, 0x92, 0x12, 0x1A, + 0x05, 0x90, 0x07, 0x03, 0x12, 0x1A, 0x19, 0x74, +/*0290*/0x82, 0x12, 0x1A, 0x05, 0x90, 0x07, 0x04, 0x12, + 0x1A, 0x19, 0x74, 0xB4, 0x12, 0x1A, 0x05, 0x90, +/*02A0*/0x07, 0x05, 0x12, 0x1A, 0x19, 0x74, 0x94, 0xFE, + 0xE5, 0x08, 0x44, 0x06, 0x12, 0x1A, 0x0A, 0xF5, +/*02B0*/0x10, 0x30, 0xE0, 0x04, 0xD2, 0x37, 0x80, 0x02, + 0xC2, 0x37, 0xE5, 0x10, 0x54, 0x7F, 0x8F, 0x82, +/*02C0*/0x8E, 0x83, 0xF0, 0x30, 0x44, 0x30, 0x12, 0x1A, + 0x03, 0x54, 0x80, 0xD3, 0x94, 0x00, 0x40, 0x04, +/*02D0*/0xD2, 0x39, 0x80, 0x02, 0xC2, 0x39, 0x8F, 0x82, + 0x8E, 0x83, 0xE0, 0x44, 0x80, 0xF0, 0x12, 0x1A, +/*02E0*/0x03, 0x54, 0x40, 0xD3, 0x94, 0x00, 0x40, 0x04, + 0xD2, 0x3A, 0x80, 0x02, 0xC2, 0x3A, 0x8F, 0x82, +/*02F0*/0x8E, 0x83, 0xE0, 0x44, 0x40, 0xF0, 0x74, 0x92, + 0xFE, 0xE5, 0x08, 0x44, 0x06, 0x12, 0x1A, 0x0A, +/*0300*/0x30, 0xE7, 0x04, 0xD2, 0x38, 0x80, 0x02, 0xC2, + 0x38, 0x8F, 0x82, 0x8E, 0x83, 0xE0, 0x54, 0x7F, +/*0310*/0xF0, 0x12, 0x1E, 0x46, 0xE4, 0xF5, 0x0A, 0x20, + 0x03, 0x02, 0x80, 0x03, 0x30, 0x43, 0x03, 0x12, +/*0320*/0x19, 0x95, 0x20, 0x02, 0x02, 0x80, 0x03, 0x30, + 0x42, 0x03, 0x12, 0x0C, 0x8F, 0x30, 0x30, 0x06, +/*0330*/0x12, 0x19, 0x95, 0x12, 0x0C, 0x8F, 0x12, 0x0D, + 0x47, 0x12, 0x19, 0xF3, 0xE0, 0x54, 0xFB, 0xF0, +/*0340*/0xE5, 0x0A, 0xC3, 0x94, 0x01, 0x40, 0x46, 0x43, + 0xE1, 0x08, 0x12, 0x19, 0xF3, 0xE0, 0x44, 0x04, +/*0350*/0xF0, 0xE5, 0xE4, 0x20, 0xE7, 0x2A, 0x12, 0x1A, + 0x12, 0x75, 0x83, 0xD2, 0xE0, 0x54, 0x08, 0xD3, +/*0360*/0x94, 0x00, 0x40, 0x04, 0x7F, 0x01, 0x80, 0x02, + 0x7F, 0x00, 0xE5, 0x0A, 0xC3, 0x94, 0x01, 0x40, +/*0370*/0x04, 0x7E, 0x01, 0x80, 0x02, 0x7E, 0x00, 0xEF, + 0x5E, 0x60, 0x05, 0x12, 0x1D, 0xD7, 0x80, 0x17, +/*0380*/0x12, 0x1A, 0x12, 0x75, 0x83, 0xD2, 0xE0, 0x44, + 0x08, 0xF0, 0x02, 0x03, 0xFB, 0x12, 0x1A, 0x12, +/*0390*/0x75, 0x83, 0xD2, 0xE0, 0x54, 0xF7, 0xF0, 0x12, + 0x1E, 0x46, 0x7F, 0x08, 0x12, 0x17, 0x31, 0x74, +/*03A0*/0x8E, 0xFE, 0x12, 0x1A, 0x12, 0x8E, 0x83, 0xE0, + 0xF5, 0x10, 0x54, 0xFE, 0xF0, 0xE5, 0x10, 0x44, +/*03B0*/0x01, 0xFF, 0xE5, 0x08, 0xFD, 0xED, 0x44, 0x07, + 0xF5, 0x82, 0xEF, 0xF0, 0xE5, 0x10, 0x54, 0xFE, +/*03C0*/0xFF, 0xED, 0x44, 0x07, 0xF5, 0x82, 0xEF, 0x12, + 0x1A, 0x11, 0x75, 0x83, 0x86, 0xE0, 0x44, 0x10, +/*03D0*/0x12, 0x1A, 0x11, 0xE0, 0x44, 0x10, 0xF0, 0x12, + 0x19, 0xF3, 0xE0, 0x54, 0xFD, 0x44, 0x01, 0xFF, +/*03E0*/0x12, 0x19, 0xF3, 0xEF, 0x12, 0x1A, 0x32, 0x30, + 0x32, 0x0C, 0xE5, 0x08, 0x44, 0x08, 0xF5, 0x82, +/*03F0*/0x75, 0x83, 0x82, 0x74, 0x05, 0xF0, 0xAF, 0x0B, + 0x12, 0x18, 0xD7, 0x74, 0x10, 0x25, 0x08, 0xF5, +/*0400*/0x08, 0x02, 0x00, 0x85, 0x05, 0x09, 0xE5, 0x09, + 0xD3, 0x94, 0x07, 0x50, 0x03, 0x02, 0x00, 0x82, +/*0410*/0xE5, 0x7E, 0xD3, 0x94, 0x00, 0x40, 0x04, 0x7F, + 0x01, 0x80, 0x02, 0x7F, 0x00, 0xE5, 0x7E, 0xC3, +/*0420*/0x94, 0xFA, 0x50, 0x04, 0x7E, 0x01, 0x80, 0x02, + 0x7E, 0x00, 0xEE, 0x5F, 0x60, 0x02, 0x05, 0x7E, +/*0430*/0x30, 0x35, 0x0B, 0x43, 0xE1, 0x01, 0x7F, 0x09, + 0x12, 0x17, 0x31, 0x02, 0x00, 0x58, 0x53, 0xE1, +/*0440*/0xFE, 0x02, 0x00, 0x58, 0x8E, 0x6A, 0x8F, 0x6B, + 0x8C, 0x6C, 0x8D, 0x6D, 0x75, 0x6E, 0x01, 0x75, +/*0450*/0x6F, 0x01, 0x75, 0x70, 0x01, 0xE4, 0xF5, 0x73, + 0xF5, 0x74, 0xF5, 0x75, 0x90, 0x07, 0x2F, 0xF0, +/*0460*/0xF5, 0x3C, 0xF5, 0x3E, 0xF5, 0x46, 0xF5, 0x47, + 0xF5, 0x3D, 0xF5, 0x3F, 0xF5, 0x6F, 0xE5, 0x6F, +/*0470*/0x70, 0x0F, 0xE5, 0x6B, 0x45, 0x6A, 0x12, 0x07, + 0x2A, 0x75, 0x83, 0x80, 0x74, 0x3A, 0xF0, 0x80, +/*0480*/0x09, 0x12, 0x07, 0x2A, 0x75, 0x83, 0x80, 0x74, + 0x1A, 0xF0, 0xE4, 0xF5, 0x6E, 0xC3, 0x74, 0x3F, +/*0490*/0x95, 0x6E, 0xFF, 0x12, 0x08, 0x65, 0x75, 0x83, + 0x82, 0xEF, 0xF0, 0x12, 0x1A, 0x4D, 0x12, 0x08, +/*04A0*/0xC6, 0xE5, 0x33, 0xF0, 0x12, 0x08, 0xFA, 0x12, + 0x08, 0xB1, 0x40, 0xE1, 0xE5, 0x6F, 0x70, 0x0B, +/*04B0*/0x12, 0x07, 0x2A, 0x75, 0x83, 0x80, 0x74, 0x36, + 0xF0, 0x80, 0x09, 0x12, 0x07, 0x2A, 0x75, 0x83, +/*04C0*/0x80, 0x74, 0x16, 0xF0, 0x75, 0x6E, 0x01, 0x12, + 0x07, 0x2A, 0x75, 0x83, 0xB4, 0xE5, 0x6E, 0xF0, +/*04D0*/0x12, 0x1A, 0x4D, 0x74, 0x3F, 0x25, 0x6E, 0xF5, + 0x82, 0xE4, 0x34, 0x00, 0xF5, 0x83, 0xE5, 0x33, +/*04E0*/0xF0, 0x74, 0xBF, 0x25, 0x6E, 0xF5, 0x82, 0xE4, + 0x34, 0x00, 0x12, 0x08, 0xB1, 0x40, 0xD8, 0xE4, +/*04F0*/0xF5, 0x70, 0xF5, 0x46, 0xF5, 0x47, 0xF5, 0x6E, + 0x12, 0x08, 0xFA, 0xF5, 0x83, 0xE0, 0xFE, 0x12, +/*0500*/0x08, 0xC6, 0xE0, 0x7C, 0x00, 0x24, 0x00, 0xFF, + 0xEC, 0x3E, 0xFE, 0xAD, 0x3B, 0xD3, 0xEF, 0x9D, +/*0510*/0xEE, 0x9C, 0x50, 0x04, 0x7B, 0x01, 0x80, 0x02, + 0x7B, 0x00, 0xE5, 0x70, 0x70, 0x04, 0x7A, 0x01, +/*0520*/0x80, 0x02, 0x7A, 0x00, 0xEB, 0x5A, 0x60, 0x06, + 0x85, 0x6E, 0x46, 0x75, 0x70, 0x01, 0xD3, 0xEF, +/*0530*/0x9D, 0xEE, 0x9C, 0x50, 0x04, 0x7F, 0x01, 0x80, + 0x02, 0x7F, 0x00, 0xE5, 0x70, 0xB4, 0x01, 0x04, +/*0540*/0x7E, 0x01, 0x80, 0x02, 0x7E, 0x00, 0xEF, 0x5E, + 0x60, 0x03, 0x85, 0x6E, 0x47, 0x05, 0x6E, 0xE5, +/*0550*/0x6E, 0x64, 0x7F, 0x70, 0xA3, 0xE5, 0x46, 0x60, + 0x05, 0xE5, 0x47, 0xB4, 0x7E, 0x03, 0x85, 0x46, +/*0560*/0x47, 0xE5, 0x6F, 0x70, 0x08, 0x85, 0x46, 0x76, + 0x85, 0x47, 0x77, 0x80, 0x0E, 0xC3, 0x74, 0x7F, +/*0570*/0x95, 0x46, 0xF5, 0x78, 0xC3, 0x74, 0x7F, 0x95, + 0x47, 0xF5, 0x79, 0xE5, 0x6F, 0x70, 0x37, 0xE5, +/*0580*/0x46, 0x65, 0x47, 0x70, 0x0C, 0x75, 0x73, 0x01, + 0x75, 0x74, 0x01, 0xF5, 0x3C, 0xF5, 0x3D, 0x80, +/*0590*/0x35, 0xE4, 0xF5, 0x4E, 0xC3, 0xE5, 0x47, 0x95, + 0x46, 0xF5, 0x3C, 0xC3, 0x13, 0xF5, 0x71, 0x25, +/*05A0*/0x46, 0xF5, 0x72, 0xC3, 0x94, 0x3F, 0x40, 0x05, + 0xE4, 0xF5, 0x3D, 0x80, 0x40, 0xC3, 0x74, 0x3F, +/*05B0*/0x95, 0x72, 0xF5, 0x3D, 0x80, 0x37, 0xE5, 0x46, + 0x65, 0x47, 0x70, 0x0F, 0x75, 0x73, 0x01, 0x75, +/*05C0*/0x75, 0x01, 0xF5, 0x3E, 0xF5, 0x3F, 0x75, 0x4E, + 0x01, 0x80, 0x22, 0xE4, 0xF5, 0x4E, 0xC3, 0xE5, +/*05D0*/0x47, 0x95, 0x46, 0xF5, 0x3E, 0xC3, 0x13, 0xF5, + 0x71, 0x25, 0x46, 0xF5, 0x72, 0xD3, 0x94, 0x3F, +/*05E0*/0x50, 0x05, 0xE4, 0xF5, 0x3F, 0x80, 0x06, 0xE5, + 0x72, 0x24, 0xC1, 0xF5, 0x3F, 0x05, 0x6F, 0xE5, +/*05F0*/0x6F, 0xC3, 0x94, 0x02, 0x50, 0x03, 0x02, 0x04, + 0x6E, 0xE5, 0x6D, 0x45, 0x6C, 0x70, 0x02, 0x80, +/*0600*/0x04, 0xE5, 0x74, 0x45, 0x75, 0x90, 0x07, 0x2F, + 0xF0, 0x7F, 0x01, 0xE5, 0x3E, 0x60, 0x04, 0xE5, +/*0610*/0x3C, 0x70, 0x14, 0xE4, 0xF5, 0x3C, 0xF5, 0x3D, + 0xF5, 0x3E, 0xF5, 0x3F, 0x12, 0x08, 0xD2, 0x70, +/*0620*/0x04, 0xF0, 0x02, 0x06, 0xA4, 0x80, 0x7A, 0xE5, + 0x3C, 0xC3, 0x95, 0x3E, 0x40, 0x07, 0xE5, 0x3C, +/*0630*/0x95, 0x3E, 0xFF, 0x80, 0x06, 0xC3, 0xE5, 0x3E, + 0x95, 0x3C, 0xFF, 0xE5, 0x76, 0xD3, 0x95, 0x79, +/*0640*/0x40, 0x05, 0x85, 0x76, 0x7A, 0x80, 0x03, 0x85, + 0x79, 0x7A, 0xE5, 0x77, 0xC3, 0x95, 0x78, 0x50, +/*0650*/0x05, 0x85, 0x77, 0x7B, 0x80, 0x03, 0x85, 0x78, + 0x7B, 0xE5, 0x7B, 0xD3, 0x95, 0x7A, 0x40, 0x30, +/*0660*/0xE5, 0x7B, 0x95, 0x7A, 0xF5, 0x3C, 0xF5, 0x3E, + 0xC3, 0xE5, 0x7B, 0x95, 0x7A, 0x90, 0x07, 0x19, +/*0670*/0xF0, 0xE5, 0x3C, 0xC3, 0x13, 0xF5, 0x71, 0x25, + 0x7A, 0xF5, 0x72, 0xC3, 0x94, 0x3F, 0x40, 0x05, +/*0680*/0xE4, 0xF5, 0x3D, 0x80, 0x1F, 0xC3, 0x74, 0x3F, + 0x95, 0x72, 0xF5, 0x3D, 0xF5, 0x3F, 0x80, 0x14, +/*0690*/0xE4, 0xF5, 0x3C, 0xF5, 0x3E, 0x90, 0x07, 0x19, + 0xF0, 0x12, 0x08, 0xD2, 0x70, 0x03, 0xF0, 0x80, +/*06A0*/0x03, 0x74, 0x01, 0xF0, 0x12, 0x08, 0x65, 0x75, + 0x83, 0xD0, 0xE0, 0x54, 0x0F, 0xFE, 0xAD, 0x3C, +/*06B0*/0x70, 0x02, 0x7E, 0x07, 0xBE, 0x0F, 0x02, 0x7E, + 0x80, 0xEE, 0xFB, 0xEF, 0xD3, 0x9B, 0x74, 0x80, +/*06C0*/0xF8, 0x98, 0x40, 0x1F, 0xE4, 0xF5, 0x3C, 0xF5, + 0x3E, 0x12, 0x08, 0xD2, 0x70, 0x03, 0xF0, 0x80, +/*06D0*/0x12, 0x74, 0x01, 0xF0, 0xE5, 0x08, 0xFB, 0xEB, + 0x44, 0x07, 0xF5, 0x82, 0x75, 0x83, 0xD2, 0xE0, +/*06E0*/0x44, 0x10, 0xF0, 0xE5, 0x08, 0xFB, 0xEB, 0x44, + 0x09, 0xF5, 0x82, 0x75, 0x83, 0x9E, 0xED, 0xF0, +/*06F0*/0xEB, 0x44, 0x07, 0xF5, 0x82, 0x75, 0x83, 0xCA, + 0xED, 0xF0, 0x12, 0x08, 0x65, 0x75, 0x83, 0xCC, +/*0700*/0xEF, 0xF0, 0x22, 0xE5, 0x08, 0x44, 0x07, 0xF5, + 0x82, 0x75, 0x83, 0xBC, 0xE0, 0x54, 0xF0, 0xF0, +/*0710*/0xE5, 0x08, 0x44, 0x07, 0xF5, 0x82, 0x75, 0x83, + 0xBE, 0xE0, 0x54, 0xF0, 0xF0, 0xE5, 0x08, 0x44, +/*0720*/0x07, 0xF5, 0x82, 0x75, 0x83, 0xC0, 0xE0, 0x54, + 0xF0, 0xF0, 0xE5, 0x08, 0x44, 0x07, 0xF5, 0x82, +/*0730*/0x22, 0xF0, 0x90, 0x07, 0x28, 0xE0, 0xFE, 0xA3, + 0xE0, 0xF5, 0x82, 0x8E, 0x83, 0x22, 0x85, 0x42, +/*0740*/0x42, 0x85, 0x41, 0x41, 0x85, 0x40, 0x40, 0x74, + 0xC0, 0x2F, 0xF5, 0x82, 0x74, 0x02, 0x3E, 0xF5, +/*0750*/0x83, 0xE5, 0x42, 0xF0, 0x74, 0xE0, 0x2F, 0xF5, + 0x82, 0x74, 0x02, 0x3E, 0xF5, 0x83, 0x22, 0xE5, +/*0760*/0x42, 0x29, 0xFD, 0xE4, 0x33, 0xFC, 0xE5, 0x3C, + 0xC3, 0x9D, 0xEC, 0x64, 0x80, 0xF8, 0x74, 0x80, +/*0770*/0x98, 0x22, 0xF5, 0x83, 0xE0, 0x90, 0x07, 0x22, + 0x54, 0x1F, 0xFD, 0xE0, 0xFA, 0xA3, 0xE0, 0xF5, +/*0780*/0x82, 0x8A, 0x83, 0xED, 0xF0, 0x22, 0x90, 0x07, + 0x22, 0xE0, 0xFC, 0xA3, 0xE0, 0xF5, 0x82, 0x8C, +/*0790*/0x83, 0x22, 0x90, 0x07, 0x24, 0xFF, 0xED, 0x44, + 0x07, 0xCF, 0xF0, 0xA3, 0xEF, 0xF0, 0x22, 0x85, +/*07A0*/0x38, 0x38, 0x85, 0x39, 0x39, 0x85, 0x3A, 0x3A, + 0x74, 0xC0, 0x2F, 0xF5, 0x82, 0x74, 0x02, 0x3E, +/*07B0*/0xF5, 0x83, 0x22, 0x90, 0x07, 0x26, 0xFF, 0xED, + 0x44, 0x07, 0xCF, 0xF0, 0xA3, 0xEF, 0xF0, 0x22, +/*07C0*/0xF0, 0x74, 0xA0, 0x2F, 0xF5, 0x82, 0x74, 0x02, + 0x3E, 0xF5, 0x83, 0x22, 0x74, 0xC0, 0x25, 0x11, +/*07D0*/0xF5, 0x82, 0xE4, 0x34, 0x01, 0xF5, 0x83, 0x22, + 0x74, 0x00, 0x25, 0x11, 0xF5, 0x82, 0xE4, 0x34, +/*07E0*/0x02, 0xF5, 0x83, 0x22, 0x74, 0x60, 0x25, 0x11, + 0xF5, 0x82, 0xE4, 0x34, 0x03, 0xF5, 0x83, 0x22, +/*07F0*/0x74, 0x80, 0x25, 0x11, 0xF5, 0x82, 0xE4, 0x34, + 0x03, 0xF5, 0x83, 0x22, 0x74, 0xE0, 0x25, 0x11, +/*0800*/0xF5, 0x82, 0xE4, 0x34, 0x03, 0xF5, 0x83, 0x22, + 0x74, 0x40, 0x25, 0x11, 0xF5, 0x82, 0xE4, 0x34, +/*0810*/0x06, 0xF5, 0x83, 0x22, 0x74, 0x80, 0x2F, 0xF5, + 0x82, 0x74, 0x02, 0x3E, 0xF5, 0x83, 0x22, 0xAF, +/*0820*/0x08, 0x7E, 0x00, 0xEF, 0x44, 0x07, 0xF5, 0x82, + 0x22, 0xF5, 0x83, 0xE5, 0x82, 0x44, 0x07, 0xF5, +/*0830*/0x82, 0xE5, 0x40, 0xF0, 0x22, 0x74, 0x40, 0x25, + 0x11, 0xF5, 0x82, 0xE4, 0x34, 0x02, 0xF5, 0x83, +/*0840*/0x22, 0x74, 0xC0, 0x25, 0x11, 0xF5, 0x82, 0xE4, + 0x34, 0x03, 0xF5, 0x83, 0x22, 0x74, 0x00, 0x25, +/*0850*/0x11, 0xF5, 0x82, 0xE4, 0x34, 0x06, 0xF5, 0x83, + 0x22, 0x74, 0x20, 0x25, 0x11, 0xF5, 0x82, 0xE4, +/*0860*/0x34, 0x06, 0xF5, 0x83, 0x22, 0xE5, 0x08, 0xFD, + 0xED, 0x44, 0x07, 0xF5, 0x82, 0x22, 0xE5, 0x41, +/*0870*/0xF0, 0xE5, 0x65, 0x64, 0x01, 0x45, 0x64, 0x22, + 0x7E, 0x00, 0xFB, 0x7A, 0x00, 0xFD, 0x7C, 0x00, +/*0880*/0x22, 0x74, 0x20, 0x25, 0x11, 0xF5, 0x82, 0xE4, + 0x34, 0x02, 0x22, 0x74, 0xA0, 0x25, 0x11, 0xF5, +/*0890*/0x82, 0xE4, 0x34, 0x03, 0x22, 0x85, 0x3E, 0x42, + 0x85, 0x3F, 0x41, 0x8F, 0x40, 0x22, 0x85, 0x3C, +/*08A0*/0x42, 0x85, 0x3D, 0x41, 0x8F, 0x40, 0x22, 0x75, + 0x45, 0x3F, 0x90, 0x07, 0x20, 0xE4, 0xF0, 0xA3, +/*08B0*/0x22, 0xF5, 0x83, 0xE5, 0x32, 0xF0, 0x05, 0x6E, + 0xE5, 0x6E, 0xC3, 0x94, 0x40, 0x22, 0xF0, 0xE5, +/*08C0*/0x08, 0x44, 0x06, 0xF5, 0x82, 0x22, 0x74, 0x00, + 0x25, 0x6E, 0xF5, 0x82, 0xE4, 0x34, 0x00, 0xF5, +/*08D0*/0x83, 0x22, 0xE5, 0x6D, 0x45, 0x6C, 0x90, 0x07, + 0x2F, 0x22, 0xE4, 0xF9, 0xE5, 0x3C, 0xD3, 0x95, +/*08E0*/0x3E, 0x22, 0x74, 0x80, 0x2E, 0xF5, 0x82, 0xE4, + 0x34, 0x02, 0xF5, 0x83, 0xE0, 0x22, 0x74, 0xA0, +/*08F0*/0x2E, 0xF5, 0x82, 0xE4, 0x34, 0x02, 0xF5, 0x83, + 0xE0, 0x22, 0x74, 0x80, 0x25, 0x6E, 0xF5, 0x82, +/*0900*/0xE4, 0x34, 0x00, 0x22, 0x25, 0x42, 0xFD, 0xE4, + 0x33, 0xFC, 0x22, 0x85, 0x42, 0x42, 0x85, 0x41, +/*0910*/0x41, 0x85, 0x40, 0x40, 0x22, 0xED, 0x4C, 0x60, + 0x03, 0x02, 0x09, 0xE5, 0xEF, 0x4E, 0x70, 0x37, +/*0920*/0x90, 0x07, 0x26, 0x12, 0x07, 0x89, 0xE0, 0xFD, + 0x12, 0x07, 0xCC, 0xED, 0xF0, 0x90, 0x07, 0x28, +/*0930*/0x12, 0x07, 0x89, 0xE0, 0xFD, 0x12, 0x07, 0xD8, + 0xED, 0xF0, 0x12, 0x07, 0x86, 0xE0, 0x54, 0x1F, +/*0940*/0xFD, 0x12, 0x08, 0x81, 0xF5, 0x83, 0xED, 0xF0, + 0x90, 0x07, 0x24, 0x12, 0x07, 0x89, 0xE0, 0x54, +/*0950*/0x1F, 0xFD, 0x12, 0x08, 0x35, 0xED, 0xF0, 0xEF, + 0x64, 0x04, 0x4E, 0x70, 0x37, 0x90, 0x07, 0x26, +/*0960*/0x12, 0x07, 0x89, 0xE0, 0xFD, 0x12, 0x07, 0xE4, + 0xED, 0xF0, 0x90, 0x07, 0x28, 0x12, 0x07, 0x89, +/*0970*/0xE0, 0xFD, 0x12, 0x07, 0xF0, 0xED, 0xF0, 0x12, + 0x07, 0x86, 0xE0, 0x54, 0x1F, 0xFD, 0x12, 0x08, +/*0980*/0x8B, 0xF5, 0x83, 0xED, 0xF0, 0x90, 0x07, 0x24, + 0x12, 0x07, 0x89, 0xE0, 0x54, 0x1F, 0xFD, 0x12, +/*0990*/0x08, 0x41, 0xED, 0xF0, 0xEF, 0x64, 0x01, 0x4E, + 0x70, 0x04, 0x7D, 0x01, 0x80, 0x02, 0x7D, 0x00, +/*09A0*/0xEF, 0x64, 0x02, 0x4E, 0x70, 0x04, 0x7F, 0x01, + 0x80, 0x02, 0x7F, 0x00, 0xEF, 0x4D, 0x60, 0x78, +/*09B0*/0x90, 0x07, 0x26, 0x12, 0x07, 0x35, 0xE0, 0xFF, + 0x12, 0x07, 0xFC, 0xEF, 0x12, 0x07, 0x31, 0xE0, +/*09C0*/0xFF, 0x12, 0x08, 0x08, 0xEF, 0xF0, 0x90, 0x07, + 0x22, 0x12, 0x07, 0x35, 0xE0, 0x54, 0x1F, 0xFF, +/*09D0*/0x12, 0x08, 0x4D, 0xEF, 0xF0, 0x90, 0x07, 0x24, + 0x12, 0x07, 0x35, 0xE0, 0x54, 0x1F, 0xFF, 0x12, +/*09E0*/0x08, 0x59, 0xEF, 0xF0, 0x22, 0x12, 0x07, 0xCC, + 0xE4, 0xF0, 0x12, 0x07, 0xD8, 0xE4, 0xF0, 0x12, +/*09F0*/0x08, 0x81, 0xF5, 0x83, 0xE4, 0xF0, 0x12, 0x08, + 0x35, 0x74, 0x14, 0xF0, 0x12, 0x07, 0xE4, 0xE4, +/*0A00*/0xF0, 0x12, 0x07, 0xF0, 0xE4, 0xF0, 0x12, 0x08, + 0x8B, 0xF5, 0x83, 0xE4, 0xF0, 0x12, 0x08, 0x41, +/*0A10*/0x74, 0x14, 0xF0, 0x12, 0x07, 0xFC, 0xE4, 0xF0, + 0x12, 0x08, 0x08, 0xE4, 0xF0, 0x12, 0x08, 0x4D, +/*0A20*/0xE4, 0xF0, 0x12, 0x08, 0x59, 0x74, 0x14, 0xF0, + 0x22, 0x53, 0xF9, 0xF7, 0x75, 0xFC, 0x10, 0xE4, +/*0A30*/0xF5, 0xFD, 0x75, 0xFE, 0x30, 0xF5, 0xFF, 0xE5, + 0xE7, 0x20, 0xE7, 0x03, 0x43, 0xF9, 0x08, 0xE5, +/*0A40*/0xE6, 0x20, 0xE7, 0x0B, 0x78, 0xFF, 0xE4, 0xF6, + 0xD8, 0xFD, 0x53, 0xE6, 0xFE, 0x80, 0x09, 0x78, +/*0A50*/0x08, 0xE4, 0xF6, 0xD8, 0xFD, 0x53, 0xE6, 0xFE, + 0x75, 0x81, 0x80, 0xE4, 0xF5, 0xA8, 0xD2, 0xA8, +/*0A60*/0xC2, 0xA9, 0xD2, 0xAF, 0xE5, 0xE2, 0x20, 0xE5, + 0x05, 0x20, 0xE6, 0x02, 0x80, 0x03, 0x43, 0xE1, +/*0A70*/0x02, 0xE5, 0xE2, 0x20, 0xE0, 0x0E, 0x90, 0x00, + 0x00, 0x7F, 0x00, 0x7E, 0x08, 0xE4, 0xF0, 0xA3, +/*0A80*/0xDF, 0xFC, 0xDE, 0xFA, 0x02, 0x0A, 0xDB, 0x43, + 0xFA, 0x01, 0xC0, 0xE0, 0xC0, 0xF0, 0xC0, 0x83, +/*0A90*/0xC0, 0x82, 0xC0, 0xD0, 0x12, 0x1C, 0xE7, 0xD0, + 0xD0, 0xD0, 0x82, 0xD0, 0x83, 0xD0, 0xF0, 0xD0, +/*0AA0*/0xE0, 0x53, 0xFA, 0xFE, 0x32, 0x02, 0x1B, 0x55, + 0xE4, 0x93, 0xA3, 0xF8, 0xE4, 0x93, 0xA3, 0xF6, +/*0AB0*/0x08, 0xDF, 0xF9, 0x80, 0x29, 0xE4, 0x93, 0xA3, + 0xF8, 0x54, 0x07, 0x24, 0x0C, 0xC8, 0xC3, 0x33, +/*0AC0*/0xC4, 0x54, 0x0F, 0x44, 0x20, 0xC8, 0x83, 0x40, + 0x04, 0xF4, 0x56, 0x80, 0x01, 0x46, 0xF6, 0xDF, +/*0AD0*/0xE4, 0x80, 0x0B, 0x01, 0x02, 0x04, 0x08, 0x10, + 0x20, 0x40, 0x80, 0x90, 0x00, 0x3F, 0xE4, 0x7E, +/*0AE0*/0x01, 0x93, 0x60, 0xC1, 0xA3, 0xFF, 0x54, 0x3F, + 0x30, 0xE5, 0x09, 0x54, 0x1F, 0xFE, 0xE4, 0x93, +/*0AF0*/0xA3, 0x60, 0x01, 0x0E, 0xCF, 0x54, 0xC0, 0x25, + 0xE0, 0x60, 0xAD, 0x40, 0xB8, 0x80, 0xFE, 0x8C, +/*0B00*/0x64, 0x8D, 0x65, 0x8A, 0x66, 0x8B, 0x67, 0xE4, + 0xF5, 0x69, 0xEF, 0x4E, 0x70, 0x03, 0x02, 0x1D, +/*0B10*/0x55, 0xE4, 0xF5, 0x68, 0xE5, 0x67, 0x45, 0x66, + 0x70, 0x32, 0x12, 0x07, 0x2A, 0x75, 0x83, 0x90, +/*0B20*/0xE4, 0x12, 0x07, 0x29, 0x75, 0x83, 0xC2, 0xE4, + 0x12, 0x07, 0x29, 0x75, 0x83, 0xC4, 0xE4, 0x12, +/*0B30*/0x08, 0x70, 0x70, 0x29, 0x12, 0x07, 0x2A, 0x75, + 0x83, 0x92, 0xE4, 0x12, 0x07, 0x29, 0x75, 0x83, +/*0B40*/0xC6, 0xE4, 0x12, 0x07, 0x29, 0x75, 0x83, 0xC8, + 0xE4, 0xF0, 0x80, 0x11, 0x90, 0x07, 0x26, 0x12, +/*0B50*/0x07, 0x35, 0xE4, 0x12, 0x08, 0x70, 0x70, 0x05, + 0x12, 0x07, 0x32, 0xE4, 0xF0, 0x12, 0x1D, 0x55, +/*0B60*/0x12, 0x1E, 0xBF, 0xE5, 0x67, 0x45, 0x66, 0x70, + 0x33, 0x12, 0x07, 0x2A, 0x75, 0x83, 0x90, 0xE5, +/*0B70*/0x41, 0x12, 0x07, 0x29, 0x75, 0x83, 0xC2, 0xE5, + 0x41, 0x12, 0x07, 0x29, 0x75, 0x83, 0xC4, 0x12, +/*0B80*/0x08, 0x6E, 0x70, 0x29, 0x12, 0x07, 0x2A, 0x75, + 0x83, 0x92, 0xE5, 0x40, 0x12, 0x07, 0x29, 0x75, +/*0B90*/0x83, 0xC6, 0xE5, 0x40, 0x12, 0x07, 0x29, 0x75, + 0x83, 0xC8, 0x80, 0x0E, 0x90, 0x07, 0x26, 0x12, +/*0BA0*/0x07, 0x35, 0x12, 0x08, 0x6E, 0x70, 0x06, 0x12, + 0x07, 0x32, 0xE5, 0x40, 0xF0, 0xAF, 0x69, 0x7E, +/*0BB0*/0x00, 0xAD, 0x67, 0xAC, 0x66, 0x12, 0x04, 0x44, + 0x12, 0x07, 0x2A, 0x75, 0x83, 0xCA, 0xE0, 0xD3, +/*0BC0*/0x94, 0x00, 0x50, 0x0C, 0x05, 0x68, 0xE5, 0x68, + 0xC3, 0x94, 0x05, 0x50, 0x03, 0x02, 0x0B, 0x14, +/*0BD0*/0x22, 0x8C, 0x60, 0x8D, 0x61, 0x12, 0x08, 0xDA, + 0x74, 0x20, 0x40, 0x0D, 0x2F, 0xF5, 0x82, 0x74, +/*0BE0*/0x03, 0x3E, 0xF5, 0x83, 0xE5, 0x3E, 0xF0, 0x80, + 0x0B, 0x2F, 0xF5, 0x82, 0x74, 0x03, 0x3E, 0xF5, +/*0BF0*/0x83, 0xE5, 0x3C, 0xF0, 0xE5, 0x3C, 0xD3, 0x95, + 0x3E, 0x40, 0x3C, 0xE5, 0x61, 0x45, 0x60, 0x70, +/*0C00*/0x10, 0xE9, 0x12, 0x09, 0x04, 0xE5, 0x3E, 0x12, + 0x07, 0x68, 0x40, 0x3B, 0x12, 0x08, 0x95, 0x80, +/*0C10*/0x18, 0xE5, 0x3E, 0xC3, 0x95, 0x38, 0x40, 0x1D, + 0x85, 0x3E, 0x38, 0xE5, 0x3E, 0x60, 0x05, 0x85, +/*0C20*/0x3F, 0x39, 0x80, 0x03, 0x85, 0x39, 0x39, 0x8F, + 0x3A, 0x12, 0x08, 0x14, 0xE5, 0x3E, 0x12, 0x07, +/*0C30*/0xC0, 0xE5, 0x3F, 0xF0, 0x22, 0x80, 0x43, 0xE5, + 0x61, 0x45, 0x60, 0x70, 0x19, 0x12, 0x07, 0x5F, +/*0C40*/0x40, 0x05, 0x12, 0x08, 0x9E, 0x80, 0x27, 0x12, + 0x09, 0x0B, 0x12, 0x08, 0x14, 0xE5, 0x42, 0x12, +/*0C50*/0x07, 0xC0, 0xE5, 0x41, 0xF0, 0x22, 0xE5, 0x3C, + 0xC3, 0x95, 0x38, 0x40, 0x1D, 0x85, 0x3C, 0x38, +/*0C60*/0xE5, 0x3C, 0x60, 0x05, 0x85, 0x3D, 0x39, 0x80, + 0x03, 0x85, 0x39, 0x39, 0x8F, 0x3A, 0x12, 0x08, +/*0C70*/0x14, 0xE5, 0x3C, 0x12, 0x07, 0xC0, 0xE5, 0x3D, + 0xF0, 0x22, 0x85, 0x38, 0x38, 0x85, 0x39, 0x39, +/*0C80*/0x85, 0x3A, 0x3A, 0x12, 0x08, 0x14, 0xE5, 0x38, + 0x12, 0x07, 0xC0, 0xE5, 0x39, 0xF0, 0x22, 0x7F, +/*0C90*/0x06, 0x12, 0x17, 0x31, 0x12, 0x1D, 0x23, 0x12, + 0x0E, 0x04, 0x12, 0x0E, 0x33, 0xE0, 0x44, 0x0A, +/*0CA0*/0xF0, 0x74, 0x8E, 0xFE, 0x12, 0x0E, 0x04, 0x12, + 0x0E, 0x0B, 0xEF, 0xF0, 0xE5, 0x28, 0x30, 0xE5, +/*0CB0*/0x03, 0xD3, 0x80, 0x01, 0xC3, 0x40, 0x05, 0x75, + 0x14, 0x20, 0x80, 0x03, 0x75, 0x14, 0x08, 0x12, +/*0CC0*/0x0E, 0x04, 0x75, 0x83, 0x8A, 0xE5, 0x14, 0xF0, + 0xB4, 0xFF, 0x05, 0x75, 0x12, 0x80, 0x80, 0x06, +/*0CD0*/0xE5, 0x14, 0xC3, 0x13, 0xF5, 0x12, 0xE4, 0xF5, + 0x16, 0xF5, 0x7F, 0x12, 0x19, 0x36, 0x12, 0x13, +/*0CE0*/0xA3, 0xE5, 0x0A, 0xC3, 0x94, 0x01, 0x50, 0x09, + 0x05, 0x16, 0xE5, 0x16, 0xC3, 0x94, 0x14, 0x40, +/*0CF0*/0xEA, 0xE5, 0xE4, 0x20, 0xE7, 0x28, 0x12, 0x0E, + 0x04, 0x75, 0x83, 0xD2, 0xE0, 0x54, 0x08, 0xD3, +/*0D00*/0x94, 0x00, 0x40, 0x04, 0x7F, 0x01, 0x80, 0x02, + 0x7F, 0x00, 0xE5, 0x0A, 0xC3, 0x94, 0x01, 0x40, +/*0D10*/0x04, 0x7E, 0x01, 0x80, 0x02, 0x7E, 0x00, 0xEF, + 0x5E, 0x60, 0x03, 0x12, 0x1D, 0xD7, 0xE5, 0x7F, +/*0D20*/0xC3, 0x94, 0x11, 0x40, 0x14, 0x12, 0x0E, 0x04, + 0x75, 0x83, 0xD2, 0xE0, 0x44, 0x80, 0xF0, 0xE5, +/*0D30*/0xE4, 0x20, 0xE7, 0x0F, 0x12, 0x1D, 0xD7, 0x80, + 0x0A, 0x12, 0x0E, 0x04, 0x75, 0x83, 0xD2, 0xE0, +/*0D40*/0x54, 0x7F, 0xF0, 0x12, 0x1D, 0x23, 0x22, 0x74, + 0x8A, 0x85, 0x08, 0x82, 0xF5, 0x83, 0xE5, 0x17, +/*0D50*/0xF0, 0x12, 0x0E, 0x3A, 0xE4, 0xF0, 0x90, 0x07, + 0x02, 0xE0, 0x12, 0x0E, 0x17, 0x75, 0x83, 0x90, +/*0D60*/0xEF, 0xF0, 0x74, 0x92, 0xFE, 0xE5, 0x08, 0x44, + 0x07, 0xFF, 0xF5, 0x82, 0x8E, 0x83, 0xE0, 0x54, +/*0D70*/0xC0, 0xFD, 0x90, 0x07, 0x03, 0xE0, 0x54, 0x3F, + 0x4D, 0x8F, 0x82, 0x8E, 0x83, 0xF0, 0x90, 0x07, +/*0D80*/0x04, 0xE0, 0x12, 0x0E, 0x17, 0x75, 0x83, 0x82, + 0xEF, 0xF0, 0x90, 0x07, 0x05, 0xE0, 0xFF, 0xED, +/*0D90*/0x44, 0x07, 0xF5, 0x82, 0x75, 0x83, 0xB4, 0xEF, + 0x12, 0x0E, 0x03, 0x75, 0x83, 0x80, 0xE0, 0x54, +/*0DA0*/0xBF, 0xF0, 0x30, 0x37, 0x0A, 0x12, 0x0E, 0x91, + 0x75, 0x83, 0x94, 0xE0, 0x44, 0x80, 0xF0, 0x30, +/*0DB0*/0x38, 0x0A, 0x12, 0x0E, 0x91, 0x75, 0x83, 0x92, + 0xE0, 0x44, 0x80, 0xF0, 0xE5, 0x28, 0x30, 0xE4, +/*0DC0*/0x1A, 0x20, 0x39, 0x0A, 0x12, 0x0E, 0x04, 0x75, + 0x83, 0x88, 0xE0, 0x54, 0x7F, 0xF0, 0x20, 0x3A, +/*0DD0*/0x0A, 0x12, 0x0E, 0x04, 0x75, 0x83, 0x88, 0xE0, + 0x54, 0xBF, 0xF0, 0x74, 0x8C, 0xFE, 0x12, 0x0E, +/*0DE0*/0x04, 0x8E, 0x83, 0xE0, 0x54, 0x0F, 0x12, 0x0E, + 0x03, 0x75, 0x83, 0x86, 0xE0, 0x54, 0xBF, 0xF0, +/*0DF0*/0xE5, 0x08, 0x44, 0x06, 0x12, 0x0D, 0xFD, 0x75, + 0x83, 0x8A, 0xE4, 0xF0, 0x22, 0xF5, 0x82, 0x75, +/*0E00*/0x83, 0x82, 0xE4, 0xF0, 0xE5, 0x08, 0x44, 0x07, + 0xF5, 0x82, 0x22, 0x8E, 0x83, 0xE0, 0xF5, 0x10, +/*0E10*/0x54, 0xFE, 0xF0, 0xE5, 0x10, 0x44, 0x01, 0xFF, + 0xE5, 0x08, 0xFD, 0xED, 0x44, 0x07, 0xF5, 0x82, +/*0E20*/0x22, 0xE5, 0x15, 0xC4, 0x54, 0x07, 0xFF, 0xE5, + 0x08, 0xFD, 0xED, 0x44, 0x08, 0xF5, 0x82, 0x75, +/*0E30*/0x83, 0x82, 0x22, 0x75, 0x83, 0x80, 0xE0, 0x44, + 0x40, 0xF0, 0xE5, 0x08, 0x44, 0x08, 0xF5, 0x82, +/*0E40*/0x75, 0x83, 0x8A, 0x22, 0xE5, 0x16, 0x25, 0xE0, + 0x25, 0xE0, 0x24, 0xAF, 0xF5, 0x82, 0xE4, 0x34, +/*0E50*/0x1A, 0xF5, 0x83, 0xE4, 0x93, 0xF5, 0x0D, 0x22, + 0x43, 0xE1, 0x10, 0x43, 0xE1, 0x80, 0x53, 0xE1, +/*0E60*/0xFD, 0x85, 0xE1, 0x10, 0x22, 0xE5, 0x16, 0x25, + 0xE0, 0x25, 0xE0, 0x24, 0xB2, 0xF5, 0x82, 0xE4, +/*0E70*/0x34, 0x1A, 0xF5, 0x83, 0xE4, 0x93, 0x22, 0x85, + 0x55, 0x82, 0x85, 0x54, 0x83, 0xE5, 0x15, 0xF0, +/*0E80*/0x22, 0xE5, 0xE2, 0x54, 0x20, 0xD3, 0x94, 0x00, + 0x22, 0xE5, 0xE2, 0x54, 0x40, 0xD3, 0x94, 0x00, +/*0E90*/0x22, 0xE5, 0x08, 0x44, 0x06, 0xF5, 0x82, 0x22, + 0xFD, 0xE5, 0x08, 0xFB, 0xEB, 0x44, 0x07, 0xF5, +/*0EA0*/0x82, 0x22, 0x53, 0xF9, 0xF7, 0x75, 0xFE, 0x30, + 0x22, 0xEF, 0x4E, 0x70, 0x26, 0x12, 0x07, 0xCC, +/*0EB0*/0xE0, 0xFD, 0x90, 0x07, 0x26, 0x12, 0x07, 0x7B, + 0x12, 0x07, 0xD8, 0xE0, 0xFD, 0x90, 0x07, 0x28, +/*0EC0*/0x12, 0x07, 0x7B, 0x12, 0x08, 0x81, 0x12, 0x07, + 0x72, 0x12, 0x08, 0x35, 0xE0, 0x90, 0x07, 0x24, +/*0ED0*/0x12, 0x07, 0x78, 0xEF, 0x64, 0x04, 0x4E, 0x70, + 0x29, 0x12, 0x07, 0xE4, 0xE0, 0xFD, 0x90, 0x07, +/*0EE0*/0x26, 0x12, 0x07, 0x7B, 0x12, 0x07, 0xF0, 0xE0, + 0xFD, 0x90, 0x07, 0x28, 0x12, 0x07, 0x7B, 0x12, +/*0EF0*/0x08, 0x8B, 0x12, 0x07, 0x72, 0x12, 0x08, 0x41, + 0xE0, 0x54, 0x1F, 0xFD, 0x90, 0x07, 0x24, 0x12, +/*0F00*/0x07, 0x7B, 0xEF, 0x64, 0x01, 0x4E, 0x70, 0x04, + 0x7D, 0x01, 0x80, 0x02, 0x7D, 0x00, 0xEF, 0x64, +/*0F10*/0x02, 0x4E, 0x70, 0x04, 0x7F, 0x01, 0x80, 0x02, + 0x7F, 0x00, 0xEF, 0x4D, 0x60, 0x35, 0x12, 0x07, +/*0F20*/0xFC, 0xE0, 0xFF, 0x90, 0x07, 0x26, 0x12, 0x07, + 0x89, 0xEF, 0xF0, 0x12, 0x08, 0x08, 0xE0, 0xFF, +/*0F30*/0x90, 0x07, 0x28, 0x12, 0x07, 0x89, 0xEF, 0xF0, + 0x12, 0x08, 0x4D, 0xE0, 0x54, 0x1F, 0xFF, 0x12, +/*0F40*/0x07, 0x86, 0xEF, 0xF0, 0x12, 0x08, 0x59, 0xE0, + 0x54, 0x1F, 0xFF, 0x90, 0x07, 0x24, 0x12, 0x07, +/*0F50*/0x89, 0xEF, 0xF0, 0x22, 0xE4, 0xF5, 0x53, 0x12, + 0x0E, 0x81, 0x40, 0x04, 0x7F, 0x01, 0x80, 0x02, +/*0F60*/0x7F, 0x00, 0x12, 0x0E, 0x89, 0x40, 0x04, 0x7E, + 0x01, 0x80, 0x02, 0x7E, 0x00, 0xEE, 0x4F, 0x70, +/*0F70*/0x03, 0x02, 0x0F, 0xF6, 0x85, 0xE1, 0x10, 0x43, + 0xE1, 0x02, 0x53, 0xE1, 0x0F, 0x85, 0xE1, 0x10, +/*0F80*/0xE4, 0xF5, 0x51, 0xE5, 0xE3, 0x54, 0x3F, 0xF5, + 0x52, 0x12, 0x0E, 0x89, 0x40, 0x1D, 0xAD, 0x52, +/*0F90*/0xAF, 0x51, 0x12, 0x11, 0x18, 0xEF, 0x60, 0x08, + 0x85, 0xE1, 0x10, 0x43, 0xE1, 0x40, 0x80, 0x0B, +/*0FA0*/0x53, 0xE1, 0xBF, 0x12, 0x0E, 0x58, 0x12, 0x00, + 0x06, 0x80, 0xFB, 0xE5, 0xE3, 0x54, 0x3F, 0xF5, +/*0FB0*/0x51, 0xE5, 0xE4, 0x54, 0x3F, 0xF5, 0x52, 0x12, + 0x0E, 0x81, 0x40, 0x1D, 0xAD, 0x52, 0xAF, 0x51, +/*0FC0*/0x12, 0x11, 0x18, 0xEF, 0x60, 0x08, 0x85, 0xE1, + 0x10, 0x43, 0xE1, 0x20, 0x80, 0x0B, 0x53, 0xE1, +/*0FD0*/0xDF, 0x12, 0x0E, 0x58, 0x12, 0x00, 0x06, 0x80, + 0xFB, 0x12, 0x0E, 0x81, 0x40, 0x04, 0x7F, 0x01, +/*0FE0*/0x80, 0x02, 0x7F, 0x00, 0x12, 0x0E, 0x89, 0x40, + 0x04, 0x7E, 0x01, 0x80, 0x02, 0x7E, 0x00, 0xEE, +/*0FF0*/0x4F, 0x60, 0x03, 0x12, 0x0E, 0x5B, 0x22, 0x12, + 0x0E, 0x21, 0xEF, 0xF0, 0x12, 0x10, 0x91, 0x22, +/*1000*/0x02, 0x11, 0x00, 0x02, 0x10, 0x40, 0x02, 0x10, + 0x90, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/*1010*/0x01, 0x20, 0x01, 0x20, 0xE4, 0xF5, 0x57, 0x12, + 0x16, 0xBD, 0x12, 0x16, 0x44, 0xE4, 0x12, 0x10, +/*1020*/0x56, 0x12, 0x14, 0xB7, 0x90, 0x07, 0x26, 0x12, + 0x07, 0x35, 0xE4, 0x12, 0x07, 0x31, 0xE4, 0xF0, +/*1030*/0x12, 0x10, 0x56, 0x12, 0x14, 0xB7, 0x90, 0x07, + 0x26, 0x12, 0x07, 0x35, 0xE5, 0x41, 0x12, 0x07, +/*1040*/0x31, 0xE5, 0x40, 0xF0, 0xAF, 0x57, 0x7E, 0x00, + 0xAD, 0x56, 0x7C, 0x00, 0x12, 0x04, 0x44, 0xAF, +/*1050*/0x56, 0x7E, 0x00, 0x02, 0x11, 0xEE, 0xFF, 0x90, + 0x07, 0x20, 0xA3, 0xE0, 0xFD, 0xE4, 0xF5, 0x56, +/*1060*/0xF5, 0x40, 0xFE, 0xFC, 0xAB, 0x56, 0xFA, 0x12, + 0x11, 0x51, 0x7F, 0x0F, 0x7D, 0x18, 0xE4, 0xF5, +/*1070*/0x56, 0xF5, 0x40, 0xFE, 0xFC, 0xAB, 0x56, 0xFA, + 0x12, 0x15, 0x41, 0xAF, 0x56, 0x7E, 0x00, 0x12, +/*1080*/0x1A, 0xFF, 0xE4, 0xFF, 0xF5, 0x56, 0x7D, 0x1F, + 0xF5, 0x40, 0xFE, 0xFC, 0xAB, 0x56, 0xFA, 0x22, +/*1090*/0x22, 0xE4, 0xF5, 0x55, 0xE5, 0x08, 0xFD, 0x74, + 0xA0, 0xF5, 0x56, 0xED, 0x44, 0x07, 0xF5, 0x57, +/*10A0*/0xE5, 0x28, 0x30, 0xE5, 0x03, 0xD3, 0x80, 0x01, + 0xC3, 0x40, 0x05, 0x7F, 0x28, 0xEF, 0x80, 0x04, +/*10B0*/0x7F, 0x14, 0xEF, 0xC3, 0x13, 0xF5, 0x54, 0xE4, + 0xF9, 0x12, 0x0E, 0x18, 0x75, 0x83, 0x8E, 0xE0, +/*10C0*/0xF5, 0x10, 0xCE, 0xEF, 0xCE, 0xEE, 0xD3, 0x94, + 0x00, 0x40, 0x26, 0xE5, 0x10, 0x54, 0xFE, 0x12, +/*10D0*/0x0E, 0x98, 0x75, 0x83, 0x8E, 0xED, 0xF0, 0xE5, + 0x10, 0x44, 0x01, 0xFD, 0xEB, 0x44, 0x07, 0xF5, +/*10E0*/0x82, 0xED, 0xF0, 0x85, 0x57, 0x82, 0x85, 0x56, + 0x83, 0xE0, 0x30, 0xE3, 0x01, 0x09, 0x1E, 0x80, +/*10F0*/0xD4, 0xC2, 0x34, 0xE9, 0xC3, 0x95, 0x54, 0x40, + 0x02, 0xD2, 0x34, 0x22, 0x02, 0x00, 0x06, 0x22, +/*1100*/0x30, 0x30, 0x11, 0x90, 0x10, 0x00, 0xE4, 0x93, + 0xF5, 0x10, 0x90, 0x10, 0x10, 0xE4, 0x93, 0xF5, +/*1110*/0x10, 0x12, 0x10, 0x90, 0x12, 0x11, 0x50, 0x22, + 0xE4, 0xFC, 0xC3, 0xED, 0x9F, 0xFA, 0xEF, 0xF5, +/*1120*/0x83, 0x75, 0x82, 0x00, 0x79, 0xFF, 0xE4, 0x93, + 0xCC, 0x6C, 0xCC, 0xA3, 0xD9, 0xF8, 0xDA, 0xF6, +/*1130*/0xE5, 0xE2, 0x30, 0xE4, 0x02, 0x8C, 0xE5, 0xED, + 0x24, 0xFF, 0xFF, 0xEF, 0x75, 0x82, 0xFF, 0xF5, +/*1140*/0x83, 0xE4, 0x93, 0x6C, 0x70, 0x03, 0x7F, 0x01, + 0x22, 0x7F, 0x00, 0x22, 0x22, 0x11, 0x00, 0x00, +/*1150*/0x22, 0x8E, 0x58, 0x8F, 0x59, 0x8C, 0x5A, 0x8D, + 0x5B, 0x8A, 0x5C, 0x8B, 0x5D, 0x75, 0x5E, 0x01, +/*1160*/0xE4, 0xF5, 0x5F, 0xF5, 0x60, 0xF5, 0x62, 0x12, + 0x07, 0x2A, 0x75, 0x83, 0xD0, 0xE0, 0xFF, 0xC4, +/*1170*/0x54, 0x0F, 0xF5, 0x61, 0x12, 0x1E, 0xA5, 0x85, + 0x59, 0x5E, 0xD3, 0xE5, 0x5E, 0x95, 0x5B, 0xE5, +/*1180*/0x5A, 0x12, 0x07, 0x6B, 0x50, 0x4B, 0x12, 0x07, + 0x03, 0x75, 0x83, 0xBC, 0xE0, 0x45, 0x5E, 0x12, +/*1190*/0x07, 0x29, 0x75, 0x83, 0xBE, 0xE0, 0x45, 0x5E, + 0x12, 0x07, 0x29, 0x75, 0x83, 0xC0, 0xE0, 0x45, +/*11A0*/0x5E, 0xF0, 0xAF, 0x5F, 0xE5, 0x60, 0x12, 0x08, + 0x78, 0x12, 0x0A, 0xFF, 0xAF, 0x62, 0x7E, 0x00, +/*11B0*/0xAD, 0x5D, 0xAC, 0x5C, 0x12, 0x04, 0x44, 0xE5, + 0x61, 0xAF, 0x5E, 0x7E, 0x00, 0xB4, 0x03, 0x05, +/*11C0*/0x12, 0x1E, 0x21, 0x80, 0x07, 0xAD, 0x5D, 0xAC, + 0x5C, 0x12, 0x13, 0x17, 0x05, 0x5E, 0x02, 0x11, +/*11D0*/0x7A, 0x12, 0x07, 0x03, 0x75, 0x83, 0xBC, 0xE0, + 0x45, 0x40, 0x12, 0x07, 0x29, 0x75, 0x83, 0xBE, +/*11E0*/0xE0, 0x45, 0x40, 0x12, 0x07, 0x29, 0x75, 0x83, + 0xC0, 0xE0, 0x45, 0x40, 0xF0, 0x22, 0x8E, 0x58, +/*11F0*/0x8F, 0x59, 0x75, 0x5A, 0x01, 0x79, 0x01, 0x75, + 0x5B, 0x01, 0xE4, 0xFB, 0x12, 0x07, 0x2A, 0x75, +/*1200*/0x83, 0xAE, 0xE0, 0x54, 0x1A, 0xFF, 0x12, 0x08, + 0x65, 0xE0, 0xC4, 0x13, 0x54, 0x07, 0xFE, 0xEF, +/*1210*/0x70, 0x0C, 0xEE, 0x65, 0x35, 0x70, 0x07, 0x90, + 0x07, 0x2F, 0xE0, 0xB4, 0x01, 0x0D, 0xAF, 0x35, +/*1220*/0x7E, 0x00, 0x12, 0x0E, 0xA9, 0xCF, 0xEB, 0xCF, + 0x02, 0x1E, 0x60, 0xE5, 0x59, 0x64, 0x02, 0x45, +/*1230*/0x58, 0x70, 0x04, 0x7F, 0x01, 0x80, 0x02, 0x7F, + 0x00, 0xE5, 0x59, 0x45, 0x58, 0x70, 0x04, 0x7E, +/*1240*/0x01, 0x80, 0x02, 0x7E, 0x00, 0xEE, 0x4F, 0x60, + 0x23, 0x85, 0x41, 0x49, 0x85, 0x40, 0x4B, 0xE5, +/*1250*/0x59, 0x45, 0x58, 0x70, 0x2C, 0xAF, 0x5A, 0xFE, + 0xCD, 0xE9, 0xCD, 0xFC, 0xAB, 0x59, 0xAA, 0x58, +/*1260*/0x12, 0x0A, 0xFF, 0xAF, 0x5B, 0x7E, 0x00, 0x12, + 0x1E, 0x60, 0x80, 0x15, 0xAF, 0x5B, 0x7E, 0x00, +/*1270*/0x12, 0x1E, 0x60, 0x90, 0x07, 0x26, 0x12, 0x07, + 0x35, 0xE5, 0x49, 0x12, 0x07, 0x31, 0xE5, 0x4B, +/*1280*/0xF0, 0xE4, 0xFD, 0xAF, 0x35, 0xFE, 0xFC, 0x12, + 0x09, 0x15, 0x22, 0x8C, 0x64, 0x8D, 0x65, 0x12, +/*1290*/0x08, 0xDA, 0x40, 0x3C, 0xE5, 0x65, 0x45, 0x64, + 0x70, 0x10, 0x12, 0x09, 0x04, 0xC3, 0xE5, 0x3E, +/*12A0*/0x12, 0x07, 0x69, 0x40, 0x3B, 0x12, 0x08, 0x95, + 0x80, 0x18, 0xE5, 0x3E, 0xC3, 0x95, 0x38, 0x40, +/*12B0*/0x1D, 0x85, 0x3E, 0x38, 0xE5, 0x3E, 0x60, 0x05, + 0x85, 0x3F, 0x39, 0x80, 0x03, 0x85, 0x39, 0x39, +/*12C0*/0x8F, 0x3A, 0x12, 0x07, 0xA8, 0xE5, 0x3E, 0x12, + 0x07, 0x53, 0xE5, 0x3F, 0xF0, 0x22, 0x80, 0x3B, +/*12D0*/0xE5, 0x65, 0x45, 0x64, 0x70, 0x11, 0x12, 0x07, + 0x5F, 0x40, 0x05, 0x12, 0x08, 0x9E, 0x80, 0x1F, +/*12E0*/0x12, 0x07, 0x3E, 0xE5, 0x41, 0xF0, 0x22, 0xE5, + 0x3C, 0xC3, 0x95, 0x38, 0x40, 0x1D, 0x85, 0x3C, +/*12F0*/0x38, 0xE5, 0x3C, 0x60, 0x05, 0x85, 0x3D, 0x39, + 0x80, 0x03, 0x85, 0x39, 0x39, 0x8F, 0x3A, 0x12, +/*1300*/0x07, 0xA8, 0xE5, 0x3C, 0x12, 0x07, 0x53, 0xE5, + 0x3D, 0xF0, 0x22, 0x12, 0x07, 0x9F, 0xE5, 0x38, +/*1310*/0x12, 0x07, 0x53, 0xE5, 0x39, 0xF0, 0x22, 0x8C, + 0x63, 0x8D, 0x64, 0x12, 0x08, 0xDA, 0x40, 0x3C, +/*1320*/0xE5, 0x64, 0x45, 0x63, 0x70, 0x10, 0x12, 0x09, + 0x04, 0xC3, 0xE5, 0x3E, 0x12, 0x07, 0x69, 0x40, +/*1330*/0x3B, 0x12, 0x08, 0x95, 0x80, 0x18, 0xE5, 0x3E, + 0xC3, 0x95, 0x38, 0x40, 0x1D, 0x85, 0x3E, 0x38, +/*1340*/0xE5, 0x3E, 0x60, 0x05, 0x85, 0x3F, 0x39, 0x80, + 0x03, 0x85, 0x39, 0x39, 0x8F, 0x3A, 0x12, 0x07, +/*1350*/0xA8, 0xE5, 0x3E, 0x12, 0x07, 0x53, 0xE5, 0x3F, + 0xF0, 0x22, 0x80, 0x3B, 0xE5, 0x64, 0x45, 0x63, +/*1360*/0x70, 0x11, 0x12, 0x07, 0x5F, 0x40, 0x05, 0x12, + 0x08, 0x9E, 0x80, 0x1F, 0x12, 0x07, 0x3E, 0xE5, +/*1370*/0x41, 0xF0, 0x22, 0xE5, 0x3C, 0xC3, 0x95, 0x38, + 0x40, 0x1D, 0x85, 0x3C, 0x38, 0xE5, 0x3C, 0x60, +/*1380*/0x05, 0x85, 0x3D, 0x39, 0x80, 0x03, 0x85, 0x39, + 0x39, 0x8F, 0x3A, 0x12, 0x07, 0xA8, 0xE5, 0x3C, +/*1390*/0x12, 0x07, 0x53, 0xE5, 0x3D, 0xF0, 0x22, 0x12, + 0x07, 0x9F, 0xE5, 0x38, 0x12, 0x07, 0x53, 0xE5, +/*13A0*/0x39, 0xF0, 0x22, 0xE5, 0x0D, 0xFE, 0xE5, 0x08, + 0x8E, 0x54, 0x44, 0x05, 0xF5, 0x55, 0x75, 0x15, +/*13B0*/0x0F, 0xF5, 0x82, 0x12, 0x0E, 0x7A, 0x12, 0x17, + 0xA3, 0x20, 0x31, 0x05, 0x75, 0x15, 0x03, 0x80, +/*13C0*/0x03, 0x75, 0x15, 0x0B, 0xE5, 0x0A, 0xC3, 0x94, + 0x01, 0x50, 0x38, 0x12, 0x14, 0x20, 0x20, 0x31, +/*13D0*/0x06, 0x05, 0x15, 0x05, 0x15, 0x80, 0x04, 0x15, + 0x15, 0x15, 0x15, 0xE5, 0x0A, 0xC3, 0x94, 0x01, +/*13E0*/0x50, 0x21, 0x12, 0x14, 0x20, 0x20, 0x31, 0x04, + 0x05, 0x15, 0x80, 0x02, 0x15, 0x15, 0xE5, 0x0A, +/*13F0*/0xC3, 0x94, 0x01, 0x50, 0x0E, 0x12, 0x0E, 0x77, + 0x12, 0x17, 0xA3, 0x20, 0x31, 0x05, 0x05, 0x15, +/*1400*/0x12, 0x0E, 0x77, 0xE5, 0x15, 0xB4, 0x08, 0x04, + 0x7F, 0x01, 0x80, 0x02, 0x7F, 0x00, 0xE5, 0x15, +/*1410*/0xB4, 0x07, 0x04, 0x7E, 0x01, 0x80, 0x02, 0x7E, + 0x00, 0xEE, 0x4F, 0x60, 0x02, 0x05, 0x7F, 0x22, +/*1420*/0x85, 0x55, 0x82, 0x85, 0x54, 0x83, 0xE5, 0x15, + 0xF0, 0x12, 0x17, 0xA3, 0x22, 0x12, 0x07, 0x2A, +/*1430*/0x75, 0x83, 0xAE, 0x74, 0xFF, 0x12, 0x07, 0x29, + 0xE0, 0x54, 0x1A, 0xF5, 0x34, 0xE0, 0xC4, 0x13, +/*1440*/0x54, 0x07, 0xF5, 0x35, 0x24, 0xFE, 0x60, 0x24, + 0x24, 0xFE, 0x60, 0x3C, 0x24, 0x04, 0x70, 0x63, +/*1450*/0x75, 0x31, 0x2D, 0xE5, 0x08, 0xFD, 0x74, 0xB6, + 0x12, 0x07, 0x92, 0x74, 0xBC, 0x90, 0x07, 0x22, +/*1460*/0x12, 0x07, 0x95, 0x74, 0x90, 0x12, 0x07, 0xB3, + 0x74, 0x92, 0x80, 0x3C, 0x75, 0x31, 0x3A, 0xE5, +/*1470*/0x08, 0xFD, 0x74, 0xBA, 0x12, 0x07, 0x92, 0x74, + 0xC0, 0x90, 0x07, 0x22, 0x12, 0x07, 0xB6, 0x74, +/*1480*/0xC4, 0x12, 0x07, 0xB3, 0x74, 0xC8, 0x80, 0x20, + 0x75, 0x31, 0x35, 0xE5, 0x08, 0xFD, 0x74, 0xB8, +/*1490*/0x12, 0x07, 0x92, 0x74, 0xBE, 0xFF, 0xED, 0x44, + 0x07, 0x90, 0x07, 0x22, 0xCF, 0xF0, 0xA3, 0xEF, +/*14A0*/0xF0, 0x74, 0xC2, 0x12, 0x07, 0xB3, 0x74, 0xC6, + 0xFF, 0xED, 0x44, 0x07, 0xA3, 0xCF, 0xF0, 0xA3, +/*14B0*/0xEF, 0xF0, 0x22, 0x75, 0x34, 0x01, 0x22, 0x8E, + 0x58, 0x8F, 0x59, 0x8C, 0x5A, 0x8D, 0x5B, 0x8A, +/*14C0*/0x5C, 0x8B, 0x5D, 0x75, 0x5E, 0x01, 0xE4, 0xF5, + 0x5F, 0x12, 0x1E, 0xA5, 0x85, 0x59, 0x5E, 0xD3, +/*14D0*/0xE5, 0x5E, 0x95, 0x5B, 0xE5, 0x5A, 0x12, 0x07, + 0x6B, 0x50, 0x57, 0xE5, 0x5D, 0x45, 0x5C, 0x70, +/*14E0*/0x30, 0x12, 0x07, 0x2A, 0x75, 0x83, 0x92, 0xE5, + 0x5E, 0x12, 0x07, 0x29, 0x75, 0x83, 0xC6, 0xE5, +/*14F0*/0x5E, 0x12, 0x07, 0x29, 0x75, 0x83, 0xC8, 0xE5, + 0x5E, 0x12, 0x07, 0x29, 0x75, 0x83, 0x90, 0xE5, +/*1500*/0x5E, 0x12, 0x07, 0x29, 0x75, 0x83, 0xC2, 0xE5, + 0x5E, 0x12, 0x07, 0x29, 0x75, 0x83, 0xC4, 0x80, +/*1510*/0x03, 0x12, 0x07, 0x32, 0xE5, 0x5E, 0xF0, 0xAF, + 0x5F, 0x7E, 0x00, 0xAD, 0x5D, 0xAC, 0x5C, 0x12, +/*1520*/0x04, 0x44, 0xAF, 0x5E, 0x7E, 0x00, 0xAD, 0x5D, + 0xAC, 0x5C, 0x12, 0x0B, 0xD1, 0x05, 0x5E, 0x02, +/*1530*/0x14, 0xCF, 0xAB, 0x5D, 0xAA, 0x5C, 0xAD, 0x5B, + 0xAC, 0x5A, 0xAF, 0x59, 0xAE, 0x58, 0x02, 0x1B, +/*1540*/0xFB, 0x8C, 0x5C, 0x8D, 0x5D, 0x8A, 0x5E, 0x8B, + 0x5F, 0x75, 0x60, 0x01, 0xE4, 0xF5, 0x61, 0xF5, +/*1550*/0x62, 0xF5, 0x63, 0x12, 0x1E, 0xA5, 0x8F, 0x60, + 0xD3, 0xE5, 0x60, 0x95, 0x5D, 0xE5, 0x5C, 0x12, +/*1560*/0x07, 0x6B, 0x50, 0x61, 0xE5, 0x5F, 0x45, 0x5E, + 0x70, 0x27, 0x12, 0x07, 0x2A, 0x75, 0x83, 0xB6, +/*1570*/0xE5, 0x60, 0x12, 0x07, 0x29, 0x75, 0x83, 0xB8, + 0xE5, 0x60, 0x12, 0x07, 0x29, 0x75, 0x83, 0xBA, +/*1580*/0xE5, 0x60, 0xF0, 0xAF, 0x61, 0x7E, 0x00, 0xE5, + 0x62, 0x12, 0x08, 0x7A, 0x12, 0x0A, 0xFF, 0x80, +/*1590*/0x19, 0x90, 0x07, 0x24, 0x12, 0x07, 0x35, 0xE5, + 0x60, 0x12, 0x07, 0x29, 0x75, 0x83, 0x8E, 0xE4, +/*15A0*/0x12, 0x07, 0x29, 0x74, 0x01, 0x12, 0x07, 0x29, + 0xE4, 0xF0, 0xAF, 0x63, 0x7E, 0x00, 0xAD, 0x5F, +/*15B0*/0xAC, 0x5E, 0x12, 0x04, 0x44, 0xAF, 0x60, 0x7E, + 0x00, 0xAD, 0x5F, 0xAC, 0x5E, 0x12, 0x12, 0x8B, +/*15C0*/0x05, 0x60, 0x02, 0x15, 0x58, 0x22, 0x90, 0x11, + 0x4D, 0xE4, 0x93, 0x90, 0x07, 0x2E, 0xF0, 0x12, +/*15D0*/0x08, 0x1F, 0x75, 0x83, 0xAE, 0xE0, 0x54, 0x1A, + 0xF5, 0x34, 0x70, 0x67, 0xEF, 0x44, 0x07, 0xF5, +/*15E0*/0x82, 0x75, 0x83, 0xCE, 0xE0, 0xFF, 0x13, 0x13, + 0x13, 0x54, 0x07, 0xF5, 0x36, 0x54, 0x0F, 0xD3, +/*15F0*/0x94, 0x00, 0x40, 0x06, 0x12, 0x14, 0x2D, 0x12, + 0x1B, 0xA9, 0xE5, 0x36, 0x54, 0x0F, 0x24, 0xFE, +/*1600*/0x60, 0x0C, 0x14, 0x60, 0x0C, 0x14, 0x60, 0x19, + 0x24, 0x03, 0x70, 0x37, 0x80, 0x10, 0x02, 0x1E, +/*1610*/0x91, 0x12, 0x1E, 0x91, 0x12, 0x07, 0x2A, 0x75, + 0x83, 0xCE, 0xE0, 0x54, 0xEF, 0xF0, 0x02, 0x1D, +/*1620*/0xAE, 0x12, 0x10, 0x14, 0xE4, 0xF5, 0x55, 0x12, + 0x1D, 0x85, 0x05, 0x55, 0xE5, 0x55, 0xC3, 0x94, +/*1630*/0x05, 0x40, 0xF4, 0x12, 0x07, 0x2A, 0x75, 0x83, + 0xCE, 0xE0, 0x54, 0xC7, 0x12, 0x07, 0x29, 0xE0, +/*1640*/0x44, 0x08, 0xF0, 0x22, 0xE4, 0xF5, 0x58, 0xF5, + 0x59, 0xAF, 0x08, 0xEF, 0x44, 0x07, 0xF5, 0x82, +/*1650*/0x75, 0x83, 0xD0, 0xE0, 0xFD, 0xC4, 0x54, 0x0F, + 0xF5, 0x5A, 0xEF, 0x44, 0x07, 0xF5, 0x82, 0x75, +/*1660*/0x83, 0x80, 0x74, 0x01, 0xF0, 0x12, 0x08, 0x21, + 0x75, 0x83, 0x82, 0xE5, 0x45, 0xF0, 0xEF, 0x44, +/*1670*/0x07, 0xF5, 0x82, 0x75, 0x83, 0x8A, 0x74, 0xFF, + 0xF0, 0x12, 0x1A, 0x4D, 0x12, 0x07, 0x2A, 0x75, +/*1680*/0x83, 0xBC, 0xE0, 0x54, 0xEF, 0x12, 0x07, 0x29, + 0x75, 0x83, 0xBE, 0xE0, 0x54, 0xEF, 0x12, 0x07, +/*1690*/0x29, 0x75, 0x83, 0xC0, 0xE0, 0x54, 0xEF, 0x12, + 0x07, 0x29, 0x75, 0x83, 0xBC, 0xE0, 0x44, 0x10, +/*16A0*/0x12, 0x07, 0x29, 0x75, 0x83, 0xBE, 0xE0, 0x44, + 0x10, 0x12, 0x07, 0x29, 0x75, 0x83, 0xC0, 0xE0, +/*16B0*/0x44, 0x10, 0xF0, 0xAF, 0x58, 0xE5, 0x59, 0x12, + 0x08, 0x78, 0x02, 0x0A, 0xFF, 0xE4, 0xF5, 0x58, +/*16C0*/0x7D, 0x01, 0xF5, 0x59, 0xAF, 0x35, 0xFE, 0xFC, + 0x12, 0x09, 0x15, 0x12, 0x07, 0x2A, 0x75, 0x83, +/*16D0*/0xB6, 0x74, 0x10, 0x12, 0x07, 0x29, 0x75, 0x83, + 0xB8, 0x74, 0x10, 0x12, 0x07, 0x29, 0x75, 0x83, +/*16E0*/0xBA, 0x74, 0x10, 0x12, 0x07, 0x29, 0x75, 0x83, + 0xBC, 0x74, 0x10, 0x12, 0x07, 0x29, 0x75, 0x83, +/*16F0*/0xBE, 0x74, 0x10, 0x12, 0x07, 0x29, 0x75, 0x83, + 0xC0, 0x74, 0x10, 0x12, 0x07, 0x29, 0x75, 0x83, +/*1700*/0x90, 0xE4, 0x12, 0x07, 0x29, 0x75, 0x83, 0xC2, + 0xE4, 0x12, 0x07, 0x29, 0x75, 0x83, 0xC4, 0xE4, +/*1710*/0x12, 0x07, 0x29, 0x75, 0x83, 0x92, 0xE4, 0x12, + 0x07, 0x29, 0x75, 0x83, 0xC6, 0xE4, 0x12, 0x07, +/*1720*/0x29, 0x75, 0x83, 0xC8, 0xE4, 0xF0, 0xAF, 0x58, + 0xFE, 0xE5, 0x59, 0x12, 0x08, 0x7A, 0x02, 0x0A, +/*1730*/0xFF, 0xE5, 0xE2, 0x30, 0xE4, 0x6C, 0xE5, 0xE7, + 0x54, 0xC0, 0x64, 0x40, 0x70, 0x64, 0xE5, 0x09, +/*1740*/0xC4, 0x54, 0x30, 0xFE, 0xE5, 0x08, 0x25, 0xE0, + 0x25, 0xE0, 0x54, 0xC0, 0x4E, 0xFE, 0xEF, 0x54, +/*1750*/0x3F, 0x4E, 0xFD, 0xE5, 0x2B, 0xAE, 0x2A, 0x78, + 0x02, 0xC3, 0x33, 0xCE, 0x33, 0xCE, 0xD8, 0xF9, +/*1760*/0xF5, 0x82, 0x8E, 0x83, 0xED, 0xF0, 0xE5, 0x2B, + 0xAE, 0x2A, 0x78, 0x02, 0xC3, 0x33, 0xCE, 0x33, +/*1770*/0xCE, 0xD8, 0xF9, 0xFF, 0xF5, 0x82, 0x8E, 0x83, + 0xA3, 0xE5, 0xFE, 0xF0, 0x8F, 0x82, 0x8E, 0x83, +/*1780*/0xA3, 0xA3, 0xE5, 0xFD, 0xF0, 0x8F, 0x82, 0x8E, + 0x83, 0xA3, 0xA3, 0xA3, 0xE5, 0xFC, 0xF0, 0xC3, +/*1790*/0xE5, 0x2B, 0x94, 0xFA, 0xE5, 0x2A, 0x94, 0x00, + 0x50, 0x08, 0x05, 0x2B, 0xE5, 0x2B, 0x70, 0x02, +/*17A0*/0x05, 0x2A, 0x22, 0xE4, 0xFF, 0xE4, 0xF5, 0x58, + 0xF5, 0x56, 0xF5, 0x57, 0x74, 0x82, 0xFC, 0x12, +/*17B0*/0x0E, 0x04, 0x8C, 0x83, 0xE0, 0xF5, 0x10, 0x54, + 0x7F, 0xF0, 0xE5, 0x10, 0x44, 0x80, 0x12, 0x0E, +/*17C0*/0x98, 0xED, 0xF0, 0x7E, 0x0A, 0x12, 0x0E, 0x04, + 0x75, 0x83, 0xA0, 0xE0, 0x20, 0xE0, 0x26, 0xDE, +/*17D0*/0xF4, 0x05, 0x57, 0xE5, 0x57, 0x70, 0x02, 0x05, + 0x56, 0xE5, 0x14, 0x24, 0x01, 0xFD, 0xE4, 0x33, +/*17E0*/0xFC, 0xD3, 0xE5, 0x57, 0x9D, 0xE5, 0x56, 0x9C, + 0x40, 0xD9, 0xE5, 0x0A, 0x94, 0x20, 0x50, 0x02, +/*17F0*/0x05, 0x0A, 0x43, 0xE1, 0x08, 0xC2, 0x31, 0x12, + 0x0E, 0x04, 0x75, 0x83, 0xA6, 0xE0, 0x55, 0x12, +/*1800*/0x65, 0x12, 0x70, 0x03, 0xD2, 0x31, 0x22, 0xC2, + 0x31, 0x22, 0x90, 0x07, 0x26, 0xE0, 0xFA, 0xA3, +/*1810*/0xE0, 0xF5, 0x82, 0x8A, 0x83, 0xE0, 0xF5, 0x41, + 0xE5, 0x39, 0xC3, 0x95, 0x41, 0x40, 0x26, 0xE5, +/*1820*/0x39, 0x95, 0x41, 0xC3, 0x9F, 0xEE, 0x12, 0x07, + 0x6B, 0x40, 0x04, 0x7C, 0x01, 0x80, 0x02, 0x7C, +/*1830*/0x00, 0xE5, 0x41, 0x64, 0x3F, 0x60, 0x04, 0x7B, + 0x01, 0x80, 0x02, 0x7B, 0x00, 0xEC, 0x5B, 0x60, +/*1840*/0x29, 0x05, 0x41, 0x80, 0x28, 0xC3, 0xE5, 0x41, + 0x95, 0x39, 0xC3, 0x9F, 0xEE, 0x12, 0x07, 0x6B, +/*1850*/0x40, 0x04, 0x7F, 0x01, 0x80, 0x02, 0x7F, 0x00, + 0xE5, 0x41, 0x60, 0x04, 0x7E, 0x01, 0x80, 0x02, +/*1860*/0x7E, 0x00, 0xEF, 0x5E, 0x60, 0x04, 0x15, 0x41, + 0x80, 0x03, 0x85, 0x39, 0x41, 0x85, 0x3A, 0x40, +/*1870*/0x22, 0xE5, 0xE2, 0x30, 0xE4, 0x60, 0xE5, 0xE1, + 0x30, 0xE2, 0x5B, 0xE5, 0x09, 0x70, 0x04, 0x7F, +/*1880*/0x01, 0x80, 0x02, 0x7F, 0x00, 0xE5, 0x08, 0x70, + 0x04, 0x7E, 0x01, 0x80, 0x02, 0x7E, 0x00, 0xEE, +/*1890*/0x5F, 0x60, 0x43, 0x53, 0xF9, 0xF8, 0xE5, 0xE2, + 0x30, 0xE4, 0x3B, 0xE5, 0xE1, 0x30, 0xE2, 0x2E, +/*18A0*/0x43, 0xFA, 0x02, 0x53, 0xFA, 0xFB, 0xE4, 0xF5, + 0x10, 0x90, 0x94, 0x70, 0xE5, 0x10, 0xF0, 0xE5, +/*18B0*/0xE1, 0x30, 0xE2, 0xE7, 0x90, 0x94, 0x70, 0xE0, + 0x65, 0x10, 0x60, 0x03, 0x43, 0xFA, 0x04, 0x05, +/*18C0*/0x10, 0x90, 0x94, 0x70, 0xE5, 0x10, 0xF0, 0x70, + 0xE6, 0x12, 0x00, 0x06, 0x80, 0xE1, 0x53, 0xFA, +/*18D0*/0xFD, 0x53, 0xFA, 0xFB, 0x80, 0xC0, 0x22, 0x8F, + 0x54, 0x12, 0x00, 0x06, 0xE5, 0xE1, 0x30, 0xE0, +/*18E0*/0x04, 0x7F, 0x01, 0x80, 0x02, 0x7F, 0x00, 0xE5, + 0x7E, 0xD3, 0x94, 0x05, 0x40, 0x04, 0x7E, 0x01, +/*18F0*/0x80, 0x02, 0x7E, 0x00, 0xEE, 0x4F, 0x60, 0x3D, + 0x85, 0x54, 0x11, 0xE5, 0xE2, 0x20, 0xE1, 0x32, +/*1900*/0x74, 0xCE, 0x12, 0x1A, 0x05, 0x30, 0xE7, 0x04, + 0x7D, 0x01, 0x80, 0x02, 0x7D, 0x00, 0x8F, 0x82, +/*1910*/0x8E, 0x83, 0xE0, 0x30, 0xE6, 0x04, 0x7F, 0x01, + 0x80, 0x02, 0x7F, 0x00, 0xEF, 0x5D, 0x70, 0x15, +/*1920*/0x12, 0x15, 0xC6, 0x74, 0xCE, 0x12, 0x1A, 0x05, + 0x30, 0xE6, 0x07, 0xE0, 0x44, 0x80, 0xF0, 0x43, +/*1930*/0xF9, 0x80, 0x12, 0x18, 0x71, 0x22, 0x12, 0x0E, + 0x44, 0xE5, 0x16, 0x25, 0xE0, 0x25, 0xE0, 0x24, +/*1940*/0xB0, 0xF5, 0x82, 0xE4, 0x34, 0x1A, 0xF5, 0x83, + 0xE4, 0x93, 0xF5, 0x0F, 0xE5, 0x16, 0x25, 0xE0, +/*1950*/0x25, 0xE0, 0x24, 0xB1, 0xF5, 0x82, 0xE4, 0x34, + 0x1A, 0xF5, 0x83, 0xE4, 0x93, 0xF5, 0x0E, 0x12, +/*1960*/0x0E, 0x65, 0xF5, 0x10, 0xE5, 0x0F, 0x54, 0xF0, + 0x12, 0x0E, 0x17, 0x75, 0x83, 0x8C, 0xEF, 0xF0, +/*1970*/0xE5, 0x0F, 0x30, 0xE0, 0x0C, 0x12, 0x0E, 0x04, + 0x75, 0x83, 0x86, 0xE0, 0x44, 0x40, 0xF0, 0x80, +/*1980*/0x0A, 0x12, 0x0E, 0x04, 0x75, 0x83, 0x86, 0xE0, + 0x54, 0xBF, 0xF0, 0x12, 0x0E, 0x91, 0x75, 0x83, +/*1990*/0x82, 0xE5, 0x0E, 0xF0, 0x22, 0x7F, 0x05, 0x12, + 0x17, 0x31, 0x12, 0x0E, 0x04, 0x12, 0x0E, 0x33, +/*19A0*/0x74, 0x02, 0xF0, 0x74, 0x8E, 0xFE, 0x12, 0x0E, + 0x04, 0x12, 0x0E, 0x0B, 0xEF, 0xF0, 0x75, 0x15, +/*19B0*/0x70, 0x12, 0x0F, 0xF7, 0x20, 0x34, 0x05, 0x75, + 0x15, 0x10, 0x80, 0x03, 0x75, 0x15, 0x50, 0x12, +/*19C0*/0x0F, 0xF7, 0x20, 0x34, 0x04, 0x74, 0x10, 0x80, + 0x02, 0x74, 0xF0, 0x25, 0x15, 0xF5, 0x15, 0x12, +/*19D0*/0x0E, 0x21, 0xEF, 0xF0, 0x12, 0x10, 0x91, 0x20, + 0x34, 0x17, 0xE5, 0x15, 0x64, 0x30, 0x60, 0x0C, +/*19E0*/0x74, 0x10, 0x25, 0x15, 0xF5, 0x15, 0xB4, 0x80, + 0x03, 0xE4, 0xF5, 0x15, 0x12, 0x0E, 0x21, 0xEF, +/*19F0*/0xF0, 0x22, 0xF0, 0xE5, 0x0B, 0x25, 0xE0, 0x25, + 0xE0, 0x24, 0x82, 0xF5, 0x82, 0xE4, 0x34, 0x07, +/*1A00*/0xF5, 0x83, 0x22, 0x74, 0x88, 0xFE, 0xE5, 0x08, + 0x44, 0x07, 0xFF, 0xF5, 0x82, 0x8E, 0x83, 0xE0, +/*1A10*/0x22, 0xF0, 0xE5, 0x08, 0x44, 0x07, 0xF5, 0x82, + 0x22, 0xF0, 0xE0, 0x54, 0xC0, 0x8F, 0x82, 0x8E, +/*1A20*/0x83, 0xF0, 0x22, 0xEF, 0x44, 0x07, 0xF5, 0x82, + 0x75, 0x83, 0x86, 0xE0, 0x54, 0x10, 0xD3, 0x94, +/*1A30*/0x00, 0x22, 0xF0, 0x90, 0x07, 0x15, 0xE0, 0x04, + 0xF0, 0x22, 0x44, 0x06, 0xF5, 0x82, 0x75, 0x83, +/*1A40*/0x9E, 0xE0, 0x22, 0xFE, 0xEF, 0x44, 0x07, 0xF5, + 0x82, 0x8E, 0x83, 0xE0, 0x22, 0xE4, 0x90, 0x07, +/*1A50*/0x2A, 0xF0, 0xA3, 0xF0, 0x12, 0x07, 0x2A, 0x75, + 0x83, 0x82, 0xE0, 0x54, 0x7F, 0x12, 0x07, 0x29, +/*1A60*/0xE0, 0x44, 0x80, 0xF0, 0x12, 0x10, 0xFC, 0x12, + 0x08, 0x1F, 0x75, 0x83, 0xA0, 0xE0, 0x20, 0xE0, +/*1A70*/0x1A, 0x90, 0x07, 0x2B, 0xE0, 0x04, 0xF0, 0x70, + 0x06, 0x90, 0x07, 0x2A, 0xE0, 0x04, 0xF0, 0x90, +/*1A80*/0x07, 0x2A, 0xE0, 0xB4, 0x10, 0xE1, 0xA3, 0xE0, + 0xB4, 0x00, 0xDC, 0xEE, 0x44, 0xA6, 0xFC, 0xEF, +/*1A90*/0x44, 0x07, 0xF5, 0x82, 0x8C, 0x83, 0xE0, 0xF5, + 0x32, 0xEE, 0x44, 0xA8, 0xFE, 0xEF, 0x44, 0x07, +/*1AA0*/0xF5, 0x82, 0x8E, 0x83, 0xE0, 0xF5, 0x33, 0x22, + 0x01, 0x20, 0x11, 0x00, 0x04, 0x20, 0x00, 0x90, +/*1AB0*/0x00, 0x20, 0x0F, 0x92, 0x00, 0x21, 0x0F, 0x94, + 0x00, 0x22, 0x0F, 0x96, 0x00, 0x23, 0x0F, 0x98, +/*1AC0*/0x00, 0x24, 0x0F, 0x9A, 0x00, 0x25, 0x0F, 0x9C, + 0x00, 0x26, 0x0F, 0x9E, 0x00, 0x27, 0x0F, 0xA0, +/*1AD0*/0x01, 0x20, 0x01, 0xA2, 0x01, 0x21, 0x01, 0xA4, + 0x01, 0x22, 0x01, 0xA6, 0x01, 0x23, 0x01, 0xA8, +/*1AE0*/0x01, 0x24, 0x01, 0xAA, 0x01, 0x25, 0x01, 0xAC, + 0x01, 0x26, 0x01, 0xAE, 0x01, 0x27, 0x01, 0xB0, +/*1AF0*/0x01, 0x28, 0x01, 0xB4, 0x00, 0x28, 0x0F, 0xB6, + 0x40, 0x28, 0x0F, 0xB8, 0x61, 0x28, 0x01, 0xCB, +/*1B00*/0xEF, 0xCB, 0xCA, 0xEE, 0xCA, 0x7F, 0x01, 0xE4, + 0xFD, 0xEB, 0x4A, 0x70, 0x24, 0xE5, 0x08, 0xF5, +/*1B10*/0x82, 0x74, 0xB6, 0x12, 0x08, 0x29, 0xE5, 0x08, + 0xF5, 0x82, 0x74, 0xB8, 0x12, 0x08, 0x29, 0xE5, +/*1B20*/0x08, 0xF5, 0x82, 0x74, 0xBA, 0x12, 0x08, 0x29, + 0x7E, 0x00, 0x7C, 0x00, 0x12, 0x0A, 0xFF, 0x80, +/*1B30*/0x12, 0x90, 0x07, 0x26, 0x12, 0x07, 0x35, 0xE5, + 0x41, 0xF0, 0x90, 0x07, 0x24, 0x12, 0x07, 0x35, +/*1B40*/0xE5, 0x40, 0xF0, 0x12, 0x07, 0x2A, 0x75, 0x83, + 0x8E, 0xE4, 0x12, 0x07, 0x29, 0x74, 0x01, 0x12, +/*1B50*/0x07, 0x29, 0xE4, 0xF0, 0x22, 0xE4, 0xF5, 0x26, + 0xF5, 0x27, 0x53, 0xE1, 0xFE, 0xF5, 0x2A, 0x75, +/*1B60*/0x2B, 0x01, 0xF5, 0x08, 0x7F, 0x01, 0x12, 0x17, + 0x31, 0x30, 0x30, 0x1C, 0x90, 0x1A, 0xA9, 0xE4, +/*1B70*/0x93, 0xF5, 0x10, 0x90, 0x1F, 0xF9, 0xE4, 0x93, + 0xF5, 0x10, 0x90, 0x00, 0x41, 0xE4, 0x93, 0xF5, +/*1B80*/0x10, 0x90, 0x1E, 0xCA, 0xE4, 0x93, 0xF5, 0x10, + 0x7F, 0x02, 0x12, 0x17, 0x31, 0x12, 0x0F, 0x54, +/*1B90*/0x7F, 0x03, 0x12, 0x17, 0x31, 0x12, 0x00, 0x06, + 0xE5, 0xE2, 0x30, 0xE7, 0x09, 0x12, 0x10, 0x00, +/*1BA0*/0x30, 0x30, 0x03, 0x12, 0x11, 0x00, 0x02, 0x00, + 0x47, 0x12, 0x08, 0x1F, 0x75, 0x83, 0xD0, 0xE0, +/*1BB0*/0xC4, 0x54, 0x0F, 0xFD, 0x75, 0x43, 0x01, 0x75, + 0x44, 0xFF, 0x12, 0x08, 0xAA, 0x74, 0x04, 0xF0, +/*1BC0*/0x75, 0x3B, 0x01, 0xED, 0x14, 0x60, 0x0C, 0x14, + 0x60, 0x0B, 0x14, 0x60, 0x0F, 0x24, 0x03, 0x70, +/*1BD0*/0x0B, 0x80, 0x09, 0x80, 0x00, 0x12, 0x08, 0xA7, + 0x04, 0xF0, 0x80, 0x06, 0x12, 0x08, 0xA7, 0x74, +/*1BE0*/0x04, 0xF0, 0xEE, 0x44, 0x82, 0xFE, 0xEF, 0x44, + 0x07, 0xF5, 0x82, 0x8E, 0x83, 0xE5, 0x45, 0x12, +/*1BF0*/0x08, 0xBE, 0x75, 0x83, 0x82, 0xE5, 0x31, 0xF0, + 0x02, 0x11, 0x4C, 0x8E, 0x60, 0x8F, 0x61, 0x12, +/*1C00*/0x1E, 0xA5, 0xE4, 0xFF, 0xCE, 0xED, 0xCE, 0xEE, + 0xD3, 0x95, 0x61, 0xE5, 0x60, 0x12, 0x07, 0x6B, +/*1C10*/0x40, 0x39, 0x74, 0x20, 0x2E, 0xF5, 0x82, 0xE4, + 0x34, 0x03, 0xF5, 0x83, 0xE0, 0x70, 0x03, 0xFF, +/*1C20*/0x80, 0x26, 0x12, 0x08, 0xE2, 0xFD, 0xC3, 0x9F, + 0x40, 0x1E, 0xCF, 0xED, 0xCF, 0xEB, 0x4A, 0x70, +/*1C30*/0x0B, 0x8D, 0x42, 0x12, 0x08, 0xEE, 0xF5, 0x41, + 0x8E, 0x40, 0x80, 0x0C, 0x12, 0x08, 0xE2, 0xF5, +/*1C40*/0x38, 0x12, 0x08, 0xEE, 0xF5, 0x39, 0x8E, 0x3A, + 0x1E, 0x80, 0xBC, 0x22, 0x75, 0x58, 0x01, 0xE5, +/*1C50*/0x35, 0x70, 0x0C, 0x12, 0x07, 0xCC, 0xE0, 0xF5, + 0x4A, 0x12, 0x07, 0xD8, 0xE0, 0xF5, 0x4C, 0xE5, +/*1C60*/0x35, 0xB4, 0x04, 0x0C, 0x12, 0x07, 0xE4, 0xE0, + 0xF5, 0x4A, 0x12, 0x07, 0xF0, 0xE0, 0xF5, 0x4C, +/*1C70*/0xE5, 0x35, 0xB4, 0x01, 0x04, 0x7F, 0x01, 0x80, + 0x02, 0x7F, 0x00, 0xE5, 0x35, 0xB4, 0x02, 0x04, +/*1C80*/0x7E, 0x01, 0x80, 0x02, 0x7E, 0x00, 0xEE, 0x4F, + 0x60, 0x0C, 0x12, 0x07, 0xFC, 0xE0, 0xF5, 0x4A, +/*1C90*/0x12, 0x08, 0x08, 0xE0, 0xF5, 0x4C, 0x85, 0x41, + 0x49, 0x85, 0x40, 0x4B, 0x22, 0x75, 0x5B, 0x01, +/*1CA0*/0x90, 0x07, 0x24, 0x12, 0x07, 0x35, 0xE0, 0x54, + 0x1F, 0xFF, 0xD3, 0x94, 0x02, 0x50, 0x04, 0x8F, +/*1CB0*/0x58, 0x80, 0x05, 0xEF, 0x24, 0xFE, 0xF5, 0x58, + 0xEF, 0xC3, 0x94, 0x18, 0x40, 0x05, 0x75, 0x59, +/*1CC0*/0x18, 0x80, 0x04, 0xEF, 0x04, 0xF5, 0x59, 0x85, + 0x43, 0x5A, 0xAF, 0x58, 0x7E, 0x00, 0xAD, 0x59, +/*1CD0*/0x7C, 0x00, 0xAB, 0x5B, 0x7A, 0x00, 0x12, 0x15, + 0x41, 0xAF, 0x5A, 0x7E, 0x00, 0x12, 0x18, 0x0A, +/*1CE0*/0xAF, 0x5B, 0x7E, 0x00, 0x02, 0x1A, 0xFF, 0xE5, + 0xE2, 0x30, 0xE7, 0x0E, 0x12, 0x10, 0x03, 0xC2, +/*1CF0*/0x30, 0x30, 0x30, 0x03, 0x12, 0x10, 0xFF, 0x20, + 0x33, 0x28, 0xE5, 0xE7, 0x30, 0xE7, 0x05, 0x12, +/*1D00*/0x0E, 0xA2, 0x80, 0x0D, 0xE5, 0xFE, 0xC3, 0x94, + 0x20, 0x50, 0x06, 0x12, 0x0E, 0xA2, 0x43, 0xF9, +/*1D10*/0x08, 0xE5, 0xF2, 0x30, 0xE7, 0x03, 0x53, 0xF9, + 0x7F, 0xE5, 0xF1, 0x54, 0x70, 0xD3, 0x94, 0x00, +/*1D20*/0x50, 0xD8, 0x22, 0x12, 0x0E, 0x04, 0x75, 0x83, + 0x80, 0xE4, 0xF0, 0xE5, 0x08, 0x44, 0x07, 0x12, +/*1D30*/0x0D, 0xFD, 0x75, 0x83, 0x84, 0x12, 0x0E, 0x02, + 0x75, 0x83, 0x86, 0x12, 0x0E, 0x02, 0x75, 0x83, +/*1D40*/0x8C, 0xE0, 0x54, 0xF3, 0x12, 0x0E, 0x03, 0x75, + 0x83, 0x8E, 0x12, 0x0E, 0x02, 0x75, 0x83, 0x94, +/*1D50*/0xE0, 0x54, 0xFB, 0xF0, 0x22, 0x12, 0x07, 0x2A, + 0x75, 0x83, 0x8E, 0xE4, 0x12, 0x07, 0x29, 0x74, +/*1D60*/0x01, 0x12, 0x07, 0x29, 0xE4, 0x12, 0x08, 0xBE, + 0x75, 0x83, 0x8C, 0xE0, 0x44, 0x20, 0x12, 0x08, +/*1D70*/0xBE, 0xE0, 0x54, 0xDF, 0xF0, 0x74, 0x84, 0x85, + 0x08, 0x82, 0xF5, 0x83, 0xE0, 0x54, 0x7F, 0xF0, +/*1D80*/0xE0, 0x44, 0x80, 0xF0, 0x22, 0x75, 0x56, 0x01, + 0xE4, 0xFD, 0xF5, 0x57, 0xAF, 0x35, 0xFE, 0xFC, +/*1D90*/0x12, 0x09, 0x15, 0x12, 0x1C, 0x9D, 0x12, 0x1E, + 0x7A, 0x12, 0x1C, 0x4C, 0xAF, 0x57, 0x7E, 0x00, +/*1DA0*/0xAD, 0x56, 0x7C, 0x00, 0x12, 0x04, 0x44, 0xAF, + 0x56, 0x7E, 0x00, 0x02, 0x11, 0xEE, 0x75, 0x56, +/*1DB0*/0x01, 0xE4, 0xFD, 0xF5, 0x57, 0xAF, 0x35, 0xFE, + 0xFC, 0x12, 0x09, 0x15, 0x12, 0x1C, 0x9D, 0x12, +/*1DC0*/0x1E, 0x7A, 0x12, 0x1C, 0x4C, 0xAF, 0x57, 0x7E, + 0x00, 0xAD, 0x56, 0x7C, 0x00, 0x12, 0x04, 0x44, +/*1DD0*/0xAF, 0x56, 0x7E, 0x00, 0x02, 0x11, 0xEE, 0xE4, + 0xF5, 0x16, 0x12, 0x0E, 0x44, 0xFE, 0xE5, 0x08, +/*1DE0*/0x44, 0x05, 0xFF, 0x12, 0x0E, 0x65, 0x8F, 0x82, + 0x8E, 0x83, 0xF0, 0x05, 0x16, 0xE5, 0x16, 0xC3, +/*1DF0*/0x94, 0x14, 0x40, 0xE6, 0xE5, 0x08, 0x12, 0x0E, + 0x2B, 0xE4, 0xF0, 0x22, 0xE4, 0xF5, 0x58, 0xF5, +/*1E00*/0x59, 0xF5, 0x5A, 0xFF, 0xFE, 0xAD, 0x58, 0xFC, + 0x12, 0x09, 0x15, 0x7F, 0x04, 0x7E, 0x00, 0xAD, +/*1E10*/0x58, 0x7C, 0x00, 0x12, 0x09, 0x15, 0x7F, 0x02, + 0x7E, 0x00, 0xAD, 0x58, 0x7C, 0x00, 0x02, 0x09, +/*1E20*/0x15, 0xE5, 0x3C, 0x25, 0x3E, 0xFC, 0xE5, 0x42, + 0x24, 0x00, 0xFB, 0xE4, 0x33, 0xFA, 0xEC, 0xC3, +/*1E30*/0x9B, 0xEA, 0x12, 0x07, 0x6B, 0x40, 0x0B, 0x8C, + 0x42, 0xE5, 0x3D, 0x25, 0x3F, 0xF5, 0x41, 0x8F, +/*1E40*/0x40, 0x22, 0x12, 0x09, 0x0B, 0x22, 0x74, 0x84, + 0xF5, 0x18, 0x85, 0x08, 0x19, 0x85, 0x19, 0x82, +/*1E50*/0x85, 0x18, 0x83, 0xE0, 0x54, 0x7F, 0xF0, 0xE0, + 0x44, 0x80, 0xF0, 0xE0, 0x44, 0x80, 0xF0, 0x22, +/*1E60*/0xEF, 0x4E, 0x70, 0x0B, 0x12, 0x07, 0x2A, 0x75, + 0x83, 0xD2, 0xE0, 0x54, 0xDF, 0xF0, 0x22, 0x12, +/*1E70*/0x07, 0x2A, 0x75, 0x83, 0xD2, 0xE0, 0x44, 0x20, + 0xF0, 0x22, 0x75, 0x58, 0x01, 0x90, 0x07, 0x26, +/*1E80*/0x12, 0x07, 0x35, 0xE0, 0x54, 0x3F, 0xF5, 0x41, + 0x12, 0x07, 0x32, 0xE0, 0x54, 0x3F, 0xF5, 0x40, +/*1E90*/0x22, 0x75, 0x56, 0x02, 0xE4, 0xF5, 0x57, 0x12, + 0x1D, 0xFC, 0xAF, 0x57, 0x7E, 0x00, 0xAD, 0x56, +/*1EA0*/0x7C, 0x00, 0x02, 0x04, 0x44, 0xE4, 0xF5, 0x42, + 0xF5, 0x41, 0xF5, 0x40, 0xF5, 0x38, 0xF5, 0x39, +/*1EB0*/0xF5, 0x3A, 0x22, 0xEF, 0x54, 0x07, 0xFF, 0xE5, + 0xF9, 0x54, 0xF8, 0x4F, 0xF5, 0xF9, 0x22, 0x7F, +/*1EC0*/0x01, 0xE4, 0xFE, 0x0F, 0x0E, 0xBE, 0xFF, 0xFB, + 0x22, 0x01, 0x20, 0x00, 0x01, 0x04, 0x20, 0x00, +/*1ED0*/0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/*1EE0*/0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/*1EF0*/0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/*1F00*/0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/*1F10*/0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/*1F20*/0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/*1F30*/0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/*1F40*/0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/*1F50*/0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/*1F60*/0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/*1F70*/0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/*1F80*/0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/*1F90*/0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/*1FA0*/0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/*1FB0*/0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/*1FC0*/0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/*1FD0*/0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/*1FE0*/0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/*1FF0*/0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x01, 0x20, 0x11, 0x00, 0x04, 0x20, 0x00, 0x81 +}; diff --git a/gpxe/src/drivers/infiniband/qib_7220_regs.h b/gpxe/src/drivers/infiniband/qib_7220_regs.h new file mode 100644 index 00000000..0dd3c53d --- /dev/null +++ b/gpxe/src/drivers/infiniband/qib_7220_regs.h @@ -0,0 +1,1763 @@ +/* + * Copyright (c) 2008 QLogic Corporation. All rights reserved. + * + * + * This software is available to you under a choice of one of two + * licenses. You may choose to be licensed under the terms of the GNU + * General Public License (GPL) Version 2, available from the file + * COPYING in the main directory of this source tree, or the + * OpenIB.org BSD license below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + * This file is mechanically generated. Any hand-edits will be lost. + * If not now, soon. + */ + +/* This file has been further processed by ./drivers/infiniband/qib_genbits.pl */ + + +#define QIB_7220_Revision_offset 0x00000000UL +struct QIB_7220_Revision_pb { + pseudo_bit_t R_ChipRevMinor[8]; + pseudo_bit_t R_ChipRevMajor[8]; + pseudo_bit_t R_Arch[8]; + pseudo_bit_t R_SW[8]; + pseudo_bit_t BoardID[8]; + pseudo_bit_t R_Palldium_Revcode[22]; + pseudo_bit_t R_Palladium[1]; + pseudo_bit_t R_Simulator[1]; +}; +struct QIB_7220_Revision { + PSEUDO_BIT_STRUCT ( struct QIB_7220_Revision_pb ); +}; + +#define QIB_7220_Control_offset 0x00000008UL +struct QIB_7220_Control_pb { + pseudo_bit_t SyncReset[1]; + pseudo_bit_t FreezeMode[1]; + pseudo_bit_t LinkEn[1]; + pseudo_bit_t PCIERetryBufDiagEn[1]; + pseudo_bit_t TxLatency[1]; + pseudo_bit_t Reserved[1]; + pseudo_bit_t PCIECplQDiagEn[1]; + pseudo_bit_t SyncResetExceptPcieIRAMRST[1]; + pseudo_bit_t _unused_0[56]; +}; +struct QIB_7220_Control { + PSEUDO_BIT_STRUCT ( struct QIB_7220_Control_pb ); +}; + +#define QIB_7220_PageAlign_offset 0x00000010UL + +#define QIB_7220_PortCnt_offset 0x00000018UL + +#define QIB_7220_DbgPortSel_offset 0x00000020UL +struct QIB_7220_DbgPortSel_pb { + pseudo_bit_t NibbleSel0[4]; + pseudo_bit_t NibbleSel1[4]; + pseudo_bit_t NibbleSel2[4]; + pseudo_bit_t NibbleSel3[4]; + pseudo_bit_t NibbleSel4[4]; + pseudo_bit_t NibbleSel5[4]; + pseudo_bit_t NibbleSel6[4]; + pseudo_bit_t NibbleSel7[4]; + pseudo_bit_t SrcMuxSel[14]; + pseudo_bit_t DbgClkPortSel[5]; + pseudo_bit_t EnDbgPort[1]; + pseudo_bit_t EnEnhancedDebugMode[1]; + pseudo_bit_t EnhMode_SrcMuxSelIndex[10]; + pseudo_bit_t EnhMode_SrcMuxSelWrEn[1]; +}; +struct QIB_7220_DbgPortSel { + PSEUDO_BIT_STRUCT ( struct QIB_7220_DbgPortSel_pb ); +}; + +#define QIB_7220_DebugSigsIntSel_offset 0x00000028UL +struct QIB_7220_DebugSigsIntSel_pb { + pseudo_bit_t debug_port_sel_pcs_pipe_lane07[3]; + pseudo_bit_t debug_port_sel_pcs_pipe_lane815[3]; + pseudo_bit_t debug_port_sel_pcs_sdout[1]; + pseudo_bit_t debug_port_sel_pcs_symlock_elfifo_lane[4]; + pseudo_bit_t debug_port_sel_pcs_rxdet_encdec_lane[4]; + pseudo_bit_t debug_port_sel_pcie_rx_tx[1]; + pseudo_bit_t debug_port_sel_xgxs[4]; + pseudo_bit_t debug_port_sel_epb_pcie[1]; + pseudo_bit_t _unused_0[43]; +}; +struct QIB_7220_DebugSigsIntSel { + PSEUDO_BIT_STRUCT ( struct QIB_7220_DebugSigsIntSel_pb ); +}; + +#define QIB_7220_SendRegBase_offset 0x00000030UL + +#define QIB_7220_UserRegBase_offset 0x00000038UL + +#define QIB_7220_CntrRegBase_offset 0x00000040UL + +#define QIB_7220_Scratch_offset 0x00000048UL + +#define QIB_7220_REG_000050_offset 0x00000050UL + +#define QIB_7220_IntBlocked_offset 0x00000060UL +struct QIB_7220_IntBlocked_pb { + pseudo_bit_t RcvAvail0IntBlocked[1]; + pseudo_bit_t RcvAvail1IntBlocked[1]; + pseudo_bit_t RcvAvail2IntBlocked[1]; + pseudo_bit_t RcvAvail3IntBlocked[1]; + pseudo_bit_t RcvAvail4IntBlocked[1]; + pseudo_bit_t RcvAvail5IntBlocked[1]; + pseudo_bit_t RcvAvail6IntBlocked[1]; + pseudo_bit_t RcvAvail7IntBlocked[1]; + pseudo_bit_t RcvAvail8IntBlocked[1]; + pseudo_bit_t RcvAvail9IntBlocked[1]; + pseudo_bit_t RcvAvail10IntBlocked[1]; + pseudo_bit_t RcvAvail11IntBlocked[1]; + pseudo_bit_t RcvAvail12IntBlocked[1]; + pseudo_bit_t RcvAvail13IntBlocked[1]; + pseudo_bit_t RcvAvail14IntBlocked[1]; + pseudo_bit_t RcvAvail15IntBlocked[1]; + pseudo_bit_t RcvAvail16IntBlocked[1]; + pseudo_bit_t Reserved1[9]; + pseudo_bit_t JIntBlocked[1]; + pseudo_bit_t IBSerdesTrimDoneIntBlocked[1]; + pseudo_bit_t assertGPIOIntBlocked[1]; + pseudo_bit_t PioBufAvailIntBlocked[1]; + pseudo_bit_t PioSetIntBlocked[1]; + pseudo_bit_t ErrorIntBlocked[1]; + pseudo_bit_t RcvUrg0IntBlocked[1]; + pseudo_bit_t RcvUrg1IntBlocked[1]; + pseudo_bit_t RcvUrg2IntBlocked[1]; + pseudo_bit_t RcvUrg3IntBlocked[1]; + pseudo_bit_t RcvUrg4IntBlocked[1]; + pseudo_bit_t RcvUrg5IntBlocked[1]; + pseudo_bit_t RcvUrg6IntBlocked[1]; + pseudo_bit_t RcvUrg7IntBlocked[1]; + pseudo_bit_t RcvUrg8IntBlocked[1]; + pseudo_bit_t RcvUrg9IntBlocked[1]; + pseudo_bit_t RcvUrg10IntBlocked[1]; + pseudo_bit_t RcvUrg11IntBlocked[1]; + pseudo_bit_t RcvUrg12IntBlocked[1]; + pseudo_bit_t RcvUrg13IntBlocked[1]; + pseudo_bit_t RcvUrg14IntBlocked[1]; + pseudo_bit_t RcvUrg15IntBlocked[1]; + pseudo_bit_t RcvUrg16IntBlocked[1]; + pseudo_bit_t Reserved[13]; + pseudo_bit_t SDmaDisabledBlocked[1]; + pseudo_bit_t SDmaIntBlocked[1]; +}; +struct QIB_7220_IntBlocked { + PSEUDO_BIT_STRUCT ( struct QIB_7220_IntBlocked_pb ); +}; + +#define QIB_7220_IntMask_offset 0x00000068UL +struct QIB_7220_IntMask_pb { + pseudo_bit_t RcvAvail0IntMask[1]; + pseudo_bit_t RcvAvail1IntMask[1]; + pseudo_bit_t RcvAvail2IntMask[1]; + pseudo_bit_t RcvAvail3IntMask[1]; + pseudo_bit_t RcvAvail4IntMask[1]; + pseudo_bit_t RcvAvail5IntMask[1]; + pseudo_bit_t RcvAvail6IntMask[1]; + pseudo_bit_t RcvAvail7IntMask[1]; + pseudo_bit_t RcvAvail8IntMask[1]; + pseudo_bit_t RcvAvail9IntMask[1]; + pseudo_bit_t RcvAvail10IntMask[1]; + pseudo_bit_t RcvAvail11IntMask[1]; + pseudo_bit_t RcvAvail12IntMask[1]; + pseudo_bit_t RcvAvail13IntMask[1]; + pseudo_bit_t RcvAvail14IntMask[1]; + pseudo_bit_t RcvAvail15IntMask[1]; + pseudo_bit_t RcvAvail16IntMask[1]; + pseudo_bit_t Reserved1[9]; + pseudo_bit_t JIntMask[1]; + pseudo_bit_t IBSerdesTrimDoneIntMask[1]; + pseudo_bit_t assertGPIOIntMask[1]; + pseudo_bit_t PioBufAvailIntMask[1]; + pseudo_bit_t PioSetIntMask[1]; + pseudo_bit_t ErrorIntMask[1]; + pseudo_bit_t RcvUrg0IntMask[1]; + pseudo_bit_t RcvUrg1IntMask[1]; + pseudo_bit_t RcvUrg2IntMask[1]; + pseudo_bit_t RcvUrg3IntMask[1]; + pseudo_bit_t RcvUrg4IntMask[1]; + pseudo_bit_t RcvUrg5IntMask[1]; + pseudo_bit_t RcvUrg6IntMask[1]; + pseudo_bit_t RcvUrg7IntMask[1]; + pseudo_bit_t RcvUrg8IntMask[1]; + pseudo_bit_t RcvUrg9IntMask[1]; + pseudo_bit_t RcvUrg10IntMask[1]; + pseudo_bit_t RcvUrg11IntMask[1]; + pseudo_bit_t RcvUrg12IntMask[1]; + pseudo_bit_t RcvUrg13IntMask[1]; + pseudo_bit_t RcvUrg14IntMask[1]; + pseudo_bit_t RcvUrg15IntMask[1]; + pseudo_bit_t RcvUrg16IntMask[1]; + pseudo_bit_t Reserved[13]; + pseudo_bit_t SDmaDisabledMasked[1]; + pseudo_bit_t SDmaIntMask[1]; +}; +struct QIB_7220_IntMask { + PSEUDO_BIT_STRUCT ( struct QIB_7220_IntMask_pb ); +}; + +#define QIB_7220_IntStatus_offset 0x00000070UL +struct QIB_7220_IntStatus_pb { + pseudo_bit_t RcvAvail0[1]; + pseudo_bit_t RcvAvail1[1]; + pseudo_bit_t RcvAvail2[1]; + pseudo_bit_t RcvAvail3[1]; + pseudo_bit_t RcvAvail4[1]; + pseudo_bit_t RcvAvail5[1]; + pseudo_bit_t RcvAvail6[1]; + pseudo_bit_t RcvAvail7[1]; + pseudo_bit_t RcvAvail8[1]; + pseudo_bit_t RcvAvail9[1]; + pseudo_bit_t RcvAvail10[1]; + pseudo_bit_t RcvAvail11[1]; + pseudo_bit_t RcvAvail12[1]; + pseudo_bit_t RcvAvail13[1]; + pseudo_bit_t RcvAvail14[1]; + pseudo_bit_t RcvAvail15[1]; + pseudo_bit_t RcvAvail16[1]; + pseudo_bit_t Reserved1[9]; + pseudo_bit_t JInt[1]; + pseudo_bit_t IBSerdesTrimDone[1]; + pseudo_bit_t assertGPIO[1]; + pseudo_bit_t PioBufAvail[1]; + pseudo_bit_t PioSent[1]; + pseudo_bit_t Error[1]; + pseudo_bit_t RcvUrg0[1]; + pseudo_bit_t RcvUrg1[1]; + pseudo_bit_t RcvUrg2[1]; + pseudo_bit_t RcvUrg3[1]; + pseudo_bit_t RcvUrg4[1]; + pseudo_bit_t RcvUrg5[1]; + pseudo_bit_t RcvUrg6[1]; + pseudo_bit_t RcvUrg7[1]; + pseudo_bit_t RcvUrg8[1]; + pseudo_bit_t RcvUrg9[1]; + pseudo_bit_t RcvUrg10[1]; + pseudo_bit_t RcvUrg11[1]; + pseudo_bit_t RcvUrg12[1]; + pseudo_bit_t RcvUrg13[1]; + pseudo_bit_t RcvUrg14[1]; + pseudo_bit_t RcvUrg15[1]; + pseudo_bit_t RcvUrg16[1]; + pseudo_bit_t Reserved[13]; + pseudo_bit_t SDmaDisabled[1]; + pseudo_bit_t SDmaInt[1]; +}; +struct QIB_7220_IntStatus { + PSEUDO_BIT_STRUCT ( struct QIB_7220_IntStatus_pb ); +}; + +#define QIB_7220_IntClear_offset 0x00000078UL +struct QIB_7220_IntClear_pb { + pseudo_bit_t RcvAvail0IntClear[1]; + pseudo_bit_t RcvAvail1IntClear[1]; + pseudo_bit_t RcvAvail2IntClear[1]; + pseudo_bit_t RcvAvail3IntClear[1]; + pseudo_bit_t RcvAvail4IntClear[1]; + pseudo_bit_t RcvAvail5IntClear[1]; + pseudo_bit_t RcvAvail6IntClear[1]; + pseudo_bit_t RcvAvail7IntClear[1]; + pseudo_bit_t RcvAvail8IntClear[1]; + pseudo_bit_t RcvAvail9IntClear[1]; + pseudo_bit_t RcvAvail10IntClear[1]; + pseudo_bit_t RcvAvail11IntClear[1]; + pseudo_bit_t RcvAvail12IntClear[1]; + pseudo_bit_t RcvAvail13IntClear[1]; + pseudo_bit_t RcvAvail14IntClear[1]; + pseudo_bit_t RcvAvail15IntClear[1]; + pseudo_bit_t RcvAvail16IntClear[1]; + pseudo_bit_t Reserved1[9]; + pseudo_bit_t JIntClear[1]; + pseudo_bit_t IBSerdesTrimDoneClear[1]; + pseudo_bit_t assertGPIOIntClear[1]; + pseudo_bit_t PioBufAvailIntClear[1]; + pseudo_bit_t PioSetIntClear[1]; + pseudo_bit_t ErrorIntClear[1]; + pseudo_bit_t RcvUrg0IntClear[1]; + pseudo_bit_t RcvUrg1IntClear[1]; + pseudo_bit_t RcvUrg2IntClear[1]; + pseudo_bit_t RcvUrg3IntClear[1]; + pseudo_bit_t RcvUrg4IntClear[1]; + pseudo_bit_t RcvUrg5IntClear[1]; + pseudo_bit_t RcvUrg6IntClear[1]; + pseudo_bit_t RcvUrg7IntClear[1]; + pseudo_bit_t RcvUrg8IntClear[1]; + pseudo_bit_t RcvUrg9IntClear[1]; + pseudo_bit_t RcvUrg10IntClear[1]; + pseudo_bit_t RcvUrg11IntClear[1]; + pseudo_bit_t RcvUrg12IntClear[1]; + pseudo_bit_t RcvUrg13IntClear[1]; + pseudo_bit_t RcvUrg14IntClear[1]; + pseudo_bit_t RcvUrg15IntClear[1]; + pseudo_bit_t RcvUrg16IntClear[1]; + pseudo_bit_t Reserved[13]; + pseudo_bit_t SDmaDisabledClear[1]; + pseudo_bit_t SDmaIntClear[1]; +}; +struct QIB_7220_IntClear { + PSEUDO_BIT_STRUCT ( struct QIB_7220_IntClear_pb ); +}; + +#define QIB_7220_ErrMask_offset 0x00000080UL +struct QIB_7220_ErrMask_pb { + pseudo_bit_t RcvFormatErrMask[1]; + pseudo_bit_t RcvVCRCErrMask[1]; + pseudo_bit_t RcvICRCErrMask[1]; + pseudo_bit_t RcvMinPktLenErrMask[1]; + pseudo_bit_t RcvMaxPktLenErrMask[1]; + pseudo_bit_t RcvLongPktLenErrMask[1]; + pseudo_bit_t RcvShortPktLenErrMask[1]; + pseudo_bit_t RcvUnexpectedCharErrMask[1]; + pseudo_bit_t RcvUnsupportedVLErrMask[1]; + pseudo_bit_t RcvEBPErrMask[1]; + pseudo_bit_t RcvIBFlowErrMask[1]; + pseudo_bit_t RcvBadVersionErrMask[1]; + pseudo_bit_t RcvEgrFullErrMask[1]; + pseudo_bit_t RcvHdrFullErrMask[1]; + pseudo_bit_t RcvBadTidErrMask[1]; + pseudo_bit_t RcvHdrLenErrMask[1]; + pseudo_bit_t RcvHdrErrMask[1]; + pseudo_bit_t RcvIBLostLinkErrMask[1]; + pseudo_bit_t Reserved1[9]; + pseudo_bit_t SendSpecialTriggerErrMask[1]; + pseudo_bit_t SDmaDisabledErrMask[1]; + pseudo_bit_t SendMinPktLenErrMask[1]; + pseudo_bit_t SendMaxPktLenErrMask[1]; + pseudo_bit_t SendUnderRunErrMask[1]; + pseudo_bit_t SendPktLenErrMask[1]; + pseudo_bit_t SendDroppedSmpPktErrMask[1]; + pseudo_bit_t SendDroppedDataPktErrMask[1]; + pseudo_bit_t SendPioArmLaunchErrMask[1]; + pseudo_bit_t SendUnexpectedPktNumErrMask[1]; + pseudo_bit_t SendUnsupportedVLErrMask[1]; + pseudo_bit_t SendBufMisuseErrMask[1]; + pseudo_bit_t SDmaGenMismatchErrMask[1]; + pseudo_bit_t SDmaOutOfBoundErrMask[1]; + pseudo_bit_t SDmaTailOutOfBoundErrMask[1]; + pseudo_bit_t SDmaBaseErrMask[1]; + pseudo_bit_t SDma1stDescErrMask[1]; + pseudo_bit_t SDmaRpyTagErrMask[1]; + pseudo_bit_t SDmaDwEnErrMask[1]; + pseudo_bit_t SDmaMissingDwErrMask[1]; + pseudo_bit_t SDmaUnexpDataErrMask[1]; + pseudo_bit_t IBStatusChangedMask[1]; + pseudo_bit_t InvalidAddrErrMask[1]; + pseudo_bit_t ResetNegatedMask[1]; + pseudo_bit_t HardwareErrMask[1]; + pseudo_bit_t SDmaDescAddrMisalignErrMask[1]; + pseudo_bit_t InvalidEEPCmdMask[1]; + pseudo_bit_t Reserved[10]; +}; +struct QIB_7220_ErrMask { + PSEUDO_BIT_STRUCT ( struct QIB_7220_ErrMask_pb ); +}; + +#define QIB_7220_ErrStatus_offset 0x00000088UL +struct QIB_7220_ErrStatus_pb { + pseudo_bit_t RcvFormatErr[1]; + pseudo_bit_t RcvVCRCErr[1]; + pseudo_bit_t RcvICRCErr[1]; + pseudo_bit_t RcvMinPktLenErr[1]; + pseudo_bit_t RcvMaxPktLenErr[1]; + pseudo_bit_t RcvLongPktLenErr[1]; + pseudo_bit_t RcvShortPktLenErr[1]; + pseudo_bit_t RcvUnexpectedCharErr[1]; + pseudo_bit_t RcvUnsupportedVLErr[1]; + pseudo_bit_t RcvEBPErr[1]; + pseudo_bit_t RcvIBFlowErr[1]; + pseudo_bit_t RcvBadVersionErr[1]; + pseudo_bit_t RcvEgrFullErr[1]; + pseudo_bit_t RcvHdrFullErr[1]; + pseudo_bit_t RcvBadTidErr[1]; + pseudo_bit_t RcvHdrLenErr[1]; + pseudo_bit_t RcvHdrErr[1]; + pseudo_bit_t RcvIBLostLinkErr[1]; + pseudo_bit_t Reserved1[9]; + pseudo_bit_t SendSpecialTriggerErr[1]; + pseudo_bit_t SDmaDisabledErr[1]; + pseudo_bit_t SendMinPktLenErr[1]; + pseudo_bit_t SendMaxPktLenErr[1]; + pseudo_bit_t SendUnderRunErr[1]; + pseudo_bit_t SendPktLenErr[1]; + pseudo_bit_t SendDroppedSmpPktErr[1]; + pseudo_bit_t SendDroppedDataPktErr[1]; + pseudo_bit_t SendPioArmLaunchErr[1]; + pseudo_bit_t SendUnexpectedPktNumErr[1]; + pseudo_bit_t SendUnsupportedVLErr[1]; + pseudo_bit_t SendBufMisuseErr[1]; + pseudo_bit_t SDmaGenMismatchErr[1]; + pseudo_bit_t SDmaOutOfBoundErr[1]; + pseudo_bit_t SDmaTailOutOfBoundErr[1]; + pseudo_bit_t SDmaBaseErr[1]; + pseudo_bit_t SDma1stDescErr[1]; + pseudo_bit_t SDmaRpyTagErr[1]; + pseudo_bit_t SDmaDwEnErr[1]; + pseudo_bit_t SDmaMissingDwErr[1]; + pseudo_bit_t SDmaUnexpDataErr[1]; + pseudo_bit_t IBStatusChanged[1]; + pseudo_bit_t InvalidAddrErr[1]; + pseudo_bit_t ResetNegated[1]; + pseudo_bit_t HardwareErr[1]; + pseudo_bit_t SDmaDescAddrMisalignErr[1]; + pseudo_bit_t InvalidEEPCmdErr[1]; + pseudo_bit_t Reserved[10]; +}; +struct QIB_7220_ErrStatus { + PSEUDO_BIT_STRUCT ( struct QIB_7220_ErrStatus_pb ); +}; + +#define QIB_7220_ErrClear_offset 0x00000090UL +struct QIB_7220_ErrClear_pb { + pseudo_bit_t RcvFormatErrClear[1]; + pseudo_bit_t RcvVCRCErrClear[1]; + pseudo_bit_t RcvICRCErrClear[1]; + pseudo_bit_t RcvMinPktLenErrClear[1]; + pseudo_bit_t RcvMaxPktLenErrClear[1]; + pseudo_bit_t RcvLongPktLenErrClear[1]; + pseudo_bit_t RcvShortPktLenErrClear[1]; + pseudo_bit_t RcvUnexpectedCharErrClear[1]; + pseudo_bit_t RcvUnsupportedVLErrClear[1]; + pseudo_bit_t RcvEBPErrClear[1]; + pseudo_bit_t RcvIBFlowErrClear[1]; + pseudo_bit_t RcvBadVersionErrClear[1]; + pseudo_bit_t RcvEgrFullErrClear[1]; + pseudo_bit_t RcvHdrFullErrClear[1]; + pseudo_bit_t RcvBadTidErrClear[1]; + pseudo_bit_t RcvHdrLenErrClear[1]; + pseudo_bit_t RcvHdrErrClear[1]; + pseudo_bit_t RcvIBLostLinkErrClear[1]; + pseudo_bit_t Reserved1[9]; + pseudo_bit_t SendSpecialTriggerErrClear[1]; + pseudo_bit_t SDmaDisabledErrClear[1]; + pseudo_bit_t SendMinPktLenErrClear[1]; + pseudo_bit_t SendMaxPktLenErrClear[1]; + pseudo_bit_t SendUnderRunErrClear[1]; + pseudo_bit_t SendPktLenErrClear[1]; + pseudo_bit_t SendDroppedSmpPktErrClear[1]; + pseudo_bit_t SendDroppedDataPktErrClear[1]; + pseudo_bit_t SendPioArmLaunchErrClear[1]; + pseudo_bit_t SendUnexpectedPktNumErrClear[1]; + pseudo_bit_t SendUnsupportedVLErrClear[1]; + pseudo_bit_t SendBufMisuseErrClear[1]; + pseudo_bit_t SDmaGenMismatchErrClear[1]; + pseudo_bit_t SDmaOutOfBoundErrClear[1]; + pseudo_bit_t SDmaTailOutOfBoundErrClear[1]; + pseudo_bit_t SDmaBaseErrClear[1]; + pseudo_bit_t SDma1stDescErrClear[1]; + pseudo_bit_t SDmaRpyTagErrClear[1]; + pseudo_bit_t SDmaDwEnErrClear[1]; + pseudo_bit_t SDmaMissingDwErrClear[1]; + pseudo_bit_t SDmaUnexpDataErrClear[1]; + pseudo_bit_t IBStatusChangedClear[1]; + pseudo_bit_t InvalidAddrErrClear[1]; + pseudo_bit_t ResetNegatedClear[1]; + pseudo_bit_t HardwareErrClear[1]; + pseudo_bit_t SDmaDescAddrMisalignErrClear[1]; + pseudo_bit_t InvalidEEPCmdErrClear[1]; + pseudo_bit_t Reserved[10]; +}; +struct QIB_7220_ErrClear { + PSEUDO_BIT_STRUCT ( struct QIB_7220_ErrClear_pb ); +}; + +#define QIB_7220_HwErrMask_offset 0x00000098UL +struct QIB_7220_HwErrMask_pb { + pseudo_bit_t PCIeMemParityErrMask[8]; + pseudo_bit_t Reserved3[20]; + pseudo_bit_t SDmaMemReadErrMask[1]; + pseudo_bit_t PoisonedTLPMask[1]; + pseudo_bit_t PcieCplTimeoutMask[1]; + pseudo_bit_t PCIeBusParityErrMask[3]; + pseudo_bit_t Reserved2[2]; + pseudo_bit_t PCIEOct0_uC_MemoryParityErrMask[1]; + pseudo_bit_t PCIEOct1_uC_MemoryParityErrMask[1]; + pseudo_bit_t IB_uC_MemoryParityErrMask[1]; + pseudo_bit_t DDSRXEQMemoryParityErrMask[1]; + pseudo_bit_t TXEMemParityErrMask[4]; + pseudo_bit_t RXEMemParityErrMask[7]; + pseudo_bit_t Reserved1[3]; + pseudo_bit_t PowerOnBISTFailedMask[1]; + pseudo_bit_t Reserved[1]; + pseudo_bit_t PCIESerdesQ0PClkNotDetectMask[1]; + pseudo_bit_t PCIESerdesQ1PClkNotDetectMask[1]; + pseudo_bit_t PCIESerdesQ2PClkNotDetectMask[1]; + pseudo_bit_t PCIESerdesQ3PClkNotDetectMask[1]; + pseudo_bit_t IBSerdesPClkNotDetectMask[1]; + pseudo_bit_t Clk_uC_PLLNotLockedMask[1]; + pseudo_bit_t IBCBusToSPCParityErrMask[1]; + pseudo_bit_t IBCBusFromSPCParityErrMask[1]; +}; +struct QIB_7220_HwErrMask { + PSEUDO_BIT_STRUCT ( struct QIB_7220_HwErrMask_pb ); +}; + +#define QIB_7220_HwErrStatus_offset 0x000000a0UL +struct QIB_7220_HwErrStatus_pb { + pseudo_bit_t PCIeMemParity[8]; + pseudo_bit_t Reserved3[20]; + pseudo_bit_t SDmaMemReadErr[1]; + pseudo_bit_t PoisenedTLP[1]; + pseudo_bit_t PcieCplTimeout[1]; + pseudo_bit_t PCIeBusParity[3]; + pseudo_bit_t Reserved2[2]; + pseudo_bit_t PCIE_uC_Oct0MemoryParityErr[1]; + pseudo_bit_t PCIE_uC_Oct1MemoryParityErr[1]; + pseudo_bit_t IB_uC_MemoryParityErr[1]; + pseudo_bit_t DDSRXEQMemoryParityErr[1]; + pseudo_bit_t TXEMemParity[4]; + pseudo_bit_t RXEMemParity[7]; + pseudo_bit_t Reserved1[3]; + pseudo_bit_t PowerOnBISTFailed[1]; + pseudo_bit_t Reserved[1]; + pseudo_bit_t PCIESerdesQ0PClkNotDetect[1]; + pseudo_bit_t PCIESerdesQ1PClkNotDetect[1]; + pseudo_bit_t PCIESerdesQ2PClkNotDetect[1]; + pseudo_bit_t PCIESerdesQ3PClkNotDetect[1]; + pseudo_bit_t IBSerdesPClkNotDetect[1]; + pseudo_bit_t Clk_uC_PLLNotLocked[1]; + pseudo_bit_t IBCBusToSPCParityErr[1]; + pseudo_bit_t IBCBusFromSPCParityErr[1]; +}; +struct QIB_7220_HwErrStatus { + PSEUDO_BIT_STRUCT ( struct QIB_7220_HwErrStatus_pb ); +}; + +#define QIB_7220_HwErrClear_offset 0x000000a8UL +struct QIB_7220_HwErrClear_pb { + pseudo_bit_t PCIeMemParityClr[8]; + pseudo_bit_t Reserved3[20]; + pseudo_bit_t SDmaMemReadErrClear[1]; + pseudo_bit_t PoisonedTLPClear[1]; + pseudo_bit_t PcieCplTimeoutClear[1]; + pseudo_bit_t PCIeBusParityClr[3]; + pseudo_bit_t Reserved2[2]; + pseudo_bit_t PCIE_uC_Oct0MemoryParityErrClear[1]; + pseudo_bit_t PCIE_uC_Oct1MemoryParityErrClear[1]; + pseudo_bit_t IB_uC_MemoryParityErrClear[1]; + pseudo_bit_t DDSRXEQMemoryParityErrClear[1]; + pseudo_bit_t TXEMemParityClear[4]; + pseudo_bit_t RXEMemParityClear[7]; + pseudo_bit_t Reserved1[3]; + pseudo_bit_t PowerOnBISTFailedClear[1]; + pseudo_bit_t Reserved[1]; + pseudo_bit_t PCIESerdesQ0PClkNotDetectClear[1]; + pseudo_bit_t PCIESerdesQ1PClkNotDetectClear[1]; + pseudo_bit_t PCIESerdesQ2PClkNotDetectClear[1]; + pseudo_bit_t PCIESerdesQ3PClkNotDetectClear[1]; + pseudo_bit_t IBSerdesPClkNotDetectClear[1]; + pseudo_bit_t Clk_uC_PLLNotLockedClear[1]; + pseudo_bit_t IBCBusToSPCparityErrClear[1]; + pseudo_bit_t IBCBusFromSPCParityErrClear[1]; +}; +struct QIB_7220_HwErrClear { + PSEUDO_BIT_STRUCT ( struct QIB_7220_HwErrClear_pb ); +}; + +#define QIB_7220_HwDiagCtrl_offset 0x000000b0UL +struct QIB_7220_HwDiagCtrl_pb { + pseudo_bit_t forcePCIeMemParity[8]; + pseudo_bit_t Reserved2[23]; + pseudo_bit_t forcePCIeBusParity[4]; + pseudo_bit_t Reserved1[1]; + pseudo_bit_t ForcePCIE_uC_Oct0MemoryParityErr[1]; + pseudo_bit_t ForcePCIE_uC_Oct1MemoryParityErr[1]; + pseudo_bit_t ForceIB_uC_MemoryParityErr[1]; + pseudo_bit_t ForceDDSRXEQMemoryParityErr[1]; + pseudo_bit_t ForceTxMemparityErr[4]; + pseudo_bit_t ForceRxMemParityErr[7]; + pseudo_bit_t Reserved[9]; + pseudo_bit_t CounterDisable[1]; + pseudo_bit_t CounterWrEnable[1]; + pseudo_bit_t ForceIBCBusToSPCParityErr[1]; + pseudo_bit_t ForceIBCBusFromSPCParityErr[1]; +}; +struct QIB_7220_HwDiagCtrl { + PSEUDO_BIT_STRUCT ( struct QIB_7220_HwDiagCtrl_pb ); +}; + +#define QIB_7220_REG_0000B8_offset 0x000000b8UL + +#define QIB_7220_IBCStatus_offset 0x000000c0UL +struct QIB_7220_IBCStatus_pb { + pseudo_bit_t LinkTrainingState[5]; + pseudo_bit_t LinkState[3]; + pseudo_bit_t LinkSpeedActive[1]; + pseudo_bit_t LinkWidthActive[1]; + pseudo_bit_t DDS_RXEQ_FAIL[1]; + pseudo_bit_t IB_SERDES_TRIM_DONE[1]; + pseudo_bit_t IBRxLaneReversed[1]; + pseudo_bit_t IBTxLaneReversed[1]; + pseudo_bit_t Reserved[16]; + pseudo_bit_t TxReady[1]; + pseudo_bit_t TxCreditOk[1]; + pseudo_bit_t _unused_0[32]; +}; +struct QIB_7220_IBCStatus { + PSEUDO_BIT_STRUCT ( struct QIB_7220_IBCStatus_pb ); +}; + +#define QIB_7220_IBCCtrl_offset 0x000000c8UL +struct QIB_7220_IBCCtrl_pb { + pseudo_bit_t FlowCtrlPeriod[8]; + pseudo_bit_t FlowCtrlWaterMark[8]; + pseudo_bit_t LinkInitCmd[3]; + pseudo_bit_t LinkCmd[2]; + pseudo_bit_t MaxPktLen[11]; + pseudo_bit_t PhyerrThreshold[4]; + pseudo_bit_t OverrunThreshold[4]; + pseudo_bit_t CreditScale[3]; + pseudo_bit_t Reserved[19]; + pseudo_bit_t LinkDownDefaultState[1]; + pseudo_bit_t Loopback[1]; +}; +struct QIB_7220_IBCCtrl { + PSEUDO_BIT_STRUCT ( struct QIB_7220_IBCCtrl_pb ); +}; + +#define QIB_7220_EXTStatus_offset 0x000000d0UL +struct QIB_7220_EXTStatus_pb { + pseudo_bit_t Reserved2[14]; + pseudo_bit_t MemBISTEndTest[1]; + pseudo_bit_t MemBISTDisabled[1]; + pseudo_bit_t Reserved1[16]; + pseudo_bit_t Reserved[16]; + pseudo_bit_t GPIOIn[16]; +}; +struct QIB_7220_EXTStatus { + PSEUDO_BIT_STRUCT ( struct QIB_7220_EXTStatus_pb ); +}; + +#define QIB_7220_EXTCtrl_offset 0x000000d8UL +struct QIB_7220_EXTCtrl_pb { + pseudo_bit_t LEDGblErrRedOff[1]; + pseudo_bit_t LEDGblOkGreenOn[1]; + pseudo_bit_t LEDPriPortYellowOn[1]; + pseudo_bit_t LEDPriPortGreenOn[1]; + pseudo_bit_t Reserved[28]; + pseudo_bit_t GPIOInvert[16]; + pseudo_bit_t GPIOOe[16]; +}; +struct QIB_7220_EXTCtrl { + PSEUDO_BIT_STRUCT ( struct QIB_7220_EXTCtrl_pb ); +}; + +#define QIB_7220_GPIOOut_offset 0x000000e0UL + +#define QIB_7220_GPIOMask_offset 0x000000e8UL + +#define QIB_7220_GPIOStatus_offset 0x000000f0UL + +#define QIB_7220_GPIOClear_offset 0x000000f8UL + +#define QIB_7220_RcvCtrl_offset 0x00000100UL +struct QIB_7220_RcvCtrl_pb { + pseudo_bit_t PortEnable[17]; + pseudo_bit_t IntrAvail[17]; + pseudo_bit_t RcvPartitionKeyDisable[1]; + pseudo_bit_t TailUpd[1]; + pseudo_bit_t PortCfg[2]; + pseudo_bit_t RcvQPMapEnable[1]; + pseudo_bit_t Reserved[25]; +}; +struct QIB_7220_RcvCtrl { + PSEUDO_BIT_STRUCT ( struct QIB_7220_RcvCtrl_pb ); +}; + +#define QIB_7220_RcvBTHQP_offset 0x00000108UL +struct QIB_7220_RcvBTHQP_pb { + pseudo_bit_t RcvBTHQP[24]; + pseudo_bit_t Reserved[8]; + pseudo_bit_t _unused_0[32]; +}; +struct QIB_7220_RcvBTHQP { + PSEUDO_BIT_STRUCT ( struct QIB_7220_RcvBTHQP_pb ); +}; + +#define QIB_7220_RcvHdrSize_offset 0x00000110UL + +#define QIB_7220_RcvHdrCnt_offset 0x00000118UL + +#define QIB_7220_RcvHdrEntSize_offset 0x00000120UL + +#define QIB_7220_RcvTIDBase_offset 0x00000128UL + +#define QIB_7220_RcvTIDCnt_offset 0x00000130UL + +#define QIB_7220_RcvEgrBase_offset 0x00000138UL + +#define QIB_7220_RcvEgrCnt_offset 0x00000140UL + +#define QIB_7220_RcvBufBase_offset 0x00000148UL + +#define QIB_7220_RcvBufSize_offset 0x00000150UL + +#define QIB_7220_RxIntMemBase_offset 0x00000158UL + +#define QIB_7220_RxIntMemSize_offset 0x00000160UL + +#define QIB_7220_RcvPartitionKey_offset 0x00000168UL + +#define QIB_7220_RcvQPMulticastPort_offset 0x00000170UL +struct QIB_7220_RcvQPMulticastPort_pb { + pseudo_bit_t RcvQpMcPort[5]; + pseudo_bit_t Reserved[59]; +}; +struct QIB_7220_RcvQPMulticastPort { + PSEUDO_BIT_STRUCT ( struct QIB_7220_RcvQPMulticastPort_pb ); +}; + +#define QIB_7220_RcvPktLEDCnt_offset 0x00000178UL +struct QIB_7220_RcvPktLEDCnt_pb { + pseudo_bit_t OFFperiod[32]; + pseudo_bit_t ONperiod[32]; +}; +struct QIB_7220_RcvPktLEDCnt { + PSEUDO_BIT_STRUCT ( struct QIB_7220_RcvPktLEDCnt_pb ); +}; + +#define QIB_7220_IBCDDRCtrl_offset 0x00000180UL +struct QIB_7220_IBCDDRCtrl_pb { + pseudo_bit_t IB_ENHANCED_MODE[1]; + pseudo_bit_t SD_SPEED[1]; + pseudo_bit_t SD_SPEED_SDR[1]; + pseudo_bit_t SD_SPEED_DDR[1]; + pseudo_bit_t SD_SPEED_QDR[1]; + pseudo_bit_t IB_NUM_CHANNELS[2]; + pseudo_bit_t IB_POLARITY_REV_SUPP[1]; + pseudo_bit_t IB_LANE_REV_SUPPORTED[1]; + pseudo_bit_t SD_RX_EQUAL_ENABLE[1]; + pseudo_bit_t SD_ADD_ENB[1]; + pseudo_bit_t SD_DDSV[1]; + pseudo_bit_t SD_DDS[4]; + pseudo_bit_t HRTBT_ENB[1]; + pseudo_bit_t HRTBT_AUTO[1]; + pseudo_bit_t HRTBT_PORT[8]; + pseudo_bit_t HRTBT_REQ[1]; + pseudo_bit_t Reserved[5]; + pseudo_bit_t IB_DLID[16]; + pseudo_bit_t IB_DLID_MASK[16]; +}; +struct QIB_7220_IBCDDRCtrl { + PSEUDO_BIT_STRUCT ( struct QIB_7220_IBCDDRCtrl_pb ); +}; + +#define QIB_7220_HRTBT_GUID_offset 0x00000188UL + +#define QIB_7220_IB_SDTEST_IF_TX_offset 0x00000190UL +struct QIB_7220_IB_SDTEST_IF_TX_pb { + pseudo_bit_t TS_T_TX_VALID[1]; + pseudo_bit_t TS_3_TX_VALID[1]; + pseudo_bit_t Reserved1[9]; + pseudo_bit_t TS_TX_OPCODE[2]; + pseudo_bit_t TS_TX_SPEED[3]; + pseudo_bit_t Reserved[16]; + pseudo_bit_t TS_TX_TX_CFG[16]; + pseudo_bit_t TS_TX_RX_CFG[16]; +}; +struct QIB_7220_IB_SDTEST_IF_TX { + PSEUDO_BIT_STRUCT ( struct QIB_7220_IB_SDTEST_IF_TX_pb ); +}; + +#define QIB_7220_IB_SDTEST_IF_RX_offset 0x00000198UL +struct QIB_7220_IB_SDTEST_IF_RX_pb { + pseudo_bit_t TS_T_RX_VALID[1]; + pseudo_bit_t TS_3_RX_VALID[1]; + pseudo_bit_t Reserved[14]; + pseudo_bit_t TS_RX_A[8]; + pseudo_bit_t TS_RX_B[8]; + pseudo_bit_t TS_RX_TX_CFG[16]; + pseudo_bit_t TS_RX_RX_CFG[16]; +}; +struct QIB_7220_IB_SDTEST_IF_RX { + PSEUDO_BIT_STRUCT ( struct QIB_7220_IB_SDTEST_IF_RX_pb ); +}; + +#define QIB_7220_IBCDDRCtrl2_offset 0x000001a0UL +struct QIB_7220_IBCDDRCtrl2_pb { + pseudo_bit_t IB_FRONT_PORCH[5]; + pseudo_bit_t IB_BACK_PORCH[5]; + pseudo_bit_t _unused_0[54]; +}; +struct QIB_7220_IBCDDRCtrl2 { + PSEUDO_BIT_STRUCT ( struct QIB_7220_IBCDDRCtrl2_pb ); +}; + +#define QIB_7220_IBCDDRStatus_offset 0x000001a8UL +struct QIB_7220_IBCDDRStatus_pb { + pseudo_bit_t LinkRoundTripLatency[26]; + pseudo_bit_t ReqDDSLocalFromRmt[4]; + pseudo_bit_t RxEqLocalDevice[2]; + pseudo_bit_t heartbeat_crosstalk[4]; + pseudo_bit_t heartbeat_timed_out[1]; + pseudo_bit_t _unused_0[27]; +}; +struct QIB_7220_IBCDDRStatus { + PSEUDO_BIT_STRUCT ( struct QIB_7220_IBCDDRStatus_pb ); +}; + +#define QIB_7220_JIntReload_offset 0x000001b0UL +struct QIB_7220_JIntReload_pb { + pseudo_bit_t J_reload[16]; + pseudo_bit_t J_limit_reload[16]; + pseudo_bit_t _unused_0[32]; +}; +struct QIB_7220_JIntReload { + PSEUDO_BIT_STRUCT ( struct QIB_7220_JIntReload_pb ); +}; + +#define QIB_7220_IBNCModeCtrl_offset 0x000001b8UL +struct QIB_7220_IBNCModeCtrl_pb { + pseudo_bit_t TSMEnable_send_TS1[1]; + pseudo_bit_t TSMEnable_send_TS2[1]; + pseudo_bit_t TSMEnable_ignore_TSM_on_rx[1]; + pseudo_bit_t Reserved1[5]; + pseudo_bit_t TSMCode_TS1[9]; + pseudo_bit_t TSMCode_TS2[9]; + pseudo_bit_t Reserved[38]; +}; +struct QIB_7220_IBNCModeCtrl { + PSEUDO_BIT_STRUCT ( struct QIB_7220_IBNCModeCtrl_pb ); +}; + +#define QIB_7220_SendCtrl_offset 0x000001c0UL +struct QIB_7220_SendCtrl_pb { + pseudo_bit_t Abort[1]; + pseudo_bit_t SendIntBufAvail[1]; + pseudo_bit_t SendBufAvailUpd[1]; + pseudo_bit_t SPioEnable[1]; + pseudo_bit_t SSpecialTriggerEn[1]; + pseudo_bit_t Reserved2[4]; + pseudo_bit_t SDmaIntEnable[1]; + pseudo_bit_t SDmaSingleDescriptor[1]; + pseudo_bit_t SDmaEnable[1]; + pseudo_bit_t SDmaHalt[1]; + pseudo_bit_t Reserved1[3]; + pseudo_bit_t DisarmPIOBuf[8]; + pseudo_bit_t AvailUpdThld[5]; + pseudo_bit_t Reserved[2]; + pseudo_bit_t Disarm[1]; + pseudo_bit_t _unused_0[32]; +}; +struct QIB_7220_SendCtrl { + PSEUDO_BIT_STRUCT ( struct QIB_7220_SendCtrl_pb ); +}; + +#define QIB_7220_SendBufBase_offset 0x000001c8UL +struct QIB_7220_SendBufBase_pb { + pseudo_bit_t BaseAddr_SmallPIO[21]; + pseudo_bit_t Reserved1[11]; + pseudo_bit_t BaseAddr_LargePIO[21]; + pseudo_bit_t Reserved[11]; +}; +struct QIB_7220_SendBufBase { + PSEUDO_BIT_STRUCT ( struct QIB_7220_SendBufBase_pb ); +}; + +#define QIB_7220_SendBufSize_offset 0x000001d0UL +struct QIB_7220_SendBufSize_pb { + pseudo_bit_t Size_SmallPIO[12]; + pseudo_bit_t Reserved1[20]; + pseudo_bit_t Size_LargePIO[13]; + pseudo_bit_t Reserved[19]; +}; +struct QIB_7220_SendBufSize { + PSEUDO_BIT_STRUCT ( struct QIB_7220_SendBufSize_pb ); +}; + +#define QIB_7220_SendBufCnt_offset 0x000001d8UL +struct QIB_7220_SendBufCnt_pb { + pseudo_bit_t Num_SmallBuffers[9]; + pseudo_bit_t Reserved1[23]; + pseudo_bit_t Num_LargeBuffers[4]; + pseudo_bit_t Reserved[28]; +}; +struct QIB_7220_SendBufCnt { + PSEUDO_BIT_STRUCT ( struct QIB_7220_SendBufCnt_pb ); +}; + +#define QIB_7220_SendBufAvailAddr_offset 0x000001e0UL +struct QIB_7220_SendBufAvailAddr_pb { + pseudo_bit_t Reserved[6]; + pseudo_bit_t SendBufAvailAddr[34]; + pseudo_bit_t _unused_0[24]; +}; +struct QIB_7220_SendBufAvailAddr { + PSEUDO_BIT_STRUCT ( struct QIB_7220_SendBufAvailAddr_pb ); +}; + +#define QIB_7220_TxIntMemBase_offset 0x000001e8UL + +#define QIB_7220_TxIntMemSize_offset 0x000001f0UL + +#define QIB_7220_SendDmaBase_offset 0x000001f8UL +struct QIB_7220_SendDmaBase_pb { + pseudo_bit_t SendDmaBase[48]; + pseudo_bit_t Reserved[16]; +}; +struct QIB_7220_SendDmaBase { + PSEUDO_BIT_STRUCT ( struct QIB_7220_SendDmaBase_pb ); +}; + +#define QIB_7220_SendDmaLenGen_offset 0x00000200UL +struct QIB_7220_SendDmaLenGen_pb { + pseudo_bit_t Length[16]; + pseudo_bit_t Generation[3]; + pseudo_bit_t Reserved[45]; +}; +struct QIB_7220_SendDmaLenGen { + PSEUDO_BIT_STRUCT ( struct QIB_7220_SendDmaLenGen_pb ); +}; + +#define QIB_7220_SendDmaTail_offset 0x00000208UL +struct QIB_7220_SendDmaTail_pb { + pseudo_bit_t SendDmaTail[16]; + pseudo_bit_t Reserved[48]; +}; +struct QIB_7220_SendDmaTail { + PSEUDO_BIT_STRUCT ( struct QIB_7220_SendDmaTail_pb ); +}; + +#define QIB_7220_SendDmaHead_offset 0x00000210UL +struct QIB_7220_SendDmaHead_pb { + pseudo_bit_t SendDmaHead[16]; + pseudo_bit_t Reserved1[16]; + pseudo_bit_t InternalSendDmaHead[16]; + pseudo_bit_t Reserved[16]; +}; +struct QIB_7220_SendDmaHead { + PSEUDO_BIT_STRUCT ( struct QIB_7220_SendDmaHead_pb ); +}; + +#define QIB_7220_SendDmaHeadAddr_offset 0x00000218UL +struct QIB_7220_SendDmaHeadAddr_pb { + pseudo_bit_t SendDmaHeadAddr[48]; + pseudo_bit_t Reserved[16]; +}; +struct QIB_7220_SendDmaHeadAddr { + PSEUDO_BIT_STRUCT ( struct QIB_7220_SendDmaHeadAddr_pb ); +}; + +#define QIB_7220_SendDmaBufMask0_offset 0x00000220UL +struct QIB_7220_SendDmaBufMask0_pb { + pseudo_bit_t BufMask_63_0[0]; + pseudo_bit_t _unused_0[64]; +}; +struct QIB_7220_SendDmaBufMask0 { + PSEUDO_BIT_STRUCT ( struct QIB_7220_SendDmaBufMask0_pb ); +}; + +#define QIB_7220_SendDmaStatus_offset 0x00000238UL +struct QIB_7220_SendDmaStatus_pb { + pseudo_bit_t SplFifoDescIndex[16]; + pseudo_bit_t SplFifoBufNum[8]; + pseudo_bit_t SplFifoFull[1]; + pseudo_bit_t SplFifoEmpty[1]; + pseudo_bit_t SplFifoDisarmed[1]; + pseudo_bit_t SplFifoReadyToGo[1]; + pseudo_bit_t ScbFetchDescFlag[1]; + pseudo_bit_t ScbEntryValid[1]; + pseudo_bit_t ScbEmpty[1]; + pseudo_bit_t ScbFull[1]; + pseudo_bit_t RpyTag_7_0[8]; + pseudo_bit_t RpyLowAddr_6_0[7]; + pseudo_bit_t ScbDescIndex_13_0[14]; + pseudo_bit_t InternalSDmaEnable[1]; + pseudo_bit_t AbortInProg[1]; + pseudo_bit_t ScoreBoardDrainInProg[1]; +}; +struct QIB_7220_SendDmaStatus { + PSEUDO_BIT_STRUCT ( struct QIB_7220_SendDmaStatus_pb ); +}; + +#define QIB_7220_SendBufErr0_offset 0x00000240UL +struct QIB_7220_SendBufErr0_pb { + pseudo_bit_t SendBufErr_63_0[0]; + pseudo_bit_t _unused_0[64]; +}; +struct QIB_7220_SendBufErr0 { + PSEUDO_BIT_STRUCT ( struct QIB_7220_SendBufErr0_pb ); +}; + +#define QIB_7220_REG_000258_offset 0x00000258UL + +#define QIB_7220_AvailUpdCount_offset 0x00000268UL +struct QIB_7220_AvailUpdCount_pb { + pseudo_bit_t AvailUpdCount[5]; + pseudo_bit_t _unused_0[59]; +}; +struct QIB_7220_AvailUpdCount { + PSEUDO_BIT_STRUCT ( struct QIB_7220_AvailUpdCount_pb ); +}; + +#define QIB_7220_RcvHdrAddr0_offset 0x00000270UL +struct QIB_7220_RcvHdrAddr0_pb { + pseudo_bit_t Reserved[2]; + pseudo_bit_t RcvHdrAddr0[38]; + pseudo_bit_t _unused_0[24]; +}; +struct QIB_7220_RcvHdrAddr0 { + PSEUDO_BIT_STRUCT ( struct QIB_7220_RcvHdrAddr0_pb ); +}; + +#define QIB_7220_REG_0002F8_offset 0x000002f8UL + +#define QIB_7220_RcvHdrTailAddr0_offset 0x00000300UL +struct QIB_7220_RcvHdrTailAddr0_pb { + pseudo_bit_t Reserved[2]; + pseudo_bit_t RcvHdrTailAddr0[38]; + pseudo_bit_t _unused_0[24]; +}; +struct QIB_7220_RcvHdrTailAddr0 { + PSEUDO_BIT_STRUCT ( struct QIB_7220_RcvHdrTailAddr0_pb ); +}; + +#define QIB_7220_REG_000388_offset 0x00000388UL + +#define QIB_7220_ibsd_epb_access_ctrl_offset 0x000003c0UL +struct QIB_7220_ibsd_epb_access_ctrl_pb { + pseudo_bit_t sw_ib_epb_req[1]; + pseudo_bit_t Reserved[7]; + pseudo_bit_t sw_ib_epb_req_granted[1]; + pseudo_bit_t _unused_0[55]; +}; +struct QIB_7220_ibsd_epb_access_ctrl { + PSEUDO_BIT_STRUCT ( struct QIB_7220_ibsd_epb_access_ctrl_pb ); +}; + +#define QIB_7220_ibsd_epb_transaction_reg_offset 0x000003c8UL +struct QIB_7220_ibsd_epb_transaction_reg_pb { + pseudo_bit_t ib_epb_data[8]; + pseudo_bit_t ib_epb_address[15]; + pseudo_bit_t Reserved2[1]; + pseudo_bit_t ib_epb_read_write[1]; + pseudo_bit_t ib_epb_cs[2]; + pseudo_bit_t Reserved1[1]; + pseudo_bit_t mem_data_parity[1]; + pseudo_bit_t Reserved[1]; + pseudo_bit_t ib_epb_req_error[1]; + pseudo_bit_t ib_epb_rdy[1]; + pseudo_bit_t _unused_0[32]; +}; +struct QIB_7220_ibsd_epb_transaction_reg { + PSEUDO_BIT_STRUCT ( struct QIB_7220_ibsd_epb_transaction_reg_pb ); +}; + +#define QIB_7220_REG_0003D0_offset 0x000003d0UL + +#define QIB_7220_XGXSCfg_offset 0x000003d8UL +struct QIB_7220_XGXSCfg_pb { + pseudo_bit_t tx_rx_reset[1]; + pseudo_bit_t Reserved2[1]; + pseudo_bit_t xcv_reset[1]; + pseudo_bit_t Reserved1[6]; + pseudo_bit_t link_sync_mask[10]; + pseudo_bit_t Reserved[44]; + pseudo_bit_t sel_link_down_for_fctrl_lane_sync_reset[1]; +}; +struct QIB_7220_XGXSCfg { + PSEUDO_BIT_STRUCT ( struct QIB_7220_XGXSCfg_pb ); +}; + +#define QIB_7220_IBSerDesCtrl_offset 0x000003e0UL +struct QIB_7220_IBSerDesCtrl_pb { + pseudo_bit_t ResetIB_uC_Core[1]; + pseudo_bit_t Reserved2[7]; + pseudo_bit_t NumSerDesRegsToWrForDDS[5]; + pseudo_bit_t NumSerDesRegsToWrForRXEQ[5]; + pseudo_bit_t Reserved1[14]; + pseudo_bit_t TXINV[1]; + pseudo_bit_t RXINV[1]; + pseudo_bit_t RXIDLE[1]; + pseudo_bit_t TWC[1]; + pseudo_bit_t TXOBPD[1]; + pseudo_bit_t PLLM[3]; + pseudo_bit_t PLLN[2]; + pseudo_bit_t CKSEL_uC[2]; + pseudo_bit_t INT_uC[1]; + pseudo_bit_t Reserved[19]; +}; +struct QIB_7220_IBSerDesCtrl { + PSEUDO_BIT_STRUCT ( struct QIB_7220_IBSerDesCtrl_pb ); +}; + +#define QIB_7220_EEPCtlStat_offset 0x000003e8UL +struct QIB_7220_EEPCtlStat_pb { + pseudo_bit_t EPAccEn[2]; + pseudo_bit_t EPReset[1]; + pseudo_bit_t ByteProg[1]; + pseudo_bit_t PageMode[1]; + pseudo_bit_t LstDatWr[1]; + pseudo_bit_t CmdWrErr[1]; + pseudo_bit_t Reserved[24]; + pseudo_bit_t CtlrStat[1]; + pseudo_bit_t _unused_0[32]; +}; +struct QIB_7220_EEPCtlStat { + PSEUDO_BIT_STRUCT ( struct QIB_7220_EEPCtlStat_pb ); +}; + +#define QIB_7220_EEPAddrCmd_offset 0x000003f0UL +struct QIB_7220_EEPAddrCmd_pb { + pseudo_bit_t EPAddr[24]; + pseudo_bit_t EPCmd[8]; + pseudo_bit_t _unused_0[32]; +}; +struct QIB_7220_EEPAddrCmd { + PSEUDO_BIT_STRUCT ( struct QIB_7220_EEPAddrCmd_pb ); +}; + +#define QIB_7220_EEPData_offset 0x000003f8UL + +#define QIB_7220_pciesd_epb_access_ctrl_offset 0x00000400UL +struct QIB_7220_pciesd_epb_access_ctrl_pb { + pseudo_bit_t sw_pcie_epb_req[1]; + pseudo_bit_t sw_pcieepb_star_en[2]; + pseudo_bit_t Reserved[5]; + pseudo_bit_t sw_pcie_epb_req_granted[1]; + pseudo_bit_t _unused_0[55]; +}; +struct QIB_7220_pciesd_epb_access_ctrl { + PSEUDO_BIT_STRUCT ( struct QIB_7220_pciesd_epb_access_ctrl_pb ); +}; + +#define QIB_7220_pciesd_epb_transaction_reg_offset 0x00000408UL +struct QIB_7220_pciesd_epb_transaction_reg_pb { + pseudo_bit_t pcie_epb_data[8]; + pseudo_bit_t pcie_epb_address[15]; + pseudo_bit_t Reserved1[1]; + pseudo_bit_t pcie_epb_read_write[1]; + pseudo_bit_t pcie_epb_cs[3]; + pseudo_bit_t mem_data_parity[1]; + pseudo_bit_t Reserved[1]; + pseudo_bit_t pcie_epb_req_error[1]; + pseudo_bit_t pcie_epb_rdy[1]; + pseudo_bit_t _unused_0[32]; +}; +struct QIB_7220_pciesd_epb_transaction_reg { + PSEUDO_BIT_STRUCT ( struct QIB_7220_pciesd_epb_transaction_reg_pb ); +}; + +#define QIB_7220_efuse_control_reg_offset 0x00000410UL +struct QIB_7220_efuse_control_reg_pb { + pseudo_bit_t start_op[1]; + pseudo_bit_t operation[1]; + pseudo_bit_t read_valid[1]; + pseudo_bit_t req_error[1]; + pseudo_bit_t Reserved[27]; + pseudo_bit_t rdy[1]; + pseudo_bit_t _unused_0[32]; +}; +struct QIB_7220_efuse_control_reg { + PSEUDO_BIT_STRUCT ( struct QIB_7220_efuse_control_reg_pb ); +}; + +#define QIB_7220_efuse_rddata0_reg_offset 0x00000418UL + +#define QIB_7220_procmon_register_offset 0x00000438UL +struct QIB_7220_procmon_register_pb { + pseudo_bit_t interval_time[12]; + pseudo_bit_t Reserved1[2]; + pseudo_bit_t clear_counter[1]; + pseudo_bit_t start_counter[1]; + pseudo_bit_t procmon_count[9]; + pseudo_bit_t Reserved[6]; + pseudo_bit_t procmon_count_valid[1]; + pseudo_bit_t _unused_0[32]; +}; +struct QIB_7220_procmon_register { + PSEUDO_BIT_STRUCT ( struct QIB_7220_procmon_register_pb ); +}; + +#define QIB_7220_PcieRbufTestReg0_offset 0x00000440UL + +#define QIB_7220_PcieRBufTestReg1_offset 0x00000448UL + +#define QIB_7220_SPC_JTAG_ACCESS_REG_offset 0x00000460UL +struct QIB_7220_SPC_JTAG_ACCESS_REG_pb { + pseudo_bit_t rdy[1]; + pseudo_bit_t tdo[1]; + pseudo_bit_t tdi[1]; + pseudo_bit_t opcode[2]; + pseudo_bit_t bist_en[5]; + pseudo_bit_t SPC_JTAG_ACCESS_EN[1]; + pseudo_bit_t _unused_0[53]; +}; +struct QIB_7220_SPC_JTAG_ACCESS_REG { + PSEUDO_BIT_STRUCT ( struct QIB_7220_SPC_JTAG_ACCESS_REG_pb ); +}; + +#define QIB_7220_LAControlReg_offset 0x00000468UL +struct QIB_7220_LAControlReg_pb { + pseudo_bit_t Finished[1]; + pseudo_bit_t Address[8]; + pseudo_bit_t Mode[2]; + pseudo_bit_t Delay[20]; + pseudo_bit_t Reserved[1]; + pseudo_bit_t _unused_0[32]; +}; +struct QIB_7220_LAControlReg { + PSEUDO_BIT_STRUCT ( struct QIB_7220_LAControlReg_pb ); +}; + +#define QIB_7220_GPIODebugSelReg_offset 0x00000470UL +struct QIB_7220_GPIODebugSelReg_pb { + pseudo_bit_t GPIOSourceSelDebug[16]; + pseudo_bit_t SelPulse[16]; + pseudo_bit_t _unused_0[32]; +}; +struct QIB_7220_GPIODebugSelReg { + PSEUDO_BIT_STRUCT ( struct QIB_7220_GPIODebugSelReg_pb ); +}; + +#define QIB_7220_DebugPortValueReg_offset 0x00000478UL + +#define QIB_7220_SendDmaBufUsed0_offset 0x00000480UL +struct QIB_7220_SendDmaBufUsed0_pb { + pseudo_bit_t BufUsed_63_0[0]; + pseudo_bit_t _unused_0[64]; +}; +struct QIB_7220_SendDmaBufUsed0 { + PSEUDO_BIT_STRUCT ( struct QIB_7220_SendDmaBufUsed0_pb ); +}; + +#define QIB_7220_SendDmaReqTagUsed_offset 0x00000498UL +struct QIB_7220_SendDmaReqTagUsed_pb { + pseudo_bit_t ReqTagUsed_7_0[8]; + pseudo_bit_t _unused_0[8]; + pseudo_bit_t Reserved[48]; + pseudo_bit_t _unused_1[8]; +}; +struct QIB_7220_SendDmaReqTagUsed { + PSEUDO_BIT_STRUCT ( struct QIB_7220_SendDmaReqTagUsed_pb ); +}; + +#define QIB_7220_efuse_pgm_data0_offset 0x000004a0UL + +#define QIB_7220_MEM_0004B0_offset 0x000004b0UL + +#define QIB_7220_SerDes_DDSRXEQ0_offset 0x00000500UL +struct QIB_7220_SerDes_DDSRXEQ0_pb { + pseudo_bit_t element_num[4]; + pseudo_bit_t reg_addr[6]; + pseudo_bit_t _unused_0[54]; +}; +struct QIB_7220_SerDes_DDSRXEQ0 { + PSEUDO_BIT_STRUCT ( struct QIB_7220_SerDes_DDSRXEQ0_pb ); +}; + +#define QIB_7220_MEM_0005F0_offset 0x000005f0UL + +#define QIB_7220_LAMemory_offset 0x00000600UL + +#define QIB_7220_MEM_0007F0_offset 0x000007f0UL + +#define QIB_7220_SendBufAvail0_offset 0x00001000UL +struct QIB_7220_SendBufAvail0_pb { + pseudo_bit_t SendBuf_31_0[0]; + pseudo_bit_t _unused_0[64]; +}; +struct QIB_7220_SendBufAvail0 { + PSEUDO_BIT_STRUCT ( struct QIB_7220_SendBufAvail0_pb ); +}; + +#define QIB_7220_MEM_001028_offset 0x00001028UL + +#define QIB_7220_LBIntCnt_offset 0x00013000UL + +#define QIB_7220_LBFlowStallCnt_offset 0x00013008UL + +#define QIB_7220_TxSDmaDescCnt_offset 0x00013010UL + +#define QIB_7220_TxUnsupVLErrCnt_offset 0x00013018UL + +#define QIB_7220_TxDataPktCnt_offset 0x00013020UL + +#define QIB_7220_TxFlowPktCnt_offset 0x00013028UL + +#define QIB_7220_TxDwordCnt_offset 0x00013030UL + +#define QIB_7220_TxLenErrCnt_offset 0x00013038UL + +#define QIB_7220_TxMaxMinLenErrCnt_offset 0x00013040UL + +#define QIB_7220_TxUnderrunCnt_offset 0x00013048UL + +#define QIB_7220_TxFlowStallCnt_offset 0x00013050UL + +#define QIB_7220_TxDroppedPktCnt_offset 0x00013058UL + +#define QIB_7220_RxDroppedPktCnt_offset 0x00013060UL + +#define QIB_7220_RxDataPktCnt_offset 0x00013068UL + +#define QIB_7220_RxFlowPktCnt_offset 0x00013070UL + +#define QIB_7220_RxDwordCnt_offset 0x00013078UL + +#define QIB_7220_RxLenErrCnt_offset 0x00013080UL + +#define QIB_7220_RxMaxMinLenErrCnt_offset 0x00013088UL + +#define QIB_7220_RxICRCErrCnt_offset 0x00013090UL + +#define QIB_7220_RxVCRCErrCnt_offset 0x00013098UL + +#define QIB_7220_RxFlowCtrlViolCnt_offset 0x000130a0UL + +#define QIB_7220_RxVersionErrCnt_offset 0x000130a8UL + +#define QIB_7220_RxLinkMalformCnt_offset 0x000130b0UL + +#define QIB_7220_RxEBPCnt_offset 0x000130b8UL + +#define QIB_7220_RxLPCRCErrCnt_offset 0x000130c0UL + +#define QIB_7220_RxBufOvflCnt_offset 0x000130c8UL + +#define QIB_7220_RxTIDFullErrCnt_offset 0x000130d0UL + +#define QIB_7220_RxTIDValidErrCnt_offset 0x000130d8UL + +#define QIB_7220_RxPKeyMismatchCnt_offset 0x000130e0UL + +#define QIB_7220_RxP0HdrEgrOvflCnt_offset 0x000130e8UL + +#define QIB_7220_IBStatusChangeCnt_offset 0x00013170UL + +#define QIB_7220_IBLinkErrRecoveryCnt_offset 0x00013178UL + +#define QIB_7220_IBLinkDownedCnt_offset 0x00013180UL + +#define QIB_7220_IBSymbolErrCnt_offset 0x00013188UL + +#define QIB_7220_RxVL15DroppedPktCnt_offset 0x00013190UL + +#define QIB_7220_RxOtherLocalPhyErrCnt_offset 0x00013198UL + +#define QIB_7220_PcieRetryBufDiagQwordCnt_offset 0x000131a0UL + +#define QIB_7220_ExcessBufferOvflCnt_offset 0x000131a8UL + +#define QIB_7220_LocalLinkIntegrityErrCnt_offset 0x000131b0UL + +#define QIB_7220_RxVlErrCnt_offset 0x000131b8UL + +#define QIB_7220_RxDlidFltrCnt_offset 0x000131c0UL + +#define QIB_7220_CNT_0131C8_offset 0x000131c8UL + +#define QIB_7220_PSStat_offset 0x00013200UL + +#define QIB_7220_PSStart_offset 0x00013208UL + +#define QIB_7220_PSInterval_offset 0x00013210UL + +#define QIB_7220_PSRcvDataCount_offset 0x00013218UL + +#define QIB_7220_PSRcvPktsCount_offset 0x00013220UL + +#define QIB_7220_PSXmitDataCount_offset 0x00013228UL + +#define QIB_7220_PSXmitPktsCount_offset 0x00013230UL + +#define QIB_7220_PSXmitWaitCount_offset 0x00013238UL + +#define QIB_7220_CNT_013240_offset 0x00013240UL + +#define QIB_7220_RcvEgrArray_offset 0x00014000UL + +#define QIB_7220_MEM_038000_offset 0x00038000UL + +#define QIB_7220_RcvTIDArray0_offset 0x00053000UL + +#define QIB_7220_PIOLaunchFIFO_offset 0x00064000UL + +#define QIB_7220_MEM_064480_offset 0x00064480UL + +#define QIB_7220_SendPIOpbcCache_offset 0x00064800UL + +#define QIB_7220_MEM_064C80_offset 0x00064c80UL + +#define QIB_7220_PreLaunchFIFO_offset 0x00065000UL + +#define QIB_7220_MEM_065080_offset 0x00065080UL + +#define QIB_7220_ScoreBoard_offset 0x00065400UL + +#define QIB_7220_MEM_065440_offset 0x00065440UL + +#define QIB_7220_DescriptorFIFO_offset 0x00065800UL + +#define QIB_7220_MEM_065880_offset 0x00065880UL + +#define QIB_7220_RcvBuf1_offset 0x00072000UL + +#define QIB_7220_MEM_074800_offset 0x00074800UL + +#define QIB_7220_RcvBuf2_offset 0x00075000UL + +#define QIB_7220_MEM_076400_offset 0x00076400UL + +#define QIB_7220_RcvFlags_offset 0x00077000UL + +#define QIB_7220_MEM_078400_offset 0x00078400UL + +#define QIB_7220_RcvLookupBuf1_offset 0x00079000UL + +#define QIB_7220_MEM_07A400_offset 0x0007a400UL + +#define QIB_7220_RcvDMADatBuf_offset 0x0007b000UL + +#define QIB_7220_RcvDMAHdrBuf_offset 0x0007b800UL + +#define QIB_7220_MiscRXEIntMem_offset 0x0007c000UL + +#define QIB_7220_MEM_07D400_offset 0x0007d400UL + +#define QIB_7220_PCIERcvBuf_offset 0x00080000UL + +#define QIB_7220_PCIERetryBuf_offset 0x00084000UL + +#define QIB_7220_PCIERcvBufRdToWrAddr_offset 0x00088000UL + +#define QIB_7220_PCIECplBuf_offset 0x00090000UL + +#define QIB_7220_IBSerDesMappTable_offset 0x00094000UL + +#define QIB_7220_MEM_095000_offset 0x00095000UL + +#define QIB_7220_SendBuf0_MA_offset 0x00100000UL + +#define QIB_7220_MEM_1A0000_offset 0x001a0000UL + +#define QIB_7220_RcvHdrTail0_offset 0x00200000UL + +#define QIB_7220_RcvHdrHead0_offset 0x00200008UL +struct QIB_7220_RcvHdrHead0_pb { + pseudo_bit_t RcvHeadPointer[32]; + pseudo_bit_t counter[16]; + pseudo_bit_t Reserved[16]; +}; +struct QIB_7220_RcvHdrHead0 { + PSEUDO_BIT_STRUCT ( struct QIB_7220_RcvHdrHead0_pb ); +}; + +#define QIB_7220_RcvEgrIndexTail0_offset 0x00200010UL + +#define QIB_7220_RcvEgrIndexHead0_offset 0x00200018UL + +#define QIB_7220_MEM_200020_offset 0x00200020UL + +#define QIB_7220_RcvHdrTail1_offset 0x00210000UL + +#define QIB_7220_RcvHdrHead1_offset 0x00210008UL +struct QIB_7220_RcvHdrHead1_pb { + pseudo_bit_t RcvHeadPointer[32]; + pseudo_bit_t counter[16]; + pseudo_bit_t Reserved[16]; +}; +struct QIB_7220_RcvHdrHead1 { + PSEUDO_BIT_STRUCT ( struct QIB_7220_RcvHdrHead1_pb ); +}; + +#define QIB_7220_RcvEgrIndexTail1_offset 0x00210010UL + +#define QIB_7220_RcvEgrIndexHead1_offset 0x00210018UL + +#define QIB_7220_MEM_210020_offset 0x00210020UL + +#define QIB_7220_RcvHdrTail2_offset 0x00220000UL + +#define QIB_7220_RcvHdrHead2_offset 0x00220008UL +struct QIB_7220_RcvHdrHead2_pb { + pseudo_bit_t RcvHeadPointer[32]; + pseudo_bit_t counter[16]; + pseudo_bit_t Reserved[16]; +}; +struct QIB_7220_RcvHdrHead2 { + PSEUDO_BIT_STRUCT ( struct QIB_7220_RcvHdrHead2_pb ); +}; + +#define QIB_7220_RcvEgrIndexTail2_offset 0x00220010UL + +#define QIB_7220_RcvEgrIndexHead2_offset 0x00220018UL + +#define QIB_7220_MEM_220020_offset 0x00220020UL + +#define QIB_7220_RcvHdrTail3_offset 0x00230000UL + +#define QIB_7220_RcvHdrHead3_offset 0x00230008UL +struct QIB_7220_RcvHdrHead3_pb { + pseudo_bit_t RcvHeadPointer[32]; + pseudo_bit_t counter[16]; + pseudo_bit_t Reserved[16]; +}; +struct QIB_7220_RcvHdrHead3 { + PSEUDO_BIT_STRUCT ( struct QIB_7220_RcvHdrHead3_pb ); +}; + +#define QIB_7220_RcvEgrIndexTail3_offset 0x00230010UL + +#define QIB_7220_RcvEgrIndexHead3_offset 0x00230018UL + +#define QIB_7220_MEM_230020_offset 0x00230020UL + +#define QIB_7220_RcvHdrTail4_offset 0x00240000UL + +#define QIB_7220_RcvHdrHead4_offset 0x00240008UL +struct QIB_7220_RcvHdrHead4_pb { + pseudo_bit_t RcvHeadPointer[32]; + pseudo_bit_t counter[16]; + pseudo_bit_t Reserved[16]; +}; +struct QIB_7220_RcvHdrHead4 { + PSEUDO_BIT_STRUCT ( struct QIB_7220_RcvHdrHead4_pb ); +}; + +#define QIB_7220_RcvEgrIndexTail4_offset 0x00240010UL + +#define QIB_7220_RcvEgrIndexHead4_offset 0x00240018UL + +#define QIB_7220_MEM_240020_offset 0x00240020UL + +#define QIB_7220_RcvHdrTail5_offset 0x00250000UL + +#define QIB_7220_RcvHdrHead5_offset 0x00250008UL +struct QIB_7220_RcvHdrHead5_pb { + pseudo_bit_t RcvHeadPointer[32]; + pseudo_bit_t counter[16]; + pseudo_bit_t Reserved[16]; +}; +struct QIB_7220_RcvHdrHead5 { + PSEUDO_BIT_STRUCT ( struct QIB_7220_RcvHdrHead5_pb ); +}; + +#define QIB_7220_RcvEgrIndexTail5_offset 0x00250010UL + +#define QIB_7220_RcvEgrIndexHead5_offset 0x00250018UL + +#define QIB_7220_MEM_250020_offset 0x00250020UL + +#define QIB_7220_RcvHdrTail6_offset 0x00260000UL + +#define QIB_7220_RcvHdrHead6_offset 0x00260008UL +struct QIB_7220_RcvHdrHead6_pb { + pseudo_bit_t RcvHeadPointer[32]; + pseudo_bit_t counter[16]; + pseudo_bit_t Reserved[16]; +}; +struct QIB_7220_RcvHdrHead6 { + PSEUDO_BIT_STRUCT ( struct QIB_7220_RcvHdrHead6_pb ); +}; + +#define QIB_7220_RcvEgrIndexTail6_offset 0x00260010UL + +#define QIB_7220_RcvEgrIndexHead6_offset 0x00260018UL + +#define QIB_7220_MEM_260020_offset 0x00260020UL + +#define QIB_7220_RcvHdrTail7_offset 0x00270000UL + +#define QIB_7220_RcvHdrHead7_offset 0x00270008UL +struct QIB_7220_RcvHdrHead7_pb { + pseudo_bit_t RcvHeadPointer[32]; + pseudo_bit_t counter[16]; + pseudo_bit_t Reserved[16]; +}; +struct QIB_7220_RcvHdrHead7 { + PSEUDO_BIT_STRUCT ( struct QIB_7220_RcvHdrHead7_pb ); +}; + +#define QIB_7220_RcvEgrIndexTail7_offset 0x00270010UL + +#define QIB_7220_RcvEgrIndexHead7_offset 0x00270018UL + +#define QIB_7220_MEM_270020_offset 0x00270020UL + +#define QIB_7220_RcvHdrTail8_offset 0x00280000UL + +#define QIB_7220_RcvHdrHead8_offset 0x00280008UL +struct QIB_7220_RcvHdrHead8_pb { + pseudo_bit_t RcvHeadPointer[32]; + pseudo_bit_t counter[16]; + pseudo_bit_t Reserved[16]; +}; +struct QIB_7220_RcvHdrHead8 { + PSEUDO_BIT_STRUCT ( struct QIB_7220_RcvHdrHead8_pb ); +}; + +#define QIB_7220_RcvEgrIndexTail8_offset 0x00280010UL + +#define QIB_7220_RcvEgrIndexHead8_offset 0x00280018UL + +#define QIB_7220_MEM_280020_offset 0x00280020UL + +#define QIB_7220_RcvHdrTail9_offset 0x00290000UL + +#define QIB_7220_RcvHdrHead9_offset 0x00290008UL +struct QIB_7220_RcvHdrHead9_pb { + pseudo_bit_t RcvHeadPointer[32]; + pseudo_bit_t counter[16]; + pseudo_bit_t Reserved[16]; +}; +struct QIB_7220_RcvHdrHead9 { + PSEUDO_BIT_STRUCT ( struct QIB_7220_RcvHdrHead9_pb ); +}; + +#define QIB_7220_RcvEgrIndexTail9_offset 0x00290010UL + +#define QIB_7220_RcvEgrIndexHead9_offset 0x00290018UL + +#define QIB_7220_MEM_290020_offset 0x00290020UL + +#define QIB_7220_RcvHdrTail10_offset 0x002a0000UL + +#define QIB_7220_RcvHdrHead10_offset 0x002a0008UL +struct QIB_7220_RcvHdrHead10_pb { + pseudo_bit_t RcvHeadPointer[32]; + pseudo_bit_t counter[16]; + pseudo_bit_t Reserved[16]; +}; +struct QIB_7220_RcvHdrHead10 { + PSEUDO_BIT_STRUCT ( struct QIB_7220_RcvHdrHead10_pb ); +}; + +#define QIB_7220_RcvEgrIndexTail10_offset 0x002a0010UL + +#define QIB_7220_RcvEgrIndexHead10_offset 0x002a0018UL + +#define QIB_7220_MEM_2A0020_offset 0x002a0020UL + +#define QIB_7220_RcvHdrTail11_offset 0x002b0000UL + +#define QIB_7220_RcvHdrHead11_offset 0x002b0008UL +struct QIB_7220_RcvHdrHead11_pb { + pseudo_bit_t RcvHeadPointer[32]; + pseudo_bit_t counter[16]; + pseudo_bit_t Reserved[16]; +}; +struct QIB_7220_RcvHdrHead11 { + PSEUDO_BIT_STRUCT ( struct QIB_7220_RcvHdrHead11_pb ); +}; + +#define QIB_7220_RcvEgrIndexTail11_offset 0x002b0010UL + +#define QIB_7220_RcvEgrIndexHead11_offset 0x002b0018UL + +#define QIB_7220_MEM_2B0020_offset 0x002b0020UL + +#define QIB_7220_RcvHdrTail12_offset 0x002c0000UL + +#define QIB_7220_RcvHdrHead12_offset 0x002c0008UL +struct QIB_7220_RcvHdrHead12_pb { + pseudo_bit_t RcvHeadPointer[32]; + pseudo_bit_t counter[16]; + pseudo_bit_t Reserved[16]; +}; +struct QIB_7220_RcvHdrHead12 { + PSEUDO_BIT_STRUCT ( struct QIB_7220_RcvHdrHead12_pb ); +}; + +#define QIB_7220_RcvEgrIndexTail12_offset 0x002c0010UL + +#define QIB_7220_RcvEgrIndexHead12_offset 0x002c0018UL + +#define QIB_7220_MEM_2C0020_offset 0x002c0020UL + +#define QIB_7220_RcvHdrTail13_offset 0x002d0000UL + +#define QIB_7220_RcvHdrHead13_offset 0x002d0008UL +struct QIB_7220_RcvHdrHead13_pb { + pseudo_bit_t RcvHeadPointer[32]; + pseudo_bit_t counter[16]; + pseudo_bit_t Reserved[16]; +}; +struct QIB_7220_RcvHdrHead13 { + PSEUDO_BIT_STRUCT ( struct QIB_7220_RcvHdrHead13_pb ); +}; + +#define QIB_7220_RcvEgrIndexTail13_offset 0x002d0010UL + +#define QIB_7220_RcvEgrIndexHead13_offset 0x002d0018UL + +#define QIB_7220_MEM_2D0020_offset 0x002d0020UL + +#define QIB_7220_RcvHdrTail14_offset 0x002e0000UL + +#define QIB_7220_RcvHdrHead14_offset 0x002e0008UL +struct QIB_7220_RcvHdrHead14_pb { + pseudo_bit_t RcvHeadPointer[32]; + pseudo_bit_t counter[16]; + pseudo_bit_t Reserved[16]; +}; +struct QIB_7220_RcvHdrHead14 { + PSEUDO_BIT_STRUCT ( struct QIB_7220_RcvHdrHead14_pb ); +}; + +#define QIB_7220_RcvEgrIndexTail14_offset 0x002e0010UL + +#define QIB_7220_RcvEgrIndexHead14_offset 0x002e0018UL + +#define QIB_7220_MEM_2E0020_offset 0x002e0020UL + +#define QIB_7220_RcvHdrTail15_offset 0x002f0000UL + +#define QIB_7220_RcvHdrHead15_offset 0x002f0008UL +struct QIB_7220_RcvHdrHead15_pb { + pseudo_bit_t RcvHeadPointer[32]; + pseudo_bit_t counter[16]; + pseudo_bit_t Reserved[16]; +}; +struct QIB_7220_RcvHdrHead15 { + PSEUDO_BIT_STRUCT ( struct QIB_7220_RcvHdrHead15_pb ); +}; + +#define QIB_7220_RcvEgrIndexTail15_offset 0x002f0010UL + +#define QIB_7220_RcvEgrIndexHead15_offset 0x002f0018UL + +#define QIB_7220_MEM_2F0020_offset 0x002f0020UL + +#define QIB_7220_RcvHdrTail16_offset 0x00300000UL + +#define QIB_7220_RcvHdrHead16_offset 0x00300008UL +struct QIB_7220_RcvHdrHead16_pb { + pseudo_bit_t RcvHeadPointer[32]; + pseudo_bit_t counter[16]; + pseudo_bit_t Reserved[16]; +}; +struct QIB_7220_RcvHdrHead16 { + PSEUDO_BIT_STRUCT ( struct QIB_7220_RcvHdrHead16_pb ); +}; + +#define QIB_7220_RcvEgrIndexTail16_offset 0x00300010UL + +#define QIB_7220_RcvEgrIndexHead16_offset 0x00300018UL + +#define QIB_7220_MEM_300020_offset 0x00300020UL + diff --git a/gpxe/src/drivers/infiniband/qib_genbits.pl b/gpxe/src/drivers/infiniband/qib_genbits.pl new file mode 100644 index 00000000..9eba4da5 --- /dev/null +++ b/gpxe/src/drivers/infiniband/qib_genbits.pl @@ -0,0 +1,95 @@ +#!/usr/bin/perl -w +# +# 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., 675 Mass Ave, Cambridge, MA 02139, USA. + +use strict; +use warnings; + +my $offsets = {}; +my $structures = {}; +my $structure = ""; + +while ( <> ) { + chomp; + if ( /^\#define (\S+)_OFFS (\S+)$/ ) { + $structure = $1; + $offsets->{$structure} = $2; + } elsif ( /^\#define ${structure}_(\S+)_LSB (\S+)$/ ) { + $structures->{$structure}->{$1}->{LSB} = $2; + } elsif ( /^\#define ${structure}_(\S+)_RMASK (\S+)$/ ) { + $structures->{$structure}->{$1}->{RMASK} = $2; + } elsif ( /^\s*$/ ) { + # Do nothing + } else { + print "$_\n"; + } +} + +my $data = [ map { { name => $_, offset => $offsets->{$_} }; } + sort { hex ( $offsets->{$a} ) <=> hex ( $offsets->{$b} ) } + keys %$offsets ]; + +foreach my $datum ( @$data ) { + next unless exists $structures->{$datum->{name}}; + $structure = $structures->{$datum->{name}}; + my $fields = [ map { { name => $_, lsb => $structure->{$_}->{LSB}, + rmask => $structure->{$_}->{RMASK} }; } + sort { hex ( $structure->{$a}->{LSB} ) <=> + hex ( $structure->{$b}->{LSB} ) } + keys %$structure ]; + $datum->{fields} = $fields; +} + +print "\n/* This file has been further processed by $0 */\n\n\n"; + +foreach my $datum ( @$data ) { + printf "#define %s_offset 0x%08xUL\n", + $datum->{name}, hex ( $datum->{offset} ); + if ( exists $datum->{fields} ) { + my $lsb = 0; + my $reserved_idx = 0; + printf "struct %s_pb {\n", $datum->{name}; + foreach my $field ( @{$datum->{fields}} ) { + my $pad_width = ( hex ( $field->{lsb} ) - $lsb ); + die "Inconsistent LSB/RMASK in $datum->{name}\n" if $pad_width < 0; + printf "\tpseudo_bit_t _unused_%u[%u];\n", $reserved_idx++, $pad_width + if $pad_width; + # Damn Perl can't cope with 64-bit hex constants + my $width = 0; + my $rmask = $field->{rmask}; + while ( $rmask =~ /^(0x.+)f$/i ) { + $width += 4; + $rmask = $1; + } + $rmask = hex ( $rmask ); + while ( $rmask ) { + $width++; + $rmask >>= 1; + } + printf "\tpseudo_bit_t %s[%u];\n", $field->{name}, $width; + $lsb += $width; + } + my $pad_width = ( 64 - $lsb ); + die "Inconsistent LSB/RMASK in $datum->{name}\n" if $pad_width < 0; + printf "\tpseudo_bit_t _unused_%u[%u];\n", $reserved_idx++, $pad_width + if $pad_width; + printf "};\n"; + printf "struct %s {\n\tPSEUDO_BIT_STRUCT ( struct %s_pb );\n};\n", + $datum->{name}, $datum->{name}; + } + print "\n"; +} diff --git a/gpxe/src/drivers/net/3c509.c b/gpxe/src/drivers/net/3c509.c index 8a15aff2..ecfdec55 100644 --- a/gpxe/src/drivers/net/3c509.c +++ b/gpxe/src/drivers/net/3c509.c @@ -8,7 +8,7 @@ #include <stdlib.h> #include <string.h> #include <errno.h> -#include <io.h> +#include <gpxe/io.h> #include <unistd.h> #include <gpxe/device.h> #include <gpxe/isa.h> diff --git a/gpxe/src/drivers/net/3c515.c b/gpxe/src/drivers/net/3c515.c index 02f03dc7..dcfe66ba 100644 --- a/gpxe/src/drivers/net/3c515.c +++ b/gpxe/src/drivers/net/3c515.c @@ -640,7 +640,7 @@ static int t515_probe ( struct nic *nic, struct isapnp_device *isapnp ) { } } - DBG ( "3c515 Resource configuration register 0x%lX, DCR 0x%hX.\n", + DBG ( "3c515 Resource configuration register 0x%X, DCR 0x%hX.\n", inl(nic->ioaddr + 0x2002), inw(nic->ioaddr + 0x2000) ); corkscrew_found_device(nic->ioaddr, nic->irqno, CORKSCREW_ID, options, nic); diff --git a/gpxe/src/drivers/net/3c595.c b/gpxe/src/drivers/net/3c595.c index 7138f936..198e12e7 100644 --- a/gpxe/src/drivers/net/3c595.c +++ b/gpxe/src/drivers/net/3c595.c @@ -363,7 +363,7 @@ vxgetlink(void) if (n > 0) { printf("/"); } - printf(conn_tab[k].name); + printf("%s", conn_tab[k].name ); n++; } } diff --git a/gpxe/src/drivers/net/3c90x.c b/gpxe/src/drivers/net/3c90x.c index 8158239d..a98e6628 100644 --- a/gpxe/src/drivers/net/3c90x.c +++ b/gpxe/src/drivers/net/3c90x.c @@ -497,7 +497,7 @@ a3c90x_transmit(struct nic *nic __unused, const char *d, unsigned int t, unsigned char status; unsigned i, retries; - tick_t ct; + unsigned long ct; for (retries=0; retries < XMIT_RETRIES ; retries++) { @@ -543,7 +543,7 @@ a3c90x_transmit(struct nic *nic __unused, const char *d, unsigned int t, ct = currticks(); while (!(inw(INF_3C90X.IOAddr + regCommandIntStatus_w)&0x0004) && - ct + 10*USECS_IN_MSEC < currticks()); + ct + 10*1000 < currticks()); ; if (!(inw(INF_3C90X.IOAddr + regCommandIntStatus_w)&0x0004)) diff --git a/gpxe/src/drivers/net/b44.c b/gpxe/src/drivers/net/b44.c new file mode 100644 index 00000000..4c9c8e6e --- /dev/null +++ b/gpxe/src/drivers/net/b44.c @@ -0,0 +1,949 @@ +/* + * Copyright (c) 2008 Stefan Hajnoczi <stefanha@gmail.com> + * Copyright (c) 2008 Pantelis Koukousoulas <pktoss@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 any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + * + * This driver is a port of the b44 linux driver version 1.01 + * + * Copyright (c) 2002 David S. Miller <davem@redhat.com> + * Copyright (c) Pekka Pietikainen <pp@ee.oulu.fi> + * Copyright (C) 2006 Broadcom Corporation. + * + * Some ssb bits copied from version 2.0 of the b44 driver + * Copyright (c) Michael Buesch + * + * Copyright (c) a lot of people too. Please respect their work. + */ + +#include <errno.h> +#include <assert.h> +#include <stdio.h> +#include <unistd.h> +#include <byteswap.h> +#include <gpxe/io.h> +#include <mii.h> +#include <gpxe/iobuf.h> +#include <gpxe/malloc.h> +#include <gpxe/pci.h> +#include <gpxe/netdevice.h> +#include <gpxe/ethernet.h> +#include <gpxe/if_ether.h> +#include <gpxe/memmap.h> +#include "b44.h" + + +static inline int ring_next(int index) +{ + /* B44_RING_SIZE is a power of 2 :) */ + return (index + 1) & (B44_RING_SIZE - 1); +} + + +/* Memory-mapped I/O wrappers */ + +static inline u32 br32(const struct b44_private *bp, u32 reg) +{ + return readl(bp->regs + reg); +} + + +static inline void bw32(const struct b44_private *bp, u32 reg, u32 val) +{ + writel(val, bp->regs + reg); +} + + +static inline void bflush(const struct b44_private *bp, u32 reg, u32 timeout) +{ + readl(bp->regs + reg); + udelay(timeout); +} + + +#define VIRT_TO_B44(addr) ( virt_to_bus(addr) + SB_PCI_DMA ) + + +/** + * Return non-zero if the installed RAM is within + * the limit given and zero if it is outside. + * Hopefully will be removed soon. + */ +int phys_ram_within_limit(u64 limit) +{ + struct memory_map memmap; + struct memory_region *highest = NULL; + get_memmap(&memmap); + + highest = &memmap.regions[memmap.count - 1]; + + return (highest->end < limit); +} + + +/** + * Ring cells waiting to be processed are between 'tx_cur' and 'pending' + * indexes in the ring. + */ +static u32 pending_tx_index(struct b44_private *bp) +{ + u32 pending = br32(bp, B44_DMATX_STAT); + pending &= DMATX_STAT_CDMASK; + + pending /= sizeof(struct dma_desc); + return pending & (B44_RING_SIZE - 1); +} + + +/** + * Ring cells waiting to be processed are between 'rx_cur' and 'pending' + * indexes in the ring. + */ +static u32 pending_rx_index(struct b44_private *bp) +{ + u32 pending = br32(bp, B44_DMARX_STAT); + pending &= DMARX_STAT_CDMASK; + + pending /= sizeof(struct dma_desc); + return pending & (B44_RING_SIZE - 1); +} + + +/** + * Wait until the given bit is set/cleared. + */ +static int b44_wait_bit(struct b44_private *bp, unsigned long reg, u32 bit, + unsigned long timeout, const int clear) +{ + unsigned long i; + + for (i = 0; i < timeout; i++) { + u32 val = br32(bp, reg); + + if (clear && !(val & bit)) + break; + + if (!clear && (val & bit)) + break; + + udelay(10); + } + if (i == timeout) { + return -ENODEV; + } + return 0; +} + + +/* + * Sonics Silicon Backplane support. SSB is a mini-bus interconnecting + * so-called IP Cores. One of those cores implements the Fast Ethernet + * functionality and another one the PCI engine. + * + * You need to switch to the core you want to talk to before actually + * sending commands. + * + * See: http://bcm-v4.sipsolutions.net/Backplane for (reverse-engineered) + * specs. + */ + +static inline u32 ssb_get_core_rev(struct b44_private *bp) +{ + return (br32(bp, B44_SBIDHIGH) & SBIDHIGH_RC_MASK); +} + + +static inline int ssb_is_core_up(struct b44_private *bp) +{ + return ((br32(bp, B44_SBTMSLOW) & (SSB_CORE_DOWN | SBTMSLOW_CLOCK)) + == SBTMSLOW_CLOCK); +} + + +static u32 ssb_pci_setup(struct b44_private *bp, u32 cores) +{ + u32 bar_orig, pci_rev, val; + + pci_read_config_dword(bp->pci, SSB_BAR0_WIN, &bar_orig); + pci_write_config_dword(bp->pci, SSB_BAR0_WIN, + BCM4400_PCI_CORE_ADDR); + pci_rev = ssb_get_core_rev(bp); + + val = br32(bp, B44_SBINTVEC); + val |= cores; + bw32(bp, B44_SBINTVEC, val); + + val = br32(bp, SSB_PCI_TRANS_2); + val |= SSB_PCI_PREF | SSB_PCI_BURST; + bw32(bp, SSB_PCI_TRANS_2, val); + + pci_write_config_dword(bp->pci, SSB_BAR0_WIN, bar_orig); + + return pci_rev; +} + + +static void ssb_core_disable(struct b44_private *bp) +{ + if (br32(bp, B44_SBTMSLOW) & SBTMSLOW_RESET) + return; + + bw32(bp, B44_SBTMSLOW, (SBTMSLOW_REJECT | SBTMSLOW_CLOCK)); + b44_wait_bit(bp, B44_SBTMSLOW, SBTMSLOW_REJECT, 100000, 0); + b44_wait_bit(bp, B44_SBTMSHIGH, SBTMSHIGH_BUSY, 100000, 1); + + bw32(bp, B44_SBTMSLOW, (SBTMSLOW_FGC | SBTMSLOW_CLOCK | + SSB_CORE_DOWN)); + bflush(bp, B44_SBTMSLOW, 1); + + bw32(bp, B44_SBTMSLOW, SSB_CORE_DOWN); + bflush(bp, B44_SBTMSLOW, 1); +} + + +static void ssb_core_reset(struct b44_private *bp) +{ + u32 val; + const u32 mask = (SBTMSLOW_CLOCK | SBTMSLOW_FGC | SBTMSLOW_RESET); + + ssb_core_disable(bp); + + bw32(bp, B44_SBTMSLOW, mask); + bflush(bp, B44_SBTMSLOW, 1); + + /* Clear SERR if set, this is a hw bug workaround. */ + if (br32(bp, B44_SBTMSHIGH) & SBTMSHIGH_SERR) + bw32(bp, B44_SBTMSHIGH, 0); + + val = br32(bp, B44_SBIMSTATE); + if (val & (SBIMSTATE_BAD)) { + bw32(bp, B44_SBIMSTATE, val & ~SBIMSTATE_BAD); + } + + bw32(bp, B44_SBTMSLOW, (SBTMSLOW_CLOCK | SBTMSLOW_FGC)); + bflush(bp, B44_SBTMSLOW, 1); + + bw32(bp, B44_SBTMSLOW, (SBTMSLOW_CLOCK)); + bflush(bp, B44_SBTMSLOW, 1); +} + + +/* + * Driver helper functions + */ + +/* + * Chip reset provides power to the b44 MAC & PCI cores, which + * is necessary for MAC register access. We only do a partial + * reset in case of transmit/receive errors (ISTAT_ERRORS) to + * avoid the chip being hung for an unnecessary long time in + * this case. + * + * Called-by: b44_close, b44_halt, b44_inithw(b44_open), b44_probe + */ +static void b44_chip_reset(struct b44_private *bp, int reset_kind) +{ + if (ssb_is_core_up(bp)) { + bw32(bp, B44_RCV_LAZY, 0); + + bw32(bp, B44_ENET_CTRL, ENET_CTRL_DISABLE); + + b44_wait_bit(bp, B44_ENET_CTRL, ENET_CTRL_DISABLE, 200, 1); + + bw32(bp, B44_DMATX_CTRL, 0); + + bp->tx_dirty = bp->tx_cur = 0; + + if (br32(bp, B44_DMARX_STAT) & DMARX_STAT_EMASK) + b44_wait_bit(bp, B44_DMARX_STAT, DMARX_STAT_SIDLE, + 100, 0); + + bw32(bp, B44_DMARX_CTRL, 0); + + bp->rx_cur = 0; + } else { + ssb_pci_setup(bp, SBINTVEC_ENET0); + } + + ssb_core_reset(bp); + + /* Don't enable PHY if we are only doing a partial reset. */ + if (reset_kind == B44_CHIP_RESET_PARTIAL) + return; + + /* Make PHY accessible. */ + bw32(bp, B44_MDIO_CTRL, + (MDIO_CTRL_PREAMBLE | (0x0d & MDIO_CTRL_MAXF_MASK))); + bflush(bp, B44_MDIO_CTRL, 1); + + /* Enable internal or external PHY */ + if (!(br32(bp, B44_DEVCTRL) & DEVCTRL_IPP)) { + bw32(bp, B44_ENET_CTRL, ENET_CTRL_EPSEL); + bflush(bp, B44_ENET_CTRL, 1); + } else { + u32 val = br32(bp, B44_DEVCTRL); + if (val & DEVCTRL_EPR) { + bw32(bp, B44_DEVCTRL, (val & ~DEVCTRL_EPR)); + bflush(bp, B44_DEVCTRL, 100); + } + } +} + + +/** + * called by b44_poll in the error path + */ +static void b44_halt(struct b44_private *bp) +{ + /* disable ints */ + bw32(bp, B44_IMASK, 0); + bflush(bp, B44_IMASK, 1); + + DBG("b44: powering down PHY\n"); + bw32(bp, B44_MAC_CTRL, MAC_CTRL_PHY_PDOWN); + + /* + * Now reset the chip, but without enabling + * the MAC&PHY part of it. + * This has to be done _after_ we shut down the PHY + */ + b44_chip_reset(bp, B44_CHIP_RESET_PARTIAL); +} + + + +/* + * Called at device open time to get the chip ready for + * packet processing. + * + * Called-by: b44_open + */ +static void b44_init_hw(struct b44_private *bp, int reset_kind) +{ + u32 val; +#define CTRL_MASK (DMARX_CTRL_ENABLE | (RX_PKT_OFFSET << DMARX_CTRL_ROSHIFT)) + + b44_chip_reset(bp, B44_CHIP_RESET_FULL); + if (reset_kind == B44_FULL_RESET) { + b44_phy_reset(bp); + } + + /* Enable CRC32, set proper LED modes and power on PHY */ + bw32(bp, B44_MAC_CTRL, MAC_CTRL_CRC32_ENAB | MAC_CTRL_PHY_LEDCTRL); + bw32(bp, B44_RCV_LAZY, (1 << RCV_LAZY_FC_SHIFT)); + + /* This sets the MAC address too. */ + b44_set_rx_mode(bp->netdev); + + /* MTU + eth header + possible VLAN tag + struct rx_header */ + bw32(bp, B44_RXMAXLEN, B44_MAX_MTU + ETH_HLEN + 8 + RX_HEADER_LEN); + bw32(bp, B44_TXMAXLEN, B44_MAX_MTU + ETH_HLEN + 8 + RX_HEADER_LEN); + + bw32(bp, B44_TX_HIWMARK, TX_HIWMARK_DEFLT); + if (reset_kind == B44_PARTIAL_RESET) { + bw32(bp, B44_DMARX_CTRL, CTRL_MASK); + } else { + bw32(bp, B44_DMATX_CTRL, DMATX_CTRL_ENABLE); + bw32(bp, B44_DMATX_ADDR, VIRT_TO_B44(bp->tx)); + + bw32(bp, B44_DMARX_CTRL, CTRL_MASK); + bw32(bp, B44_DMARX_ADDR, VIRT_TO_B44(bp->rx)); + bw32(bp, B44_DMARX_PTR, B44_RX_RING_LEN_BYTES); + + bw32(bp, B44_MIB_CTRL, MIB_CTRL_CLR_ON_READ); + } + + val = br32(bp, B44_ENET_CTRL); + bw32(bp, B44_ENET_CTRL, (val | ENET_CTRL_ENABLE)); +#undef CTRL_MASK +} + + +/*** Management of ring descriptors ***/ + + +static void b44_populate_rx_descriptor(struct b44_private *bp, u32 idx) +{ + struct rx_header *rh; + u32 ctrl, addr; + + rh = bp->rx_iobuf[idx]->data; + rh->len = 0; + rh->flags = 0; + ctrl = DESC_CTRL_LEN & (RX_PKT_BUF_SZ - RX_PKT_OFFSET); + if (idx == B44_RING_LAST) { + ctrl |= DESC_CTRL_EOT; + } + addr = VIRT_TO_B44(bp->rx_iobuf[idx]->data); + + bp->rx[idx].ctrl = cpu_to_le32(ctrl); + bp->rx[idx].addr = cpu_to_le32(addr); + bw32(bp, B44_DMARX_PTR, idx * sizeof(struct dma_desc)); +} + + +/* + * Refill RX ring descriptors with buffers. This is needed + * because during rx we are passing ownership of descriptor + * buffers to the network stack. + */ +static void b44_rx_refill(struct b44_private *bp, u32 pending) +{ + u32 i; + + // skip pending + for (i = pending + 1; i != bp->rx_cur; i = ring_next(i)) { + if (bp->rx_iobuf[i] != NULL) + continue; + + bp->rx_iobuf[i] = alloc_iob(RX_PKT_BUF_SZ); + if (!bp->rx_iobuf[i]) { + DBG("Refill rx ring failed!!\n"); + break; + } + + b44_populate_rx_descriptor(bp, i); + } +} + + +static void b44_free_rx_ring(struct b44_private *bp) +{ + u32 i; + + if (bp->rx) { + for (i = 0; i < B44_RING_SIZE; i++) { + free_iob(bp->rx_iobuf[i]); + bp->rx_iobuf[i] = NULL; + } + free_dma(bp->rx, B44_RX_RING_LEN_BYTES); + bp->rx = NULL; + } +} + + +static int b44_init_rx_ring(struct b44_private *bp) +{ + b44_free_rx_ring(bp); + + bp->rx = malloc_dma(B44_RX_RING_LEN_BYTES, B44_DMA_ALIGNMENT); + if (!bp->rx) + return -ENOMEM; + + memset(bp->rx_iobuf, 0, sizeof(bp->rx_iobuf)); + + bp->rx_iobuf[0] = alloc_iob(RX_PKT_BUF_SZ); + b44_populate_rx_descriptor(bp, 0); + b44_rx_refill(bp, 0); + + DBG("Init RX rings: rx=0x%08lx\n", VIRT_TO_B44(bp->rx)); + return 0; +} + + +static void b44_free_tx_ring(struct b44_private *bp) +{ + if (bp->tx) { + free_dma(bp->tx, B44_TX_RING_LEN_BYTES); + bp->tx = NULL; + } +} + + +static int b44_init_tx_ring(struct b44_private *bp) +{ + b44_free_tx_ring(bp); + + bp->tx = malloc_dma(B44_TX_RING_LEN_BYTES, B44_DMA_ALIGNMENT); + if (!bp->tx) + return -ENOMEM; + + memset(bp->tx, 0, B44_TX_RING_LEN_BYTES); + memset(bp->tx_iobuf, 0, sizeof(bp->tx_iobuf)); + + DBG("Init TX rings: tx=0x%08lx\n", VIRT_TO_B44(bp->tx)); + return 0; +} + + +/*** Interaction with the PHY ***/ + + +static int b44_phy_read(struct b44_private *bp, int reg, u32 * val) +{ + int err; + + u32 arg1 = (MDIO_OP_READ << MDIO_DATA_OP_SHIFT); + u32 arg2 = (bp->phy_addr << MDIO_DATA_PMD_SHIFT); + u32 arg3 = (reg << MDIO_DATA_RA_SHIFT); + u32 arg4 = (MDIO_TA_VALID << MDIO_DATA_TA_SHIFT); + u32 argv = arg1 | arg2 | arg3 | arg4; + + bw32(bp, B44_EMAC_ISTAT, EMAC_INT_MII); + bw32(bp, B44_MDIO_DATA, (MDIO_DATA_SB_START | argv)); + err = b44_wait_bit(bp, B44_EMAC_ISTAT, EMAC_INT_MII, 100, 0); + *val = br32(bp, B44_MDIO_DATA) & MDIO_DATA_DATA; + + return err; +} + + +static int b44_phy_write(struct b44_private *bp, int reg, u32 val) +{ + u32 arg1 = (MDIO_OP_WRITE << MDIO_DATA_OP_SHIFT); + u32 arg2 = (bp->phy_addr << MDIO_DATA_PMD_SHIFT); + u32 arg3 = (reg << MDIO_DATA_RA_SHIFT); + u32 arg4 = (MDIO_TA_VALID << MDIO_DATA_TA_SHIFT); + u32 arg5 = (val & MDIO_DATA_DATA); + u32 argv = arg1 | arg2 | arg3 | arg4 | arg5; + + + bw32(bp, B44_EMAC_ISTAT, EMAC_INT_MII); + bw32(bp, B44_MDIO_DATA, (MDIO_DATA_SB_START | argv)); + return b44_wait_bit(bp, B44_EMAC_ISTAT, EMAC_INT_MII, 100, 0); +} + + +static int b44_phy_reset(struct b44_private *bp) +{ + u32 val; + int err; + + err = b44_phy_write(bp, MII_BMCR, BMCR_RESET); + if (err) + return err; + + udelay(100); + err = b44_phy_read(bp, MII_BMCR, &val); + if (!err) { + if (val & BMCR_RESET) { + return -ENODEV; + } + } + + return 0; +} + + +/* + * The BCM44xx CAM (Content Addressable Memory) stores the MAC + * and PHY address. + */ +static void b44_cam_write(struct b44_private *bp, unsigned char *data, + int index) +{ + u32 val; + + val = ((u32) data[2]) << 24; + val |= ((u32) data[3]) << 16; + val |= ((u32) data[4]) << 8; + val |= ((u32) data[5]) << 0; + bw32(bp, B44_CAM_DATA_LO, val); + + + val = (CAM_DATA_HI_VALID | + (((u32) data[0]) << 8) | (((u32) data[1]) << 0)); + + bw32(bp, B44_CAM_DATA_HI, val); + + val = CAM_CTRL_WRITE | (index << CAM_CTRL_INDEX_SHIFT); + bw32(bp, B44_CAM_CTRL, val); + + b44_wait_bit(bp, B44_CAM_CTRL, CAM_CTRL_BUSY, 100, 1); +} + + +static void b44_set_mac_addr(struct b44_private *bp) +{ + u32 val; + bw32(bp, B44_CAM_CTRL, 0); + b44_cam_write(bp, bp->netdev->ll_addr, 0); + val = br32(bp, B44_CAM_CTRL); + bw32(bp, B44_CAM_CTRL, val | CAM_CTRL_ENABLE); +} + + +/* Read 128-bytes of EEPROM. */ +static void b44_read_eeprom(struct b44_private *bp, u8 * data) +{ + long i; + u16 *ptr = (u16 *) data; + + for (i = 0; i < 128; i += 2) + ptr[i / 2] = cpu_to_le16(readw(bp->regs + 4096 + i)); +} + + +static void b44_load_mac_and_phy_addr(struct b44_private *bp) +{ + u8 eeprom[128]; + + /* Load MAC address, note byteswapping */ + b44_read_eeprom(bp, &eeprom[0]); + bp->netdev->ll_addr[0] = eeprom[79]; + bp->netdev->ll_addr[1] = eeprom[78]; + bp->netdev->ll_addr[2] = eeprom[81]; + bp->netdev->ll_addr[3] = eeprom[80]; + bp->netdev->ll_addr[4] = eeprom[83]; + bp->netdev->ll_addr[5] = eeprom[82]; + + /* Load PHY address */ + bp->phy_addr = eeprom[90] & 0x1f; +} + + +static void b44_set_rx_mode(struct net_device *netdev) +{ + struct b44_private *bp = netdev_priv(netdev); + unsigned char zero[6] = { 0, 0, 0, 0, 0, 0 }; + u32 val; + int i; + + val = br32(bp, B44_RXCONFIG); + val &= ~RXCONFIG_PROMISC; + val |= RXCONFIG_ALLMULTI; + + b44_set_mac_addr(bp); + + for (i = 1; i < 64; i++) + b44_cam_write(bp, zero, i); + + bw32(bp, B44_RXCONFIG, val); + val = br32(bp, B44_CAM_CTRL); + bw32(bp, B44_CAM_CTRL, val | CAM_CTRL_ENABLE); +} + + +/*** Implementation of gPXE driver callbacks ***/ + +/** + * Probe device + * + * @v pci PCI device + * @v id Matching entry in ID table + * @ret rc Return status code + */ +static int b44_probe(struct pci_device *pci, const struct pci_device_id *id) +{ + struct net_device *netdev; + struct b44_private *bp; + int rc; + + /* + * Bail out if more than 1GB of physical RAM is installed. + * This limitation will be removed later when dma mapping + * is merged into mainline. + */ + if (!phys_ram_within_limit(B44_30BIT_DMA_MASK)) { + DBG("Sorry, this version of the driver does not\n" + "support systems with more than 1GB of RAM.\n"); + return -ENOMEM; + } + + /* Set up netdev */ + netdev = alloc_etherdev(sizeof(*bp)); + if (!netdev) + return -ENOMEM; + + netdev_init(netdev, &b44_operations); + pci_set_drvdata(pci, netdev); + netdev->dev = &pci->dev; + + /* Set up private data */ + bp = netdev_priv(netdev); + memset(bp, 0, sizeof(*bp)); + bp->netdev = netdev; + bp->pci = pci; + + /* Map device registers */ + bp->regs = ioremap(pci->membase, B44_REGS_SIZE); + if (!bp->regs) { + netdev_put(netdev); + return -ENOMEM; + } + + /* Enable PCI bus mastering */ + adjust_pci_device(pci); + + b44_load_mac_and_phy_addr(bp); + + /* Link management currently not implemented */ + netdev_link_up(netdev); + + rc = register_netdev(netdev); + if (rc != 0) { + iounmap(bp->regs); + netdev_put(netdev); + return rc; + } + + b44_chip_reset(bp, B44_CHIP_RESET_FULL); + + DBG("b44 %s (%04x:%04x) regs=%p MAC=%s\n", id->name, id->vendor, + id->device, bp->regs, eth_ntoa(netdev->ll_addr)); + + return 0; +} + + +/** + * Remove device + * + * @v pci PCI device + */ +static void b44_remove(struct pci_device *pci) +{ + struct net_device *netdev = pci_get_drvdata(pci); + struct b44_private *bp = netdev_priv(netdev); + + ssb_core_disable(bp); + unregister_netdev(netdev); + iounmap(bp->regs); + netdev_nullify(netdev); + netdev_put(netdev); +} + + +/** Enable or disable interrupts + * + * @v netdev Network device + * @v enable Interrupts should be enabled + */ +static void b44_irq(struct net_device *netdev, int enable) +{ + struct b44_private *bp = netdev_priv(netdev); + + /* Interrupt mask specifies which events generate interrupts */ + bw32(bp, B44_IMASK, enable ? IMASK_DEF : IMASK_DISABLE); +} + + +/** Open network device + * + * @v netdev Network device + * @ret rc Return status code + */ +static int b44_open(struct net_device *netdev) +{ + struct b44_private *bp = netdev_priv(netdev); + int rc; + + rc = b44_init_tx_ring(bp); + if (rc != 0) + return rc; + + rc = b44_init_rx_ring(bp); + if (rc != 0) + return rc; + + b44_init_hw(bp, B44_FULL_RESET); + + /* Disable interrupts */ + b44_irq(netdev, 0); + + return 0; +} + + +/** Close network device + * + * @v netdev Network device + */ +static void b44_close(struct net_device *netdev) +{ + struct b44_private *bp = netdev_priv(netdev); + + b44_chip_reset(bp, B44_FULL_RESET); + b44_free_tx_ring(bp); + b44_free_rx_ring(bp); +} + + +/** Transmit packet + * + * @v netdev Network device + * @v iobuf I/O buffer + * @ret rc Return status code + */ +static int b44_transmit(struct net_device *netdev, struct io_buffer *iobuf) +{ + struct b44_private *bp = netdev_priv(netdev); + u32 cur = bp->tx_cur; + u32 ctrl; + + /* Check for TX ring overflow */ + if (bp->tx[cur].ctrl) { + DBG("tx overflow\n"); + return -ENOBUFS; + } + + /* Will call netdev_tx_complete() on the iobuf later */ + bp->tx_iobuf[cur] = iobuf; + + /* Set up TX descriptor */ + ctrl = (iob_len(iobuf) & DESC_CTRL_LEN) | + DESC_CTRL_IOC | DESC_CTRL_SOF | DESC_CTRL_EOF; + + if (cur == B44_RING_LAST) + ctrl |= DESC_CTRL_EOT; + + bp->tx[cur].ctrl = cpu_to_le32(ctrl); + bp->tx[cur].addr = cpu_to_le32(VIRT_TO_B44(iobuf->data)); + + /* Update next available descriptor index */ + cur = ring_next(cur); + bp->tx_cur = cur; + wmb(); + + /* Tell card that a new TX descriptor is ready */ + bw32(bp, B44_DMATX_PTR, cur * sizeof(struct dma_desc)); + return 0; +} + + +/** Recycles sent TX descriptors and notifies network stack + * + * @v bp Driver state + */ +static void b44_tx_complete(struct b44_private *bp) +{ + u32 cur, i; + + cur = pending_tx_index(bp); + + for (i = bp->tx_dirty; i != cur; i = ring_next(i)) { + /* Free finished frame */ + netdev_tx_complete(bp->netdev, bp->tx_iobuf[i]); + bp->tx_iobuf[i] = NULL; + + /* Clear TX descriptor */ + bp->tx[i].ctrl = 0; + bp->tx[i].addr = 0; + } + bp->tx_dirty = cur; +} + + +static void b44_process_rx_packets(struct b44_private *bp) +{ + struct io_buffer *iob; /* received data */ + struct rx_header *rh; + u32 pending, i; + u16 len; + + pending = pending_rx_index(bp); + + for (i = bp->rx_cur; i != pending; i = ring_next(i)) { + iob = bp->rx_iobuf[i]; + if (iob == NULL) + break; + + rh = iob->data; + len = le16_to_cpu(rh->len); + + /* + * Guard against incompletely written RX descriptors. + * Without this, things can get really slow! + */ + if (len == 0) + break; + + /* Discard CRC that is generated by the card */ + len -= 4; + + /* Check for invalid packets and errors */ + if (len > RX_PKT_BUF_SZ - RX_PKT_OFFSET || + (rh->flags & cpu_to_le16(RX_FLAG_ERRORS))) { + DBG("rx error len=%d flags=%04x\n", len, + cpu_to_le16(rh->flags)); + rh->len = 0; + rh->flags = 0; + netdev_rx_err(bp->netdev, iob, -EINVAL); + continue; + } + + /* Clear RX descriptor */ + rh->len = 0; + rh->flags = 0; + bp->rx_iobuf[i] = NULL; + + /* Hand off the IO buffer to the network stack */ + iob_reserve(iob, RX_PKT_OFFSET); + iob_put(iob, len); + netdev_rx(bp->netdev, iob); + } + bp->rx_cur = i; + b44_rx_refill(bp, pending_rx_index(bp)); +} + + +/** Poll for completed and received packets + * + * @v netdev Network device + */ +static void b44_poll(struct net_device *netdev) +{ + struct b44_private *bp = netdev_priv(netdev); + u32 istat; + + /* Interrupt status */ + istat = br32(bp, B44_ISTAT); + istat &= IMASK_DEF; /* only the events we care about */ + + if (!istat) + return; + if (istat & ISTAT_TX) + b44_tx_complete(bp); + if (istat & ISTAT_RX) + b44_process_rx_packets(bp); + if (istat & ISTAT_ERRORS) { + DBG("b44 error istat=0x%08x\n", istat); + + /* Reset B44 core partially to avoid long waits */ + b44_irq(bp->netdev, 0); + b44_halt(bp); + b44_init_tx_ring(bp); + b44_init_rx_ring(bp); + b44_init_hw(bp, B44_FULL_RESET_SKIP_PHY); + } + + /* Acknowledge interrupt */ + bw32(bp, B44_ISTAT, 0); + bflush(bp, B44_ISTAT, 1); +} + + +static struct net_device_operations b44_operations = { + .open = b44_open, + .close = b44_close, + .transmit = b44_transmit, + .poll = b44_poll, + .irq = b44_irq, +}; + + +static struct pci_device_id b44_nics[] = { + PCI_ROM(0x14e4, 0x4401, "BCM4401", "BCM4401"), + PCI_ROM(0x14e4, 0x170c, "BCM4401-B0", "BCM4401-B0"), + PCI_ROM(0x14e4, 0x4402, "BCM4401-B1", "BCM4401-B1"), +}; + + +struct pci_driver b44_driver __pci_driver = { + .ids = b44_nics, + .id_count = sizeof b44_nics / sizeof b44_nics[0], + .probe = b44_probe, + .remove = b44_remove, +}; diff --git a/gpxe/src/drivers/net/b44.h b/gpxe/src/drivers/net/b44.h new file mode 100644 index 00000000..fb36757f --- /dev/null +++ b/gpxe/src/drivers/net/b44.h @@ -0,0 +1,467 @@ +/* + * Copyright (c) 2008 Stefan Hajnoczi <stefanha@gmail.com> + * Copyright (c) 2008 Pantelis Koukousoulas <pktoss@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 any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + * + * This driver is a port of the b44 linux driver version 1.01 + * + * Copyright (c) 2002 David S. Miller <davem@redhat.com> + * Copyright (c) Pekka Pietikainen <pp@ee.oulu.fi> + * Copyright (C) 2006 Broadcom Corporation. + * + * Some ssb bits copied from version 2.0 of the b44 driver + * Copyright (c) Michael Buesch + * + * Copyright (c) a lot of people too. Please respect their work. + */ +#ifndef _B44_H +#define _B44_H + +/* BCM44xx Register layout */ +#define B44_DEVCTRL 0x0000UL /* Device Control */ +#define DEVCTRL_MPM 0x00000040 /* MP PME Enable (B0 only) */ +#define DEVCTRL_PFE 0x00000080 /* Pattern Filtering Enable */ +#define DEVCTRL_IPP 0x00000400 /* Internal EPHY Present */ +#define DEVCTRL_EPR 0x00008000 /* EPHY Reset */ +#define DEVCTRL_PME 0x00001000 /* PHY Mode Enable */ +#define DEVCTRL_PMCE 0x00002000 /* PHY Mode Clocks Enable */ +#define DEVCTRL_PADDR 0x0007c000 /* PHY Address */ +#define DEVCTRL_PADDR_SHIFT 18 +#define B44_BIST_STAT 0x000CUL /* Built-In Self-Test Status */ +#define B44_WKUP_LEN 0x0010UL /* Wakeup Length */ +#define WKUP_LEN_P0_MASK 0x0000007f /* Pattern 0 */ +#define WKUP_LEN_D0 0x00000080 +#define WKUP_LEN_P1_MASK 0x00007f00 /* Pattern 1 */ +#define WKUP_LEN_P1_SHIFT 8 +#define WKUP_LEN_D1 0x00008000 +#define WKUP_LEN_P2_MASK 0x007f0000 /* Pattern 2 */ +#define WKUP_LEN_P2_SHIFT 16 +#define WKUP_LEN_D2 0x00000000 +#define WKUP_LEN_P3_MASK 0x7f000000 /* Pattern 3 */ +#define WKUP_LEN_P3_SHIFT 24 +#define WKUP_LEN_D3 0x80000000 +#define WKUP_LEN_DISABLE 0x80808080 +#define WKUP_LEN_ENABLE_TWO 0x80800000 +#define WKUP_LEN_ENABLE_THREE 0x80000000 +#define B44_ISTAT 0x0020UL /* Interrupt Status */ +#define ISTAT_LS 0x00000020 /* Link Change (B0 only) */ +#define ISTAT_PME 0x00000040 /* Power Management Event */ +#define ISTAT_TO 0x00000080 /* General Purpose Timeout */ +#define ISTAT_DSCE 0x00000400 /* Descriptor Error */ +#define ISTAT_DATAE 0x00000800 /* Data Error */ +#define ISTAT_DPE 0x00001000 /* Descr. Protocol Error */ +#define ISTAT_RDU 0x00002000 /* Receive Descr. Underflow */ +#define ISTAT_RFO 0x00004000 /* Receive FIFO Overflow */ +#define ISTAT_TFU 0x00008000 /* Transmit FIFO Underflow */ +#define ISTAT_RX 0x00010000 /* RX Interrupt */ +#define ISTAT_TX 0x01000000 /* TX Interrupt */ +#define ISTAT_EMAC 0x04000000 /* EMAC Interrupt */ +#define ISTAT_MII_WRITE 0x08000000 /* MII Write Interrupt */ +#define ISTAT_MII_READ 0x10000000 /* MII Read Interrupt */ +#define ISTAT_ERRORS (ISTAT_DSCE|ISTAT_DATAE|ISTAT_DPE|\ + ISTAT_RDU|ISTAT_RFO|ISTAT_TFU) +#define B44_IMASK 0x0024UL /* Interrupt Mask */ +#define IMASK_DEF (ISTAT_ERRORS | ISTAT_RX | ISTAT_TX) +#define IMASK_DISABLE 0 +#define B44_GPTIMER 0x0028UL /* General Purpose Timer */ +#define B44_ADDR_LO 0x0088UL /* ENET Address Lo (B0 only) */ +#define B44_ADDR_HI 0x008CUL /* ENET Address Hi (B0 only) */ +#define B44_FILT_ADDR 0x0090UL /* ENET Filter Address */ +#define B44_FILT_DATA 0x0094UL /* ENET Filter Data */ +#define B44_TXBURST 0x00A0UL /* TX Max Burst Length */ +#define B44_RXBURST 0x00A4UL /* RX Max Burst Length */ +#define B44_MAC_CTRL 0x00A8UL /* MAC Control */ +#define MAC_CTRL_CRC32_ENAB 0x00000001 /* CRC32 Generation Enable */ +#define MAC_CTRL_PHY_PDOWN 0x00000004 /* Onchip EPHY Powerdown */ +#define MAC_CTRL_PHY_EDET 0x00000008 /* Onchip EPHY Energy Detected*/ +#define MAC_CTRL_PHY_LEDCTRL 0x000000e0 /* Onchip EPHY LED Control */ +#define MAC_CTRL_PHY_LEDCTRL_SHIFT 5 +#define B44_MAC_FLOW 0x00ACUL /* MAC Flow Control */ +#define MAC_FLOW_RX_HI_WATER 0x000000ff /* Receive FIFO HI Water Mark */ +#define MAC_FLOW_PAUSE_ENAB 0x00008000 /* Enbl Pause Frm Generation */ +#define B44_RCV_LAZY 0x0100UL /* Lazy Interrupt Control */ +#define RCV_LAZY_TO_MASK 0x00ffffff /* Timeout */ +#define RCV_LAZY_FC_MASK 0xff000000 /* Frame Count */ +#define RCV_LAZY_FC_SHIFT 24 +#define B44_DMATX_CTRL 0x0200UL /* DMA TX Control */ +#define DMATX_CTRL_ENABLE 0x00000001 /* Enable */ +#define DMATX_CTRL_SUSPEND 0x00000002 /* Suepend Request */ +#define DMATX_CTRL_LPBACK 0x00000004 /* Loopback Enable */ +#define DMATX_CTRL_FAIRPRIOR 0x00000008 /* Fair Priority */ +#define DMATX_CTRL_FLUSH 0x00000010 /* Flush Request */ +#define B44_DMATX_ADDR 0x0204UL /* DMA TX Descriptor Ring Addr */ +#define B44_DMATX_PTR 0x0208UL /* DMA TX Last Posted Desc. */ +#define B44_DMATX_STAT 0x020CUL /* DMA TX Cur Actve Desc. + Sts */ +#define DMATX_STAT_CDMASK 0x00000fff /* Current Descriptor Mask */ +#define DMATX_STAT_SMASK 0x0000f000 /* State Mask */ +#define DMATX_STAT_SDISABLED 0x00000000 /* State Disabled */ +#define DMATX_STAT_SACTIVE 0x00001000 /* State Active */ +#define DMATX_STAT_SIDLE 0x00002000 /* State Idle Wait */ +#define DMATX_STAT_SSTOPPED 0x00003000 /* State Stopped */ +#define DMATX_STAT_SSUSP 0x00004000 /* State Suspend Pending */ +#define DMATX_STAT_EMASK 0x000f0000 /* Error Mask */ +#define DMATX_STAT_ENONE 0x00000000 /* Error None */ +#define DMATX_STAT_EDPE 0x00010000 /* Error Desc. Protocol Error */ +#define DMATX_STAT_EDFU 0x00020000 /* Error Data FIFO Underrun */ +#define DMATX_STAT_EBEBR 0x00030000 /* Bus Error on Buffer Read */ +#define DMATX_STAT_EBEDA 0x00040000 /* Bus Error on Desc. Access */ +#define DMATX_STAT_FLUSHED 0x00100000 /* Flushed */ +#define B44_DMARX_CTRL 0x0210UL /* DMA RX Control */ +#define DMARX_CTRL_ENABLE 0x00000001 /* Enable */ +#define DMARX_CTRL_ROMASK 0x000000fe /* Receive Offset Mask */ +#define DMARX_CTRL_ROSHIFT 1 /* Receive Offset Shift */ +#define B44_DMARX_ADDR 0x0214UL /* DMA RX Descriptor Ring Addr */ +#define B44_DMARX_PTR 0x0218UL /* DMA RX Last Posted Desc */ +#define B44_DMARX_STAT 0x021CUL /* Cur Active Desc. + Status */ +#define DMARX_STAT_CDMASK 0x00000fff /* Current Descriptor Mask */ +#define DMARX_STAT_SMASK 0x0000f000 /* State Mask */ +#define DMARX_STAT_SDISABLED 0x00000000 /* State Disbaled */ +#define DMARX_STAT_SACTIVE 0x00001000 /* State Active */ +#define DMARX_STAT_SIDLE 0x00002000 /* State Idle Wait */ +#define DMARX_STAT_SSTOPPED 0x00003000 /* State Stopped */ +#define DMARX_STAT_EMASK 0x000f0000 /* Error Mask */ +#define DMARX_STAT_ENONE 0x00000000 /* Error None */ +#define DMARX_STAT_EDPE 0x00010000 /* Error Desc. Protocol Error */ +#define DMARX_STAT_EDFO 0x00020000 /* Error Data FIFO Overflow */ +#define DMARX_STAT_EBEBW 0x00030000 /* Error on Buffer Write */ +#define DMARX_STAT_EBEDA 0x00040000 /* Bus Error on Desc. Access */ +#define B44_DMAFIFO_AD 0x0220UL /* DMA FIFO Diag Address */ +#define DMAFIFO_AD_OMASK 0x0000ffff /* Offset Mask */ +#define DMAFIFO_AD_SMASK 0x000f0000 /* Select Mask */ +#define DMAFIFO_AD_SXDD 0x00000000 /* Select Transmit DMA Data */ +#define DMAFIFO_AD_SXDP 0x00010000 /* Sel Transmit DMA Pointers */ +#define DMAFIFO_AD_SRDD 0x00040000 /* Select Receive DMA Data */ +#define DMAFIFO_AD_SRDP 0x00050000 /* Sel Receive DMA Pointers */ +#define DMAFIFO_AD_SXFD 0x00080000 /* Select Transmit FIFO Data */ +#define DMAFIFO_AD_SXFP 0x00090000 /* Sel Transmit FIFO Pointers */ +#define DMAFIFO_AD_SRFD 0x000c0000 /* Select Receive FIFO Data */ +#define DMAFIFO_AD_SRFP 0x000c0000 /* Sel Receive FIFO Pointers */ +#define B44_DMAFIFO_LO 0x0224UL /* DMA FIFO Diag Low Data */ +#define B44_DMAFIFO_HI 0x0228UL /* DMA FIFO Diag High Data */ +#define B44_RXCONFIG 0x0400UL /* EMAC RX Config */ +#define RXCONFIG_DBCAST 0x00000001 /* Disable Broadcast */ +#define RXCONFIG_ALLMULTI 0x00000002 /* Accept All Multicast */ +#define RXCONFIG_NORX_WHILE_TX 0x00000004 /* Rcv Disble While TX */ +#define RXCONFIG_PROMISC 0x00000008 /* Promiscuous Enable */ +#define RXCONFIG_LPBACK 0x00000010 /* Loopback Enable */ +#define RXCONFIG_FLOW 0x00000020 /* Flow Control Enable */ +#define RXCONFIG_FLOW_ACCEPT 0x00000040 /* Accept UFC Frame */ +#define RXCONFIG_RFILT 0x00000080 /* Reject Filter */ +#define B44_RXMAXLEN 0x0404UL /* EMAC RX Max Packet Length */ +#define B44_TXMAXLEN 0x0408UL /* EMAC TX Max Packet Length */ +#define B44_MDIO_CTRL 0x0410UL /* EMAC MDIO Control */ +#define MDIO_CTRL_MAXF_MASK 0x0000007f /* MDC Frequency */ +#define MDIO_CTRL_PREAMBLE 0x00000080 /* MII Preamble Enable */ +#define B44_MDIO_DATA 0x0414UL /* EMAC MDIO Data */ +#define MDIO_DATA_DATA 0x0000ffff /* R/W Data */ +#define MDIO_DATA_TA_MASK 0x00030000 /* Turnaround Value */ +#define MDIO_DATA_TA_SHIFT 16 +#define MDIO_TA_VALID 2 +#define MDIO_DATA_RA_MASK 0x007c0000 /* Register Address */ +#define MDIO_DATA_RA_SHIFT 18 +#define MDIO_DATA_PMD_MASK 0x0f800000 /* Physical Media Device */ +#define MDIO_DATA_PMD_SHIFT 23 +#define MDIO_DATA_OP_MASK 0x30000000 /* Opcode */ +#define MDIO_DATA_OP_SHIFT 28 +#define MDIO_OP_WRITE 1 +#define MDIO_OP_READ 2 +#define MDIO_DATA_SB_MASK 0xc0000000 /* Start Bits */ +#define MDIO_DATA_SB_SHIFT 30 +#define MDIO_DATA_SB_START 0x40000000 /* Start Of Frame */ +#define B44_EMAC_IMASK 0x0418UL /* EMAC Interrupt Mask */ +#define B44_EMAC_ISTAT 0x041CUL /* EMAC Interrupt Status */ +#define EMAC_INT_MII 0x00000001 /* MII MDIO Interrupt */ +#define EMAC_INT_MIB 0x00000002 /* MIB Interrupt */ +#define EMAC_INT_FLOW 0x00000003 /* Flow Control Interrupt */ +#define B44_CAM_DATA_LO 0x0420UL /* EMAC CAM Data Low */ +#define B44_CAM_DATA_HI 0x0424UL /* EMAC CAM Data High */ +#define CAM_DATA_HI_VALID 0x00010000 /* Valid Bit */ +#define B44_CAM_CTRL 0x0428UL /* EMAC CAM Control */ +#define CAM_CTRL_ENABLE 0x00000001 /* CAM Enable */ +#define CAM_CTRL_MSEL 0x00000002 /* Mask Select */ +#define CAM_CTRL_READ 0x00000004 /* Read */ +#define CAM_CTRL_WRITE 0x00000008 /* Read */ +#define CAM_CTRL_INDEX_MASK 0x003f0000 /* Index Mask */ +#define CAM_CTRL_INDEX_SHIFT 16 +#define CAM_CTRL_BUSY 0x80000000 /* CAM Busy */ +#define B44_ENET_CTRL 0x042CUL /* EMAC ENET Control */ +#define ENET_CTRL_ENABLE 0x00000001 /* EMAC Enable */ +#define ENET_CTRL_DISABLE 0x00000002 /* EMAC Disable */ +#define ENET_CTRL_SRST 0x00000004 /* EMAC Soft Reset */ +#define ENET_CTRL_EPSEL 0x00000008 /* External PHY Select */ +#define B44_TX_CTRL 0x0430UL /* EMAC TX Control */ +#define TX_CTRL_DUPLEX 0x00000001 /* Full Duplex */ +#define TX_CTRL_FMODE 0x00000002 /* Flow Mode */ +#define TX_CTRL_SBENAB 0x00000004 /* Single Backoff Enable */ +#define TX_CTRL_SMALL_SLOT 0x00000008 /* Small Slottime */ +#define B44_TX_HIWMARK 0x0434UL /* EMAC TX High Watermark */ +#define TX_HIWMARK_DEFLT 56 /* Default used in all drivers */ +#define B44_MIB_CTRL 0x0438UL /* EMAC MIB Control */ +#define MIB_CTRL_CLR_ON_READ 0x00000001 /* Autoclear on Read */ +#define B44_TX_GOOD_O 0x0500UL /* MIB TX Good Octets */ +#define B44_TX_GOOD_P 0x0504UL /* MIB TX Good Packets */ +#define B44_TX_O 0x0508UL /* MIB TX Octets */ +#define B44_TX_P 0x050CUL /* MIB TX Packets */ +#define B44_TX_BCAST 0x0510UL /* MIB TX Broadcast Packets */ +#define B44_TX_MCAST 0x0514UL /* MIB TX Multicast Packets */ +#define B44_TX_64 0x0518UL /* MIB TX <= 64 byte Packets */ +#define B44_TX_65_127 0x051CUL /* MIB TX 65 to 127 byte Pkts */ +#define B44_TX_128_255 0x0520UL /* MIB TX 128 to 255 byte Pkts */ +#define B44_TX_256_511 0x0524UL /* MIB TX 256 to 511 byte Pkts */ +#define B44_TX_512_1023 0x0528UL /* MIB TX 512 to 1023 byte Pkts */ +#define B44_TX_1024_MAX 0x052CUL /* MIB TX 1024 to max byte Pkts */ +#define B44_TX_JABBER 0x0530UL /* MIB TX Jabber Packets */ +#define B44_TX_OSIZE 0x0534UL /* MIB TX Oversize Packets */ +#define B44_TX_FRAG 0x0538UL /* MIB TX Fragment Packets */ +#define B44_TX_URUNS 0x053CUL /* MIB TX Underruns */ +#define B44_TX_TCOLS 0x0540UL /* MIB TX Total Collisions */ +#define B44_TX_SCOLS 0x0544UL /* MIB TX Single Collisions */ +#define B44_TX_MCOLS 0x0548UL /* MIB TX Multiple Collisions */ +#define B44_TX_ECOLS 0x054CUL /* MIB TX Excessive Collisions */ +#define B44_TX_LCOLS 0x0550UL /* MIB TX Late Collisions */ +#define B44_TX_DEFERED 0x0554UL /* MIB TX Defered Packets */ +#define B44_TX_CLOST 0x0558UL /* MIB TX Carrier Lost */ +#define B44_TX_PAUSE 0x055CUL /* MIB TX Pause Packets */ +#define B44_RX_GOOD_O 0x0580UL /* MIB RX Good Octets */ +#define B44_RX_GOOD_P 0x0584UL /* MIB RX Good Packets */ +#define B44_RX_O 0x0588UL /* MIB RX Octets */ +#define B44_RX_P 0x058CUL /* MIB RX Packets */ +#define B44_RX_BCAST 0x0590UL /* MIB RX Broadcast Packets */ +#define B44_RX_MCAST 0x0594UL /* MIB RX Multicast Packets */ +#define B44_RX_64 0x0598UL /* MIB RX <= 64 byte Packets */ +#define B44_RX_65_127 0x059CUL /* MIB RX 65 to 127 byte Pkts */ +#define B44_RX_128_255 0x05A0UL /* MIB RX 128 to 255 byte Pkts */ +#define B44_RX_256_511 0x05A4UL /* MIB RX 256 to 511 byte Pkts */ +#define B44_RX_512_1023 0x05A8UL /* MIB RX 512 to 1023 byte Pkts */ +#define B44_RX_1024_MAX 0x05ACUL /* MIB RX 1024 to max byte Pkts */ +#define B44_RX_JABBER 0x05B0UL /* MIB RX Jabber Packets */ +#define B44_RX_OSIZE 0x05B4UL /* MIB RX Oversize Packets */ +#define B44_RX_FRAG 0x05B8UL /* MIB RX Fragment Packets */ +#define B44_RX_MISS 0x05BCUL /* MIB RX Missed Packets */ +#define B44_RX_CRCA 0x05C0UL /* MIB RX CRC Align Errors */ +#define B44_RX_USIZE 0x05C4UL /* MIB RX Undersize Packets */ +#define B44_RX_CRC 0x05C8UL /* MIB RX CRC Errors */ +#define B44_RX_ALIGN 0x05CCUL /* MIB RX Align Errors */ +#define B44_RX_SYM 0x05D0UL /* MIB RX Symbol Errors */ +#define B44_RX_PAUSE 0x05D4UL /* MIB RX Pause Packets */ +#define B44_RX_NPAUSE 0x05D8UL /* MIB RX Non-Pause Packets */ + +/* Sonics Silicon backplane register definitions */ +#define B44_SBIMSTATE 0x0F90UL /* SB Initiator Agent State */ +#define SBIMSTATE_PC 0x0000000f /* Pipe Count */ +#define SBIMSTATE_AP_MASK 0x00000030 /* Arbitration Priority */ +#define SBIMSTATE_AP_BOTH 0x00000000 /* both timeslices and token */ +#define SBIMSTATE_AP_TS 0x00000010 /* Use timeslices only */ +#define SBIMSTATE_AP_TK 0x00000020 /* Use token only */ +#define SBIMSTATE_AP_RSV 0x00000030 /* Reserved */ +#define SBIMSTATE_IBE 0x00020000 /* In Band Error */ +#define SBIMSTATE_TO 0x00040000 /* Timeout */ +#define SBIMSTATE_BAD ( SBIMSTATE_IBE | SBIMSTATE_TO ) +#define B44_SBINTVEC 0x0F94UL /* SB Interrupt Mask */ +#define SBINTVEC_PCI 0x00000001 /* Enable interrupts for PCI */ +#define SBINTVEC_ENET0 0x00000002 /* Enable ints for enet 0 */ +#define SBINTVEC_ILINE20 0x00000004 /* Enable ints for iline20 */ +#define SBINTVEC_CODEC 0x00000008 /* Enable ints for v90 codec */ +#define SBINTVEC_USB 0x00000010 /* Enable intts for usb */ +#define SBINTVEC_EXTIF 0x00000020 /* Enable ints for ext i/f */ +#define SBINTVEC_ENET1 0x00000040 /* Enable ints for enet 1 */ +#define B44_SBTMSLOW 0x0F98UL /* SB Target State Low */ +#define SBTMSLOW_RESET 0x00000001 /* Reset */ +#define SBTMSLOW_REJECT 0x00000002 /* Reject */ +#define SBTMSLOW_CLOCK 0x00010000 /* Clock Enable */ +#define SBTMSLOW_FGC 0x00020000 /* Force Gated Clocks On */ +#define SBTMSLOW_PE 0x40000000 /* Power Management Enable */ +#define SBTMSLOW_BE 0x80000000 /* BIST Enable */ +#define B44_SBTMSHIGH 0x0F9CUL /* SB Target State High */ +#define SBTMSHIGH_SERR 0x00000001 /* S-error */ +#define SBTMSHIGH_INT 0x00000002 /* Interrupt */ +#define SBTMSHIGH_BUSY 0x00000004 /* Busy */ +#define SBTMSHIGH_GCR 0x20000000 /* Gated Clock Request */ +#define SBTMSHIGH_BISTF 0x40000000 /* BIST Failed */ +#define SBTMSHIGH_BISTD 0x80000000 /* BIST Done */ +#define B44_SBIDHIGH 0x0FFCUL /* SB Identification High */ +#define SBIDHIGH_RC_MASK 0x0000000f /* Revision Code */ +#define SBIDHIGH_CC_MASK 0x0000fff0 /* Core Code */ +#define SBIDHIGH_CC_SHIFT 4 +#define SBIDHIGH_VC_MASK 0xffff0000 /* Vendor Code */ +#define SBIDHIGH_VC_SHIFT 16 + +/* SSB PCI config space registers. */ +#define SSB_PMCSR 0x44 +#define SSB_PE 0x100 +#define SSB_BAR0_WIN 0x80 +#define SSB_BAR1_WIN 0x84 +#define SSB_SPROM_CONTROL 0x88 +#define SSB_BAR1_CONTROL 0x8c + +/* SSB core and host control registers. */ +#define SSB_CONTROL 0x0000UL +#define SSB_ARBCONTROL 0x0010UL +#define SSB_ISTAT 0x0020UL +#define SSB_IMASK 0x0024UL +#define SSB_MBOX 0x0028UL +#define SSB_BCAST_ADDR 0x0050UL +#define SSB_BCAST_DATA 0x0054UL +#define SSB_PCI_TRANS_0 0x0100UL +#define SSB_PCI_TRANS_1 0x0104UL +#define SSB_PCI_TRANS_2 0x0108UL +#define SSB_SPROM 0x0800UL + +#define SSB_PCI_MEM 0x00000000 +#define SSB_PCI_IO 0x00000001 +#define SSB_PCI_CFG0 0x00000002 +#define SSB_PCI_CFG1 0x00000003 +#define SSB_PCI_PREF 0x00000004 +#define SSB_PCI_BURST 0x00000008 +#define SSB_PCI_MASK0 0xfc000000 +#define SSB_PCI_MASK1 0xfc000000 +#define SSB_PCI_MASK2 0xc0000000 + +/* 4400 PHY registers */ +#define B44_MII_AUXCTRL 24 /* Auxiliary Control */ +#define MII_AUXCTRL_DUPLEX 0x0001 /* Full Duplex */ +#define MII_AUXCTRL_SPEED 0x0002 /* 1=100Mbps, 0=10Mbps */ +#define MII_AUXCTRL_FORCED 0x0004 /* Forced 10/100 */ +#define B44_MII_ALEDCTRL 26 /* Activity LED */ +#define MII_ALEDCTRL_ALLMSK 0x7fff +#define B44_MII_TLEDCTRL 27 /* Traffic Meter LED */ +#define MII_TLEDCTRL_ENABLE 0x0040 + +/* RX/TX descriptor */ +struct dma_desc { + u32 ctrl; /* length of data and flags */ + u32 addr; /* address of data */ +}; + +/* There are only 12 bits in the DMA engine for descriptor offsetting + * so the table must be aligned on a boundary of this. + */ +#define B44_DMA_ALIGNMENT 4096 + +/* The DMA engine can only address the first gigabyte of address space + */ +#define B44_30BIT_DMA_MASK 0x3fffffff + +#define DESC_CTRL_LEN 0x00001fff +#define DESC_CTRL_CMASK 0x0ff00000 /* Core specific bits */ +#define DESC_CTRL_EOT 0x10000000 /* End of Table */ +#define DESC_CTRL_IOC 0x20000000 /* Interrupt On Completion */ +#define DESC_CTRL_EOF 0x40000000 /* End of Frame */ +#define DESC_CTRL_SOF 0x80000000 /* Start of Frame */ + +struct rx_header { + u16 len; + u16 flags; + u16 pad[12]; +}; +#define RX_HEADER_LEN 28 + +#define RX_FLAG_OFIFO 0x00000001 /* FIFO Overflow */ +#define RX_FLAG_CRCERR 0x00000002 /* CRC Error */ +#define RX_FLAG_SERR 0x00000004 /* Receive Symbol Error */ +#define RX_FLAG_ODD 0x00000008 /* Frame has odd number of nibbles */ +#define RX_FLAG_LARGE 0x00000010 /* Frame is > RX MAX Length */ +#define RX_FLAG_MCAST 0x00000020 /* Dest is Multicast Address */ +#define RX_FLAG_BCAST 0x00000040 /* Dest is Broadcast Address */ +#define RX_FLAG_MISS 0x00000080 /* Received due to promisc mode */ +#define RX_FLAG_LAST 0x00000800 /* Last buffer in frame */ +#define RX_FLAG_ERRORS (RX_FLAG_ODD | RX_FLAG_SERR |\ + RX_FLAG_CRCERR | RX_FLAG_OFIFO) + +/* Client Mode PCI memory access space (1 GB) */ +#define SB_PCI_DMA 0x40000000 + + /* Address of PCI core on BCM4400 cards */ +#define BCM4400_PCI_CORE_ADDR 0x18002000 + +/* Hardware minimum and maximum for a single frame's data payload */ +#define B44_MIN_MTU 60 +#define B44_MAX_MTU 1500 + +#define B44_RING_SIZE 8 +#define B44_RING_LAST ( B44_RING_SIZE - 1 ) + +#define B44_RX_RING_LEN_BYTES ( sizeof bp->rx[0] * B44_RING_SIZE ) +#define B44_TX_RING_LEN_BYTES ( sizeof bp->tx[0] * B44_RING_SIZE ) + +#define RX_PKT_OFFSET 30 +#define RX_PKT_BUF_SZ (1536 + RX_PKT_OFFSET + 64) + +#define B44_FULL_RESET 1 +#define B44_FULL_RESET_SKIP_PHY 2 +#define B44_PARTIAL_RESET 3 +#define B44_CHIP_RESET_FULL 4 +#define B44_CHIP_RESET_PARTIAL 5 + +#define SSB_CORE_DOWN ( SBTMSLOW_RESET | SBTMSLOW_REJECT ) + +#define B44_REGS_SIZE 8192 + +/** Driver private state */ +struct b44_private { + struct net_device *netdev; + struct pci_device *pci; + u8 *regs; /* memory-mapped registers */ + u8 phy_addr; + + struct dma_desc *tx; + struct io_buffer *tx_iobuf[B44_RING_SIZE]; + u32 tx_cur; /* next available descriptor */ + u32 tx_dirty; /* oldest pending descriptor */ + + struct dma_desc *rx; + struct io_buffer *rx_iobuf[B44_RING_SIZE]; + u32 rx_cur; /* next descriptor to read */ +}; + + +static void ssb_core_reset ( struct b44_private *bp ); +static void ssb_core_disable ( struct b44_private *bp ); +static u32 ssb_pci_setup ( struct b44_private *bp, u32 cores ); + +static void b44_chip_reset ( struct b44_private *bp, int reset_kind ); +static void b44_init_hw ( struct b44_private *bp, int reset_kind ); +static void b44_cam_write ( struct b44_private *bp, u8 *data, int index ); +static void b44_set_mac_addr ( struct b44_private *bp ); +static void b44_set_rx_mode ( struct net_device *netdev ); +static void b44_halt(struct b44_private *); + +static int b44_phy_reset ( struct b44_private *bp ); +static int b44_phy_write ( struct b44_private *bp, int reg, u32 val ); +static int b44_phy_read ( struct b44_private *bp, int reg, u32 *val ); + +static int b44_init_tx_ring ( struct b44_private *bp ); +static void b44_free_tx_ring ( struct b44_private *bp ); +static int b44_init_rx_ring ( struct b44_private *bp ); +static void b44_free_rx_ring ( struct b44_private *bp ); +static void b44_rx_refill ( struct b44_private *bp, u32 pending ); +static void b44_populate_rx_descriptor (struct b44_private *bp, u32 index); + +static int b44_probe ( struct pci_device *pci, + const struct pci_device_id *id ); +static void b44_remove ( struct pci_device *pci ); + +static int b44_open ( struct net_device *netdev ); +static void b44_close ( struct net_device *netdev ); +static void b44_irq ( struct net_device *netdev, int enable ); +static void b44_poll ( struct net_device *netdev ); +static void b44_process_rx_packets ( struct b44_private *bp ); +static int b44_transmit ( struct net_device *netdev, + struct io_buffer *iobuf ); + +static struct net_device_operations b44_operations; + +#endif /* _B44_H */ diff --git a/gpxe/src/drivers/net/cs89x0.c b/gpxe/src/drivers/net/cs89x0.c index 11988add..1f647a8e 100644 --- a/gpxe/src/drivers/net/cs89x0.c +++ b/gpxe/src/drivers/net/cs89x0.c @@ -419,8 +419,8 @@ retry: ETH_ALEN/2); outw(((t >> 8)&0xFF)|(t << 8), eth_nic_base + TX_FRAME_PORT); outsw(eth_nic_base + TX_FRAME_PORT, p, (s+1)/2); - for (sr = sr/2 - (s+1)/2 - ETH_ALEN - 1; sr-- > 0; - outw(0, eth_nic_base + TX_FRAME_PORT)); + for (sr = sr/2 - (s+1)/2 - ETH_ALEN - 1; sr > 0; sr--) + outw(0, eth_nic_base + TX_FRAME_PORT); /* wait for transfer to succeed */ for (tmo = currticks()+5*TICKS_PER_SEC; diff --git a/gpxe/src/drivers/net/davicom.c b/gpxe/src/drivers/net/davicom.c index 079e647e..bb6d7e96 100644 --- a/gpxe/src/drivers/net/davicom.c +++ b/gpxe/src/drivers/net/davicom.c @@ -630,7 +630,7 @@ static void davicom_disable ( struct nic *nic ) { outl(inl(ioaddr + CSR6) & ~0x00002002, ioaddr + CSR6); /* Clear the missed-packet counter. */ - (volatile unsigned long)inl(ioaddr + CSR8); + inl(ioaddr + CSR8); } @@ -676,7 +676,7 @@ static int davicom_probe ( struct nic *nic, struct pci_device *pci ) { outl(inl(ioaddr + CSR6) & ~0x00002002, ioaddr + CSR6); /* Clear the missed-packet counter. */ - (volatile unsigned long)inl(ioaddr + CSR8); + inl(ioaddr + CSR8); /* Get MAC Address */ /* read EEPROM data */ diff --git a/gpxe/src/drivers/net/dmfe.c b/gpxe/src/drivers/net/dmfe.c index 9cf50418..26021e6b 100644 --- a/gpxe/src/drivers/net/dmfe.c +++ b/gpxe/src/drivers/net/dmfe.c @@ -133,14 +133,14 @@ /* Structure/enum declaration ------------------------------- */ struct tx_desc { u32 tdes0, tdes1, tdes2, tdes3; /* Data for the card */ - u32 tx_buf_ptr; /* Data for us */ - u32 /* struct tx_desc * */ next_tx_desc; + void * tx_buf_ptr; /* Data for us */ + struct tx_desc * next_tx_desc; } __attribute__ ((aligned(32))); struct rx_desc { u32 rdes0, rdes1, rdes2, rdes3; /* Data for the card */ - u32 rx_skb_ptr; /* Data for us */ - u32 /* struct rx_desc * */ next_rx_desc; + void * rx_skb_ptr; /* Data for us */ + struct rx_desc * next_rx_desc; } __attribute__ ((aligned(32))); static struct dmfe_private { @@ -522,30 +522,30 @@ static void dmfe_descriptor_init(struct nic *nic __unused, unsigned long ioaddr) /* Init Transmit chain */ for (i = 0; i < TX_DESC_CNT; i++) { - txd[i].tx_buf_ptr = (u32) & txb[i]; + txd[i].tx_buf_ptr = &txb[i]; txd[i].tdes0 = cpu_to_le32(0); txd[i].tdes1 = cpu_to_le32(0x81000000); /* IC, chain */ txd[i].tdes2 = cpu_to_le32(virt_to_bus(&txb[i])); txd[i].tdes3 = cpu_to_le32(virt_to_bus(&txd[i + 1])); - txd[i].next_tx_desc = virt_to_le32desc(&txd[i + 1]); + txd[i].next_tx_desc = &txd[i + 1]; } /* Mark the last entry as wrapping the ring */ txd[i - 1].tdes3 = virt_to_le32desc(&txd[0]); - txd[i - 1].next_tx_desc = (u32) & txd[0]; + txd[i - 1].next_tx_desc = &txd[0]; /* receive descriptor chain */ for (i = 0; i < RX_DESC_CNT; i++) { - rxd[i].rx_skb_ptr = (u32) & rxb[i * RX_ALLOC_SIZE]; + rxd[i].rx_skb_ptr = &rxb[i * RX_ALLOC_SIZE]; rxd[i].rdes0 = cpu_to_le32(0x80000000); rxd[i].rdes1 = cpu_to_le32(0x01000600); rxd[i].rdes2 = cpu_to_le32(virt_to_bus(&rxb[i * RX_ALLOC_SIZE])); rxd[i].rdes3 = cpu_to_le32(virt_to_bus(&rxd[i + 1])); - rxd[i].next_rx_desc = virt_to_le32desc(&rxd[i + 1]); + rxd[i].next_rx_desc = &rxd[i + 1]; } /* Mark the last entry as wrapping the ring */ rxd[i - 1].rdes3 = cpu_to_le32(virt_to_bus(&rxd[0])); - rxd[i - 1].next_rx_desc = virt_to_le32desc(&rxd[0]); + rxd[i - 1].next_rx_desc = &rxd[0]; } diff --git a/gpxe/src/drivers/net/e1000/e1000.c b/gpxe/src/drivers/net/e1000/e1000.c index a9aa508a..c1a4a52d 100644 --- a/gpxe/src/drivers/net/e1000/e1000.c +++ b/gpxe/src/drivers/net/e1000/e1000.c @@ -258,8 +258,8 @@ e1000_configure_tx ( struct e1000_adapter *adapter ) E1000_WRITE_REG ( hw, TDBAL, virt_to_bus ( adapter->tx_base ) ); E1000_WRITE_REG ( hw, TDLEN, adapter->tx_ring_size ); - DBG ( "TDBAL: %#08lx\n", E1000_READ_REG ( hw, TDBAL ) ); - DBG ( "TDLEN: %ld\n", E1000_READ_REG ( hw, TDLEN ) ); + DBG ( "TDBAL: %#08x\n", E1000_READ_REG ( hw, TDBAL ) ); + DBG ( "TDLEN: %d\n", E1000_READ_REG ( hw, TDLEN ) ); /* Setup the HW Tx Head and Tail descriptor pointers */ E1000_WRITE_REG ( hw, TDH, 0 ); @@ -385,9 +385,9 @@ e1000_configure_rx ( struct e1000_adapter *adapter ) E1000_WRITE_REG ( hw, RCTL, rctl ); E1000_WRITE_FLUSH ( hw ); - DBG ( "RDBAL: %#08lx\n", E1000_READ_REG ( hw, RDBAL ) ); - DBG ( "RDLEN: %ld\n", E1000_READ_REG ( hw, RDLEN ) ); - DBG ( "RCTL: %#08lx\n", E1000_READ_REG ( hw, RCTL ) ); + DBG ( "RDBAL: %#08x\n", E1000_READ_REG ( hw, RDBAL ) ); + DBG ( "RDLEN: %d\n", E1000_READ_REG ( hw, RDLEN ) ); + DBG ( "RCTL: %#08x\n", E1000_READ_REG ( hw, RCTL ) ); } /** @@ -577,7 +577,7 @@ e1000_transmit ( struct net_device *netdev, struct io_buffer *iobuf ) E1000_TXD_CMD_IFCS | iob_len ( iobuf ); tx_curr_desc->upper.data = 0; - DBG ( "TX fill: %ld tx_curr: %ld addr: %#08lx len: %zd\n", adapter->tx_fill_ctr, + DBG ( "TX fill: %d tx_curr: %d addr: %#08lx len: %zd\n", adapter->tx_fill_ctr, tx_curr, virt_to_bus ( iobuf->data ), iob_len ( iobuf ) ); /* Point to next free descriptor */ @@ -620,7 +620,7 @@ e1000_poll ( struct net_device *netdev ) if ( ! icr ) return; - DBG ( "e1000_poll: intr_status = %#08lx\n", icr ); + DBG ( "e1000_poll: intr_status = %#08x\n", icr ); /* Check status of transmitted packets */ @@ -635,17 +635,17 @@ e1000_poll ( struct net_device *netdev ) if ( ! ( tx_status & E1000_TXD_STAT_DD ) ) break; - DBG ( "Sent packet. tx_head: %ld tx_tail: %ld tx_status: %#08lx\n", + DBG ( "Sent packet. tx_head: %d tx_tail: %d tx_status: %#08x\n", adapter->tx_head, adapter->tx_tail, tx_status ); if ( tx_status & ( E1000_TXD_STAT_EC | E1000_TXD_STAT_LC | E1000_TXD_STAT_TU ) ) { netdev_tx_complete_err ( netdev, adapter->tx_iobuf[i], -EINVAL ); - DBG ( "Error transmitting packet, tx_status: %#08lx\n", + DBG ( "Error transmitting packet, tx_status: %#08x\n", tx_status ); } else { netdev_tx_complete ( netdev, adapter->tx_iobuf[i] ); - DBG ( "Success transmitting packet, tx_status: %#08lx\n", + DBG ( "Success transmitting packet, tx_status: %#08x\n", tx_status ); } @@ -667,16 +667,16 @@ e1000_poll ( struct net_device *netdev ) ( i * sizeof ( *adapter->rx_base ) ); rx_status = rx_curr_desc->status; - DBG2 ( "Before DD Check RX_status: %#08lx\n", rx_status ); + DBG2 ( "Before DD Check RX_status: %#08x\n", rx_status ); if ( ! ( rx_status & E1000_RXD_STAT_DD ) ) break; - DBG ( "RCTL = %#08lx\n", E1000_READ_REG ( &adapter->hw, RCTL ) ); + DBG ( "RCTL = %#08x\n", E1000_READ_REG ( &adapter->hw, RCTL ) ); rx_len = rx_curr_desc->length; - DBG ( "Received packet, rx_curr: %ld rx_status: %#08lx rx_len: %ld\n", + DBG ( "Received packet, rx_curr: %d rx_status: %#08x rx_len: %d\n", i, rx_status, rx_len ); rx_err = rx_curr_desc->errors; @@ -685,7 +685,7 @@ e1000_poll ( struct net_device *netdev ) netdev_rx_err ( netdev, NULL, -EINVAL ); DBG ( "e1000_poll: Corrupted packet received!" - " rx_err: %#08lx\n", rx_err ); + " rx_err: %#08x\n", rx_err ); } else { /* If unable allocate space for this packet, @@ -818,8 +818,8 @@ e1000_probe ( struct pci_device *pdev, * because it depends on mac_type */ if ( ( adapter->hw.mac_type == e1000_ich8lan ) && ( pdev->ioaddr ) ) { - flash_start = pci_bar_start ( pdev, 1 ); - flash_len = pci_bar_size ( pdev, 1 ); + flash_start = pci_bar_start ( pdev, PCI_BASE_ADDRESS_1 ); + flash_len = pci_bar_size ( pdev, PCI_BASE_ADDRESS_1 ); adapter->hw.flash_address = ioremap ( flash_start, flash_len ); if ( ! adapter->hw.flash_address ) goto err_flashmap; @@ -962,7 +962,7 @@ e1000_open ( struct net_device *netdev ) e1000_configure_rx ( adapter ); - DBG ( "RXDCTL: %#08lx\n", E1000_READ_REG ( &adapter->hw, RXDCTL ) ); + DBG ( "RXDCTL: %#08x\n", E1000_READ_REG ( &adapter->hw, RXDCTL ) ); return 0; diff --git a/gpxe/src/drivers/net/e1000/e1000.h b/gpxe/src/drivers/net/e1000/e1000.h index 4ae41451..77a09ef1 100644 --- a/gpxe/src/drivers/net/e1000/e1000.h +++ b/gpxe/src/drivers/net/e1000/e1000.h @@ -34,7 +34,8 @@ #include <stdint.h> #include <stdlib.h> #include <stdio.h> -#include <io.h> +#include <string.h> +#include <gpxe/io.h> #include <errno.h> #include <byteswap.h> #include <gpxe/pci.h> diff --git a/gpxe/src/drivers/net/e1000/e1000_hw.c b/gpxe/src/drivers/net/e1000/e1000_hw.c index 0667ad61..1054b90a 100644 --- a/gpxe/src/drivers/net/e1000/e1000_hw.c +++ b/gpxe/src/drivers/net/e1000/e1000_hw.c @@ -1429,7 +1429,7 @@ e1000_copper_link_preconfig(struct e1000_hw *hw) DEBUGOUT("Error, did not detect valid phy.\n"); return ret_val; } - DEBUGOUT1("Phy ID = %#08lx \n", hw->phy_id); + DEBUGOUT1("Phy ID = %#08x \n", hw->phy_id); /* Set PHY to class A mode (if necessary) */ ret_val = e1000_set_phy_mode(hw); @@ -3551,7 +3551,7 @@ e1000_read_phy_reg_ex(struct e1000_hw *hw, uint32_t reg_addr, DEBUGFUNC("e1000_read_phy_reg_ex"); if (reg_addr > MAX_PHY_REG_ADDRESS) { - DEBUGOUT1("PHY Address %ld is out of range\n", reg_addr); + DEBUGOUT1("PHY Address %d is out of range\n", reg_addr); return -E1000_ERR_PARAM; } @@ -3689,7 +3689,7 @@ e1000_write_phy_reg_ex(struct e1000_hw *hw, uint32_t reg_addr, DEBUGFUNC("e1000_write_phy_reg_ex"); if (reg_addr > MAX_PHY_REG_ADDRESS) { - DEBUGOUT1("PHY Address %ld is out of range\n", reg_addr); + DEBUGOUT1("PHY Address %d is out of range\n", reg_addr); return -E1000_ERR_PARAM; } @@ -4141,10 +4141,10 @@ e1000_detect_gig_phy(struct e1000_hw *hw) phy_init_status = e1000_set_phy_type(hw); if ((match) && (phy_init_status == E1000_SUCCESS)) { - DEBUGOUT1("PHY ID %#08lx detected\n", hw->phy_id); + DEBUGOUT1("PHY ID %#08x detected\n", hw->phy_id); return E1000_SUCCESS; } - DEBUGOUT1("Invalid PHY ID %#08lx\n", hw->phy_id); + DEBUGOUT1("Invalid PHY ID %#08x\n", hw->phy_id); return -E1000_ERR_PHY; } @@ -8795,13 +8795,13 @@ e1000_verify_write_ich8_byte(struct e1000_hw *hw, uint32_t index, uint8_t byte) int32_t error = E1000_SUCCESS; int32_t program_retries = 0; - DEBUGOUT2("Byte := %2.2X Offset := %ld\n", byte, index); + DEBUGOUT2("Byte := %2.2X Offset := %d\n", byte, index); error = e1000_write_ich8_byte(hw, index, byte); if (error != E1000_SUCCESS) { for (program_retries = 0; program_retries < 100; program_retries++) { - DEBUGOUT2("Retrying \t Byte := %2.2X Offset := %ld\n", byte, index); + DEBUGOUT2("Retrying \t Byte := %2.2X Offset := %d\n", byte, index); error = e1000_write_ich8_byte(hw, index, byte); udelay(100); if (error == E1000_SUCCESS) diff --git a/gpxe/src/drivers/net/e1000/e1000_osdep.h b/gpxe/src/drivers/net/e1000/e1000_osdep.h index 7df9b5e9..c2d9eb9c 100644 --- a/gpxe/src/drivers/net/e1000/e1000_osdep.h +++ b/gpxe/src/drivers/net/e1000/e1000_osdep.h @@ -37,7 +37,7 @@ #include <stdint.h> #include <stdlib.h> #include <stdio.h> -#include <io.h> +#include <gpxe/io.h> #include <errno.h> #include <unistd.h> #include <byteswap.h> @@ -74,60 +74,60 @@ typedef enum { #define DEBUGOUT3 DEBUGOUT1 #define DEBUGOUT7 DEBUGOUT1 -#define E1000_WRITE_REG(a, reg, value) ( \ +#define E1000_WRITE_REG(a, reg, value) \ writel((value), ((a)->hw_addr + \ - (((a)->mac_type >= e1000_82543) ? E1000_##reg : E1000_82542_##reg)))) + (((a)->mac_type >= e1000_82543) ? E1000_##reg : E1000_82542_##reg))) -#define E1000_READ_REG(a, reg) ( \ +#define E1000_READ_REG(a, reg) \ readl((a)->hw_addr + \ - (((a)->mac_type >= e1000_82543) ? E1000_##reg : E1000_82542_##reg))) + (((a)->mac_type >= e1000_82543) ? E1000_##reg : E1000_82542_##reg)) -#define E1000_WRITE_REG_ARRAY(a, reg, offset, value) ( \ +#define E1000_WRITE_REG_ARRAY(a, reg, offset, value) \ writel((value), ((a)->hw_addr + \ (((a)->mac_type >= e1000_82543) ? E1000_##reg : E1000_82542_##reg) + \ - ((offset) << 2)))) + ((offset) << 2))) -#define E1000_READ_REG_ARRAY(a, reg, offset) ( \ +#define E1000_READ_REG_ARRAY(a, reg, offset) \ readl((a)->hw_addr + \ (((a)->mac_type >= e1000_82543) ? E1000_##reg : E1000_82542_##reg) + \ - ((offset) << 2))) + ((offset) << 2)) #define E1000_READ_REG_ARRAY_DWORD E1000_READ_REG_ARRAY #define E1000_WRITE_REG_ARRAY_DWORD E1000_WRITE_REG_ARRAY -#define E1000_WRITE_REG_ARRAY_WORD(a, reg, offset, value) ( \ +#define E1000_WRITE_REG_ARRAY_WORD(a, reg, offset, value) \ writew((value), ((a)->hw_addr + \ (((a)->mac_type >= e1000_82543) ? E1000_##reg : E1000_82542_##reg) + \ - ((offset) << 1)))) + ((offset) << 1))) -#define E1000_READ_REG_ARRAY_WORD(a, reg, offset) ( \ +#define E1000_READ_REG_ARRAY_WORD(a, reg, offset) \ readw((a)->hw_addr + \ (((a)->mac_type >= e1000_82543) ? E1000_##reg : E1000_82542_##reg) + \ - ((offset) << 1))) + ((offset) << 1)) -#define E1000_WRITE_REG_ARRAY_BYTE(a, reg, offset, value) ( \ +#define E1000_WRITE_REG_ARRAY_BYTE(a, reg, offset, value) \ writeb((value), ((a)->hw_addr + \ (((a)->mac_type >= e1000_82543) ? E1000_##reg : E1000_82542_##reg) + \ - (offset)))) + (offset))) -#define E1000_READ_REG_ARRAY_BYTE(a, reg, offset) ( \ +#define E1000_READ_REG_ARRAY_BYTE(a, reg, offset) \ readb((a)->hw_addr + \ (((a)->mac_type >= e1000_82543) ? E1000_##reg : E1000_82542_##reg) + \ - (offset))) + (offset)) #define E1000_WRITE_FLUSH(a) E1000_READ_REG(a, STATUS) -#define E1000_WRITE_ICH_FLASH_REG(a, reg, value) ( \ - writel((value), ((a)->flash_address + reg))) +#define E1000_WRITE_ICH_FLASH_REG(a, reg, value) \ + writel((value), ((a)->flash_address + reg)) -#define E1000_READ_ICH_FLASH_REG(a, reg) ( \ - readl((a)->flash_address + reg)) +#define E1000_READ_ICH_FLASH_REG(a, reg) \ + readl((a)->flash_address + reg) -#define E1000_WRITE_ICH_FLASH_REG16(a, reg, value) ( \ - writew((value), ((a)->flash_address + reg))) +#define E1000_WRITE_ICH_FLASH_REG16(a, reg, value) \ + writew((value), ((a)->flash_address + reg)) -#define E1000_READ_ICH_FLASH_REG16(a, reg) ( \ - readw((a)->flash_address + reg)) +#define E1000_READ_ICH_FLASH_REG16(a, reg) \ + readw((a)->flash_address + reg) #define msleep(n) mdelay(n) diff --git a/gpxe/src/drivers/net/eepro100.c b/gpxe/src/drivers/net/eepro100.c index f746976a..e6e7db49 100644 --- a/gpxe/src/drivers/net/eepro100.c +++ b/gpxe/src/drivers/net/eepro100.c @@ -407,7 +407,7 @@ static void eepro100_transmit(struct nic *nic, const char *d, unsigned int t, un } hdr; unsigned short status; int s1, s2; - tick_t ct; + unsigned long ct; status = inw(ioaddr + SCBStatus); /* Acknowledge all of the current interrupt sources ASAP. */ @@ -448,7 +448,7 @@ static void eepro100_transmit(struct nic *nic, const char *d, unsigned int t, un ct = currticks(); /* timeout 10 ms for transmit */ - while (!txfd.status && ct + 10*USECS_IN_MSEC) + while (!txfd.status && ct + 10*1000) /* Wait */; s2 = inw (ioaddr + SCBStatus); @@ -608,7 +608,7 @@ static int eepro100_probe ( struct nic *nic, struct pci_device *pci ) { int read_cmd, ee_size; int options; int rx_mode; - tick_t ct; + unsigned long ct; /* we cache only the first few words of the EEPROM data be careful not to access beyond this array */ @@ -753,7 +753,7 @@ static int eepro100_probe ( struct nic *nic, struct pci_device *pci ) { whereami ("started TX thingy (config, iasetup)."); ct = currticks(); - while (!txfd.status && ct + 10*USECS_IN_MSEC < currticks()) + while (!txfd.status && ct + 10*1000 < currticks()) /* Wait */; /* Read the status register once to disgard stale data */ diff --git a/gpxe/src/drivers/net/epic100.c b/gpxe/src/drivers/net/epic100.c index 67b4f0fb..1e36a680 100644 --- a/gpxe/src/drivers/net/epic100.c +++ b/gpxe/src/drivers/net/epic100.c @@ -309,7 +309,7 @@ epic100_transmit(struct nic *nic, const char *destaddr, unsigned int type, unsigned short nstype; unsigned char *txp; int entry; - tick_t ct; + unsigned long ct; /* Calculate the next Tx descriptor entry. */ entry = cur_tx % TX_RING_SIZE; @@ -352,7 +352,7 @@ epic100_transmit(struct nic *nic, const char *destaddr, unsigned int type, ct = currticks(); /* timeout 10 ms for transmit */ while ((le32_to_cpu(tx_ring[entry].status) & (TRING_OWN)) && - ct + 10*USECS_IN_MSEC < currticks()) + ct + 10*1000 < currticks()) /* Wait */; if ((le32_to_cpu(tx_ring[entry].status) & TRING_OWN) != 0) diff --git a/gpxe/src/drivers/net/etherfabric.c b/gpxe/src/drivers/net/etherfabric.c index 8a6b1a17..704ce98b 100644 --- a/gpxe/src/drivers/net/etherfabric.c +++ b/gpxe/src/drivers/net/etherfabric.c @@ -15,17 +15,22 @@ * ************************************************************************** */ - -#include "etherboot.h" -#include "nic.h" +#include <stdint.h> +#include <stdlib.h> +#include <unistd.h> #include <errno.h> +#include <assert.h> +#include <byteswap.h> +#include <console.h> +#include <gpxe/io.h> #include <gpxe/pci.h> -#include <gpxe/bitbash.h> -#include <gpxe/i2c.h> -#include <gpxe/spi.h> -#include <gpxe/nvo.h> -#define dma_addr_t unsigned long +#include <gpxe/malloc.h> +#include <gpxe/ethernet.h> +#include <gpxe/iobuf.h> +#include <gpxe/netdevice.h> +#include <gpxe/timer.h> #include "etherfabric.h" +#include "etherfabric_nic.h" /************************************************************************** * @@ -34,193 +39,35 @@ ************************************************************************** */ -#define EFAB_ASSERT(x) \ - do { \ - if ( ! (x) ) { \ - DBG ( "ASSERT(%s) failed at %s line %d [%s]\n", #x, \ - __FILE__, __LINE__, __FUNCTION__ ); \ - } \ - } while (0) - -#define EFAB_TRACE(...) DBG ( __VA_ARGS__ ) - #define EFAB_REGDUMP(...) +#define EFAB_TRACE(...) DBGP(__VA_ARGS__) -#define EFAB_LOG(...) printf ( __VA_ARGS__ ) -#define EFAB_ERR(...) printf ( __VA_ARGS__ ) - -#define FALCON_USE_IO_BAR 1 +// printf() is not allowed within drivers. Use DBG() instead. +#define EFAB_LOG(...) DBG(__VA_ARGS__) +#define EFAB_ERR(...) DBG(__VA_ARGS__) -/* - * EtherFabric constants - * - */ +#define FALCON_USE_IO_BAR 0 -/* PCI Definitions */ -#define EFAB_VENDID_LEVEL5 0x1924 -#define FALCON_P_DEVID 0x0703 /* Temporary PCI ID */ -#define EF1002_DEVID 0xC101 +#define HZ 100 +#define EFAB_BYTE 1 /************************************************************************** * - * Data structures + * Hardware data structures and sizing * ************************************************************************** */ +extern int __invalid_queue_size; +#define FQS(_prefix, _x) \ + ( ( (_x) == 512 ) ? _prefix ## _SIZE_512 : \ + ( ( (_x) == 1024 ) ? _prefix ## _SIZE_1K : \ + ( ( (_x) == 2048 ) ? _prefix ## _SIZE_2K : \ + ( ( (_x) == 4096) ? _prefix ## _SIZE_4K : \ + __invalid_queue_size ) ) ) ) -/* - * Buffers used for TX, RX and event queue - * - */ -#define EFAB_BUF_ALIGN 4096 -#define EFAB_DATA_BUF_SIZE 2048 -#define EFAB_RX_BUFS 16 -#define EFAB_RXD_SIZE 512 -#define EFAB_TXD_SIZE 512 -#define EFAB_EVQ_SIZE 512 -struct efab_buffers { - uint8_t eventq[4096]; - uint8_t rxd[4096]; - uint8_t txd[4096]; - uint8_t tx_buf[EFAB_DATA_BUF_SIZE]; - uint8_t rx_buf[EFAB_RX_BUFS][EFAB_DATA_BUF_SIZE]; - uint8_t padding[EFAB_BUF_ALIGN-1]; -}; -static struct efab_buffers efab_buffers; - -/** An RX buffer */ -struct efab_rx_buf { - uint8_t *addr; - unsigned int len; - int id; -}; - -/** A TX buffer */ -struct efab_tx_buf { - uint8_t *addr; - unsigned int len; - int id; -}; - -/** Etherfabric event type */ -enum efab_event_type { - EFAB_EV_NONE = 0, - EFAB_EV_TX, - EFAB_EV_RX, -}; - -/** Etherfabric event */ -struct efab_event { - /** Event type */ - enum efab_event_type type; - /** RX buffer ID */ - int rx_id; - /** RX length */ - unsigned int rx_len; - /** Packet should be dropped */ - int drop; -}; - -/* - * Etherfabric abstraction layer - * - */ -struct efab_nic; -struct efab_operations { - void ( * get_membase ) ( struct efab_nic *efab ); - int ( * reset ) ( struct efab_nic *efab ); - int ( * init_nic ) ( struct efab_nic *efab ); - int ( * read_eeprom ) ( struct efab_nic *efab ); - void ( * build_rx_desc ) ( struct efab_nic *efab, - struct efab_rx_buf *rx_buf ); - void ( * notify_rx_desc ) ( struct efab_nic *efab ); - void ( * build_tx_desc ) ( struct efab_nic *efab, - struct efab_tx_buf *tx_buf ); - void ( * notify_tx_desc ) ( struct efab_nic *efab ); - int ( * fetch_event ) ( struct efab_nic *efab, - struct efab_event *event ); - void ( * mask_irq ) ( struct efab_nic *efab, int enabled ); - void ( * generate_irq ) ( struct efab_nic *efab ); - void ( * mdio_write ) ( struct efab_nic *efab, int location, - int value ); - int ( * mdio_read ) ( struct efab_nic *efab, int location ); -}; - -struct efab_mac_operations { - void ( * mac_writel ) ( struct efab_nic *efab, efab_dword_t *value, - unsigned int mac_reg ); - void ( * mac_readl ) ( struct efab_nic *efab, efab_dword_t *value, - unsigned int mac_reg ); - int ( * init ) ( struct efab_nic *efab ); - int ( * reset ) ( struct efab_nic *efab ); -}; - -/* - * Driver private data structure - * - */ -struct efab_nic { - - /** PCI device */ - struct pci_device *pci; - - /** Operations table */ - struct efab_operations *op; - - /** MAC operations table */ - struct efab_mac_operations *mac_op; - /** Memory base */ - void *membase; - - /** I/O base */ - unsigned int iobase; - - /** Buffers */ - uint8_t *eventq; /* Falcon only */ - uint8_t *txd; /* Falcon only */ - uint8_t *rxd; /* Falcon only */ - struct efab_tx_buf tx_buf; - struct efab_rx_buf rx_bufs[EFAB_RX_BUFS]; - - /** Buffer pointers */ - unsigned int eventq_read_ptr; /* Falcon only */ - unsigned int tx_write_ptr; - unsigned int rx_write_ptr; - - /** Port 0/1 on the NIC */ - int port; - - /** MAC address */ - uint8_t mac_addr[ETH_ALEN]; - /** GMII link options */ - unsigned int link_options; - /** Link status */ - int link_up; - - /* Nic type fields */ - int has_flash : 1; - int has_eeprom : 1; - int is_10g : 1; - int is_dual : 1; - int is_asic : 1; - - /** INT_REG_KER for Falcon */ - efab_oword_t int_ker __attribute__ (( aligned ( 16 ) )); - - /** I2C access */ - struct i2c_bit_basher ef1002_i2c; - unsigned long ef1002_i2c_outputs; - struct i2c_device ef1002_eeprom; - - /** SPI access */ - struct spi_bus spi; - struct spi_device falcon_flash; - struct spi_device falcon_eeprom; - - /** Non-volatile options */ - struct nvo_block nvo; -}; +#define EFAB_MAX_FRAME_LEN(mtu) \ + ( ( ( ( mtu ) + 4/* FCS */ ) + 7 ) & ~7 ) /************************************************************************** * @@ -229,6 +76,10 @@ struct efab_nic { ************************************************************************** */ +static void falcon_mdio_write (struct efab_nic *efab, int device, + int location, int value ); +static int falcon_mdio_read ( struct efab_nic *efab, int device, int location ); + /* GMII registers */ #define MII_BMSR 0x01 /* Basic mode status register */ #define MII_ADVERTISE 0x04 /* Advertisement control register */ @@ -257,7 +108,8 @@ struct efab_nic { #define LPA_100 (LPA_100FULL | LPA_100HALF | LPA_100BASE4) #define LPA_1000 ( LPA_1000FULL | LPA_1000HALF ) #define LPA_10000 ( LPA_10000FULL | LPA_10000HALF ) -#define LPA_DUPLEX ( LPA_10FULL | LPA_100FULL | LPA_1000FULL ) +#define LPA_DUPLEX ( LPA_10FULL | LPA_100FULL | LPA_1000FULL | \ + LPA_10000FULL ) /* Mask of bits not associated with speed or duplexity. */ #define LPA_OTHER ~( LPA_10FULL | LPA_10HALF | LPA_100FULL | \ @@ -270,13 +122,15 @@ struct efab_nic { * Retrieve GMII autonegotiation advertised abilities * */ -static unsigned int gmii_autoneg_advertised ( struct efab_nic *efab ) { +static unsigned int +gmii_autoneg_advertised ( struct efab_nic *efab ) +{ unsigned int mii_advertise; unsigned int gmii_advertise; - + /* Extended bits are in bits 8 and 9 of GMII_GTCR */ - mii_advertise = efab->op->mdio_read ( efab, MII_ADVERTISE ); - gmii_advertise = ( ( efab->op->mdio_read ( efab, GMII_GTCR ) >> 8 ) + mii_advertise = falcon_mdio_read ( efab, 0, MII_ADVERTISE ); + gmii_advertise = ( ( falcon_mdio_read ( efab, 0, GMII_GTCR ) >> 8 ) & 0x03 ); return ( ( gmii_advertise << 16 ) | mii_advertise ); } @@ -285,13 +139,15 @@ static unsigned int gmii_autoneg_advertised ( struct efab_nic *efab ) { * Retrieve GMII autonegotiation link partner abilities * */ -static unsigned int gmii_autoneg_lpa ( struct efab_nic *efab ) { +static unsigned int +gmii_autoneg_lpa ( struct efab_nic *efab ) +{ unsigned int mii_lpa; unsigned int gmii_lpa; - + /* Extended bits are in bits 10 and 11 of GMII_GTSR */ - mii_lpa = efab->op->mdio_read ( efab, MII_LPA ); - gmii_lpa = ( efab->op->mdio_read ( efab, GMII_GTSR ) >> 10 ) & 0x03; + mii_lpa = falcon_mdio_read ( efab, 0, MII_LPA ); + gmii_lpa = ( falcon_mdio_read ( efab, 0, GMII_GTSR ) >> 10 ) & 0x03; return ( ( gmii_lpa << 16 ) | mii_lpa ); } @@ -299,7 +155,9 @@ static unsigned int gmii_autoneg_lpa ( struct efab_nic *efab ) { * Calculate GMII autonegotiated link technology * */ -static unsigned int gmii_nway_result ( unsigned int negotiated ) { +static unsigned int +gmii_nway_result ( unsigned int negotiated ) +{ unsigned int other_bits; /* Mask out the speed and duplexity bits */ @@ -324,1167 +182,244 @@ static unsigned int gmii_nway_result ( unsigned int negotiated ) { * Check GMII PHY link status * */ -static int gmii_link_ok ( struct efab_nic *efab ) { +static int +gmii_link_ok ( struct efab_nic *efab ) +{ int status; int phy_status; - + /* BMSR is latching - it returns "link down" if the link has * been down at any point since the last read. To get a * real-time status, we therefore read the register twice and * use the result of the second read. */ - efab->op->mdio_read ( efab, MII_BMSR ); - status = efab->op->mdio_read ( efab, MII_BMSR ); + (void) falcon_mdio_read ( efab, 0, MII_BMSR ); + status = falcon_mdio_read ( efab, 0, MII_BMSR ); /* Read the PHY-specific Status Register. This is * non-latching, so we need do only a single read. */ - phy_status = efab->op->mdio_read ( efab, GMII_PSSR ); + phy_status = falcon_mdio_read ( efab, 0, GMII_PSSR ); return ( ( status & BMSR_LSTATUS ) && ( phy_status & PSSR_LSTATUS ) ); } /************************************************************************** * - * Alaska PHY + * MDIO routines * ************************************************************************** */ -/** - * Initialise Alaska PHY - * - */ -static void alaska_init ( struct efab_nic *efab ) { - unsigned int advertised, lpa; - - /* Read link up status */ - efab->link_up = gmii_link_ok ( efab ); - - if ( ! efab->link_up ) - return; - - /* Determine link options from PHY. */ - advertised = gmii_autoneg_advertised ( efab ); - lpa = gmii_autoneg_lpa ( efab ); - efab->link_options = gmii_nway_result ( advertised & lpa ); - - /* print out the link speed */ - EFAB_LOG ( "%dMbps %s-duplex (%04x,%04x)\n", - ( efab->link_options & LPA_10000 ? 1000 : - ( efab->link_options & LPA_1000 ? 1000 : - ( efab->link_options & LPA_100 ? 100 : 10 ) ) ), - ( efab->link_options & LPA_DUPLEX ? "full" : "half" ), - advertised, lpa ); -} - - -/************************************************************************** - * - * Mentor MAC - * - ************************************************************************** - */ - -/* GMAC configuration register 1 */ -#define GM_CFG1_REG_MAC 0x00 -#define GM_SW_RST_LBN 31 -#define GM_SW_RST_WIDTH 1 -#define GM_RX_FC_EN_LBN 5 -#define GM_RX_FC_EN_WIDTH 1 -#define GM_TX_FC_EN_LBN 4 -#define GM_TX_FC_EN_WIDTH 1 -#define GM_RX_EN_LBN 2 -#define GM_RX_EN_WIDTH 1 -#define GM_TX_EN_LBN 0 -#define GM_TX_EN_WIDTH 1 - -/* GMAC configuration register 2 */ -#define GM_CFG2_REG_MAC 0x01 -#define GM_PAMBL_LEN_LBN 12 -#define GM_PAMBL_LEN_WIDTH 4 -#define GM_IF_MODE_LBN 8 -#define GM_IF_MODE_WIDTH 2 -#define GM_PAD_CRC_EN_LBN 2 -#define GM_PAD_CRC_EN_WIDTH 1 -#define GM_FD_LBN 0 -#define GM_FD_WIDTH 1 - -/* GMAC maximum frame length register */ -#define GM_MAX_FLEN_REG_MAC 0x04 -#define GM_MAX_FLEN_LBN 0 -#define GM_MAX_FLEN_WIDTH 16 - -/* GMAC MII management configuration register */ -#define GM_MII_MGMT_CFG_REG_MAC 0x08 -#define GM_MGMT_CLK_SEL_LBN 0 -#define GM_MGMT_CLK_SEL_WIDTH 3 - -/* GMAC MII management command register */ -#define GM_MII_MGMT_CMD_REG_MAC 0x09 -#define GM_MGMT_SCAN_CYC_LBN 1 -#define GM_MGMT_SCAN_CYC_WIDTH 1 -#define GM_MGMT_RD_CYC_LBN 0 -#define GM_MGMT_RD_CYC_WIDTH 1 - -/* GMAC MII management address register */ -#define GM_MII_MGMT_ADR_REG_MAC 0x0a -#define GM_MGMT_PHY_ADDR_LBN 8 -#define GM_MGMT_PHY_ADDR_WIDTH 5 -#define GM_MGMT_REG_ADDR_LBN 0 -#define GM_MGMT_REG_ADDR_WIDTH 5 - -/* GMAC MII management control register */ -#define GM_MII_MGMT_CTL_REG_MAC 0x0b -#define GM_MGMT_CTL_LBN 0 -#define GM_MGMT_CTL_WIDTH 16 - -/* GMAC MII management status register */ -#define GM_MII_MGMT_STAT_REG_MAC 0x0c -#define GM_MGMT_STAT_LBN 0 -#define GM_MGMT_STAT_WIDTH 16 - -/* GMAC MII management indicators register */ -#define GM_MII_MGMT_IND_REG_MAC 0x0d -#define GM_MGMT_BUSY_LBN 0 -#define GM_MGMT_BUSY_WIDTH 1 - -/* GMAC station address register 1 */ -#define GM_ADR1_REG_MAC 0x10 -#define GM_HWADDR_5_LBN 24 -#define GM_HWADDR_5_WIDTH 8 -#define GM_HWADDR_4_LBN 16 -#define GM_HWADDR_4_WIDTH 8 -#define GM_HWADDR_3_LBN 8 -#define GM_HWADDR_3_WIDTH 8 -#define GM_HWADDR_2_LBN 0 -#define GM_HWADDR_2_WIDTH 8 - -/* GMAC station address register 2 */ -#define GM_ADR2_REG_MAC 0x11 -#define GM_HWADDR_1_LBN 24 -#define GM_HWADDR_1_WIDTH 8 -#define GM_HWADDR_0_LBN 16 -#define GM_HWADDR_0_WIDTH 8 - -/* GMAC FIFO configuration register 0 */ -#define GMF_CFG0_REG_MAC 0x12 -#define GMF_FTFENREQ_LBN 12 -#define GMF_FTFENREQ_WIDTH 1 -#define GMF_STFENREQ_LBN 11 -#define GMF_STFENREQ_WIDTH 1 -#define GMF_FRFENREQ_LBN 10 -#define GMF_FRFENREQ_WIDTH 1 -#define GMF_SRFENREQ_LBN 9 -#define GMF_SRFENREQ_WIDTH 1 -#define GMF_WTMENREQ_LBN 8 -#define GMF_WTMENREQ_WIDTH 1 - -/* GMAC FIFO configuration register 1 */ -#define GMF_CFG1_REG_MAC 0x13 -#define GMF_CFGFRTH_LBN 16 -#define GMF_CFGFRTH_WIDTH 5 -#define GMF_CFGXOFFRTX_LBN 0 -#define GMF_CFGXOFFRTX_WIDTH 16 - -/* GMAC FIFO configuration register 2 */ -#define GMF_CFG2_REG_MAC 0x14 -#define GMF_CFGHWM_LBN 16 -#define GMF_CFGHWM_WIDTH 6 -#define GMF_CFGLWM_LBN 0 -#define GMF_CFGLWM_WIDTH 6 - -/* GMAC FIFO configuration register 3 */ -#define GMF_CFG3_REG_MAC 0x15 -#define GMF_CFGHWMFT_LBN 16 -#define GMF_CFGHWMFT_WIDTH 6 -#define GMF_CFGFTTH_LBN 0 -#define GMF_CFGFTTH_WIDTH 6 - -/* GMAC FIFO configuration register 4 */ -#define GMF_CFG4_REG_MAC 0x16 -#define GMF_HSTFLTRFRM_PAUSE_LBN 12 -#define GMF_HSTFLTRFRM_PAUSE_WIDTH 12 - -/* GMAC FIFO configuration register 5 */ -#define GMF_CFG5_REG_MAC 0x17 -#define GMF_CFGHDPLX_LBN 22 -#define GMF_CFGHDPLX_WIDTH 1 -#define GMF_CFGBYTMODE_LBN 19 -#define GMF_CFGBYTMODE_WIDTH 1 -#define GMF_HSTDRPLT64_LBN 18 -#define GMF_HSTDRPLT64_WIDTH 1 -#define GMF_HSTFLTRFRMDC_PAUSE_LBN 12 -#define GMF_HSTFLTRFRMDC_PAUSE_WIDTH 1 - -struct efab_mentormac_parameters { - int gmf_cfgfrth; - int gmf_cfgftth; - int gmf_cfghwmft; - int gmf_cfghwm; - int gmf_cfglwm; -}; - -/** - * Reset Mentor MAC - * - */ -static void mentormac_reset ( struct efab_nic *efab ) { - efab_dword_t reg; - int save_port; - - /* Take into reset */ - EFAB_POPULATE_DWORD_1 ( reg, GM_SW_RST, 1 ); - efab->mac_op->mac_writel ( efab, ®, GM_CFG1_REG_MAC ); - udelay ( 1000 ); - - /* Take out of reset */ - EFAB_POPULATE_DWORD_1 ( reg, GM_SW_RST, 0 ); - efab->mac_op->mac_writel ( efab, ®, GM_CFG1_REG_MAC ); - udelay ( 1000 ); - - /* Mentor MAC connects both PHYs to MAC 0 */ - save_port = efab->port; - efab->port = 0; - /* Configure GMII interface so PHY is accessible. Note that - * GMII interface is connected only to port 0, and that on - * Falcon this is a no-op. - */ - EFAB_POPULATE_DWORD_1 ( reg, GM_MGMT_CLK_SEL, 0x4 ); - efab->mac_op->mac_writel ( efab, ®, GM_MII_MGMT_CFG_REG_MAC ); - udelay ( 10 ); - efab->port = save_port; -} - -/** - * Initialise Mentor MAC - * - */ -static void mentormac_init ( struct efab_nic *efab, - struct efab_mentormac_parameters *params ) { - int pause, if_mode, full_duplex, bytemode, half_duplex; - efab_dword_t reg; - - /* Configuration register 1 */ - pause = ( efab->link_options & LPA_PAUSE ) ? 1 : 0; - if ( ! ( efab->link_options & LPA_DUPLEX ) ) { - /* Half-duplex operation requires TX flow control */ - pause = 1; +/* Numbering of the MDIO Manageable Devices (MMDs) */ +/* Physical Medium Attachment/ Physical Medium Dependent sublayer */ +#define MDIO_MMD_PMAPMD (1) +/* WAN Interface Sublayer */ +#define MDIO_MMD_WIS (2) +/* Physical Coding Sublayer */ +#define MDIO_MMD_PCS (3) +/* PHY Extender Sublayer */ +#define MDIO_MMD_PHYXS (4) +/* Extender Sublayer */ +#define MDIO_MMD_DTEXS (5) +/* Transmission convergence */ +#define MDIO_MMD_TC (6) +/* Auto negotiation */ +#define MDIO_MMD_AN (7) + +/* Generic register locations */ +#define MDIO_MMDREG_CTRL1 (0) +#define MDIO_MMDREG_STAT1 (1) +#define MDIO_MMDREG_DEVS0 (5) +#define MDIO_MMDREG_STAT2 (8) + +/* Bits in MMDREG_CTRL1 */ +/* Reset */ +#define MDIO_MMDREG_CTRL1_RESET_LBN (15) +#define MDIO_MMDREG_CTRL1_RESET_WIDTH (1) + +/* Bits in MMDREG_STAT1 */ +#define MDIO_MMDREG_STAT1_FAULT_LBN (7) +#define MDIO_MMDREG_STAT1_FAULT_WIDTH (1) + +/* Link state */ +#define MDIO_MMDREG_STAT1_LINK_LBN (2) +#define MDIO_MMDREG_STAT1_LINK_WIDTH (1) + +/* Bits in MMDREG_DEVS0. */ +#define DEV_PRESENT_BIT(_b) (1 << _b) + +#define MDIO_MMDREG_DEVS0_DTEXS DEV_PRESENT_BIT(MDIO_MMD_DTEXS) +#define MDIO_MMDREG_DEVS0_PHYXS DEV_PRESENT_BIT(MDIO_MMD_PHYXS) +#define MDIO_MMDREG_DEVS0_PCS DEV_PRESENT_BIT(MDIO_MMD_PCS) +#define MDIO_MMDREG_DEVS0_WIS DEV_PRESENT_BIT(MDIO_MMD_WIS) +#define MDIO_MMDREG_DEVS0_PMAPMD DEV_PRESENT_BIT(MDIO_MMD_PMAPMD) + +#define MDIO_MMDREG_DEVS0_AN DEV_PRESENT_BIT(MDIO_MMD_AN) + +/* Bits in MMDREG_STAT2 */ +#define MDIO_MMDREG_STAT2_PRESENT_VAL (2) +#define MDIO_MMDREG_STAT2_PRESENT_LBN (14) +#define MDIO_MMDREG_STAT2_PRESENT_WIDTH (2) + +/* PHY XGXS lane state */ +#define MDIO_PHYXS_LANE_STATE (0x18) +#define MDIO_PHYXS_LANE_ALIGNED_LBN (12) +#define MDIO_PHYXS_LANE_SYNC0_LBN (0) +#define MDIO_PHYXS_LANE_SYNC1_LBN (1) +#define MDIO_PHYXS_LANE_SYNC2_LBN (2) +#define MDIO_PHYXS_LANE_SYNC3_LBN (3) + +/* This ought to be ridiculous overkill. We expect it to fail rarely */ +#define MDIO45_RESET_TRIES 100 +#define MDIO45_RESET_SPINTIME 10 + +static int +mdio_clause45_wait_reset_mmds ( struct efab_nic* efab ) +{ + int tries = MDIO45_RESET_TRIES; + int in_reset; + + while(tries) { + int mask = efab->phy_op->mmds; + int mmd = 0; + in_reset = 0; + while(mask) { + if (mask & 1) { + int stat = falcon_mdio_read ( efab, mmd, + MDIO_MMDREG_CTRL1 ); + if (stat < 0) { + EFAB_ERR("Failed to read status of MMD %d\n", + mmd ); + in_reset = 1; + break; + } + if (stat & (1 << MDIO_MMDREG_CTRL1_RESET_LBN)) + in_reset |= (1 << mmd); + } + mask = mask >> 1; + mmd++; + } + if (!in_reset) + break; + tries--; + mdelay ( MDIO45_RESET_SPINTIME ); } - EFAB_POPULATE_DWORD_4 ( reg, - GM_TX_EN, 1, - GM_TX_FC_EN, pause, - GM_RX_EN, 1, - GM_RX_FC_EN, 1 ); - efab->mac_op->mac_writel ( efab, ®, GM_CFG1_REG_MAC ); - udelay ( 10 ); - - /* Configuration register 2 */ - if_mode = ( efab->link_options & LPA_1000 ) ? 2 : 1; - full_duplex = ( efab->link_options & LPA_DUPLEX ) ? 1 : 0; - EFAB_POPULATE_DWORD_4 ( reg, - GM_IF_MODE, if_mode, - GM_PAD_CRC_EN, 1, - GM_FD, full_duplex, - GM_PAMBL_LEN, 0x7 /* ? */ ); - efab->mac_op->mac_writel ( efab, ®, GM_CFG2_REG_MAC ); - udelay ( 10 ); - - /* Max frame len register */ - EFAB_POPULATE_DWORD_1 ( reg, GM_MAX_FLEN, ETH_FRAME_LEN + 4 /* FCS */); - efab->mac_op->mac_writel ( efab, ®, GM_MAX_FLEN_REG_MAC ); - udelay ( 10 ); - - /* FIFO configuration register 0 */ - EFAB_POPULATE_DWORD_5 ( reg, - GMF_FTFENREQ, 1, - GMF_STFENREQ, 1, - GMF_FRFENREQ, 1, - GMF_SRFENREQ, 1, - GMF_WTMENREQ, 1 ); - efab->mac_op->mac_writel ( efab, ®, GMF_CFG0_REG_MAC ); - udelay ( 10 ); - - /* FIFO configuration register 1 */ - EFAB_POPULATE_DWORD_2 ( reg, - GMF_CFGFRTH, params->gmf_cfgfrth, - GMF_CFGXOFFRTX, 0xffff ); - efab->mac_op->mac_writel ( efab, ®, GMF_CFG1_REG_MAC ); - udelay ( 10 ); - - /* FIFO configuration register 2 */ - EFAB_POPULATE_DWORD_2 ( reg, - GMF_CFGHWM, params->gmf_cfghwm, - GMF_CFGLWM, params->gmf_cfglwm ); - efab->mac_op->mac_writel ( efab, ®, GMF_CFG2_REG_MAC ); - udelay ( 10 ); - - /* FIFO configuration register 3 */ - EFAB_POPULATE_DWORD_2 ( reg, - GMF_CFGHWMFT, params->gmf_cfghwmft, - GMF_CFGFTTH, params->gmf_cfgftth ); - efab->mac_op->mac_writel ( efab, ®, GMF_CFG3_REG_MAC ); - udelay ( 10 ); - - /* FIFO configuration register 4 */ - EFAB_POPULATE_DWORD_1 ( reg, GMF_HSTFLTRFRM_PAUSE, 1 ); - efab->mac_op->mac_writel ( efab, ®, GMF_CFG4_REG_MAC ); - udelay ( 10 ); - - /* FIFO configuration register 5 */ - bytemode = ( efab->link_options & LPA_1000 ) ? 1 : 0; - half_duplex = ( efab->link_options & LPA_DUPLEX ) ? 0 : 1; - efab->mac_op->mac_readl ( efab, ®, GMF_CFG5_REG_MAC ); - EFAB_SET_DWORD_FIELD ( reg, GMF_CFGBYTMODE, bytemode ); - EFAB_SET_DWORD_FIELD ( reg, GMF_CFGHDPLX, half_duplex ); - EFAB_SET_DWORD_FIELD ( reg, GMF_HSTDRPLT64, half_duplex ); - EFAB_SET_DWORD_FIELD ( reg, GMF_HSTFLTRFRMDC_PAUSE, 0 ); - efab->mac_op->mac_writel ( efab, ®, GMF_CFG5_REG_MAC ); - udelay ( 10 ); - - /* MAC address */ - EFAB_POPULATE_DWORD_4 ( reg, - GM_HWADDR_5, efab->mac_addr[5], - GM_HWADDR_4, efab->mac_addr[4], - GM_HWADDR_3, efab->mac_addr[3], - GM_HWADDR_2, efab->mac_addr[2] ); - efab->mac_op->mac_writel ( efab, ®, GM_ADR1_REG_MAC ); - udelay ( 10 ); - EFAB_POPULATE_DWORD_2 ( reg, - GM_HWADDR_1, efab->mac_addr[1], - GM_HWADDR_0, efab->mac_addr[0] ); - efab->mac_op->mac_writel ( efab, ®, GM_ADR2_REG_MAC ); - udelay ( 10 ); -} - -/** - * Wait for GMII access to complete - * - */ -static int mentormac_gmii_wait ( struct efab_nic *efab ) { - int count; - efab_dword_t indicator; - - for ( count = 0 ; count < 1000 ; count++ ) { - udelay ( 10 ); - efab->mac_op->mac_readl ( efab, &indicator, - GM_MII_MGMT_IND_REG_MAC ); - if ( EFAB_DWORD_FIELD ( indicator, GM_MGMT_BUSY ) == 0 ) - return 1; + if (in_reset != 0) { + EFAB_ERR("Not all MMDs came out of reset in time. MMDs " + "still in reset: %x\n", in_reset); + return -ETIMEDOUT; } - EFAB_ERR ( "Timed out waiting for GMII\n" ); return 0; } -/** - * Write a GMII register - * - */ -static void mentormac_mdio_write ( struct efab_nic *efab, int phy_id, - int location, int value ) { - efab_dword_t reg; - int save_port; - - EFAB_TRACE ( "Writing GMII %d register %02x with %04x\n", phy_id, - location, value ); - - /* Mentor MAC connects both PHYs to MAC 0 */ - save_port = efab->port; - efab->port = 0; - - /* Check MII not currently being accessed */ - if ( ! mentormac_gmii_wait ( efab ) ) - goto out; - - /* Write the address register */ - EFAB_POPULATE_DWORD_2 ( reg, - GM_MGMT_PHY_ADDR, phy_id, - GM_MGMT_REG_ADDR, location ); - efab->mac_op->mac_writel ( efab, ®, GM_MII_MGMT_ADR_REG_MAC ); - udelay ( 10 ); - - /* Write data */ - EFAB_POPULATE_DWORD_1 ( reg, GM_MGMT_CTL, value ); - efab->mac_op->mac_writel ( efab, ®, GM_MII_MGMT_CTL_REG_MAC ); - - /* Wait for data to be written */ - mentormac_gmii_wait ( efab ); - - out: - /* Restore efab->port */ - efab->port = save_port; -} - -/** - * Read a GMII register - * - */ -static int mentormac_mdio_read ( struct efab_nic *efab, int phy_id, - int location ) { - efab_dword_t reg; - int value = 0xffff; - int save_port; - - /* Mentor MAC connects both PHYs to MAC 0 */ - save_port = efab->port; - efab->port = 0; - - /* Check MII not currently being accessed */ - if ( ! mentormac_gmii_wait ( efab ) ) - goto out; - - /* Write the address register */ - EFAB_POPULATE_DWORD_2 ( reg, - GM_MGMT_PHY_ADDR, phy_id, - GM_MGMT_REG_ADDR, location ); - efab->mac_op->mac_writel ( efab, ®, GM_MII_MGMT_ADR_REG_MAC ); - udelay ( 10 ); - - /* Request data to be read */ - EFAB_POPULATE_DWORD_1 ( reg, GM_MGMT_RD_CYC, 1 ); - efab->mac_op->mac_writel ( efab, ®, GM_MII_MGMT_CMD_REG_MAC ); - - /* Wait for data to be become available */ - if ( mentormac_gmii_wait ( efab ) ) { - /* Read data */ - efab->mac_op->mac_readl ( efab, ®, GM_MII_MGMT_STAT_REG_MAC ); - value = EFAB_DWORD_FIELD ( reg, GM_MGMT_STAT ); - EFAB_TRACE ( "Read from GMII %d register %02x, got %04x\n", - phy_id, location, value ); - } - - /* Signal completion */ - EFAB_ZERO_DWORD ( reg ); - efab->mac_op->mac_writel ( efab, ®, GM_MII_MGMT_CMD_REG_MAC ); - udelay ( 10 ); - - out: - /* Restore efab->port */ - efab->port = save_port; - - return value; -} - -/************************************************************************** - * - * EF1002 routines - * - ************************************************************************** - */ - -/** Control and General Status */ -#define EF1_CTR_GEN_STATUS0_REG 0x0 -#define EF1_MASTER_EVENTS_LBN 12 -#define EF1_MASTER_EVENTS_WIDTH 1 -#define EF1_TX_ENGINE_EN_LBN 19 -#define EF1_TX_ENGINE_EN_WIDTH 1 -#define EF1_RX_ENGINE_EN_LBN 18 -#define EF1_RX_ENGINE_EN_WIDTH 1 -#define EF1_TURBO2_LBN 17 -#define EF1_TURBO2_WIDTH 1 -#define EF1_TURBO1_LBN 16 -#define EF1_TURBO1_WIDTH 1 -#define EF1_TURBO3_LBN 14 -#define EF1_TURBO3_WIDTH 1 -#define EF1_LB_RESET_LBN 3 -#define EF1_LB_RESET_WIDTH 1 -#define EF1_MAC_RESET_LBN 2 -#define EF1_MAC_RESET_WIDTH 1 -#define EF1_CAM_ENABLE_LBN 1 -#define EF1_CAM_ENABLE_WIDTH 1 - -/** IRQ sources */ -#define EF1_IRQ_SRC_REG 0x0008 - -/** IRQ mask */ -#define EF1_IRQ_MASK_REG 0x000c -#define EF1_IRQ_PHY1_LBN 11 -#define EF1_IRQ_PHY1_WIDTH 1 -#define EF1_IRQ_PHY0_LBN 10 -#define EF1_IRQ_PHY0_WIDTH 1 -#define EF1_IRQ_SERR_LBN 7 -#define EF1_IRQ_SERR_WIDTH 1 -#define EF1_IRQ_EVQ_LBN 3 -#define EF1_IRQ_EVQ_WIDTH 1 - -/** Event generation */ -#define EF1_EVT3_REG 0x38 - -/** EEPROMaccess */ -#define EF1_EEPROM_REG 0x40 -#define EF1_EEPROM_SDA_LBN 31 -#define EF1_EEPROM_SDA_WIDTH 1 -#define EF1_EEPROM_SCL_LBN 30 -#define EF1_EEPROM_SCL_WIDTH 1 -#define EF1_JTAG_DISCONNECT_LBN 17 -#define EF1_JTAG_DISCONNECT_WIDTH 1 -#define EF1_EEPROM_LBN 0 -#define EF1_EEPROM_WIDTH 32 - -/** Control register 2 */ -#define EF1_CTL2_REG 0x4c -#define EF1_PLL_TRAP_LBN 31 -#define EF1_PLL_TRAP_WIDTH 1 -#define EF1_MEM_MAP_4MB_LBN 11 -#define EF1_MEM_MAP_4MB_WIDTH 1 -#define EF1_EV_INTR_CLR_WRITE_LBN 6 -#define EF1_EV_INTR_CLR_WRITE_WIDTH 1 -#define EF1_BURST_MERGE_LBN 5 -#define EF1_BURST_MERGE_WIDTH 1 -#define EF1_CLEAR_NULL_PAD_LBN 4 -#define EF1_CLEAR_NULL_PAD_WIDTH 1 -#define EF1_SW_RESET_LBN 2 -#define EF1_SW_RESET_WIDTH 1 -#define EF1_INTR_AFTER_EVENT_LBN 1 -#define EF1_INTR_AFTER_EVENT_WIDTH 1 - -/** Event FIFO */ -#define EF1_EVENT_FIFO_REG 0x50 - -/** Event FIFO count */ -#define EF1_EVENT_FIFO_COUNT_REG 0x5c -#define EF1_EV_COUNT_LBN 0 -#define EF1_EV_COUNT_WIDTH 16 - -/** TX DMA control and status */ -#define EF1_DMA_TX_CSR_REG 0x80 -#define EF1_DMA_TX_CSR_CHAIN_EN_LBN 8 -#define EF1_DMA_TX_CSR_CHAIN_EN_WIDTH 1 -#define EF1_DMA_TX_CSR_ENABLE_LBN 4 -#define EF1_DMA_TX_CSR_ENABLE_WIDTH 1 -#define EF1_DMA_TX_CSR_INT_EN_LBN 0 -#define EF1_DMA_TX_CSR_INT_EN_WIDTH 1 - -/** RX DMA control and status */ -#define EF1_DMA_RX_CSR_REG 0xa0 -#define EF1_DMA_RX_ABOVE_1GB_EN_LBN 6 -#define EF1_DMA_RX_ABOVE_1GB_EN_WIDTH 1 -#define EF1_DMA_RX_BELOW_1MB_EN_LBN 5 -#define EF1_DMA_RX_BELOW_1MB_EN_WIDTH 1 -#define EF1_DMA_RX_CSR_ENABLE_LBN 0 -#define EF1_DMA_RX_CSR_ENABLE_WIDTH 1 - -/** Level 5 watermark register (in MAC space) */ -#define EF1_GMF_L5WM_REG_MAC 0x20 -#define EF1_L5WM_LBN 0 -#define EF1_L5WM_WIDTH 32 - -/** MAC clock */ -#define EF1_GM_MAC_CLK_REG 0x112000 -#define EF1_GM_PORT0_MAC_CLK_LBN 0 -#define EF1_GM_PORT0_MAC_CLK_WIDTH 1 -#define EF1_GM_PORT1_MAC_CLK_LBN 1 -#define EF1_GM_PORT1_MAC_CLK_WIDTH 1 - -/** TX descriptor FIFO */ -#define EF1_TX_DESC_FIFO 0x141000 -#define EF1_TX_KER_EVQ_LBN 80 -#define EF1_TX_KER_EVQ_WIDTH 12 -#define EF1_TX_KER_IDX_LBN 64 -#define EF1_TX_KER_IDX_WIDTH 16 -#define EF1_TX_KER_MODE_LBN 63 -#define EF1_TX_KER_MODE_WIDTH 1 -#define EF1_TX_KER_PORT_LBN 60 -#define EF1_TX_KER_PORT_WIDTH 1 -#define EF1_TX_KER_CONT_LBN 56 -#define EF1_TX_KER_CONT_WIDTH 1 -#define EF1_TX_KER_BYTE_CNT_LBN 32 -#define EF1_TX_KER_BYTE_CNT_WIDTH 24 -#define EF1_TX_KER_BUF_ADR_LBN 0 -#define EF1_TX_KER_BUF_ADR_WIDTH 32 - -/** TX descriptor FIFO flush */ -#define EF1_TX_DESC_FIFO_FLUSH 0x141ffc - -/** RX descriptor FIFO */ -#define EF1_RX_DESC_FIFO 0x145000 -#define EF1_RX_KER_EVQ_LBN 48 -#define EF1_RX_KER_EVQ_WIDTH 12 -#define EF1_RX_KER_IDX_LBN 32 -#define EF1_RX_KER_IDX_WIDTH 16 -#define EF1_RX_KER_BUF_ADR_LBN 0 -#define EF1_RX_KER_BUF_ADR_WIDTH 32 - -/** RX descriptor FIFO flush */ -#define EF1_RX_DESC_FIFO_FLUSH 0x145ffc - -/** CAM */ -#define EF1_CAM_BASE 0x1c0000 -#define EF1_CAM_WTF_DOES_THIS_DO_LBN 0 -#define EF1_CAM_WTF_DOES_THIS_DO_WIDTH 32 - -/** Event queue pointers */ -#define EF1_EVQ_PTR_BASE 0x260000 -#define EF1_EVQ_SIZE_LBN 29 -#define EF1_EVQ_SIZE_WIDTH 2 -#define EF1_EVQ_SIZE_4K 3 -#define EF1_EVQ_SIZE_2K 2 -#define EF1_EVQ_SIZE_1K 1 -#define EF1_EVQ_SIZE_512 0 -#define EF1_EVQ_BUF_BASE_ID_LBN 0 -#define EF1_EVQ_BUF_BASE_ID_WIDTH 29 - -/* MAC registers */ -#define EF1002_MAC_REGBANK 0x110000 -#define EF1002_MAC_REGBANK_SIZE 0x1000 -#define EF1002_MAC_REG_SIZE 0x08 - -/** Offset of a MAC register within EF1002 */ -#define EF1002_MAC_REG( efab, mac_reg ) \ - ( EF1002_MAC_REGBANK + \ - ( (efab)->port * EF1002_MAC_REGBANK_SIZE ) + \ - ( (mac_reg) * EF1002_MAC_REG_SIZE ) ) - -/* Event queue entries */ -#define EF1_EV_CODE_LBN 20 -#define EF1_EV_CODE_WIDTH 8 -#define EF1_RX_EV_DECODE 0x01 -#define EF1_TX_EV_DECODE 0x02 -#define EF1_TIMER_EV_DECODE 0x0b -#define EF1_DRV_GEN_EV_DECODE 0x0f - -/* Receive events */ -#define EF1_RX_EV_LEN_LBN 48 -#define EF1_RX_EV_LEN_WIDTH 16 -#define EF1_RX_EV_PORT_LBN 17 -#define EF1_RX_EV_PORT_WIDTH 3 -#define EF1_RX_EV_OK_LBN 16 -#define EF1_RX_EV_OK_WIDTH 1 -#define EF1_RX_EV_IDX_LBN 0 -#define EF1_RX_EV_IDX_WIDTH 16 - -/* Transmit events */ -#define EF1_TX_EV_PORT_LBN 17 -#define EF1_TX_EV_PORT_WIDTH 3 -#define EF1_TX_EV_OK_LBN 16 -#define EF1_TX_EV_OK_WIDTH 1 -#define EF1_TX_EV_IDX_LBN 0 -#define EF1_TX_EV_IDX_WIDTH 16 - -/* forward decleration */ -static struct efab_mac_operations ef1002_mac_operations; - -/* I2C ID of the EEPROM */ -#define EF1_EEPROM_I2C_ID 0x50 - -/* Offset of MAC address within EEPROM */ -#define EF1_EEPROM_HWADDR_OFFSET 0x0 - -/** - * Write dword to EF1002 register - * - */ -static inline void ef1002_writel ( struct efab_nic *efab, efab_dword_t *value, - unsigned int reg ) { - EFAB_REGDUMP ( "Writing register %x with " EFAB_DWORD_FMT "\n", - reg, EFAB_DWORD_VAL ( *value ) ); - writel ( value->u32[0], efab->membase + reg ); -} - -/** - * Read dword from an EF1002 register - * - */ -static inline void ef1002_readl ( struct efab_nic *efab, efab_dword_t *value, - unsigned int reg ) { - value->u32[0] = readl ( efab->membase + reg ); - EFAB_REGDUMP ( "Read from register %x, got " EFAB_DWORD_FMT "\n", - reg, EFAB_DWORD_VAL ( *value ) ); -} - -/** - * Read dword from an EF1002 register, silently - * - */ -static inline void ef1002_readl_silent ( struct efab_nic *efab, - efab_dword_t *value, - unsigned int reg ) { - value->u32[0] = readl ( efab->membase + reg ); -} - -/** - * Get memory base - * - */ -static void ef1002_get_membase ( struct efab_nic *efab ) { - unsigned long membase_phys; - - membase_phys = pci_bar_start ( efab->pci, PCI_BASE_ADDRESS_0 ); - efab->membase = ioremap ( membase_phys, 0x800000 ); -} - -/** PCI registers to backup/restore over a device reset */ -static const unsigned int efab_pci_reg_addr[] = { - PCI_COMMAND, 0x0c /* PCI_CACHE_LINE_SIZE */, - PCI_BASE_ADDRESS_0, PCI_BASE_ADDRESS_1, PCI_BASE_ADDRESS_2, - PCI_BASE_ADDRESS_3, PCI_ROM_ADDRESS, PCI_INTERRUPT_LINE, -}; -/** Number of registers in efab_pci_reg_addr */ -#define EFAB_NUM_PCI_REG \ - ( sizeof ( efab_pci_reg_addr ) / sizeof ( efab_pci_reg_addr[0] ) ) -/** PCI configuration space backup */ -struct efab_pci_reg { - uint32_t reg[EFAB_NUM_PCI_REG]; -}; - -/* - * I2C interface and EEPROM - * - */ - -static unsigned long ef1002_i2c_bits[] = { - [I2C_BIT_SCL] = ( 1 << 30 ), - [I2C_BIT_SDA] = ( 1 << 31 ), -}; - -static void ef1002_i2c_write_bit ( struct bit_basher *basher, - unsigned int bit_id, unsigned long data ) { - struct efab_nic *efab = container_of ( basher, struct efab_nic, - ef1002_i2c.basher ); - unsigned long mask; - efab_dword_t reg; +static int +mdio_clause45_reset_mmd ( struct efab_nic *efab, int mmd ) +{ + int tries = MDIO45_RESET_TRIES; + int ctrl; - mask = ef1002_i2c_bits[bit_id]; - efab->ef1002_i2c_outputs &= ~mask; - efab->ef1002_i2c_outputs |= ( data & mask ); - EFAB_POPULATE_DWORD_1 ( reg, EF1_EEPROM, efab->ef1002_i2c_outputs ); - ef1002_writel ( efab, ®, EF1_EEPROM_REG ); -} + falcon_mdio_write ( efab, mmd, MDIO_MMDREG_CTRL1, + ( 1 << MDIO_MMDREG_CTRL1_RESET_LBN ) ); -static int ef1002_i2c_read_bit ( struct bit_basher *basher, - unsigned int bit_id ) { - struct efab_nic *efab = container_of ( basher, struct efab_nic, - ef1002_i2c.basher ); - unsigned long mask; - efab_dword_t reg; + /* Wait for the reset bit to clear. */ + do { + mdelay ( MDIO45_RESET_SPINTIME ); - mask = ef1002_i2c_bits[bit_id]; - ef1002_readl ( efab, ®, EF1_EEPROM_REG ); - return ( EFAB_DWORD_FIELD ( reg, EF1_EEPROM ) & mask ); -} + ctrl = falcon_mdio_read ( efab, mmd, MDIO_MMDREG_CTRL1 ); + if ( ~ctrl & ( 1 << MDIO_MMDREG_CTRL1_RESET_LBN ) ) + return 0; + } while ( --tries ); -static struct bit_basher_operations ef1002_basher_ops = { - .read = ef1002_i2c_read_bit, - .write = ef1002_i2c_write_bit, -}; + EFAB_ERR ( "Failed to reset mmd %d\n", mmd ); -static void ef1002_init_eeprom ( struct efab_nic *efab ) { - efab->ef1002_i2c.basher.op = &ef1002_basher_ops; - init_i2c_bit_basher ( &efab->ef1002_i2c ); - efab->ef1002_eeprom.address = EF1_EEPROM_I2C_ID; + return -ETIMEDOUT; } -/** - * Reset device - * - */ -static int ef1002_reset ( struct efab_nic *efab ) { - struct efab_pci_reg pci_reg; - struct pci_device *pci_dev = efab->pci; - efab_dword_t reg; - unsigned int i; - uint32_t tmp; - - /* Back up PCI configuration registers */ - for ( i = 0 ; i < EFAB_NUM_PCI_REG ; i++ ) { - pci_read_config_dword ( pci_dev, efab_pci_reg_addr[i], - &pci_reg.reg[i] ); - } - - /* Reset the whole device. */ - EFAB_POPULATE_DWORD_1 ( reg, EF1_SW_RESET, 1 ); - ef1002_writel ( efab, ®, EF1_CTL2_REG ); - mdelay ( 200 ); - - /* Restore PCI configuration space */ - for ( i = 0 ; i < EFAB_NUM_PCI_REG ; i++ ) { - pci_write_config_dword ( pci_dev, efab_pci_reg_addr[i], - pci_reg.reg[i] ); - } - - /* Verify PCI configuration space */ - for ( i = 0 ; i < EFAB_NUM_PCI_REG ; i++ ) { - pci_read_config_dword ( pci_dev, efab_pci_reg_addr[i], &tmp ); - if ( tmp != pci_reg.reg[i] ) { - EFAB_LOG ( "PCI restore failed on register %02x " - "(is %08lx, should be %08lx); reboot\n", - i, tmp, pci_reg.reg[i] ); - return 0; +static int +mdio_clause45_links_ok(struct efab_nic *efab ) +{ + int status, good; + int ok = 1; + int mmd = 0; + int mmd_mask = efab->phy_op->mmds; + + while (mmd_mask) { + if (mmd_mask & 1) { + /* Double reads because link state is latched, and a + * read moves the current state into the register */ + status = falcon_mdio_read ( efab, mmd, + MDIO_MMDREG_STAT1 ); + status = falcon_mdio_read ( efab, mmd, + MDIO_MMDREG_STAT1 ); + + good = status & (1 << MDIO_MMDREG_STAT1_LINK_LBN); + ok = ok && good; } + mmd_mask = (mmd_mask >> 1); + mmd++; } - - /* Verify device reset complete */ - ef1002_readl ( efab, ®, EF1_CTR_GEN_STATUS0_REG ); - if ( EFAB_DWORD_IS_ALL_ONES ( reg ) ) { - EFAB_ERR ( "Reset failed\n" ); - return 0; - } - - return 1; -} - -/** - * Initialise NIC - * - */ -static int ef1002_init_nic ( struct efab_nic *efab ) { - efab_dword_t reg; - - /* patch in the MAC operations */ - efab->mac_op = &ef1002_mac_operations; - - /* No idea what CAM is, but the 'datasheet' says that we have - * to write these values in at start of day - */ - EFAB_POPULATE_DWORD_1 ( reg, EF1_CAM_WTF_DOES_THIS_DO, 0x6 ); - ef1002_writel ( efab, ®, EF1_CAM_BASE + 0x20018 ); - udelay ( 1000 ); - EFAB_POPULATE_DWORD_1 ( reg, EF1_CAM_WTF_DOES_THIS_DO, 0x01000000 ); - ef1002_writel ( efab, ®, EF1_CAM_BASE + 0x00018 ); - udelay ( 1000 ); - - /* General control register 0 */ - ef1002_readl ( efab, ®, EF1_CTR_GEN_STATUS0_REG ); - EFAB_SET_DWORD_FIELD ( reg, EF1_MASTER_EVENTS, 0 ); - EFAB_SET_DWORD_FIELD ( reg, EF1_TX_ENGINE_EN, 0 ); - EFAB_SET_DWORD_FIELD ( reg, EF1_RX_ENGINE_EN, 0 ); - EFAB_SET_DWORD_FIELD ( reg, EF1_TURBO2, 1 ); - EFAB_SET_DWORD_FIELD ( reg, EF1_TURBO1, 1 ); - EFAB_SET_DWORD_FIELD ( reg, EF1_TURBO3, 1 ); - EFAB_SET_DWORD_FIELD ( reg, EF1_CAM_ENABLE, 1 ); - ef1002_writel ( efab, ®, EF1_CTR_GEN_STATUS0_REG ); - udelay ( 1000 ); - - /* General control register 2 */ - ef1002_readl ( efab, ®, EF1_CTL2_REG ); - EFAB_SET_DWORD_FIELD ( reg, EF1_PLL_TRAP, 1 ); - EFAB_SET_DWORD_FIELD ( reg, EF1_MEM_MAP_4MB, 0 ); - EFAB_SET_DWORD_FIELD ( reg, EF1_EV_INTR_CLR_WRITE, 0 ); - EFAB_SET_DWORD_FIELD ( reg, EF1_BURST_MERGE, 0 ); - EFAB_SET_DWORD_FIELD ( reg, EF1_CLEAR_NULL_PAD, 1 ); - EFAB_SET_DWORD_FIELD ( reg, EF1_INTR_AFTER_EVENT, 1 ); - ef1002_writel ( efab, ®, EF1_CTL2_REG ); - udelay ( 1000 ); - - /* Enable RX DMA */ - ef1002_readl ( efab, ®, EF1_DMA_RX_CSR_REG ); - EFAB_SET_DWORD_FIELD ( reg, EF1_DMA_RX_CSR_ENABLE, 1 ); - EFAB_SET_DWORD_FIELD ( reg, EF1_DMA_RX_BELOW_1MB_EN, 1 ); - EFAB_SET_DWORD_FIELD ( reg, EF1_DMA_RX_ABOVE_1GB_EN, 1 ); - ef1002_writel ( efab, ®, EF1_DMA_RX_CSR_REG ); - udelay ( 1000 ); - - /* Enable TX DMA */ - ef1002_readl ( efab, ®, EF1_DMA_TX_CSR_REG ); - EFAB_SET_DWORD_FIELD ( reg, EF1_DMA_TX_CSR_CHAIN_EN, 1 ); - EFAB_SET_DWORD_FIELD ( reg, EF1_DMA_TX_CSR_ENABLE, 0 /* ?? */ ); - EFAB_SET_DWORD_FIELD ( reg, EF1_DMA_TX_CSR_INT_EN, 0 /* ?? */ ); - ef1002_writel ( efab, ®, EF1_DMA_TX_CSR_REG ); - udelay ( 1000 ); - - /* Disconnect the JTAG chain. Read-modify-write is impossible - * on the I2C control bits, since reading gives the state of - * the line inputs rather than the last written state. - */ - ef1002_readl ( efab, ®, EF1_EEPROM_REG ); - EFAB_SET_DWORD_FIELD ( reg, EF1_EEPROM_SDA, 1 ); - EFAB_SET_DWORD_FIELD ( reg, EF1_EEPROM_SCL, 1 ); - EFAB_SET_DWORD_FIELD ( reg, EF1_JTAG_DISCONNECT, 1 ); - ef1002_writel ( efab, ®, EF1_EEPROM_REG ); - udelay ( 10 ); - - /* Flush descriptor queues */ - EFAB_ZERO_DWORD ( reg ); - ef1002_writel ( efab, ®, EF1_RX_DESC_FIFO_FLUSH ); - ef1002_writel ( efab, ®, EF1_TX_DESC_FIFO_FLUSH ); - wmb(); - udelay ( 10000 ); - - /* Reset MAC */ - efab->mac_op->reset ( efab ); - - /* Attach I2C bus */ - ef1002_init_eeprom ( efab ); - - return 1; -} - -/** - * Read MAC address from EEPROM - * - */ -static int ef1002_read_eeprom ( struct efab_nic *efab ) { - struct i2c_interface *i2c = &efab->ef1002_i2c.i2c; - struct i2c_device *i2cdev = &efab->ef1002_eeprom; - - if ( i2c->read ( i2c, i2cdev, EF1_EEPROM_HWADDR_OFFSET, - efab->mac_addr, sizeof ( efab->mac_addr ) ) != 0 ) - return 0; - - efab->mac_addr[ETH_ALEN-1] += efab->port; - - return 1; -} - -/** RX descriptor */ -typedef efab_qword_t ef1002_rx_desc_t; - -/** - * Build RX descriptor - * - */ -static void ef1002_build_rx_desc ( struct efab_nic *efab, - struct efab_rx_buf *rx_buf ) { - ef1002_rx_desc_t rxd; - - EFAB_POPULATE_QWORD_3 ( rxd, - EF1_RX_KER_EVQ, 0, - EF1_RX_KER_IDX, rx_buf->id, - EF1_RX_KER_BUF_ADR, - virt_to_bus ( rx_buf->addr ) ); - ef1002_writel ( efab, &rxd.dword[0], EF1_RX_DESC_FIFO + 0 ); - wmb(); - ef1002_writel ( efab, &rxd.dword[1], EF1_RX_DESC_FIFO + 4 ); - udelay ( 10 ); -} - -/** - * Update RX descriptor write pointer - * - */ -static void ef1002_notify_rx_desc ( struct efab_nic *efab __unused ) { - /* Nothing to do */ + return ok; } -/** TX descriptor */ -typedef efab_oword_t ef1002_tx_desc_t; - -/** - * Build TX descriptor - * - */ -static void ef1002_build_tx_desc ( struct efab_nic *efab, - struct efab_tx_buf *tx_buf ) { - ef1002_tx_desc_t txd; - - EFAB_POPULATE_OWORD_7 ( txd, - EF1_TX_KER_EVQ, 0, - EF1_TX_KER_IDX, tx_buf->id, - EF1_TX_KER_MODE, 0 /* IP mode */, - EF1_TX_KER_PORT, efab->port, - EF1_TX_KER_CONT, 0, - EF1_TX_KER_BYTE_CNT, tx_buf->len, - EF1_TX_KER_BUF_ADR, - virt_to_bus ( tx_buf->addr ) ); - - ef1002_writel ( efab, &txd.dword[0], EF1_TX_DESC_FIFO + 0 ); - ef1002_writel ( efab, &txd.dword[1], EF1_TX_DESC_FIFO + 4 ); - wmb(); - ef1002_writel ( efab, &txd.dword[2], EF1_TX_DESC_FIFO + 8 ); - udelay ( 10 ); -} - -/** - * Update TX descriptor write pointer - * - */ -static void ef1002_notify_tx_desc ( struct efab_nic *efab __unused ) { - /* Nothing to do */ -} - -/** An event */ -typedef efab_qword_t ef1002_event_t; - -/** - * Retrieve event from event queue - * - */ -static int ef1002_fetch_event ( struct efab_nic *efab, - struct efab_event *event ) { - efab_dword_t reg; - int ev_code; - int words; - - /* Check event FIFO depth */ - ef1002_readl_silent ( efab, ®, EF1_EVENT_FIFO_COUNT_REG ); - words = EFAB_DWORD_FIELD ( reg, EF1_EV_COUNT ); - if ( ! words ) - return 0; - - /* Read event data */ - ef1002_readl ( efab, ®, EF1_EVENT_FIFO_REG ); - DBG ( "Event is " EFAB_DWORD_FMT "\n", EFAB_DWORD_VAL ( reg ) ); - - /* Decode event */ - ev_code = EFAB_DWORD_FIELD ( reg, EF1_EV_CODE ); - event->drop = 0; - switch ( ev_code ) { - case EF1_TX_EV_DECODE: - event->type = EFAB_EV_TX; - break; - case EF1_RX_EV_DECODE: - event->type = EFAB_EV_RX; - event->rx_id = EFAB_DWORD_FIELD ( reg, EF1_RX_EV_IDX ); - /* RX len not available via event FIFO */ - event->rx_len = ETH_FRAME_LEN; - break; - case EF1_TIMER_EV_DECODE: - /* These are safe to ignore. We seem to get some at - * start of day, presumably due to the timers starting - * up with random contents. - */ - event->type = EFAB_EV_NONE; - break; - default: - EFAB_ERR ( "Unknown event type %d\n", ev_code ); - event->type = EFAB_EV_NONE; +static int +mdio_clause45_check_mmds ( struct efab_nic *efab ) +{ + int mmd = 0; + int devices = falcon_mdio_read ( efab, MDIO_MMD_PHYXS, + MDIO_MMDREG_DEVS0 ); + int mmd_mask = efab->phy_op->mmds; + + /* Check all the expected MMDs are present */ + if ( devices < 0 ) { + EFAB_ERR ( "Failed to read devices present\n" ); + return -EIO; } - - /* Clear any pending interrupts */ - ef1002_readl ( efab, ®, EF1_IRQ_SRC_REG ); - - return 1; -} - -/** - * Enable/disable interrupts - * - */ -static void ef1002_mask_irq ( struct efab_nic *efab, int enabled ) { - efab_dword_t irq_mask; - - EFAB_POPULATE_DWORD_2 ( irq_mask, - EF1_IRQ_SERR, enabled, - EF1_IRQ_EVQ, enabled ); - ef1002_writel ( efab, &irq_mask, EF1_IRQ_MASK_REG ); -} - -/** - * Generate interrupt - * - */ -static void ef1002_generate_irq ( struct efab_nic *efab ) { - ef1002_event_t test_event; - - EFAB_POPULATE_QWORD_1 ( test_event, - EF1_EV_CODE, EF1_DRV_GEN_EV_DECODE ); - ef1002_writel ( efab, &test_event.dword[0], EF1_EVT3_REG ); -} - -/** - * Write dword to an EF1002 MAC register - * - */ -static void ef1002_mac_writel ( struct efab_nic *efab, - efab_dword_t *value, unsigned int mac_reg ) { - ef1002_writel ( efab, value, EF1002_MAC_REG ( efab, mac_reg ) ); -} - -/** - * Read dword from an EF1002 MAC register - * - */ -static void ef1002_mac_readl ( struct efab_nic *efab, - efab_dword_t *value, unsigned int mac_reg ) { - ef1002_readl ( efab, value, EF1002_MAC_REG ( efab, mac_reg ) ); -} - -/** - * Initialise MAC - * - */ -static int ef1002_init_mac ( struct efab_nic *efab ) { - static struct efab_mentormac_parameters ef1002_mentormac_params = { - .gmf_cfgfrth = 0x13, - .gmf_cfgftth = 0x10, - .gmf_cfghwmft = 0x555, - .gmf_cfghwm = 0x2a, - .gmf_cfglwm = 0x15, - }; - efab_dword_t reg; - unsigned int mac_clk; - - /* Initialise PHY */ - alaska_init ( efab ); - - /* Initialise MAC */ - mentormac_init ( efab, &ef1002_mentormac_params ); - - /* Write Level 5 watermark register */ - EFAB_POPULATE_DWORD_1 ( reg, EF1_L5WM, 0x10040000 ); - efab->mac_op->mac_writel ( efab, ®, EF1_GMF_L5WM_REG_MAC ); - udelay ( 10 ); - - /* Set MAC clock speed */ - ef1002_readl ( efab, ®, EF1_GM_MAC_CLK_REG ); - mac_clk = ( efab->link_options & LPA_1000 ) ? 0 : 1; - if ( efab->port == 0 ) { - EFAB_SET_DWORD_FIELD ( reg, EF1_GM_PORT0_MAC_CLK, mac_clk ); - } else { - EFAB_SET_DWORD_FIELD ( reg, EF1_GM_PORT1_MAC_CLK, mac_clk ); + if ( ( devices & mmd_mask ) != mmd_mask ) { + EFAB_ERR ( "required MMDs not present: got %x, wanted %x\n", + devices, mmd_mask ); + return -EIO; } - ef1002_writel ( efab, ®, EF1_GM_MAC_CLK_REG ); - udelay ( 10 ); - return 1; -} + /* Check all required MMDs are responding and happy. */ + while ( mmd_mask ) { + if ( mmd_mask & 1 ) { + efab_dword_t reg; + int status; + reg.opaque = falcon_mdio_read ( efab, mmd, + MDIO_MMDREG_STAT2 ); + status = EFAB_DWORD_FIELD ( reg, + MDIO_MMDREG_STAT2_PRESENT ); + if ( status != MDIO_MMDREG_STAT2_PRESENT_VAL ) { -/** - * Reset MAC - * - */ -static int ef1002_reset_mac ( struct efab_nic *efab ) { - mentormac_reset ( efab ); - return 1; -} -/** MDIO write */ -static void ef1002_mdio_write ( struct efab_nic *efab, int location, - int value ) { - mentormac_mdio_write ( efab, efab->port + 2, location, value ); -} + return -EIO; + } + } + mmd_mask >>= 1; + mmd++; + } -/** MDIO read */ -static int ef1002_mdio_read ( struct efab_nic *efab, int location ) { - return mentormac_mdio_read ( efab, efab->port + 2, location ); + return 0; } -static struct efab_operations ef1002_operations = { - .get_membase = ef1002_get_membase, - .reset = ef1002_reset, - .init_nic = ef1002_init_nic, - .read_eeprom = ef1002_read_eeprom, - .build_rx_desc = ef1002_build_rx_desc, - .notify_rx_desc = ef1002_notify_rx_desc, - .build_tx_desc = ef1002_build_tx_desc, - .notify_tx_desc = ef1002_notify_tx_desc, - .fetch_event = ef1002_fetch_event, - .mask_irq = ef1002_mask_irq, - .generate_irq = ef1002_generate_irq, - .mdio_write = ef1002_mdio_write, - .mdio_read = ef1002_mdio_read, -}; - -static struct efab_mac_operations ef1002_mac_operations = { - .mac_writel = ef1002_mac_writel, - .mac_readl = ef1002_mac_readl, - .init = ef1002_init_mac, - .reset = ef1002_reset_mac, -}; - -/************************************************************************** - * - * Falcon routines - * - ************************************************************************** - */ - /* I/O BAR address register */ #define FCN_IOM_IND_ADR_REG 0x0 /* I/O BAR data register */ #define FCN_IOM_IND_DAT_REG 0x4 +/* Address region register */ +#define FCN_ADR_REGION_REG_KER 0x00 +#define FCN_ADR_REGION0_LBN 0 +#define FCN_ADR_REGION0_WIDTH 18 +#define FCN_ADR_REGION1_LBN 32 +#define FCN_ADR_REGION1_WIDTH 18 +#define FCN_ADR_REGION2_LBN 64 +#define FCN_ADR_REGION2_WIDTH 18 +#define FCN_ADR_REGION3_LBN 96 +#define FCN_ADR_REGION3_WIDTH 18 + /* Interrupt enable register */ #define FCN_INT_EN_REG_KER 0x0010 #define FCN_MEM_PERR_INT_EN_KER_LBN 5 @@ -1505,11 +440,25 @@ static struct efab_mac_operations ef1002_mac_operations = { #define FCN_INT_ADR_KER_LBN 0 #define FCN_INT_ADR_KER_WIDTH EFAB_DMA_TYPE_WIDTH ( 64 ) -/* Interrupt acknowledge register */ -#define FCN_INT_ACK_KER_REG 0x0050 +/* Interrupt status register (B0 only) */ +#define INT_ISR0_B0 0x90 +#define INT_ISR1_B0 0xA0 + +/* Interrupt acknowledge register (A0/A1 only) */ +#define FCN_INT_ACK_KER_REG_A1 0x0050 +#define INT_ACK_DUMMY_DATA_LBN 0 +#define INT_ACK_DUMMY_DATA_WIDTH 32 + +/* Interrupt acknowledge work-around register (A0/A1 only )*/ +#define WORK_AROUND_BROKEN_PCI_READS_REG_KER_A1 0x0070 + +/* Hardware initialisation register */ +#define FCN_HW_INIT_REG_KER 0x00c0 +#define FCN_BCSR_TARGET_MASK_LBN 101 +#define FCN_BCSR_TARGET_MASK_WIDTH 4 /* SPI host command register */ -#define FCN_EE_SPI_HCMD_REG_KER 0x0100 +#define FCN_EE_SPI_HCMD_REG 0x0100 #define FCN_EE_SPI_HCMD_CMD_EN_LBN 31 #define FCN_EE_SPI_HCMD_CMD_EN_WIDTH 1 #define FCN_EE_WR_TIMER_ACTIVE_LBN 28 @@ -1532,14 +481,14 @@ static struct efab_mac_operations ef1002_mac_operations = { #define FCN_EE_SPI_HCMD_ENC_WIDTH 8 /* SPI host address register */ -#define FCN_EE_SPI_HADR_REG_KER 0x0110 +#define FCN_EE_SPI_HADR_REG 0x0110 #define FCN_EE_SPI_HADR_DUBYTE_LBN 24 #define FCN_EE_SPI_HADR_DUBYTE_WIDTH 8 #define FCN_EE_SPI_HADR_ADR_LBN 0 #define FCN_EE_SPI_HADR_ADR_WIDTH 24 /* SPI host data register */ -#define FCN_EE_SPI_HDATA_REG_KER 0x0120 +#define FCN_EE_SPI_HDATA_REG 0x0120 #define FCN_EE_SPI_HDATA3_LBN 96 #define FCN_EE_SPI_HDATA3_WIDTH 32 #define FCN_EE_SPI_HDATA2_LBN 64 @@ -1549,89 +498,130 @@ static struct efab_mac_operations ef1002_mac_operations = { #define FCN_EE_SPI_HDATA0_LBN 0 #define FCN_EE_SPI_HDATA0_WIDTH 32 -/* VPI configuration register */ -#define FCN_VPD_CONFIG_REG_KER 0x0140 -#define FCN_VPD_9BIT_LBN 1 -#define FCN_VPD_9BIT_WIDTH 1 +/* VPD Config 0 Register register */ +#define FCN_EE_VPD_CFG_REG 0x0140 +#define FCN_EE_VPD_EN_LBN 0 +#define FCN_EE_VPD_EN_WIDTH 1 +#define FCN_EE_VPD_EN_AD9_MODE_LBN 1 +#define FCN_EE_VPD_EN_AD9_MODE_WIDTH 1 +#define FCN_EE_EE_CLOCK_DIV_LBN 112 +#define FCN_EE_EE_CLOCK_DIV_WIDTH 7 +#define FCN_EE_SF_CLOCK_DIV_LBN 120 +#define FCN_EE_SF_CLOCK_DIV_WIDTH 7 + /* NIC status register */ #define FCN_NIC_STAT_REG 0x0200 -#define ONCHIP_SRAM_LBN 16 -#define ONCHIP_SRAM_WIDTH 1 -#define SF_PRST_LBN 9 -#define SF_PRST_WIDTH 1 -#define EE_PRST_LBN 8 -#define EE_PRST_WIDTH 1 -#define EE_STRAP_LBN 7 -#define EE_STRAP_WIDTH 1 -#define PCI_PCIX_MODE_LBN 4 -#define PCI_PCIX_MODE_WIDTH 3 -#define PCI_PCIX_MODE_PCI33_DECODE 0 -#define PCI_PCIX_MODE_PCI66_DECODE 1 -#define PCI_PCIX_MODE_PCIX66_DECODE 5 -#define PCI_PCIX_MODE_PCIX100_DECODE 6 -#define PCI_PCIX_MODE_PCIX133_DECODE 7 -#define STRAP_ISCSI_EN_LBN 3 -#define STRAP_ISCSI_EN_WIDTH 1 -#define STRAP_PINS_LBN 0 -#define STRAP_PINS_WIDTH 3 -/* These bit definitions are extrapolated from the list of numerical - * values for STRAP_PINS. If you want a laugh, read the datasheet's - * definition for when bits 2:0 are set to 7. - */ -#define STRAP_10G_LBN 2 -#define STRAP_10G_WIDTH 1 -#define STRAP_DUAL_PORT_LBN 1 -#define STRAP_DUAL_PORT_WIDTH 1 -#define STRAP_PCIE_LBN 0 -#define STRAP_PCIE_WIDTH 1 +#define FCN_ONCHIP_SRAM_LBN 16 +#define FCN_ONCHIP_SRAM_WIDTH 1 +#define FCN_SF_PRST_LBN 9 +#define FCN_SF_PRST_WIDTH 1 +#define FCN_EE_PRST_LBN 8 +#define FCN_EE_PRST_WIDTH 1 +#define FCN_EE_STRAP_LBN 7 +#define FCN_EE_STRAP_WIDTH 1 +#define FCN_PCI_PCIX_MODE_LBN 4 +#define FCN_PCI_PCIX_MODE_WIDTH 3 +#define FCN_PCI_PCIX_MODE_PCI33_DECODE 0 +#define FCN_PCI_PCIX_MODE_PCI66_DECODE 1 +#define FCN_PCI_PCIX_MODE_PCIX66_DECODE 5 +#define FCN_PCI_PCIX_MODE_PCIX100_DECODE 6 +#define FCN_PCI_PCIX_MODE_PCIX133_DECODE 7 +#define FCN_STRAP_ISCSI_EN_LBN 3 +#define FCN_STRAP_ISCSI_EN_WIDTH 1 +#define FCN_STRAP_PINS_LBN 0 +#define FCN_STRAP_PINS_WIDTH 3 +#define FCN_STRAP_10G_LBN 2 +#define FCN_STRAP_10G_WIDTH 1 +#define FCN_STRAP_DUAL_PORT_LBN 1 +#define FCN_STRAP_DUAL_PORT_WIDTH 1 +#define FCN_STRAP_PCIE_LBN 0 +#define FCN_STRAP_PCIE_WIDTH 1 + +/* Falcon revisions */ +#define FALCON_REV_A0 0 +#define FALCON_REV_A1 1 +#define FALCON_REV_B0 2 /* GPIO control register */ #define FCN_GPIO_CTL_REG_KER 0x0210 +#define FCN_GPIO_CTL_REG_KER 0x0210 + +#define FCN_GPIO3_OEN_LBN 27 +#define FCN_GPIO3_OEN_WIDTH 1 +#define FCN_GPIO2_OEN_LBN 26 +#define FCN_GPIO2_OEN_WIDTH 1 +#define FCN_GPIO1_OEN_LBN 25 +#define FCN_GPIO1_OEN_WIDTH 1 +#define FCN_GPIO0_OEN_LBN 24 +#define FCN_GPIO0_OEN_WIDTH 1 + +#define FCN_GPIO3_OUT_LBN 19 +#define FCN_GPIO3_OUT_WIDTH 1 +#define FCN_GPIO2_OUT_LBN 18 +#define FCN_GPIO2_OUT_WIDTH 1 +#define FCN_GPIO1_OUT_LBN 17 +#define FCN_GPIO1_OUT_WIDTH 1 +#define FCN_GPIO0_OUT_LBN 16 +#define FCN_GPIO0_OUT_WIDTH 1 + +#define FCN_GPIO3_IN_LBN 11 +#define FCN_GPIO3_IN_WIDTH 1 +#define FCN_GPIO2_IN_LBN 10 +#define FCN_GPIO2_IN_WIDTH 1 +#define FCN_GPIO1_IN_LBN 9 +#define FCN_GPIO1_IN_WIDTH 1 +#define FCN_GPIO0_IN_LBN 8 +#define FCN_GPIO0_IN_WIDTH 1 + #define FCN_FLASH_PRESENT_LBN 7 #define FCN_FLASH_PRESENT_WIDTH 1 #define FCN_EEPROM_PRESENT_LBN 6 #define FCN_EEPROM_PRESENT_WIDTH 1 +#define FCN_BOOTED_USING_NVDEVICE_LBN 3 +#define FCN_BOOTED_USING_NVDEVICE_WIDTH 1 + +/* Defines for extra non-volatile storage */ +#define FCN_NV_MAGIC_NUMBER 0xFA1C /* Global control register */ #define FCN_GLB_CTL_REG_KER 0x0220 -#define EXT_PHY_RST_CTL_LBN 63 -#define EXT_PHY_RST_CTL_WIDTH 1 -#define PCIE_SD_RST_CTL_LBN 61 -#define PCIE_SD_RST_CTL_WIDTH 1 -#define PCIX_RST_CTL_LBN 60 -#define PCIX_RST_CTL_WIDTH 1 -#define PCIE_STCK_RST_CTL_LBN 59 -#define PCIE_STCK_RST_CTL_WIDTH 1 -#define PCIE_NSTCK_RST_CTL_LBN 58 -#define PCIE_NSTCK_RST_CTL_WIDTH 1 -#define PCIE_CORE_RST_CTL_LBN 57 -#define PCIE_CORE_RST_CTL_WIDTH 1 -#define EE_RST_CTL_LBN 49 -#define EE_RST_CTL_WIDTH 1 -#define CS_RST_CTL_LBN 48 -#define CS_RST_CTL_WIDTH 1 -#define RST_EXT_PHY_LBN 31 -#define RST_EXT_PHY_WIDTH 1 -#define INT_RST_DUR_LBN 4 -#define INT_RST_DUR_WIDTH 3 -#define EXT_PHY_RST_DUR_LBN 1 -#define EXT_PHY_RST_DUR_WIDTH 3 -#define SWRST_LBN 0 -#define SWRST_WIDTH 1 +#define FCN_EXT_PHY_RST_CTL_LBN 63 +#define FCN_EXT_PHY_RST_CTL_WIDTH 1 +#define FCN_PCIE_SD_RST_CTL_LBN 61 +#define FCN_PCIE_SD_RST_CTL_WIDTH 1 +#define FCN_PCIE_STCK_RST_CTL_LBN 59 +#define FCN_PCIE_STCK_RST_CTL_WIDTH 1 +#define FCN_PCIE_NSTCK_RST_CTL_LBN 58 +#define FCN_PCIE_NSTCK_RST_CTL_WIDTH 1 +#define FCN_PCIE_CORE_RST_CTL_LBN 57 +#define FCN_PCIE_CORE_RST_CTL_WIDTH 1 +#define FCN_EE_RST_CTL_LBN 49 +#define FCN_EE_RST_CTL_WIDTH 1 +#define FCN_RST_EXT_PHY_LBN 31 +#define FCN_RST_EXT_PHY_WIDTH 1 +#define FCN_EXT_PHY_RST_DUR_LBN 1 +#define FCN_EXT_PHY_RST_DUR_WIDTH 3 +#define FCN_SWRST_LBN 0 +#define FCN_SWRST_WIDTH 1 #define INCLUDE_IN_RESET 0 #define EXCLUDE_FROM_RESET 1 /* FPGA build version */ -#define ALTERA_BUILD_REG_KER 0x0300 -#define VER_MAJOR_LBN 24 -#define VER_MAJOR_WIDTH 8 -#define VER_MINOR_LBN 16 -#define VER_MINOR_WIDTH 8 -#define VER_BUILD_LBN 0 -#define VER_BUILD_WIDTH 16 -#define VER_ALL_LBN 0 -#define VER_ALL_WIDTH 32 +#define FCN_ALTERA_BUILD_REG_KER 0x0300 +#define FCN_VER_MAJOR_LBN 24 +#define FCN_VER_MAJOR_WIDTH 8 +#define FCN_VER_MINOR_LBN 16 +#define FCN_VER_MINOR_WIDTH 8 +#define FCN_VER_BUILD_LBN 0 +#define FCN_VER_BUILD_WIDTH 16 +#define FCN_VER_ALL_LBN 0 +#define FCN_VER_ALL_WIDTH 32 + +/* Spare EEPROM bits register (flash 0x390) */ +#define FCN_SPARE_REG_KER 0x310 +#define FCN_MEM_PERR_EN_TX_DATA_LBN 72 +#define FCN_MEM_PERR_EN_TX_DATA_WIDTH 2 /* Timer table for kernel access */ #define FCN_TIMER_CMD_REG_KER 0x420 @@ -1657,10 +647,65 @@ static struct efab_mac_operations ef1002_mac_operations = { #define FCN_SRM_TX_DC_BASE_ADR_LBN 0 #define FCN_SRM_TX_DC_BASE_ADR_WIDTH 21 +/* SRAM configuration register */ +#define FCN_SRM_CFG_REG_KER 0x630 +#define FCN_SRAM_OOB_ADR_INTEN_LBN 5 +#define FCN_SRAM_OOB_ADR_INTEN_WIDTH 1 +#define FCN_SRAM_OOB_BUF_INTEN_LBN 4 +#define FCN_SRAM_OOB_BUF_INTEN_WIDTH 1 +#define FCN_SRAM_OOB_BT_INIT_EN_LBN 3 +#define FCN_SRAM_OOB_BT_INIT_EN_WIDTH 1 +#define FCN_SRM_NUM_BANK_LBN 2 +#define FCN_SRM_NUM_BANK_WIDTH 1 +#define FCN_SRM_BANK_SIZE_LBN 0 +#define FCN_SRM_BANK_SIZE_WIDTH 2 +#define FCN_SRM_NUM_BANKS_AND_BANK_SIZE_LBN 0 +#define FCN_SRM_NUM_BANKS_AND_BANK_SIZE_WIDTH 3 + +#define FCN_RX_CFG_REG_KER 0x800 +#define FCN_RX_INGR_EN_B0_LBN 47 +#define FCN_RX_INGR_EN_B0_WIDTH 1 +#define FCN_RX_USR_BUF_SIZE_B0_LBN 19 +#define FCN_RX_USR_BUF_SIZE_B0_WIDTH 9 +#define FCN_RX_XON_MAC_TH_B0_LBN 10 +#define FCN_RX_XON_MAC_TH_B0_WIDTH 9 +#define FCN_RX_XOFF_MAC_TH_B0_LBN 1 +#define FCN_RX_XOFF_MAC_TH_B0_WIDTH 9 +#define FCN_RX_XOFF_MAC_EN_B0_LBN 0 +#define FCN_RX_XOFF_MAC_EN_B0_WIDTH 1 +#define FCN_RX_USR_BUF_SIZE_A1_LBN 11 +#define FCN_RX_USR_BUF_SIZE_A1_WIDTH 9 +#define FCN_RX_XON_MAC_TH_A1_LBN 6 +#define FCN_RX_XON_MAC_TH_A1_WIDTH 5 +#define FCN_RX_XOFF_MAC_TH_A1_LBN 1 +#define FCN_RX_XOFF_MAC_TH_A1_WIDTH 5 +#define FCN_RX_XOFF_MAC_EN_A1_LBN 0 +#define FCN_RX_XOFF_MAC_EN_A1_WIDTH 1 + +#define FCN_RX_USR_BUF_SIZE_A1_LBN 11 +#define FCN_RX_USR_BUF_SIZE_A1_WIDTH 9 +#define FCN_RX_XOFF_MAC_EN_A1_LBN 0 +#define FCN_RX_XOFF_MAC_EN_A1_WIDTH 1 + /* Receive filter control register */ #define FCN_RX_FILTER_CTL_REG_KER 0x810 +#define FCN_UDP_FULL_SRCH_LIMIT_LBN 32 +#define FCN_UDP_FULL_SRCH_LIMIT_WIDTH 8 #define FCN_NUM_KER_LBN 24 #define FCN_NUM_KER_WIDTH 2 +#define FCN_UDP_WILD_SRCH_LIMIT_LBN 16 +#define FCN_UDP_WILD_SRCH_LIMIT_WIDTH 8 +#define FCN_TCP_WILD_SRCH_LIMIT_LBN 8 +#define FCN_TCP_WILD_SRCH_LIMIT_WIDTH 8 +#define FCN_TCP_FULL_SRCH_LIMIT_LBN 0 +#define FCN_TCP_FULL_SRCH_LIMIT_WIDTH 8 + +/* RX queue flush register */ +#define FCN_RX_FLUSH_DESCQ_REG_KER 0x0820 +#define FCN_RX_FLUSH_DESCQ_CMD_LBN 24 +#define FCN_RX_FLUSH_DESCQ_CMD_WIDTH 1 +#define FCN_RX_FLUSH_DESCQ_LBN 0 +#define FCN_RX_FLUSH_DESCQ_WIDTH 12 /* Receive descriptor update register */ #define FCN_RX_DESC_UPD_REG_KER 0x0830 @@ -1675,6 +720,26 @@ static struct efab_mac_operations ef1002_mac_operations = { #define FCN_RX_DC_SIZE_LBN 0 #define FCN_RX_DC_SIZE_WIDTH 2 +#define FCN_RX_SELF_RST_REG_KER 0x890 +#define FCN_RX_ISCSI_DIS_LBN 17 +#define FCN_RX_ISCSI_DIS_WIDTH 1 +#define FCN_RX_NODESC_WAIT_DIS_LBN 9 +#define FCN_RX_NODESC_WAIT_DIS_WIDTH 1 +#define FCN_RX_RECOVERY_EN_LBN 8 +#define FCN_RX_RECOVERY_EN_WIDTH 1 + +/* TX queue flush register */ +#define FCN_TX_FLUSH_DESCQ_REG_KER 0x0a00 +#define FCN_TX_FLUSH_DESCQ_CMD_LBN 12 +#define FCN_TX_FLUSH_DESCQ_CMD_WIDTH 1 +#define FCN_TX_FLUSH_DESCQ_LBN 0 +#define FCN_TX_FLUSH_DESCQ_WIDTH 12 + +/* Transmit configuration register 2 */ +#define FCN_TX_CFG2_REG_KER 0xa80 +#define FCN_TX_DIS_NON_IP_EV_LBN 17 +#define FCN_TX_DIS_NON_IP_EV_WIDTH 1 + /* Transmit descriptor update register */ #define FCN_TX_DESC_UPD_REG_KER 0x0a10 #define FCN_TX_DESC_WPTR_LBN 96 @@ -1704,6 +769,8 @@ static struct efab_mac_operations ef1002_mac_operations = { #define FCN_MD_GC_WIDTH 1 #define FCN_MD_RIC_LBN 2 #define FCN_MD_RIC_WIDTH 1 +#define FCN_MD_RDC_LBN 1 +#define FCN_MD_RDC_WIDTH 1 #define FCN_MD_WRC_LBN 0 #define FCN_MD_WRC_WIDTH 1 @@ -1721,6 +788,14 @@ static struct efab_mac_operations ef1002_mac_operations = { /* PHY management status & mask register */ #define FCN_MD_STAT_REG_KER 0xc50 +#define FCN_MD_PINT_LBN 4 +#define FCN_MD_PINT_WIDTH 1 +#define FCN_MD_DONE_LBN 3 +#define FCN_MD_DONE_WIDTH 1 +#define FCN_MD_BSERR_LBN 2 +#define FCN_MD_BSERR_WIDTH 1 +#define FCN_MD_LNFL_LBN 1 +#define FCN_MD_LNFL_WIDTH 1 #define FCN_MD_BSY_LBN 0 #define FCN_MD_BSY_WIDTH 1 @@ -1738,6 +813,11 @@ static struct efab_mac_operations ef1002_mac_operations = { #define FCN_MAC_SPEED_LBN 0 #define FCN_MAC_SPEED_WIDTH 2 +/* 10Gig Xaui XGXS Default Values */ +#define XX_TXDRV_DEQ_DEFAULT 0xe /* deq=.6 */ +#define XX_TXDRV_DTX_DEFAULT 0x5 /* 1.25 */ +#define XX_SD_CTL_DRV_DEFAULT 0 /* 20mA */ + /* GMAC registers */ #define FALCON_GMAC_REGBANK 0xe00 #define FALCON_GMAC_REGBANK_SIZE 0x200 @@ -1801,18 +881,45 @@ static struct efab_mac_operations ef1002_mac_operations = { #define FCN_XM_RXEN_LBN 1 #define FCN_XM_RXEN_WIDTH 1 +/* XGMAC management interrupt mask register */ +#define FCN_XM_MGT_INT_MSK_REG_MAC_B0 0x5 +#define FCN_XM_MSK_PRMBLE_ERR_LBN 2 +#define FCN_XM_MSK_PRMBLE_ERR_WIDTH 1 +#define FCN_XM_MSK_RMTFLT_LBN 1 +#define FCN_XM_MSK_RMTFLT_WIDTH 1 +#define FCN_XM_MSK_LCLFLT_LBN 0 +#define FCN_XM_MSK_LCLFLT_WIDTH 1 + +/* XGMAC flow control register */ +#define FCN_XM_FC_REG_MAC 0x7 +#define FCN_XM_PAUSE_TIME_LBN 16 +#define FCN_XM_PAUSE_TIME_WIDTH 16 +#define FCN_XM_DIS_FCNTL_LBN 0 +#define FCN_XM_DIS_FCNTL_WIDTH 1 + /* XGMAC transmit parameter register */ #define FCN_XM_TX_PARAM_REG_MAC 0x0d #define FCN_XM_TX_JUMBO_MODE_LBN 31 #define FCN_XM_TX_JUMBO_MODE_WIDTH 1 #define FCN_XM_MAX_TX_FRM_SIZE_LBN 16 #define FCN_XM_MAX_TX_FRM_SIZE_WIDTH 14 +#define FCN_XM_ACPT_ALL_MCAST_LBN 11 +#define FCN_XM_ACPT_ALL_MCAST_WIDTH 1 /* XGMAC receive parameter register */ #define FCN_XM_RX_PARAM_REG_MAC 0x0e #define FCN_XM_MAX_RX_FRM_SIZE_LBN 0 #define FCN_XM_MAX_RX_FRM_SIZE_WIDTH 14 +/* XGMAC management interrupt status register */ +#define FCN_XM_MGT_INT_REG_MAC_B0 0x0f +#define FCN_XM_PRMBLE_ERR 2 +#define FCN_XM_PRMBLE_WIDTH 1 +#define FCN_XM_RMTFLT_LBN 1 +#define FCN_XM_RMTFLT_WIDTH 1 +#define FCN_XM_LCLFLT_LBN 0 +#define FCN_XM_LCLFLT_WIDTH 1 + /* XAUI XGXS core status register */ #define FCN_XX_ALIGN_DONE_LBN 20 #define FCN_XX_ALIGN_DONE_WIDTH 1 @@ -1823,10 +930,35 @@ static struct efab_mac_operations ef1002_mac_operations = { #define FCN_XX_COMMA_DET_LBN 12 #define FCN_XX_COMMA_DET_WIDTH 4 #define FCN_XX_COMMA_DET_RESET 0xf - +#define FCN_XX_CHARERR_LBN 4 +#define FCN_XX_CHARERR_WIDTH 4 +#define FCN_XX_CHARERR_RESET 0xf +#define FCN_XX_DISPERR_LBN 0 +#define FCN_XX_DISPERR_WIDTH 4 +#define FCN_XX_DISPERR_RESET 0xf /* XGXS/XAUI powerdown/reset register */ #define FCN_XX_PWR_RST_REG_MAC 0x10 +#define FCN_XX_PWRDND_EN_LBN 15 +#define FCN_XX_PWRDND_EN_WIDTH 1 +#define FCN_XX_PWRDNC_EN_LBN 14 +#define FCN_XX_PWRDNC_EN_WIDTH 1 +#define FCN_XX_PWRDNB_EN_LBN 13 +#define FCN_XX_PWRDNB_EN_WIDTH 1 +#define FCN_XX_PWRDNA_EN_LBN 12 +#define FCN_XX_PWRDNA_EN_WIDTH 1 +#define FCN_XX_RSTPLLCD_EN_LBN 9 +#define FCN_XX_RSTPLLCD_EN_WIDTH 1 +#define FCN_XX_RSTPLLAB_EN_LBN 8 +#define FCN_XX_RSTPLLAB_EN_WIDTH 1 +#define FCN_XX_RESETD_EN_LBN 7 +#define FCN_XX_RESETD_EN_WIDTH 1 +#define FCN_XX_RESETC_EN_LBN 6 +#define FCN_XX_RESETC_EN_WIDTH 1 +#define FCN_XX_RESETB_EN_LBN 5 +#define FCN_XX_RESETB_EN_WIDTH 1 +#define FCN_XX_RESETA_EN_LBN 4 +#define FCN_XX_RESETA_EN_WIDTH 1 #define FCN_XX_RSTXGXSRX_EN_LBN 2 #define FCN_XX_RSTXGXSRX_EN_WIDTH 1 #define FCN_XX_RSTXGXSTX_EN_LBN 1 @@ -1834,8 +966,66 @@ static struct efab_mac_operations ef1002_mac_operations = { #define FCN_XX_RST_XX_EN_LBN 0 #define FCN_XX_RST_XX_EN_WIDTH 1 + +/* XGXS/XAUI powerdown/reset control register */ +#define FCN_XX_SD_CTL_REG_MAC 0x11 +#define FCN_XX_TERMADJ1_LBN 17 +#define FCN_XX_TERMADJ1_WIDTH 1 +#define FCN_XX_TERMADJ0_LBN 16 +#define FCN_XX_TERMADJ0_WIDTH 1 +#define FCN_XX_HIDRVD_LBN 15 +#define FCN_XX_HIDRVD_WIDTH 1 +#define FCN_XX_LODRVD_LBN 14 +#define FCN_XX_LODRVD_WIDTH 1 +#define FCN_XX_HIDRVC_LBN 13 +#define FCN_XX_HIDRVC_WIDTH 1 +#define FCN_XX_LODRVC_LBN 12 +#define FCN_XX_LODRVC_WIDTH 1 +#define FCN_XX_HIDRVB_LBN 11 +#define FCN_XX_HIDRVB_WIDTH 1 +#define FCN_XX_LODRVB_LBN 10 +#define FCN_XX_LODRVB_WIDTH 1 +#define FCN_XX_HIDRVA_LBN 9 +#define FCN_XX_HIDRVA_WIDTH 1 +#define FCN_XX_LODRVA_LBN 8 +#define FCN_XX_LODRVA_WIDTH 1 +#define FCN_XX_LPBKD_LBN 3 +#define FCN_XX_LPBKD_WIDTH 1 +#define FCN_XX_LPBKC_LBN 2 +#define FCN_XX_LPBKC_WIDTH 1 +#define FCN_XX_LPBKB_LBN 1 +#define FCN_XX_LPBKB_WIDTH 1 +#define FCN_XX_LPBKA_LBN 0 +#define FCN_XX_LPBKA_WIDTH 1 + +#define FCN_XX_TXDRV_CTL_REG_MAC 0x12 +#define FCN_XX_DEQD_LBN 28 +#define FCN_XX_DEQD_WIDTH 4 +#define FCN_XX_DEQC_LBN 24 +#define FCN_XX_DEQC_WIDTH 4 +#define FCN_XX_DEQB_LBN 20 +#define FCN_XX_DEQB_WIDTH 4 +#define FCN_XX_DEQA_LBN 16 +#define FCN_XX_DEQA_WIDTH 4 +#define FCN_XX_DTXD_LBN 12 +#define FCN_XX_DTXD_WIDTH 4 +#define FCN_XX_DTXC_LBN 8 +#define FCN_XX_DTXC_WIDTH 4 +#define FCN_XX_DTXB_LBN 4 +#define FCN_XX_DTXB_WIDTH 4 +#define FCN_XX_DTXA_LBN 0 +#define FCN_XX_DTXA_WIDTH 4 + +/* Receive filter table */ +#define FCN_RX_FILTER_TBL0 0xF00000 + /* Receive descriptor pointer table */ -#define FCN_RX_DESC_PTR_TBL_KER 0x11800 +#define FCN_RX_DESC_PTR_TBL_KER_A1 0x11800 +#define FCN_RX_DESC_PTR_TBL_KER_B0 0xF40000 +#define FCN_RX_ISCSI_DDIG_EN_LBN 88 +#define FCN_RX_ISCSI_DDIG_EN_WIDTH 1 +#define FCN_RX_ISCSI_HDIG_EN_LBN 87 +#define FCN_RX_ISCSI_HDIG_EN_WIDTH 1 #define FCN_RX_DESCQ_BUF_BASE_ID_LBN 36 #define FCN_RX_DESCQ_BUF_BASE_ID_WIDTH 20 #define FCN_RX_DESCQ_EVQ_ID_LBN 24 @@ -1856,9 +1046,16 @@ static struct efab_mac_operations ef1002_mac_operations = { #define FCN_RX_DESCQ_EN_WIDTH 1 /* Transmit descriptor pointer table */ -#define FCN_TX_DESC_PTR_TBL_KER 0x11900 +#define FCN_TX_DESC_PTR_TBL_KER_A1 0x11900 +#define FCN_TX_DESC_PTR_TBL_KER_B0 0xF50000 +#define FCN_TX_NON_IP_DROP_DIS_B0_LBN 91 +#define FCN_TX_NON_IP_DROP_DIS_B0_WIDTH 1 #define FCN_TX_DESCQ_EN_LBN 88 #define FCN_TX_DESCQ_EN_WIDTH 1 +#define FCN_TX_ISCSI_DDIG_EN_LBN 87 +#define FCN_TX_ISCSI_DDIG_EN_WIDTH 1 +#define FCN_TX_ISCSI_HDIG_EN_LBN 86 +#define FCN_TX_ISCSI_HDIG_EN_WIDTH 1 #define FCN_TX_DESCQ_BUF_BASE_ID_LBN 36 #define FCN_TX_DESCQ_BUF_BASE_ID_WIDTH 20 #define FCN_TX_DESCQ_EVQ_ID_LBN 24 @@ -1877,7 +1074,8 @@ static struct efab_mac_operations ef1002_mac_operations = { #define FCN_TX_DESCQ_FLUSH_WIDTH 1 /* Event queue pointer */ -#define FCN_EVQ_PTR_TBL_KER 0x11a00 +#define FCN_EVQ_PTR_TBL_KER_A1 0x11a00 +#define FCN_EVQ_PTR_TBL_KER_B0 0xf60000 #define FCN_EVQ_EN_LBN 23 #define FCN_EVQ_EN_WIDTH 1 #define FCN_EVQ_SIZE_LBN 20 @@ -1892,16 +1090,22 @@ static struct efab_mac_operations ef1002_mac_operations = { #define FCN_EVQ_BUF_BASE_ID_LBN 0 #define FCN_EVQ_BUF_BASE_ID_WIDTH 20 +/* RSS indirection table */ +#define FCN_RX_RSS_INDIR_TBL_B0 0xFB0000 + /* Event queue read pointer */ -#define FCN_EVQ_RPTR_REG_KER 0x11b00 +#define FCN_EVQ_RPTR_REG_KER_A1 0x11b00 +#define FCN_EVQ_RPTR_REG_KER_B0 0xfa0000 #define FCN_EVQ_RPTR_LBN 0 #define FCN_EVQ_RPTR_WIDTH 14 -#define FCN_EVQ_RPTR_REG_KER_DWORD ( FCN_EVQ_RPTR_REG_KER + 0 ) +#define FCN_EVQ_RPTR_REG_KER_DWORD_A1 ( FCN_EVQ_RPTR_REG_KER_A1 + 0 ) +#define FCN_EVQ_RPTR_REG_KER_DWORD_B0 ( FCN_EVQ_RPTR_REG_KER_B0 + 0 ) #define FCN_EVQ_RPTR_DWORD_LBN 0 #define FCN_EVQ_RPTR_DWORD_WIDTH 14 /* Special buffer descriptors */ -#define FCN_BUF_FULL_TBL_KER 0x18000 +#define FCN_BUF_FULL_TBL_KER_A1 0x18000 +#define FCN_BUF_FULL_TBL_KER_B0 0x800000 #define FCN_IP_DAT_BUF_SIZE_LBN 50 #define FCN_IP_DAT_BUF_SIZE_WIDTH 1 #define FCN_IP_DAT_BUF_SIZE_8K 1 @@ -1914,13 +1118,11 @@ static struct efab_mac_operations ef1002_mac_operations = { /** Offset of a GMAC register within Falcon */ #define FALCON_GMAC_REG( efab, mac_reg ) \ ( FALCON_GMAC_REGBANK + \ - ( (efab)->port * FALCON_GMAC_REGBANK_SIZE ) + \ ( (mac_reg) * FALCON_GMAC_REG_SIZE ) ) /** Offset of an XMAC register within Falcon */ #define FALCON_XMAC_REG( efab_port, mac_reg ) \ ( FALCON_XMAC_REGBANK + \ - ( (efab_port)->port * FALCON_XMAC_REGBANK_SIZE ) + \ ( (mac_reg) * FALCON_XMAC_REG_SIZE ) ) #define FCN_MAC_DATA_LBN 0 @@ -1962,10 +1164,22 @@ static struct efab_mac_operations ef1002_mac_operations = { #define FCN_TX_EV_DESC_PTR_LBN 0 #define FCN_TX_EV_DESC_PTR_WIDTH 12 -/* Fixed special buffer numbers to use */ -#define FALCON_EVQ_ID 0 -#define FALCON_TXD_ID 1 -#define FALCON_RXD_ID 2 +/******************************************************************************* + * + * + * Low-level hardware access + * + * + *******************************************************************************/ + +#define FCN_REVISION_REG(efab, reg) \ + ( ( efab->pci_revision == FALCON_REV_B0 ) ? reg ## _B0 : reg ## _A1 ) + +#define EFAB_SET_OWORD_FIELD_VER(efab, reg, field, val) \ + if ( efab->pci_revision == FALCON_REV_B0 ) \ + EFAB_SET_OWORD_FIELD ( reg, field ## _B0, val ); \ + else \ + EFAB_SET_OWORD_FIELD ( reg, field ## _A1, val ); #if FALCON_USE_IO_BAR @@ -1995,8 +1209,9 @@ static inline uint32_t _falcon_readl ( struct efab_nic *efab, * Write to a Falcon register * */ -static inline void falcon_write ( struct efab_nic *efab, efab_oword_t *value, - unsigned int reg ) { +static inline void +falcon_write ( struct efab_nic *efab, efab_oword_t *value, unsigned int reg ) +{ EFAB_REGDUMP ( "Writing register %x with " EFAB_OWORD_FMT "\n", reg, EFAB_OWORD_VAL ( *value ) ); @@ -2004,6 +1219,7 @@ static inline void falcon_write ( struct efab_nic *efab, efab_oword_t *value, _falcon_writel ( efab, value->u32[0], reg + 0 ); _falcon_writel ( efab, value->u32[1], reg + 4 ); _falcon_writel ( efab, value->u32[2], reg + 8 ); + wmb(); _falcon_writel ( efab, value->u32[3], reg + 12 ); wmb(); } @@ -2012,10 +1228,11 @@ static inline void falcon_write ( struct efab_nic *efab, efab_oword_t *value, * Write to Falcon SRAM * */ -static inline void falcon_write_sram ( struct efab_nic *efab, - efab_qword_t *value, - unsigned int index ) { - unsigned int reg = ( FCN_BUF_FULL_TBL_KER + +static inline void +falcon_write_sram ( struct efab_nic *efab, efab_qword_t *value, + unsigned int index ) +{ + unsigned int reg = ( FCN_REVISION_REG ( efab, FCN_BUF_FULL_TBL_KER ) + ( index * sizeof ( *value ) ) ); EFAB_REGDUMP ( "Writing SRAM register %x with " EFAB_QWORD_FMT "\n", @@ -2030,8 +1247,9 @@ static inline void falcon_write_sram ( struct efab_nic *efab, * Write dword to Falcon register that allows partial writes * */ -static inline void falcon_writel ( struct efab_nic *efab, efab_dword_t *value, - unsigned int reg ) { +static inline void +falcon_writel ( struct efab_nic *efab, efab_dword_t *value, unsigned int reg ) +{ EFAB_REGDUMP ( "Writing partial register %x with " EFAB_DWORD_FMT "\n", reg, EFAB_DWORD_VAL ( *value ) ); _falcon_writel ( efab, value->u32[0], reg ); @@ -2041,9 +1259,11 @@ static inline void falcon_writel ( struct efab_nic *efab, efab_dword_t *value, * Read from a Falcon register * */ -static inline void falcon_read ( struct efab_nic *efab, efab_oword_t *value, - unsigned int reg ) { +static inline void +falcon_read ( struct efab_nic *efab, efab_oword_t *value, unsigned int reg ) +{ value->u32[0] = _falcon_readl ( efab, reg + 0 ); + wmb(); value->u32[1] = _falcon_readl ( efab, reg + 4 ); value->u32[2] = _falcon_readl ( efab, reg + 8 ); value->u32[3] = _falcon_readl ( efab, reg + 12 ); @@ -2056,10 +1276,11 @@ static inline void falcon_read ( struct efab_nic *efab, efab_oword_t *value, * Read from Falcon SRAM * */ -static inline void falcon_read_sram ( struct efab_nic *efab, - efab_qword_t *value, - unsigned int index ) { - unsigned int reg = ( FCN_BUF_FULL_TBL_KER + +static inline void +falcon_read_sram ( struct efab_nic *efab, efab_qword_t *value, + unsigned int index ) +{ + unsigned int reg = ( FCN_REVISION_REG ( efab, FCN_BUF_FULL_TBL_KER ) + ( index * sizeof ( *value ) ) ); value->u32[0] = _falcon_readl ( efab, reg + 0 ); @@ -2072,44 +1293,14 @@ static inline void falcon_read_sram ( struct efab_nic *efab, * Read dword from a portion of a Falcon register * */ -static inline void falcon_readl ( struct efab_nic *efab, efab_dword_t *value, - unsigned int reg ) { +static inline void +falcon_readl ( struct efab_nic *efab, efab_dword_t *value, unsigned int reg ) +{ value->u32[0] = _falcon_readl ( efab, reg ); EFAB_REGDUMP ( "Read from register %x, got " EFAB_DWORD_FMT "\n", reg, EFAB_DWORD_VAL ( *value ) ); } -/** - * Verified write to Falcon SRAM - * - */ -static inline void falcon_write_sram_verify ( struct efab_nic *efab, - efab_qword_t *value, - unsigned int index ) { - efab_qword_t verify; - - falcon_write_sram ( efab, value, index ); - udelay ( 1000 ); - falcon_read_sram ( efab, &verify, index ); - if ( memcmp ( &verify, value, sizeof ( verify ) ) != 0 ) { - EFAB_ERR ( "SRAM index %x failure: wrote " EFAB_QWORD_FMT - " got " EFAB_QWORD_FMT "\n", index, - EFAB_QWORD_VAL ( *value ), - EFAB_QWORD_VAL ( verify ) ); - } -} - -/** - * Get memory base - * - */ -static void falcon_get_membase ( struct efab_nic *efab ) { - unsigned long membase_phys; - - membase_phys = pci_bar_start ( efab->pci, PCI_BASE_ADDRESS_2 ); - efab->membase = ioremap ( membase_phys, 0x20000 ); -} - #define FCN_DUMP_REG( efab, _reg ) do { \ efab_oword_t reg; \ falcon_read ( efab, ®, _reg ); \ @@ -2125,12 +1316,47 @@ static void falcon_get_membase ( struct efab_nic *efab ) { } while ( 0 ); /** + * See if an event is present + * + * @v event Falcon event structure + * @ret True An event is pending + * @ret False No event is pending + * + * We check both the high and low dword of the event for all ones. We + * wrote all ones when we cleared the event, and no valid event can + * have all ones in either its high or low dwords. This approach is + * robust against reordering. + * + * Note that using a single 64-bit comparison is incorrect; even + * though the CPU read will be atomic, the DMA write may not be. + */ +static inline int +falcon_event_present ( falcon_event_t* event ) +{ + return ( ! ( EFAB_DWORD_IS_ALL_ONES ( event->dword[0] ) | + EFAB_DWORD_IS_ALL_ONES ( event->dword[1] ) ) ); +} + +static void +falcon_eventq_read_ack ( struct efab_nic *efab, struct efab_ev_queue *ev_queue ) +{ + efab_dword_t reg; + + EFAB_POPULATE_DWORD_1 ( reg, FCN_EVQ_RPTR_DWORD, ev_queue->read_ptr ); + falcon_writel ( efab, ®, + FCN_REVISION_REG ( efab, FCN_EVQ_RPTR_REG_KER_DWORD ) ); +} + +#if 0 +/** * Dump register contents (for debugging) * * Marked as static inline so that it will not be compiled in if not * used. */ -static inline void falcon_dump_regs ( struct efab_nic *efab ) { +static inline void +falcon_dump_regs ( struct efab_nic *efab ) +{ FCN_DUMP_REG ( efab, FCN_INT_EN_REG_KER ); FCN_DUMP_REG ( efab, FCN_INT_ADR_REG_KER ); FCN_DUMP_REG ( efab, FCN_GLB_CTL_REG_KER ); @@ -2142,9 +1368,9 @@ static inline void falcon_dump_regs ( struct efab_nic *efab ) { FCN_DUMP_REG ( efab, FCN_TX_DC_CFG_REG_KER ); FCN_DUMP_REG ( efab, FCN_MAC0_CTRL_REG_KER ); FCN_DUMP_REG ( efab, FCN_MAC1_CTRL_REG_KER ); - FCN_DUMP_REG ( efab, FCN_RX_DESC_PTR_TBL_KER ); - FCN_DUMP_REG ( efab, FCN_TX_DESC_PTR_TBL_KER ); - FCN_DUMP_REG ( efab, FCN_EVQ_PTR_TBL_KER ); + FCN_DUMP_REG ( efab, FCN_REVISION_REG ( efab, FCN_RX_DESC_PTR_TBL_KER ) ); + FCN_DUMP_REG ( efab, FCN_REVISION_REG ( efab, FCN_TX_DESC_PTR_TBL_KER ) ); + FCN_DUMP_REG ( efab, FCN_REVISION_REG ( efab, FCN_EVQ_PTR_TBL_KER ) ); FCN_DUMP_MAC_REG ( efab, GM_CFG1_REG_MAC ); FCN_DUMP_MAC_REG ( efab, GM_CFG2_REG_MAC ); FCN_DUMP_MAC_REG ( efab, GM_MAX_FLEN_REG_MAC ); @@ -2158,391 +1384,356 @@ static inline void falcon_dump_regs ( struct efab_nic *efab ) { FCN_DUMP_MAC_REG ( efab, GMF_CFG4_REG_MAC ); FCN_DUMP_MAC_REG ( efab, GMF_CFG5_REG_MAC ); } +#endif -/** - * Create special buffer - * - */ -static void falcon_create_special_buffer ( struct efab_nic *efab, - void *addr, unsigned int index ) { - efab_qword_t buf_desc; - unsigned long dma_addr; +static void +falcon_interrupts ( struct efab_nic *efab, int enabled, int force ) +{ + efab_oword_t int_en_reg_ker; - memset ( addr, 0, 4096 ); - dma_addr = virt_to_bus ( addr ); - EFAB_ASSERT ( ( dma_addr & ( EFAB_BUF_ALIGN - 1 ) ) == 0 ); - EFAB_POPULATE_QWORD_3 ( buf_desc, - FCN_IP_DAT_BUF_SIZE, FCN_IP_DAT_BUF_SIZE_4K, - FCN_BUF_ADR_FBUF, ( dma_addr >> 12 ), - FCN_BUF_OWNER_ID_FBUF, 0 ); - falcon_write_sram_verify ( efab, &buf_desc, index ); + EFAB_POPULATE_OWORD_2 ( int_en_reg_ker, + FCN_KER_INT_KER, force, + FCN_DRV_INT_EN_KER, enabled ); + falcon_write ( efab, &int_en_reg_ker, FCN_INT_EN_REG_KER ); } -/** - * Update event queue read pointer +/******************************************************************************* * - */ -static void falcon_eventq_read_ack ( struct efab_nic *efab ) { - efab_dword_t reg; - - EFAB_ASSERT ( efab->eventq_read_ptr < EFAB_EVQ_SIZE ); - - EFAB_POPULATE_DWORD_1 ( reg, FCN_EVQ_RPTR_DWORD, - efab->eventq_read_ptr ); - falcon_writel ( efab, ®, FCN_EVQ_RPTR_REG_KER_DWORD ); -} - -/** - * Reset device * - */ -static int falcon_reset ( struct efab_nic *efab ) { - efab_oword_t glb_ctl_reg_ker; - - /* Initiate software reset */ - EFAB_POPULATE_OWORD_7 ( glb_ctl_reg_ker, - PCIE_CORE_RST_CTL, EXCLUDE_FROM_RESET, - PCIE_NSTCK_RST_CTL, EXCLUDE_FROM_RESET, - PCIE_SD_RST_CTL, EXCLUDE_FROM_RESET, - EE_RST_CTL, EXCLUDE_FROM_RESET, - PCIX_RST_CTL, EXCLUDE_FROM_RESET, - EXT_PHY_RST_DUR, 0x7 /* datasheet recommended */, - SWRST, 1 ); - - falcon_write ( efab, &glb_ctl_reg_ker, FCN_GLB_CTL_REG_KER ); - - /* Allow 20ms for reset */ - mdelay ( 20 ); + * SPI access + * + * + *******************************************************************************/ - /* Check for device reset complete */ - falcon_read ( efab, &glb_ctl_reg_ker, FCN_GLB_CTL_REG_KER ); - if ( EFAB_OWORD_FIELD ( glb_ctl_reg_ker, SWRST ) != 0 ) { - EFAB_ERR ( "Reset failed\n" ); - return 0; - } - return 1; -} +/** Maximum length for a single SPI transaction */ +#define FALCON_SPI_MAX_LEN 16 -/** - * Wait for SPI command completion - * - */ -static int falcon_spi_wait ( struct efab_nic *efab ) { +static int +falcon_spi_wait ( struct efab_nic *efab ) +{ efab_oword_t reg; int count; count = 0; do { udelay ( 100 ); - falcon_read ( efab, ®, FCN_EE_SPI_HCMD_REG_KER ); + falcon_read ( efab, ®, FCN_EE_SPI_HCMD_REG ); if ( EFAB_OWORD_FIELD ( reg, FCN_EE_SPI_HCMD_CMD_EN ) == 0 ) - return 1; + return 0; } while ( ++count < 1000 ); - printf ( "Timed out waiting for SPI\n" ); - return 0; + + EFAB_ERR ( "Timed out waiting for SPI\n" ); + return -ETIMEDOUT; } -/** - * Perform SPI read/write - * - */ -static int falcon_spi_rw ( struct spi_bus *bus, struct spi_device *device, - unsigned int command, int address, - const void *data_out, void *data_in, size_t len ) { - struct efab_nic *efab = container_of ( bus, struct efab_nic, spi ); +static int +falcon_spi_rw ( struct spi_bus* bus, struct spi_device *device, + unsigned int command, int address, + const void* data_out, void *data_in, size_t len ) +{ + struct efab_nic *efab = container_of ( bus, struct efab_nic, spi_bus ); + int address_len, rc, device_id, read_cmd; efab_oword_t reg; - /* Program address register */ - EFAB_POPULATE_OWORD_1 ( reg, FCN_EE_SPI_HADR_ADR, address ); - falcon_write ( efab, ®, FCN_EE_SPI_HADR_REG_KER ); - - /* Program data register, if applicable */ + /* falcon_init_spi_device() should have reduced the block size + * down so this constraint holds */ + assert ( len <= FALCON_SPI_MAX_LEN ); + + /* Is this the FLASH or EEPROM device? */ + if ( device == &efab->spi_flash ) + device_id = FCN_EE_SPI_FLASH; + else if ( device == &efab->spi_eeprom ) + device_id = FCN_EE_SPI_EEPROM; + else { + EFAB_ERR ( "Unknown device %p\n", device ); + return -EINVAL; + } + + EFAB_TRACE ( "Executing spi command %d on device %d at %d for %zd bytes\n", + command, device_id, address, len ); + + /* The bus must be idle */ + rc = falcon_spi_wait ( efab ); + if ( rc ) + goto fail1; + + /* Copy data out */ if ( data_out ) { memcpy ( ®, data_out, len ); - falcon_write ( efab, ®, FCN_EE_SPI_HDATA_REG_KER ); + falcon_write ( efab, ®, FCN_EE_SPI_HDATA_REG ); + } + + /* Program address register */ + if ( address >= 0 ) { + EFAB_POPULATE_OWORD_1 ( reg, FCN_EE_SPI_HADR_ADR, address ); + falcon_write ( efab, ®, FCN_EE_SPI_HADR_REG ); } /* Issue command */ + address_len = ( address >= 0 ) ? device->address_len / 8 : 0; + read_cmd = ( data_in ? FCN_EE_SPI_READ : FCN_EE_SPI_WRITE ); EFAB_POPULATE_OWORD_7 ( reg, - FCN_EE_SPI_HCMD_CMD_EN, 1, - FCN_EE_SPI_HCMD_SF_SEL, device->slave, + FCN_EE_SPI_HCMD_CMD_EN, 1, + FCN_EE_SPI_HCMD_SF_SEL, device_id, FCN_EE_SPI_HCMD_DABCNT, len, - FCN_EE_SPI_HCMD_READ, ( data_out ? - FCN_EE_SPI_WRITE : FCN_EE_SPI_READ ), + FCN_EE_SPI_HCMD_READ, read_cmd, FCN_EE_SPI_HCMD_DUBCNT, 0, - FCN_EE_SPI_HCMD_ADBCNT, - ( device->address_len / 8 ), + FCN_EE_SPI_HCMD_ADBCNT, address_len, FCN_EE_SPI_HCMD_ENC, command ); - falcon_write ( efab, ®, FCN_EE_SPI_HCMD_REG_KER ); - - /* Wait for operation to complete */ - if ( ! falcon_spi_wait ( efab ) ) - return 0; + falcon_write ( efab, ®, FCN_EE_SPI_HCMD_REG ); - /* Read data, if applicable */ + /* Wait for the command to complete */ + rc = falcon_spi_wait ( efab ); + if ( rc ) + goto fail2; + + /* Copy data in */ if ( data_in ) { - falcon_read ( efab, ®, FCN_EE_SPI_HDATA_REG_KER ); + falcon_read ( efab, ®, FCN_EE_SPI_HDATA_REG ); memcpy ( data_in, ®, len ); } - + return 0; -} -/** - * Initialise SPI bus and devices - * - */ -static void falcon_init_spi ( struct efab_nic *efab ) { - efab_oword_t reg; - int eeprom_9bit; - - /* Initialise SPI bus */ - efab->spi.rw = falcon_spi_rw; - efab->falcon_eeprom.bus = &efab->spi; - efab->falcon_eeprom.slave = FCN_EE_SPI_EEPROM; - efab->falcon_flash.bus = &efab->spi; - efab->falcon_flash.slave = FCN_EE_SPI_FLASH; - - /* Initialise flash if present */ - if ( efab->has_flash ) { - DBG ( "Flash is present\n" ); - init_at25f1024 ( &efab->falcon_flash ); - } - - /* Initialise EEPROM if present */ - if ( efab->has_eeprom ) { - if ( efab->is_asic ) { - falcon_read ( efab, ®, FCN_VPD_CONFIG_REG_KER ); - eeprom_9bit = EFAB_OWORD_FIELD ( reg, FCN_VPD_9BIT ); - } else { - eeprom_9bit = 1; - } - if ( eeprom_9bit ) { - DBG ( "Small EEPROM is present\n" ); - init_at25040 ( &efab->falcon_eeprom ); - } else { - DBG ( "Large EEPROM is present\n" ); - init_mc25xx640 ( &efab->falcon_eeprom ); - /* Falcon's SPI interface cannot support a block - size larger than 16, so forcibly reduce it - */ - efab->falcon_eeprom.nvs.block_size = 16; - } - } -} +fail2: +fail1: + EFAB_ERR ( "Failed SPI command %d to device %d address 0x%x len 0x%zx\n", + command, device_id, address, len ); -/** Offset of MAC address within EEPROM or Flash */ -#define FALCON_MAC_ADDRESS_OFFSET(port) ( 0x310 + 0x08 * (port) ) + return rc; +} -static struct nvo_fragment falcon_eeprom_fragments[] = { - { 0x100, 0x100 }, +/** Portion of EEPROM available for non-volatile options */ +static struct nvo_fragment falcon_nvo_fragments[] = { + { 0x100, 0xf0 }, { 0, 0 } }; -/** - * Read MAC address from EEPROM +/******************************************************************************* * - */ -static int falcon_read_eeprom ( struct efab_nic *efab ) { - struct nvs_device *nvs; - - /* Determine the NVS device containing the MAC address */ - nvs = ( efab->has_flash ? - &efab->falcon_flash.nvs : &efab->falcon_eeprom.nvs ); - - return ( nvs_read ( nvs, FALCON_MAC_ADDRESS_OFFSET ( efab->port ), - efab->mac_addr, sizeof ( efab->mac_addr ) ) == 0 ); -} - -/** RX descriptor */ -typedef efab_qword_t falcon_rx_desc_t; - -/** - * Build RX descriptor * - */ -static void falcon_build_rx_desc ( struct efab_nic *efab, - struct efab_rx_buf *rx_buf ) { - falcon_rx_desc_t *rxd; - - rxd = ( ( falcon_rx_desc_t * ) efab->rxd ) + rx_buf->id; - EFAB_POPULATE_QWORD_2 ( *rxd, - FCN_RX_KER_BUF_SIZE, EFAB_DATA_BUF_SIZE, - FCN_RX_KER_BUF_ADR, - virt_to_bus ( rx_buf->addr ) ); -} - -/** - * Update RX descriptor write pointer + * Falcon bit-bashed I2C interface * - */ -static void falcon_notify_rx_desc ( struct efab_nic *efab ) { - efab_dword_t reg; - - EFAB_POPULATE_DWORD_1 ( reg, FCN_RX_DESC_WPTR_DWORD, - efab->rx_write_ptr ); - falcon_writel ( efab, ®, FCN_RX_DESC_UPD_REG_KER_DWORD ); -} + * + *******************************************************************************/ -/** TX descriptor */ -typedef efab_qword_t falcon_tx_desc_t; +static void +falcon_i2c_bit_write ( struct bit_basher *basher, unsigned int bit_id, + unsigned long data ) +{ + struct efab_nic *efab = container_of ( basher, struct efab_nic, + i2c_bb.basher ); + efab_oword_t reg; -/** - * Build TX descriptor - * - */ -static void falcon_build_tx_desc ( struct efab_nic *efab, - struct efab_tx_buf *tx_buf ) { - falcon_rx_desc_t *txd; + falcon_read ( efab, ®, FCN_GPIO_CTL_REG_KER ); + switch ( bit_id ) { + case I2C_BIT_SCL: + EFAB_SET_OWORD_FIELD ( reg, FCN_GPIO0_OEN, ( data ? 0 : 1 ) ); + break; + case I2C_BIT_SDA: + EFAB_SET_OWORD_FIELD ( reg, FCN_GPIO3_OEN, ( data ? 0 : 1 ) ); + break; + default: + EFAB_ERR ( "%s bit=%d\n", __func__, bit_id ); + break; + } - txd = ( ( falcon_rx_desc_t * ) efab->txd ) + tx_buf->id; - EFAB_POPULATE_QWORD_3 ( *txd, - FCN_TX_KER_PORT, efab->port, - FCN_TX_KER_BYTE_CNT, tx_buf->len, - FCN_TX_KER_BUF_ADR, - virt_to_bus ( tx_buf->addr ) ); + falcon_write ( efab, ®, FCN_GPIO_CTL_REG_KER ); } -/** - * Update TX descriptor write pointer - * - */ -static void falcon_notify_tx_desc ( struct efab_nic *efab ) { - efab_dword_t reg; +static int +falcon_i2c_bit_read ( struct bit_basher *basher, unsigned int bit_id ) +{ + struct efab_nic *efab = container_of ( basher, struct efab_nic, + i2c_bb.basher ); + efab_oword_t reg; + + falcon_read ( efab, ®, FCN_GPIO_CTL_REG_KER ); + switch ( bit_id ) { + case I2C_BIT_SCL: + return EFAB_OWORD_FIELD ( reg, FCN_GPIO0_IN ); + break; + case I2C_BIT_SDA: + return EFAB_OWORD_FIELD ( reg, FCN_GPIO3_IN ); + break; + default: + EFAB_ERR ( "%s bit=%d\n", __func__, bit_id ); + break; + } - EFAB_POPULATE_DWORD_1 ( reg, FCN_TX_DESC_WPTR_DWORD, - efab->tx_write_ptr ); - falcon_writel ( efab, ®, FCN_TX_DESC_UPD_REG_KER_DWORD ); + return -1; } -/** An event */ -typedef efab_qword_t falcon_event_t; +static struct bit_basher_operations falcon_i2c_bit_ops = { + .read = falcon_i2c_bit_read, + .write = falcon_i2c_bit_write, +}; -/** - * See if an event is present + +/******************************************************************************* * - * @v event Falcon event structure - * @ret True An event is pending - * @ret False No event is pending * - * We check both the high and low dword of the event for all ones. We - * wrote all ones when we cleared the event, and no valid event can - * have all ones in either its high or low dwords. This approach is - * robust against reordering. + * MDIO access * - * Note that using a single 64-bit comparison is incorrect; even - * though the CPU read will be atomic, the DMA write may not be. - */ -static inline int falcon_event_present ( falcon_event_t* event ) { - return ( ! ( EFAB_DWORD_IS_ALL_ONES ( event->dword[0] ) | - EFAB_DWORD_IS_ALL_ONES ( event->dword[1] ) ) ); -} - -/** - * Retrieve event from event queue * - */ -static int falcon_fetch_event ( struct efab_nic *efab, - struct efab_event *event ) { - falcon_event_t *evt; - int ev_code; - int rx_port; + *******************************************************************************/ - /* Check for event */ - evt = ( ( falcon_event_t * ) efab->eventq ) + efab->eventq_read_ptr; - if ( !falcon_event_present ( evt ) ) { - /* No event */ - return 0; - } - - DBG ( "Event is " EFAB_QWORD_FMT "\n", EFAB_QWORD_VAL ( *evt ) ); +static int +falcon_gmii_wait ( struct efab_nic *efab ) +{ + efab_dword_t md_stat; + int count; - /* Decode event */ - ev_code = EFAB_QWORD_FIELD ( *evt, FCN_EV_CODE ); - event->drop = 0; - switch ( ev_code ) { - case FCN_TX_IP_EV_DECODE: - event->type = EFAB_EV_TX; - break; - case FCN_RX_IP_EV_DECODE: - event->type = EFAB_EV_RX; - event->rx_id = EFAB_QWORD_FIELD ( *evt, FCN_RX_EV_DESC_PTR ); - event->rx_len = EFAB_QWORD_FIELD ( *evt, FCN_RX_EV_BYTE_CNT ); - event->drop = !EFAB_QWORD_FIELD ( *evt, FCN_RX_EV_PKT_OK ); - rx_port = EFAB_QWORD_FIELD ( *evt, FCN_RX_PORT ); - if ( rx_port != efab->port ) { - /* Ignore packets on the wrong port. We can't - * just set event->type = EFAB_EV_NONE, - * because then the descriptor ring won't get - * refilled. - */ - event->rx_len = 0; + /* wait upto 10ms */ + for (count = 0; count < 1000; count++) { + falcon_readl ( efab, &md_stat, FCN_MD_STAT_REG_KER ); + if ( EFAB_DWORD_FIELD ( md_stat, FCN_MD_BSY ) == 0 ) { + if ( EFAB_DWORD_FIELD ( md_stat, FCN_MD_LNFL ) != 0 || + EFAB_DWORD_FIELD ( md_stat, FCN_MD_BSERR ) != 0 ) { + EFAB_ERR ( "Error from GMII access " + EFAB_DWORD_FMT"\n", + EFAB_DWORD_VAL ( md_stat )); + return -EIO; + } + return 0; } - break; - case FCN_DRIVER_EV_DECODE: - /* Ignore start-of-day events */ - event->type = EFAB_EV_NONE; - break; - default: - EFAB_ERR ( "Unknown event type %d data %08lx\n", ev_code, - EFAB_DWORD_FIELD ( *evt, EFAB_DWORD_0 ) ); - event->type = EFAB_EV_NONE; + udelay(10); } - /* Clear event and any pending interrupts */ - EFAB_SET_QWORD ( *evt ); - falcon_writel ( efab, 0, FCN_INT_ACK_KER_REG ); - udelay ( 10 ); + EFAB_ERR ( "Timed out waiting for GMII\n" ); + return -ETIMEDOUT; +} - /* Increment and update event queue read pointer */ - efab->eventq_read_ptr = ( ( efab->eventq_read_ptr + 1 ) - % EFAB_EVQ_SIZE ); - falcon_eventq_read_ack ( efab ); +static void +falcon_mdio_write ( struct efab_nic *efab, int device, + int location, int value ) +{ + efab_oword_t reg; - return 1; -} + EFAB_TRACE ( "Writing GMII %d register %02x with %04x\n", + device, location, value ); -/** - * Enable/disable/generate interrupt - * - */ -static inline void falcon_interrupts ( struct efab_nic *efab, int enabled, - int force ) { - efab_oword_t int_en_reg_ker; + /* Check MII not currently being accessed */ + if ( falcon_gmii_wait ( efab ) ) + return; - EFAB_POPULATE_OWORD_2 ( int_en_reg_ker, - FCN_KER_INT_KER, force, - FCN_DRV_INT_EN_KER, enabled ); - falcon_write ( efab, &int_en_reg_ker, FCN_INT_EN_REG_KER ); -} + /* Write the address/ID register */ + EFAB_POPULATE_OWORD_1 ( reg, FCN_MD_PHY_ADR, location ); + falcon_write ( efab, ®, FCN_MD_PHY_ADR_REG_KER ); -/** - * Enable/disable interrupts - * - */ -static void falcon_mask_irq ( struct efab_nic *efab, int enabled ) { - falcon_interrupts ( efab, enabled, 0 ); - if ( enabled ) { - /* Events won't trigger interrupts until we do this */ - falcon_eventq_read_ack ( efab ); + if ( efab->phy_10g ) { + /* clause45 */ + EFAB_POPULATE_OWORD_2 ( reg, + FCN_MD_PRT_ADR, efab->phy_addr, + FCN_MD_DEV_ADR, device ); } -} + else { + /* clause22 */ + assert ( device == 0 ); -/** - * Generate interrupt - * - */ -static void falcon_generate_irq ( struct efab_nic *efab ) { - falcon_interrupts ( efab, 1, 1 ); + EFAB_POPULATE_OWORD_2 ( reg, + FCN_MD_PRT_ADR, efab->phy_addr, + FCN_MD_DEV_ADR, location ); + } + falcon_write ( efab, ®, FCN_MD_ID_REG_KER ); + + + /* Write data */ + EFAB_POPULATE_OWORD_1 ( reg, FCN_MD_TXD, value ); + falcon_write ( efab, ®, FCN_MD_TXD_REG_KER ); + + EFAB_POPULATE_OWORD_2 ( reg, + FCN_MD_WRC, 1, + FCN_MD_GC, ( efab->phy_10g ? 0 : 1 ) ); + falcon_write ( efab, ®, FCN_MD_CS_REG_KER ); + + /* Wait for data to be written */ + if ( falcon_gmii_wait ( efab ) ) { + /* Abort the write operation */ + EFAB_POPULATE_OWORD_2 ( reg, + FCN_MD_WRC, 0, + FCN_MD_GC, 1); + falcon_write ( efab, ®, FCN_MD_CS_REG_KER ); + udelay(10); + } } +static int +falcon_mdio_read ( struct efab_nic *efab, int device, int location ) +{ + efab_oword_t reg; + int value; -/** - * Reconfigure MAC wrapper + /* Check MII not currently being accessed */ + if ( falcon_gmii_wait ( efab ) ) + return -1; + + if ( efab->phy_10g ) { + /* clause45 */ + EFAB_POPULATE_OWORD_1 ( reg, FCN_MD_PHY_ADR, location ); + falcon_write ( efab, ®, FCN_MD_PHY_ADR_REG_KER ); + + EFAB_POPULATE_OWORD_2 ( reg, + FCN_MD_PRT_ADR, efab->phy_addr, + FCN_MD_DEV_ADR, device ); + falcon_write ( efab, ®, FCN_MD_ID_REG_KER); + + /* request data to be read */ + EFAB_POPULATE_OWORD_2 ( reg, + FCN_MD_RDC, 1, + FCN_MD_GC, 0 ); + } + else { + /* clause22 */ + assert ( device == 0 ); + + EFAB_POPULATE_OWORD_2 ( reg, + FCN_MD_PRT_ADR, efab->phy_addr, + FCN_MD_DEV_ADR, location ); + falcon_write ( efab, ®, FCN_MD_ID_REG_KER ); + + /* Request data to be read */ + EFAB_POPULATE_OWORD_2 ( reg, + FCN_MD_RIC, 1, + FCN_MD_GC, 1 ); + } + + falcon_write ( efab, ®, FCN_MD_CS_REG_KER ); + + /* Wait for data to become available */ + if ( falcon_gmii_wait ( efab ) ) { + /* Abort the read operation */ + EFAB_POPULATE_OWORD_2 ( reg, + FCN_MD_RIC, 0, + FCN_MD_GC, 1 ); + falcon_write ( efab, ®, FCN_MD_CS_REG_KER ); + udelay ( 10 ); + value = -1; + } + else { + /* Read the data */ + falcon_read ( efab, ®, FCN_MD_RXD_REG_KER ); + value = EFAB_OWORD_FIELD ( reg, FCN_MD_RXD ); + } + + EFAB_TRACE ( "Read from GMII %d register %02x, got %04x\n", + device, location, value ); + + return value; +} + +/******************************************************************************* * - */ -static void falcon_reconfigure_mac_wrapper ( struct efab_nic *efab ) { + * + * MAC wrapper + * + * + *******************************************************************************/ + +static void +falcon_reconfigure_mac_wrapper ( struct efab_nic *efab ) +{ efab_oword_t reg; int link_speed; @@ -2561,22 +1752,153 @@ static void falcon_reconfigure_mac_wrapper ( struct efab_nic *efab ) { FCN_MAC_UC_PROM, 0, FCN_MAC_LINK_STATUS, 1, FCN_MAC_SPEED, link_speed ); - falcon_write ( efab, ®, - ( efab->port == 0 ? - FCN_MAC0_CTRL_REG_KER : FCN_MAC1_CTRL_REG_KER ) ); - /* Disable flow-control (i.e. never generate pause frames) */ - falcon_read ( efab, ®, FCN_RX_CFG_REG_KER ); - EFAB_SET_OWORD_FIELD ( reg, FCN_RX_XOFF_EN, 0 ); - falcon_write ( efab, ®, FCN_RX_CFG_REG_KER ); + falcon_write ( efab, ®, FCN_MAC0_CTRL_REG_KER ); } -/** - * Write dword to a Falcon MAC register +/******************************************************************************* * - */ -static void falcon_gmac_writel ( struct efab_nic *efab, - efab_dword_t *value, unsigned int mac_reg ) { + * + * GMAC handling + * + * + *******************************************************************************/ + +/* GMAC configuration register 1 */ +#define GM_CFG1_REG_MAC 0x00 +#define GM_SW_RST_LBN 31 +#define GM_SW_RST_WIDTH 1 +#define GM_RX_FC_EN_LBN 5 +#define GM_RX_FC_EN_WIDTH 1 +#define GM_TX_FC_EN_LBN 4 +#define GM_TX_FC_EN_WIDTH 1 +#define GM_RX_EN_LBN 2 +#define GM_RX_EN_WIDTH 1 +#define GM_TX_EN_LBN 0 +#define GM_TX_EN_WIDTH 1 + +/* GMAC configuration register 2 */ +#define GM_CFG2_REG_MAC 0x01 +#define GM_PAMBL_LEN_LBN 12 +#define GM_PAMBL_LEN_WIDTH 4 +#define GM_IF_MODE_LBN 8 +#define GM_IF_MODE_WIDTH 2 +#define GM_PAD_CRC_EN_LBN 2 +#define GM_PAD_CRC_EN_WIDTH 1 +#define GM_FD_LBN 0 +#define GM_FD_WIDTH 1 + +/* GMAC maximum frame length register */ +#define GM_MAX_FLEN_REG_MAC 0x04 +#define GM_MAX_FLEN_LBN 0 +#define GM_MAX_FLEN_WIDTH 16 + +/* GMAC MII management configuration register */ +#define GM_MII_MGMT_CFG_REG_MAC 0x08 +#define GM_MGMT_CLK_SEL_LBN 0 +#define GM_MGMT_CLK_SEL_WIDTH 3 + +/* GMAC MII management command register */ +#define GM_MII_MGMT_CMD_REG_MAC 0x09 +#define GM_MGMT_SCAN_CYC_LBN 1 +#define GM_MGMT_SCAN_CYC_WIDTH 1 +#define GM_MGMT_RD_CYC_LBN 0 +#define GM_MGMT_RD_CYC_WIDTH 1 + +/* GMAC MII management address register */ +#define GM_MII_MGMT_ADR_REG_MAC 0x0a +#define GM_MGMT_PHY_ADDR_LBN 8 +#define GM_MGMT_PHY_ADDR_WIDTH 5 +#define GM_MGMT_REG_ADDR_LBN 0 +#define GM_MGMT_REG_ADDR_WIDTH 5 + +/* GMAC MII management control register */ +#define GM_MII_MGMT_CTL_REG_MAC 0x0b +#define GM_MGMT_CTL_LBN 0 +#define GM_MGMT_CTL_WIDTH 16 + +/* GMAC MII management status register */ +#define GM_MII_MGMT_STAT_REG_MAC 0x0c +#define GM_MGMT_STAT_LBN 0 +#define GM_MGMT_STAT_WIDTH 16 + +/* GMAC MII management indicators register */ +#define GM_MII_MGMT_IND_REG_MAC 0x0d +#define GM_MGMT_BUSY_LBN 0 +#define GM_MGMT_BUSY_WIDTH 1 + +/* GMAC station address register 1 */ +#define GM_ADR1_REG_MAC 0x10 +#define GM_HWADDR_5_LBN 24 +#define GM_HWADDR_5_WIDTH 8 +#define GM_HWADDR_4_LBN 16 +#define GM_HWADDR_4_WIDTH 8 +#define GM_HWADDR_3_LBN 8 +#define GM_HWADDR_3_WIDTH 8 +#define GM_HWADDR_2_LBN 0 +#define GM_HWADDR_2_WIDTH 8 + +/* GMAC station address register 2 */ +#define GM_ADR2_REG_MAC 0x11 +#define GM_HWADDR_1_LBN 24 +#define GM_HWADDR_1_WIDTH 8 +#define GM_HWADDR_0_LBN 16 +#define GM_HWADDR_0_WIDTH 8 + +/* GMAC FIFO configuration register 0 */ +#define GMF_CFG0_REG_MAC 0x12 +#define GMF_FTFENREQ_LBN 12 +#define GMF_FTFENREQ_WIDTH 1 +#define GMF_STFENREQ_LBN 11 +#define GMF_STFENREQ_WIDTH 1 +#define GMF_FRFENREQ_LBN 10 +#define GMF_FRFENREQ_WIDTH 1 +#define GMF_SRFENREQ_LBN 9 +#define GMF_SRFENREQ_WIDTH 1 +#define GMF_WTMENREQ_LBN 8 +#define GMF_WTMENREQ_WIDTH 1 + +/* GMAC FIFO configuration register 1 */ +#define GMF_CFG1_REG_MAC 0x13 +#define GMF_CFGFRTH_LBN 16 +#define GMF_CFGFRTH_WIDTH 5 +#define GMF_CFGXOFFRTX_LBN 0 +#define GMF_CFGXOFFRTX_WIDTH 16 + +/* GMAC FIFO configuration register 2 */ +#define GMF_CFG2_REG_MAC 0x14 +#define GMF_CFGHWM_LBN 16 +#define GMF_CFGHWM_WIDTH 6 +#define GMF_CFGLWM_LBN 0 +#define GMF_CFGLWM_WIDTH 6 + +/* GMAC FIFO configuration register 3 */ +#define GMF_CFG3_REG_MAC 0x15 +#define GMF_CFGHWMFT_LBN 16 +#define GMF_CFGHWMFT_WIDTH 6 +#define GMF_CFGFTTH_LBN 0 +#define GMF_CFGFTTH_WIDTH 6 + +/* GMAC FIFO configuration register 4 */ +#define GMF_CFG4_REG_MAC 0x16 +#define GMF_HSTFLTRFRM_PAUSE_LBN 12 +#define GMF_HSTFLTRFRM_PAUSE_WIDTH 12 + +/* GMAC FIFO configuration register 5 */ +#define GMF_CFG5_REG_MAC 0x17 +#define GMF_CFGHDPLX_LBN 22 +#define GMF_CFGHDPLX_WIDTH 1 +#define GMF_CFGBYTMODE_LBN 19 +#define GMF_CFGBYTMODE_WIDTH 1 +#define GMF_HSTDRPLT64_LBN 18 +#define GMF_HSTDRPLT64_WIDTH 1 +#define GMF_HSTFLTRFRMDC_PAUSE_LBN 12 +#define GMF_HSTFLTRFRMDC_PAUSE_WIDTH 1 + +static void +falcon_gmac_writel ( struct efab_nic *efab, efab_dword_t *value, + unsigned int mac_reg ) +{ efab_oword_t temp; EFAB_POPULATE_OWORD_1 ( temp, FCN_MAC_DATA, @@ -2584,12 +1906,10 @@ static void falcon_gmac_writel ( struct efab_nic *efab, falcon_write ( efab, &temp, FALCON_GMAC_REG ( efab, mac_reg ) ); } -/** - * Read dword from a Falcon GMAC register - * - */ -static void falcon_gmac_readl ( struct efab_nic *efab, efab_dword_t *value, - unsigned int mac_reg ) { +static void +falcon_gmac_readl ( struct efab_nic *efab, efab_dword_t *value, + unsigned int mac_reg ) +{ efab_oword_t temp; falcon_read ( efab, &temp, FALCON_GMAC_REG ( efab, mac_reg ) ); @@ -2597,12 +1917,172 @@ static void falcon_gmac_readl ( struct efab_nic *efab, efab_dword_t *value, EFAB_OWORD_FIELD ( temp, FCN_MAC_DATA ) ); } +static void +mentormac_reset ( struct efab_nic *efab ) +{ + efab_dword_t reg; + + /* Take into reset */ + EFAB_POPULATE_DWORD_1 ( reg, GM_SW_RST, 1 ); + falcon_gmac_writel ( efab, ®, GM_CFG1_REG_MAC ); + udelay ( 1000 ); + + /* Take out of reset */ + EFAB_POPULATE_DWORD_1 ( reg, GM_SW_RST, 0 ); + falcon_gmac_writel ( efab, ®, GM_CFG1_REG_MAC ); + udelay ( 1000 ); + + /* Configure GMII interface so PHY is accessible. Note that + * GMII interface is connected only to port 0, and that on + * Falcon this is a no-op. + */ + EFAB_POPULATE_DWORD_1 ( reg, GM_MGMT_CLK_SEL, 0x4 ); + falcon_gmac_writel ( efab, ®, GM_MII_MGMT_CFG_REG_MAC ); + udelay ( 10 ); +} + +static void +mentormac_init ( struct efab_nic *efab ) +{ + int pause, if_mode, full_duplex, bytemode, half_duplex; + efab_dword_t reg; + + /* Configuration register 1 */ + pause = ( efab->link_options & LPA_PAUSE ) ? 1 : 0; + if ( ! ( efab->link_options & LPA_DUPLEX ) ) { + /* Half-duplex operation requires TX flow control */ + pause = 1; + } + EFAB_POPULATE_DWORD_4 ( reg, + GM_TX_EN, 1, + GM_TX_FC_EN, pause, + GM_RX_EN, 1, + GM_RX_FC_EN, 1 ); + falcon_gmac_writel ( efab, ®, GM_CFG1_REG_MAC ); + udelay ( 10 ); + + /* Configuration register 2 */ + if_mode = ( efab->link_options & LPA_1000 ) ? 2 : 1; + full_duplex = ( efab->link_options & LPA_DUPLEX ) ? 1 : 0; + EFAB_POPULATE_DWORD_4 ( reg, + GM_IF_MODE, if_mode, + GM_PAD_CRC_EN, 1, + GM_FD, full_duplex, + GM_PAMBL_LEN, 0x7 /* ? */ ); + falcon_gmac_writel ( efab, ®, GM_CFG2_REG_MAC ); + udelay ( 10 ); + + /* Max frame len register */ + EFAB_POPULATE_DWORD_1 ( reg, GM_MAX_FLEN, + EFAB_MAX_FRAME_LEN ( ETH_FRAME_LEN ) ); + falcon_gmac_writel ( efab, ®, GM_MAX_FLEN_REG_MAC ); + udelay ( 10 ); + + /* FIFO configuration register 0 */ + EFAB_POPULATE_DWORD_5 ( reg, + GMF_FTFENREQ, 1, + GMF_STFENREQ, 1, + GMF_FRFENREQ, 1, + GMF_SRFENREQ, 1, + GMF_WTMENREQ, 1 ); + falcon_gmac_writel ( efab, ®, GMF_CFG0_REG_MAC ); + udelay ( 10 ); + + /* FIFO configuration register 1 */ + EFAB_POPULATE_DWORD_2 ( reg, + GMF_CFGFRTH, 0x12, + GMF_CFGXOFFRTX, 0xffff ); + falcon_gmac_writel ( efab, ®, GMF_CFG1_REG_MAC ); + udelay ( 10 ); + + /* FIFO configuration register 2 */ + EFAB_POPULATE_DWORD_2 ( reg, + GMF_CFGHWM, 0x3f, + GMF_CFGLWM, 0xa ); + falcon_gmac_writel ( efab, ®, GMF_CFG2_REG_MAC ); + udelay ( 10 ); + + /* FIFO configuration register 3 */ + EFAB_POPULATE_DWORD_2 ( reg, + GMF_CFGHWMFT, 0x1c, + GMF_CFGFTTH, 0x08 ); + falcon_gmac_writel ( efab, ®, GMF_CFG3_REG_MAC ); + udelay ( 10 ); + + /* FIFO configuration register 4 */ + EFAB_POPULATE_DWORD_1 ( reg, GMF_HSTFLTRFRM_PAUSE, 1 ); + falcon_gmac_writel ( efab, ®, GMF_CFG4_REG_MAC ); + udelay ( 10 ); + + /* FIFO configuration register 5 */ + bytemode = ( efab->link_options & LPA_1000 ) ? 1 : 0; + half_duplex = ( efab->link_options & LPA_DUPLEX ) ? 0 : 1; + falcon_gmac_readl ( efab, ®, GMF_CFG5_REG_MAC ); + EFAB_SET_DWORD_FIELD ( reg, GMF_CFGBYTMODE, bytemode ); + EFAB_SET_DWORD_FIELD ( reg, GMF_CFGHDPLX, half_duplex ); + EFAB_SET_DWORD_FIELD ( reg, GMF_HSTDRPLT64, half_duplex ); + EFAB_SET_DWORD_FIELD ( reg, GMF_HSTFLTRFRMDC_PAUSE, 0 ); + falcon_gmac_writel ( efab, ®, GMF_CFG5_REG_MAC ); + udelay ( 10 ); + + /* MAC address */ + EFAB_POPULATE_DWORD_4 ( reg, + GM_HWADDR_5, efab->mac_addr[5], + GM_HWADDR_4, efab->mac_addr[4], + GM_HWADDR_3, efab->mac_addr[3], + GM_HWADDR_2, efab->mac_addr[2] ); + falcon_gmac_writel ( efab, ®, GM_ADR1_REG_MAC ); + udelay ( 10 ); + EFAB_POPULATE_DWORD_2 ( reg, + GM_HWADDR_1, efab->mac_addr[1], + GM_HWADDR_0, efab->mac_addr[0] ); + falcon_gmac_writel ( efab, ®, GM_ADR2_REG_MAC ); + udelay ( 10 ); +} + +static int +falcon_init_gmac ( struct efab_nic *efab ) +{ + /* Reset the MAC */ + mentormac_reset ( efab ); + + /* Initialise PHY */ + efab->phy_op->init ( efab ); + + /* check the link is up */ + if ( !efab->link_up ) + return -EAGAIN; + + /* Initialise MAC */ + mentormac_init ( efab ); + + /* reconfigure the MAC wrapper */ + falcon_reconfigure_mac_wrapper ( efab ); + + return 0; +} + +static struct efab_mac_operations falcon_gmac_operations = { + .init = falcon_init_gmac, +}; + + +/******************************************************************************* + * + * + * XMAC handling + * + * + *******************************************************************************/ + /** * Write dword to a Falcon XMAC register * */ -static void falcon_xmac_writel ( struct efab_nic *efab, - efab_dword_t *value, unsigned int mac_reg ) { +static void +falcon_xmac_writel ( struct efab_nic *efab, efab_dword_t *value, + unsigned int mac_reg ) +{ efab_oword_t temp; EFAB_POPULATE_OWORD_1 ( temp, FCN_MAC_DATA, @@ -2615,9 +2095,10 @@ static void falcon_xmac_writel ( struct efab_nic *efab, * Read dword from a Falcon XMAC register * */ -static void falcon_xmac_readl ( struct efab_nic *efab, - efab_dword_t *value, - unsigned int mac_reg ) { +static void +falcon_xmac_readl ( struct efab_nic *efab, efab_dword_t *value, + unsigned int mac_reg ) +{ efab_oword_t temp; falcon_read ( efab, &temp, @@ -2627,109 +2108,159 @@ static void falcon_xmac_readl ( struct efab_nic *efab, } /** - * Initialise GMAC - * + * Configure Falcon XAUI output */ -static int falcon_init_gmac ( struct efab_nic *efab ) { - static struct efab_mentormac_parameters falcon_mentormac_params = { - .gmf_cfgfrth = 0x12, - .gmf_cfgftth = 0x08, - .gmf_cfghwmft = 0x1c, - .gmf_cfghwm = 0x3f, - .gmf_cfglwm = 0xa, - }; +static void +falcon_setup_xaui ( struct efab_nic *efab ) +{ + efab_dword_t sdctl, txdrv; + + falcon_xmac_readl ( efab, &sdctl, FCN_XX_SD_CTL_REG_MAC ); + EFAB_SET_DWORD_FIELD ( sdctl, FCN_XX_HIDRVD, XX_SD_CTL_DRV_DEFAULT ); + EFAB_SET_DWORD_FIELD ( sdctl, FCN_XX_LODRVD, XX_SD_CTL_DRV_DEFAULT ); + EFAB_SET_DWORD_FIELD ( sdctl, FCN_XX_HIDRVC, XX_SD_CTL_DRV_DEFAULT ); + EFAB_SET_DWORD_FIELD ( sdctl, FCN_XX_LODRVC, XX_SD_CTL_DRV_DEFAULT ); + EFAB_SET_DWORD_FIELD ( sdctl, FCN_XX_HIDRVB, XX_SD_CTL_DRV_DEFAULT ); + EFAB_SET_DWORD_FIELD ( sdctl, FCN_XX_LODRVB, XX_SD_CTL_DRV_DEFAULT ); + EFAB_SET_DWORD_FIELD ( sdctl, FCN_XX_HIDRVA, XX_SD_CTL_DRV_DEFAULT ); + EFAB_SET_DWORD_FIELD ( sdctl, FCN_XX_LODRVA, XX_SD_CTL_DRV_DEFAULT ); + falcon_xmac_writel ( efab, &sdctl, FCN_XX_SD_CTL_REG_MAC ); + + EFAB_POPULATE_DWORD_8 ( txdrv, + FCN_XX_DEQD, XX_TXDRV_DEQ_DEFAULT, + FCN_XX_DEQC, XX_TXDRV_DEQ_DEFAULT, + FCN_XX_DEQB, XX_TXDRV_DEQ_DEFAULT, + FCN_XX_DEQA, XX_TXDRV_DEQ_DEFAULT, + FCN_XX_DTXD, XX_TXDRV_DTX_DEFAULT, + FCN_XX_DTXC, XX_TXDRV_DTX_DEFAULT, + FCN_XX_DTXB, XX_TXDRV_DTX_DEFAULT, + FCN_XX_DTXA, XX_TXDRV_DTX_DEFAULT); + falcon_xmac_writel ( efab, &txdrv, FCN_XX_TXDRV_CTL_REG_MAC); +} - /* Initialise PHY */ - alaska_init ( efab ); +static int +falcon_xgmii_status ( struct efab_nic *efab ) +{ + efab_dword_t reg; - /* check the link is up */ - if ( !efab->link_up ) + if ( efab->pci_revision < FALCON_REV_B0 ) + return 1; + /* The ISR latches, so clear it and re-read */ + falcon_xmac_readl ( efab, ®, FCN_XM_MGT_INT_REG_MAC_B0 ); + falcon_xmac_readl ( efab, ®, FCN_XM_MGT_INT_REG_MAC_B0 ); + + if ( EFAB_DWORD_FIELD ( reg, FCN_XM_LCLFLT ) || + EFAB_DWORD_FIELD ( reg, FCN_XM_RMTFLT ) ) { + EFAB_TRACE ( "MGT_INT: "EFAB_DWORD_FMT"\n", + EFAB_DWORD_VAL ( reg ) ); return 0; - - /* Initialise MAC */ - mentormac_init ( efab, &falcon_mentormac_params ); - - /* reconfigure the MAC wrapper */ - falcon_reconfigure_mac_wrapper ( efab ); + } return 1; } -/** - * Reset GMAC - * - */ -static int falcon_reset_gmac ( struct efab_nic *efab ) { - mentormac_reset ( efab ); - return 1; +static void +falcon_mask_status_intr ( struct efab_nic *efab, int enable ) +{ + efab_dword_t reg; + + if ( efab->pci_revision < FALCON_REV_B0 ) + return; + + /* Flush the ISR */ + if ( enable ) + falcon_xmac_readl ( efab, ®, FCN_XM_MGT_INT_REG_MAC_B0 ); + + EFAB_POPULATE_DWORD_2 ( reg, + FCN_XM_MSK_RMTFLT, !enable, + FCN_XM_MSK_LCLFLT, !enable); + falcon_xmac_readl ( efab, ®, FCN_XM_MGT_INT_MSK_REG_MAC_B0 ); } /** - * Reset XAUI/XGXS block + * Reset 10G MAC connected to port * */ -static int falcon_reset_xaui ( struct efab_nic *efab ) +static int +falcon_reset_xmac ( struct efab_nic *efab ) { efab_dword_t reg; int count; - - EFAB_POPULATE_DWORD_1 ( reg, FCN_XX_RST_XX_EN, 1 ); - efab->mac_op->mac_writel ( efab, ®, FCN_XX_PWR_RST_REG_MAC ); + + EFAB_POPULATE_DWORD_1 ( reg, FCN_XM_CORE_RST, 1 ); + falcon_xmac_writel ( efab, ®, FCN_XM_GLB_CFG_REG_MAC ); for ( count = 0 ; count < 1000 ; count++ ) { udelay ( 10 ); - efab->mac_op->mac_readl ( efab, ®, - FCN_XX_PWR_RST_REG_MAC ); - if ( EFAB_DWORD_FIELD ( reg, FCN_XX_RST_XX_EN ) == 0 ) - return 1; + falcon_xmac_readl ( efab, ®, + FCN_XM_GLB_CFG_REG_MAC ); + if ( EFAB_DWORD_FIELD ( reg, FCN_XM_CORE_RST ) == 0 ) + return 0; } - - /* an error of some kind */ - return 0; + return -ETIMEDOUT; } -/** - * Reset 10G MAC connected to port - * - */ -static int falcon_reset_xmac ( struct efab_nic *efab ) { + +static int +falcon_reset_xaui ( struct efab_nic *efab ) +{ efab_dword_t reg; int count; - EFAB_POPULATE_DWORD_1 ( reg, FCN_XM_CORE_RST, 1 ); - efab->mac_op->mac_writel ( efab, ®, FCN_XM_GLB_CFG_REG_MAC ); + if (!efab->is_asic) + return 0; - for ( count = 0 ; count < 1000 ; count++ ) { - udelay ( 10 ); - efab->mac_op->mac_readl ( efab, ®, - FCN_XM_GLB_CFG_REG_MAC ); - if ( EFAB_DWORD_FIELD ( reg, FCN_XM_CORE_RST ) == 0 ) - return 1; + EFAB_POPULATE_DWORD_1 ( reg, FCN_XX_RST_XX_EN, 1 ); + falcon_xmac_writel ( efab, ®, FCN_XX_PWR_RST_REG_MAC ); + + /* Give some time for the link to establish */ + for (count = 0; count < 1000; count++) { /* wait upto 10ms */ + falcon_xmac_readl ( efab, ®, FCN_XX_PWR_RST_REG_MAC ); + if ( EFAB_DWORD_FIELD ( reg, FCN_XX_RST_XX_EN ) == 0 ) { + falcon_setup_xaui ( efab ); + return 0; + } + udelay(10); } - return 0; + EFAB_ERR ( "timed out waiting for XAUI/XGXS reset\n" ); + return -ETIMEDOUT; } -/** - * Get status of 10G link - * - */ -static int falcon_xaui_link_ok ( struct efab_nic *efab ) { +static int +falcon_xaui_link_ok ( struct efab_nic *efab ) +{ efab_dword_t reg; - int align_done; - int sync_status; - int link_ok = 0; + int align_done, lane_status, sync; + int has_phyxs; + int link_ok = 1; + + /* Read Falcon XAUI side */ + if ( efab->is_asic ) { + /* Read link status */ + falcon_xmac_readl ( efab, ®, FCN_XX_CORE_STAT_REG_MAC ); + align_done = EFAB_DWORD_FIELD ( reg, FCN_XX_ALIGN_DONE ); - /* Read link status */ - efab->mac_op->mac_readl ( efab, ®, FCN_XX_CORE_STAT_REG_MAC ); - align_done = EFAB_DWORD_FIELD ( reg, FCN_XX_ALIGN_DONE ); - sync_status = EFAB_DWORD_FIELD ( reg, FCN_XX_SYNC_STAT ); - if ( align_done && ( sync_status == FCN_XX_SYNC_STAT_DECODE_SYNCED ) ) { - link_ok = 1; + sync = EFAB_DWORD_FIELD ( reg, FCN_XX_SYNC_STAT ); + sync = ( sync == FCN_XX_SYNC_STAT_DECODE_SYNCED ); + + link_ok = align_done && sync; } /* Clear link status ready for next read */ EFAB_SET_DWORD_FIELD ( reg, FCN_XX_COMMA_DET, FCN_XX_COMMA_DET_RESET ); - efab->mac_op->mac_writel ( efab, ®, FCN_XX_CORE_STAT_REG_MAC ); + EFAB_SET_DWORD_FIELD ( reg, FCN_XX_CHARERR, FCN_XX_CHARERR_RESET); + EFAB_SET_DWORD_FIELD ( reg, FCN_XX_DISPERR, FCN_XX_DISPERR_RESET); + falcon_xmac_writel ( efab, ®, FCN_XX_CORE_STAT_REG_MAC ); + + has_phyxs = ( efab->phy_op->mmds & ( 1 << MDIO_MMD_PHYXS ) ); + if ( link_ok && has_phyxs ) { + lane_status = falcon_mdio_read ( efab, MDIO_MMD_PHYXS, + MDIO_PHYXS_LANE_STATE ); + link_ok = ( lane_status & ( 1 << MDIO_PHYXS_LANE_ALIGNED_LBN ) ); + + if (!link_ok ) + EFAB_LOG ( "XGXS lane status: %x\n", lane_status ); + } return link_ok; } @@ -2738,28 +2269,18 @@ static int falcon_xaui_link_ok ( struct efab_nic *efab ) { * Initialise XMAC * */ -static int falcon_init_xmac ( struct efab_nic *efab ) { +static void +falcon_reconfigure_xmac ( struct efab_nic *efab ) +{ efab_dword_t reg; - int count; + int max_frame_len; - if ( !falcon_reset_xmac ( efab ) ) { - EFAB_ERR ( "failed resetting XMAC\n" ); - return 0; - } - if ( !falcon_reset_xaui ( efab ) ) { - EFAB_ERR ( "failed resetting XAUI\n"); - return 0; - } - - /* CX4 is always 10000FD only */ - efab->link_options = LPA_10000FULL; - - /* Configure MAC */ + /* Configure MAC - cut-thru mode is hard wired on */ EFAB_POPULATE_DWORD_3 ( reg, FCN_XM_RX_JUMBO_MODE, 1, FCN_XM_TX_STAT_EN, 1, FCN_XM_RX_STAT_EN, 1); - efab->mac_op->mac_writel ( efab, ®, FCN_XM_GLB_CFG_REG_MAC ); + falcon_xmac_writel ( efab, ®, FCN_XM_GLB_CFG_REG_MAC ); /* Configure TX */ EFAB_POPULATE_DWORD_6 ( reg, @@ -2769,23 +2290,31 @@ static int falcon_init_xmac ( struct efab_nic *efab ) { FCN_XM_TXCRC, 1, FCN_XM_FCNTL, 1, FCN_XM_IPG, 0x3 ); - efab->mac_op->mac_writel ( efab, ®, FCN_XM_TX_CFG_REG_MAC ); + falcon_xmac_writel ( efab, ®, FCN_XM_TX_CFG_REG_MAC ); /* Configure RX */ - EFAB_POPULATE_DWORD_3 ( reg, + EFAB_POPULATE_DWORD_4 ( reg, FCN_XM_RXEN, 1, - FCN_XM_AUTO_DEPAD, 1, + FCN_XM_AUTO_DEPAD, 0, + FCN_XM_ACPT_ALL_MCAST, 1, FCN_XM_PASS_CRC_ERR, 1 ); - efab->mac_op->mac_writel ( efab, ®, FCN_XM_RX_CFG_REG_MAC ); + falcon_xmac_writel ( efab, ®, FCN_XM_RX_CFG_REG_MAC ); /* Set frame length */ + max_frame_len = EFAB_MAX_FRAME_LEN ( ETH_FRAME_LEN ); EFAB_POPULATE_DWORD_1 ( reg, - FCN_XM_MAX_RX_FRM_SIZE, ETH_FRAME_LEN ); - efab->mac_op->mac_writel ( efab, ®, FCN_XM_RX_PARAM_REG_MAC ); + FCN_XM_MAX_RX_FRM_SIZE, max_frame_len ); + falcon_xmac_writel ( efab, ®, FCN_XM_RX_PARAM_REG_MAC ); EFAB_POPULATE_DWORD_2 ( reg, - FCN_XM_MAX_TX_FRM_SIZE, ETH_FRAME_LEN, + FCN_XM_MAX_TX_FRM_SIZE, max_frame_len, FCN_XM_TX_JUMBO_MODE, 1 ); - efab->mac_op->mac_writel ( efab, ®, FCN_XM_TX_PARAM_REG_MAC ); + falcon_xmac_writel ( efab, ®, FCN_XM_TX_PARAM_REG_MAC ); + + /* Enable flow control receipt */ + EFAB_POPULATE_DWORD_2 ( reg, + FCN_XM_PAUSE_TIME, 0xfffe, + FCN_XM_DIS_FCNTL, 0 ); + falcon_xmac_writel ( efab, ®, FCN_XM_FC_REG_MAC ); /* Set MAC address */ EFAB_POPULATE_DWORD_4 ( reg, @@ -2793,639 +2322,1922 @@ static int falcon_init_xmac ( struct efab_nic *efab ) { FCN_XM_ADR_1, efab->mac_addr[1], FCN_XM_ADR_2, efab->mac_addr[2], FCN_XM_ADR_3, efab->mac_addr[3] ); - efab->mac_op->mac_writel ( efab, ®, FCN_XM_ADR_LO_REG_MAC ); + falcon_xmac_writel ( efab, ®, FCN_XM_ADR_LO_REG_MAC ); EFAB_POPULATE_DWORD_2 ( reg, FCN_XM_ADR_4, efab->mac_addr[4], FCN_XM_ADR_5, efab->mac_addr[5] ); - efab->mac_op->mac_writel ( efab, ®, FCN_XM_ADR_HI_REG_MAC ); + falcon_xmac_writel ( efab, ®, FCN_XM_ADR_HI_REG_MAC ); +} - /* Reconfigure MAC wrapper */ - falcon_reconfigure_mac_wrapper ( efab ); +static int +falcon_init_xmac ( struct efab_nic *efab ) +{ + int count, rc; + + /* Mask the PHY management interrupt */ + falcon_mask_status_intr ( efab, 0 ); + /* Initialise the PHY to instantiate the clock. */ + rc = efab->phy_op->init ( efab ); + if ( rc ) { + EFAB_ERR ( "unable to initialise PHY\n" ); + goto fail1; + } + + falcon_reset_xaui ( efab ); + + /* Give the PHY and MAC time to faff */ + mdelay ( 100 ); + + /* Reset and reconfigure the XMAC */ + rc = falcon_reset_xmac ( efab ); + if ( rc ) + goto fail2; + falcon_reconfigure_xmac ( efab ); + falcon_reconfigure_mac_wrapper ( efab ); /** - * Try resetting XAUI on its own waiting for the link - * to come up + * Now wait for the link to come up. This may take a while + * for some slower PHY's. */ - for(count=0; count<5; count++) { - /* Check link status */ - efab->link_up = falcon_xaui_link_ok ( efab ); - if ( efab->link_up ) { - /** - * Print out a speed message since we don't have a PHY - */ - EFAB_LOG ( "%dMbps %s-duplex\n", - ( efab->link_options & LPA_10000 ? 1000 : - ( efab->link_options & LPA_1000 ? 1000 : - ( efab->link_options & LPA_100 ? 100 : 10 ) ) ), - ( efab->link_options & LPA_DUPLEX ? "full" : "half" ) ); - break; + for (count=0; count<50; count++) { + int link_ok = 1; + + /* Wait a while for the link to come up. */ + mdelay ( 100 ); + if ((count % 5) == 0) + putchar ( '.' ); + + /* Does the PHY think the wire-side link is up? */ + link_ok = mdio_clause45_links_ok ( efab ); + /* Ensure the XAUI link to the PHY is good */ + if ( link_ok ) { + link_ok = falcon_xaui_link_ok ( efab ); + if ( !link_ok ) + falcon_reset_xaui ( efab ); } - if ( !falcon_reset_xaui ( efab ) ) { - EFAB_ERR ( "failed resetting xaui\n" ); + /* Check fault indication */ + if ( link_ok ) + link_ok = falcon_xgmii_status ( efab ); + + efab->link_up = link_ok; + if ( link_ok ) { + /* unmask the status interrupt */ + falcon_mask_status_intr ( efab, 1 ); return 0; } - udelay(100); } - return 1; + /* Link failed to come up, but initialisation was fine. */ + rc = -ETIMEDOUT; + +fail2: +fail1: + return rc; +} + +static struct efab_mac_operations falcon_xmac_operations = { + .init = falcon_init_xmac, +}; + +/******************************************************************************* + * + * + * Null PHY handling + * + * + *******************************************************************************/ + +static int +falcon_xaui_phy_init ( struct efab_nic *efab ) +{ + /* CX4 is always 10000FD only */ + efab->link_options = LPA_10000FULL; + + /* There is no PHY! */ + return 0; } +static struct efab_phy_operations falcon_xaui_phy_ops = { + .init = falcon_xaui_phy_init, + .mmds = 0, +}; + + +/******************************************************************************* + * + * + * Alaska PHY + * + * + *******************************************************************************/ + /** - * Wait for GMII access to complete + * Initialise Alaska PHY * */ -static int falcon_gmii_wait ( struct efab_nic *efab ) { - efab_oword_t md_stat; +static int +alaska_init ( struct efab_nic *efab ) +{ + unsigned int advertised, lpa; + + /* Read link up status */ + efab->link_up = gmii_link_ok ( efab ); + + if ( ! efab->link_up ) + return -EIO; + + /* Determine link options from PHY. */ + advertised = gmii_autoneg_advertised ( efab ); + lpa = gmii_autoneg_lpa ( efab ); + efab->link_options = gmii_nway_result ( advertised & lpa ); + + return 0; +} + +static struct efab_phy_operations falcon_alaska_phy_ops = { + .init = alaska_init, +}; + +/******************************************************************************* + * + * + * xfp + * + * + *******************************************************************************/ + +#define XFP_REQUIRED_DEVS ( MDIO_MMDREG_DEVS0_PCS | \ + MDIO_MMDREG_DEVS0_PMAPMD | \ + MDIO_MMDREG_DEVS0_PHYXS ) + +static int +falcon_xfp_phy_init ( struct efab_nic *efab ) +{ + int rc; + + /* Optical link is always 10000FD only */ + efab->link_options = LPA_10000FULL; + + /* Reset the PHY */ + rc = mdio_clause45_reset_mmd ( efab, MDIO_MMD_PHYXS ); + if ( rc ) + return rc; + + return 0; +} + +static struct efab_phy_operations falcon_xfp_phy_ops = { + .init = falcon_xfp_phy_init, + .mmds = XFP_REQUIRED_DEVS, +}; + +/******************************************************************************* + * + * + * txc43128 + * + * + *******************************************************************************/ + +/* Command register */ +#define TXC_GLRGS_GLCMD (0xc004) +#define TXC_GLCMD_LMTSWRST_LBN (14) + +/* Amplitude on lanes 0+1, 2+3 */ +#define TXC_ALRGS_ATXAMP0 (0xc041) +#define TXC_ALRGS_ATXAMP1 (0xc042) +/* Bit position of value for lane 0+2, 1+3 */ +#define TXC_ATXAMP_LANE02_LBN (3) +#define TXC_ATXAMP_LANE13_LBN (11) + +#define TXC_ATXAMP_1280_mV (0) +#define TXC_ATXAMP_1200_mV (8) +#define TXC_ATXAMP_1120_mV (12) +#define TXC_ATXAMP_1060_mV (14) +#define TXC_ATXAMP_0820_mV (25) +#define TXC_ATXAMP_0720_mV (26) +#define TXC_ATXAMP_0580_mV (27) +#define TXC_ATXAMP_0440_mV (28) + +#define TXC_ATXAMP_0820_BOTH ( (TXC_ATXAMP_0820_mV << TXC_ATXAMP_LANE02_LBN) | \ + (TXC_ATXAMP_0820_mV << TXC_ATXAMP_LANE13_LBN) ) + +#define TXC_ATXAMP_DEFAULT (0x6060) /* From databook */ + +/* Preemphasis on lanes 0+1, 2+3 */ +#define TXC_ALRGS_ATXPRE0 (0xc043) +#define TXC_ALRGS_ATXPRE1 (0xc044) + +#define TXC_ATXPRE_NONE (0) +#define TXC_ATXPRE_DEFAULT (0x1010) /* From databook */ + +#define TXC_REQUIRED_DEVS ( MDIO_MMDREG_DEVS0_PCS | \ + MDIO_MMDREG_DEVS0_PMAPMD | \ + MDIO_MMDREG_DEVS0_PHYXS ) + +static int +falcon_txc_logic_reset ( struct efab_nic *efab ) +{ + int val; + int tries = 50; + + val = falcon_mdio_read ( efab, MDIO_MMD_PCS, TXC_GLRGS_GLCMD ); + val |= (1 << TXC_GLCMD_LMTSWRST_LBN); + falcon_mdio_write ( efab, MDIO_MMD_PCS, TXC_GLRGS_GLCMD, val ); + + while ( tries--) { + val = falcon_mdio_read ( efab, MDIO_MMD_PCS, TXC_GLRGS_GLCMD ); + if ( ~val & ( 1 << TXC_GLCMD_LMTSWRST_LBN ) ) + return 0; + udelay(1); + } + + EFAB_ERR ( "logic reset failed\n" ); + + return -ETIMEDOUT; +} + +static int +falcon_txc_phy_init ( struct efab_nic *efab ) +{ + int rc; + + /* CX4 is always 10000FD only */ + efab->link_options = LPA_10000FULL; + + /* reset the phy */ + rc = mdio_clause45_reset_mmd ( efab, MDIO_MMD_PMAPMD ); + if ( rc ) + goto fail1; + + rc = mdio_clause45_check_mmds ( efab ); + if ( rc ) + goto fail2; + + /* Turn amplitude down and preemphasis off on the host side + * (PHY<->MAC) as this is believed less likely to upset falcon + * and no adverse effects have been noted. It probably also + * saves a picowatt or two */ + + /* Turn off preemphasis */ + falcon_mdio_write ( efab, MDIO_MMD_PHYXS, TXC_ALRGS_ATXPRE0, + TXC_ATXPRE_NONE ); + falcon_mdio_write ( efab, MDIO_MMD_PHYXS, TXC_ALRGS_ATXPRE1, + TXC_ATXPRE_NONE ); + + /* Turn down the amplitude */ + falcon_mdio_write ( efab, MDIO_MMD_PHYXS, TXC_ALRGS_ATXAMP0, + TXC_ATXAMP_0820_BOTH ); + falcon_mdio_write ( efab, MDIO_MMD_PHYXS, TXC_ALRGS_ATXAMP1, + TXC_ATXAMP_0820_BOTH ); + + /* Set the line side amplitude and preemphasis to the databook + * defaults as an erratum causes them to be 0 on at least some + * PHY rev.s */ + falcon_mdio_write ( efab, MDIO_MMD_PMAPMD, TXC_ALRGS_ATXPRE0, + TXC_ATXPRE_DEFAULT ); + falcon_mdio_write ( efab, MDIO_MMD_PMAPMD, TXC_ALRGS_ATXPRE1, + TXC_ATXPRE_DEFAULT ); + falcon_mdio_write ( efab, MDIO_MMD_PMAPMD, TXC_ALRGS_ATXAMP0, + TXC_ATXAMP_DEFAULT ); + falcon_mdio_write ( efab, MDIO_MMD_PMAPMD, TXC_ALRGS_ATXAMP1, + TXC_ATXAMP_DEFAULT ); + + rc = falcon_txc_logic_reset ( efab ); + if ( rc ) + goto fail3; + + return 0; + +fail3: +fail2: +fail1: + return rc; +} + +static struct efab_phy_operations falcon_txc_phy_ops = { + .init = falcon_txc_phy_init, + .mmds = TXC_REQUIRED_DEVS, +}; + +/******************************************************************************* + * + * + * tenxpress + * + * + *******************************************************************************/ + + +#define TENXPRESS_REQUIRED_DEVS ( MDIO_MMDREG_DEVS0_PMAPMD | \ + MDIO_MMDREG_DEVS0_PCS | \ + MDIO_MMDREG_DEVS0_PHYXS ) + +#define PCS_TEST_SELECT_REG 0xd807 /* PRM 10.5.8 */ +#define CLK312_EN_LBN 3 +#define CLK312_EN_WIDTH 1 + +#define PCS_CLOCK_CTRL_REG 0xd801 +#define PLL312_RST_N_LBN 2 + +/* Special Software reset register */ +#define PMA_PMD_EXT_CTRL_REG 49152 +#define PMA_PMD_EXT_SSR_LBN 15 + +/* Boot status register */ +#define PCS_BOOT_STATUS_REG 0xd000 +#define PCS_BOOT_FATAL_ERR_LBN 0 +#define PCS_BOOT_PROGRESS_LBN 1 +#define PCS_BOOT_PROGRESS_WIDTH 2 +#define PCS_BOOT_COMPLETE_LBN 3 + +#define PCS_SOFT_RST2_REG 0xd806 +#define SERDES_RST_N_LBN 13 +#define XGXS_RST_N_LBN 12 + +static int +falcon_tenxpress_check_c11 ( struct efab_nic *efab ) +{ int count; + uint32_t boot_stat; - for ( count = 0 ; count < 1000 ; count++ ) { - udelay ( 10 ); - falcon_read ( efab, &md_stat, FCN_MD_STAT_REG_KER ); - if ( EFAB_OWORD_FIELD ( md_stat, FCN_MD_BSY ) == 0 ) - return 1; + /* Check that the C11 CPU has booted */ + for (count=0; count<10; count++) { + boot_stat = falcon_mdio_read ( efab, MDIO_MMD_PCS, + PCS_BOOT_STATUS_REG ); + if ( boot_stat & ( 1 << PCS_BOOT_COMPLETE_LBN ) ) + return 0; + + udelay(10); } - EFAB_ERR ( "Timed out waiting for GMII\n" ); + + EFAB_ERR ( "C11 failed to boot\n" ); + return -ETIMEDOUT; +} + +static int +falcon_tenxpress_phy_init ( struct efab_nic *efab ) +{ + int rc, reg; + + /* 10XPRESS is always 10000FD (at the moment) */ + efab->link_options = LPA_10000FULL; + + /* Wait for the blocks to come out of reset */ + rc = mdio_clause45_wait_reset_mmds ( efab ); + if ( rc ) + goto fail1; + + rc = mdio_clause45_check_mmds ( efab ); + if ( rc ) + goto fail2; + + /* Turn on the clock */ + reg = (1 << CLK312_EN_LBN); + falcon_mdio_write ( efab, MDIO_MMD_PCS, PCS_TEST_SELECT_REG, reg); + + /* Wait 200ms for the PHY to boot */ + mdelay(200); + + rc = falcon_tenxpress_check_c11 ( efab ); + if ( rc ) + goto fail3; + return 0; + +fail3: +fail2: +fail1: + return rc; } +static struct efab_phy_operations falcon_tenxpress_phy_ops = { + .init = falcon_tenxpress_phy_init, + .mmds = TENXPRESS_REQUIRED_DEVS, +}; -static struct efab_mac_operations falcon_xmac_operations = { - .mac_readl = falcon_xmac_readl, - .mac_writel = falcon_xmac_writel, - .init = falcon_init_xmac, - .reset = falcon_reset_xmac, +/******************************************************************************* + * + * + * PM8358 + * + * + *******************************************************************************/ + +/* The PM8358 just presents a DTE XS */ +#define PM8358_REQUIRED_DEVS (MDIO_MMDREG_DEVS0_DTEXS) + +/* PHY-specific definitions */ +/* Master ID and Global Performance Monitor Update */ +#define PMC_MASTER_REG (0xd000) +/* Analog Tx Rx settings under software control */ +#define PMC_MASTER_ANLG_CTRL (1<< 11) + +/* Master Configuration register 2 */ +#define PMC_MCONF2_REG (0xd002) +/* Drive Tx off centre of data eye (1) vs. clock edge (0) */ +#define PMC_MCONF2_TEDGE (1 << 2) +/* Drive Rx off centre of data eye (1) vs. clock edge (0) */ +#define PMC_MCONF2_REDGE (1 << 3) + +/* Analog Rx settings */ +#define PMC_ANALOG_RX_CFG0 (0xd025) +#define PMC_ANALOG_RX_CFG1 (0xd02d) +#define PMC_ANALOG_RX_CFG2 (0xd035) +#define PMC_ANALOG_RX_CFG3 (0xd03d) + + +#define PMC_ANALOG_RX_TERM (1 << 15) /* Bit 15 of RX CFG: 0 for 100 ohms float, + 1 for 50 to 1.2V */ +#define PMC_ANALOG_RX_EQ_MASK (3 << 8) +#define PMC_ANALOG_RX_EQ_NONE (0 << 8) +#define PMC_ANALOG_RX_EQ_HALF (1 << 8) +#define PMC_ANALOG_RX_EQ_FULL (2 << 8) +#define PMC_ANALOG_RX_EQ_RSVD (3 << 8) + +static int +falcon_pm8358_phy_init ( struct efab_nic *efab ) +{ + int rc, reg, i; + + /* This is a XAUI retimer part */ + efab->link_options = LPA_10000FULL; + + rc = mdio_clause45_reset_mmd ( efab, MDIO_MMDREG_DEVS0_DTEXS ); + if ( rc ) + return rc; + + /* Enable software control of analogue settings */ + reg = falcon_mdio_read ( efab, MDIO_MMD_DTEXS, PMC_MASTER_REG ); + reg |= PMC_MASTER_ANLG_CTRL; + falcon_mdio_write ( efab, MDIO_MMD_DTEXS, PMC_MASTER_REG, reg ); + + /* Turn rx eq on for all channels */ + for (i=0; i< 3; i++) { + /* The analog CFG registers are evenly spaced 8 apart */ + uint16_t addr = PMC_ANALOG_RX_CFG0 + 8*i; + reg = falcon_mdio_read ( efab, MDIO_MMD_DTEXS, addr ); + reg = ( reg & ~PMC_ANALOG_RX_EQ_MASK ) | PMC_ANALOG_RX_EQ_FULL; + falcon_mdio_write ( efab, MDIO_MMD_DTEXS, addr, reg ); + } + + /* Set TEDGE, clear REDGE */ + reg = falcon_mdio_read ( efab, MDIO_MMD_DTEXS, PMC_MCONF2_REG ); + reg = ( reg & ~PMC_MCONF2_REDGE) | PMC_MCONF2_TEDGE; + falcon_mdio_write ( efab, MDIO_MMD_DTEXS, PMC_MCONF2_REG, reg ); + + return 0; +} + +static struct efab_phy_operations falcon_pm8358_phy_ops = { + .init = falcon_pm8358_phy_init, + .mmds = PM8358_REQUIRED_DEVS, }; -static struct efab_mac_operations falcon_gmac_operations = { - .mac_readl = falcon_gmac_readl, - .mac_writel = falcon_gmac_writel, - .init = falcon_init_gmac, - .reset = falcon_reset_gmac, +/******************************************************************************* + * + * + * SFE4001 support + * + * + *******************************************************************************/ + +#define MAX_TEMP_THRESH 90 + +/* I2C Expander */ +#define PCA9539 0x74 + +#define P0_IN 0x00 +#define P0_OUT 0x02 +#define P0_CONFIG 0x06 + +#define P0_EN_1V0X_LBN 0 +#define P0_EN_1V0X_WIDTH 1 +#define P0_EN_1V2_LBN 1 +#define P0_EN_1V2_WIDTH 1 +#define P0_EN_2V5_LBN 2 +#define P0_EN_2V5_WIDTH 1 +#define P0_EN_3V3X_LBN 3 +#define P0_EN_3V3X_WIDTH 1 +#define P0_EN_5V_LBN 4 +#define P0_EN_5V_WIDTH 1 +#define P0_X_TRST_LBN 6 +#define P0_X_TRST_WIDTH 1 + +#define P1_IN 0x01 +#define P1_CONFIG 0x07 + +#define P1_AFE_PWD_LBN 0 +#define P1_AFE_PWD_WIDTH 1 +#define P1_DSP_PWD25_LBN 1 +#define P1_DSP_PWD25_WIDTH 1 +#define P1_SPARE_LBN 4 +#define P1_SPARE_WIDTH 4 + +/* Temperature Sensor */ +#define MAX6647 0x4e + +#define RSL 0x02 +#define RLHN 0x05 +#define WLHO 0x0b + +static struct i2c_device i2c_pca9539 = { + .dev_addr = PCA9539, + .dev_addr_len = 1, + .word_addr_len = 1, }; -/** - * Initialise NIC +static struct i2c_device i2c_max6647 = { + .dev_addr = MAX6647, + .dev_addr_len = 1, + .word_addr_len = 1, +}; + +static int +sfe4001_init ( struct efab_nic *efab ) +{ + struct i2c_interface *i2c = &efab->i2c_bb.i2c; + efab_dword_t reg; + uint8_t in, cfg, out; + int count, rc; + + EFAB_LOG ( "Initialise SFE4001 board\n" ); + + /* Ensure XGXS and XAUI SerDes are held in reset */ + EFAB_POPULATE_DWORD_7 ( reg, + FCN_XX_PWRDNA_EN, 1, + FCN_XX_PWRDNB_EN, 1, + FCN_XX_RSTPLLAB_EN, 1, + FCN_XX_RESETA_EN, 1, + FCN_XX_RESETB_EN, 1, + FCN_XX_RSTXGXSRX_EN, 1, + FCN_XX_RSTXGXSTX_EN, 1 ); + falcon_xmac_writel ( efab, ®, FCN_XX_PWR_RST_REG_MAC); + udelay(10); + + /* Set DSP over-temperature alert threshold */ + cfg = MAX_TEMP_THRESH; + rc = i2c->write ( i2c, &i2c_max6647, WLHO, &cfg, EFAB_BYTE ); + if ( rc ) + goto fail1; + + /* Read it back and verify */ + rc = i2c->read ( i2c, &i2c_max6647, RLHN, &in, EFAB_BYTE ); + if ( rc ) + goto fail2; + + if ( in != MAX_TEMP_THRESH ) { + EFAB_ERR ( "Unable to verify MAX6647 limit (requested=%d " + "confirmed=%d)\n", cfg, in ); + rc = -EIO; + goto fail3; + } + + /* Clear any previous over-temperature alert */ + rc = i2c->read ( i2c, &i2c_max6647, RSL, &in, EFAB_BYTE ); + if ( rc ) + goto fail4; + + /* Enable port 0 and 1 outputs on IO expander */ + cfg = 0x00; + rc = i2c->write ( i2c, &i2c_pca9539, P0_CONFIG, &cfg, EFAB_BYTE ); + if ( rc ) + goto fail5; + cfg = 0xff & ~(1 << P1_SPARE_LBN); + rc = i2c->write ( i2c, &i2c_pca9539, P1_CONFIG, &cfg, EFAB_BYTE ); + if ( rc ) + goto fail6; + + /* Turn all power off then wait 1 sec. This ensures PHY is reset */ + out = 0xff & ~((0 << P0_EN_1V2_LBN) | (0 << P0_EN_2V5_LBN) | + (0 << P0_EN_3V3X_LBN) | (0 << P0_EN_5V_LBN) | + (0 << P0_EN_1V0X_LBN)); + + rc = i2c->write ( i2c, &i2c_pca9539, P0_OUT, &out, EFAB_BYTE ); + if ( rc ) + goto fail7; + + mdelay(1000); + + for (count=0; count<20; count++) { + /* Turn on 1.2V, 2.5V, 3.3V and 5V power rails */ + out = 0xff & ~( (1 << P0_EN_1V2_LBN) | (1 << P0_EN_2V5_LBN) | + (1 << P0_EN_3V3X_LBN) | (1 << P0_EN_5V_LBN) | + (1 << P0_X_TRST_LBN) ); + + rc = i2c->write ( i2c, &i2c_pca9539, P0_OUT, &out, EFAB_BYTE ); + if ( rc ) + goto fail8; + + mdelay ( 10 ); + + /* Turn on the 1V power rail */ + out &= ~( 1 << P0_EN_1V0X_LBN ); + rc = i2c->write ( i2c, &i2c_pca9539, P0_OUT, &out, EFAB_BYTE ); + if ( rc ) + goto fail9; + + EFAB_LOG ( "Waiting for power...(attempt %d)\n", count); + mdelay ( 1000 ); + + /* Check DSP is powered */ + rc = i2c->read ( i2c, &i2c_pca9539, P1_IN, &in, EFAB_BYTE ); + if ( rc ) + goto fail10; + + if ( in & ( 1 << P1_AFE_PWD_LBN ) ) + return 0; + } + + rc = -ETIMEDOUT; + +fail10: +fail9: +fail8: +fail7: + /* Turn off power rails */ + out = 0xff; + (void) i2c->write ( i2c, &i2c_pca9539, P0_OUT, &out, EFAB_BYTE ); + /* Disable port 1 outputs on IO expander */ + out = 0xff; + (void) i2c->write ( i2c, &i2c_pca9539, P1_CONFIG, &out, EFAB_BYTE ); +fail6: + /* Disable port 0 outputs */ + out = 0xff; + (void) i2c->write ( i2c, &i2c_pca9539, P1_CONFIG, &out, EFAB_BYTE ); +fail5: +fail4: +fail3: +fail2: +fail1: + EFAB_ERR ( "Failed initialising SFE4001 board\n" ); + return rc; +} + +static void +sfe4001_fini ( struct efab_nic *efab ) +{ + struct i2c_interface *i2c = &efab->i2c_bb.i2c; + uint8_t in, cfg, out; + + EFAB_ERR ( "Turning off SFE4001\n" ); + + /* Turn off all power rails */ + out = 0xff; + (void) i2c->write ( i2c, &i2c_pca9539, P0_OUT, &out, EFAB_BYTE ); + + /* Disable port 1 outputs on IO expander */ + cfg = 0xff; + (void) i2c->write ( i2c, &i2c_pca9539, P1_CONFIG, &cfg, EFAB_BYTE ); + + /* Disable port 0 outputs on IO expander */ + cfg = 0xff; + (void) i2c->write ( i2c, &i2c_pca9539, P0_CONFIG, &cfg, EFAB_BYTE ); + + /* Clear any over-temperature alert */ + (void) i2c->read ( i2c, &i2c_max6647, RSL, &in, EFAB_BYTE ); +} + +struct efab_board_operations sfe4001_ops = { + .init = sfe4001_init, + .fini = sfe4001_fini, +}; + +static int sfe4002_init ( struct efab_nic *efab __attribute__((unused)) ) +{ + return 0; +} +static void sfe4002_fini ( struct efab_nic *efab __attribute__((unused)) ) +{ +} + +struct efab_board_operations sfe4002_ops = { + .init = sfe4002_init, + .fini = sfe4002_fini, +}; + +static int sfe4003_init ( struct efab_nic *efab __attribute__((unused)) ) +{ + return 0; +} +static void sfe4003_fini ( struct efab_nic *efab __attribute__((unused)) ) +{ +} + +struct efab_board_operations sfe4003_ops = { + .init = sfe4003_init, + .fini = sfe4003_fini, +}; + +/******************************************************************************* * - */ -static int falcon_init_nic ( struct efab_nic *efab ) { - efab_oword_t reg; - efab_dword_t timer_cmd; - int version, minor; + * + * Hardware initialisation + * + * + *******************************************************************************/ - /* use card in internal SRAM mode */ - falcon_read ( efab, ®, FCN_NIC_STAT_REG ); - EFAB_SET_OWORD_FIELD ( reg, ONCHIP_SRAM, 1 ); - falcon_write ( efab, ®, FCN_NIC_STAT_REG ); - wmb(); +static void +falcon_free_special_buffer ( void *p ) +{ + /* We don't bother cleaning up the buffer table entries - + * we're hardly limited */ + free_dma ( p, EFAB_BUF_ALIGN ); +} + +static void* +falcon_alloc_special_buffer ( struct efab_nic *efab, int bytes, + struct efab_special_buffer *entry ) +{ + void* buffer; + int remaining; + efab_qword_t buf_desc; + unsigned long dma_addr; + + /* Allocate the buffer, aligned on a buffer address boundary */ + buffer = malloc_dma ( bytes, EFAB_BUF_ALIGN ); + if ( ! buffer ) + return NULL; + + /* Push buffer table entries to back the buffer */ + entry->id = efab->buffer_head; + entry->dma_addr = dma_addr = virt_to_bus ( buffer ); + assert ( ( dma_addr & ( EFAB_BUF_ALIGN - 1 ) ) == 0 ); + + remaining = bytes; + while ( remaining > 0 ) { + EFAB_POPULATE_QWORD_3 ( buf_desc, + FCN_IP_DAT_BUF_SIZE, FCN_IP_DAT_BUF_SIZE_4K, + FCN_BUF_ADR_FBUF, ( dma_addr >> 12 ), + FCN_BUF_OWNER_ID_FBUF, 0 ); + + falcon_write_sram ( efab, &buf_desc, efab->buffer_head ); + + ++efab->buffer_head; + dma_addr += EFAB_BUF_ALIGN; + remaining -= EFAB_BUF_ALIGN; + } + + EFAB_TRACE ( "Allocated 0x%x bytes at %p backed by buffer table " + "entries 0x%x..0x%x\n", bytes, buffer, entry->id, + efab->buffer_head - 1 ); + + return buffer; +} - /* identify FPGA/ASIC, and strapping mode */ - falcon_read ( efab, ®, ALTERA_BUILD_REG_KER ); - version = EFAB_OWORD_FIELD ( reg, VER_ALL ); - efab->is_asic = version ? 0 : 1; +static void +clear_b0_fpga_memories ( struct efab_nic *efab) +{ + efab_oword_t blanko, temp; + efab_dword_t blankd; + int offset; + + EFAB_ZERO_OWORD ( blanko ); + EFAB_ZERO_DWORD ( blankd ); + + /* Clear the address region register */ + EFAB_POPULATE_OWORD_4 ( temp, + FCN_ADR_REGION0, 0, + FCN_ADR_REGION1, ( 1 << 16 ), + FCN_ADR_REGION2, ( 2 << 16 ), + FCN_ADR_REGION3, ( 3 << 16 ) ); + falcon_write ( efab, &temp, FCN_ADR_REGION_REG_KER ); - if ( efab->is_asic ) { - falcon_read ( efab, ®, FCN_NIC_STAT_REG ); - if ( EFAB_OWORD_FIELD ( reg, STRAP_10G ) ) { - efab->is_10g = 1; - } - if ( EFAB_OWORD_FIELD ( reg, STRAP_DUAL_PORT ) ) { - efab->is_dual = 1; - } + EFAB_TRACE ( "Clearing filter and RSS tables\n" ); + + for ( offset = FCN_RX_FILTER_TBL0 ; + offset < FCN_RX_RSS_INDIR_TBL_B0+0x800 ; + offset += 0x10 ) { + falcon_write ( efab, &blanko, offset ); + } + + EFAB_TRACE ( "Wiping buffer tables\n" ); + + /* Notice the 8 byte access mode */ + for ( offset = 0x2800000 ; + offset < 0x3000000 ; + offset += 0x8) { + _falcon_writel ( efab, 0, offset ); + _falcon_writel ( efab, 0, offset + 4 ); + wmb(); + } +} + +static int +falcon_reset ( struct efab_nic *efab ) +{ + efab_oword_t glb_ctl_reg_ker; + + /* Initiate software reset */ + EFAB_POPULATE_OWORD_6 ( glb_ctl_reg_ker, + FCN_PCIE_CORE_RST_CTL, EXCLUDE_FROM_RESET, + FCN_PCIE_NSTCK_RST_CTL, EXCLUDE_FROM_RESET, + FCN_PCIE_SD_RST_CTL, EXCLUDE_FROM_RESET, + FCN_EE_RST_CTL, EXCLUDE_FROM_RESET, + FCN_EXT_PHY_RST_DUR, 0x7, /* 10ms */ + FCN_SWRST, 1 ); + + falcon_write ( efab, &glb_ctl_reg_ker, FCN_GLB_CTL_REG_KER ); + + /* Allow 50ms for reset */ + mdelay ( 50 ); + + /* Check for device reset complete */ + falcon_read ( efab, &glb_ctl_reg_ker, FCN_GLB_CTL_REG_KER ); + if ( EFAB_OWORD_FIELD ( glb_ctl_reg_ker, FCN_SWRST ) != 0 ) { + EFAB_ERR ( "Reset failed\n" ); + return -ETIMEDOUT; + } + + if ( ( efab->pci_revision == FALCON_REV_B0 ) && !efab->is_asic ) { + clear_b0_fpga_memories ( efab ); + } + + return 0; +} + +/** Offset of MAC address within EEPROM or Flash */ +#define FALCON_MAC_ADDRESS_OFFSET 0x310 + +/* + * Falcon EEPROM structure + */ +#define SF_NV_CONFIG_BASE 0x300 +#define SF_NV_CONFIG_EXTRA 0xA0 + +struct falcon_nv_config_ver2 { + uint16_t nports; + uint8_t port0_phy_addr; + uint8_t port0_phy_type; + uint8_t port1_phy_addr; + uint8_t port1_phy_type; + uint16_t asic_sub_revision; + uint16_t board_revision; + uint8_t mac_location; +}; + +struct falcon_nv_extra { + uint16_t magicnumber; + uint16_t structure_version; + uint16_t checksum; + union { + struct falcon_nv_config_ver2 ver2; + } ver_specific; +}; + +#define BOARD_TYPE(_rev) (_rev >> 8) + +static void +falcon_probe_nic_variant ( struct efab_nic *efab, struct pci_device *pci ) +{ + efab_oword_t altera_build, nic_stat; + int is_pcie, fpga_version; + uint8_t revision; + + /* PCI revision */ + pci_read_config_byte ( pci, PCI_CLASS_REVISION, &revision ); + efab->pci_revision = revision; + + /* Asic vs FPGA */ + falcon_read ( efab, &altera_build, FCN_ALTERA_BUILD_REG_KER ); + fpga_version = EFAB_OWORD_FIELD ( altera_build, FCN_VER_ALL ); + efab->is_asic = (fpga_version == 0); + + /* MAC and PCI type */ + falcon_read ( efab, &nic_stat, FCN_NIC_STAT_REG ); + if ( efab->pci_revision == FALCON_REV_B0 ) { + is_pcie = 1; + efab->phy_10g = EFAB_OWORD_FIELD ( nic_stat, FCN_STRAP_10G ); + } + else if ( efab->is_asic ) { + is_pcie = EFAB_OWORD_FIELD ( nic_stat, FCN_STRAP_PCIE ); + efab->phy_10g = EFAB_OWORD_FIELD ( nic_stat, FCN_STRAP_10G ); } else { - falcon_read ( efab, ®, ALTERA_BUILD_REG_KER ); - minor = EFAB_OWORD_FIELD ( reg, VER_MINOR ); + int minor = EFAB_OWORD_FIELD ( altera_build, FCN_VER_MINOR ); + is_pcie = 0; + efab->phy_10g = ( minor == 0x14 ); + } +} + +static void +falcon_init_spi_device ( struct efab_nic *efab, struct spi_device *spi ) +{ + /* Falcon's SPI interface only supports reads/writes of up to 16 bytes. + * Reduce the nvs block size down to satisfy this - which means callers + * should use the nvs_* functions rather than spi_*. */ + if ( spi->nvs.block_size > FALCON_SPI_MAX_LEN ) + spi->nvs.block_size = FALCON_SPI_MAX_LEN; + + spi->bus = &efab->spi_bus; + efab->spi = spi; +} + +static int +falcon_probe_spi ( struct efab_nic *efab ) +{ + efab_oword_t nic_stat, gpio_ctl, ee_vpd_cfg; + int has_flash, has_eeprom, ad9bit; + + falcon_read ( efab, &nic_stat, FCN_NIC_STAT_REG ); + falcon_read ( efab, &gpio_ctl, FCN_GPIO_CTL_REG_KER ); + falcon_read ( efab, &ee_vpd_cfg, FCN_EE_VPD_CFG_REG ); + + /* determine if FLASH / EEPROM is present */ + if ( ( efab->pci_revision >= FALCON_REV_B0 ) || efab->is_asic ) { + has_flash = EFAB_OWORD_FIELD ( nic_stat, FCN_SF_PRST ); + has_eeprom = EFAB_OWORD_FIELD ( nic_stat, FCN_EE_PRST ); + } else { + has_flash = EFAB_OWORD_FIELD ( gpio_ctl, FCN_FLASH_PRESENT ); + has_eeprom = EFAB_OWORD_FIELD ( gpio_ctl, FCN_EEPROM_PRESENT ); + } + ad9bit = EFAB_OWORD_FIELD ( ee_vpd_cfg, FCN_EE_VPD_EN_AD9_MODE ); + + /* Configure the SPI and I2C bus */ + efab->spi_bus.rw = falcon_spi_rw; + init_i2c_bit_basher ( &efab->i2c_bb, &falcon_i2c_bit_ops ); + + /* Configure the EEPROM SPI device. Generally, an Atmel 25040 + * (or similar) is used, but this is only possible if there is also + * a flash device present to store the boot-time chip configuration. + */ + if ( has_eeprom ) { + if ( has_flash && ad9bit ) + init_at25040 ( &efab->spi_eeprom ); + else + init_mc25xx640 ( &efab->spi_eeprom ); + falcon_init_spi_device ( efab, &efab->spi_eeprom ); + } + + /* Configure the FLASH SPI device */ + if ( has_flash ) { + init_at25f1024 ( &efab->spi_flash ); + falcon_init_spi_device ( efab, &efab->spi_flash ); + } + + EFAB_LOG ( "flash is %s, EEPROM is %s%s\n", + ( has_flash ? "present" : "absent" ), + ( has_eeprom ? "present " : "absent" ), + ( has_eeprom ? (ad9bit ? "(9bit)" : "(16bit)") : "") ); + + /* The device MUST have flash or eeprom */ + if ( ! efab->spi ) { + EFAB_ERR ( "Device appears to have no flash or eeprom\n" ); + return -EIO; + } + + /* If the device has EEPROM attached, then advertise NVO space */ + if ( has_eeprom ) + nvo_init ( &efab->nvo, &efab->spi_eeprom.nvs, falcon_nvo_fragments, + &efab->netdev->refcnt ); + + return 0; +} + +static int +falcon_probe_nvram ( struct efab_nic *efab ) +{ + struct nvs_device *nvs = &efab->spi->nvs; + struct falcon_nv_extra nv; + int rc, board_revision; + + /* Read the MAC address */ + rc = nvs_read ( nvs, FALCON_MAC_ADDRESS_OFFSET, + efab->mac_addr, ETH_ALEN ); + if ( rc ) + return rc; + + /* Poke through the NVRAM structure for the PHY type. */ + rc = nvs_read ( nvs, SF_NV_CONFIG_BASE + SF_NV_CONFIG_EXTRA, + &nv, sizeof ( nv ) ); + if ( rc ) + return rc; + + /* Handle each supported NVRAM version */ + if ( ( le16_to_cpu ( nv.magicnumber ) == FCN_NV_MAGIC_NUMBER ) && + ( le16_to_cpu ( nv.structure_version ) >= 2 ) ) { + struct falcon_nv_config_ver2* ver2 = &nv.ver_specific.ver2; - if ( minor == 0x14 ) { - efab->is_10g = 1; - } else if ( minor == 0x13 ) { - efab->is_dual = 1; - } + /* Get the PHY type */ + efab->phy_addr = le16_to_cpu ( ver2->port0_phy_addr ); + efab->phy_type = le16_to_cpu ( ver2->port0_phy_type ); + board_revision = le16_to_cpu ( ver2->board_revision ); + } + else { + EFAB_ERR ( "NVram is not recognised\n" ); + return -EINVAL; } - DBG ( "NIC type: %s %dx%s\n", - efab->is_asic ? "ASIC" : "FPGA", - efab->is_dual ? 2 : 1, - efab->is_10g ? "10G" : "1G" ); + efab->board_type = BOARD_TYPE ( board_revision ); + + EFAB_TRACE ( "Falcon board %d phy %d @ addr %d\n", + efab->board_type, efab->phy_type, efab->phy_addr ); - /* patch in MAC operations */ - if ( efab->is_10g ) + /* Patch in the board operations */ + switch ( efab->board_type ) { + case EFAB_BOARD_SFE4001: + efab->board_op = &sfe4001_ops; + break; + case EFAB_BOARD_SFE4002: + efab->board_op = &sfe4002_ops; + break; + case EFAB_BOARD_SFE4003: + efab->board_op = &sfe4003_ops; + break; + default: + EFAB_ERR ( "Unrecognised board type\n" ); + return -EINVAL; + } + + /* Patch in MAC operations */ + if ( efab->phy_10g ) efab->mac_op = &falcon_xmac_operations; else efab->mac_op = &falcon_gmac_operations; - - if ( !efab->is_dual && ( efab->port == 1 ) ) { - /* device doesn't exist */ - return 0; - } - /* determine EEPROM / FLASH */ - if ( efab->is_asic ) { - falcon_read ( efab, ®, FCN_NIC_STAT_REG ); - efab->has_flash = EFAB_OWORD_FIELD ( reg, SF_PRST ); - efab->has_eeprom = EFAB_OWORD_FIELD ( reg, EE_PRST ); - } else { - falcon_read ( efab, ®, FCN_GPIO_CTL_REG_KER ); - efab->has_flash = EFAB_OWORD_FIELD ( reg, FCN_FLASH_PRESENT ); - efab->has_eeprom = EFAB_OWORD_FIELD ( reg, FCN_EEPROM_PRESENT); + /* Hook in the PHY ops */ + switch ( efab->phy_type ) { + case PHY_TYPE_10XPRESS: + efab->phy_op = &falcon_tenxpress_phy_ops; + break; + case PHY_TYPE_CX4: + efab->phy_op = &falcon_xaui_phy_ops; + break; + case PHY_TYPE_XFP: + efab->phy_op = &falcon_xfp_phy_ops; + break; + case PHY_TYPE_CX4_RTMR: + efab->phy_op = &falcon_txc_phy_ops; + break; + case PHY_TYPE_PM8358: + efab->phy_op = &falcon_pm8358_phy_ops; + break; + case PHY_TYPE_1GIG_ALASKA: + efab->phy_op = &falcon_alaska_phy_ops; + break; + default: + EFAB_ERR ( "Unknown PHY type: %d\n", efab->phy_type ); + return -EINVAL; } - DBG ( "flash is %s, EEPROM is %s\n", - ( efab->has_flash ? "present" : "absent" ), - ( efab->has_eeprom ? "present" : "absent" ) ); - falcon_init_spi ( efab ); + return 0; +} + +static int +falcon_init_sram ( struct efab_nic *efab ) +{ + efab_oword_t reg; + int count; + + /* use card in internal SRAM mode */ + falcon_read ( efab, ®, FCN_NIC_STAT_REG ); + EFAB_SET_OWORD_FIELD ( reg, FCN_ONCHIP_SRAM, 1 ); + falcon_write ( efab, ®, FCN_NIC_STAT_REG ); + + /* Deactivate any external SRAM that might be present */ + EFAB_POPULATE_OWORD_2 ( reg, + FCN_GPIO1_OEN, 1, + FCN_GPIO1_OUT, 1 ); + falcon_write ( efab, ®, FCN_GPIO_CTL_REG_KER ); + + /* Initiate SRAM reset */ + EFAB_POPULATE_OWORD_2 ( reg, + FCN_SRAM_OOB_BT_INIT_EN, 1, + FCN_SRM_NUM_BANKS_AND_BANK_SIZE, 0 ); + falcon_write ( efab, ®, FCN_SRM_CFG_REG_KER ); + + /* Wait for SRAM reset to complete */ + count = 0; + do { + /* SRAM reset is slow; expect around 16ms */ + mdelay ( 20 ); + + /* Check for reset complete */ + falcon_read ( efab, ®, FCN_SRM_CFG_REG_KER ); + if ( !EFAB_OWORD_FIELD ( reg, FCN_SRAM_OOB_BT_INIT_EN ) ) + return 0; + } while (++count < 20); /* wait upto 0.4 sec */ + + EFAB_ERR ( "timed out waiting for SRAM reset\n"); + return -ETIMEDOUT; +} + +static void +falcon_setup_nic ( struct efab_nic *efab ) +{ + efab_dword_t timer_cmd; + efab_oword_t reg; + int tx_fc, xoff_thresh, xon_thresh; + + /* bug5129: Clear the parity enables on the TX data fifos as + * they produce false parity errors because of timing issues + */ + falcon_read ( efab, ®, FCN_SPARE_REG_KER ); + EFAB_SET_OWORD_FIELD ( reg, FCN_MEM_PERR_EN_TX_DATA, 0 ); + falcon_write ( efab, ®, FCN_SPARE_REG_KER ); + /* Set up TX and RX descriptor caches in SRAM */ - EFAB_POPULATE_OWORD_1 ( reg, FCN_SRM_TX_DC_BASE_ADR, - 0x130000 /* recommended in datasheet */ ); + EFAB_POPULATE_OWORD_1 ( reg, FCN_SRM_TX_DC_BASE_ADR, 0x130000 ); falcon_write ( efab, ®, FCN_SRM_TX_DC_CFG_REG_KER ); - EFAB_POPULATE_OWORD_1 ( reg, FCN_TX_DC_SIZE, 2 /* 32 descriptors */ ); + EFAB_POPULATE_OWORD_1 ( reg, FCN_TX_DC_SIZE, 1 /* 16 descriptors */ ); falcon_write ( efab, ®, FCN_TX_DC_CFG_REG_KER ); - EFAB_POPULATE_OWORD_1 ( reg, FCN_SRM_RX_DC_BASE_ADR, - 0x100000 /* recommended in datasheet */ ); + EFAB_POPULATE_OWORD_1 ( reg, FCN_SRM_RX_DC_BASE_ADR, 0x100000 ); falcon_write ( efab, ®, FCN_SRM_RX_DC_CFG_REG_KER ); EFAB_POPULATE_OWORD_1 ( reg, FCN_RX_DC_SIZE, 2 /* 32 descriptors */ ); falcon_write ( efab, ®, FCN_RX_DC_CFG_REG_KER ); - /* Set number of RSS CPUs */ - EFAB_POPULATE_OWORD_1 ( reg, FCN_NUM_KER, 0 ); + /* Set number of RSS CPUs + * bug7244: Increase filter depth to reduce RX_RESET likelyhood + */ + EFAB_POPULATE_OWORD_5 ( reg, + FCN_NUM_KER, 0, + FCN_UDP_FULL_SRCH_LIMIT, 8, + FCN_UDP_WILD_SRCH_LIMIT, 8, + FCN_TCP_WILD_SRCH_LIMIT, 8, + FCN_TCP_FULL_SRCH_LIMIT, 8); falcon_write ( efab, ®, FCN_RX_FILTER_CTL_REG_KER ); udelay ( 1000 ); + + /* Setup RX. Wait for descriptor is broken and must + * be disabled. RXDP recovery shouldn't be needed, but is. + * disable ISCSI parsing because we don't need it + */ + falcon_read ( efab, ®, FCN_RX_SELF_RST_REG_KER ); + EFAB_SET_OWORD_FIELD ( reg, FCN_RX_NODESC_WAIT_DIS, 1 ); + EFAB_SET_OWORD_FIELD ( reg, FCN_RX_RECOVERY_EN, 1 ); + EFAB_SET_OWORD_FIELD ( reg, FCN_RX_ISCSI_DIS, 1 ); + falcon_write ( efab, ®, FCN_RX_SELF_RST_REG_KER ); - /* Reset the MAC */ - mentormac_reset ( efab ); + /* Determine recommended flow control settings. * + * Flow control is qualified on B0 and A1/1G, not on A1/10G */ + if ( efab->pci_revision == FALCON_REV_B0 ) { + tx_fc = 1; + xoff_thresh = 54272; /* ~80Kb - 3*max MTU */ + xon_thresh = 27648; /* ~3*max MTU */ + } + else if ( !efab->phy_10g ) { + tx_fc = 1; + xoff_thresh = 2048; + xon_thresh = 512; + } + else { + tx_fc = xoff_thresh = xon_thresh = 0; + } - /* Set up event queue */ - falcon_create_special_buffer ( efab, efab->eventq, FALCON_EVQ_ID ); - /* Fill eventq with all ones ( empty events ) */ - memset(efab->eventq, 0xff, 4096); - /* push eventq to card */ - EFAB_POPULATE_OWORD_3 ( reg, - FCN_EVQ_EN, 1, - FCN_EVQ_SIZE, FCN_EVQ_SIZE_512, - FCN_EVQ_BUF_BASE_ID, FALCON_EVQ_ID ); - falcon_write ( efab, ®, FCN_EVQ_PTR_TBL_KER ); - udelay ( 1000 ); + /* Setup TX and RX */ + falcon_read ( efab, ®, FCN_TX_CFG2_REG_KER ); + EFAB_SET_OWORD_FIELD ( reg, FCN_TX_DIS_NON_IP_EV, 1 ); + falcon_write ( efab, ®, FCN_TX_CFG2_REG_KER ); + + falcon_read ( efab, ®, FCN_RX_CFG_REG_KER ); + EFAB_SET_OWORD_FIELD_VER ( efab, reg, FCN_RX_USR_BUF_SIZE, + (3*4096) / 32 ); + if ( efab->pci_revision == FALCON_REV_B0) + EFAB_SET_OWORD_FIELD ( reg, FCN_RX_INGR_EN_B0, 1 ); + EFAB_SET_OWORD_FIELD_VER ( efab, reg, FCN_RX_XON_MAC_TH, + xon_thresh / 256); + EFAB_SET_OWORD_FIELD_VER ( efab, reg, FCN_RX_XOFF_MAC_TH, + xoff_thresh / 256); + EFAB_SET_OWORD_FIELD_VER ( efab, reg, FCN_RX_XOFF_MAC_EN, tx_fc); + falcon_write ( efab, ®, FCN_RX_CFG_REG_KER ); /* Set timer register */ EFAB_POPULATE_DWORD_2 ( timer_cmd, FCN_TIMER_MODE, FCN_TIMER_MODE_DIS, FCN_TIMER_VAL, 0 ); falcon_writel ( efab, &timer_cmd, FCN_TIMER_CMD_REG_KER ); - udelay ( 1000 ); +} + +static void +falcon_init_resources ( struct efab_nic *efab ) +{ + struct efab_ev_queue *ev_queue = &efab->ev_queue; + struct efab_rx_queue *rx_queue = &efab->rx_queue; + struct efab_tx_queue *tx_queue = &efab->tx_queue; - /* Initialise event queue read pointer */ - falcon_eventq_read_ack ( efab ); + efab_oword_t reg; + int jumbo; + + /* Initialise the ptrs */ + tx_queue->read_ptr = tx_queue->write_ptr = 0; + rx_queue->read_ptr = rx_queue->write_ptr = 0; + ev_queue->read_ptr = 0; + + /* Push the event queue to the hardware */ + EFAB_POPULATE_OWORD_3 ( reg, + FCN_EVQ_EN, 1, + FCN_EVQ_SIZE, FQS(FCN_EVQ, EFAB_EVQ_SIZE), + FCN_EVQ_BUF_BASE_ID, ev_queue->entry.id ); + falcon_write ( efab, ®, + FCN_REVISION_REG ( efab, FCN_EVQ_PTR_TBL_KER ) ); - /* Set up TX descriptor ring */ - falcon_create_special_buffer ( efab, efab->txd, FALCON_TXD_ID ); - EFAB_POPULATE_OWORD_5 ( reg, + /* Push the tx queue to the hardware */ + EFAB_POPULATE_OWORD_8 ( reg, FCN_TX_DESCQ_EN, 1, - FCN_TX_DESCQ_BUF_BASE_ID, FALCON_TXD_ID, + FCN_TX_ISCSI_DDIG_EN, 0, + FCN_TX_ISCSI_DDIG_EN, 0, + FCN_TX_DESCQ_BUF_BASE_ID, tx_queue->entry.id, FCN_TX_DESCQ_EVQ_ID, 0, - FCN_TX_DESCQ_SIZE, FCN_TX_DESCQ_SIZE_512, - FCN_TX_DESCQ_TYPE, 0 /* kernel queue */ ); - falcon_write ( efab, ®, FCN_TX_DESC_PTR_TBL_KER ); - - /* Set up RX descriptor ring */ - falcon_create_special_buffer ( efab, efab->rxd, FALCON_RXD_ID ); - EFAB_POPULATE_OWORD_6 ( reg, - FCN_RX_DESCQ_BUF_BASE_ID, FALCON_RXD_ID, + FCN_TX_DESCQ_SIZE, FQS(FCN_TX_DESCQ, EFAB_TXD_SIZE), + FCN_TX_DESCQ_TYPE, 0 /* kernel queue */, + FCN_TX_NON_IP_DROP_DIS_B0, 1 ); + falcon_write ( efab, ®, + FCN_REVISION_REG ( efab, FCN_TX_DESC_PTR_TBL_KER ) ); + + /* Push the rx queue to the hardware */ + jumbo = ( efab->pci_revision == FALCON_REV_B0 ) ? 0 : 1; + EFAB_POPULATE_OWORD_8 ( reg, + FCN_RX_ISCSI_DDIG_EN, 0, + FCN_RX_ISCSI_HDIG_EN, 0, + FCN_RX_DESCQ_BUF_BASE_ID, rx_queue->entry.id, FCN_RX_DESCQ_EVQ_ID, 0, - FCN_RX_DESCQ_SIZE, FCN_RX_DESCQ_SIZE_512, + FCN_RX_DESCQ_SIZE, FQS(FCN_RX_DESCQ, EFAB_RXD_SIZE), FCN_RX_DESCQ_TYPE, 0 /* kernel queue */, - FCN_RX_DESCQ_JUMBO, 1, + FCN_RX_DESCQ_JUMBO, jumbo, FCN_RX_DESCQ_EN, 1 ); - falcon_write ( efab, ®, FCN_RX_DESC_PTR_TBL_KER ); + falcon_write ( efab, ®, + FCN_REVISION_REG ( efab, FCN_RX_DESC_PTR_TBL_KER ) ); /* Program INT_ADR_REG_KER */ EFAB_POPULATE_OWORD_1 ( reg, - FCN_INT_ADR_KER, - virt_to_bus ( &efab->int_ker ) ); + FCN_INT_ADR_KER, virt_to_bus ( &efab->int_ker ) ); falcon_write ( efab, ®, FCN_INT_ADR_REG_KER ); - udelay ( 1000 ); - /* Register non-volatile storage */ - if ( efab->has_eeprom ) { - nvo_init ( &efab->nvo, &efab->falcon_eeprom.nvs, - falcon_eeprom_fragments, NULL /* hack */ ); - if ( register_nvo ( &efab->nvo, NULL /* hack */ ) != 0 ) - return 0; - } + /* Ack the event queue */ + falcon_eventq_read_ack ( efab, ev_queue ); +} - return 1; +static void +falcon_fini_resources ( struct efab_nic *efab ) +{ + efab_oword_t cmd; + + /* Disable interrupts */ + falcon_interrupts ( efab, 0, 0 ); + + /* Flush the dma queues */ + EFAB_POPULATE_OWORD_2 ( cmd, + FCN_TX_FLUSH_DESCQ_CMD, 1, + FCN_TX_FLUSH_DESCQ, 0 ); + falcon_write ( efab, &cmd, + FCN_REVISION_REG ( efab, FCN_TX_DESC_PTR_TBL_KER ) ); + + EFAB_POPULATE_OWORD_2 ( cmd, + FCN_RX_FLUSH_DESCQ_CMD, 1, + FCN_RX_FLUSH_DESCQ, 0 ); + falcon_write ( efab, &cmd, + FCN_REVISION_REG ( efab, FCN_RX_DESC_PTR_TBL_KER ) ); + + mdelay ( 100 ); + + /* Remove descriptor rings from card */ + EFAB_ZERO_OWORD ( cmd ); + falcon_write ( efab, &cmd, + FCN_REVISION_REG ( efab, FCN_TX_DESC_PTR_TBL_KER ) ); + falcon_write ( efab, &cmd, + FCN_REVISION_REG ( efab, FCN_RX_DESC_PTR_TBL_KER ) ); + falcon_write ( efab, &cmd, + FCN_REVISION_REG ( efab, FCN_EVQ_PTR_TBL_KER ) ); } -/** MDIO write */ -static void falcon_mdio_write ( struct efab_nic *efab, int location, - int value ) { - int phy_id = efab->port + 2; - efab_oword_t reg; +/******************************************************************************* + * + * + * Hardware rx path + * + * + *******************************************************************************/ - EFAB_TRACE ( "Writing GMII %d register %02x with %04x\n", - phy_id, location, value ); +static void +falcon_build_rx_desc ( falcon_rx_desc_t *rxd, struct io_buffer *iob ) +{ + EFAB_POPULATE_QWORD_2 ( *rxd, + FCN_RX_KER_BUF_SIZE, EFAB_RX_BUF_SIZE, + FCN_RX_KER_BUF_ADR, virt_to_bus ( iob->data ) ); +} - /* Check MII not currently being accessed */ - if ( ! falcon_gmii_wait ( efab ) ) - return; +static void +falcon_notify_rx_desc ( struct efab_nic *efab, struct efab_rx_queue *rx_queue ) +{ + efab_dword_t reg; + int ptr = rx_queue->write_ptr % EFAB_RXD_SIZE; - /* Write the address registers */ - EFAB_POPULATE_OWORD_1 ( reg, FCN_MD_PHY_ADR, 0 /* phy_id ? */ ); - falcon_write ( efab, ®, FCN_MD_PHY_ADR_REG_KER ); - udelay ( 10 ); - EFAB_POPULATE_OWORD_2 ( reg, - FCN_MD_PRT_ADR, phy_id, - FCN_MD_DEV_ADR, location ); - falcon_write ( efab, ®, FCN_MD_ID_REG_KER ); - udelay ( 10 ); + EFAB_POPULATE_DWORD_1 ( reg, FCN_RX_DESC_WPTR_DWORD, ptr ); + falcon_writel ( efab, ®, FCN_RX_DESC_UPD_REG_KER_DWORD ); +} - /* Write data */ - EFAB_POPULATE_OWORD_1 ( reg, FCN_MD_TXD, value ); - falcon_write ( efab, ®, FCN_MD_TXD_REG_KER ); - udelay ( 10 ); - EFAB_POPULATE_OWORD_2 ( reg, - FCN_MD_WRC, 1, - FCN_MD_GC, 1 ); - falcon_write ( efab, ®, FCN_MD_CS_REG_KER ); - udelay ( 10 ); - - /* Wait for data to be written */ - falcon_gmii_wait ( efab ); + +/******************************************************************************* + * + * + * Hardware tx path + * + * + *******************************************************************************/ + +static void +falcon_build_tx_desc ( falcon_tx_desc_t *txd, struct io_buffer *iob ) +{ + EFAB_POPULATE_QWORD_2 ( *txd, + FCN_TX_KER_BYTE_CNT, iob_len ( iob ), + FCN_TX_KER_BUF_ADR, virt_to_bus ( iob->data ) ); } -/** MDIO read */ -static int falcon_mdio_read ( struct efab_nic *efab, int location ) { - int phy_id = efab->port + 2; - efab_oword_t reg; - int value; +static void +falcon_notify_tx_desc ( struct efab_nic *efab, + struct efab_tx_queue *tx_queue ) +{ + efab_dword_t reg; + int ptr = tx_queue->write_ptr % EFAB_TXD_SIZE; - /* Check MII not currently being accessed */ - if ( ! falcon_gmii_wait ( efab ) ) - return 0xffff; + EFAB_POPULATE_DWORD_1 ( reg, FCN_TX_DESC_WPTR_DWORD, ptr ); + falcon_writel ( efab, ®, FCN_TX_DESC_UPD_REG_KER_DWORD ); +} - /* Write the address registers */ - EFAB_POPULATE_OWORD_1 ( reg, FCN_MD_PHY_ADR, 0 /* phy_id ? */ ); - falcon_write ( efab, ®, FCN_MD_PHY_ADR_REG_KER ); - udelay ( 10 ); - EFAB_POPULATE_OWORD_2 ( reg, - FCN_MD_PRT_ADR, phy_id, - FCN_MD_DEV_ADR, location ); - falcon_write ( efab, ®, FCN_MD_ID_REG_KER ); - udelay ( 10 ); - /* Request data to be read */ - EFAB_POPULATE_OWORD_2 ( reg, - FCN_MD_RIC, 1, - FCN_MD_GC, 1 ); - falcon_write ( efab, ®, FCN_MD_CS_REG_KER ); - udelay ( 10 ); - - /* Wait for data to become available */ - falcon_gmii_wait ( efab ); +/******************************************************************************* + * + * + * Software receive interface + * + * + *******************************************************************************/ - /* Read the data */ - falcon_read ( efab, ®, FCN_MD_RXD_REG_KER ); - value = EFAB_OWORD_FIELD ( reg, FCN_MD_RXD ); +static int +efab_fill_rx_queue ( struct efab_nic *efab, + struct efab_rx_queue *rx_queue ) +{ + int fill_level = rx_queue->write_ptr - rx_queue->read_ptr; + int space = EFAB_NUM_RX_DESC - fill_level - 1; + int pushed = 0; + + while ( space ) { + int buf_id = rx_queue->write_ptr % EFAB_NUM_RX_DESC; + int desc_id = rx_queue->write_ptr % EFAB_RXD_SIZE; + struct io_buffer *iob; + falcon_rx_desc_t *rxd; + + assert ( rx_queue->buf[buf_id] == NULL ); + iob = alloc_iob ( EFAB_RX_BUF_SIZE ); + if ( !iob ) + break; - EFAB_TRACE ( "Read from GMII %d register %02x, got %04x\n", - phy_id, location, value ); + EFAB_TRACE ( "pushing rx_buf[%d] iob %p data %p\n", + buf_id, iob, iob->data ); - return value; + rx_queue->buf[buf_id] = iob; + rxd = rx_queue->ring + desc_id; + falcon_build_rx_desc ( rxd, iob ); + ++rx_queue->write_ptr; + ++pushed; + --space; + } + + if ( pushed ) { + /* Push the ptr to hardware */ + falcon_notify_rx_desc ( efab, rx_queue ); + + fill_level = rx_queue->write_ptr - rx_queue->read_ptr; + EFAB_TRACE ( "pushed %d rx buffers to fill level %d\n", + pushed, fill_level ); + } + + if ( fill_level == 0 ) + return -ENOMEM; + return 0; } + +static void +efab_receive ( struct efab_nic *efab, unsigned int id, int len, int drop ) +{ + struct efab_rx_queue *rx_queue = &efab->rx_queue; + struct io_buffer *iob; + unsigned int read_ptr = rx_queue->read_ptr % EFAB_RXD_SIZE; + unsigned int buf_ptr = rx_queue->read_ptr % EFAB_NUM_RX_DESC; -static struct efab_operations falcon_operations = { - .get_membase = falcon_get_membase, - .reset = falcon_reset, - .init_nic = falcon_init_nic, - .read_eeprom = falcon_read_eeprom, - .build_rx_desc = falcon_build_rx_desc, - .notify_rx_desc = falcon_notify_rx_desc, - .build_tx_desc = falcon_build_tx_desc, - .notify_tx_desc = falcon_notify_tx_desc, - .fetch_event = falcon_fetch_event, - .mask_irq = falcon_mask_irq, - .generate_irq = falcon_generate_irq, - .mdio_write = falcon_mdio_write, - .mdio_read = falcon_mdio_read, -}; + assert ( id == read_ptr ); + + /* Pop this rx buffer out of the software ring */ + iob = rx_queue->buf[buf_ptr]; + rx_queue->buf[buf_ptr] = NULL; -/************************************************************************** + EFAB_TRACE ( "popping rx_buf[%d] iob %p data %p with %d bytes %s\n", + id, iob, iob->data, len, drop ? "bad" : "ok" ); + + /* Pass the packet up if required */ + if ( drop ) + free_iob ( iob ); + else { + iob_put ( iob, len ); + netdev_rx ( efab->netdev, iob ); + } + + ++rx_queue->read_ptr; +} + +/******************************************************************************* * - * Etherfabric abstraction layer * - ************************************************************************** - */ - -/** - * Push RX buffer to RXD ring + * Software transmit interface * - */ -static inline void efab_push_rx_buffer ( struct efab_nic *efab, - struct efab_rx_buf *rx_buf ) { - /* Create RX descriptor */ - rx_buf->id = efab->rx_write_ptr; - efab->op->build_rx_desc ( efab, rx_buf ); + * + *******************************************************************************/ - /* Update RX write pointer */ - efab->rx_write_ptr = ( efab->rx_write_ptr + 1 ) % EFAB_RXD_SIZE; - efab->op->notify_rx_desc ( efab ); +static int +efab_transmit ( struct net_device *netdev, struct io_buffer *iob ) +{ + struct efab_nic *efab = netdev_priv ( netdev ); + struct efab_tx_queue *tx_queue = &efab->tx_queue; + int fill_level, space; + falcon_tx_desc_t *txd; + int buf_id; + + fill_level = tx_queue->write_ptr - tx_queue->read_ptr; + space = EFAB_TXD_SIZE - fill_level - 1; + if ( space < 1 ) + return -ENOBUFS; + + /* Save the iobuffer for later completion */ + buf_id = tx_queue->write_ptr % EFAB_TXD_SIZE; + assert ( tx_queue->buf[buf_id] == NULL ); + tx_queue->buf[buf_id] = iob; + + EFAB_TRACE ( "tx_buf[%d] for iob %p data %p len %zd\n", + buf_id, iob, iob->data, iob_len ( iob ) ); + + /* Form the descriptor, and push it to hardware */ + txd = tx_queue->ring + buf_id; + falcon_build_tx_desc ( txd, iob ); + ++tx_queue->write_ptr; + falcon_notify_tx_desc ( efab, tx_queue ); - DBG ( "Added RX id %x\n", rx_buf->id ); + return 0; } -/** - * Push TX buffer to TXD ring - * - */ -static inline void efab_push_tx_buffer ( struct efab_nic *efab, - struct efab_tx_buf *tx_buf ) { - /* Create TX descriptor */ - tx_buf->id = efab->tx_write_ptr; - efab->op->build_tx_desc ( efab, tx_buf ); +static int +efab_transmit_done ( struct efab_nic *efab, int id ) +{ + struct efab_tx_queue *tx_queue = &efab->tx_queue; + unsigned int read_ptr, stop; + + /* Complete all buffers from read_ptr up to and including id */ + read_ptr = tx_queue->read_ptr % EFAB_TXD_SIZE; + stop = ( id + 1 ) % EFAB_TXD_SIZE; - /* Update TX write pointer */ - efab->tx_write_ptr = ( efab->tx_write_ptr + 1 ) % EFAB_TXD_SIZE; - efab->op->notify_tx_desc ( efab ); + while ( read_ptr != stop ) { + struct io_buffer *iob = tx_queue->buf[read_ptr]; + assert ( iob ); - DBG ( "Added TX id %x\n", tx_buf->id ); + /* Complete the tx buffer */ + if ( iob ) + netdev_tx_complete ( efab->netdev, iob ); + tx_queue->buf[read_ptr] = NULL; + + ++tx_queue->read_ptr; + read_ptr = tx_queue->read_ptr % EFAB_TXD_SIZE; + } + + return 0; } -/** - * Initialise MAC and wait for link up +/******************************************************************************* * - */ -static int efab_init_mac ( struct efab_nic *efab ) { - int count; + * + * Hardware event path + * + * + *******************************************************************************/ - /* This can take several seconds */ - EFAB_LOG ( "Waiting for link.." ); - for ( count=0; count<5; count++ ) { - putchar ( '.' ); +static void +falcon_clear_interrupts ( struct efab_nic *efab ) +{ + efab_dword_t reg; - if ( ! efab->mac_op->init ( efab ) ) { - EFAB_ERR ( "Failed reinitialising MAC\n" ); - return 0; - } - if ( efab->link_up ) { - /* PHY init printed the message for us */ - return 1; - } - EFAB_ERR( "link is down" ); - sleep ( 1 ); + if ( efab->pci_revision == FALCON_REV_B0 ) { + /* read the ISR */ + falcon_readl( efab, ®, INT_ISR0_B0 ); + } + else { + /* write to the INT_ACK register */ + falcon_writel ( efab, 0, FCN_INT_ACK_KER_REG_A1 ); + mb(); + falcon_readl ( efab, ®, + WORK_AROUND_BROKEN_PCI_READS_REG_KER_A1 ); } - EFAB_ERR ( " timed initialising MAC\n " ); +} - return 0; +static void +falcon_handle_event ( struct efab_nic *efab, falcon_event_t *evt ) +{ + int ev_code, desc_ptr, len, drop; + + /* Decode event */ + ev_code = EFAB_QWORD_FIELD ( *evt, FCN_EV_CODE ); + switch ( ev_code ) { + case FCN_TX_IP_EV_DECODE: + desc_ptr = EFAB_QWORD_FIELD ( *evt, FCN_TX_EV_DESC_PTR ); + efab_transmit_done ( efab, desc_ptr ); + break; + + case FCN_RX_IP_EV_DECODE: + desc_ptr = EFAB_QWORD_FIELD ( *evt, FCN_RX_EV_DESC_PTR ); + len = EFAB_QWORD_FIELD ( *evt, FCN_RX_EV_BYTE_CNT ); + drop = !EFAB_QWORD_FIELD ( *evt, FCN_RX_EV_PKT_OK ); + + efab_receive ( efab, desc_ptr, len, drop ); + break; + + default: + EFAB_TRACE ( "Unknown event type %d\n", ev_code ); + break; + } } -/** - * Initialise NIC +/******************************************************************************* * - */ -static int efab_init_nic ( struct efab_nic *efab ) { - int i; + * + * Software (polling) interrupt handler + * + * + *******************************************************************************/ - /* Initialise NIC */ - if ( ! efab->op->init_nic ( efab ) ) - return 0; +static void +efab_poll ( struct net_device *netdev ) +{ + struct efab_nic *efab = netdev_priv ( netdev ); + struct efab_ev_queue *ev_queue = &efab->ev_queue; + struct efab_rx_queue *rx_queue = &efab->rx_queue; + falcon_event_t *evt; - /* Push RX descriptors */ - for ( i = 0 ; i < EFAB_RX_BUFS ; i++ ) { - efab_push_rx_buffer ( efab, &efab->rx_bufs[i] ); + /* Read the event queue by directly looking for events + * (we don't even bother to read the eventq write ptr) */ + evt = ev_queue->ring + ev_queue->read_ptr; + while ( falcon_event_present ( evt ) ) { + + EFAB_TRACE ( "Event at index 0x%x address %p is " + EFAB_QWORD_FMT "\n", ev_queue->read_ptr, + evt, EFAB_QWORD_VAL ( *evt ) ); + + falcon_handle_event ( efab, evt ); + + /* Clear the event */ + EFAB_SET_QWORD ( *evt ); + + /* Move to the next event. We don't ack the event + * queue until the end */ + ev_queue->read_ptr = ( ( ev_queue->read_ptr + 1 ) % + EFAB_EVQ_SIZE ); + evt = ev_queue->ring + ev_queue->read_ptr; } - /* Read MAC address from EEPROM */ - if ( ! efab->op->read_eeprom ( efab ) ) - return 0; + /* Push more buffers if needed */ + (void) efab_fill_rx_queue ( efab, rx_queue ); - /* Initialise MAC and wait for link up */ - if ( ! efab_init_mac ( efab ) ) - return 0; + /* Clear any pending interrupts */ + falcon_clear_interrupts ( efab ); - return 1; + /* Ack the event queue */ + falcon_eventq_read_ack ( efab, ev_queue ); } -/************************************************************************** +static void +efab_irq ( struct net_device *netdev, int enable ) +{ + struct efab_nic *efab = netdev_priv ( netdev ); + struct efab_ev_queue *ev_queue = &efab->ev_queue; + + switch ( enable ) { + case 0: + falcon_interrupts ( efab, 0, 0 ); + break; + case 1: + falcon_interrupts ( efab, 1, 0 ); + falcon_eventq_read_ack ( efab, ev_queue ); + break; + case 2: + falcon_interrupts ( efab, 1, 1 ); + break; + } +} + +/******************************************************************************* * - * Etherboot interface * - ************************************************************************** - */ + * Software open/close + * + * + *******************************************************************************/ -/************************************************************************** -POLL - Wait for a frame -***************************************************************************/ -static int etherfabric_poll ( struct nic *nic, int retrieve ) { - struct efab_nic *efab = nic->priv_data; - struct efab_event event; - static struct efab_rx_buf *rx_buf = NULL; - int i, drop = 0; - - /* Process the event queue until we hit either a packet - * received event or an empty event slot. - */ - while ( ( rx_buf == NULL ) && - efab->op->fetch_event ( efab, &event ) ) { - drop = event.drop; - if ( event.type == EFAB_EV_TX ) { - /* TX completed - mark as done */ - DBG ( "TX id %x complete\n", - efab->tx_buf.id ); - } else if ( event.type == EFAB_EV_RX ) { - /* RX - find corresponding buffer */ - for ( i = 0 ; i < EFAB_RX_BUFS ; i++ ) { - if ( efab->rx_bufs[i].id == event.rx_id ) { - rx_buf = &efab->rx_bufs[i]; - rx_buf->len = event.rx_len; - DBG ( "RX id %x (len %x) received\n", - rx_buf->id, rx_buf->len ); - break; - } - } - if ( ! rx_buf ) { - EFAB_ERR ( "Invalid RX ID %x\n", event.rx_id ); - } - } else if ( event.type == EFAB_EV_NONE ) { - DBG ( "Ignorable event\n" ); - } else { - DBG ( "Unknown event\n" ); - } - } +static void +efab_free_resources ( struct efab_nic *efab ) +{ + struct efab_ev_queue *ev_queue = &efab->ev_queue; + struct efab_rx_queue *rx_queue = &efab->rx_queue; + struct efab_tx_queue *tx_queue = &efab->tx_queue; + int i; - /* If there is no packet, return 0 */ - if ( ! rx_buf ) - return 0; + for ( i = 0; i < EFAB_NUM_RX_DESC; i++ ) { + if ( rx_queue->buf[i] ) + free_iob ( rx_queue->buf[i] ); + } - /* drop this event if necessary */ - if ( drop ) { - DBG( "discarding RX event\n" ); - return 0; + for ( i = 0; i < EFAB_TXD_SIZE; i++ ) { + if ( tx_queue->buf[i] ) + netdev_tx_complete ( efab->netdev, tx_queue->buf[i] ); } - /* If we don't want to retrieve it just yet, return 1 */ - if ( ! retrieve ) - return 1; + if ( rx_queue->ring ) + falcon_free_special_buffer ( rx_queue->ring ); - /* There seems to be a hardware race. The event can show up - * on the event FIFO before the DMA has completed, so we - * insert a tiny delay. If this proves unreliable, we should - * switch to using event DMA rather than the event FIFO, since - * event DMA ordering is guaranteed. - */ - udelay ( 2 ); + if ( tx_queue->ring ) + falcon_free_special_buffer ( tx_queue->ring ); - /* Copy packet contents */ - nic->packetlen = rx_buf->len; - memcpy ( nic->packet, rx_buf->addr, nic->packetlen ); + if ( ev_queue->ring ) + falcon_free_special_buffer ( ev_queue->ring ); - /* Give this buffer back to the NIC */ - efab_push_rx_buffer ( efab, rx_buf ); + memset ( rx_queue, 0, sizeof ( *rx_queue ) ); + memset ( tx_queue, 0, sizeof ( *tx_queue ) ); + memset ( ev_queue, 0, sizeof ( *ev_queue ) ); - /* Prepare to receive next packet */ - rx_buf = NULL; + /* Ensure subsequent buffer allocations start at id 0 */ + efab->buffer_head = 0; +} - return 1; +static int +efab_alloc_resources ( struct efab_nic *efab ) +{ + struct efab_ev_queue *ev_queue = &efab->ev_queue; + struct efab_rx_queue *rx_queue = &efab->rx_queue; + struct efab_tx_queue *tx_queue = &efab->tx_queue; + size_t bytes; + + /* Allocate the hardware event queue */ + bytes = sizeof ( falcon_event_t ) * EFAB_TXD_SIZE; + ev_queue->ring = falcon_alloc_special_buffer ( efab, bytes, + &ev_queue->entry ); + if ( !ev_queue->ring ) + goto fail1; + + /* Initialise the hardware event queue */ + memset ( ev_queue->ring, 0xff, bytes ); + + /* Allocate the hardware tx queue */ + bytes = sizeof ( falcon_tx_desc_t ) * EFAB_TXD_SIZE; + tx_queue->ring = falcon_alloc_special_buffer ( efab, bytes, + &tx_queue->entry ); + if ( ! tx_queue->ring ) + goto fail2; + + /* Allocate the hardware rx queue */ + bytes = sizeof ( falcon_rx_desc_t ) * EFAB_RXD_SIZE; + rx_queue->ring = falcon_alloc_special_buffer ( efab, bytes, + &rx_queue->entry ); + if ( ! rx_queue->ring ) + goto fail3; + + return 0; + +fail3: + falcon_free_special_buffer ( tx_queue->ring ); + tx_queue->ring = NULL; +fail2: + falcon_free_special_buffer ( ev_queue->ring ); + ev_queue->ring = NULL; +fail1: + return -ENOMEM; } -/************************************************************************** -TRANSMIT - Transmit a frame -***************************************************************************/ -static void etherfabric_transmit ( struct nic *nic, const char *dest, - unsigned int type, unsigned int size, - const char *data ) { - struct efab_nic *efab = nic->priv_data; - unsigned int nstype = htons ( type ); - - /* Fill TX buffer, pad to ETH_ZLEN */ - memcpy ( efab->tx_buf.addr, dest, ETH_ALEN ); - memcpy ( efab->tx_buf.addr + ETH_ALEN, nic->node_addr, ETH_ALEN ); - memcpy ( efab->tx_buf.addr + 2 * ETH_ALEN, &nstype, 2 ); - memcpy ( efab->tx_buf.addr + ETH_HLEN, data, size ); - size += ETH_HLEN; - while ( size < ETH_ZLEN ) { - efab->tx_buf.addr[size++] = '\0'; - } - efab->tx_buf.len = size; - - /* Push TX descriptor */ - efab_push_tx_buffer ( efab, &efab->tx_buf ); - - /* Allow enough time for the packet to be transmitted. This - * is a temporary hack until we update to the new driver API. - */ - udelay ( 20 ); +static int +efab_init_mac ( struct efab_nic *efab ) +{ + int count, rc; + + /* This can take several seconds */ + EFAB_LOG ( "Waiting for link..\n" ); + for ( count=0; count<5; count++ ) { + rc = efab->mac_op->init ( efab ); + if ( rc ) { + EFAB_ERR ( "Failed reinitialising MAC, error %s\n", + strerror ( rc )); + return rc; + } - return; + /* Sleep for 2s to wait for the link to settle, either + * because we want to use it, or because we're about + * to reset the mac anyway + */ + sleep ( 2 ); + + if ( ! efab->link_up ) { + EFAB_ERR ( "!\n" ); + continue; + } + + EFAB_LOG ( "\n%dMbps %s-duplex\n", + ( efab->link_options & LPA_10000 ? 10000 : + ( efab->link_options & LPA_1000 ? 1000 : + ( efab->link_options & LPA_100 ? 100 : 10 ) ) ), + ( efab->link_options & LPA_DUPLEX ? + "full" : "half" ) ); + + /* TODO: Move link state handling to the poll() routine */ + netdev_link_up ( efab->netdev ); + return 0; + } + + EFAB_ERR ( "timed initialising MAC\n" ); + return -ETIMEDOUT; } -/************************************************************************** -DISABLE - Turn off ethernet interface -***************************************************************************/ -static void etherfabric_disable ( struct nic *nic ) { - struct efab_nic *efab = nic->priv_data; +static void +efab_close ( struct net_device *netdev ) +{ + struct efab_nic *efab = netdev_priv ( netdev ); - efab->op->reset ( efab ); - if ( efab->membase ) - iounmap ( efab->membase ); + falcon_fini_resources ( efab ); + efab_free_resources ( efab ); + efab->board_op->fini ( efab ); + falcon_reset ( efab ); } -/************************************************************************** -IRQ - handle interrupts -***************************************************************************/ -static void etherfabric_irq ( struct nic *nic, irq_action_t action ) { - struct efab_nic *efab = nic->priv_data; - - switch ( action ) { - case DISABLE : - efab->op->mask_irq ( efab, 1 ); - break; - case ENABLE : - efab->op->mask_irq ( efab, 0 ); - break; - case FORCE : - /* Force NIC to generate a receive interrupt */ - efab->op->generate_irq ( efab ); - break; - } +static int +efab_open ( struct net_device *netdev ) +{ + struct efab_nic *efab = netdev_priv ( netdev ); + struct efab_rx_queue *rx_queue = &efab->rx_queue; + int rc; + + rc = falcon_reset ( efab ); + if ( rc ) + goto fail1; + + rc = efab->board_op->init ( efab ); + if ( rc ) + goto fail2; - return; + rc = falcon_init_sram ( efab ); + if ( rc ) + goto fail3; + + /* Configure descriptor caches before pushing hardware queues */ + falcon_setup_nic ( efab ); + + rc = efab_alloc_resources ( efab ); + if ( rc ) + goto fail4; + + falcon_init_resources ( efab ); + + /* Push rx buffers */ + rc = efab_fill_rx_queue ( efab, rx_queue ); + if ( rc ) + goto fail5; + + /* Try and bring the interface up */ + rc = efab_init_mac ( efab ); + if ( rc ) + goto fail6; + + return 0; + +fail6: +fail5: + efab_free_resources ( efab ); +fail4: +fail3: + efab->board_op->fini ( efab ); +fail2: + falcon_reset ( efab ); +fail1: + return rc; } -static struct nic_operations etherfabric_operations = { - .connect = dummy_connect, - .poll = etherfabric_poll, - .transmit = etherfabric_transmit, - .irq = etherfabric_irq, +static struct net_device_operations efab_operations = { + .open = efab_open, + .close = efab_close, + .transmit = efab_transmit, + .poll = efab_poll, + .irq = efab_irq, }; -/************************************************************************** -PROBE - Look for an adapter, this routine's visible to the outside -***************************************************************************/ -static int etherfabric_probe ( struct nic *nic, struct pci_device *pci ) { - static struct efab_nic efab; - static int nic_port = 1; - struct efab_buffers *buffers; - int i; +static void +efab_remove ( struct pci_device *pci ) +{ + struct net_device *netdev = pci_get_drvdata ( pci ); + struct efab_nic *efab = netdev_priv ( netdev ); - /* Set up our private data structure */ - nic->priv_data = &efab; - memset ( &efab, 0, sizeof ( efab ) ); - memset ( &efab_buffers, 0, sizeof ( efab_buffers ) ); + if ( efab->membase ) { + falcon_reset ( efab ); - /* Hook in appropriate operations table. Do this early. */ - if ( pci->device == EF1002_DEVID ) { - efab.op = &ef1002_operations; - } else { - efab.op = &falcon_operations; + iounmap ( efab->membase ); + efab->membase = NULL; } - /* Initialise efab data structure */ - efab.pci = pci; - buffers = ( ( struct efab_buffers * ) - ( ( ( void * ) &efab_buffers ) + - ( - virt_to_bus ( &efab_buffers ) ) % EFAB_BUF_ALIGN ) ); - efab.eventq = buffers->eventq; - efab.txd = buffers->txd; - efab.rxd = buffers->rxd; - efab.tx_buf.addr = buffers->tx_buf; - for ( i = 0 ; i < EFAB_RX_BUFS ; i++ ) { - efab.rx_bufs[i].addr = buffers->rx_buf[i]; + if ( efab->nvo.nvs ) { + unregister_nvo ( &efab->nvo ); + efab->nvo.nvs = NULL; } - /* Enable the PCI device */ - adjust_pci_device ( pci ); - nic->ioaddr = pci->ioaddr & ~3; - nic->irqno = pci->irq; + unregister_netdev ( netdev ); + netdev_nullify ( netdev ); + netdev_put ( netdev ); +} + +static int +efab_probe ( struct pci_device *pci, + const struct pci_device_id *id ) +{ + struct net_device *netdev; + struct efab_nic *efab; + unsigned long mmio_start, mmio_len; + int rc; + + /* Create the network adapter */ + netdev = alloc_etherdev ( sizeof ( struct efab_nic ) ); + if ( ! netdev ) { + rc = -ENOMEM; + goto fail1; + } + + /* Initialise the network adapter, and initialise private storage */ + netdev_init ( netdev, &efab_operations ); + pci_set_drvdata ( pci, netdev ); + netdev->dev = &pci->dev; + + efab = netdev_priv ( netdev ); + memset ( efab, 0, sizeof ( *efab ) ); + efab->netdev = netdev; /* Get iobase/membase */ - efab.iobase = nic->ioaddr; - efab.op->get_membase ( &efab ); + mmio_start = pci_bar_start ( pci, PCI_BASE_ADDRESS_2 ); + mmio_len = pci_bar_size ( pci, PCI_BASE_ADDRESS_2 ); + efab->membase = ioremap ( mmio_start, mmio_len ); + EFAB_TRACE ( "BAR of %lx bytes at phys %lx mapped at %p\n", + mmio_len, mmio_start, efab->membase ); - /* Switch NIC ports (i.e. try different ports on each probe) */ - nic_port = 1 - nic_port; - efab.port = nic_port; + /* Enable the PCI device */ + adjust_pci_device ( pci ); + efab->iobase = pci->ioaddr & ~3; + + /* Determine the NIC variant */ + falcon_probe_nic_variant ( efab, pci ); + + /* Read the SPI interface and determine the MAC address, + * and the board and phy variant. Hook in the op tables */ + rc = falcon_probe_spi ( efab ); + if ( rc ) + goto fail2; + rc = falcon_probe_nvram ( efab ); + if ( rc ) + goto fail3; + + memcpy ( netdev->ll_addr, efab->mac_addr, ETH_ALEN ); + + netdev_link_up ( netdev ); + rc = register_netdev ( netdev ); + if ( rc ) + goto fail4; + + /* Advertise non-volatile storage */ + if ( efab->nvo.nvs ) { + rc = register_nvo ( &efab->nvo, netdev_settings ( netdev ) ); + if ( rc ) + goto fail5; + } - /* Initialise hardware */ - if ( ! efab_init_nic ( &efab ) ) - return 0; - memcpy ( nic->node_addr, efab.mac_addr, ETH_ALEN ); + EFAB_LOG ( "Found %s EtherFabric %s %s revision %d\n", id->name, + efab->is_asic ? "ASIC" : "FPGA", + efab->phy_10g ? "10G" : "1G", + efab->pci_revision ); - /* point to NIC specific routines */ - nic->nic_op = ðerfabric_operations; + return 0; - return 1; +fail5: + unregister_netdev ( netdev ); +fail4: +fail3: +fail2: + iounmap ( efab->membase ); + efab->membase = NULL; + netdev_put ( netdev ); +fail1: + return rc; } -static struct pci_device_id etherfabric_nics[] = { -PCI_ROM(0x1924, 0xC101, "ef1002", "EtherFabric EF1002"), -PCI_ROM(0x1924, 0x0703, "falcon", "EtherFabric Falcon"), -}; -PCI_DRIVER ( etherfabric_driver, etherfabric_nics, PCI_NO_CLASS ); +static struct pci_device_id efab_nics[] = { + PCI_ROM(0x1924, 0x0703, "falcon", "EtherFabric Falcon"), + PCI_ROM(0x1924, 0x0710, "falconb0", "EtherFabric FalconB0"), +}; -DRIVER ( "EFAB", nic_driver, pci_driver, etherfabric_driver, - etherfabric_probe, etherfabric_disable ); +struct pci_driver etherfabric_driver __pci_driver = { + .ids = efab_nics, + .id_count = sizeof ( efab_nics ) / sizeof ( efab_nics[0] ), + .probe = efab_probe, + .remove = efab_remove, +}; /* * Local variables: diff --git a/gpxe/src/drivers/net/etherfabric_nic.h b/gpxe/src/drivers/net/etherfabric_nic.h new file mode 100644 index 00000000..4be50fbb --- /dev/null +++ b/gpxe/src/drivers/net/etherfabric_nic.h @@ -0,0 +1,201 @@ +/************************************************************************** + * + * Etherboot driver for Level 5 Etherfabric network cards + * + * Written by Michael Brown <mbrown@fensystems.co.uk> + * + * Copyright Fen Systems Ltd. 2005 + * Copyright Level 5 Networks Inc. 2005 + * + * This software may be used and distributed according to the terms of + * the GNU General Public License (GPL), incorporated herein by + * reference. Drivers based on or derived from this code fall under + * the GPL and must retain the authorship, copyright and license + * notice. + * + ************************************************************************** + */ +#ifndef EFAB_NIC_H +#define EFAB_NIC_H +#include <gpxe/bitbash.h> +#include <gpxe/i2c.h> +#include <gpxe/spi.h> +#include <gpxe/nvo.h> +#include <gpxe/if_ether.h> +/************************************************************************** + * + * Constants and macros + * + ************************************************************************** + */ +/* Board IDs. Early boards have no board_type, (e.g. EF1002 and 401/403) + * But newer boards are getting bigger... + */ +typedef enum { + EFAB_BOARD_INVALID = 0, /* Early boards do not have board rev. info. */ + EFAB_BOARD_SFE4001 = 1, + EFAB_BOARD_SFE4002 = 2, + EFAB_BOARD_SFE4003 = 3, + /* Insert new types before here */ + EFAB_BOARD_MAX +} efab_board_type; + +/* PHY types. */ +typedef enum { + PHY_TYPE_AUTO = 0, /* on development board detect between CX4 & alaska */ + PHY_TYPE_CX4_RTMR = 1, + PHY_TYPE_1GIG_ALASKA = 2, + PHY_TYPE_10XPRESS = 3, + PHY_TYPE_XFP = 4, + PHY_TYPE_CX4 = 5, + PHY_TYPE_PM8358 = 6, +} phy_type_t; + +/************************************************************************** + * + * Hardware data structures and sizing + * + ************************************************************************** + */ + +#define dma_addr_t unsigned long +typedef efab_qword_t falcon_rx_desc_t; +typedef efab_qword_t falcon_tx_desc_t; +typedef efab_qword_t falcon_event_t; + +#define EFAB_BUF_ALIGN 4096 +#define EFAB_RXD_SIZE 512 +#define EFAB_TXD_SIZE 512 +#define EFAB_EVQ_SIZE 512 + +#define EFAB_NUM_RX_DESC 16 +#define EFAB_RX_BUF_SIZE 1600 + +/************************************************************************** + * + * Data structures + * + ************************************************************************** + */ + +struct efab_nic; + +/* A buffer table allocation backing a tx dma, rx dma or eventq */ +struct efab_special_buffer { + dma_addr_t dma_addr; + int id; +}; + +/* A TX queue */ +struct efab_tx_queue { + /* The hardware ring */ + falcon_tx_desc_t *ring; + + /* The software ring storing io_buffers. */ + struct io_buffer *buf[EFAB_TXD_SIZE]; + + /* The buffer table reservation pushed to hardware */ + struct efab_special_buffer entry; + + /* Software descriptor write ptr */ + unsigned int write_ptr; + + /* Hardware descriptor read ptr */ + unsigned int read_ptr; +}; + +/* An RX queue */ +struct efab_rx_queue { + /* The hardware ring */ + falcon_rx_desc_t *ring; + + /* The software ring storing io_buffers */ + struct io_buffer *buf[EFAB_NUM_RX_DESC]; + + /* The buffer table reservation pushed to hardware */ + struct efab_special_buffer entry; + + /* Descriptor write ptr, into both the hardware and software rings */ + unsigned int write_ptr; + + /* Hardware completion ptr */ + unsigned int read_ptr; +}; + +/* An event queue */ +struct efab_ev_queue { + /* The hardware ring to push to hardware. + * Must be the first entry in the structure */ + falcon_event_t *ring; + + /* The buffer table reservation pushed to hardware */ + struct efab_special_buffer entry; + + /* Pointers into the ring */ + unsigned int read_ptr; +}; + +struct efab_mac_operations { + int ( * init ) ( struct efab_nic *efab ); +}; + +struct efab_phy_operations { + int ( * init ) ( struct efab_nic *efab ); + unsigned int mmds; +}; + +struct efab_board_operations { + int ( * init ) ( struct efab_nic *efab ); + void ( * fini ) ( struct efab_nic *efab ); +}; + +struct efab_nic { + struct net_device *netdev; + int pci_revision; + int is_asic; + + /* I2C bit-bashed interface */ + struct i2c_bit_basher i2c_bb; + + /** SPI bus and devices, and the user visible NVO area */ + struct spi_bus spi_bus; + struct spi_device spi_flash; + struct spi_device spi_eeprom; + struct spi_device *spi; + struct nvo_block nvo; + + /** Board, MAC, and PHY operations tables */ + struct efab_board_operations *board_op; + struct efab_mac_operations *mac_op; + struct efab_phy_operations *phy_op; + + /* PHY and board types */ + int phy_addr; + int phy_type; + int phy_10g; + int board_type; + + /** Memory and IO base */ + void *membase; + unsigned int iobase; + + /* Buffer table allocation head */ + int buffer_head; + + /* Queues */ + struct efab_rx_queue rx_queue; + struct efab_tx_queue tx_queue; + struct efab_ev_queue ev_queue; + + /** MAC address */ + uint8_t mac_addr[ETH_ALEN]; + /** GMII link options */ + unsigned int link_options; + /** Link status */ + int link_up; + + /** INT_REG_KER */ + efab_oword_t int_ker __attribute__ (( aligned ( 16 ) )); +}; +#endif /* EFAB_NIC_H */ + diff --git a/gpxe/src/drivers/net/forcedeth.c b/gpxe/src/drivers/net/forcedeth.c index 54fadbd7..a30f1378 100644 --- a/gpxe/src/drivers/net/forcedeth.c +++ b/gpxe/src/drivers/net/forcedeth.c @@ -452,7 +452,7 @@ static int reg_delay(int offset, u32 mask, delaymax -= delay; if (delaymax < 0) { if (msg) - printf(msg); + printf("%s", msg); return 1; } } while ((readl(base + offset) & mask) != target); diff --git a/gpxe/src/drivers/net/ipoib.c b/gpxe/src/drivers/net/ipoib.c index 16b2a0c8..8ad2c29f 100644 --- a/gpxe/src/drivers/net/ipoib.c +++ b/gpxe/src/drivers/net/ipoib.c @@ -33,9 +33,6 @@ * IP over Infiniband */ -/** IPoIB MTU */ -#define IPOIB_MTU 2048 - /** Number of IPoIB data send work queue entries */ #define IPOIB_DATA_NUM_SEND_WQES 2 @@ -60,8 +57,6 @@ struct ipoib_queue_set { struct ib_completion_queue *cq; /** Queue pair */ struct ib_queue_pair *qp; - /** Receive work queue fill level */ - unsigned int recv_fill; /** Receive work queue maximum fill level */ unsigned int recv_max_fill; }; @@ -90,49 +85,146 @@ struct ipoib_device { int broadcast_attached; }; +/** TID half used to identify get path record replies */ +#define IPOIB_TID_GET_PATH_REC 0x11111111UL + +/** TID half used to identify multicast member record replies */ +#define IPOIB_TID_MC_MEMBER_REC 0x22222222UL + +/** IPoIB metadata TID */ +static uint32_t ipoib_meta_tid = 0; + +/** Broadcast QPN used in IPoIB MAC addresses + * + * This is a guaranteed invalid real QPN + */ +#define IPOIB_BROADCAST_QPN 0xffffffffUL + +/** Broadcast IPoIB address */ +static struct ipoib_mac ipoib_broadcast = { + .qpn = ntohl ( IPOIB_BROADCAST_QPN ), + .gid.u.bytes = { 0xff, 0x12, 0x40, 0x1b, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff }, +}; + +/**************************************************************************** + * + * IPoIB peer cache + * + **************************************************************************** + */ + /** - * IPoIB path cache entry + * IPoIB peer address * * This serves a similar role to the ARP cache for Ethernet. (ARP * *is* used on IPoIB; we have two caches to maintain.) */ -struct ipoib_cached_path { - /** Destination GID */ - struct ib_gid gid; - /** Destination LID */ - unsigned int dlid; +struct ipoib_peer { + /** Key */ + uint8_t key; + /** MAC address */ + struct ipoib_mac mac; + /** LID */ + unsigned int lid; /** Service level */ unsigned int sl; /** Rate */ unsigned int rate; }; -/** Number of IPoIB path cache entries */ -#define IPOIB_NUM_CACHED_PATHS 2 +/** Number of IPoIB peer cache entries + * + * Must be a power of two. + */ +#define IPOIB_NUM_CACHED_PEERS 4 -/** IPoIB path cache */ -static struct ipoib_cached_path ipoib_path_cache[IPOIB_NUM_CACHED_PATHS]; +/** IPoIB peer address cache */ +static struct ipoib_peer ipoib_peer_cache[IPOIB_NUM_CACHED_PEERS]; -/** Oldest IPoIB path cache entry index */ -static unsigned int ipoib_path_cache_idx = 0; +/** Oldest IPoIB peer cache entry index */ +static unsigned int ipoib_peer_cache_idx = 1; -/** TID half used to identify get path record replies */ -#define IPOIB_TID_GET_PATH_REC 0x11111111UL +/** + * Look up cached peer by key + * + * @v key Peer cache key + * @ret peer Peer cache entry, or NULL + */ +static struct ipoib_peer * ipoib_lookup_peer_by_key ( unsigned int key ) { + struct ipoib_peer *peer; + unsigned int i; -/** TID half used to identify multicast member record replies */ -#define IPOIB_TID_MC_MEMBER_REC 0x22222222UL + for ( i = 0 ; i < IPOIB_NUM_CACHED_PEERS ; i++ ) { + peer = &ipoib_peer_cache[i]; + if ( peer->key == key ) + return peer; + } -/** IPoIB metadata TID */ -static uint32_t ipoib_meta_tid = 0; + if ( key != 0 ) { + DBG ( "IPoIB warning: peer cache lost track of key %x while " + "still in use\n", key ); + } + return NULL; +} -/** IPv4 broadcast GID */ -static const struct ib_gid ipv4_broadcast_gid = { - { { 0xff, 0x12, 0x40, 0x1b, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff } } -}; +/** + * Look up cached peer by GID + * + * @v gid Peer GID + * @ret peer Peer cache entry, or NULL + */ +static struct ipoib_peer * +ipoib_lookup_peer_by_gid ( const struct ib_gid *gid ) { + struct ipoib_peer *peer; + unsigned int i; + + for ( i = 0 ; i < IPOIB_NUM_CACHED_PEERS ; i++ ) { + peer = &ipoib_peer_cache[i]; + if ( memcmp ( &peer->mac.gid, gid, + sizeof ( peer->mac.gid) ) == 0 ) { + return peer; + } + } -/** Maximum time we will wait for the broadcast join to succeed */ -#define IPOIB_JOIN_MAX_DELAY_MS 1000 + return NULL; +} + +/** + * Store GID and QPN in peer cache + * + * @v gid Peer GID + * @v qpn Peer QPN + * @ret peer Peer cache entry + */ +static struct ipoib_peer * +ipoib_cache_peer ( const struct ib_gid *gid, unsigned long qpn ) { + struct ipoib_peer *peer; + unsigned int key; + + /* Look for existing cache entry */ + peer = ipoib_lookup_peer_by_gid ( gid ); + if ( peer ) { + assert ( peer->mac.qpn = ntohl ( qpn ) ); + return peer; + } + + /* No entry found: create a new one */ + key = ipoib_peer_cache_idx++; + peer = &ipoib_peer_cache[ key % IPOIB_NUM_CACHED_PEERS ]; + if ( peer->key ) + DBG ( "IPoIB peer %x evicted from cache\n", peer->key ); + + memset ( peer, 0, sizeof ( *peer ) ); + peer->key = key; + peer->mac.qpn = htonl ( qpn ); + memcpy ( &peer->mac.gid, gid, sizeof ( peer->mac.gid ) ); + DBG ( "IPoIB peer %x has GID %08x:%08x:%08x:%08x and QPN %lx\n", + peer->key, htonl ( gid->u.dwords[0] ), + htonl ( gid->u.dwords[1] ), htonl ( gid->u.dwords[2] ), + htonl ( gid->u.dwords[3] ), qpn ); + return peer; +} /**************************************************************************** * @@ -141,37 +233,32 @@ static const struct ib_gid ipv4_broadcast_gid = { **************************************************************************** */ -/** Broadcast QPN used in IPoIB MAC addresses - * - * This is a guaranteed invalid real QPN - */ -#define IPOIB_BROADCAST_QPN 0xffffffffUL - -/** Broadcast IPoIB address */ -static struct ipoib_mac ipoib_broadcast = { - .qpn = ntohl ( IPOIB_BROADCAST_QPN ), -}; - /** * Add IPoIB link-layer header * * @v iobuf I/O buffer - * @v netdev Network device - * @v net_protocol Network-layer protocol * @v ll_dest Link-layer destination address + * @v ll_source Source link-layer address + * @v net_proto Network-layer protocol, in network-byte order + * @ret rc Return status code */ -static int ipoib_push ( struct io_buffer *iobuf, - struct net_device *netdev __unused, - struct net_protocol *net_protocol, - const void *ll_dest ) { +static int ipoib_push ( struct io_buffer *iobuf, const void *ll_dest, + const void *ll_source __unused, uint16_t net_proto ) { struct ipoib_hdr *ipoib_hdr = iob_push ( iobuf, sizeof ( *ipoib_hdr ) ); + const struct ipoib_mac *dest_mac = ll_dest; + const struct ipoib_mac *src_mac = ll_source; + struct ipoib_peer *dest; + struct ipoib_peer *src; + + /* Add link-layer addresses to cache */ + dest = ipoib_cache_peer ( &dest_mac->gid, ntohl ( dest_mac->qpn ) ); + src = ipoib_cache_peer ( &src_mac->gid, ntohl ( src_mac->qpn ) ); /* Build IPoIB header */ - memcpy ( &ipoib_hdr->pseudo.peer, ll_dest, - sizeof ( ipoib_hdr->pseudo.peer ) ); - ipoib_hdr->real.proto = net_protocol->net_proto; - ipoib_hdr->real.reserved = 0; + ipoib_hdr->proto = net_proto; + ipoib_hdr->u.peer.dest = dest->key; + ipoib_hdr->u.peer.src = src->key; return 0; } @@ -180,15 +267,16 @@ static int ipoib_push ( struct io_buffer *iobuf, * Remove IPoIB link-layer header * * @v iobuf I/O buffer - * @v netdev Network device - * @v net_proto Network-layer protocol, in network-byte order - * @v ll_source Source link-layer address + * @ret ll_dest Link-layer destination address + * @ret ll_source Source link-layer address + * @ret net_proto Network-layer protocol, in network-byte order * @ret rc Return status code */ -static int ipoib_pull ( struct io_buffer *iobuf, - struct net_device *netdev __unused, - uint16_t *net_proto, const void **ll_source ) { +static int ipoib_pull ( struct io_buffer *iobuf, const void **ll_dest, + const void **ll_source, uint16_t *net_proto ) { struct ipoib_hdr *ipoib_hdr = iobuf->data; + struct ipoib_peer *dest; + struct ipoib_peer *source; /* Sanity check */ if ( iob_len ( iobuf ) < sizeof ( *ipoib_hdr ) ) { @@ -200,9 +288,17 @@ static int ipoib_pull ( struct io_buffer *iobuf, /* Strip off IPoIB header */ iob_pull ( iobuf, sizeof ( *ipoib_hdr ) ); + /* Identify source and destination addresses, and clear + * reserved word in IPoIB header + */ + dest = ipoib_lookup_peer_by_key ( ipoib_hdr->u.peer.dest ); + source = ipoib_lookup_peer_by_key ( ipoib_hdr->u.peer.src ); + ipoib_hdr->u.reserved = 0; + /* Fill in required fields */ - *net_proto = ipoib_hdr->real.proto; - *ll_source = &ipoib_hdr->pseudo.peer; + *ll_dest = ( dest ? &dest->mac : &ipoib_broadcast ); + *ll_source = ( source ? &source->mac : &ipoib_broadcast ); + *net_proto = ipoib_hdr->proto; return 0; } @@ -217,7 +313,7 @@ const char * ipoib_ntoa ( const void *ll_addr ) { static char buf[45]; const struct ipoib_mac *mac = ll_addr; - snprintf ( buf, sizeof ( buf ), "%08lx:%08lx:%08lx:%08lx:%08lx", + snprintf ( buf, sizeof ( buf ), "%08x:%08x:%08x:%08x:%08x", htonl ( mac->qpn ), htonl ( mac->gid.u.dwords[0] ), htonl ( mac->gid.u.dwords[1] ), htonl ( mac->gid.u.dwords[2] ), @@ -225,6 +321,21 @@ const char * ipoib_ntoa ( const void *ll_addr ) { return buf; } +/** + * Hash multicast address + * + * @v af Address family + * @v net_addr Network-layer address + * @v ll_addr Link-layer address to fill in + * @ret rc Return status code + */ +static int ipoib_mc_hash ( unsigned int af __unused, + const void *net_addr __unused, + void *ll_addr __unused ) { + + return -ENOTSUP; +} + /** IPoIB protocol */ struct ll_protocol ipoib_protocol __ll_protocol = { .name = "IPoIB", @@ -235,6 +346,7 @@ struct ll_protocol ipoib_protocol __ll_protocol = { .push = ipoib_push, .pull = ipoib_pull, .ntoa = ipoib_ntoa, + .mc_hash = ipoib_mc_hash, }; /**************************************************************************** @@ -266,11 +378,17 @@ static void ipoib_destroy_qset ( struct ipoib_device *ipoib, * * @v ipoib IPoIB device * @v qset Queue set + * @v num_cqes Number of completion queue entries + * @v cq_op Completion queue operations + * @v num_send_wqes Number of send work queue entries + * @v num_recv_wqes Number of receive work queue entries + * @v qkey Queue key * @ret rc Return status code */ static int ipoib_create_qset ( struct ipoib_device *ipoib, struct ipoib_queue_set *qset, unsigned int num_cqes, + struct ib_completion_queue_operations *cq_op, unsigned int num_send_wqes, unsigned int num_recv_wqes, unsigned long qkey ) { @@ -285,7 +403,7 @@ static int ipoib_create_qset ( struct ipoib_device *ipoib, qset->recv_max_fill = num_recv_wqes; /* Allocate completion queue */ - qset->cq = ib_create_cq ( ibdev, num_cqes ); + qset->cq = ib_create_cq ( ibdev, num_cqes, cq_op ); if ( ! qset->cq ) { DBGC ( ipoib, "IPoIB %p could not allocate completion queue\n", ipoib ); @@ -312,28 +430,6 @@ static int ipoib_create_qset ( struct ipoib_device *ipoib, } /** - * Find path cache entry by GID - * - * @v gid GID - * @ret entry Path cache entry, or NULL - */ -static struct ipoib_cached_path * -ipoib_find_cached_path ( struct ib_gid *gid ) { - struct ipoib_cached_path *path; - unsigned int i; - - for ( i = 0 ; i < IPOIB_NUM_CACHED_PATHS ; i++ ) { - path = &ipoib_path_cache[i]; - if ( memcmp ( &path->gid, gid, sizeof ( *gid ) ) == 0 ) - return path; - } - DBG ( "IPoIB %08lx:%08lx:%08lx:%08lx cache miss\n", - htonl ( gid->u.dwords[0] ), htonl ( gid->u.dwords[1] ), - htonl ( gid->u.dwords[2] ), htonl ( gid->u.dwords[3] ) ); - return NULL; -} - -/** * Transmit path record request * * @v ipoib IPoIB device @@ -344,36 +440,38 @@ static int ipoib_get_path_record ( struct ipoib_device *ipoib, struct ib_gid *gid ) { struct ib_device *ibdev = ipoib->ibdev; struct io_buffer *iobuf; - struct ib_mad_path_record *path_record; + struct ib_mad_sa *sa; struct ib_address_vector av; int rc; /* Allocate I/O buffer */ - iobuf = alloc_iob ( sizeof ( *path_record ) ); + iobuf = alloc_iob ( sizeof ( *sa ) ); if ( ! iobuf ) return -ENOMEM; - iob_put ( iobuf, sizeof ( *path_record ) ); - path_record = iobuf->data; - memset ( path_record, 0, sizeof ( *path_record ) ); + iob_put ( iobuf, sizeof ( *sa ) ); + sa = iobuf->data; + memset ( sa, 0, sizeof ( *sa ) ); /* Construct path record request */ - path_record->mad_hdr.base_version = IB_MGMT_BASE_VERSION; - path_record->mad_hdr.mgmt_class = IB_MGMT_CLASS_SUBN_ADM; - path_record->mad_hdr.class_version = 2; - path_record->mad_hdr.method = IB_MGMT_METHOD_GET; - path_record->mad_hdr.attr_id = htons ( IB_SA_ATTR_PATH_REC ); - path_record->mad_hdr.tid[0] = IPOIB_TID_GET_PATH_REC; - path_record->mad_hdr.tid[1] = ipoib_meta_tid++; - path_record->sa_hdr.comp_mask[1] = + sa->mad_hdr.base_version = IB_MGMT_BASE_VERSION; + sa->mad_hdr.mgmt_class = IB_MGMT_CLASS_SUBN_ADM; + sa->mad_hdr.class_version = 2; + sa->mad_hdr.method = IB_MGMT_METHOD_GET; + sa->mad_hdr.attr_id = htons ( IB_SA_ATTR_PATH_REC ); + sa->mad_hdr.tid[0] = IPOIB_TID_GET_PATH_REC; + sa->mad_hdr.tid[1] = ipoib_meta_tid++; + sa->sa_hdr.comp_mask[1] = htonl ( IB_SA_PATH_REC_DGID | IB_SA_PATH_REC_SGID ); - memcpy ( &path_record->dgid, gid, sizeof ( path_record->dgid ) ); - memcpy ( &path_record->sgid, &ibdev->port_gid, - sizeof ( path_record->sgid ) ); + memcpy ( &sa->sa_data.path_record.dgid, gid, + sizeof ( sa->sa_data.path_record.dgid ) ); + memcpy ( &sa->sa_data.path_record.sgid, &ibdev->gid, + sizeof ( sa->sa_data.path_record.sgid ) ); /* Construct address vector */ memset ( &av, 0, sizeof ( av ) ); - av.dlid = ibdev->sm_lid; - av.dest_qp = IB_SA_QPN; + av.lid = ibdev->sm_lid; + av.sl = ibdev->sm_sl; + av.qpn = IB_SA_QPN; av.qkey = IB_GLOBAL_QKEY; /* Post send request */ @@ -400,40 +498,41 @@ static int ipoib_mc_member_record ( struct ipoib_device *ipoib, struct ib_gid *gid, int join ) { struct ib_device *ibdev = ipoib->ibdev; struct io_buffer *iobuf; - struct ib_mad_mc_member_record *mc_member_record; + struct ib_mad_sa *sa; struct ib_address_vector av; int rc; /* Allocate I/O buffer */ - iobuf = alloc_iob ( sizeof ( *mc_member_record ) ); + iobuf = alloc_iob ( sizeof ( *sa ) ); if ( ! iobuf ) return -ENOMEM; - iob_put ( iobuf, sizeof ( *mc_member_record ) ); - mc_member_record = iobuf->data; - memset ( mc_member_record, 0, sizeof ( *mc_member_record ) ); + iob_put ( iobuf, sizeof ( *sa ) ); + sa = iobuf->data; + memset ( sa, 0, sizeof ( *sa ) ); /* Construct path record request */ - mc_member_record->mad_hdr.base_version = IB_MGMT_BASE_VERSION; - mc_member_record->mad_hdr.mgmt_class = IB_MGMT_CLASS_SUBN_ADM; - mc_member_record->mad_hdr.class_version = 2; - mc_member_record->mad_hdr.method = + sa->mad_hdr.base_version = IB_MGMT_BASE_VERSION; + sa->mad_hdr.mgmt_class = IB_MGMT_CLASS_SUBN_ADM; + sa->mad_hdr.class_version = 2; + sa->mad_hdr.method = ( join ? IB_MGMT_METHOD_SET : IB_MGMT_METHOD_DELETE ); - mc_member_record->mad_hdr.attr_id = htons ( IB_SA_ATTR_MC_MEMBER_REC ); - mc_member_record->mad_hdr.tid[0] = IPOIB_TID_MC_MEMBER_REC; - mc_member_record->mad_hdr.tid[1] = ipoib_meta_tid++; - mc_member_record->sa_hdr.comp_mask[1] = + sa->mad_hdr.attr_id = htons ( IB_SA_ATTR_MC_MEMBER_REC ); + sa->mad_hdr.tid[0] = IPOIB_TID_MC_MEMBER_REC; + sa->mad_hdr.tid[1] = ipoib_meta_tid++; + sa->sa_hdr.comp_mask[1] = htonl ( IB_SA_MCMEMBER_REC_MGID | IB_SA_MCMEMBER_REC_PORT_GID | IB_SA_MCMEMBER_REC_JOIN_STATE ); - mc_member_record->scope__join_state = 1; - memcpy ( &mc_member_record->mgid, gid, - sizeof ( mc_member_record->mgid ) ); - memcpy ( &mc_member_record->port_gid, &ibdev->port_gid, - sizeof ( mc_member_record->port_gid ) ); + sa->sa_data.mc_member_record.scope__join_state = 1; + memcpy ( &sa->sa_data.mc_member_record.mgid, gid, + sizeof ( sa->sa_data.mc_member_record.mgid ) ); + memcpy ( &sa->sa_data.mc_member_record.port_gid, &ibdev->gid, + sizeof ( sa->sa_data.mc_member_record.port_gid ) ); /* Construct address vector */ memset ( &av, 0, sizeof ( av ) ); - av.dlid = ibdev->sm_lid; - av.dest_qp = IB_SA_QPN; + av.lid = ibdev->sm_lid; + av.sl = ibdev->sm_sl; + av.qpn = IB_SA_QPN; av.qkey = IB_GLOBAL_QKEY; /* Post send request */ @@ -459,49 +558,51 @@ static int ipoib_transmit ( struct net_device *netdev, struct io_buffer *iobuf ) { struct ipoib_device *ipoib = netdev->priv; struct ib_device *ibdev = ipoib->ibdev; - struct ipoib_pseudo_hdr *ipoib_pshdr = iobuf->data; + struct ipoib_hdr *ipoib_hdr; + struct ipoib_peer *dest; struct ib_address_vector av; struct ib_gid *gid; - struct ipoib_cached_path *path; - int rc; /* Sanity check */ - if ( iob_len ( iobuf ) < sizeof ( *ipoib_pshdr ) ) { + if ( iob_len ( iobuf ) < sizeof ( *ipoib_hdr ) ) { DBGC ( ipoib, "IPoIB %p buffer too short\n", ipoib ); return -EINVAL; } - iob_pull ( iobuf, ( sizeof ( *ipoib_pshdr ) ) ); + ipoib_hdr = iobuf->data; /* Attempting transmission while link is down will put the * queue pair into an error state, so don't try it. */ - if ( ! ibdev->link_up ) + if ( ! ib_link_ok ( ibdev ) ) return -ENETUNREACH; + /* Identify destination address */ + dest = ipoib_lookup_peer_by_key ( ipoib_hdr->u.peer.dest ); + if ( ! dest ) + return -ENXIO; + ipoib_hdr->u.reserved = 0; + /* Construct address vector */ memset ( &av, 0, sizeof ( av ) ); - av.qkey = IB_GLOBAL_QKEY; + av.qkey = ipoib->data_qkey; av.gid_present = 1; - if ( ipoib_pshdr->peer.qpn == htonl ( IPOIB_BROADCAST_QPN ) ) { - /* Broadcast address */ - av.dest_qp = IB_BROADCAST_QPN; - av.dlid = ipoib->broadcast_lid; + if ( dest->mac.qpn == htonl ( IPOIB_BROADCAST_QPN ) ) { + /* Broadcast */ + av.qpn = IB_BROADCAST_QPN; + av.lid = ipoib->broadcast_lid; gid = &ipoib->broadcast_gid; } else { - /* Unicast - look in path cache */ - path = ipoib_find_cached_path ( &ipoib_pshdr->peer.gid ); - if ( ! path ) { - /* No path entry - get path record */ - rc = ipoib_get_path_record ( ipoib, - &ipoib_pshdr->peer.gid ); - netdev_tx_complete ( netdev, iobuf ); - return rc; + /* Unicast */ + if ( ! dest->lid ) { + /* No LID yet - get path record to fetch LID */ + ipoib_get_path_record ( ipoib, &dest->mac.gid ); + return -ENOENT; } - av.dest_qp = ntohl ( ipoib_pshdr->peer.qpn ); - av.dlid = path->dlid; - av.rate = path->rate; - av.sl = path->sl; - gid = &ipoib_pshdr->peer.gid; + av.qpn = ntohl ( dest->mac.qpn ); + av.lid = dest->lid; + av.rate = dest->rate; + av.sl = dest->sl; + gid = &dest->mac.gid; } memcpy ( &av.gid, gid, sizeof ( av.gid ) ); @@ -513,17 +614,15 @@ static int ipoib_transmit ( struct net_device *netdev, * * @v ibdev Infiniband device * @v qp Queue pair - * @v completion Completion * @v iobuf I/O buffer + * @v rc Completion status code */ static void ipoib_data_complete_send ( struct ib_device *ibdev __unused, struct ib_queue_pair *qp, - struct ib_completion *completion, - struct io_buffer *iobuf ) { + struct io_buffer *iobuf, int rc ) { struct net_device *netdev = ib_qp_get_ownerdata ( qp ); - netdev_tx_complete_err ( netdev, iobuf, - ( completion->syndrome ? -EIO : 0 ) ); + netdev_tx_complete_err ( netdev, iobuf, rc ); } /** @@ -531,67 +630,67 @@ static void ipoib_data_complete_send ( struct ib_device *ibdev __unused, * * @v ibdev Infiniband device * @v qp Queue pair - * @v completion Completion + * @v av Address vector, or NULL * @v iobuf I/O buffer + * @v rc Completion status code */ static void ipoib_data_complete_recv ( struct ib_device *ibdev __unused, struct ib_queue_pair *qp, - struct ib_completion *completion, - struct io_buffer *iobuf ) { + struct ib_address_vector *av, + struct io_buffer *iobuf, int rc ) { struct net_device *netdev = ib_qp_get_ownerdata ( qp ); struct ipoib_device *ipoib = netdev->priv; - struct ipoib_pseudo_hdr *ipoib_pshdr; + struct ipoib_hdr *ipoib_hdr; + struct ipoib_peer *src; - if ( completion->syndrome ) { - netdev_rx_err ( netdev, iobuf, -EIO ); - goto done; - } - - iob_put ( iobuf, completion->len ); - if ( iob_len ( iobuf ) < sizeof ( struct ib_global_route_header ) ) { - DBGC ( ipoib, "IPoIB %p received data packet too short to " - "contain GRH\n", ipoib ); - DBGC_HD ( ipoib, iobuf->data, iob_len ( iobuf ) ); - netdev_rx_err ( netdev, iobuf, -EIO ); - goto done; + if ( rc != 0 ) { + netdev_rx_err ( netdev, iobuf, rc ); + return; } - iob_pull ( iobuf, sizeof ( struct ib_global_route_header ) ); - if ( iob_len ( iobuf ) < sizeof ( struct ipoib_real_hdr ) ) { + /* Sanity check */ + if ( iob_len ( iobuf ) < sizeof ( struct ipoib_hdr ) ) { DBGC ( ipoib, "IPoIB %p received data packet too short to " "contain IPoIB header\n", ipoib ); DBGC_HD ( ipoib, iobuf->data, iob_len ( iobuf ) ); netdev_rx_err ( netdev, iobuf, -EIO ); - goto done; + return; } + ipoib_hdr = iobuf->data; - ipoib_pshdr = iob_push ( iobuf, sizeof ( *ipoib_pshdr ) ); - /* FIXME: fill in a MAC address for the sake of AoE! */ + /* Parse source address */ + if ( av->gid_present ) { + src = ipoib_cache_peer ( &av->gid, av->qpn ); + ipoib_hdr->u.peer.src = src->key; + } + /* Hand off to network layer */ netdev_rx ( netdev, iobuf ); - - done: - ipoib->data.recv_fill--; } +/** IPoIB data completion operations */ +static struct ib_completion_queue_operations ipoib_data_cq_op = { + .complete_send = ipoib_data_complete_send, + .complete_recv = ipoib_data_complete_recv, +}; + /** * Handle IPoIB metadata send completion * * @v ibdev Infiniband device * @v qp Queue pair - * @v completion Completion * @v iobuf I/O buffer + * @v rc Completion status code */ static void ipoib_meta_complete_send ( struct ib_device *ibdev __unused, struct ib_queue_pair *qp, - struct ib_completion *completion, - struct io_buffer *iobuf ) { + struct io_buffer *iobuf, int rc ) { struct net_device *netdev = ib_qp_get_ownerdata ( qp ); struct ipoib_device *ipoib = netdev->priv; - if ( completion->syndrome ) { - DBGC ( ipoib, "IPoIB %p metadata TX completion error %x\n", - ipoib, completion->syndrome ); + if ( rc != 0 ) { + DBGC ( ipoib, "IPoIB %p metadata TX completion error: %s\n", + ipoib, strerror ( rc ) ); } free_iob ( iobuf ); } @@ -602,26 +701,25 @@ static void ipoib_meta_complete_send ( struct ib_device *ibdev __unused, * @v ipoib IPoIB device * @v path_record Path record */ -static void ipoib_recv_path_record ( struct ipoib_device *ipoib __unused, - struct ib_mad_path_record *path_record ) { - struct ipoib_cached_path *path; +static void ipoib_recv_path_record ( struct ipoib_device *ipoib, + struct ib_path_record *path_record ) { + struct ipoib_peer *peer; + + /* Locate peer cache entry */ + peer = ipoib_lookup_peer_by_gid ( &path_record->dgid ); + if ( ! peer ) { + DBGC ( ipoib, "IPoIB %p received unsolicited path record\n", + ipoib ); + return; + } /* Update path cache entry */ - path = &ipoib_path_cache[ipoib_path_cache_idx]; - memcpy ( &path->gid, &path_record->dgid, sizeof ( path->gid ) ); - path->dlid = ntohs ( path_record->dlid ); - path->sl = ( path_record->reserved__sl & 0x0f ); - path->rate = ( path_record->rate_selector__rate & 0x3f ); - - DBG ( "IPoIB %08lx:%08lx:%08lx:%08lx dlid %x sl %x rate %x\n", - htonl ( path->gid.u.dwords[0] ), htonl ( path->gid.u.dwords[1] ), - htonl ( path->gid.u.dwords[2] ), htonl ( path->gid.u.dwords[3] ), - path->dlid, path->sl, path->rate ); - - /* Update path cache index */ - ipoib_path_cache_idx++; - if ( ipoib_path_cache_idx == IPOIB_NUM_CACHED_PATHS ) - ipoib_path_cache_idx = 0; + peer->lid = ntohs ( path_record->dlid ); + peer->sl = ( path_record->reserved__sl & 0x0f ); + peer->rate = ( path_record->rate_selector__rate & 0x3f ); + + DBG ( "IPoIB peer %x has dlid %x sl %x rate %x\n", + peer->key, peer->lid, peer->sl, peer->rate ); } /** @@ -631,7 +729,7 @@ static void ipoib_recv_path_record ( struct ipoib_device *ipoib __unused, * @v mc_member_record Multicast membership record */ static void ipoib_recv_mc_member_record ( struct ipoib_device *ipoib, - struct ib_mad_mc_member_record *mc_member_record ) { + struct ib_mc_member_record *mc_member_record ) { int joined; int rc; @@ -657,64 +755,64 @@ static void ipoib_recv_mc_member_record ( struct ipoib_device *ipoib, * * @v ibdev Infiniband device * @v qp Queue pair - * @v completion Completion + * @v av Address vector, or NULL * @v iobuf I/O buffer + * @v rc Completion status code */ -static void ipoib_meta_complete_recv ( struct ib_device *ibdev __unused, - struct ib_queue_pair *qp, - struct ib_completion *completion, - struct io_buffer *iobuf ) { +static void +ipoib_meta_complete_recv ( struct ib_device *ibdev __unused, + struct ib_queue_pair *qp, + struct ib_address_vector *av __unused, + struct io_buffer *iobuf, int rc ) { struct net_device *netdev = ib_qp_get_ownerdata ( qp ); struct ipoib_device *ipoib = netdev->priv; - union ib_mad *mad; + struct ib_mad_sa *sa; - if ( completion->syndrome ) { - DBGC ( ipoib, "IPoIB %p metadata RX completion error %x\n", - ipoib, completion->syndrome ); + if ( rc != 0 ) { + DBGC ( ipoib, "IPoIB %p metadata RX completion error: %s\n", + ipoib, strerror ( rc ) ); goto done; } - iob_put ( iobuf, completion->len ); - if ( iob_len ( iobuf ) < sizeof ( struct ib_global_route_header ) ) { - DBGC ( ipoib, "IPoIB %p received metadata packet too short " - "to contain GRH\n", ipoib ); - DBGC_HD ( ipoib, iobuf->data, iob_len ( iobuf ) ); - goto done; - } - iob_pull ( iobuf, sizeof ( struct ib_global_route_header ) ); - if ( iob_len ( iobuf ) < sizeof ( *mad ) ) { + if ( iob_len ( iobuf ) < sizeof ( *sa ) ) { DBGC ( ipoib, "IPoIB %p received metadata packet too short " "to contain reply\n", ipoib ); DBGC_HD ( ipoib, iobuf->data, iob_len ( iobuf ) ); goto done; } - mad = iobuf->data; + sa = iobuf->data; - if ( mad->mad_hdr.status != 0 ) { + if ( sa->mad_hdr.status != 0 ) { DBGC ( ipoib, "IPoIB %p metadata RX err status %04x\n", - ipoib, ntohs ( mad->mad_hdr.status ) ); + ipoib, ntohs ( sa->mad_hdr.status ) ); goto done; } - switch ( mad->mad_hdr.tid[0] ) { + switch ( sa->mad_hdr.tid[0] ) { case IPOIB_TID_GET_PATH_REC: - ipoib_recv_path_record ( ipoib, &mad->path_record ); + ipoib_recv_path_record ( ipoib, &sa->sa_data.path_record ); break; case IPOIB_TID_MC_MEMBER_REC: - ipoib_recv_mc_member_record ( ipoib, &mad->mc_member_record ); + ipoib_recv_mc_member_record ( ipoib, + &sa->sa_data.mc_member_record ); break; default: DBGC ( ipoib, "IPoIB %p unwanted response:\n", ipoib ); - DBGC_HD ( ipoib, mad, sizeof ( *mad ) ); + DBGC_HD ( ipoib, sa, sizeof ( *sa ) ); break; } done: - ipoib->meta.recv_fill--; free_iob ( iobuf ); } +/** IPoIB metadata completion operations */ +static struct ib_completion_queue_operations ipoib_meta_cq_op = { + .complete_send = ipoib_meta_complete_send, + .complete_recv = ipoib_meta_complete_recv, +}; + /** * Refill IPoIB receive ring * @@ -726,15 +824,14 @@ static void ipoib_refill_recv ( struct ipoib_device *ipoib, struct io_buffer *iobuf; int rc; - while ( qset->recv_fill < qset->recv_max_fill ) { - iobuf = alloc_iob ( IPOIB_MTU ); + while ( qset->qp->recv.fill < qset->recv_max_fill ) { + iobuf = alloc_iob ( IPOIB_PKT_LEN ); if ( ! iobuf ) break; if ( ( rc = ib_post_recv ( ibdev, qset->qp, iobuf ) ) != 0 ) { free_iob ( iobuf ); break; } - qset->recv_fill++; } } @@ -747,10 +844,8 @@ static void ipoib_poll ( struct net_device *netdev ) { struct ipoib_device *ipoib = netdev->priv; struct ib_device *ibdev = ipoib->ibdev; - ib_poll_cq ( ibdev, ipoib->meta.cq, ipoib_meta_complete_send, - ipoib_meta_complete_recv ); - ib_poll_cq ( ibdev, ipoib->data.cq, ipoib_data_complete_send, - ipoib_data_complete_recv ); + ib_poll_cq ( ibdev, ipoib->meta.cq ); + ib_poll_cq ( ibdev, ipoib->data.cq ); ipoib_refill_recv ( ipoib, &ipoib->meta ); ipoib_refill_recv ( ipoib, &ipoib->data ); } @@ -831,9 +926,17 @@ static int ipoib_open ( struct net_device *netdev ) { struct ipoib_mac *mac = ( ( struct ipoib_mac * ) netdev->ll_addr ); int rc; + /* Open IB device */ + if ( ( rc = ib_open ( ipoib->ibdev ) ) != 0 ) { + DBGC ( ipoib, "IPoIB %p could not open device: %s\n", + ipoib, strerror ( rc ) ); + goto err_ib_open; + } + /* Allocate metadata queue set */ if ( ( rc = ipoib_create_qset ( ipoib, &ipoib->meta, IPOIB_META_NUM_CQES, + &ipoib_meta_cq_op, IPOIB_META_NUM_SEND_WQES, IPOIB_META_NUM_RECV_WQES, IB_GLOBAL_QKEY ) ) != 0 ) { @@ -845,6 +948,7 @@ static int ipoib_open ( struct net_device *netdev ) { /* Allocate data queue set */ if ( ( rc = ipoib_create_qset ( ipoib, &ipoib->data, IPOIB_DATA_NUM_CQES, + &ipoib_data_cq_op, IPOIB_DATA_NUM_SEND_WQES, IPOIB_DATA_NUM_RECV_WQES, IB_GLOBAL_QKEY ) ) != 0 ) { @@ -874,6 +978,8 @@ static int ipoib_open ( struct net_device *netdev ) { err_create_data_qset: ipoib_destroy_qset ( ipoib, &ipoib->meta ); err_create_meta_qset: + ib_close ( ipoib->ibdev ); + err_ib_open: return rc; } @@ -895,6 +1001,9 @@ static void ipoib_close ( struct net_device *netdev ) { /* Tear down the queues */ ipoib_destroy_qset ( ipoib, &ipoib->data ); ipoib_destroy_qset ( ipoib, &ipoib->meta ); + + /* Close IB device */ + ib_close ( ipoib->ibdev ); } /** IPoIB network device operations */ @@ -923,15 +1032,15 @@ static void ipoib_set_ib_params ( struct ipoib_device *ipoib ) { /* Calculate GID portion of MAC address based on port GID */ mac = ( ( struct ipoib_mac * ) netdev->ll_addr ); - memcpy ( &mac->gid, &ibdev->port_gid, sizeof ( mac->gid ) ); + memcpy ( &mac->gid, &ibdev->gid, sizeof ( mac->gid ) ); /* Calculate broadcast GID based on partition key */ - memcpy ( &ipoib->broadcast_gid, &ipv4_broadcast_gid, + memcpy ( &ipoib->broadcast_gid, &ipoib_broadcast.gid, sizeof ( ipoib->broadcast_gid ) ); ipoib->broadcast_gid.u.words[2] = htons ( ibdev->pkey ); /* Set net device link state to reflect Infiniband link state */ - if ( ibdev->link_up ) { + if ( ib_link_ok ( ibdev ) ) { netdev_link_up ( netdev ); } else { netdev_link_down ( netdev ); diff --git a/gpxe/src/drivers/net/mtnic.c b/gpxe/src/drivers/net/mtnic.c index dd577f4a..0d84a44c 100755..100644 --- a/gpxe/src/drivers/net/mtnic.c +++ b/gpxe/src/drivers/net/mtnic.c @@ -30,13 +30,13 @@ * SOFTWARE. * */ -#include <stdio.h> #include <strings.h> #include <errno.h> #include <gpxe/malloc.h> #include <gpxe/umalloc.h> #include <byteswap.h> #include <unistd.h> +#include <gpxe/io.h> #include <gpxe/pci.h> #include <gpxe/ethernet.h> #include <gpxe/netdevice.h> @@ -47,28 +47,12 @@ /* - mtnic.c - gPXE driver for Mellanox 10Gig ConnectX EN + mtnic.c - gPXE driver for Mellanox 10Gig ConnectX EN */ -/* (mcb30) - The Mellanox driver used "1" as a universal error code; - * this at least makes it a valid error number. - */ -#define MTNIC_ERROR -EIO - - -/** Set port number to use - * - * 0 - port 1 - * 1 - port 2 - */ -#define MTNIC_PORT_NUM 0 -/* Note: for verbose printing do Make ... DEBUG=mtnic */ - - - /******************************************************************** * @@ -87,11 +71,11 @@ * and it's physical aligned address in 'pa' */ static int -mtnic_alloc_aligned(unsigned int size, void **va, u32 *pa, unsigned int alignment) +mtnic_alloc_aligned(unsigned int size, void **va, unsigned long *pa, unsigned int alignment) { *va = alloc_memblock(size, alignment); if (!*va) { - return MTNIC_ERROR; + return -EADDRINUSE; } *pa = (u32)virt_to_bus(*va); return 0; @@ -105,21 +89,21 @@ mtnic_alloc_aligned(unsigned int size, void **va, u32 *pa, unsigned int alignmen * */ static int -mtnic_alloc_cmdif(struct mtnic_priv *priv) +mtnic_alloc_cmdif(struct mtnic *mtnic) { - u32 bar = mtnic_pci_dev.dev.bar[0]; + u32 bar = mtnic_pci_dev.dev.bar[0]; - priv->hcr = ioremap(bar + MTNIC_HCR_BASE, MTNIC_HCR_SIZE); - if (!priv->hcr) { - DBG("Couldn't map command register."); - return MTNIC_ERROR; + mtnic->hcr = ioremap(bar + MTNIC_HCR_BASE, MTNIC_HCR_SIZE); + if ( !mtnic->hcr ) { + DBG("Couldn't map command register\n"); + return -EADDRINUSE; } - mtnic_alloc_aligned(PAGE_SIZE, (void *)&priv->cmd.buf, &priv->cmd.mapping, PAGE_SIZE); - if (!priv->cmd.buf) { + mtnic_alloc_aligned(PAGE_SIZE, (void *)&mtnic->cmd.buf, &mtnic->cmd.mapping, PAGE_SIZE); + if ( !mtnic->cmd.buf ) { DBG("Error in allocating buffer for command interface\n"); - return MTNIC_ERROR; + return -EADDRINUSE; } - return 0; + return 0; } /** @@ -128,12 +112,13 @@ mtnic_alloc_cmdif(struct mtnic_priv *priv) static void mtnic_free_io_buffers(struct mtnic_ring *ring) { - int index; + int index; for (; ring->cons <= ring->prod; ++ring->cons) { index = ring->cons & ring->size_mask; - if (ring->iobuf[index]) + if ( ring->iobuf[index] ) { free_iob(ring->iobuf[index]); + } } } @@ -145,7 +130,7 @@ mtnic_free_io_buffers(struct mtnic_ring *ring) * */ static int -mtnic_alloc_iobuf(struct mtnic_priv *priv, struct mtnic_ring *ring, +mtnic_alloc_iobuf(struct mtnic_port *priv, struct mtnic_ring *ring, unsigned int size) { struct mtnic_rx_desc *rx_desc_ptr = ring->buf; @@ -154,25 +139,20 @@ mtnic_alloc_iobuf(struct mtnic_priv *priv, struct mtnic_ring *ring, while ((u32)(ring->prod - ring->cons) < UNITS_BUFFER_SIZE) { index = ring->prod & ring->size_mask; ring->iobuf[index] = alloc_iob(size); - if (!&ring->iobuf[index]) { + if (!ring->iobuf[index]) { if (ring->prod <= (ring->cons + 1)) { - DBG("Error allocating Rx io " - "buffer number %lx", index); - /* In case of error freeing io buffer */ - mtnic_free_io_buffers(ring); - return MTNIC_ERROR; + DBG ( "Dropping packet, buffer is full\n" ); } - break; } /* Attach io_buffer to descriptor */ rx_desc_ptr = ring->buf + - (sizeof(struct mtnic_rx_desc) * index); + (sizeof(struct mtnic_rx_desc) * index); rx_desc_ptr->data.count = cpu_to_be32(size); - rx_desc_ptr->data.mem_type = priv->fw.mem_type_snoop_be; + rx_desc_ptr->data.mem_type = priv->mtnic->fw.mem_type_snoop_be; rx_desc_ptr->data.addr_l = cpu_to_be32( - virt_to_bus(ring->iobuf[index]->data)); + virt_to_bus(ring->iobuf[index]->data)); ++ ring->prod; } @@ -190,8 +170,8 @@ mtnic_alloc_iobuf(struct mtnic_priv *priv, struct mtnic_ring *ring, * */ static int -mtnic_alloc_ring(struct mtnic_priv *priv, struct mtnic_ring *ring, - u32 size, u16 stride, u16 cq, u8 is_rx) +mtnic_alloc_ring(struct mtnic_port *priv, struct mtnic_ring *ring, + u32 size, u16 stride, u16 cq, u8 is_rx) { unsigned int i; int err; @@ -207,18 +187,18 @@ mtnic_alloc_ring(struct mtnic_priv *priv, struct mtnic_ring *ring, /* Alloc descriptors buffer */ ring->buf_size = ring->size * ((is_rx) ? sizeof(struct mtnic_rx_desc) : - sizeof(struct mtnic_tx_desc)); + sizeof(struct mtnic_tx_desc)); err = mtnic_alloc_aligned(ring->buf_size, (void *)&ring->buf, - &ring->dma, PAGE_SIZE); - if (err) { - DBG("Failed allocating descriptor ring sizeof %lx\n", + &ring->dma, PAGE_SIZE); + if (err) { + DBG("Failed allocating descriptor ring sizeof %x\n", ring->buf_size); - return MTNIC_ERROR; + return -EADDRINUSE; } - memset(ring->buf, 0, ring->buf_size); + memset(ring->buf, 0, ring->buf_size); - DBG("Allocated %s ring (addr:%p) - buf:%p size:%lx" - "buf_size:%lx dma:%lx\n", + DBG("Allocated %s ring (addr:%p) - buf:%p size:%x" + "buf_size:%x dma:%lx\n", is_rx ? "Rx" : "Tx", ring, ring->buf, ring->size, ring->buf_size, ring->dma); @@ -226,11 +206,11 @@ mtnic_alloc_ring(struct mtnic_priv *priv, struct mtnic_ring *ring, if (is_rx) { /* RX ring */ /* Alloc doorbell */ err = mtnic_alloc_aligned(sizeof(struct mtnic_cq_db_record), - (void *)&ring->db, &ring->db_dma, 32); + (void *)&ring->db, &ring->db_dma, 32); if (err) { DBG("Failed allocating Rx ring doorbell record\n"); - free(ring->buf); - return MTNIC_ERROR; + free_memblock(ring->buf, ring->buf_size); + return -EADDRINUSE; } /* ==- Configure Descriptor -== */ @@ -244,14 +224,14 @@ mtnic_alloc_ring(struct mtnic_priv *priv, struct mtnic_ring *ring, /*The last ctrl descriptor is '0' and points to the first one*/ /* Alloc IO_BUFFERS */ - err = mtnic_alloc_iobuf(priv, ring, DEF_IOBUF_SIZE); + err = mtnic_alloc_iobuf ( priv, ring, DEF_IOBUF_SIZE ); if (err) { - DBG("ERROR Allocating io buffer"); - free(ring->buf); - return MTNIC_ERROR; + DBG("ERROR Allocating io buffer\n"); + free_memblock(ring->buf, ring->buf_size); + return -EADDRINUSE; } - } else { /* TX ring */ + } else { /* TX ring */ /* Set initial ownership of all Tx Desc' to SW (1) */ for (i = 0; i < ring->size; i++) { tx_desc = ring->buf + ring->stride * i; @@ -259,17 +239,17 @@ mtnic_alloc_ring(struct mtnic_priv *priv, struct mtnic_ring *ring, } /* DB */ ring->db_offset = cpu_to_be32( - ((u32) priv->fw.tx_offset[priv->port]) << 8); + ((u32) priv->mtnic->fw.tx_offset[priv->port]) << 8); /* Map Tx+CQ doorbells */ - DBG("Mapping TxCQ doorbell at offset:0x%lx\n", - priv->fw.txcq_db_offset); + DBG("Mapping TxCQ doorbell at offset:0x%x\n", + priv->mtnic->fw.txcq_db_offset); ring->txcq_db = ioremap(mtnic_pci_dev.dev.bar[2] + - priv->fw.txcq_db_offset, PAGE_SIZE); + priv->mtnic->fw.txcq_db_offset, PAGE_SIZE); if (!ring->txcq_db) { DBG("Couldn't map txcq doorbell, aborting...\n"); - free(ring->buf); - return MTNIC_ERROR; + free_memblock(ring->buf, ring->buf_size); + return -EADDRINUSE; } } @@ -286,7 +266,7 @@ mtnic_alloc_ring(struct mtnic_priv *priv, struct mtnic_ring *ring, */ static int mtnic_alloc_cq(struct net_device *dev, int num, struct mtnic_cq *cq, - u8 is_rx, u32 size, u32 offset_ind) + u8 is_rx, u32 size, u32 offset_ind) { int err ; unsigned int i; @@ -300,26 +280,26 @@ mtnic_alloc_cq(struct net_device *dev, int num, struct mtnic_cq *cq, /* Alloc doorbell */ err = mtnic_alloc_aligned(sizeof(struct mtnic_cq_db_record), - (void *)&cq->db, &cq->db_dma, 32); + (void *)&cq->db, &cq->db_dma, 32); if (err) { DBG("Failed allocating CQ doorbell record\n"); - return MTNIC_ERROR; + return -EADDRINUSE; } memset(cq->db, 0, sizeof(struct mtnic_cq_db_record)); /* Alloc CQEs buffer */ cq->buf_size = size * sizeof(struct mtnic_cqe); err = mtnic_alloc_aligned(cq->buf_size, - (void *)&cq->buf, &cq->dma, PAGE_SIZE); + (void *)&cq->buf, &cq->dma, PAGE_SIZE); if (err) { DBG("Failed allocating CQ buffer\n"); - free(cq->db); - return MTNIC_ERROR; + free_memblock(cq->db, sizeof(struct mtnic_cq_db_record)); + return -EADDRINUSE; } - memset(cq->buf, 0, cq->buf_size); - DBG("Allocated CQ (addr:%p) - size:%lx buf:%p buf_size:%lx " + memset(cq->buf, 0, cq->buf_size); + DBG("Allocated CQ (addr:%p) - size:%x buf:%p buf_size:%x " "dma:%lx db:%p db_dma:%lx\n" - "cqn offset:%lx \n", cq, cq->size, cq->buf, + "cqn offset:%x \n", cq, cq->size, cq->buf, cq->buf_size, cq->dma, cq->db, cq->db_dma, offset_ind); @@ -343,19 +323,20 @@ mtnic_alloc_cq(struct net_device *dev, int num, struct mtnic_cq *cq, unsigned int mtnic_alloc_resources(struct net_device *dev) { - struct mtnic_priv *priv = netdev_priv(dev); - int err; + struct mtnic_port *priv = netdev_priv(dev); + int err; int cq_ind = 0; - int cq_offset = priv->fw.cq_offset; + int cq_offset = priv->mtnic->fw.cq_offset; /* Alloc 1st CQ */ - err = mtnic_alloc_cq(dev, cq_ind, &priv->cq[cq_ind], 1 /* RX */, + err = mtnic_alloc_cq(dev, cq_ind, &priv->cq[cq_ind], 1 /* RX */, UNITS_BUFFER_SIZE, cq_offset + cq_ind); if (err) { DBG("Failed allocating Rx CQ\n"); - return MTNIC_ERROR; + return -EADDRINUSE; } + /* Alloc RX */ err = mtnic_alloc_ring(priv, &priv->rx_ring, UNITS_BUFFER_SIZE, sizeof(struct mtnic_rx_desc), cq_ind, /* RX */1); @@ -364,7 +345,8 @@ mtnic_alloc_resources(struct net_device *dev) goto cq0_error; } - ++cq_ind; + + ++cq_ind; /* alloc 2nd CQ */ err = mtnic_alloc_cq(dev, cq_ind, &priv->cq[cq_ind], 0 /* TX */, @@ -385,17 +367,18 @@ mtnic_alloc_resources(struct net_device *dev) return 0; cq1_error: - free(priv->cq[1].buf); - free(priv->cq[1].db); + free_memblock(priv->cq[1].buf, priv->cq[1].buf_size); + free_memblock(priv->cq[1].db, sizeof(struct mtnic_cq_db_record)); + rx_error: - free(priv->rx_ring.buf); - free(priv->rx_ring.db); + free_memblock(priv->rx_ring.buf, priv->rx_ring.buf_size); + free_memblock(priv->rx_ring.db, sizeof(struct mtnic_cq_db_record)); mtnic_free_io_buffers(&priv->rx_ring); cq0_error: - free(priv->cq[0].buf); - free(priv->cq[0].db); + free_memblock(priv->cq[0].buf, priv->cq[0].buf_size); + free_memblock(priv->cq[0].db, sizeof(struct mtnic_cq_db_record)); - return MTNIC_ERROR; + return -EADDRINUSE; } @@ -405,35 +388,35 @@ cq0_error: * Note: EQ is not used by the driver but must be allocated */ static int -mtnic_alloc_eq(struct mtnic_priv *priv) +mtnic_alloc_eq(struct mtnic *mtnic) { int err; unsigned int i; struct mtnic_eqe *eqe_desc = NULL; /* Allocating doorbell */ - priv->eq_db = ioremap(mtnic_pci_dev.dev.bar[2] + - priv->fw.eq_db_offset, sizeof(u32)); - if (!priv->eq_db) { + mtnic->eq_db = ioremap(mtnic_pci_dev.dev.bar[2] + + mtnic->fw.eq_db_offset, sizeof(u32)); + if (!mtnic->eq_db) { DBG("Couldn't map EQ doorbell, aborting...\n"); - return MTNIC_ERROR; + return -EADDRINUSE; } /* Allocating buffer */ - priv->eq.size = NUM_EQES; - priv->eq.buf_size = priv->eq.size * sizeof(struct mtnic_eqe); - err = mtnic_alloc_aligned(priv->eq.buf_size, (void *)&priv->eq.buf, - &priv->eq.dma, PAGE_SIZE); + mtnic->eq.size = NUM_EQES; + mtnic->eq.buf_size = mtnic->eq.size * sizeof(struct mtnic_eqe); + err = mtnic_alloc_aligned(mtnic->eq.buf_size, (void *)&mtnic->eq.buf, + &mtnic->eq.dma, PAGE_SIZE); if (err) { DBG("Failed allocating EQ buffer\n"); - iounmap(priv->eq_db); - return MTNIC_ERROR; + iounmap(mtnic->eq_db); + return -EADDRINUSE; } - memset(priv->eq.buf, 0, priv->eq.buf_size); + memset(mtnic->eq.buf, 0, mtnic->eq.buf_size); - for (i = 0; i < priv->eq.size; i++) - eqe_desc = priv->eq.buf + (sizeof(struct mtnic_eqe) * i); - eqe_desc->own |= MTNIC_BIT_EQE_OWN; + for (i = 0; i < mtnic->eq.size; i++) + eqe_desc = mtnic->eq.buf + (sizeof(struct mtnic_eqe) * i); + eqe_desc->own |= MTNIC_BIT_EQE_OWN; mdelay(20); return 0; @@ -458,32 +441,32 @@ mtnic_alloc_eq(struct mtnic_priv *priv) * *********************************************************************/ static inline int -cmdif_go_bit(struct mtnic_priv *priv) +cmdif_go_bit(struct mtnic *mtnic) { - struct mtnic_if_cmd_reg *hcr = priv->hcr; + struct mtnic_if_cmd_reg *hcr = mtnic->hcr; u32 status; int i; for (i = 0; i < TBIT_RETRIES; i++) { status = be32_to_cpu(readl(&hcr->status_go_opcode)); if ((status & MTNIC_BC_MASK(MTNIC_MASK_CMD_REG_T_BIT)) == - (priv->cmd.tbit << MTNIC_BC_OFF(MTNIC_MASK_CMD_REG_T_BIT))) { + (mtnic->cmd.tbit << MTNIC_BC_OFF(MTNIC_MASK_CMD_REG_T_BIT))) { /* Read expected t-bit - now return go-bit value */ return status & MTNIC_BC_MASK(MTNIC_MASK_CMD_REG_GO_BIT); } } DBG("Invalid tbit after %d retries!\n", TBIT_RETRIES); - return 1; /* Return busy... */ + return -EBUSY; /* Return busy... */ } /* Base Command interface */ static int -mtnic_cmd(struct mtnic_priv *priv, void *in_imm, +mtnic_cmd(struct mtnic *mtnic, void *in_imm, void *out_imm, u32 in_modifier, u16 op) { - struct mtnic_if_cmd_reg *hcr = priv->hcr; + struct mtnic_if_cmd_reg *hcr = mtnic->hcr; int err = 0; u32 out_param_h = 0; u32 out_param_l = 0; @@ -497,43 +480,43 @@ mtnic_cmd(struct mtnic_priv *priv, void *in_imm, token++; - if (cmdif_go_bit(priv)) { + if ( cmdif_go_bit ( mtnic ) ) { DBG("GO BIT BUSY:%p.\n", hcr + 6); - err = MTNIC_ERROR; + err = -EBUSY; goto out; } if (in_imm) { in_param_h = *((u32*)in_imm); in_param_l = *((u32*)in_imm + 1); } else { - in_param_l = cpu_to_be32(priv->cmd.mapping); + in_param_l = cpu_to_be32(mtnic->cmd.mapping); } - out_param_l = cpu_to_be32(priv->cmd.mapping); + out_param_l = cpu_to_be32(mtnic->cmd.mapping); /* writing to MCR */ - writel(in_param_h, &hcr->in_param_h); - writel(in_param_l, &hcr->in_param_l); - writel((u32) cpu_to_be32(in_modifier), &hcr->input_modifier); - writel(out_param_h, &hcr->out_param_h); - writel(out_param_l, &hcr->out_param_l); - writel((u32)cpu_to_be32(token << 16), &hcr->token); + writel(in_param_h, &hcr->in_param_h); + writel(in_param_l, &hcr->in_param_l); + writel((u32) cpu_to_be32(in_modifier), &hcr->input_modifier); + writel(out_param_h, &hcr->out_param_h); + writel(out_param_l, &hcr->out_param_l); + writel((u32)cpu_to_be32(token << 16), &hcr->token); wmb(); /* flip toggle bit before each write to the HCR */ - priv->cmd.tbit = !priv->cmd.tbit; - writel((u32) + mtnic->cmd.tbit = !mtnic->cmd.tbit; + writel( ( u32 ) cpu_to_be32(MTNIC_BC_MASK(MTNIC_MASK_CMD_REG_GO_BIT) | - (priv->cmd.tbit << MTNIC_BC_OFF(MTNIC_MASK_CMD_REG_T_BIT)) | op), + ( mtnic->cmd.tbit << MTNIC_BC_OFF ( MTNIC_MASK_CMD_REG_T_BIT ) ) | op ), &hcr->status_go_opcode); - while (cmdif_go_bit(priv) && (timeout <= GO_BIT_TIMEOUT)) { - mdelay(1); + while ( cmdif_go_bit ( mtnic ) && ( timeout <= GO_BIT_TIMEOUT ) ) { + mdelay ( 1 ); ++timeout; } - if (cmdif_go_bit(priv)) { + if ( cmdif_go_bit ( mtnic ) ) { DBG("Command opcode:0x%x token:0x%x TIMEOUT.\n", op, token); - err = MTNIC_ERROR; + err = -EBUSY; goto out; } @@ -543,10 +526,10 @@ mtnic_cmd(struct mtnic_priv *priv, void *in_imm, } status = be32_to_cpu((u32)readl(&hcr->status_go_opcode)) >> 24; - /*DBG("Command opcode:0x%x token:0x%x returned:0x%lx\n", - op, token, status);*/ if (status) { + DBG("Command opcode:0x%x token:0x%x returned:0x%x\n", + op, token, status); return status; } @@ -556,12 +539,12 @@ out: /* MAP PAGES wrapper */ static int -mtnic_map_cmd(struct mtnic_priv *priv, u16 op, struct mtnic_pages pages) +mtnic_map_cmd(struct mtnic *mtnic, u16 op, struct mtnic_pages pages) { - unsigned int j; + unsigned int j; u32 addr; unsigned int len; - u32 *page_arr = priv->cmd.buf; + u32 *page_arr = mtnic->cmd.buf; int nent = 0; int err = 0; @@ -570,28 +553,28 @@ mtnic_map_cmd(struct mtnic_priv *priv, u16 op, struct mtnic_pages pages) len = PAGE_SIZE * pages.num; pages.buf = (u32 *)umalloc(PAGE_SIZE * (pages.num + 1)); addr = PAGE_SIZE + ((virt_to_bus(pages.buf) & 0xfffff000) + PAGE_SIZE); - DBG("Mapping pages: size: %lx address: %p\n", pages.num, pages.buf); + DBG("Mapping pages: size: %x address: %p\n", pages.num, pages.buf); if (addr & (PAGE_MASK)) { DBG("Got FW area not aligned to %d (%llx/%x)\n", PAGE_SIZE, (u64) addr, len); - return MTNIC_ERROR; + return -EADDRINUSE; } /* Function maps each PAGE seperately */ for (j = 0; j < len; j+= PAGE_SIZE) { page_arr[nent * 4 + 3] = cpu_to_be32(addr + j); if (++nent == MTNIC_MAILBOX_SIZE / 16) { - err = mtnic_cmd(priv, NULL, NULL, nent, op); + err = mtnic_cmd(mtnic, NULL, NULL, nent, op); if (err) - return MTNIC_ERROR; - nent = 0; + return -EIO; + nent = 0; } } - if (nent) - err = mtnic_cmd(priv, NULL, NULL, nent, op); - + if (nent) { + err = mtnic_cmd(mtnic, NULL, NULL, nent, op); + } return err; } @@ -601,45 +584,44 @@ mtnic_map_cmd(struct mtnic_priv *priv, u16 op, struct mtnic_pages pages) * Query FW */ static int -mtnic_QUERY_FW(struct mtnic_priv *priv) +mtnic_QUERY_FW ( struct mtnic *mtnic ) { int err; - struct mtnic_if_query_fw_out_mbox *cmd = priv->cmd.buf; + struct mtnic_if_query_fw_out_mbox *cmd = mtnic->cmd.buf; - err = mtnic_cmd(priv, NULL, NULL, 0, MTNIC_IF_CMD_QUERY_FW); + err = mtnic_cmd(mtnic, NULL, NULL, 0, MTNIC_IF_CMD_QUERY_FW); if (err) - return MTNIC_ERROR; + return -EIO; /* Get FW and interface versions */ - priv->fw_ver = ((u64) be16_to_cpu(cmd->rev_maj) << 32) | - ((u64) be16_to_cpu(cmd->rev_min) << 16) | - (u64) be16_to_cpu(cmd->rev_smin); - priv->fw.ifc_rev = be16_to_cpu(cmd->ifc_rev); + mtnic->fw_ver = ((u64) be16_to_cpu(cmd->rev_maj) << 32) | + ((u64) be16_to_cpu(cmd->rev_min) << 16) | + (u64) be16_to_cpu(cmd->rev_smin); + mtnic->fw.ifc_rev = be16_to_cpu(cmd->ifc_rev); /* Get offset for internal error reports (debug) */ - priv->fw.err_buf.offset = be64_to_cpu(cmd->err_buf_start); - priv->fw.err_buf.size = be32_to_cpu(cmd->err_buf_size); + mtnic->fw.err_buf.offset = be64_to_cpu(cmd->err_buf_start); + mtnic->fw.err_buf.size = be32_to_cpu(cmd->err_buf_size); - DBG("Error buf offset is %llx\n", priv->fw.err_buf.offset); + DBG("Error buf offset is %llx\n", mtnic->fw.err_buf.offset); /* Get number of required FW (4k) pages */ - priv->fw.fw_pages.num = be16_to_cpu(cmd->fw_pages); + mtnic->fw.fw_pages.num = be16_to_cpu(cmd->fw_pages); return 0; } static int -mtnic_OPEN_NIC(struct mtnic_priv *priv) +mtnic_OPEN_NIC(struct mtnic *mtnic) { - - struct mtnic_if_open_nic_in_mbox *open_nic = priv->cmd.buf; + struct mtnic_if_open_nic_in_mbox *open_nic = mtnic->cmd.buf; u32 extra_pages[2] = {0}; int err; memset(open_nic, 0, sizeof *open_nic); - /* port 1 */ + /* port 1 */ open_nic->log_rx_p1 = 0; open_nic->log_cq_p1 = 1; @@ -655,46 +637,47 @@ mtnic_OPEN_NIC(struct mtnic_priv *priv) open_nic->steer_p2 = MTNIC_IF_STEER_RSS; /* MAC + VLAN - leave reserved */ - err = mtnic_cmd(priv, NULL, extra_pages, 0, MTNIC_IF_CMD_OPEN_NIC); - priv->fw.extra_pages.num = be32_to_cpu(*(extra_pages+1)); - DBG("Extra pages num is %lx\n", priv->fw.extra_pages.num); + err = mtnic_cmd(mtnic, NULL, extra_pages, 0, MTNIC_IF_CMD_OPEN_NIC); + + mtnic->fw.extra_pages.num = be32_to_cpu(*(extra_pages+1)); + DBG("Extra pages num is %x\n", mtnic->fw.extra_pages.num); return err; } static int -mtnic_CONFIG_RX(struct mtnic_priv *priv) +mtnic_CONFIG_RX(struct mtnic *mtnic) { struct mtnic_if_config_rx_in_imm config_rx; memset(&config_rx, 0, sizeof config_rx); - return mtnic_cmd(priv, &config_rx, NULL, 0, MTNIC_IF_CMD_CONFIG_RX); + return mtnic_cmd(mtnic, &config_rx, NULL, 0, MTNIC_IF_CMD_CONFIG_RX); } static int -mtnic_CONFIG_TX(struct mtnic_priv *priv) +mtnic_CONFIG_TX(struct mtnic *mtnic) { struct mtnic_if_config_send_in_imm config_tx; config_tx.enph_gpf = 0; - return mtnic_cmd(priv, &config_tx, NULL, 0, MTNIC_IF_CMD_CONFIG_TX); + return mtnic_cmd(mtnic, &config_tx, NULL, 0, MTNIC_IF_CMD_CONFIG_TX); } static int -mtnic_HEART_BEAT(struct mtnic_priv *priv, u32 *link_state) +mtnic_HEART_BEAT(struct mtnic_port *priv, u32 *link_state) { struct mtnic_if_heart_beat_out_imm heart_beat; int err; u32 flags; - err = mtnic_cmd(priv, NULL, &heart_beat, 0, MTNIC_IF_CMD_HEART_BEAT); + err = mtnic_cmd(priv->mtnic, NULL, &heart_beat, 0, MTNIC_IF_CMD_HEART_BEAT); if (!err) { flags = be32_to_cpu(heart_beat.flags); if (flags & MTNIC_BC_MASK(MTNIC_MASK_HEAR_BEAT_INT_ERROR)) { DBG("Internal error detected\n"); - return MTNIC_ERROR; + return -EIO; } *link_state = flags & - ~((u32) MTNIC_BC_MASK(MTNIC_MASK_HEAR_BEAT_INT_ERROR)); + ~((u32) MTNIC_BC_MASK(MTNIC_MASK_HEAR_BEAT_INT_ERROR)); } return err; } @@ -705,31 +688,31 @@ mtnic_HEART_BEAT(struct mtnic_priv *priv, u32 *link_state) */ static int -mtnic_SET_PORT_DEFAULT_RING(struct mtnic_priv *priv, u8 port, u16 ring) +mtnic_SET_PORT_DEFAULT_RING(struct mtnic_port *priv, u8 port, u16 ring) { struct mtnic_if_set_port_default_ring_in_imm def_ring; memset(&def_ring, 0, sizeof(def_ring)); def_ring.ring = ring; - return mtnic_cmd(priv, &def_ring, NULL, port + 1, + return mtnic_cmd(priv->mtnic, &def_ring, NULL, port + 1, MTNIC_IF_CMD_SET_PORT_DEFAULT_RING); } static int -mtnic_CONFIG_PORT_RSS_STEER(struct mtnic_priv *priv, int port) +mtnic_CONFIG_PORT_RSS_STEER(struct mtnic_port *priv, int port) { - memset(priv->cmd.buf, 0, PAGE_SIZE); - return mtnic_cmd(priv, NULL, NULL, port + 1, - MTNIC_IF_CMD_CONFIG_PORT_RSS_STEER); + memset(priv->mtnic->cmd.buf, 0, PAGE_SIZE); + return mtnic_cmd(priv->mtnic, NULL, NULL, port + 1, + MTNIC_IF_CMD_CONFIG_PORT_RSS_STEER); } static int -mtnic_SET_PORT_RSS_INDIRECTION(struct mtnic_priv *priv, int port) +mtnic_SET_PORT_RSS_INDIRECTION(struct mtnic_port *priv, int port) { - memset(priv->cmd.buf, 0, PAGE_SIZE); - return mtnic_cmd(priv, NULL, NULL, port + 1, - MTNIC_IF_CMD_SET_PORT_RSS_INDIRECTION); + memset(priv->mtnic->cmd.buf, 0, PAGE_SIZE); + return mtnic_cmd(priv->mtnic, NULL, NULL, port + 1, + MTNIC_IF_CMD_SET_PORT_RSS_INDIRECTION); } @@ -737,89 +720,89 @@ mtnic_SET_PORT_RSS_INDIRECTION(struct mtnic_priv *priv, int port) * Config commands */ static int -mtnic_CONFIG_CQ(struct mtnic_priv *priv, int port, - u16 cq_ind, struct mtnic_cq *cq) +mtnic_CONFIG_CQ(struct mtnic_port *priv, int port, + u16 cq_ind, struct mtnic_cq *cq) { - struct mtnic_if_config_cq_in_mbox *config_cq = priv->cmd.buf; + struct mtnic_if_config_cq_in_mbox *config_cq = priv->mtnic->cmd.buf; memset(config_cq, 0, sizeof *config_cq); config_cq->cq = cq_ind; config_cq->size = fls(UNITS_BUFFER_SIZE - 1); config_cq->offset = ((cq->dma) & (PAGE_MASK)) >> 6; config_cq->db_record_addr_l = cpu_to_be32(cq->db_dma); - config_cq->page_address[1] = cpu_to_be32(cq->dma); - DBG("config cq address: %lx dma_address: %lx" - "offset: %d size %d index: %d " + config_cq->page_address[1] = cpu_to_be32(cq->dma); + DBG("config cq address: %x dma_address: %lx" + "offset: %d size %d index: %d\n" , config_cq->page_address[1],cq->dma, config_cq->offset, config_cq->size, config_cq->cq ); - return mtnic_cmd(priv, NULL, NULL, port + 1, - MTNIC_IF_CMD_CONFIG_CQ); + return mtnic_cmd(priv->mtnic, NULL, NULL, port + 1, + MTNIC_IF_CMD_CONFIG_CQ); } static int -mtnic_CONFIG_TX_RING(struct mtnic_priv *priv, u8 port, - u16 ring_ind, struct mtnic_ring *ring) +mtnic_CONFIG_TX_RING(struct mtnic_port *priv, u8 port, + u16 ring_ind, struct mtnic_ring *ring) { - struct mtnic_if_config_send_ring_in_mbox *config_tx_ring = priv->cmd.buf; + struct mtnic_if_config_send_ring_in_mbox *config_tx_ring = priv->mtnic->cmd.buf; memset(config_tx_ring, 0, sizeof *config_tx_ring); config_tx_ring->ring = cpu_to_be16(ring_ind); config_tx_ring->size = fls(UNITS_BUFFER_SIZE - 1); config_tx_ring->cq = cpu_to_be16(ring->cq); config_tx_ring->page_address[1] = cpu_to_be32(ring->dma); - return mtnic_cmd(priv, NULL, NULL, port + 1, + return mtnic_cmd(priv->mtnic, NULL, NULL, port + 1, MTNIC_IF_CMD_CONFIG_TX_RING); } static int -mtnic_CONFIG_RX_RING(struct mtnic_priv *priv, u8 port, - u16 ring_ind, struct mtnic_ring *ring) +mtnic_CONFIG_RX_RING(struct mtnic_port *priv, u8 port, + u16 ring_ind, struct mtnic_ring *ring) { - struct mtnic_if_config_rx_ring_in_mbox *config_rx_ring = priv->cmd.buf; + struct mtnic_if_config_rx_ring_in_mbox *config_rx_ring = priv->mtnic->cmd.buf; memset(config_rx_ring, 0, sizeof *config_rx_ring); config_rx_ring->ring = ring_ind; - MTNIC_BC_PUT(config_rx_ring->stride_size, fls(UNITS_BUFFER_SIZE - 1), - MTNIC_MASK_CONFIG_RX_RING_SIZE); - MTNIC_BC_PUT(config_rx_ring->stride_size, 1, - MTNIC_MASK_CONFIG_RX_RING_STRIDE); + MTNIC_BC_PUT(config_rx_ring->stride_size, fls(UNITS_BUFFER_SIZE - 1), + MTNIC_MASK_CONFIG_RX_RING_SIZE); + MTNIC_BC_PUT(config_rx_ring->stride_size, 1, + MTNIC_MASK_CONFIG_RX_RING_STRIDE); config_rx_ring->cq = cpu_to_be16(ring->cq); config_rx_ring->db_record_addr_l = cpu_to_be32(ring->db_dma); - DBG("Config RX ring starting at address:%lx\n", ring->dma); + DBG("Config RX ring starting at address:%lx\n", ring->dma); config_rx_ring->page_address[1] = cpu_to_be32(ring->dma); - return mtnic_cmd(priv, NULL, NULL, port + 1, - MTNIC_IF_CMD_CONFIG_RX_RING); + return mtnic_cmd(priv->mtnic, NULL, NULL, port + 1, + MTNIC_IF_CMD_CONFIG_RX_RING); } static int -mtnic_CONFIG_EQ(struct mtnic_priv *priv) +mtnic_CONFIG_EQ(struct mtnic *mtnic) { - struct mtnic_if_config_eq_in_mbox *eq = priv->cmd.buf; + struct mtnic_if_config_eq_in_mbox *eq = mtnic->cmd.buf; - if (priv->eq.dma & (PAGE_MASK)) { + if (mtnic->eq.dma & (PAGE_MASK)) { DBG("misalligned eq buffer:%lx\n", - priv->eq.dma); - return MTNIC_ERROR; - } + mtnic->eq.dma); + return -EADDRINUSE; + } - memset(eq, 0, sizeof *eq); - MTNIC_BC_PUT(eq->offset, priv->eq.dma >> 6, MTNIC_MASK_CONFIG_EQ_OFFSET); - MTNIC_BC_PUT(eq->size, fls(priv->eq.size - 1) - 1, MTNIC_MASK_CONFIG_EQ_SIZE); + memset(eq, 0, sizeof *eq); + MTNIC_BC_PUT(eq->offset, mtnic->eq.dma >> 6, MTNIC_MASK_CONFIG_EQ_OFFSET); + MTNIC_BC_PUT(eq->size, fls(mtnic->eq.size - 1) - 1, MTNIC_MASK_CONFIG_EQ_SIZE); MTNIC_BC_PUT(eq->int_vector, 0, MTNIC_MASK_CONFIG_EQ_INT_VEC); - eq->page_address[1] = cpu_to_be32(priv->eq.dma); + eq->page_address[1] = cpu_to_be32(mtnic->eq.dma); - return mtnic_cmd(priv, NULL, NULL, 0, MTNIC_IF_CMD_CONFIG_EQ); + return mtnic_cmd(mtnic, NULL, NULL, 0, MTNIC_IF_CMD_CONFIG_EQ); } static int -mtnic_SET_RX_RING_ADDR(struct mtnic_priv *priv, u8 port, u64* mac) +mtnic_SET_RX_RING_ADDR(struct mtnic_port *priv, u8 port, u64* mac) { struct mtnic_if_set_rx_ring_addr_in_imm ring_addr; u32 modifier = ((u32) port + 1) << 16; @@ -829,63 +812,64 @@ mtnic_SET_RX_RING_ADDR(struct mtnic_priv *priv, u8 port, u64* mac) ring_addr.mac_31_0 = cpu_to_be32(*mac & 0xffffffff); ring_addr.mac_47_32 = cpu_to_be16((*mac >> 32) & 0xffff); ring_addr.flags_vlan_id |= cpu_to_be16( - MTNIC_BC_MASK(MTNIC_MASK_SET_RX_RING_ADDR_BY_MAC)); + MTNIC_BC_MASK(MTNIC_MASK_SET_RX_RING_ADDR_BY_MAC)); - return mtnic_cmd(priv, &ring_addr, NULL, modifier, MTNIC_IF_CMD_SET_RX_RING_ADDR); + return mtnic_cmd(priv->mtnic, &ring_addr, NULL, modifier, MTNIC_IF_CMD_SET_RX_RING_ADDR); } static int -mtnic_SET_PORT_STATE(struct mtnic_priv *priv, u8 port, u8 state) +mtnic_SET_PORT_STATE(struct mtnic_port *priv, u8 port, u8 state) { struct mtnic_if_set_port_state_in_imm port_state; port_state.state = state ? cpu_to_be32( - MTNIC_BC_MASK(MTNIC_MASK_CONFIG_PORT_STATE)) : 0; + MTNIC_BC_MASK(MTNIC_MASK_CONFIG_PORT_STATE)) : 0; port_state.reserved = 0; - return mtnic_cmd(priv, &port_state, NULL, port + 1, + return mtnic_cmd(priv->mtnic, &port_state, NULL, port + 1, MTNIC_IF_CMD_SET_PORT_STATE); } static int -mtnic_SET_PORT_MTU(struct mtnic_priv *priv, u8 port, u16 mtu) +mtnic_SET_PORT_MTU(struct mtnic_port *priv, u8 port, u16 mtu) { struct mtnic_if_set_port_mtu_in_imm set_mtu; memset(&set_mtu, 0, sizeof(set_mtu)); set_mtu.mtu = cpu_to_be16(mtu); - return mtnic_cmd(priv, &set_mtu, NULL, port + 1, - MTNIC_IF_CMD_SET_PORT_MTU); + return mtnic_cmd(priv->mtnic, &set_mtu, NULL, port + 1, + MTNIC_IF_CMD_SET_PORT_MTU); } - +/* static int -mtnic_CONFIG_PORT_VLAN_FILTER(struct mtnic_priv *priv, int port) +mtnic_CONFIG_PORT_VLAN_FILTER(struct mtnic_port *priv, int port) { - struct mtnic_if_config_port_vlan_filter_in_mbox *vlan_filter = priv->cmd.buf; + struct mtnic_if_config_port_vlan_filter_in_mbox *vlan_filter = priv->mtnic->cmd.buf; - /* When no vlans are configured we disable the filter - * (i.e., pass all vlans) because we ignore them anyhow */ + // When no vlans are configured we disable the filter + // (i.e., pass all vlans) because we ignore them anyhow memset(vlan_filter, 0xff, sizeof(*vlan_filter)); - return mtnic_cmd(priv, NULL, NULL, port + 1, - MTNIC_IF_CMD_CONFIG_PORT_VLAN_FILTER); + return mtnic_cmd(priv->mtnic, NULL, NULL, port + 1, + MTNIC_IF_CMD_CONFIG_PORT_VLAN_FILTER); } +*/ static int -mtnic_RELEASE_RESOURCE(struct mtnic_priv *priv, u8 port, u8 type, u8 index) +mtnic_RELEASE_RESOURCE(struct mtnic_port *priv, u8 port, u8 type, u8 index) { struct mtnic_if_release_resource_in_imm rel; memset(&rel, 0, sizeof rel); rel.index = index; rel.type = type; - return mtnic_cmd(priv, - &rel, NULL, (type == MTNIC_IF_RESOURCE_TYPE_EQ) ? - 0 : port + 1, MTNIC_IF_CMD_RELEASE_RESOURCE); + return mtnic_cmd ( priv->mtnic, + &rel, NULL, ( type == MTNIC_IF_RESOURCE_TYPE_EQ ) ? + 0 : port + 1, MTNIC_IF_CMD_RELEASE_RESOURCE ); } static int -mtnic_QUERY_CAP(struct mtnic_priv *priv, u8 index, u8 mod, u64 *result) +mtnic_QUERY_CAP(struct mtnic *mtnic, u8 index, u8 mod, u64 *result) { struct mtnic_if_query_cap_in_imm cap; u32 out_imm[2]; @@ -894,7 +878,7 @@ mtnic_QUERY_CAP(struct mtnic_priv *priv, u8 index, u8 mod, u64 *result) memset(&cap, 0, sizeof cap); cap.cap_index = index; cap.cap_modifier = mod; - err = mtnic_cmd(priv, &cap, &out_imm, 0, MTNIC_IF_CMD_QUERY_CAP); + err = mtnic_cmd(mtnic, &cap, &out_imm, 0, MTNIC_IF_CMD_QUERY_CAP); *((u32*)result) = be32_to_cpu(*(out_imm+1)); *((u32*)result + 1) = be32_to_cpu(*out_imm); @@ -906,28 +890,38 @@ mtnic_QUERY_CAP(struct mtnic_priv *priv, u8 index, u8 mod, u64 *result) #define DO_QUERY_CAP(cap, mod, var) \ - err = mtnic_QUERY_CAP(priv, cap, mod, &result); \ + err = mtnic_QUERY_CAP(mtnic, cap, mod, &result);\ if (err) \ return err; \ (var) = result static int -mtnic_query_cap(struct mtnic_priv *priv) +mtnic_query_num_ports(struct mtnic *mtnic) +{ + int err = 0; + u64 result; + + DO_QUERY_CAP(MTNIC_IF_CAP_NUM_PORTS, 0, mtnic->fw.num_ports); + + return 0; +} + +static int +mtnic_query_mac(struct mtnic *mtnic) { int err = 0; int i; - u64 result; + u64 result; - DO_QUERY_CAP(MTNIC_IF_CAP_NUM_PORTS, 0, priv->fw.num_ports); - for (i = 0; i < priv->fw.num_ports; i++) { - DO_QUERY_CAP(MTNIC_IF_CAP_DEFAULT_MAC, i + 1, priv->fw.mac[i]); + for (i = 0; i < mtnic->fw.num_ports; i++) { + DO_QUERY_CAP(MTNIC_IF_CAP_DEFAULT_MAC, i + 1, mtnic->fw.mac[i]); } return 0; } static int -mtnic_query_offsets(struct mtnic_priv *priv) +mtnic_query_offsets(struct mtnic *mtnic) { int err; int i; @@ -935,18 +929,18 @@ mtnic_query_offsets(struct mtnic_priv *priv) DO_QUERY_CAP(MTNIC_IF_CAP_MEM_KEY, MTNIC_IF_MEM_TYPE_SNOOP, - priv->fw.mem_type_snoop_be); - priv->fw.mem_type_snoop_be = cpu_to_be32(priv->fw.mem_type_snoop_be); - DO_QUERY_CAP(MTNIC_IF_CAP_TX_CQ_DB_OFFSET, 0, priv->fw.txcq_db_offset); - DO_QUERY_CAP(MTNIC_IF_CAP_EQ_DB_OFFSET, 0, priv->fw.eq_db_offset); + mtnic->fw.mem_type_snoop_be); + mtnic->fw.mem_type_snoop_be = cpu_to_be32(mtnic->fw.mem_type_snoop_be); + DO_QUERY_CAP(MTNIC_IF_CAP_TX_CQ_DB_OFFSET, 0, mtnic->fw.txcq_db_offset); + DO_QUERY_CAP(MTNIC_IF_CAP_EQ_DB_OFFSET, 0, mtnic->fw.eq_db_offset); - for (i = 0; i < priv->fw.num_ports; i++) { - DO_QUERY_CAP(MTNIC_IF_CAP_CQ_OFFSET, i + 1, priv->fw.cq_offset); - DO_QUERY_CAP(MTNIC_IF_CAP_TX_OFFSET, i + 1, priv->fw.tx_offset[i]); - DO_QUERY_CAP(MTNIC_IF_CAP_RX_OFFSET, i + 1, priv->fw.rx_offset[i]); - DBG("--> Port %d CQ offset:0x%x\n", i, priv->fw.cq_offset); - DBG("--> Port %d Tx offset:0x%x\n", i, priv->fw.tx_offset[i]); - DBG("--> Port %d Rx offset:0x%x\n", i, priv->fw.rx_offset[i]); + for (i = 0; i < mtnic->fw.num_ports; i++) { + DO_QUERY_CAP(MTNIC_IF_CAP_CQ_OFFSET, i + 1, mtnic->fw.cq_offset); + DO_QUERY_CAP(MTNIC_IF_CAP_TX_OFFSET, i + 1, mtnic->fw.tx_offset[i]); + DO_QUERY_CAP(MTNIC_IF_CAP_RX_OFFSET, i + 1, mtnic->fw.rx_offset[i]); + DBG("--> Port %d CQ offset:0x%x\n", i, mtnic->fw.cq_offset); + DBG("--> Port %d Tx offset:0x%x\n", i, mtnic->fw.tx_offset[i]); + DBG("--> Port %d Rx offset:0x%x\n", i, mtnic->fw.rx_offset[i]); } mdelay(20); @@ -976,11 +970,12 @@ mtnic_query_offsets(struct mtnic_priv *priv) * Reset device */ void -mtnic_reset(void) +mtnic_reset ( void ) { - void *reset = ioremap(mtnic_pci_dev.dev.bar[0] + MTNIC_RESET_OFFSET, 4); - writel(cpu_to_be32(1), reset); - iounmap(reset); + void *reset = ioremap ( mtnic_pci_dev.dev.bar[0] + MTNIC_RESET_OFFSET, + 4 ); + writel ( cpu_to_be32 ( 1 ), reset ); + iounmap ( reset ); } @@ -1018,18 +1013,18 @@ mtnic_init_pci(struct pci_device *dev) int err; /* save bars */ - DBG("bus=%d devfn=0x%x", dev->bus, dev->devfn); + DBG("bus=%d devfn=0x%x\n", dev->bus, dev->devfn); for (i = 0; i < 6; ++i) { mtnic_pci_dev.dev.bar[i] = - pci_bar_start(dev, PCI_BASE_ADDRESS_0 + (i << 2)); + pci_bar_start(dev, PCI_BASE_ADDRESS_0 + (i << 2)); DBG("bar[%d]= 0x%08lx \n", i, mtnic_pci_dev.dev.bar[i]); } /* save config space */ for (i = 0; i < 64; ++i) { err = pci_read_config_dword(dev, i << 2, - &mtnic_pci_dev.dev. - dev_config_space[i]); + &mtnic_pci_dev.dev. + dev_config_space[i]); if (err) { DBG("Can not save configuration space"); return err; @@ -1038,144 +1033,140 @@ mtnic_init_pci(struct pci_device *dev) mtnic_pci_dev.dev.dev = dev; - return 0; + return 0; } /** * Initial hardware */ static inline -int mtnic_init_card(struct net_device *dev) +int mtnic_init_card(struct mtnic *mtnic) { - struct mtnic_priv *priv = netdev_priv(dev); int err = 0; - /* Set state */ - priv->state = CARD_DOWN; - /* Set port */ - priv->port = MTNIC_PORT_NUM; - - /* Alloc command interface */ - err = mtnic_alloc_cmdif(priv); + /* Alloc command interface */ + err = mtnic_alloc_cmdif ( mtnic ); if (err) { - DBG("Failed to init command interface, aborting.\n"); - return MTNIC_ERROR; + DBG("Failed to init command interface, aborting\n"); + return -EADDRINUSE; } - - /** - * Bring up HW - */ - err = mtnic_QUERY_FW(priv); + /** + * Bring up HW + */ + err = mtnic_QUERY_FW ( mtnic ); if (err) { - DBG("QUERY_FW command failed, aborting.\n"); + DBG("QUERY_FW command failed, aborting\n"); goto cmd_error; } - - DBG("Command interface revision:%d\n", priv->fw.ifc_rev); + DBG("Command interface revision:%d\n", mtnic->fw.ifc_rev); /* Allocate memory for FW and start it */ - err = mtnic_map_cmd(priv, MTNIC_IF_CMD_MAP_FW, priv->fw.fw_pages); + err = mtnic_map_cmd(mtnic, MTNIC_IF_CMD_MAP_FW, mtnic->fw.fw_pages); if (err) { DBG("Eror In MAP_FW\n"); - if (priv->fw.fw_pages.buf) - free(priv->fw.fw_pages.buf); + if (mtnic->fw.fw_pages.buf) + ufree((intptr_t)mtnic->fw.fw_pages.buf); goto cmd_error; } /* Run firmware */ - err = mtnic_cmd(priv, NULL, NULL, 0, MTNIC_IF_CMD_RUN_FW); + err = mtnic_cmd(mtnic, NULL, NULL, 0, MTNIC_IF_CMD_RUN_FW); if (err) { DBG("Eror In RUN FW\n"); goto map_fw_error; } - DBG("FW version:%d.%d.%d\n", - (u16) (priv->fw_ver >> 32), - (u16) ((priv->fw_ver >> 16) & 0xffff), - (u16) (priv->fw_ver & 0xffff)); + DBG("FW version:%d.%d.%d\n", + (u16) (mtnic->fw_ver >> 32), + (u16) ((mtnic->fw_ver >> 16) & 0xffff), + (u16) (mtnic->fw_ver & 0xffff)); - /* Get device information */ - err = mtnic_query_cap(priv); + /* Query num ports */ + err = mtnic_query_num_ports(mtnic); if (err) { - DBG("Insufficient resources, aborting.\n"); + DBG("Insufficient resources, aborting\n"); goto map_fw_error; } /* Open NIC */ - err = mtnic_OPEN_NIC(priv); + err = mtnic_OPEN_NIC(mtnic); if (err) { - DBG("Failed opening NIC, aborting.\n"); + DBG("Failed opening NIC, aborting\n"); goto map_fw_error; } /* Allocate and map pages worksace */ - err = mtnic_map_cmd(priv, MTNIC_IF_CMD_MAP_PAGES, priv->fw.extra_pages); + err = mtnic_map_cmd(mtnic, MTNIC_IF_CMD_MAP_PAGES, mtnic->fw.extra_pages); + if (err) { + DBG("Couldn't allocate %x FW extra pages, aborting\n", + mtnic->fw.extra_pages.num); + if (mtnic->fw.extra_pages.buf) + ufree((intptr_t)mtnic->fw.extra_pages.buf); + goto map_fw_error; + } + + + /* Get device information */ + err = mtnic_query_mac(mtnic); if (err) { - DBG("Couldn't allocate %lx FW extra pages, aborting.\n", - priv->fw.extra_pages.num); - if (priv->fw.extra_pages.buf) - free(priv->fw.extra_pages.buf); + DBG("Insufficient resources in quesry mac, aborting\n"); goto map_fw_error; } /* Get device offsets */ - err = mtnic_query_offsets(priv); + err = mtnic_query_offsets(mtnic); if (err) { - DBG("Failed retrieving resource offests, aborting.\n"); - free(priv->fw.extra_pages.buf); + DBG("Failed retrieving resource offests, aborting\n"); + ufree((intptr_t)mtnic->fw.extra_pages.buf); goto map_extra_error; } - /* Alloc EQ */ - err = mtnic_alloc_eq(priv); + /* Alloc EQ */ + err = mtnic_alloc_eq(mtnic); if (err) { DBG("Failed init shared resources. error: %d\n", err); goto map_extra_error; - } + } /* Configure HW */ - err = mtnic_CONFIG_EQ(priv); + err = mtnic_CONFIG_EQ(mtnic); if (err) { DBG("Failed configuring EQ\n"); goto eq_error; } - err = mtnic_CONFIG_RX(priv); + err = mtnic_CONFIG_RX(mtnic); if (err) { DBG("Failed Rx configuration\n"); goto eq_error; } - err = mtnic_CONFIG_TX(priv); + err = mtnic_CONFIG_TX(mtnic); if (err) { DBG("Failed Tx configuration\n"); goto eq_error; } - DBG("Activating port:%d\n", MTNIC_PORT_NUM + 1); - - priv->state = CARD_INITIALIZED; return 0; eq_error: - iounmap(priv->eq_db); - free(priv->eq.buf); + iounmap(mtnic->eq_db); + free_memblock(mtnic->eq.buf, mtnic->eq.buf_size); map_extra_error: - free(priv->fw.extra_pages.buf); + ufree((intptr_t)mtnic->fw.extra_pages.buf); map_fw_error: - free(priv->fw.fw_pages.buf); + ufree((intptr_t)mtnic->fw.fw_pages.buf); cmd_error: - iounmap(priv->hcr); - free(priv->cmd.buf); - free(priv); + iounmap(mtnic->hcr); + free_memblock(mtnic->cmd.buf, PAGE_SIZE); - return MTNIC_ERROR; + return -EADDRINUSE; } @@ -1195,7 +1186,7 @@ cmd_error: * * ********************************************************************/ -void mtnic_process_tx_cq(struct mtnic_priv *priv, struct net_device *dev, +void mtnic_process_tx_cq(struct mtnic_port *priv, struct net_device *dev, struct mtnic_cq *cq) { struct mtnic_cqe *cqe = cq->buf; @@ -1209,10 +1200,10 @@ void mtnic_process_tx_cq(struct mtnic_priv *priv, struct net_device *dev, /* Owner bit changes every round */ while (XNOR(cqe->op_tr_own & MTNIC_BIT_CQ_OWN, cq->last & cq->size)) { netdev_tx_complete (dev, ring->iobuf[index]); - ++cq->last; - index = cq->last & (cq->size-1); + ++cq->last; + index = cq->last & (cq->size-1); cqe = &cq->buf[index]; - } + } /* Update consumer index */ cq->db->update_ci = cpu_to_be32(cq->last & 0xffffff); @@ -1221,13 +1212,16 @@ void mtnic_process_tx_cq(struct mtnic_priv *priv, struct net_device *dev, } -int mtnic_process_rx_cq(struct mtnic_priv *priv, struct net_device *dev, struct mtnic_cq *cq) +int mtnic_process_rx_cq(struct mtnic_port *priv, + struct net_device *dev, + struct mtnic_cq *cq) { struct mtnic_cqe *cqe; struct mtnic_ring *ring = &priv->rx_ring; int index; int err; struct io_buffer *rx_iob; + unsigned int length; /* We assume a 1:1 mapping between CQEs and Rx descriptors, so Rx @@ -1253,16 +1247,21 @@ int mtnic_process_rx_cq(struct mtnic_priv *priv, struct net_device *dev, struct /* * Packet is OK - process it. */ - rx_iob = ring->iobuf[index]; - iob_put(rx_iob, DEF_IOBUF_SIZE); + length = be32_to_cpu(cqe->byte_cnt); + rx_iob = ring->iobuf[index]; + iob_put(rx_iob, length); + /* Add this packet to the receive queue. */ netdev_rx(dev, rx_iob); - ring->iobuf[index] = NULL; + ring->iobuf[index] = NULL; next: ++cq->last; index = cq->last & (cq->size-1); cqe = &cq->buf[index]; + + + } /* Update consumer index */ @@ -1274,7 +1273,7 @@ next: err = mtnic_alloc_iobuf(priv, &priv->rx_ring, DEF_IOBUF_SIZE); if (err) { DBG("ERROR Allocating io buffer"); - return MTNIC_ERROR; + return -EADDRINUSE; } } @@ -1307,24 +1306,27 @@ next: static int mtnic_open(struct net_device *dev) { - struct mtnic_priv *priv = netdev_priv(dev); + struct mtnic_port *priv = netdev_priv(dev); + int err = 0; struct mtnic_ring *ring; struct mtnic_cq *cq; int cq_ind = 0; u32 dev_link_state; + int link_check; - DBG("starting port:%d", priv->port); + DBG("starting port:%d, MAC Address: 0x%12llx\n", + priv->port, priv->mtnic->fw.mac[priv->port]); /* Alloc and configure CQs, TX, RX */ - err = mtnic_alloc_resources(dev); + err = mtnic_alloc_resources ( dev ); if (err) { DBG("Error allocating resources\n"); - return MTNIC_ERROR; + return -EADDRINUSE; } /* Pass CQs configuration to HW */ - for (cq_ind = 0; cq_ind < NUM_CQS; ++cq_ind) { + for (cq_ind = 0; cq_ind < NUM_CQS; ++cq_ind) { cq = &priv->cq[cq_ind]; err = mtnic_CONFIG_CQ(priv, priv->port, cq_ind, cq); if (err) { @@ -1333,24 +1335,25 @@ mtnic_open(struct net_device *dev) if (cq_ind) goto cq_error; else - return MTNIC_ERROR; - } + goto allocation_error; + } /* Update consumer index */ cq->db->update_ci = cpu_to_be32(cq->last & 0xffffff); } + /* Pass Tx configuration to HW */ ring = &priv->tx_ring; - err = mtnic_CONFIG_TX_RING(priv, priv->port, 0, ring); + err = mtnic_CONFIG_TX_RING(priv, priv->port, 0, ring); if (err) { DBG("Failed configuring Tx ring:0\n"); - goto cq_error; + goto cq_error; } /* Pass RX configuration to HW */ - ring = &priv->rx_ring; - err = mtnic_CONFIG_RX_RING(priv, priv->port, 0, ring); + ring = &priv->rx_ring; + err = mtnic_CONFIG_RX_RING(priv, priv->port, 0, ring); if (err) { DBG("Failed configuring Rx ring:0\n"); goto tx_error; @@ -1365,6 +1368,7 @@ mtnic_open(struct net_device *dev) goto rx_error; } + /* Set the port default ring to ring 0 */ err = mtnic_SET_PORT_DEFAULT_RING(priv, priv->port, 0); if (err) { @@ -1373,7 +1377,7 @@ mtnic_open(struct net_device *dev) } /* Set Mac address */ - err = mtnic_SET_RX_RING_ADDR(priv, priv->port, &priv->fw.mac[priv->port]); + err = mtnic_SET_RX_RING_ADDR(priv, priv->port, &priv->mtnic->fw.mac[priv->port]); if (err) { DBG("Failed setting default MAC address\n"); goto rx_error; @@ -1387,11 +1391,14 @@ mtnic_open(struct net_device *dev) } /* Configure VLAN filter */ + /* By adding this function, The second port won't accept packets err = mtnic_CONFIG_PORT_VLAN_FILTER(priv, priv->port); - if (err) { + if (err) { DBG("Failed configuring VLAN filter\n"); goto rx_error; } + */ + /* Bring up physical link */ err = mtnic_SET_PORT_STATE(priv, priv->port, 1); @@ -1399,29 +1406,52 @@ mtnic_open(struct net_device *dev) DBG("Failed bringing up port\n"); goto rx_error; } - mdelay(300); /* Let link state stabilize if cable was connected */ + /* PORT IS UP */ priv->state = CARD_UP; - err = mtnic_HEART_BEAT(priv, &dev_link_state); - if (err) { - DBG("Failed getting device link state\n"); - return MTNIC_ERROR; + + /* Checking Link is up */ + DBG ( "Checking if link is up\n" ); + + + for ( link_check = 0; link_check < CHECK_LINK_TIMES; link_check ++ ) { + /* Let link state stabilize if cable was connected */ + mdelay ( DELAY_LINK_CHECK ); + + err = mtnic_HEART_BEAT(priv, &dev_link_state); + if (err) { + DBG("Failed getting device link state\n"); + return -ENETDOWN; + } + + if ( dev_link_state & priv->port ) { + /* Link is up */ + break; + } } - if (!(dev_link_state & 0x3)) { + + + if ( ! ( dev_link_state & 0x3 ) ) { DBG("Link down, check cables and restart\n"); - return MTNIC_ERROR; + netdev_link_down ( dev ); + return -ENETDOWN; } - return 0; + DBG ( "Link is up!\n" ); + /* Mark as link up */ + netdev_link_up ( dev ); + + return 0; rx_error: err = mtnic_RELEASE_RESOURCE(priv, priv->port, - MTNIC_IF_RESOURCE_TYPE_RX_RING, 0); + MTNIC_IF_RESOURCE_TYPE_RX_RING, 0); tx_error: err |= mtnic_RELEASE_RESOURCE(priv, priv->port, MTNIC_IF_RESOURCE_TYPE_TX_RING, 0); + cq_error: while (cq_ind) { err |= mtnic_RELEASE_RESOURCE(priv, priv->port, @@ -1430,66 +1460,81 @@ cq_error: if (err) DBG("Eror Releasing resources\n"); - return MTNIC_ERROR; +allocation_error: + + free_memblock(priv->tx_ring.buf, priv->tx_ring.buf_size); + iounmap(priv->tx_ring.txcq_db); + free_memblock(priv->cq[1].buf, priv->cq[1].buf_size); + free_memblock(priv->cq[1].db, sizeof(struct mtnic_cq_db_record)); + free_memblock(priv->rx_ring.buf, priv->rx_ring.buf_size); + free_memblock(priv->rx_ring.db, sizeof(struct mtnic_cq_db_record)); + free_memblock(priv->cq[0].buf, priv->cq[0].buf_size); + free_memblock(priv->cq[0].db, sizeof(struct mtnic_cq_db_record)); + + mtnic_free_io_buffers(&priv->rx_ring); + + return -ENETDOWN; } + /** Check if we got completion for receive and transmit and * check the line with heart_bit command */ static void -mtnic_poll(struct net_device *dev) +mtnic_poll ( struct net_device *dev ) { - struct mtnic_priv *priv = netdev_priv(dev); + struct mtnic_port *priv = netdev_priv(dev); struct mtnic_cq *cq; u32 dev_link_state; int err; unsigned int i; - /* In case of an old error then return */ + /* In case of an old error then return */ if (priv->state != CARD_UP) return; /* We do not check the device every call _poll call, - since it will slow it down */ + since it will slow it down */ if ((priv->poll_counter % ROUND_TO_CHECK) == 0) { /* Check device */ err = mtnic_HEART_BEAT(priv, &dev_link_state); if (err) { DBG("Device has internal error\n"); - priv->state = CARD_DOWN; + priv->state = CARD_LINK_DOWN; return; } if (!(dev_link_state & 0x3)) { DBG("Link down, check cables and restart\n"); - priv->state = CARD_DOWN; + priv->state = CARD_LINK_DOWN; return; } } - /* Polling CQ */ for (i = 0; i < NUM_CQS; i++) { cq = &priv->cq[i]; //Passing on the 2 cqs. if (cq->is_rx) { - err = mtnic_process_rx_cq(priv, cq->dev, cq); + err = mtnic_process_rx_cq(priv, cq->dev, cq); if (err) { - priv->state = CARD_DOWN; + priv->state = CARD_LINK_DOWN; DBG(" Error allocating RX buffers\n"); return; } - } else { - mtnic_process_tx_cq(priv, cq->dev, cq); + } else { + mtnic_process_tx_cq(priv, cq->dev, cq); } } ++ priv->poll_counter; } + + static int mtnic_transmit( struct net_device *dev, struct io_buffer *iobuf ) { - struct mtnic_priv *priv = netdev_priv(dev); + struct mtnic_port *priv = netdev_priv(dev); struct mtnic_ring *ring; struct mtnic_tx_desc *tx_desc; struct mtnic_data_seg *data; @@ -1497,34 +1542,34 @@ mtnic_transmit( struct net_device *dev, struct io_buffer *iobuf ) /* In case of an error then return */ if (priv->state != CARD_UP) - return MTNIC_ERROR; + return -ENETDOWN; ring = &priv->tx_ring; - index = ring->prod & ring->size_mask; + index = ring->prod & ring->size_mask; if ((ring->prod - ring->cons) >= ring->size) { - DBG("No space left for descriptors!!! cons: %lx prod: %lx\n", + DBG("No space left for descriptors!!! cons: %x prod: %x\n", ring->cons, ring->prod); mdelay(5); - return MTNIC_ERROR;/* no space left */ + return -EAGAIN;/* no space left */ } - /* get current descriptor */ + /* get current descriptor */ tx_desc = ring->buf + (index * sizeof(struct mtnic_tx_desc)); - /* Prepare ctrl segement */ - tx_desc->ctrl.size_vlan = cpu_to_be32(2); - tx_desc->ctrl.flags = cpu_to_be32(MTNIC_BIT_TX_COMP | - MTNIC_BIT_NO_ICRC); - tx_desc->ctrl.op_own = cpu_to_be32(MTNIC_OPCODE_SEND) | - ((ring->prod & ring->size) ? - cpu_to_be32(MTNIC_BIT_DESC_OWN) : 0); - /* Prepare Data Seg */ data = &tx_desc->data; data->addr_l = cpu_to_be32((u32)virt_to_bus(iobuf->data)); data->count = cpu_to_be32(iob_len(iobuf)); - data->mem_type = priv->fw.mem_type_snoop_be; + data->mem_type = priv->mtnic->fw.mem_type_snoop_be; + + /* Prepare ctrl segement */ + tx_desc->ctrl.size_vlan = cpu_to_be32(2); + tx_desc->ctrl.flags = cpu_to_be32(MTNIC_BIT_TX_COMP | + MTNIC_BIT_NO_ICRC); + tx_desc->ctrl.op_own = cpu_to_be32(MTNIC_OPCODE_SEND) | + ((ring->prod & ring->size) ? + cpu_to_be32(MTNIC_BIT_DESC_OWN) : 0); /* Attach io_buffer */ ring->iobuf[index] = iobuf; @@ -1543,11 +1588,13 @@ mtnic_transmit( struct net_device *dev, struct io_buffer *iobuf ) static void mtnic_close(struct net_device *dev) { - struct mtnic_priv *priv = netdev_priv(dev); + struct mtnic_port *priv = netdev_priv(dev); int err = 0; DBG("Close called for port:%d\n", priv->port); - if (priv->state == CARD_UP) { + if ( ( priv->state == CARD_UP ) || + ( priv->state == CARD_LINK_DOWN ) ) { + /* Disable port */ err |= mtnic_SET_PORT_STATE(priv, priv->port, 0); /* @@ -1565,31 +1612,33 @@ mtnic_close(struct net_device *dev) /* Stop CQs */ err |= mtnic_RELEASE_RESOURCE(priv, priv->port, - MTNIC_IF_RESOURCE_TYPE_CQ, 0); + MTNIC_IF_RESOURCE_TYPE_CQ, 0); err |= mtnic_RELEASE_RESOURCE(priv, priv->port, - MTNIC_IF_RESOURCE_TYPE_CQ, 1); + MTNIC_IF_RESOURCE_TYPE_CQ, 1); if (err) { - DBG("Close reported error %d", err); + DBG("Close reported error %d\n", err); } - /* Free memory */ - free(priv->tx_ring.buf); + mdelay ( 10 ); + + /* free memory */ + free_memblock(priv->tx_ring.buf, priv->tx_ring.buf_size); iounmap(priv->tx_ring.txcq_db); - free(priv->cq[1].buf); - free(priv->cq[1].db); + free_memblock(priv->cq[1].buf, priv->cq[1].buf_size); + free_memblock(priv->cq[1].db, sizeof(struct mtnic_cq_db_record)); + free_memblock(priv->rx_ring.buf, priv->rx_ring.buf_size); + free_memblock(priv->rx_ring.db, sizeof(struct mtnic_cq_db_record)); + free_memblock(priv->cq[0].buf, priv->cq[0].buf_size); + free_memblock(priv->cq[0].db, sizeof(struct mtnic_cq_db_record)); /* Free RX buffers */ mtnic_free_io_buffers(&priv->rx_ring); - free(priv->rx_ring.buf); - free(priv->rx_ring.db); - free(priv->cq[0].buf); - free(priv->cq[0].db); - priv->state = CARD_INITIALIZED; } + priv->state = CARD_INITIALIZED; } @@ -1599,35 +1648,61 @@ mtnic_disable(struct pci_device *pci) { int err; - struct net_device *dev = pci_get_drvdata(pci); - struct mtnic_priv *priv = netdev_priv(dev); - - /* Should NOT happen! but just in case */ - if (priv->state == CARD_UP) - mtnic_close(dev); - - if (priv->state == CARD_INITIALIZED) { - err = mtnic_RELEASE_RESOURCE(priv, 0, - MTNIC_IF_RESOURCE_TYPE_EQ, 0); - DBG("Calling MTNIC_CLOSE command\n"); - err |= mtnic_cmd(priv, NULL, NULL, 0, - MTNIC_IF_CMD_CLOSE_NIC); - if (err) { - DBG("Error Releasing resources %d\n", err); - } + int i; + struct mtnic *mtnic = pci_get_drvdata(pci); + + + struct net_device *dev; + struct mtnic_port *priv; - free(priv->cmd.buf); - iounmap(priv->hcr); - ufree((u32)priv->fw.fw_pages.buf); - ufree((u32)priv->fw.extra_pages.buf); - free(priv->eq.buf); - iounmap(priv->eq_db); - priv->state = CARD_DOWN; + for ( i = ( mtnic->fw.num_ports - 1 ); i >= 0; i-- ) { + + dev = mtnic->netdev[i]; + + priv = netdev_priv(dev); + + /* Just in case */ + if ( ( priv->state == CARD_UP ) || + ( priv->state == CARD_LINK_DOWN ) ) + mtnic_close ( dev ); + } + + /* Releasing EQ */ + priv = netdev_priv ( mtnic->netdev[0] ); + err = mtnic_RELEASE_RESOURCE(priv, 1, + MTNIC_IF_RESOURCE_TYPE_EQ, 0); + + DBG("Calling MTNIC_CLOSE command\n"); + err |= mtnic_cmd(mtnic, NULL, NULL, 0, + MTNIC_IF_CMD_CLOSE_NIC); + if (err) { + DBG("Error Releasing resources %d\n", err); + } + + free_memblock(mtnic->cmd.buf, PAGE_SIZE); + iounmap(mtnic->hcr); + ufree((intptr_t)mtnic->fw.fw_pages.buf); + ufree((intptr_t)mtnic->fw.extra_pages.buf); + free_memblock(mtnic->eq.buf, mtnic->eq.buf_size); + iounmap(mtnic->eq_db); + + + for ( i = ( mtnic->fw.num_ports - 1 ); i >= 0; i-- ) { + dev = mtnic->netdev[i]; + unregister_netdev ( dev ); + netdev_nullify ( dev ); + netdev_put ( dev ); } - unregister_netdev(dev); - netdev_nullify(dev); - netdev_put(dev); + free ( mtnic ); + + + mtnic_reset (); + mdelay ( 1000 ); + /* Restore config, if we would like to retry booting */ + restore_config (); + + } @@ -1642,11 +1717,11 @@ mtnic_irq(struct net_device *netdev __unused, int enable __unused) /** mtnic net device operations */ static struct net_device_operations mtnic_operations = { - .open = mtnic_open, - .close = mtnic_close, - .transmit = mtnic_transmit, - .poll = mtnic_poll, - .irq = mtnic_irq, + .open = mtnic_open, + .close = mtnic_close, + .transmit = mtnic_transmit, + .poll = mtnic_poll, + .irq = mtnic_irq, }; @@ -1657,102 +1732,119 @@ static struct net_device_operations mtnic_operations = { static int mtnic_probe(struct pci_device *pci, - const struct pci_device_id *id __unused) + const struct pci_device_id *id __unused) { - struct net_device *dev; - struct mtnic_priv *priv; + struct mtnic_port *priv; + struct mtnic *mtnic; int err; u64 mac; - u32 result = 0; - void *dev_id; - int i; + int port_index; + - adjust_pci_device(pci); + adjust_pci_device(pci); - err = mtnic_init_pci(pci); + err = mtnic_init_pci(pci); if (err) { DBG("Error in pci_init\n"); - return MTNIC_ERROR; + return -EIO; } mtnic_reset(); - mdelay(1000); + mdelay(1000); - err = restore_config(); + err = restore_config(); if (err) { - DBG("Error restoring config\n"); + DBG("Error in restoring config\n"); return err; } - /* Checking MTNIC device ID */ - dev_id = ioremap(mtnic_pci_dev.dev.bar[0] + - MTNIC_DEVICE_ID_OFFSET, 4); - result = ntohl(readl(dev_id)); - iounmap(dev_id); - if (result != MTNIC_DEVICE_ID) { - DBG("Wrong Devie ID (0x%lx) !!!", result); - return MTNIC_ERROR; + mtnic = zalloc ( sizeof ( *mtnic ) ); + if ( ! mtnic ) { + DBG ( "Error Allocating mtnic buffer\n" ); + return -EADDRINUSE; } - /* Initializing net device */ - dev = alloc_etherdev(sizeof(struct mtnic_priv)); - if (dev == NULL) { - DBG("Net device allocation failed\n"); - return MTNIC_ERROR; - } - /* - * Initialize driver private data - */ - priv = netdev_priv(dev); - memset(priv, 0, sizeof(struct mtnic_priv)); - priv->dev = dev; - priv->pdev = pci; - priv->dev->dev = &pci->dev; - /* Attach pci device */ - pci_set_drvdata(pci, priv->dev); - netdev_init(dev, &mtnic_operations); + pci_set_drvdata(pci, mtnic); + + mtnic->pdev = pci; /* Initialize hardware */ - err = mtnic_init_card(dev); + err = mtnic_init_card ( mtnic ); if (err) { DBG("Error in init_card\n"); - return MTNIC_ERROR; + goto err_init_card; } - /* Program the MAC address */ - mac = priv->fw.mac[priv->port]; - printf("Port %d Mac address: 0x%12llx\n", MTNIC_PORT_NUM + 1, mac); - for (i = 0;i < MAC_ADDRESS_SIZE; ++i) { - dev->ll_addr[MAC_ADDRESS_SIZE - i - 1] = mac & 0xFF; - mac = mac >> 8; + for ( port_index = 0; port_index < mtnic->fw.num_ports; port_index ++ ) { + /* Initializing net device */ + mtnic->netdev[port_index] = alloc_etherdev( sizeof ( struct mtnic_port ) ); + if ( mtnic->netdev[port_index] == NULL ) { + DBG("Net device allocation failed\n"); + goto err_alloc_mtnic; + } + + /* + * Initialize driver private data + */ + + mtnic->netdev[port_index]->dev = &pci->dev; + priv = netdev_priv ( mtnic->netdev[port_index] ); + memset ( priv, 0, sizeof ( struct mtnic_port ) ); + priv->mtnic = mtnic; + priv->netdev = mtnic->netdev[port_index]; + + /* Attach pci device */ + netdev_init(mtnic->netdev[port_index], &mtnic_operations); + + /* Set port number */ + priv->port = port_index; + + /* Set state */ + priv->state = CARD_DOWN; } - /* Mark as link up; we don't yet handle link state */ - netdev_link_up ( dev ); - if (register_netdev(dev)) { - DBG("Netdev registration failed\n"); - return MTNIC_ERROR; + int mac_idx; + for ( port_index = 0; port_index < mtnic->fw.num_ports; port_index ++ ) { + priv = netdev_priv ( mtnic->netdev[port_index] ); + /* Program the MAC address */ + mac = priv->mtnic->fw.mac[port_index]; + for (mac_idx = 0; mac_idx < MAC_ADDRESS_SIZE; ++mac_idx) { + mtnic->netdev[port_index]->ll_addr[MAC_ADDRESS_SIZE - mac_idx - 1] = mac & 0xFF; + mac = mac >> 8; + } + + if ( register_netdev ( mtnic->netdev[port_index] ) ) { + DBG("Netdev registration failed\n"); + priv->state = CARD_INITIALIZED; + goto err_alloc_mtnic; + } } return 0; -} - +err_alloc_mtnic: + free ( mtnic ); +err_init_card: + return -EIO; +} static struct pci_device_id mtnic_nics[] = { - PCI_ROM(0x15b3, 0x6368, "mtnic", "Mellanox MTNIC driver"), + PCI_ROM ( 0x15b3, 0x6368, "mt25448", "Mellanox ConnectX EN driver" ), + PCI_ROM ( 0x15b3, 0x6372, "mt25458", "Mellanox ConnectX ENt driver" ), + PCI_ROM ( 0x15b3, 0x6750, "mt26448", "Mellanox ConnectX EN GEN2 driver" ), + PCI_ROM ( 0x15b3, 0x675a, "mt26458", "Mellanox ConnectX ENt GEN2 driver" ), }; struct pci_driver mtnic_driver __pci_driver = { .ids = mtnic_nics, .id_count = sizeof(mtnic_nics) / sizeof(mtnic_nics[0]), - .probe = mtnic_probe, + .probe = mtnic_probe, .remove = mtnic_disable, }; diff --git a/gpxe/src/drivers/net/mtnic.h b/gpxe/src/drivers/net/mtnic.h index 70a238e5..57a7b98c 100755..100644 --- a/gpxe/src/drivers/net/mtnic.h +++ b/gpxe/src/drivers/net/mtnic.h @@ -38,24 +38,28 @@ /* * Device setup */ - -/* - Note port number can be changed under mtnic.c ! -*/ #define MTNIC_MAX_PORTS 2 +#define MTNIC_PORT1 0 +#define MTNIC_PORT2 1 #define NUM_TX_RINGS 1 #define NUM_RX_RINGS 1 #define NUM_CQS (NUM_RX_RINGS + NUM_TX_RINGS) #define GO_BIT_TIMEOUT 6000 #define TBIT_RETRIES 100 #define UNITS_BUFFER_SIZE 8 /* can be configured to 4/8/16 */ -#define MAX_GAP_PROD_CONS (UNITS_BUFFER_SIZE/4) -#define DEF_MTU 1600 -#define DEF_IOBUF_SIZE 1600 +#define MAX_GAP_PROD_CONS ( UNITS_BUFFER_SIZE / 4 ) +#define ETH_DEF_LEN 1540 /* 40 bytes used by the card */ +#define ETH_FCS_LEN 14 +#define DEF_MTU ETH_DEF_LEN + ETH_FCS_LEN +#define DEF_IOBUF_SIZE ETH_DEF_LEN + #define MAC_ADDRESS_SIZE 6 #define NUM_EQES 16 #define ROUND_TO_CHECK 0x400 +#define DELAY_LINK_CHECK 300 +#define CHECK_LINK_TIMES 7 + #define XNOR(x,y) (!(x) == !(y)) #define dma_addr_t unsigned long @@ -108,7 +112,7 @@ typedef enum mtnic_if_cmd { MTNIC_IF_CMD_CONFIG_RX = 0x005, /* general receive configuration */ MTNIC_IF_CMD_CONFIG_TX = 0x006, /* general transmit configuration */ MTNIC_IF_CMD_CONFIG_INT_FREQ = 0x007, /* interrupt timers freq limits */ - MTNIC_IF_CMD_HEART_BEAT = 0x008, /* NOP command testing liveliness */ + MTNIC_IF_CMD_HEART_BEAT = 0x008, /* NOP command testing liveliness */ MTNIC_IF_CMD_CLOSE_NIC = 0x009, /* release memory and stop the NIC */ /* Port commands: */ @@ -119,22 +123,22 @@ typedef enum mtnic_if_cmd { MTNIC_IF_CMD_CONFIG_PORT_VLAN_FILTER = 0x14, /* configure VLAN filter */ MTNIC_IF_CMD_CONFIG_PORT_MCAST_FILTER = 0x15, /* configure mcast filter */ MTNIC_IF_CMD_ENABLE_PORT_MCAST_FILTER = 0x16, /* enable/disable */ - MTNIC_IF_CMD_SET_PORT_MTU = 0x17, /* set port MTU */ + MTNIC_IF_CMD_SET_PORT_MTU = 0x17, /* set port MTU */ MTNIC_IF_CMD_SET_PORT_PROMISCUOUS_MODE = 0x18, /* enable/disable promisc */ MTNIC_IF_CMD_SET_PORT_DEFAULT_RING = 0x19, /* set the default ring */ - MTNIC_IF_CMD_SET_PORT_STATE = 0x1a, /* set link up/down */ - MTNIC_IF_CMD_DUMP_STAT = 0x1b, /* dump statistics */ + MTNIC_IF_CMD_SET_PORT_STATE = 0x1a, /* set link up/down */ + MTNIC_IF_CMD_DUMP_STAT = 0x1b, /* dump statistics */ MTNIC_IF_CMD_ARM_PORT_STATE_EVENT = 0x1c, /* arm the port state event */ /* Ring / Completion queue commands: */ - MTNIC_IF_CMD_CONFIG_CQ = 0x20, /* set up completion queue */ - MTNIC_IF_CMD_CONFIG_RX_RING = 0x21, /* setup Rx ring */ - MTNIC_IF_CMD_SET_RX_RING_ADDR = 0x22, /* set Rx ring filter by address */ + MTNIC_IF_CMD_CONFIG_CQ = 0x20, /* set up completion queue */ + MTNIC_IF_CMD_CONFIG_RX_RING = 0x21, /* setup Rx ring */ + MTNIC_IF_CMD_SET_RX_RING_ADDR = 0x22, /* set Rx ring filter by address */ MTNIC_IF_CMD_SET_RX_RING_MCAST = 0x23, /* set Rx ring mcast filter */ - MTNIC_IF_CMD_ARM_RX_RING_WM = 0x24, /* one-time low-watermark INT */ - MTNIC_IF_CMD_CONFIG_TX_RING = 0x25, /* set up Tx ring */ + MTNIC_IF_CMD_ARM_RX_RING_WM = 0x24, /* one-time low-watermark INT */ + MTNIC_IF_CMD_CONFIG_TX_RING = 0x25, /* set up Tx ring */ MTNIC_IF_CMD_ENFORCE_TX_RING_ADDR = 0x26, /* setup anti spoofing */ - MTNIC_IF_CMD_CONFIG_EQ = 0x27, /* config EQ ring */ + MTNIC_IF_CMD_CONFIG_EQ = 0x27, /* config EQ ring */ MTNIC_IF_CMD_RELEASE_RESOURCE = 0x28, /* release internal ref to resource */ } mtnic_if_cmd_t; @@ -144,15 +148,15 @@ mtnic_if_cmd_t; typedef enum mtnic_if_caps { MTNIC_IF_CAP_MAX_TX_RING_PER_PORT = 0x0, MTNIC_IF_CAP_MAX_RX_RING_PER_PORT = 0x1, - MTNIC_IF_CAP_MAX_CQ_PER_PORT = 0x2, - MTNIC_IF_CAP_NUM_PORTS = 0x3, - MTNIC_IF_CAP_MAX_TX_DESC = 0x4, - MTNIC_IF_CAP_MAX_RX_DESC = 0x5, - MTNIC_IF_CAP_MAX_CQES = 0x6, - MTNIC_IF_CAP_MAX_TX_SG_ENTRIES = 0x7, - MTNIC_IF_CAP_MAX_RX_SG_ENTRIES = 0x8, - MTNIC_IF_CAP_MEM_KEY = 0x9, /* key to mem (after map_pages) */ - MTNIC_IF_CAP_RSS_HASH_TYPE = 0xa, /* one of mtnic_if_rss_types_t */ + MTNIC_IF_CAP_MAX_CQ_PER_PORT = 0x2, + MTNIC_IF_CAP_NUM_PORTS = 0x3, + MTNIC_IF_CAP_MAX_TX_DESC = 0x4, + MTNIC_IF_CAP_MAX_RX_DESC = 0x5, + MTNIC_IF_CAP_MAX_CQES = 0x6, + MTNIC_IF_CAP_MAX_TX_SG_ENTRIES = 0x7, + MTNIC_IF_CAP_MAX_RX_SG_ENTRIES = 0x8, + MTNIC_IF_CAP_MEM_KEY = 0x9, /* key to mem (after map_pages) */ + MTNIC_IF_CAP_RSS_HASH_TYPE = 0xa, /* one of mtnic_if_rss_types_t */ MTNIC_IF_CAP_MAX_PORT_UCAST_ADDR = 0xc, MTNIC_IF_CAP_MAX_RING_UCAST_ADDR = 0xd, /* only for ADDR steer */ MTNIC_IF_CAP_MAX_PORT_MCAST_ADDR = 0xe, @@ -164,20 +168,20 @@ typedef enum mtnic_if_caps { MTNIC_IF_CAP_EQ_DB_OFFSET = 0x14, /* offset in bytes for EQ doorbell record */ /* These are per port - using port number from cap modifier field */ - MTNIC_IF_CAP_SPEED = 0x20, - MTNIC_IF_CAP_DEFAULT_MAC = 0x21, - MTNIC_IF_CAP_EQ_OFFSET = 0x22, - MTNIC_IF_CAP_CQ_OFFSET = 0x23, + MTNIC_IF_CAP_SPEED = 0x20, + MTNIC_IF_CAP_DEFAULT_MAC = 0x21, + MTNIC_IF_CAP_EQ_OFFSET = 0x22, + MTNIC_IF_CAP_CQ_OFFSET = 0x23, MTNIC_IF_CAP_TX_OFFSET = 0x24, MTNIC_IF_CAP_RX_OFFSET = 0x25, } mtnic_if_caps_t; typedef enum mtnic_if_steer_types { - MTNIC_IF_STEER_NONE = 0, - MTNIC_IF_STEER_PRIORITY = 1, - MTNIC_IF_STEER_RSS = 2, - MTNIC_IF_STEER_ADDRESS = 3, + MTNIC_IF_STEER_NONE = 0, + MTNIC_IF_STEER_PRIORITY = 1, + MTNIC_IF_STEER_RSS = 2, + MTNIC_IF_STEER_ADDRESS = 3, } mtnic_if_steer_types_t; /** types of memory access modes */ @@ -188,19 +192,12 @@ typedef enum mtnic_if_memory_types { enum { - MTNIC_HCR_BASE = 0x1f000, - MTNIC_HCR_SIZE = 0x0001c, - MTNIC_CLR_INT_SIZE = 0x00008, + MTNIC_HCR_BASE = 0x1f000, + MTNIC_HCR_SIZE = 0x0001c, + MTNIC_CLR_INT_SIZE = 0x00008, }; -#define MELLANOX_VENDOR_ID 0x15b3 -#define MTNIC_DEVICE_ID 0x00a00190 #define MTNIC_RESET_OFFSET 0xF0010 -#define MTNIC_DEVICE_ID_OFFSET 0xF0014 - - - - @@ -265,7 +262,7 @@ struct mtnic_ring { /* Buffers */ u32 buf_size; /* ring buffer size in bytes */ - dma_addr_t dma; + dma_addr_t dma; void *buf; struct io_buffer *iobuf[UNITS_BUFFER_SIZE]; @@ -274,7 +271,7 @@ struct mtnic_ring { u32 db_offset; /* Rx ring only */ - dma_addr_t iobuf_dma; + dma_addr_t iobuf_dma; struct mtnic_rx_db_record *db; dma_addr_t db_dma; }; @@ -351,15 +348,16 @@ struct mtnic_eqe { struct mtnic_eq { u32 size; /* number of EQEs in ring */ - u32 buf_size; /* EQ size in bytes */ + u32 buf_size; /* EQ size in bytes */ void *buf; dma_addr_t dma; }; enum mtnic_state { CARD_DOWN, - CARD_INITIALIZED, - CARD_UP + CARD_INITIALIZED, + CARD_UP, + CARD_LINK_DOWN, }; /* FW */ @@ -375,9 +373,9 @@ struct mtnic_err_buf { struct mtnic_cmd { - void *buf; - u32 mapping; - u32 tbit; + void *buf; + unsigned long mapping; + u32 tbit; }; @@ -395,40 +393,52 @@ struct mtnic_txcq_db { * Device private data * */ -struct mtnic_priv { - struct net_device *dev; - struct pci_device *pdev; - u8 port; +struct mtnic { + struct net_device *netdev[MTNIC_MAX_PORTS]; + struct mtnic_if_cmd_reg *hcr; + struct mtnic_cmd cmd; + struct pci_device *pdev; - enum mtnic_state state; - /* Firmware and board info */ - u64 fw_ver; + struct mtnic_eq eq; + u32 *eq_db; + + /* Firmware and board info */ + u64 fw_ver; struct { - struct mtnic_pages fw_pages; - struct mtnic_pages extra_pages; - struct mtnic_err_buf err_buf; - u16 ifc_rev; - u8 num_ports; - u64 mac[MTNIC_MAX_PORTS]; - u16 cq_offset; - u16 tx_offset[MTNIC_MAX_PORTS]; - u16 rx_offset[MTNIC_MAX_PORTS]; - u32 mem_type_snoop_be; - u32 txcq_db_offset; - u32 eq_db_offset; - } fw; - - - struct mtnic_if_cmd_reg *hcr; - struct mtnic_cmd cmd; + struct mtnic_pages fw_pages; + struct mtnic_pages extra_pages; + struct mtnic_err_buf err_buf; + u16 ifc_rev; + u8 num_ports; + u64 mac[MTNIC_MAX_PORTS]; + u16 cq_offset; + u16 tx_offset[MTNIC_MAX_PORTS]; + u16 rx_offset[MTNIC_MAX_PORTS]; + u32 mem_type_snoop_be; + u32 txcq_db_offset; + u32 eq_db_offset; + } fw; +}; + + + + + +struct mtnic_port { + + struct mtnic *mtnic; + u8 port; + + enum mtnic_state state; /* TX, RX, CQs, EQ */ - struct mtnic_ring tx_ring; - struct mtnic_ring rx_ring; - struct mtnic_cq cq[NUM_CQS]; - struct mtnic_eq eq; - u32 *eq_db; - u32 poll_counter; + struct mtnic_ring tx_ring; + struct mtnic_ring rx_ring; + struct mtnic_cq cq[NUM_CQS]; + u32 poll_counter; + struct net_device *netdev; + + }; @@ -492,33 +502,34 @@ struct mtnic_if_query_fw_out_mbox { /* CMD MTNIC_IF_CMD_QUERY_CAP */ struct mtnic_if_query_cap_in_imm { u16 reserved1; - u8 cap_modifier; /* a modifier for the particular capability */ - u8 cap_index; /* the index of the capability queried */ + u8 cap_modifier; /* a modifier for the particular capability */ + u8 cap_index; /* the index of the capability queried */ u32 reserved2; }; /* CMD OPEN_NIC */ struct mtnic_if_open_nic_in_mbox { - u16 reserved1; - u16 mkey; /* number of mem keys for all chip*/ - u32 mkey_entry; /* mem key entries for each key*/ - u8 log_rx_p1; /* log2 rx rings for port1 */ - u8 log_cq_p1; /* log2 cq for port1 */ - u8 log_tx_p1; /* log2 tx rings for port1 */ - u8 steer_p1; /* port 1 steering mode */ - u16 reserved2; - u8 log_vlan_p1; /* log2 vlan per rx port1 */ - u8 log_mac_p1; /* log2 mac per rx port1 */ - - u8 log_rx_p2; /* log2 rx rings for port1 */ - u8 log_cq_p2; /* log2 cq for port1 */ - u8 log_tx_p2; /* log2 tx rings for port1 */ - u8 steer_p2; /* port 1 steering mode */ - u16 reserved3; - u8 log_vlan_p2; /* log2 vlan per rx port1 */ - u8 log_mac_p2; /* log2 mac per rx port1 */ + u16 reserved1; + u16 mkey; /* number of mem keys for all chip*/ + u32 mkey_entry; /* mem key entries for each key*/ + u8 log_rx_p1; /* log2 rx rings for port1 */ + u8 log_cq_p1; /* log2 cq for port1 */ + u8 log_tx_p1; /* log2 tx rings for port1 */ + u8 steer_p1; /* port 1 steering mode */ + u16 reserved2; + u8 log_vlan_p1; /* log2 vlan per rx port1 */ + u8 log_mac_p1; /* log2 mac per rx port1 */ + + u8 log_rx_p2; /* log2 rx rings for port1 */ + u8 log_cq_p2; /* log2 cq for port1 */ + u8 log_tx_p2; /* log2 tx rings for port1 */ + u8 steer_p2; /* port 1 steering mode */ + u16 reserved3; + u8 log_vlan_p2; /* log2 vlan per rx port1 */ + u8 log_mac_p2; /* log2 mac per rx port1 */ }; + /* CMD CONFIG_RX */ struct mtnic_if_config_rx_in_imm { u16 spkt_size; /* size of small packets interrupts enabled on CQ */ @@ -535,9 +546,9 @@ struct mtnic_if_config_send_in_imm { /* CMD HEART_BEAT */ struct mtnic_if_heart_beat_out_imm { - u32 flags; /* several flags */ + u32 flags; /* several flags */ #define MTNIC_MASK_HEAR_BEAT_INT_ERROR MTNIC_BC(31,1) - u32 reserved; + u32 reserved; }; @@ -547,14 +558,14 @@ struct mtnic_if_heart_beat_out_imm { /* CMD CONFIG_PORT_VLAN_FILTER */ /* in mbox is a 4K bits mask - bit per VLAN */ struct mtnic_if_config_port_vlan_filter_in_mbox { - u64 filter[64]; /* vlans[63:0] sit in filter[0], vlans[127:64] sit in filter[1] .. */ + u64 filter[64]; /* vlans[63:0] sit in filter[0], vlans[127:64] sit in filter[1] .. */ }; /* CMD SET_PORT_MTU */ struct mtnic_if_set_port_mtu_in_imm { u16 reserved1; - u16 mtu; /* The MTU of the port in bytes */ + u16 mtu; /* The MTU of the port in bytes */ u32 reserved2; }; @@ -574,17 +585,17 @@ struct mtnic_if_set_port_state_in_imm { /* CMD CONFIG_CQ */ struct mtnic_if_config_cq_in_mbox { - u8 reserved1; - u8 cq; - u8 size; /* Num CQs is 2^size (size <= 22) */ - u8 offset; /* start address of CQE in first page (11:6) */ - u16 tlast; /* interrupt moderation timer from last completion usec */ + u8 reserved1; + u8 cq; + u8 size; /* Num CQs is 2^size (size <= 22) */ + u8 offset; /* start address of CQE in first page (11:6) */ + u16 tlast; /* interrupt moderation timer from last completion usec */ u8 flags; /* flags */ - u8 int_vector; /* MSI index if MSI is enabled, otherwise reserved */ + u8 int_vector; /* MSI index if MSI is enabled, otherwise reserved */ u16 reserved2; u16 max_cnt; /* interrupt moderation counter */ - u8 page_size; /* each mapped page is 2^(12+page_size) bytes */ - u8 reserved4[3]; + u8 page_size; /* each mapped page is 2^(12+page_size) bytes */ + u8 reserved4[3]; u32 db_record_addr_h; /*physical address of CQ doorbell record */ u32 db_record_addr_l; /*physical address of CQ doorbell record */ u32 page_address[0]; /* 64 bit page addresses of CQ buffer */ @@ -592,21 +603,21 @@ struct mtnic_if_config_cq_in_mbox { /* CMD CONFIG_RX_RING */ struct mtnic_if_config_rx_ring_in_mbox { - u8 reserved1; - u8 ring; /* The ring index (with offset) */ - u8 stride_size; /* stride and size */ + u8 reserved1; + u8 ring; /* The ring index (with offset) */ + u8 stride_size; /* stride and size */ /* Entry size = 16* (2^stride) bytes */ #define MTNIC_MASK_CONFIG_RX_RING_STRIDE MTNIC_BC(4,3) /* Rx ring size is 2^size entries */ #define MTNIC_MASK_CONFIG_RX_RING_SIZE MTNIC_BC(0,4) - u8 flags; /* Bit0 - header separation */ - u8 page_size; /* Each mapped page is 2^(12+page_size) bytes */ - u8 reserved2[2]; - u8 cq; /* CQ associated with this ring */ - u32 db_record_addr_h; - u32 db_record_addr_l; - u32 page_address[0];/* Array of 2^size 64b page descriptor addresses */ - /* Must hold all Rx descriptors + doorbell record. */ + u8 flags; /* Bit0 - header separation */ + u8 page_size; /* Each mapped page is 2^(12+page_size) bytes */ + u8 reserved2[2]; + u8 cq; /* CQ associated with this ring */ + u32 db_record_addr_h; + u32 db_record_addr_l; + u32 page_address[0];/* Array of 2^size 64b page descriptor addresses */ + /* Must hold all Rx descriptors + doorbell record. */ }; /* The modifier for SET_RX_RING_ADDR */ @@ -619,27 +630,27 @@ struct mtnic_if_set_rx_ring_modifier { /* CMD SET_RX_RING_ADDR */ struct mtnic_if_set_rx_ring_addr_in_imm { - u16 mac_47_32; /* UCAST MAC Address bits 47:32 */ + u16 mac_47_32; /* UCAST MAC Address bits 47:32 */ u16 flags_vlan_id; /* MAC/VLAN flags and vlan id */ #define MTNIC_MASK_SET_RX_RING_ADDR_VLAN_ID MTNIC_BC(0,12) #define MTNIC_MASK_SET_RX_RING_ADDR_BY_MAC MTNIC_BC(12,1) #define MTNIC_MASK_SET_RX_RING_ADDR_BY_VLAN MTNIC_BC(13,1) - u32 mac_31_0; /* UCAST MAC Address bits 31:0 */ + u32 mac_31_0; /* UCAST MAC Address bits 31:0 */ }; /* CMD CONFIG_TX_RING */ struct mtnic_if_config_send_ring_in_mbox { - u16 ring; /* The ring index (with offset) */ + u16 ring; /* The ring index (with offset) */ #define MTNIC_MASK_CONFIG_TX_RING_INDEX MTNIC_BC(0,8) - u8 size; /* Tx ring size is 32*2^size bytes */ + u8 size; /* Tx ring size is 32*2^size bytes */ #define MTNIC_MASK_CONFIG_TX_RING_SIZE MTNIC_BC(0,4) - u8 reserved; - u8 page_size; /* Each mapped page is 2^(12+page_size) bytes */ - u8 qos_class; /* The COS used for this Tx */ - u16 cq; /* CQ associated with this ring */ + u8 reserved; + u8 page_size; /* Each mapped page is 2^(12+page_size) bytes */ + u8 qos_class; /* The COS used for this Tx */ + u16 cq; /* CQ associated with this ring */ #define MTNIC_MASK_CONFIG_TX_CQ_INDEX MTNIC_BC(0,8) u32 page_address[0]; /* 64 bit page addresses of descriptor buffer. */ - /* The buffer must accommodate all Tx descriptors */ + /* The buffer must accommodate all Tx descriptors */ }; /* CMD CONFIG_EQ */ @@ -647,9 +658,9 @@ struct mtnic_if_config_eq_in_mbox { u8 reserved1; u8 int_vector; /* MSI index if MSI enabled; otherwise reserved */ #define MTNIC_MASK_CONFIG_EQ_INT_VEC MTNIC_BC(0,6) - u8 size; /* Num CQs is 2^size entries (size <= 22) */ + u8 size; /* Num CQs is 2^size entries (size <= 22) */ #define MTNIC_MASK_CONFIG_EQ_SIZE MTNIC_BC(0,5) - u8 offset; /* Start address of CQE in first page (11:6) */ + u8 offset; /* Start address of CQE in first page (11:6) */ #define MTNIC_MASK_CONFIG_EQ_OFFSET MTNIC_BC(0,6) u8 page_size; /* Each mapped page is 2^(12+page_size) bytes*/ u8 reserved[3]; diff --git a/gpxe/src/drivers/net/natsemi.c b/gpxe/src/drivers/net/natsemi.c index 028b905c..3a776234 100644 --- a/gpxe/src/drivers/net/natsemi.c +++ b/gpxe/src/drivers/net/natsemi.c @@ -61,7 +61,8 @@ #include <stdint.h> #include <stdlib.h> #include <stdio.h> -#include <io.h> +#include <string.h> +#include <gpxe/io.h> #include <errno.h> #include <byteswap.h> #include <unistd.h> @@ -357,7 +358,7 @@ static int natsemi_open (struct net_device *netdev) } outl (virt_to_bus (&np->tx[0]),np->ioaddr + TxRingPtr); - DBG ("Natsemi Tx descriptor loaded with: %#08lx\n", + DBG ("Natsemi Tx descriptor loaded with: %#08x\n", inl (np->ioaddr + TxRingPtr)); /* Setup RX ring @@ -376,7 +377,7 @@ static int natsemi_open (struct net_device *netdev) } outl (virt_to_bus (&np->rx[0]), np->ioaddr + RxRingPtr); - DBG ("Natsemi Rx descriptor loaded with: %#08lx\n", + DBG ("Natsemi Rx descriptor loaded with: %#08x\n", inl (np->ioaddr + RxRingPtr)); /* Setup RX Filter @@ -400,7 +401,7 @@ static int natsemi_open (struct net_device *netdev) outl (tx_config, np->ioaddr + TxConfig); outl (rx_config, np->ioaddr + RxConfig); - DBG ("Tx config register = %#08lx Rx config register = %#08lx\n", + DBG ("Tx config register = %#08x Rx config register = %#08x\n", inl (np->ioaddr + TxConfig), inl (np->ioaddr + RxConfig)); @@ -551,7 +552,7 @@ static void natsemi_poll (struct net_device *netdev) netdev_rx_err (netdev, NULL, -EINVAL); DBG ("natsemi_poll: Corrupted packet received!" - " Status = %#08lx\n", + " Status = %#08x\n", np->rx[np->rx_cur].cmdsts); } else { diff --git a/gpxe/src/drivers/net/ne2k_isa.c b/gpxe/src/drivers/net/ne2k_isa.c new file mode 100644 index 00000000..f8a45cc8 --- /dev/null +++ b/gpxe/src/drivers/net/ne2k_isa.c @@ -0,0 +1,373 @@ +/************************************************************************** + ETHERBOOT - BOOTP/TFTP Bootstrap Program + + Author: Martin Renters + Date: May/94 + + This code is based heavily on David Greenman's if_ed.c driver + + Copyright (C) 1993-1994, David Greenman, Martin Renters. + This software may be used, modified, copied, distributed, and sold, in + both source and binary form provided that the above copyright and these + terms are retained. 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. + + Multicast support added by Timothy Legge (timlegge@users.sourceforge.net) 09/28/2003 + Relocation support added by Ken Yap (ken_yap@users.sourceforge.net) 28/12/02 + Card Detect support adapted from the eCos driver (Christian Plessl <cplessl@ee.ethz.ch>) + Extracted from ns8390.c and adapted by Pantelis Koukousoulas <pktoss@gmail.com> + **************************************************************************/ + +#include "ns8390.h" +#include "etherboot.h" +#include "nic.h" +#include <gpxe/ethernet.h> +#include <gpxe/isa.h> +#include <errno.h> + +#define ASIC_PIO NE_DATA + +static unsigned char eth_vendor, eth_flags; +static unsigned short eth_nic_base, eth_asic_base; +static unsigned char eth_memsize, eth_rx_start, eth_tx_start; +static Address eth_bmem, eth_rmem; +static unsigned char eth_drain_receiver; + +static struct nic_operations ne_operations; +static void ne_reset(struct nic *nic, struct isa_device *isa); + +static isa_probe_addr_t ne_probe_addrs[] = { 0x300, 0x280, 0x320, 0x340, 0x380, 0x220, }; + +/************************************************************************** + ETH_PIO_READ - Read a frame via Programmed I/O + **************************************************************************/ +static void eth_pio_read(unsigned int src, unsigned char *dst, unsigned int cnt) { + outb(D8390_COMMAND_RD2 | D8390_COMMAND_STA, eth_nic_base + D8390_P0_COMMAND); + outb(cnt, eth_nic_base + D8390_P0_RBCR0); + outb(cnt >> 8, eth_nic_base + D8390_P0_RBCR1); + outb(src, eth_nic_base + D8390_P0_RSAR0); + outb(src >> 8, eth_nic_base + D8390_P0_RSAR1); + outb(D8390_COMMAND_RD0 | D8390_COMMAND_STA, eth_nic_base + D8390_P0_COMMAND); + if (eth_flags & FLAG_16BIT) + cnt = (cnt + 1) >> 1; + + while (cnt--) { + if (eth_flags & FLAG_16BIT) { + *((unsigned short *) dst) = inw(eth_asic_base + ASIC_PIO); + dst += 2; + } else + *(dst++) = inb(eth_asic_base + ASIC_PIO); + } +} + +/************************************************************************** + ETH_PIO_WRITE - Write a frame via Programmed I/O + **************************************************************************/ +static void eth_pio_write(const unsigned char *src, unsigned int dst, + unsigned int cnt) { + outb(D8390_COMMAND_RD2 | D8390_COMMAND_STA, eth_nic_base + D8390_P0_COMMAND); + outb(D8390_ISR_RDC, eth_nic_base + D8390_P0_ISR); + outb(cnt, eth_nic_base + D8390_P0_RBCR0); + outb(cnt >> 8, eth_nic_base + D8390_P0_RBCR1); + outb(dst, eth_nic_base + D8390_P0_RSAR0); + outb(dst >> 8, eth_nic_base + D8390_P0_RSAR1); + outb(D8390_COMMAND_RD1 | D8390_COMMAND_STA, eth_nic_base + D8390_P0_COMMAND); + if (eth_flags & FLAG_16BIT) + cnt = (cnt + 1) >> 1; + + while (cnt--) { + + if (eth_flags & FLAG_16BIT) { + outw(*((unsigned short *) src), eth_asic_base + ASIC_PIO); + src += 2; + } else + outb(*(src++), eth_asic_base + ASIC_PIO); + } +} + +/************************************************************************** + enable_multicast - Enable Multicast + **************************************************************************/ +static void enable_multicast(unsigned short eth_nic_base) { + unsigned char mcfilter[8]; + int i; + + memset(mcfilter, 0xFF, 8); + outb(4, eth_nic_base + D8390_P0_RCR); + outb(D8390_COMMAND_RD2 + D8390_COMMAND_PS1, eth_nic_base + D8390_P0_COMMAND); + for (i = 0; i < 8; i++) { + outb(mcfilter[i], eth_nic_base + 8 + i); + if (inb(eth_nic_base + 8 + i) != mcfilter[i]) + DBG("Error SMC 83C690 Multicast filter read/write mishap %d\n", + i); + } + outb(D8390_COMMAND_RD2 + D8390_COMMAND_PS0, eth_nic_base + D8390_P0_COMMAND); + outb(4 | 0x08, eth_nic_base + D8390_P0_RCR); +} + +/************************************************************************** + NE_PROBE1 - Look for an adapter on the ISA bus + **************************************************************************/ +static int ne_probe1(isa_probe_addr_t ioaddr) { + //From the eCos driver + unsigned int regd; + unsigned int state; + + state = inb(ioaddr); + outb(ioaddr, D8390_COMMAND_RD2 | D8390_COMMAND_PS1 | D8390_COMMAND_STP); + regd = inb(ioaddr + D8390_P0_TCR); + + if (inb(ioaddr + D8390_P0_TCR)) { + outb(ioaddr, state); + outb(ioaddr + 0x0d, regd); + return 0; + } + + return 1; +} + +/************************************************************************** + NE_PROBE - Initialize an adapter ??? + **************************************************************************/ +static int ne_probe(struct nic *nic, struct isa_device *isa) { + int i; + unsigned char c; + unsigned char romdata[16]; + unsigned char testbuf[32]; + + eth_vendor = VENDOR_NONE; + eth_drain_receiver = 0; + + nic->irqno = 0; + nic->ioaddr = isa->ioaddr; + eth_nic_base = isa->ioaddr; + + /****************************************************************** + Search for NE1000/2000 if no WD/SMC or 3com cards + ******************************************************************/ + if (eth_vendor == VENDOR_NONE) { + + static unsigned char test[] = "NE*000 memory"; + + eth_bmem = 0; /* No shared memory */ + + eth_flags = FLAG_PIO; + eth_asic_base = eth_nic_base + NE_ASIC_OFFSET; + eth_memsize = MEM_16384; + eth_tx_start = 32; + eth_rx_start = 32 + D8390_TXBUF_SIZE; + c = inb(eth_asic_base + NE_RESET); + outb(c, eth_asic_base + NE_RESET); + (void) inb(0x84); + outb(D8390_COMMAND_STP | D8390_COMMAND_RD2, eth_nic_base + + D8390_P0_COMMAND); + outb(D8390_RCR_MON, eth_nic_base + D8390_P0_RCR); + outb(D8390_DCR_FT1 | D8390_DCR_LS, eth_nic_base + D8390_P0_DCR); + outb(MEM_8192, eth_nic_base + D8390_P0_PSTART); + outb(MEM_16384, eth_nic_base + D8390_P0_PSTOP); + eth_pio_write((unsigned char *) test, 8192, sizeof(test)); + eth_pio_read(8192, testbuf, sizeof(test)); + if (!memcmp(test, testbuf, sizeof(test))) + goto out; + eth_flags |= FLAG_16BIT; + eth_memsize = MEM_32768; + eth_tx_start = 64; + eth_rx_start = 64 + D8390_TXBUF_SIZE; + outb(D8390_DCR_WTS | D8390_DCR_FT1 | D8390_DCR_LS, eth_nic_base + + D8390_P0_DCR); + outb(MEM_16384, eth_nic_base + D8390_P0_PSTART); + outb(MEM_32768, eth_nic_base + D8390_P0_PSTOP); + eth_pio_write((unsigned char *) test, 16384, sizeof(test)); + eth_pio_read(16384, testbuf, sizeof(test)); + if (!memcmp(testbuf, test, sizeof(test))) + goto out; + + +out: + if (eth_nic_base == 0) + return (0); + if (eth_nic_base > ISA_MAX_ADDR) /* PCI probably */ + eth_flags |= FLAG_16BIT; + eth_vendor = VENDOR_NOVELL; + eth_pio_read(0, romdata, sizeof(romdata)); + for (i = 0; i < ETH_ALEN; i++) { + nic->node_addr[i] = romdata[i + ((eth_flags & FLAG_16BIT) ? i : 0)]; + } + nic->ioaddr = eth_nic_base; + DBG("\nNE%c000 base %4.4x, MAC Addr %s\n", + (eth_flags & FLAG_16BIT) ? '2' : '1', eth_nic_base, eth_ntoa( + nic->node_addr)); + } + + if (eth_vendor == VENDOR_NONE) + return (0); + + if (eth_vendor != VENDOR_3COM) + eth_rmem = eth_bmem; + + ne_reset(nic, isa); + nic->nic_op = &ne_operations; + return 1; +} + + +/************************************************************************** + NE_DISABLE - Turn off adapter + **************************************************************************/ +static void ne_disable(struct nic *nic, struct isa_device *isa) { + ne_reset(nic, isa); +} + + +/************************************************************************** + NE_RESET - Reset adapter + **************************************************************************/ +static void ne_reset(struct nic *nic, struct isa_device *isa __unused) +{ + int i; + + eth_drain_receiver = 0; + outb(D8390_COMMAND_PS0 | D8390_COMMAND_RD2 | + D8390_COMMAND_STP, eth_nic_base+D8390_P0_COMMAND); + if (eth_flags & FLAG_16BIT) + outb(0x49, eth_nic_base+D8390_P0_DCR); + else + outb(0x48, eth_nic_base+D8390_P0_DCR); + outb(0, eth_nic_base+D8390_P0_RBCR0); + outb(0, eth_nic_base+D8390_P0_RBCR1); + outb(0x20, eth_nic_base+D8390_P0_RCR); /* monitor mode */ + outb(2, eth_nic_base+D8390_P0_TCR); + outb(eth_tx_start, eth_nic_base+D8390_P0_TPSR); + outb(eth_rx_start, eth_nic_base+D8390_P0_PSTART); + + outb(eth_memsize, eth_nic_base+D8390_P0_PSTOP); + outb(eth_memsize - 1, eth_nic_base+D8390_P0_BOUND); + outb(0xFF, eth_nic_base+D8390_P0_ISR); + outb(0, eth_nic_base+D8390_P0_IMR); + outb(D8390_COMMAND_PS1 | + D8390_COMMAND_RD2 | D8390_COMMAND_STP, eth_nic_base+D8390_P0_COMMAND); + + for (i=0; i<ETH_ALEN; i++) + outb(nic->node_addr[i], eth_nic_base+D8390_P1_PAR0+i); + for (i=0; i<ETH_ALEN; i++) + outb(0xFF, eth_nic_base+D8390_P1_MAR0+i); + outb(eth_rx_start, eth_nic_base+D8390_P1_CURR); + outb(D8390_COMMAND_PS0 | + D8390_COMMAND_RD2 | D8390_COMMAND_STA, eth_nic_base+D8390_P0_COMMAND); + outb(0xFF, eth_nic_base+D8390_P0_ISR); + outb(0, eth_nic_base+D8390_P0_TCR); /* transmitter on */ + outb(4, eth_nic_base+D8390_P0_RCR); /* allow rx broadcast frames */ + + enable_multicast(eth_nic_base); +} + + +/************************************************************************** + NE_POLL - Wait for a frame + **************************************************************************/ +static int ne_poll(struct nic *nic __unused, int retrieve __unused) +{ + int ret = 0; + unsigned char rstat, curr, next; + unsigned short len, frag; + unsigned short pktoff; + unsigned char *p; + struct ringbuffer pkthdr; + + rstat = inb(eth_nic_base+D8390_P0_RSR); + if (!(rstat & D8390_RSTAT_PRX)) return(0); + next = inb(eth_nic_base+D8390_P0_BOUND)+1; + if (next >= eth_memsize) next = eth_rx_start; + outb(D8390_COMMAND_PS1, eth_nic_base+D8390_P0_COMMAND); + curr = inb(eth_nic_base+D8390_P1_CURR); + outb(D8390_COMMAND_PS0, eth_nic_base+D8390_P0_COMMAND); + if (curr >= eth_memsize) curr=eth_rx_start; + if (curr == next) return(0); + + if ( ! retrieve ) return 1; + + pktoff = next << 8; + if (eth_flags & FLAG_PIO) + eth_pio_read(pktoff, (unsigned char *)&pkthdr, 4); + else + memcpy(&pkthdr, bus_to_virt(eth_rmem + pktoff), 4); + pktoff += sizeof(pkthdr); + /* incoming length includes FCS so must sub 4 */ + len = pkthdr.len - 4; + if ((pkthdr.status & D8390_RSTAT_PRX) == 0 || len < ETH_ZLEN + || len> ETH_FRAME_LEN) { + DBG("Bogus packet, ignoring\n"); + return (0); + } + else { + p = nic->packet; + nic->packetlen = len; /* available to caller */ + frag = (eth_memsize << 8) - pktoff; + if (len> frag) { /* We have a wrap-around */ + /* read first part */ + if (eth_flags & FLAG_PIO) + eth_pio_read(pktoff, p, frag); + else + memcpy(p, bus_to_virt(eth_rmem + pktoff), frag); + pktoff = eth_rx_start << 8; + p += frag; + len -= frag; + } + /* read second part */ + if (eth_flags & FLAG_PIO) + eth_pio_read(pktoff, p, len); + else + memcpy(p, bus_to_virt(eth_rmem + pktoff), len); + ret = 1; + } + next = pkthdr.next; /* frame number of next packet */ + if (next == eth_rx_start) + next = eth_memsize; + outb(next-1, eth_nic_base+D8390_P0_BOUND); + return(ret); +} + + +/************************************************************************** + NE_TRANSMIT - Transmit a frame + **************************************************************************/ +static void ne_transmit(struct nic *nic, const char *d, /* Destination */ +unsigned int t, /* Type */ +unsigned int s, /* size */ +const char *p) { /* Packet */ + + /* Programmed I/O */ + unsigned short type; + type = (t >> 8) | (t << 8); + eth_pio_write((unsigned char *) d, eth_tx_start << 8, ETH_ALEN); + eth_pio_write(nic->node_addr, (eth_tx_start << 8) + ETH_ALEN, ETH_ALEN); + /* bcc generates worse code without (const+const) below */ + eth_pio_write((unsigned char *) &type, (eth_tx_start << 8) + (ETH_ALEN + + ETH_ALEN), 2); + eth_pio_write((unsigned char *) p, (eth_tx_start << 8) + ETH_HLEN, s); + s += ETH_HLEN; + if (s < ETH_ZLEN) + s = ETH_ZLEN; + + outb(D8390_COMMAND_PS0 | D8390_COMMAND_RD2 | D8390_COMMAND_STA, + eth_nic_base + D8390_P0_COMMAND); + outb(eth_tx_start, eth_nic_base + D8390_P0_TPSR); + outb(s, eth_nic_base + D8390_P0_TBCR0); + outb(s >> 8, eth_nic_base + D8390_P0_TBCR1); + + outb(D8390_COMMAND_PS0 | D8390_COMMAND_TXP | D8390_COMMAND_RD2 + | D8390_COMMAND_STA, eth_nic_base + D8390_P0_COMMAND); +} + +static struct nic_operations ne_operations = { .connect = dummy_connect, + .poll = ne_poll, .transmit = ne_transmit, .irq = dummy_irq, +}; + +ISA_DRIVER ( ne_driver, ne_probe_addrs, ne_probe1, + GENERIC_ISAPNP_VENDOR, 0x0600 ); + +DRIVER ( "ne", nic_driver, isapnp_driver, ne_driver, + ne_probe, ne_disable ); + +ISA_ROM("ne","NE1000/2000 and clones"); diff --git a/gpxe/src/drivers/net/phantom/phantom.c b/gpxe/src/drivers/net/phantom/phantom.c index 6c7d1fc9..1d1637d8 100644 --- a/gpxe/src/drivers/net/phantom/phantom.c +++ b/gpxe/src/drivers/net/phantom/phantom.c @@ -25,12 +25,14 @@ #include <assert.h> #include <byteswap.h> #include <gpxe/pci.h> +#include <gpxe/io.h> #include <gpxe/malloc.h> #include <gpxe/iobuf.h> #include <gpxe/netdevice.h> #include <gpxe/if_ether.h> #include <gpxe/ethernet.h> #include <gpxe/spi.h> +#include <gpxe/settings.h> #include "phantom.h" /** @@ -40,11 +42,8 @@ * */ -/** Maximum time to wait for SPI lock */ -#define PHN_SPI_LOCK_TIMEOUT_MS 100 - -/** Maximum time to wait for SPI command to be issued */ -#define PHN_SPI_CMD_TIMEOUT_MS 100 +/** Maximum number of ports */ +#define PHN_MAX_NUM_PORTS 4 /** Maximum time to wait for command PEG to initialise * @@ -71,6 +70,9 @@ /** Maximum time to wait for test memory */ #define PHN_TEST_MEM_TIMEOUT_MS 100 +/** Maximum time to wait for CLP command to be issued */ +#define PHN_CLP_CMD_TIMEOUT_MS 500 + /** Link state poll frequency * * The link state will be checked once in every N calls to poll(). @@ -105,10 +107,41 @@ struct phantom_descriptor_rings { volatile uint32_t cmd_cons; }; -/** A Phantom NIC port */ -struct phantom_nic_port { - /** Phantom NIC containing this port */ - struct phantom_nic *phantom; +/** RX context creation request and response buffers */ +struct phantom_create_rx_ctx_rqrsp { + struct { + struct nx_hostrq_rx_ctx_s rx_ctx; + struct nx_hostrq_rds_ring_s rds; + struct nx_hostrq_sds_ring_s sds; + } __unm_dma_aligned hostrq; + struct { + struct nx_cardrsp_rx_ctx_s rx_ctx; + struct nx_cardrsp_rds_ring_s rds; + struct nx_cardrsp_sds_ring_s sds; + } __unm_dma_aligned cardrsp; +}; + +/** TX context creation request and response buffers */ +struct phantom_create_tx_ctx_rqrsp { + struct { + struct nx_hostrq_tx_ctx_s tx_ctx; + } __unm_dma_aligned hostrq; + struct { + struct nx_cardrsp_tx_ctx_s tx_ctx; + } __unm_dma_aligned cardrsp; +}; + +/** A Phantom NIC */ +struct phantom_nic { + /** BAR 0 */ + void *bar0; + /** Current CRB window */ + unsigned long crb_window; + /** CRB window access method */ + unsigned long ( *crb_access ) ( struct phantom_nic *phantom, + unsigned long reg ); + + /** Port number */ unsigned int port; @@ -143,73 +176,18 @@ struct phantom_nic_port { struct io_buffer *cds_iobuf[PHN_NUM_CDS]; - /** Link state poll timer */ - unsigned long link_poll_timer; - - /** Descriptor rings */ struct phantom_descriptor_rings *desc; -}; - -/** RX context creation request and response buffers */ -struct phantom_create_rx_ctx_rqrsp { - struct { - struct nx_hostrq_rx_ctx_s rx_ctx; - struct nx_hostrq_rds_ring_s rds; - struct nx_hostrq_sds_ring_s sds; - } __unm_dma_aligned hostrq; - struct { - struct nx_cardrsp_rx_ctx_s rx_ctx; - struct nx_cardrsp_rds_ring_s rds; - struct nx_cardrsp_sds_ring_s sds; - } __unm_dma_aligned cardrsp; -}; - -/** TX context creation request and response buffers */ -struct phantom_create_tx_ctx_rqrsp { - struct { - struct nx_hostrq_tx_ctx_s tx_ctx; - } __unm_dma_aligned hostrq; - struct { - struct nx_cardrsp_tx_ctx_s tx_ctx; - } __unm_dma_aligned cardrsp; -}; - -/** A Phantom DMA buffer area */ -union phantom_dma_buffer { - /** Dummy area required for (read-only) self-tests */ - uint8_t dummy_dma[UNM_DUMMY_DMA_SIZE]; - /** RX context creation request and response buffers */ - struct phantom_create_rx_ctx_rqrsp create_rx_ctx; - /** TX context creation request and response buffers */ - struct phantom_create_tx_ctx_rqrsp create_tx_ctx; -}; - -/** A Phantom NIC */ -struct phantom_nic { - /** BAR 0 */ - void *bar0; - /** Current CRB window */ - unsigned long crb_window; - /** CRB window access method */ - unsigned long ( *crb_access ) ( struct phantom_nic *phantom, - unsigned long reg ); - - /** Number of ports */ - int num_ports; - /** Per-port network devices */ - struct net_device *netdev[UNM_FLASH_NUM_PORTS]; - /** DMA buffers */ - union phantom_dma_buffer *dma_buf; - - /** Flash memory SPI bus */ - struct spi_bus spi_bus; - /** Flash memory SPI device */ - struct spi_device flash; /** Last known link state */ uint32_t link_state; + /** Link state poll timer */ + unsigned long link_poll_timer; + + + /** Non-volatile settings */ + struct settings settings; }; /*************************************************************************** @@ -227,21 +205,8 @@ struct phantom_nic { */ static unsigned long phantom_crb_access_128m ( struct phantom_nic *phantom, unsigned long reg ) { - static const uint32_t reg_window[] = { - [UNM_CRB_BLK_PCIE] = 0x0000000, - [UNM_CRB_BLK_CAM] = 0x2000000, - [UNM_CRB_BLK_ROMUSB] = 0x2000000, - [UNM_CRB_BLK_TEST] = 0x0000000, - }; - static const uint32_t reg_bases[] = { - [UNM_CRB_BLK_PCIE] = 0x6100000, - [UNM_CRB_BLK_CAM] = 0x6200000, - [UNM_CRB_BLK_ROMUSB] = 0x7300000, - [UNM_CRB_BLK_TEST] = 0x6200000, - }; - unsigned int block = UNM_CRB_BLK ( reg ); - unsigned long offset = UNM_CRB_OFFSET ( reg ); - uint32_t window = reg_window[block]; + unsigned long offset = ( 0x6000000 + ( reg & 0x1ffffff ) ); + uint32_t window = ( reg & 0x2000000 ); uint32_t verify_window; if ( phantom->crb_window != window ) { @@ -257,7 +222,7 @@ static unsigned long phantom_crb_access_128m ( struct phantom_nic *phantom, phantom->crb_window = window; } - return ( reg_bases[block] + offset ); + return offset; } /** @@ -269,21 +234,8 @@ static unsigned long phantom_crb_access_128m ( struct phantom_nic *phantom, */ static unsigned long phantom_crb_access_32m ( struct phantom_nic *phantom, unsigned long reg ) { - static const uint32_t reg_window[] = { - [UNM_CRB_BLK_PCIE] = 0x0000000, - [UNM_CRB_BLK_CAM] = 0x2000000, - [UNM_CRB_BLK_ROMUSB] = 0x2000000, - [UNM_CRB_BLK_TEST] = 0x0000000, - }; - static const uint32_t reg_bases[] = { - [UNM_CRB_BLK_PCIE] = 0x0100000, - [UNM_CRB_BLK_CAM] = 0x0200000, - [UNM_CRB_BLK_ROMUSB] = 0x1300000, - [UNM_CRB_BLK_TEST] = 0x0200000, - }; - unsigned int block = UNM_CRB_BLK ( reg ); - unsigned long offset = UNM_CRB_OFFSET ( reg ); - uint32_t window = reg_window[block]; + unsigned long offset = ( reg & 0x1ffffff ); + uint32_t window = ( reg & 0x2000000 ); uint32_t verify_window; if ( phantom->crb_window != window ) { @@ -299,7 +251,7 @@ static unsigned long phantom_crb_access_32m ( struct phantom_nic *phantom, phantom->crb_window = window; } - return ( reg_bases[block] + offset ); + return offset; } /** @@ -311,31 +263,54 @@ static unsigned long phantom_crb_access_32m ( struct phantom_nic *phantom, */ static unsigned long phantom_crb_access_2m ( struct phantom_nic *phantom, unsigned long reg ) { - static const uint32_t reg_window_hi[] = { - [UNM_CRB_BLK_PCIE] = 0x77300000, - [UNM_CRB_BLK_CAM] = 0x41600000, - [UNM_CRB_BLK_ROMUSB] = 0x42100000, - [UNM_CRB_BLK_TEST] = 0x29500000, + static const struct { + uint8_t block; + uint16_t window_hi; + } reg_window_hi[] = { + { UNM_CRB_BLK_PCIE, 0x773 }, + { UNM_CRB_BLK_CAM, 0x416 }, + { UNM_CRB_BLK_ROMUSB, 0x421 }, + { UNM_CRB_BLK_TEST, 0x295 }, + { UNM_CRB_BLK_PEG_0, 0x340 }, + { UNM_CRB_BLK_PEG_1, 0x341 }, + { UNM_CRB_BLK_PEG_2, 0x342 }, + { UNM_CRB_BLK_PEG_3, 0x343 }, + { UNM_CRB_BLK_PEG_4, 0x34b }, }; unsigned int block = UNM_CRB_BLK ( reg ); unsigned long offset = UNM_CRB_OFFSET ( reg ); - uint32_t window = ( reg_window_hi[block] | ( offset & 0x000f0000 ) ); + uint32_t window; uint32_t verify_window; + unsigned int i; - if ( phantom->crb_window != window ) { + for ( i = 0 ; i < ( sizeof ( reg_window_hi ) / + sizeof ( reg_window_hi[0] ) ) ; i++ ) { - /* Write to the CRB window register */ - writel ( window, phantom->bar0 + UNM_2M_CRB_WINDOW ); + if ( reg_window_hi[i].block != block ) + continue; - /* Ensure that the write has reached the card */ - verify_window = readl ( phantom->bar0 + UNM_2M_CRB_WINDOW ); - assert ( verify_window == window ); + window = ( ( reg_window_hi[i].window_hi << 20 ) | + ( offset & 0x000f0000 ) ); - /* Record new window */ - phantom->crb_window = window; + if ( phantom->crb_window != window ) { + + /* Write to the CRB window register */ + writel ( window, phantom->bar0 + UNM_2M_CRB_WINDOW ); + + /* Ensure that the write has reached the card */ + verify_window = readl ( phantom->bar0 + + UNM_2M_CRB_WINDOW ); + assert ( verify_window == window ); + + /* Record new window */ + phantom->crb_window = window; + } + + return ( 0x1e0000 + ( offset & 0xffff ) ); } - return ( 0x1e0000 + ( offset & 0xffff ) ); + assert ( 0 ); + return 0; } /** @@ -401,8 +376,9 @@ static inline void phantom_write_hilo ( struct phantom_nic *phantom, * @v buf 8-byte buffer to fill * @ret rc Return status code */ -static int phantom_read_test_mem ( struct phantom_nic *phantom, - uint64_t offset, uint32_t buf[2] ) { +static int phantom_read_test_mem_block ( struct phantom_nic *phantom, + unsigned long offset, + uint32_t buf[2] ) { unsigned int retries; uint32_t test_control; @@ -429,199 +405,100 @@ static int phantom_read_test_mem ( struct phantom_nic *phantom, } /** + * Read single byte from Phantom test memory + * + * @v phantom Phantom NIC + * @v offset Offset within test memory + * @ret byte Byte read, or negative error + */ +static int phantom_read_test_mem ( struct phantom_nic *phantom, + unsigned long offset ) { + static union { + uint8_t bytes[8]; + uint32_t dwords[2]; + } cache; + static unsigned long cache_offset = -1UL; + unsigned long sub_offset; + int rc; + + sub_offset = ( offset & ( sizeof ( cache ) - 1 ) ); + offset = ( offset & ~( sizeof ( cache ) - 1 ) ); + + if ( cache_offset != offset ) { + if ( ( rc = phantom_read_test_mem_block ( phantom, offset, + cache.dwords )) !=0 ) + return rc; + cache_offset = offset; + } + + return cache.bytes[sub_offset]; +} + +/** * Dump Phantom firmware dmesg log * * @v phantom Phantom NIC * @v log Log number + * @v max_lines Maximum number of lines to show, or -1 to show all + * @ret rc Return status code */ -static void phantom_dmesg ( struct phantom_nic *phantom, unsigned int log ) { +static int phantom_dmesg ( struct phantom_nic *phantom, unsigned int log, + unsigned int max_lines ) { uint32_t head; uint32_t tail; uint32_t len; uint32_t sig; uint32_t offset; - union { - uint8_t bytes[8]; - uint32_t dwords[2]; - } buf; - unsigned int i; - int rc; + int byte; /* Optimise out for non-debug builds */ if ( ! DBG_LOG ) - return; + return 0; + /* Locate log */ head = phantom_readl ( phantom, UNM_CAM_RAM_DMESG_HEAD ( log ) ); len = phantom_readl ( phantom, UNM_CAM_RAM_DMESG_LEN ( log ) ); tail = phantom_readl ( phantom, UNM_CAM_RAM_DMESG_TAIL ( log ) ); sig = phantom_readl ( phantom, UNM_CAM_RAM_DMESG_SIG ( log ) ); - DBGC ( phantom, "Phantom %p firmware dmesg buffer %d (%08lx-%08lx)\n", + DBGC ( phantom, "Phantom %p firmware dmesg buffer %d (%08x-%08x)\n", phantom, log, head, tail ); assert ( ( head & 0x07 ) == 0 ); if ( sig != UNM_CAM_RAM_DMESG_SIG_MAGIC ) { - DBGC ( phantom, "Warning: bad signature %08lx (want %08lx)\n", + DBGC ( phantom, "Warning: bad signature %08x (want %08lx)\n", sig, UNM_CAM_RAM_DMESG_SIG_MAGIC ); } - for ( offset = head ; offset < tail ; offset += 8 ) { - if ( ( rc = phantom_read_test_mem ( phantom, offset, - buf.dwords ) ) != 0 ) { - DBGC ( phantom, "Phantom %p could not read from test " - "memory: %s\n", phantom, strerror ( rc ) ); + /* Locate start of last (max_lines) lines */ + for ( offset = tail ; offset > head ; offset-- ) { + if ( ( byte = phantom_read_test_mem ( phantom, + ( offset - 1 ) ) ) < 0 ) + return byte; + if ( ( byte == '\n' ) && ( max_lines-- == 0 ) ) break; - } - for ( i = 0 ; ( ( i < sizeof ( buf ) ) && - ( offset + i ) < tail ) ; i++ ) { - DBG ( "%c", buf.bytes[i] ); - } + } + + /* Print lines */ + for ( ; offset < tail ; offset++ ) { + if ( ( byte = phantom_read_test_mem ( phantom, offset ) ) < 0 ) + return byte; + DBG ( "%c", byte ); } DBG ( "\n" ); + return 0; } /** * Dump Phantom firmware dmesg logs * * @v phantom Phantom NIC + * @v max_lines Maximum number of lines to show, or -1 to show all */ static void __attribute__ (( unused )) -phantom_dmesg_all ( struct phantom_nic *phantom ) { +phantom_dmesg_all ( struct phantom_nic *phantom, unsigned int max_lines ) { unsigned int i; for ( i = 0 ; i < UNM_CAM_RAM_NUM_DMESG_BUFFERS ; i++ ) - phantom_dmesg ( phantom, i ); -} - -/*************************************************************************** - * - * SPI bus access (for flash memory) - * - */ - -/** - * Acquire Phantom SPI lock - * - * @v phantom Phantom NIC - * @ret rc Return status code - */ -static int phantom_spi_lock ( struct phantom_nic *phantom ) { - unsigned int retries; - uint32_t pcie_sem2_lock; - - for ( retries = 0 ; retries < PHN_SPI_LOCK_TIMEOUT_MS ; retries++ ) { - pcie_sem2_lock = phantom_readl ( phantom, UNM_PCIE_SEM2_LOCK ); - if ( pcie_sem2_lock != 0 ) - return 0; - mdelay ( 1 ); - } - - DBGC ( phantom, "Phantom %p timed out waiting for SPI lock\n", - phantom ); - return -ETIMEDOUT; -} - -/** - * Wait for Phantom SPI command to complete - * - * @v phantom Phantom NIC - * @ret rc Return status code - */ -static int phantom_spi_wait ( struct phantom_nic *phantom ) { - unsigned int retries; - uint32_t glb_status; - - for ( retries = 0 ; retries < PHN_SPI_CMD_TIMEOUT_MS ; retries++ ) { - glb_status = phantom_readl ( phantom, UNM_ROMUSB_GLB_STATUS ); - if ( glb_status & UNM_ROMUSB_GLB_STATUS_ROM_DONE ) - return 0; - mdelay ( 1 ); - } - - DBGC ( phantom, "Phantom %p timed out waiting for SPI command\n", - phantom ); - return -ETIMEDOUT; -} - -/** - * Release Phantom SPI lock - * - * @v phantom Phantom NIC - */ -static void phantom_spi_unlock ( struct phantom_nic *phantom ) { - phantom_readl ( phantom, UNM_PCIE_SEM2_UNLOCK ); -} - -/** - * Read/write data via Phantom SPI bus - * - * @v bus SPI bus - * @v device SPI device - * @v command Command - * @v address Address to read/write (<0 for no address) - * @v data_out TX data buffer (or NULL) - * @v data_in RX data buffer (or NULL) - * @v len Length of data buffer(s) - * @ret rc Return status code - */ -static int phantom_spi_rw ( struct spi_bus *bus, - struct spi_device *device, - unsigned int command, int address, - const void *data_out, void *data_in, - size_t len ) { - struct phantom_nic *phantom = - container_of ( bus, struct phantom_nic, spi_bus ); - uint32_t data; - int rc; - - DBGCP ( phantom, "Phantom %p SPI command %x at %x+%zx\n", - phantom, command, address, len ); - if ( data_out ) - DBGCP_HDA ( phantom, address, data_out, len ); - - /* We support only exactly 4-byte reads */ - if ( len != UNM_SPI_BLKSIZE ) { - DBGC ( phantom, "Phantom %p invalid SPI length %zx\n", - phantom, len ); - return -EINVAL; - } - - /* Acquire SPI lock */ - if ( ( rc = phantom_spi_lock ( phantom ) ) != 0 ) - goto err_lock; - - /* Issue SPI command as per the PRM */ - if ( data_out ) { - memcpy ( &data, data_out, sizeof ( data ) ); - phantom_writel ( phantom, data, UNM_ROMUSB_ROM_WDATA ); - } - phantom_writel ( phantom, address, UNM_ROMUSB_ROM_ADDRESS ); - phantom_writel ( phantom, ( device->address_len / 8 ), - UNM_ROMUSB_ROM_ABYTE_CNT ); - udelay ( 100 ); /* according to PRM */ - phantom_writel ( phantom, 0, UNM_ROMUSB_ROM_DUMMY_BYTE_CNT ); - phantom_writel ( phantom, command, UNM_ROMUSB_ROM_INSTR_OPCODE ); - - /* Wait for SPI command to complete */ - if ( ( rc = phantom_spi_wait ( phantom ) ) != 0 ) - goto err_wait; - - /* Reset address byte count and dummy byte count, because the - * PRM asks us to. - */ - phantom_writel ( phantom, 0, UNM_ROMUSB_ROM_ABYTE_CNT ); - udelay ( 100 ); /* according to PRM */ - phantom_writel ( phantom, 0, UNM_ROMUSB_ROM_DUMMY_BYTE_CNT ); - - /* Read data, if applicable */ - if ( data_in ) { - data = phantom_readl ( phantom, UNM_ROMUSB_ROM_RDATA ); - memcpy ( data_in, &data, sizeof ( data ) ); - DBGCP_HDA ( phantom, address, data_in, len ); - } - - err_wait: - phantom_spi_unlock ( phantom ); - err_lock: - return rc; + phantom_dmesg ( phantom, i, max_lines ); } /*************************************************************************** @@ -665,26 +542,24 @@ static int phantom_wait_for_cmd ( struct phantom_nic *phantom ) { /** * Issue command to firmware * - * @v phantom_port Phantom NIC port + * @v phantom Phantom NIC * @v command Firmware command * @v arg1 Argument 1 * @v arg2 Argument 2 * @v arg3 Argument 3 * @ret rc Return status code */ -static int phantom_issue_cmd ( struct phantom_nic_port *phantom_port, +static int phantom_issue_cmd ( struct phantom_nic *phantom, uint32_t command, uint32_t arg1, uint32_t arg2, uint32_t arg3 ) { - struct phantom_nic *phantom = phantom_port->phantom; uint32_t signature; int rc; /* Issue command */ - signature = NX_CDRP_SIGNATURE_MAKE ( phantom_port->port, + signature = NX_CDRP_SIGNATURE_MAKE ( phantom->port, NXHAL_VERSION ); - DBGC2 ( phantom, "Phantom %p port %d issuing command %08lx (%08lx, " - "%08lx, %08lx)\n", phantom, phantom_port->port, - command, arg1, arg2, arg3 ); + DBGC2 ( phantom, "Phantom %p issuing command %08x (%08x, %08x, " + "%08x)\n", phantom, command, arg1, arg2, arg3 ); phantom_writel ( phantom, signature, UNM_NIC_REG_NX_SIGN ); phantom_writel ( phantom, arg1, UNM_NIC_REG_NX_ARG1 ); phantom_writel ( phantom, arg2, UNM_NIC_REG_NX_ARG2 ); @@ -705,36 +580,41 @@ static int phantom_issue_cmd ( struct phantom_nic_port *phantom_port, /** * Issue buffer-format command to firmware * - * @v phantom_port Phantom NIC port + * @v phantom Phantom NIC * @v command Firmware command * @v buffer Buffer to pass to firmware * @v len Length of buffer * @ret rc Return status code */ -static int phantom_issue_buf_cmd ( struct phantom_nic_port *phantom_port, +static int phantom_issue_buf_cmd ( struct phantom_nic *phantom, uint32_t command, void *buffer, size_t len ) { uint64_t physaddr; physaddr = virt_to_bus ( buffer ); - return phantom_issue_cmd ( phantom_port, command, ( physaddr >> 32 ), + return phantom_issue_cmd ( phantom, command, ( physaddr >> 32 ), ( physaddr & 0xffffffffUL ), len ); } /** * Create Phantom RX context * - * @v phantom_port Phantom NIC port + * @v phantom Phantom NIC * @ret rc Return status code */ -static int phantom_create_rx_ctx ( struct phantom_nic_port *phantom_port ) { - struct phantom_nic *phantom = phantom_port->phantom; +static int phantom_create_rx_ctx ( struct phantom_nic *phantom ) { struct phantom_create_rx_ctx_rqrsp *buf; int rc; + + /* Allocate context creation buffer */ + buf = malloc_dma ( sizeof ( *buf ), UNM_DMA_BUFFER_ALIGN ); + if ( ! buf ) { + rc = -ENOMEM; + goto out; + } + memset ( buf, 0, sizeof ( *buf ) ); /* Prepare request */ - buf = &phantom->dma_buf->create_rx_ctx; - memset ( buf, 0, sizeof ( *buf ) ); buf->hostrq.rx_ctx.host_rsp_dma_addr = cpu_to_le64 ( virt_to_bus ( &buf->cardrsp ) ); buf->hostrq.rx_ctx.capabilities[0] = @@ -749,197 +629,194 @@ static int phantom_create_rx_ctx ( struct phantom_nic_port *phantom_port ) { buf->hostrq.rx_ctx.num_rds_rings = cpu_to_le16 ( 1 ); buf->hostrq.rx_ctx.num_sds_rings = cpu_to_le16 ( 1 ); buf->hostrq.rds.host_phys_addr = - cpu_to_le64 ( virt_to_bus ( phantom_port->desc->rds ) ); + cpu_to_le64 ( virt_to_bus ( phantom->desc->rds ) ); buf->hostrq.rds.buff_size = cpu_to_le64 ( PHN_RX_BUFSIZE ); buf->hostrq.rds.ring_size = cpu_to_le32 ( PHN_NUM_RDS ); buf->hostrq.rds.ring_kind = cpu_to_le32 ( NX_RDS_RING_TYPE_NORMAL ); buf->hostrq.sds.host_phys_addr = - cpu_to_le64 ( virt_to_bus ( phantom_port->desc->sds ) ); + cpu_to_le64 ( virt_to_bus ( phantom->desc->sds ) ); buf->hostrq.sds.ring_size = cpu_to_le32 ( PHN_NUM_SDS ); - DBGC ( phantom, "Phantom %p port %d creating RX context\n", - phantom, phantom_port->port ); + DBGC ( phantom, "Phantom %p creating RX context\n", phantom ); DBGC2_HDA ( phantom, virt_to_bus ( &buf->hostrq ), &buf->hostrq, sizeof ( buf->hostrq ) ); /* Issue request */ - if ( ( rc = phantom_issue_buf_cmd ( phantom_port, + if ( ( rc = phantom_issue_buf_cmd ( phantom, NX_CDRP_CMD_CREATE_RX_CTX, &buf->hostrq, sizeof ( buf->hostrq ) ) ) != 0 ) { - DBGC ( phantom, "Phantom %p port %d could not create RX " - "context: %s\n", - phantom, phantom_port->port, strerror ( rc ) ); + DBGC ( phantom, "Phantom %p could not create RX context: " + "%s\n", phantom, strerror ( rc ) ); DBGC ( phantom, "Request:\n" ); DBGC_HDA ( phantom, virt_to_bus ( &buf->hostrq ), &buf->hostrq, sizeof ( buf->hostrq ) ); DBGC ( phantom, "Response:\n" ); DBGC_HDA ( phantom, virt_to_bus ( &buf->cardrsp ), &buf->cardrsp, sizeof ( buf->cardrsp ) ); - return rc; + goto out; } /* Retrieve context parameters */ - phantom_port->rx_context_id = + phantom->rx_context_id = le16_to_cpu ( buf->cardrsp.rx_ctx.context_id ); - phantom_port->rds_producer_crb = + phantom->rds_producer_crb = ( UNM_CAM_RAM + le32_to_cpu ( buf->cardrsp.rds.host_producer_crb )); - phantom_port->sds_consumer_crb = + phantom->sds_consumer_crb = ( UNM_CAM_RAM + le32_to_cpu ( buf->cardrsp.sds.host_consumer_crb )); - DBGC ( phantom, "Phantom %p port %d created RX context (id %04x, " - "port phys %02x virt %02x)\n", phantom, phantom_port->port, - phantom_port->rx_context_id, buf->cardrsp.rx_ctx.phys_port, - buf->cardrsp.rx_ctx.virt_port ); + DBGC ( phantom, "Phantom %p created RX context (id %04x, port phys " + "%02x virt %02x)\n", phantom, phantom->rx_context_id, + buf->cardrsp.rx_ctx.phys_port, buf->cardrsp.rx_ctx.virt_port ); DBGC2_HDA ( phantom, virt_to_bus ( &buf->cardrsp ), &buf->cardrsp, sizeof ( buf->cardrsp ) ); - DBGC ( phantom, "Phantom %p port %d RDS producer CRB is %08lx\n", - phantom, phantom_port->port, phantom_port->rds_producer_crb ); - DBGC ( phantom, "Phantom %p port %d SDS consumer CRB is %08lx\n", - phantom, phantom_port->port, phantom_port->sds_consumer_crb ); + DBGC ( phantom, "Phantom %p RDS producer CRB is %08lx\n", + phantom, phantom->rds_producer_crb ); + DBGC ( phantom, "Phantom %p SDS consumer CRB is %08lx\n", + phantom, phantom->sds_consumer_crb ); - return 0; + out: + free_dma ( buf, sizeof ( *buf ) ); + return rc; } /** * Destroy Phantom RX context * - * @v phantom_port Phantom NIC port + * @v phantom Phantom NIC * @ret rc Return status code */ -static void phantom_destroy_rx_ctx ( struct phantom_nic_port *phantom_port ) { - struct phantom_nic *phantom = phantom_port->phantom; +static void phantom_destroy_rx_ctx ( struct phantom_nic *phantom ) { int rc; - DBGC ( phantom, "Phantom %p port %d destroying RX context (id %04x)\n", - phantom, phantom_port->port, phantom_port->rx_context_id ); + DBGC ( phantom, "Phantom %p destroying RX context (id %04x)\n", + phantom, phantom->rx_context_id ); /* Issue request */ - if ( ( rc = phantom_issue_cmd ( phantom_port, + if ( ( rc = phantom_issue_cmd ( phantom, NX_CDRP_CMD_DESTROY_RX_CTX, - phantom_port->rx_context_id, + phantom->rx_context_id, NX_DESTROY_CTX_RESET, 0 ) ) != 0 ) { - DBGC ( phantom, "Phantom %p port %d could not destroy RX " - "context: %s\n", - phantom, phantom_port->port, strerror ( rc ) ); + DBGC ( phantom, "Phantom %p could not destroy RX context: " + "%s\n", phantom, strerror ( rc ) ); /* We're probably screwed */ return; } /* Clear context parameters */ - phantom_port->rx_context_id = 0; - phantom_port->rds_producer_crb = 0; - phantom_port->sds_consumer_crb = 0; + phantom->rx_context_id = 0; + phantom->rds_producer_crb = 0; + phantom->sds_consumer_crb = 0; /* Reset software counters */ - phantom_port->rds_producer_idx = 0; - phantom_port->rds_consumer_idx = 0; - phantom_port->sds_consumer_idx = 0; + phantom->rds_producer_idx = 0; + phantom->rds_consumer_idx = 0; + phantom->sds_consumer_idx = 0; } /** * Create Phantom TX context * - * @v phantom_port Phantom NIC port + * @v phantom Phantom NIC * @ret rc Return status code */ -static int phantom_create_tx_ctx ( struct phantom_nic_port *phantom_port ) { - struct phantom_nic *phantom = phantom_port->phantom; +static int phantom_create_tx_ctx ( struct phantom_nic *phantom ) { struct phantom_create_tx_ctx_rqrsp *buf; int rc; - /* Prepare request */ - buf = &phantom->dma_buf->create_tx_ctx; + /* Allocate context creation buffer */ + buf = malloc_dma ( sizeof ( *buf ), UNM_DMA_BUFFER_ALIGN ); + if ( ! buf ) { + rc = -ENOMEM; + goto out; + } memset ( buf, 0, sizeof ( *buf ) ); + + /* Prepare request */ buf->hostrq.tx_ctx.host_rsp_dma_addr = cpu_to_le64 ( virt_to_bus ( &buf->cardrsp ) ); buf->hostrq.tx_ctx.cmd_cons_dma_addr = - cpu_to_le64 ( virt_to_bus ( &phantom_port->desc->cmd_cons ) ); - buf->hostrq.tx_ctx.dummy_dma_addr = - cpu_to_le64 ( virt_to_bus ( phantom->dma_buf->dummy_dma ) ); + cpu_to_le64 ( virt_to_bus ( &phantom->desc->cmd_cons ) ); buf->hostrq.tx_ctx.capabilities[0] = cpu_to_le32 ( NX_CAP0_LEGACY_CONTEXT | NX_CAP0_LEGACY_MN ); buf->hostrq.tx_ctx.host_int_crb_mode = cpu_to_le32 ( NX_HOST_INT_CRB_MODE_SHARED ); buf->hostrq.tx_ctx.cds_ring.host_phys_addr = - cpu_to_le64 ( virt_to_bus ( phantom_port->desc->cds ) ); + cpu_to_le64 ( virt_to_bus ( phantom->desc->cds ) ); buf->hostrq.tx_ctx.cds_ring.ring_size = cpu_to_le32 ( PHN_NUM_CDS ); - DBGC ( phantom, "Phantom %p port %d creating TX context\n", - phantom, phantom_port->port ); + DBGC ( phantom, "Phantom %p creating TX context\n", phantom ); DBGC2_HDA ( phantom, virt_to_bus ( &buf->hostrq ), &buf->hostrq, sizeof ( buf->hostrq ) ); /* Issue request */ - if ( ( rc = phantom_issue_buf_cmd ( phantom_port, + if ( ( rc = phantom_issue_buf_cmd ( phantom, NX_CDRP_CMD_CREATE_TX_CTX, &buf->hostrq, sizeof ( buf->hostrq ) ) ) != 0 ) { - DBGC ( phantom, "Phantom %p port %d could not create TX " - "context: %s\n", - phantom, phantom_port->port, strerror ( rc ) ); + DBGC ( phantom, "Phantom %p could not create TX context: " + "%s\n", phantom, strerror ( rc ) ); DBGC ( phantom, "Request:\n" ); DBGC_HDA ( phantom, virt_to_bus ( &buf->hostrq ), &buf->hostrq, sizeof ( buf->hostrq ) ); DBGC ( phantom, "Response:\n" ); DBGC_HDA ( phantom, virt_to_bus ( &buf->cardrsp ), &buf->cardrsp, sizeof ( buf->cardrsp ) ); - return rc; + goto out; } /* Retrieve context parameters */ - phantom_port->tx_context_id = + phantom->tx_context_id = le16_to_cpu ( buf->cardrsp.tx_ctx.context_id ); - phantom_port->cds_producer_crb = + phantom->cds_producer_crb = ( UNM_CAM_RAM + le32_to_cpu(buf->cardrsp.tx_ctx.cds_ring.host_producer_crb)); - DBGC ( phantom, "Phantom %p port %d created TX context (id %04x, " - "port phys %02x virt %02x)\n", phantom, phantom_port->port, - phantom_port->tx_context_id, buf->cardrsp.tx_ctx.phys_port, - buf->cardrsp.tx_ctx.virt_port ); + DBGC ( phantom, "Phantom %p created TX context (id %04x, port phys " + "%02x virt %02x)\n", phantom, phantom->tx_context_id, + buf->cardrsp.tx_ctx.phys_port, buf->cardrsp.tx_ctx.virt_port ); DBGC2_HDA ( phantom, virt_to_bus ( &buf->cardrsp ), &buf->cardrsp, sizeof ( buf->cardrsp ) ); - DBGC ( phantom, "Phantom %p port %d CDS producer CRB is %08lx\n", - phantom, phantom_port->port, phantom_port->cds_producer_crb ); + DBGC ( phantom, "Phantom %p CDS producer CRB is %08lx\n", + phantom, phantom->cds_producer_crb ); - return 0; + out: + free_dma ( buf, sizeof ( *buf ) ); + return rc; } /** * Destroy Phantom TX context * - * @v phantom_port Phantom NIC port + * @v phantom Phantom NIC * @ret rc Return status code */ -static void phantom_destroy_tx_ctx ( struct phantom_nic_port *phantom_port ) { - struct phantom_nic *phantom = phantom_port->phantom; +static void phantom_destroy_tx_ctx ( struct phantom_nic *phantom ) { int rc; - DBGC ( phantom, "Phantom %p port %d destroying TX context (id %04x)\n", - phantom, phantom_port->port, phantom_port->tx_context_id ); + DBGC ( phantom, "Phantom %p destroying TX context (id %04x)\n", + phantom, phantom->tx_context_id ); /* Issue request */ - if ( ( rc = phantom_issue_cmd ( phantom_port, + if ( ( rc = phantom_issue_cmd ( phantom, NX_CDRP_CMD_DESTROY_TX_CTX, - phantom_port->tx_context_id, + phantom->tx_context_id, NX_DESTROY_CTX_RESET, 0 ) ) != 0 ) { - DBGC ( phantom, "Phantom %p port %d could not destroy TX " - "context: %s\n", - phantom, phantom_port->port, strerror ( rc ) ); + DBGC ( phantom, "Phantom %p could not destroy TX context: " + "%s\n", phantom, strerror ( rc ) ); /* We're probably screwed */ return; } /* Clear context parameters */ - phantom_port->tx_context_id = 0; - phantom_port->cds_producer_crb = 0; + phantom->tx_context_id = 0; + phantom->cds_producer_crb = 0; /* Reset software counters */ - phantom_port->cds_producer_idx = 0; - phantom_port->cds_consumer_idx = 0; + phantom->cds_producer_idx = 0; + phantom->cds_consumer_idx = 0; } /*************************************************************************** @@ -951,11 +828,10 @@ static void phantom_destroy_tx_ctx ( struct phantom_nic_port *phantom_port ) { /** * Allocate Phantom RX descriptor * - * @v phantom_port Phantom NIC port + * @v phantom Phantom NIC * @ret index RX descriptor index, or negative error */ -static int phantom_alloc_rds ( struct phantom_nic_port *phantom_port ) { - struct phantom_nic *phantom = phantom_port->phantom; +static int phantom_alloc_rds ( struct phantom_nic *phantom ) { unsigned int rds_producer_idx; unsigned int next_rds_producer_idx; @@ -965,12 +841,11 @@ static int phantom_alloc_rds ( struct phantom_nic_port *phantom_port ) { * guaranteed never to be an overestimate of the number of * descriptors read by the hardware. */ - rds_producer_idx = phantom_port->rds_producer_idx; + rds_producer_idx = phantom->rds_producer_idx; next_rds_producer_idx = ( ( rds_producer_idx + 1 ) % PHN_NUM_RDS ); - if ( next_rds_producer_idx == phantom_port->rds_consumer_idx ) { - DBGC ( phantom, "Phantom %p port %d RDS ring full (index %d " - "not consumed)\n", phantom, phantom_port->port, - next_rds_producer_idx ); + if ( next_rds_producer_idx == phantom->rds_consumer_idx ) { + DBGC ( phantom, "Phantom %p RDS ring full (index %d not " + "consumed)\n", phantom, next_rds_producer_idx ); return -ENOBUFS; } @@ -980,41 +855,38 @@ static int phantom_alloc_rds ( struct phantom_nic_port *phantom_port ) { /** * Post Phantom RX descriptor * - * @v phantom_port Phantom NIC port + * @v phantom Phantom NIC * @v rds RX descriptor */ -static void phantom_post_rds ( struct phantom_nic_port *phantom_port, +static void phantom_post_rds ( struct phantom_nic *phantom, struct phantom_rds *rds ) { - struct phantom_nic *phantom = phantom_port->phantom; unsigned int rds_producer_idx; unsigned int next_rds_producer_idx; struct phantom_rds *entry; /* Copy descriptor to ring */ - rds_producer_idx = phantom_port->rds_producer_idx; - entry = &phantom_port->desc->rds[rds_producer_idx]; + rds_producer_idx = phantom->rds_producer_idx; + entry = &phantom->desc->rds[rds_producer_idx]; memcpy ( entry, rds, sizeof ( *entry ) ); - DBGC2 ( phantom, "Phantom %p port %d posting RDS %ld (slot %d):\n", - phantom, phantom_port->port, NX_GET ( rds, handle ), - rds_producer_idx ); + DBGC2 ( phantom, "Phantom %p posting RDS %ld (slot %d):\n", + phantom, NX_GET ( rds, handle ), rds_producer_idx ); DBGC2_HDA ( phantom, virt_to_bus ( entry ), entry, sizeof ( *entry ) ); /* Update producer index */ next_rds_producer_idx = ( ( rds_producer_idx + 1 ) % PHN_NUM_RDS ); - phantom_port->rds_producer_idx = next_rds_producer_idx; + phantom->rds_producer_idx = next_rds_producer_idx; wmb(); - phantom_writel ( phantom, phantom_port->rds_producer_idx, - phantom_port->rds_producer_crb ); + phantom_writel ( phantom, phantom->rds_producer_idx, + phantom->rds_producer_crb ); } /** * Allocate Phantom TX descriptor * - * @v phantom_port Phantom NIC port + * @v phantom Phantom NIC * @ret index TX descriptor index, or negative error */ -static int phantom_alloc_cds ( struct phantom_nic_port *phantom_port ) { - struct phantom_nic *phantom = phantom_port->phantom; +static int phantom_alloc_cds ( struct phantom_nic *phantom ) { unsigned int cds_producer_idx; unsigned int next_cds_producer_idx; @@ -1022,12 +894,11 @@ static int phantom_alloc_cds ( struct phantom_nic_port *phantom_port ) { * in strict order, so we just check for a collision against * the consumer index. */ - cds_producer_idx = phantom_port->cds_producer_idx; + cds_producer_idx = phantom->cds_producer_idx; next_cds_producer_idx = ( ( cds_producer_idx + 1 ) % PHN_NUM_CDS ); - if ( next_cds_producer_idx == phantom_port->cds_consumer_idx ) { - DBGC ( phantom, "Phantom %p port %d CDS ring full (index %d " - "not consumed)\n", phantom, phantom_port->port, - next_cds_producer_idx ); + if ( next_cds_producer_idx == phantom->cds_consumer_idx ) { + DBGC ( phantom, "Phantom %p CDS ring full (index %d not " + "consumed)\n", phantom, next_cds_producer_idx ); return -ENOBUFS; } @@ -1037,30 +908,29 @@ static int phantom_alloc_cds ( struct phantom_nic_port *phantom_port ) { /** * Post Phantom TX descriptor * - * @v phantom_port Phantom NIC port + * @v phantom Phantom NIC * @v cds TX descriptor */ -static void phantom_post_cds ( struct phantom_nic_port *phantom_port, +static void phantom_post_cds ( struct phantom_nic *phantom, union phantom_cds *cds ) { - struct phantom_nic *phantom = phantom_port->phantom; unsigned int cds_producer_idx; unsigned int next_cds_producer_idx; union phantom_cds *entry; /* Copy descriptor to ring */ - cds_producer_idx = phantom_port->cds_producer_idx; - entry = &phantom_port->desc->cds[cds_producer_idx]; + cds_producer_idx = phantom->cds_producer_idx; + entry = &phantom->desc->cds[cds_producer_idx]; memcpy ( entry, cds, sizeof ( *entry ) ); - DBGC2 ( phantom, "Phantom %p port %d posting CDS %d:\n", - phantom, phantom_port->port, cds_producer_idx ); + DBGC2 ( phantom, "Phantom %p posting CDS %d:\n", + phantom, cds_producer_idx ); DBGC2_HDA ( phantom, virt_to_bus ( entry ), entry, sizeof ( *entry ) ); /* Update producer index */ next_cds_producer_idx = ( ( cds_producer_idx + 1 ) % PHN_NUM_CDS ); - phantom_port->cds_producer_idx = next_cds_producer_idx; + phantom->cds_producer_idx = next_cds_producer_idx; wmb(); - phantom_writel ( phantom, phantom_port->cds_producer_idx, - phantom_port->cds_producer_crb ); + phantom_writel ( phantom, phantom->cds_producer_idx, + phantom->cds_producer_crb ); } /*************************************************************************** @@ -1072,19 +942,19 @@ static void phantom_post_cds ( struct phantom_nic_port *phantom_port, /** * Add/remove MAC address * - * @v phantom_port Phantom NIC port + * @v phantom Phantom NIC * @v ll_addr MAC address to add or remove * @v opcode MAC request opcode * @ret rc Return status code */ -static int phantom_update_macaddr ( struct phantom_nic_port *phantom_port, +static int phantom_update_macaddr ( struct phantom_nic *phantom, const uint8_t *ll_addr, unsigned int opcode ) { union phantom_cds cds; int index; /* Get descriptor ring entry */ - index = phantom_alloc_cds ( phantom_port ); + index = phantom_alloc_cds ( phantom ); if ( index < 0 ) return index; @@ -1094,7 +964,7 @@ static int phantom_update_macaddr ( struct phantom_nic_port *phantom_port, nic_request.common.opcode, UNM_NIC_REQUEST ); NX_FILL_2 ( &cds, 1, nic_request.header.opcode, UNM_MAC_EVENT, - nic_request.header.context_id, phantom_port->port ); + nic_request.header.context_id, phantom->port ); NX_FILL_7 ( &cds, 2, nic_request.body.mac_request.opcode, opcode, nic_request.body.mac_request.mac_addr_0, ll_addr[0], @@ -1105,7 +975,7 @@ static int phantom_update_macaddr ( struct phantom_nic_port *phantom_port, nic_request.body.mac_request.mac_addr_5, ll_addr[5] ); /* Post descriptor */ - phantom_post_cds ( phantom_port, &cds ); + phantom_post_cds ( phantom, &cds ); return 0; } @@ -1113,35 +983,33 @@ static int phantom_update_macaddr ( struct phantom_nic_port *phantom_port, /** * Add MAC address * - * @v phantom_port Phantom NIC port + * @v phantom Phantom NIC * @v ll_addr MAC address to add or remove * @ret rc Return status code */ -static inline int phantom_add_macaddr ( struct phantom_nic_port *phantom_port, +static inline int phantom_add_macaddr ( struct phantom_nic *phantom, const uint8_t *ll_addr ) { - struct phantom_nic *phantom = phantom_port->phantom; - DBGC ( phantom, "Phantom %p port %d adding MAC address %s\n", - phantom, phantom_port->port, eth_ntoa ( ll_addr ) ); + DBGC ( phantom, "Phantom %p adding MAC address %s\n", + phantom, eth_ntoa ( ll_addr ) ); - return phantom_update_macaddr ( phantom_port, ll_addr, UNM_MAC_ADD ); + return phantom_update_macaddr ( phantom, ll_addr, UNM_MAC_ADD ); } /** * Remove MAC address * - * @v phantom_port Phantom NIC port + * @v phantom Phantom NIC * @v ll_addr MAC address to add or remove * @ret rc Return status code */ -static inline int phantom_del_macaddr ( struct phantom_nic_port *phantom_port, +static inline int phantom_del_macaddr ( struct phantom_nic *phantom, const uint8_t *ll_addr ) { - struct phantom_nic *phantom = phantom_port->phantom; - DBGC ( phantom, "Phantom %p port %d removing MAC address %s\n", - phantom, phantom_port->port, eth_ntoa ( ll_addr ) ); + DBGC ( phantom, "Phantom %p removing MAC address %s\n", + phantom, eth_ntoa ( ll_addr ) ); - return phantom_update_macaddr ( phantom_port, ll_addr, UNM_MAC_DEL ); + return phantom_update_macaddr ( phantom, ll_addr, UNM_MAC_DEL ); } /*************************************************************************** @@ -1153,14 +1021,12 @@ static inline int phantom_del_macaddr ( struct phantom_nic_port *phantom_port, /** * Poll link state * - * @v phantom Phantom NIC + * @v netdev Network device */ -static void phantom_poll_link_state ( struct phantom_nic *phantom ) { - struct net_device *netdev; - struct phantom_nic_port *phantom_port; +static void phantom_poll_link_state ( struct net_device *netdev ) { + struct phantom_nic *phantom = netdev_priv ( netdev ); uint32_t xg_state_p3; unsigned int link; - int i; /* Read link state */ xg_state_p3 = phantom_readl ( phantom, UNM_NIC_REG_XG_STATE_P3 ); @@ -1170,32 +1036,26 @@ static void phantom_poll_link_state ( struct phantom_nic *phantom ) { return; /* Record new link state */ - DBGC ( phantom, "Phantom %p new link state %08lx (was %08lx)\n", + DBGC ( phantom, "Phantom %p new link state %08x (was %08x)\n", phantom, xg_state_p3, phantom->link_state ); phantom->link_state = xg_state_p3; - /* Indicate per-port link state to gPXE */ - for ( i = 0 ; i < phantom->num_ports ; i++ ) { - netdev = phantom->netdev[i]; - phantom_port = netdev_priv ( netdev ); - link = UNM_NIC_REG_XG_STATE_P3_LINK ( phantom_port->port, - phantom->link_state ); - switch ( link ) { - case UNM_NIC_REG_XG_STATE_P3_LINK_UP: - DBGC ( phantom, "Phantom %p port %d link is up\n", - phantom, phantom_port->port ); - netdev_link_up ( netdev ); - break; - case UNM_NIC_REG_XG_STATE_P3_LINK_DOWN: - DBGC ( phantom, "Phantom %p port %d link is down\n", - phantom, phantom_port->port ); - netdev_link_down ( netdev ); - break; - default: - DBGC ( phantom, "Phantom %p port %d bad link state " - "%d\n", phantom, phantom_port->port, link ); - break; - } + /* Indicate link state to gPXE */ + link = UNM_NIC_REG_XG_STATE_P3_LINK ( phantom->port, + phantom->link_state ); + switch ( link ) { + case UNM_NIC_REG_XG_STATE_P3_LINK_UP: + DBGC ( phantom, "Phantom %p link is up\n", phantom ); + netdev_link_up ( netdev ); + break; + case UNM_NIC_REG_XG_STATE_P3_LINK_DOWN: + DBGC ( phantom, "Phantom %p link is down\n", phantom ); + netdev_link_down ( netdev ); + break; + default: + DBGC ( phantom, "Phantom %p bad link state %d\n", + phantom, link ); + break; } } @@ -1211,7 +1071,7 @@ static void phantom_poll_link_state ( struct phantom_nic *phantom ) { * @v netdev Net device */ static void phantom_refill_rx_ring ( struct net_device *netdev ) { - struct phantom_nic_port *phantom_port = netdev_priv ( netdev ); + struct phantom_nic *phantom = netdev_priv ( netdev ); struct io_buffer *iobuf; struct phantom_rds rds; unsigned int handle; @@ -1222,11 +1082,11 @@ static void phantom_refill_rx_ring ( struct net_device *netdev ) { /* Skip this index if the descriptor has not yet been * consumed. */ - if ( phantom_port->rds_iobuf[handle] != NULL ) + if ( phantom->rds_iobuf[handle] != NULL ) continue; /* Allocate descriptor ring entry */ - index = phantom_alloc_rds ( phantom_port ); + index = phantom_alloc_rds ( phantom ); assert ( PHN_RDS_MAX_FILL < PHN_NUM_RDS ); assert ( index >= 0 ); /* Guaranteed by MAX_FILL < NUM_RDS ) */ @@ -1247,11 +1107,11 @@ static void phantom_refill_rx_ring ( struct net_device *netdev ) { dma_addr, virt_to_bus ( iobuf->data ) ); /* Record I/O buffer */ - assert ( phantom_port->rds_iobuf[handle] == NULL ); - phantom_port->rds_iobuf[handle] = iobuf; + assert ( phantom->rds_iobuf[handle] == NULL ); + phantom->rds_iobuf[handle] = iobuf; /* Post descriptor */ - phantom_post_rds ( phantom_port, &rds ); + phantom_post_rds ( phantom, &rds ); } } @@ -1262,24 +1122,24 @@ static void phantom_refill_rx_ring ( struct net_device *netdev ) { * @ret rc Return status code */ static int phantom_open ( struct net_device *netdev ) { - struct phantom_nic_port *phantom_port = netdev_priv ( netdev ); + struct phantom_nic *phantom = netdev_priv ( netdev ); int rc; /* Allocate and zero descriptor rings */ - phantom_port->desc = malloc_dma ( sizeof ( *(phantom_port->desc) ), + phantom->desc = malloc_dma ( sizeof ( *(phantom->desc) ), UNM_DMA_BUFFER_ALIGN ); - if ( ! phantom_port->desc ) { + if ( ! phantom->desc ) { rc = -ENOMEM; goto err_alloc_desc; } - memset ( phantom_port->desc, 0, sizeof ( *(phantom_port->desc) ) ); + memset ( phantom->desc, 0, sizeof ( *(phantom->desc) ) ); /* Create RX context */ - if ( ( rc = phantom_create_rx_ctx ( phantom_port ) ) != 0 ) + if ( ( rc = phantom_create_rx_ctx ( phantom ) ) != 0 ) goto err_create_rx_ctx; /* Create TX context */ - if ( ( rc = phantom_create_tx_ctx ( phantom_port ) ) != 0 ) + if ( ( rc = phantom_create_tx_ctx ( phantom ) ) != 0 ) goto err_create_tx_ctx; /* Fill the RX descriptor ring */ @@ -1293,26 +1153,26 @@ static int phantom_open ( struct net_device *netdev ) { * packets (or, failing that, promiscuous mode), but the * firmware doesn't currently support this. */ - if ( ( rc = phantom_add_macaddr ( phantom_port, + if ( ( rc = phantom_add_macaddr ( phantom, netdev->ll_protocol->ll_broadcast ) ) != 0 ) goto err_add_macaddr_broadcast; - if ( ( rc = phantom_add_macaddr ( phantom_port, + if ( ( rc = phantom_add_macaddr ( phantom, netdev->ll_addr ) ) != 0 ) goto err_add_macaddr_unicast; return 0; - phantom_del_macaddr ( phantom_port, netdev->ll_addr ); + phantom_del_macaddr ( phantom, netdev->ll_addr ); err_add_macaddr_unicast: - phantom_del_macaddr ( phantom_port, + phantom_del_macaddr ( phantom, netdev->ll_protocol->ll_broadcast ); err_add_macaddr_broadcast: - phantom_destroy_tx_ctx ( phantom_port ); + phantom_destroy_tx_ctx ( phantom ); err_create_tx_ctx: - phantom_destroy_rx_ctx ( phantom_port ); + phantom_destroy_rx_ctx ( phantom ); err_create_rx_ctx: - free_dma ( phantom_port->desc, sizeof ( *(phantom_port->desc) ) ); - phantom_port->desc = NULL; + free_dma ( phantom->desc, sizeof ( *(phantom->desc) ) ); + phantom->desc = NULL; err_alloc_desc: return rc; } @@ -1323,32 +1183,32 @@ static int phantom_open ( struct net_device *netdev ) { * @v netdev Net device */ static void phantom_close ( struct net_device *netdev ) { - struct phantom_nic_port *phantom_port = netdev_priv ( netdev ); + struct phantom_nic *phantom = netdev_priv ( netdev ); struct io_buffer *iobuf; unsigned int i; /* Shut down the port */ - phantom_del_macaddr ( phantom_port, netdev->ll_addr ); - phantom_del_macaddr ( phantom_port, + phantom_del_macaddr ( phantom, netdev->ll_addr ); + phantom_del_macaddr ( phantom, netdev->ll_protocol->ll_broadcast ); - phantom_destroy_tx_ctx ( phantom_port ); - phantom_destroy_rx_ctx ( phantom_port ); - free_dma ( phantom_port->desc, sizeof ( *(phantom_port->desc) ) ); - phantom_port->desc = NULL; + phantom_destroy_tx_ctx ( phantom ); + phantom_destroy_rx_ctx ( phantom ); + free_dma ( phantom->desc, sizeof ( *(phantom->desc) ) ); + phantom->desc = NULL; /* Flush any uncompleted descriptors */ for ( i = 0 ; i < PHN_RDS_MAX_FILL ; i++ ) { - iobuf = phantom_port->rds_iobuf[i]; + iobuf = phantom->rds_iobuf[i]; if ( iobuf ) { free_iob ( iobuf ); - phantom_port->rds_iobuf[i] = NULL; + phantom->rds_iobuf[i] = NULL; } } for ( i = 0 ; i < PHN_NUM_CDS ; i++ ) { - iobuf = phantom_port->cds_iobuf[i]; + iobuf = phantom->cds_iobuf[i]; if ( iobuf ) { netdev_tx_complete_err ( netdev, iobuf, -ECANCELED ); - phantom_port->cds_iobuf[i] = NULL; + phantom->cds_iobuf[i] = NULL; } } } @@ -1362,12 +1222,12 @@ static void phantom_close ( struct net_device *netdev ) { */ static int phantom_transmit ( struct net_device *netdev, struct io_buffer *iobuf ) { - struct phantom_nic_port *phantom_port = netdev_priv ( netdev ); + struct phantom_nic *phantom = netdev_priv ( netdev ); union phantom_cds cds; int index; /* Get descriptor ring entry */ - index = phantom_alloc_cds ( phantom_port ); + index = phantom_alloc_cds ( phantom ); if ( index < 0 ) return index; @@ -1378,19 +1238,19 @@ static int phantom_transmit ( struct net_device *netdev, tx.num_buffers, 1, tx.length, iob_len ( iobuf ) ); NX_FILL_2 ( &cds, 2, - tx.port, phantom_port->port, - tx.context_id, phantom_port->port ); + tx.port, phantom->port, + tx.context_id, phantom->port ); NX_FILL_1 ( &cds, 4, tx.buffer1_dma_addr, virt_to_bus ( iobuf->data ) ); NX_FILL_1 ( &cds, 5, tx.buffer1_length, iob_len ( iobuf ) ); /* Record I/O buffer */ - assert ( phantom_port->cds_iobuf[index] == NULL ); - phantom_port->cds_iobuf[index] = iobuf; + assert ( phantom->cds_iobuf[index] == NULL ); + phantom->cds_iobuf[index] = iobuf; /* Post descriptor */ - phantom_post_cds ( phantom_port, &cds ); + phantom_post_cds ( phantom, &cds ); return 0; } @@ -1401,8 +1261,7 @@ static int phantom_transmit ( struct net_device *netdev, * @v netdev Network device */ static void phantom_poll ( struct net_device *netdev ) { - struct phantom_nic_port *phantom_port = netdev_priv ( netdev ); - struct phantom_nic *phantom = phantom_port->phantom; + struct phantom_nic *phantom = netdev_priv ( netdev ); struct io_buffer *iobuf; unsigned int cds_consumer_idx; unsigned int raw_new_cds_consumer_idx; @@ -1414,33 +1273,33 @@ static void phantom_poll ( struct net_device *netdev ) { unsigned int sds_opcode; /* Check for TX completions */ - cds_consumer_idx = phantom_port->cds_consumer_idx; - raw_new_cds_consumer_idx = phantom_port->desc->cmd_cons; + cds_consumer_idx = phantom->cds_consumer_idx; + raw_new_cds_consumer_idx = phantom->desc->cmd_cons; new_cds_consumer_idx = le32_to_cpu ( raw_new_cds_consumer_idx ); while ( cds_consumer_idx != new_cds_consumer_idx ) { - DBGC2 ( phantom, "Phantom %p port %d CDS %d complete\n", - phantom, phantom_port->port, cds_consumer_idx ); + DBGC2 ( phantom, "Phantom %p CDS %d complete\n", + phantom, cds_consumer_idx ); /* Completions may be for commands other than TX, so * there may not always be an associated I/O buffer. */ - if ( ( iobuf = phantom_port->cds_iobuf[cds_consumer_idx] ) ) { + if ( ( iobuf = phantom->cds_iobuf[cds_consumer_idx] ) ) { netdev_tx_complete ( netdev, iobuf ); - phantom_port->cds_iobuf[cds_consumer_idx] = NULL; + phantom->cds_iobuf[cds_consumer_idx] = NULL; } cds_consumer_idx = ( ( cds_consumer_idx + 1 ) % PHN_NUM_CDS ); - phantom_port->cds_consumer_idx = cds_consumer_idx; + phantom->cds_consumer_idx = cds_consumer_idx; } /* Check for received packets */ - rds_consumer_idx = phantom_port->rds_consumer_idx; - sds_consumer_idx = phantom_port->sds_consumer_idx; + rds_consumer_idx = phantom->rds_consumer_idx; + sds_consumer_idx = phantom->sds_consumer_idx; while ( 1 ) { - sds = &phantom_port->desc->sds[sds_consumer_idx]; + sds = &phantom->desc->sds[sds_consumer_idx]; if ( NX_GET ( sds, owner ) == 0 ) break; - DBGC2 ( phantom, "Phantom %p port %d SDS %d status:\n", - phantom, phantom_port->port, sds_consumer_idx ); + DBGC2 ( phantom, "Phantom %p SDS %d status:\n", + phantom, sds_consumer_idx ); DBGC2_HDA ( phantom, virt_to_bus ( sds ), sds, sizeof (*sds) ); /* Check received opcode */ @@ -1452,24 +1311,23 @@ static void phantom_poll ( struct net_device *netdev ) { * descriptor has been written. */ if ( NX_GET ( sds, total_length ) == 0 ) { - DBGC ( phantom, "Phantom %p port %d SDS %d " - "incomplete; deferring\n", phantom, - phantom_port->port, sds_consumer_idx ); + DBGC ( phantom, "Phantom %p SDS %d " + "incomplete; deferring\n", + phantom, sds_consumer_idx ); /* Leave for next poll() */ break; } /* Process received packet */ sds_handle = NX_GET ( sds, handle ); - iobuf = phantom_port->rds_iobuf[sds_handle]; + iobuf = phantom->rds_iobuf[sds_handle]; assert ( iobuf != NULL ); iob_put ( iobuf, NX_GET ( sds, total_length ) ); iob_pull ( iobuf, NX_GET ( sds, pkt_offset ) ); - DBGC2 ( phantom, "Phantom %p port %d RDS %d " - "complete\n", - phantom, phantom_port->port, sds_handle ); + DBGC2 ( phantom, "Phantom %p RDS %d complete\n", + phantom, sds_handle ); netdev_rx ( netdev, iobuf ); - phantom_port->rds_iobuf[sds_handle] = NULL; + phantom->rds_iobuf[sds_handle] = NULL; /* Update RDS consumer counter. This is a * lower bound for the number of descriptors @@ -1480,13 +1338,12 @@ static void phantom_poll ( struct net_device *netdev ) { */ rds_consumer_idx = ( ( rds_consumer_idx + 1 ) % PHN_NUM_RDS ); - phantom_port->rds_consumer_idx = rds_consumer_idx; + phantom->rds_consumer_idx = rds_consumer_idx; } else { - DBGC ( phantom, "Phantom %p port %d unexpected SDS " - "opcode %02x\n", - phantom, phantom_port->port, sds_opcode ); + DBGC ( phantom, "Phantom %p unexpected SDS opcode " + "%02x\n", phantom, sds_opcode ); DBGC_HDA ( phantom, virt_to_bus ( sds ), sds, sizeof ( *sds ) ); } @@ -1496,20 +1353,20 @@ static void phantom_poll ( struct net_device *netdev ) { /* Update SDS consumer index */ sds_consumer_idx = ( ( sds_consumer_idx + 1 ) % PHN_NUM_SDS ); - phantom_port->sds_consumer_idx = sds_consumer_idx; + phantom->sds_consumer_idx = sds_consumer_idx; wmb(); - phantom_writel ( phantom, phantom_port->sds_consumer_idx, - phantom_port->sds_consumer_crb ); + phantom_writel ( phantom, phantom->sds_consumer_idx, + phantom->sds_consumer_crb ); } /* Refill the RX descriptor ring */ phantom_refill_rx_ring ( netdev ); /* Occasionally poll the link state */ - if ( phantom_port->link_poll_timer-- == 0 ) { - phantom_poll_link_state ( phantom ); + if ( phantom->link_poll_timer-- == 0 ) { + phantom_poll_link_state ( netdev ); /* Reset the link poll timer */ - phantom_port->link_poll_timer = PHN_LINK_POLL_FREQUENCY; + phantom->link_poll_timer = PHN_LINK_POLL_FREQUENCY; } } @@ -1520,9 +1377,8 @@ static void phantom_poll ( struct net_device *netdev ) { * @v enable Interrupts should be enabled */ static void phantom_irq ( struct net_device *netdev, int enable ) { - struct phantom_nic_port *phantom_port = netdev_priv ( netdev ); - struct phantom_nic *phantom = phantom_port->phantom; - static const unsigned long sw_int_mask_reg[UNM_FLASH_NUM_PORTS] = { + struct phantom_nic *phantom = netdev_priv ( netdev ); + static const unsigned long sw_int_mask_reg[PHN_MAX_NUM_PORTS] = { UNM_NIC_REG_SW_INT_MASK_0, UNM_NIC_REG_SW_INT_MASK_1, UNM_NIC_REG_SW_INT_MASK_2, @@ -1531,7 +1387,7 @@ static void phantom_irq ( struct net_device *netdev, int enable ) { phantom_writel ( phantom, ( enable ? 1 : 0 ), - sw_int_mask_reg[phantom_port->port] ); + sw_int_mask_reg[phantom->port] ); } /** Phantom net device operations */ @@ -1543,6 +1399,336 @@ static struct net_device_operations phantom_operations = { .irq = phantom_irq, }; +/*************************************************************************** + * + * CLP settings + * + */ + +/** 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 data + * + */ +union phantom_clp_data { + /** Data bytes + * + * This field is right-aligned; if only N bytes are present + * then bytes[0]..bytes[7-N] should be zero, and the data + * should be in bytes[7-N+1] to bytes[7]; + */ + uint8_t bytes[8]; + /** Dwords for the CLP interface */ + struct { + /** High dword, in network byte order */ + uint32_t hi; + /** Low dword, in network byte order */ + uint32_t lo; + } dwords; +}; +#define PHN_CLP_BLKSIZE ( sizeof ( union phantom_clp_data ) ) + +/** + * Wait for Phantom CLP command to complete + * + * @v phantom Phantom NIC + * @ret rc Return status code + */ +static int phantom_clp_wait ( struct phantom_nic *phantom ) { + unsigned int retries; + uint32_t status; + + for ( retries = 0 ; retries < PHN_CLP_CMD_TIMEOUT_MS ; retries++ ) { + status = phantom_readl ( phantom, UNM_CAM_RAM_CLP_STATUS ); + if ( status & UNM_CAM_RAM_CLP_STATUS_DONE ) + return 0; + mdelay ( 1 ); + } + + DBGC ( phantom, "Phantom %p timed out waiting for CLP command\n", + phantom ); + return -ETIMEDOUT; +} + +/** + * Issue Phantom CLP command + * + * @v phantom Phantom NIC + * @v port Virtual port number + * @v opcode Opcode + * @v data_in Data in, or NULL + * @v data_out Data out, or NULL + * @v offset Offset within data + * @v len Data buffer length + * @ret len Total transfer length (for reads), or negative error + */ +static int phantom_clp_cmd ( struct phantom_nic *phantom, unsigned int port, + unsigned int opcode, const void *data_in, + void *data_out, size_t offset, size_t len ) { + union phantom_clp_data data; + unsigned int index = ( offset / sizeof ( data ) ); + unsigned int last = 0; + size_t in_frag_len; + uint8_t *in_frag; + uint32_t command; + uint32_t status; + size_t read_len; + unsigned int error; + size_t out_frag_len; + uint8_t *out_frag; + int rc; + + /* Sanity checks */ + assert ( ( offset % sizeof ( data ) ) == 0 ); + if ( len > 255 ) { + DBGC ( phantom, "Phantom %p invalid CLP length %zd\n", + phantom, len ); + return -EINVAL; + } + + /* Check that CLP interface is ready */ + if ( ( rc = phantom_clp_wait ( phantom ) ) != 0 ) + return rc; + + /* Copy data in */ + memset ( &data, 0, sizeof ( data ) ); + if ( data_in ) { + assert ( offset < len ); + in_frag_len = ( len - offset ); + if ( in_frag_len > sizeof ( data ) ) { + in_frag_len = sizeof ( data ); + } else { + last = 1; + } + in_frag = &data.bytes[ sizeof ( data ) - in_frag_len ]; + memcpy ( in_frag, ( data_in + offset ), in_frag_len ); + phantom_writel ( phantom, be32_to_cpu ( data.dwords.lo ), + UNM_CAM_RAM_CLP_DATA_LO ); + phantom_writel ( phantom, be32_to_cpu ( data.dwords.hi ), + UNM_CAM_RAM_CLP_DATA_HI ); + } + + /* Issue CLP command */ + command = ( ( index << 24 ) | ( ( data_in ? len : 0 ) << 16 ) | + ( port << 8 ) | ( last << 7 ) | ( opcode << 0 ) ); + phantom_writel ( phantom, command, UNM_CAM_RAM_CLP_COMMAND ); + mb(); + phantom_writel ( phantom, UNM_CAM_RAM_CLP_STATUS_START, + UNM_CAM_RAM_CLP_STATUS ); + + /* Wait for command to complete */ + if ( ( rc = phantom_clp_wait ( phantom ) ) != 0 ) + return rc; + + /* Get command status */ + status = phantom_readl ( phantom, UNM_CAM_RAM_CLP_STATUS ); + read_len = ( ( status >> 16 ) & 0xff ); + error = ( ( status >> 8 ) & 0xff ); + if ( error ) { + DBGC ( phantom, "Phantom %p CLP command error %02x\n", + phantom, error ); + return -EIO; + } + + /* Copy data out */ + if ( data_out ) { + data.dwords.lo = cpu_to_be32 ( phantom_readl ( phantom, + UNM_CAM_RAM_CLP_DATA_LO ) ); + data.dwords.hi = cpu_to_be32 ( phantom_readl ( phantom, + UNM_CAM_RAM_CLP_DATA_HI ) ); + out_frag_len = ( read_len - offset ); + if ( out_frag_len > sizeof ( data ) ) + out_frag_len = sizeof ( data ); + out_frag = &data.bytes[ sizeof ( data ) - out_frag_len ]; + if ( out_frag_len > ( len - offset ) ) + out_frag_len = ( len - offset ); + memcpy ( ( data_out + offset ), out_frag, out_frag_len ); + } + + return read_len; +} + +/** + * Store Phantom CLP setting + * + * @v phantom Phantom NIC + * @v port Virtual port number + * @v setting Setting number + * @v data Data buffer + * @v len Length of data buffer + * @ret rc Return status code + */ +static int phantom_clp_store ( struct phantom_nic *phantom, unsigned int port, + unsigned int setting, const void *data, + size_t len ) { + unsigned int opcode = setting; + size_t offset; + int rc; + + for ( offset = 0 ; offset < len ; offset += PHN_CLP_BLKSIZE ) { + if ( ( rc = phantom_clp_cmd ( phantom, port, opcode, data, + NULL, offset, len ) ) < 0 ) + return rc; + } + return 0; +} + +/** + * Fetch Phantom CLP setting + * + * @v phantom Phantom NIC + * @v port Virtual port number + * @v setting Setting number + * @v data Data buffer + * @v len Length of data buffer + * @ret len Length of setting, or negative error + */ +static int phantom_clp_fetch ( struct phantom_nic *phantom, unsigned int port, + unsigned int setting, void *data, size_t len ) { + unsigned int opcode = ( setting + 1 ); + size_t offset = 0; + int read_len; + + while ( 1 ) { + read_len = phantom_clp_cmd ( phantom, port, opcode, NULL, + data, offset, len ); + if ( read_len < 0 ) + return read_len; + offset += PHN_CLP_BLKSIZE; + if ( offset >= ( unsigned ) read_len ) + break; + if ( offset >= len ) + break; + } + return read_len; +} + +/** A Phantom CLP setting */ +struct phantom_clp_setting { + /** gPXE setting */ + struct setting *setting; + /** Setting number */ + unsigned int clp_setting; +}; + +/** Phantom CLP settings */ +static struct phantom_clp_setting clp_settings[] = { + { &mac_setting, 0x01 }, +}; + +/** + * Find Phantom CLP setting + * + * @v setting gPXE setting + * @v clp_setting Setting number, or 0 if not found + */ +static unsigned int +phantom_clp_setting ( struct phantom_nic *phantom, struct setting *setting ) { + struct phantom_clp_setting *clp_setting; + unsigned int i; + + /* Search the list of explicitly-defined settings */ + for ( i = 0 ; i < ( sizeof ( clp_settings ) / + sizeof ( clp_settings[0] ) ) ; i++ ) { + clp_setting = &clp_settings[i]; + if ( setting_cmp ( setting, clp_setting->setting ) == 0 ) + return clp_setting->clp_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 ); + + DBGC2 ( phantom, "Phantom %p has no \"%s\" setting\n", + phantom, setting->name ); + + return 0; +} + +/** + * Store Phantom CLP setting + * + * @v settings Settings block + * @v setting Setting to store + * @v data Setting data, or NULL to clear setting + * @v len Length of setting data + * @ret rc Return status code + */ +static int phantom_store_setting ( struct settings *settings, + struct setting *setting, + const void *data, size_t len ) { + struct phantom_nic *phantom = + container_of ( settings, struct phantom_nic, settings ); + unsigned int clp_setting; + int rc; + + /* Find Phantom setting equivalent to gPXE setting */ + clp_setting = phantom_clp_setting ( phantom, setting ); + if ( ! clp_setting ) + return -ENOTSUP; + + /* Store setting */ + if ( ( rc = phantom_clp_store ( phantom, phantom->port, + clp_setting, data, len ) ) != 0 ) { + DBGC ( phantom, "Phantom %p could not store setting \"%s\": " + "%s\n", phantom, setting->name, strerror ( rc ) ); + return rc; + } + + return 0; +} + +/** + * Fetch Phantom CLP 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 phantom_fetch_setting ( struct settings *settings, + struct setting *setting, + void *data, size_t len ) { + struct phantom_nic *phantom = + container_of ( settings, struct phantom_nic, settings ); + unsigned int clp_setting; + int read_len; + int rc; + + /* Find Phantom setting equivalent to gPXE setting */ + clp_setting = phantom_clp_setting ( phantom, setting ); + if ( ! clp_setting ) + return -ENOTSUP; + + /* Fetch setting */ + if ( ( read_len = phantom_clp_fetch ( phantom, phantom->port, + clp_setting, data, len ) ) < 0 ){ + rc = read_len; + DBGC ( phantom, "Phantom %p could not fetch setting \"%s\": " + "%s\n", phantom, setting->name, strerror ( rc ) ); + return rc; + } + + return read_len; +} + +/** Phantom CLP settings operations */ +static struct settings_operations phantom_settings_operations = { + .store = phantom_store_setting, + .fetch = phantom_fetch_setting, +}; + +/*************************************************************************** + * + * Initialisation + * + */ + /** * Map Phantom CRB window * @@ -1556,8 +1742,15 @@ static int phantom_map_crb ( struct phantom_nic *phantom, bar0_start = pci_bar_start ( pci, PCI_BASE_ADDRESS_0 ); bar0_size = pci_bar_size ( pci, PCI_BASE_ADDRESS_0 ); - DBGC ( phantom, "Phantom %p BAR0 is %08lx+%lx\n", - phantom, bar0_start, bar0_size ); + DBGC ( phantom, "Phantom %p is PCI %02x:%02x.%x with BAR0 at " + "%08lx+%lx\n", phantom, pci->bus, PCI_SLOT ( pci->devfn ), + PCI_FUNC ( pci->devfn ), bar0_start, bar0_size ); + + if ( ! bar0_start ) { + DBGC ( phantom, "Phantom %p BAR not assigned; ignoring\n", + phantom ); + return -EINVAL; + } switch ( bar0_size ) { case ( 128 * 1024 * 1024 ) : @@ -1592,71 +1785,23 @@ static int phantom_map_crb ( struct phantom_nic *phantom, } /** - * Read Phantom flash contents + * Unhalt all PEGs * * @v phantom Phantom NIC - * @ret rc Return status code */ -static int phantom_read_flash ( struct phantom_nic *phantom ) { - struct unm_board_info board_info; - int rc; - - /* Initialise flash access */ - phantom->spi_bus.rw = phantom_spi_rw; - phantom->flash.bus = &phantom->spi_bus; - init_m25p32 ( &phantom->flash ); - /* Phantom doesn't support greater than 4-byte block sizes */ - phantom->flash.nvs.block_size = UNM_SPI_BLKSIZE; - - /* Read and verify board information */ - if ( ( rc = nvs_read ( &phantom->flash.nvs, UNM_BRDCFG_START, - &board_info, sizeof ( board_info ) ) ) != 0 ) { - DBGC ( phantom, "Phantom %p could not read board info: %s\n", - phantom, strerror ( rc ) ); - return rc; - } - if ( board_info.magic != UNM_BDINFO_MAGIC ) { - DBGC ( phantom, "Phantom %p has bad board info magic %lx\n", - phantom, board_info.magic ); - DBGC_HD ( phantom, &board_info, sizeof ( board_info ) ); - return -EINVAL; - } - if ( board_info.header_version != UNM_BDINFO_VERSION ) { - DBGC ( phantom, "Phantom %p has bad board info version %lx\n", - phantom, board_info.header_version ); - DBGC_HD ( phantom, &board_info, sizeof ( board_info ) ); - return -EINVAL; - } - - /* Identify board type and number of ports */ - switch ( board_info.board_type ) { - case UNM_BRDTYPE_P3_4_GB: - case UNM_BRDTYPE_P3_4_GB_MM: - phantom->num_ports = 4; - break; - case UNM_BRDTYPE_P3_HMEZ: - case UNM_BRDTYPE_P3_IMEZ: - case UNM_BRDTYPE_P3_10G_CX4: - case UNM_BRDTYPE_P3_10G_CX4_LP: - case UNM_BRDTYPE_P3_10G_SFP_PLUS: - case UNM_BRDTYPE_P3_XG_LOM: - phantom->num_ports = 2; - break; - case UNM_BRDTYPE_P3_10000_BASE_T: - case UNM_BRDTYPE_P3_10G_XFP: - phantom->num_ports = 1; - break; - default: - DBGC ( phantom, "Phantom %p unrecognised board type %#lx; " - "assuming single-port\n", - phantom, board_info.board_type ); - phantom->num_ports = 1; - break; - } - DBGC ( phantom, "Phantom %p board type is %#lx (%d ports)\n", - phantom, board_info.board_type, phantom->num_ports ); - - return 0; +static void phantom_unhalt_pegs ( struct phantom_nic *phantom ) { + uint32_t halt_status; + + halt_status = phantom_readl ( phantom, UNM_PEG_0_HALT_STATUS ); + phantom_writel ( phantom, halt_status, UNM_PEG_0_HALT_STATUS ); + halt_status = phantom_readl ( phantom, UNM_PEG_1_HALT_STATUS ); + phantom_writel ( phantom, halt_status, UNM_PEG_1_HALT_STATUS ); + halt_status = phantom_readl ( phantom, UNM_PEG_2_HALT_STATUS ); + phantom_writel ( phantom, halt_status, UNM_PEG_2_HALT_STATUS ); + halt_status = phantom_readl ( phantom, UNM_PEG_3_HALT_STATUS ); + phantom_writel ( phantom, halt_status, UNM_PEG_3_HALT_STATUS ); + halt_status = phantom_readl ( phantom, UNM_PEG_4_HALT_STATUS ); + phantom_writel ( phantom, halt_status, UNM_PEG_4_HALT_STATUS ); } /** @@ -1668,7 +1813,6 @@ static int phantom_read_flash ( struct phantom_nic *phantom ) { static int phantom_init_cmdpeg ( struct phantom_nic *phantom ) { uint32_t cold_boot; uint32_t sw_reset; - physaddr_t dummy_dma_phys; unsigned int retries; uint32_t cmdpeg_state; uint32_t last_cmdpeg_state = 0; @@ -1681,6 +1825,11 @@ static int phantom_init_cmdpeg ( struct phantom_nic *phantom ) { if ( cmdpeg_state == UNM_NIC_REG_CMDPEG_STATE_INITIALIZE_ACK ) { DBGC ( phantom, "Phantom %p command PEG already initialized\n", phantom ); + /* Unhalt the PEGs. Previous firmware (e.g. BOFM) may + * have halted the PEGs to prevent internal bus + * collisions when the BIOS re-reads the expansion ROM. + */ + phantom_unhalt_pegs ( phantom ); return 0; } @@ -1691,13 +1840,13 @@ static int phantom_init_cmdpeg ( struct phantom_nic *phantom ) { phantom ); sw_reset = phantom_readl ( phantom, UNM_ROMUSB_GLB_SW_RESET ); if ( sw_reset != UNM_ROMUSB_GLB_SW_RESET_MAGIC ) { - DBGC ( phantom, "Phantom %p reset failed: %08lx\n", + DBGC ( phantom, "Phantom %p reset failed: %08x\n", phantom, sw_reset ); return -EIO; } } else { DBGC ( phantom, "Phantom %p coming up from warm boot " - "(%08lx)\n", phantom, cold_boot ); + "(%08x)\n", phantom, cold_boot ); } /* Clear cold-boot flag */ phantom_writel ( phantom, 0, UNM_CAM_RAM_COLD_BOOT ); @@ -1707,10 +1856,7 @@ static int phantom_init_cmdpeg ( struct phantom_nic *phantom ) { UNM_CAM_RAM_WOL_PORT_MODE ); /* Pass dummy DMA area to card */ - dummy_dma_phys = virt_to_bus ( phantom->dma_buf->dummy_dma ); - DBGC ( phantom, "Phantom %p dummy DMA at %08lx\n", - phantom, dummy_dma_phys ); - phantom_write_hilo ( phantom, dummy_dma_phys, + phantom_write_hilo ( phantom, 0, UNM_NIC_REG_DUMMY_BUF_ADDR_LO, UNM_NIC_REG_DUMMY_BUF_ADDR_HI ); phantom_writel ( phantom, UNM_NIC_REG_DUMMY_BUF_INIT, @@ -1728,7 +1874,7 @@ static int phantom_init_cmdpeg ( struct phantom_nic *phantom ) { UNM_NIC_REG_CMDPEG_STATE ); if ( cmdpeg_state != last_cmdpeg_state ) { DBGC ( phantom, "Phantom %p command PEG state is " - "%08lx after %d seconds...\n", + "%08x after %d seconds...\n", phantom, cmdpeg_state, retries ); last_cmdpeg_state = cmdpeg_state; } @@ -1743,19 +1889,18 @@ static int phantom_init_cmdpeg ( struct phantom_nic *phantom ) { } DBGC ( phantom, "Phantom %p timed out waiting for command PEG to " - "initialise (status %08lx)\n", phantom, cmdpeg_state ); + "initialise (status %08x)\n", phantom, cmdpeg_state ); return -ETIMEDOUT; } /** * Read Phantom MAC address * - * @v phanton_port Phantom NIC port + * @v phanton_port Phantom NIC * @v ll_addr Buffer to fill with MAC address */ -static void phantom_get_macaddr ( struct phantom_nic_port *phantom_port, +static void phantom_get_macaddr ( struct phantom_nic *phantom, uint8_t *ll_addr ) { - struct phantom_nic *phantom = phantom_port->phantom; union { uint8_t mac_addr[2][ETH_ALEN]; uint32_t dwords[3]; @@ -1765,7 +1910,7 @@ static void phantom_get_macaddr ( struct phantom_nic_port *phantom_port, /* Read the three dwords that include this MAC address and one other */ offset = ( UNM_CAM_RAM_MAC_ADDRS + - ( 12 * ( phantom_port->port / 2 ) ) ); + ( 12 * ( phantom->port / 2 ) ) ); for ( i = 0 ; i < 3 ; i++, offset += 4 ) { u.dwords[i] = phantom_readl ( phantom, offset ); } @@ -1773,10 +1918,36 @@ static void phantom_get_macaddr ( struct phantom_nic_port *phantom_port, /* Copy out the relevant MAC address */ for ( i = 0 ; i < ETH_ALEN ; i++ ) { ll_addr[ ETH_ALEN - i - 1 ] = - u.mac_addr[ phantom_port->port & 1 ][i]; + u.mac_addr[ phantom->port & 1 ][i]; } - DBGC ( phantom, "Phantom %p port %d MAC address is %s\n", - phantom, phantom_port->port, eth_ntoa ( ll_addr ) ); + DBGC ( phantom, "Phantom %p MAC address is %s\n", + phantom, eth_ntoa ( ll_addr ) ); +} + +/** + * Check Phantom is enabled for boot + * + * @v phanton_port Phantom NIC + * @ret rc Return status code + * + * This is something of an ugly hack to accommodate an OEM + * requirement. The NIC has only one expansion ROM BAR, rather than + * one per port. To allow individual ports to be selectively + * enabled/disabled for PXE boot (as required), we must therefore + * leave the expansion ROM always enabled, and place the per-port + * enable/disable logic within the gPXE driver. + */ +static int phantom_check_boot_enable ( struct phantom_nic *phantom ) { + unsigned long boot_enable; + + boot_enable = phantom_readl ( phantom, UNM_CAM_RAM_BOOT_ENABLE ); + if ( ! ( boot_enable & ( 1 << phantom->port ) ) ) { + DBGC ( phantom, "Phantom %p PXE boot is disabled\n", + phantom ); + return -ENOTSUP; + } + + return 0; } /** @@ -1797,7 +1968,7 @@ static int phantom_init_rcvpeg ( struct phantom_nic *phantom ) { UNM_NIC_REG_RCVPEG_STATE ); if ( rcvpeg_state != last_rcvpeg_state ) { DBGC ( phantom, "Phantom %p receive PEG state is " - "%08lx after %d seconds...\n", + "%08x after %d seconds...\n", phantom, rcvpeg_state, retries ); last_rcvpeg_state = rcvpeg_state; } @@ -1807,7 +1978,7 @@ static int phantom_init_rcvpeg ( struct phantom_nic *phantom ) { } DBGC ( phantom, "Phantom %p timed out waiting for receive PEG to " - "initialise (status %08lx)\n", phantom, rcvpeg_state ); + "initialise (status %08x)\n", phantom, rcvpeg_state ); return -ETIMEDOUT; } @@ -1820,25 +1991,27 @@ static int phantom_init_rcvpeg ( struct phantom_nic *phantom ) { */ static int phantom_probe ( struct pci_device *pci, const struct pci_device_id *id __unused ) { - struct phantom_nic *phantom; struct net_device *netdev; - struct phantom_nic_port *phantom_port; - int i; + struct phantom_nic *phantom; + struct settings *parent_settings; int rc; - /* Phantom NICs expose multiple PCI functions, used for - * virtualisation. Ignore everything except function 0. - */ - if ( PCI_FUNC ( pci->devfn ) != 0 ) - return -ENODEV; - /* Allocate Phantom device */ - phantom = zalloc ( sizeof ( *phantom ) ); - if ( ! phantom ) { + netdev = alloc_etherdev ( sizeof ( *phantom ) ); + if ( ! netdev ) { rc = -ENOMEM; - goto err_alloc_phantom; + goto err_alloc_etherdev; } - pci_set_drvdata ( pci, phantom ); + netdev_init ( netdev, &phantom_operations ); + phantom = netdev_priv ( netdev ); + pci_set_drvdata ( pci, netdev ); + netdev->dev = &pci->dev; + memset ( phantom, 0, sizeof ( *phantom ) ); + phantom->port = PCI_FUNC ( pci->devfn ); + assert ( phantom->port < PHN_MAX_NUM_PORTS ); + settings_init ( &phantom->settings, + &phantom_settings_operations, + &netdev->refcnt, "clp", PHN_CLP_TAG_MAGIC ); /* Fix up PCI device */ adjust_pci_device ( pci ); @@ -1847,87 +2020,66 @@ static int phantom_probe ( struct pci_device *pci, if ( ( rc = phantom_map_crb ( phantom, pci ) ) != 0 ) goto err_map_crb; - /* Read flash information */ - if ( ( rc = phantom_read_flash ( phantom ) ) != 0 ) - goto err_read_flash; - - /* Allocate net devices for each port */ - for ( i = 0 ; i < phantom->num_ports ; i++ ) { - netdev = alloc_etherdev ( sizeof ( *phantom_port ) ); - if ( ! netdev ) { - rc = -ENOMEM; - goto err_alloc_etherdev; - } - phantom->netdev[i] = netdev; - netdev_init ( netdev, &phantom_operations ); - phantom_port = netdev_priv ( netdev ); - netdev->dev = &pci->dev; - phantom_port->phantom = phantom; - phantom_port->port = i; - } - /* BUG5945 - need to hack PCI config space on P3 B1 silicon. * B2 will have this fixed; remove this hack when B1 is no * longer in use. */ - for ( i = 0 ; i < 8 ; i++ ) { - uint32_t temp; - pci->devfn = PCI_DEVFN ( PCI_SLOT ( pci->devfn ), i ); - pci_read_config_dword ( pci, 0xc8, &temp ); - pci_read_config_dword ( pci, 0xc8, &temp ); - pci_write_config_dword ( pci, 0xc8, 0xf1000 ); + if ( PCI_FUNC ( pci->devfn ) == 0 ) { + unsigned int i; + for ( i = 0 ; i < 8 ; i++ ) { + uint32_t temp; + pci->devfn = PCI_DEVFN ( PCI_SLOT ( pci->devfn ), i ); + pci_read_config_dword ( pci, 0xc8, &temp ); + pci_read_config_dword ( pci, 0xc8, &temp ); + pci_write_config_dword ( pci, 0xc8, 0xf1000 ); + } + pci->devfn = PCI_DEVFN ( PCI_SLOT ( pci->devfn ), 0 ); } - pci->devfn = PCI_DEVFN ( PCI_SLOT ( pci->devfn ), 0 ); - /* Allocate dummy DMA buffer and perform initial hardware handshake */ - phantom->dma_buf = malloc_dma ( sizeof ( *(phantom->dma_buf) ), - UNM_DMA_BUFFER_ALIGN ); - if ( ! phantom->dma_buf ) - goto err_dma_buf; + /* Initialise the command PEG */ if ( ( rc = phantom_init_cmdpeg ( phantom ) ) != 0 ) goto err_init_cmdpeg; - /* Initialise the receive firmware */ + /* Initialise the receive PEG */ if ( ( rc = phantom_init_rcvpeg ( phantom ) ) != 0 ) goto err_init_rcvpeg; /* Read MAC addresses */ - for ( i = 0 ; i < phantom->num_ports ; i++ ) { - phantom_port = netdev_priv ( phantom->netdev[i] ); - phantom_get_macaddr ( phantom_port, - phantom->netdev[i]->ll_addr ); - } + phantom_get_macaddr ( phantom, netdev->ll_addr ); + + /* Skip if boot disabled on NIC */ + if ( ( rc = phantom_check_boot_enable ( phantom ) ) != 0 ) + goto err_check_boot_enable; /* Register network devices */ - for ( i = 0 ; i < phantom->num_ports ; i++ ) { - if ( ( rc = register_netdev ( phantom->netdev[i] ) ) != 0 ) { - DBGC ( phantom, "Phantom %p could not register port " - "%d: %s\n", phantom, i, strerror ( rc ) ); - goto err_register_netdev; - } + if ( ( rc = register_netdev ( netdev ) ) != 0 ) { + DBGC ( phantom, "Phantom %p could not register net device: " + "%s\n", phantom, strerror ( rc ) ); + goto err_register_netdev; + } + + /* Register settings blocks */ + parent_settings = netdev_settings ( netdev ); + if ( ( rc = register_settings ( &phantom->settings, + parent_settings ) ) != 0 ) { + DBGC ( phantom, "Phantom %p could not register settings: " + "%s\n", phantom, strerror ( rc ) ); + goto err_register_settings; } return 0; - i = ( phantom->num_ports - 1 ); + unregister_settings ( &phantom->settings ); + err_register_settings: + unregister_netdev ( netdev ); err_register_netdev: - for ( ; i >= 0 ; i-- ) - unregister_netdev ( phantom->netdev[i] ); + err_check_boot_enable: err_init_rcvpeg: err_init_cmdpeg: - free_dma ( phantom->dma_buf, sizeof ( *(phantom->dma_buf) ) ); - phantom->dma_buf = NULL; - err_dma_buf: - i = ( phantom->num_ports - 1 ); - err_alloc_etherdev: - for ( ; i >= 0 ; i-- ) { - netdev_nullify ( phantom->netdev[i] ); - netdev_put ( phantom->netdev[i] ); - } - err_read_flash: err_map_crb: - free ( phantom ); - err_alloc_phantom: + netdev_nullify ( netdev ); + netdev_put ( netdev ); + err_alloc_etherdev: return rc; } @@ -1937,18 +2089,13 @@ static int phantom_probe ( struct pci_device *pci, * @v pci PCI device */ static void phantom_remove ( struct pci_device *pci ) { - struct phantom_nic *phantom = pci_get_drvdata ( pci ); - int i; + struct net_device *netdev = pci_get_drvdata ( pci ); + struct phantom_nic *phantom = netdev_priv ( netdev ); - for ( i = ( phantom->num_ports - 1 ) ; i >= 0 ; i-- ) - unregister_netdev ( phantom->netdev[i] ); - free_dma ( phantom->dma_buf, sizeof ( *(phantom->dma_buf) ) ); - phantom->dma_buf = NULL; - for ( i = ( phantom->num_ports - 1 ) ; i >= 0 ; i-- ) { - netdev_nullify ( phantom->netdev[i] ); - netdev_put ( phantom->netdev[i] ); - } - free ( phantom ); + unregister_settings ( &phantom->settings ); + unregister_netdev ( netdev ); + netdev_nullify ( netdev ); + netdev_put ( netdev ); } /** Phantom PCI IDs */ diff --git a/gpxe/src/drivers/net/phantom/phantom.h b/gpxe/src/drivers/net/phantom/phantom.h index 110c1226..974eecae 100644 --- a/gpxe/src/drivers/net/phantom/phantom.h +++ b/gpxe/src/drivers/net/phantom/phantom.h @@ -45,18 +45,12 @@ typedef uint32_t nx_rcode_t; #define NXHAL_VERSION 1 #include "nxhal_nic_interface.h" -/** SPI controller maximum block size */ -#define UNM_SPI_BLKSIZE 4 - /** DMA buffer alignment */ #define UNM_DMA_BUFFER_ALIGN 16 /** Mark structure as DMA-aligned */ #define __unm_dma_aligned __attribute__ (( aligned ( UNM_DMA_BUFFER_ALIGN ) )) -/** Dummy DMA buffer size */ -#define UNM_DUMMY_DMA_SIZE 1024 - /****************************************************************************** * * Register definitions @@ -76,14 +70,19 @@ typedef uint32_t nx_rcode_t; * address by the phantom_crb_access_xxx() methods. */ enum unm_reg_blocks { - UNM_CRB_BLK_PCIE, - UNM_CRB_BLK_CAM, - UNM_CRB_BLK_ROMUSB, - UNM_CRB_BLK_TEST, + UNM_CRB_BLK_PCIE = 0x01, + UNM_CRB_BLK_CAM = 0x22, + UNM_CRB_BLK_ROMUSB = 0x33, + UNM_CRB_BLK_TEST = 0x02, + UNM_CRB_BLK_PEG_0 = 0x11, + UNM_CRB_BLK_PEG_1 = 0x12, + UNM_CRB_BLK_PEG_2 = 0x13, + UNM_CRB_BLK_PEG_3 = 0x14, + UNM_CRB_BLK_PEG_4 = 0x0f, }; -#define UNM_CRB_BASE(blk) ( (blk) << 24 ) -#define UNM_CRB_BLK(reg) ( (reg) >> 24 ) -#define UNM_CRB_OFFSET(reg) ( (reg) & 0x00ffffff ) +#define UNM_CRB_BASE(blk) ( (blk) << 20 ) +#define UNM_CRB_BLK(reg) ( (reg) >> 20 ) +#define UNM_CRB_OFFSET(reg) ( (reg) & 0x000fffff ) #define UNM_CRB_PCIE UNM_CRB_BASE ( UNM_CRB_BLK_PCIE ) #define UNM_PCIE_SEM2_LOCK ( UNM_CRB_PCIE + 0x1c010 ) @@ -101,6 +100,16 @@ enum unm_reg_blocks { #define UNM_CAM_RAM_DMESG_SIG(n) ( UNM_CAM_RAM + 0x0003c + (n) * 0x10 ) #define UNM_CAM_RAM_DMESG_SIG_MAGIC 0xcafebabeUL #define UNM_CAM_RAM_NUM_DMESG_BUFFERS 5 +#define UNM_CAM_RAM_CLP_COMMAND ( UNM_CAM_RAM + 0x000c0 ) +#define UNM_CAM_RAM_CLP_COMMAND_LAST 0x00000080UL +#define UNM_CAM_RAM_CLP_DATA_LO ( UNM_CAM_RAM + 0x000c4 ) +#define UNM_CAM_RAM_CLP_DATA_HI ( UNM_CAM_RAM + 0x000c8 ) +#define UNM_CAM_RAM_CLP_STATUS ( UNM_CAM_RAM + 0x000cc ) +#define UNM_CAM_RAM_CLP_STATUS_START 0x00000001UL +#define UNM_CAM_RAM_CLP_STATUS_DONE 0x00000002UL +#define UNM_CAM_RAM_CLP_STATUS_ERROR 0x0000ff00UL +#define UNM_CAM_RAM_CLP_STATUS_UNINITIALISED 0xffffffffUL +#define UNM_CAM_RAM_BOOT_ENABLE ( UNM_CAM_RAM + 0x000fc ) #define UNM_CAM_RAM_WOL_PORT_MODE ( UNM_CAM_RAM + 0x00198 ) #define UNM_CAM_RAM_MAC_ADDRS ( UNM_CAM_RAM + 0x001c0 ) #define UNM_CAM_RAM_COLD_BOOT ( UNM_CAM_RAM + 0x001fc ) @@ -160,114 +169,24 @@ enum unm_reg_blocks { #define UNM_TEST_RDDATA_LO ( UNM_CRB_TEST + 0x000a8 ) #define UNM_TEST_RDDATA_HI ( UNM_CRB_TEST + 0x000ac ) -/****************************************************************************** - * - * Flash layout - * - */ - -/* Board configuration */ - -#define UNM_BRDCFG_START 0x4000 - -struct unm_board_info { - uint32_t header_version; - uint32_t board_mfg; - uint32_t board_type; - uint32_t board_num; - uint32_t chip_id; - uint32_t chip_minor; - uint32_t chip_major; - uint32_t chip_pkg; - uint32_t chip_lot; - uint32_t port_mask; - uint32_t peg_mask; - uint32_t icache_ok; - uint32_t dcache_ok; - uint32_t casper_ok; - uint32_t mac_addr_lo_0; - uint32_t mac_addr_lo_1; - uint32_t mac_addr_lo_2; - uint32_t mac_addr_lo_3; - uint32_t mn_sync_mode; - uint32_t mn_sync_shift_cclk; - uint32_t mn_sync_shift_mclk; - uint32_t mn_wb_en; - uint32_t mn_crystal_freq; - uint32_t mn_speed; - uint32_t mn_org; - uint32_t mn_depth; - uint32_t mn_ranks_0; - uint32_t mn_ranks_1; - uint32_t mn_rd_latency_0; - uint32_t mn_rd_latency_1; - uint32_t mn_rd_latency_2; - uint32_t mn_rd_latency_3; - uint32_t mn_rd_latency_4; - uint32_t mn_rd_latency_5; - uint32_t mn_rd_latency_6; - uint32_t mn_rd_latency_7; - uint32_t mn_rd_latency_8; - uint32_t mn_dll_val[18]; - uint32_t mn_mode_reg; - uint32_t mn_ext_mode_reg; - uint32_t mn_timing_0; - uint32_t mn_timing_1; - uint32_t mn_timing_2; - uint32_t sn_sync_mode; - uint32_t sn_pt_mode; - uint32_t sn_ecc_en; - uint32_t sn_wb_en; - uint32_t sn_crystal_freq; - uint32_t sn_speed; - uint32_t sn_org; - uint32_t sn_depth; - uint32_t sn_dll_tap; - uint32_t sn_rd_latency; - uint32_t mac_addr_hi_0; - uint32_t mac_addr_hi_1; - uint32_t mac_addr_hi_2; - uint32_t mac_addr_hi_3; - uint32_t magic; - uint32_t mn_rdimm; - uint32_t mn_dll_override; -}; - -#define UNM_BDINFO_VERSION 1 -#define UNM_BRDTYPE_P3_HMEZ 0x0022 -#define UNM_BRDTYPE_P3_10G_CX4_LP 0x0023 -#define UNM_BRDTYPE_P3_4_GB 0x0024 -#define UNM_BRDTYPE_P3_IMEZ 0x0025 -#define UNM_BRDTYPE_P3_10G_SFP_PLUS 0x0026 -#define UNM_BRDTYPE_P3_10000_BASE_T 0x0027 -#define UNM_BRDTYPE_P3_XG_LOM 0x0028 -#define UNM_BRDTYPE_P3_4_GB_MM 0x0029 -#define UNM_BRDTYPE_P3_10G_CX4 0x0031 -#define UNM_BRDTYPE_P3_10G_XFP 0x0032 -#define UNM_BDINFO_MAGIC 0x12345678 +#define UNM_CRB_PEG_0 UNM_CRB_BASE ( UNM_CRB_BLK_PEG_0 ) +#define UNM_PEG_0_HALT_STATUS ( UNM_CRB_PEG_0 + 0x00030 ) +#define UNM_PEG_0_HALT ( UNM_CRB_PEG_0 + 0x0003c ) -/* User defined region */ +#define UNM_CRB_PEG_1 UNM_CRB_BASE ( UNM_CRB_BLK_PEG_1 ) +#define UNM_PEG_1_HALT_STATUS ( UNM_CRB_PEG_1 + 0x00030 ) +#define UNM_PEG_1_HALT ( UNM_CRB_PEG_1 + 0x0003c ) -#define UNM_USER_START 0x3e8000 +#define UNM_CRB_PEG_2 UNM_CRB_BASE ( UNM_CRB_BLK_PEG_2 ) +#define UNM_PEG_2_HALT_STATUS ( UNM_CRB_PEG_2 + 0x00030 ) +#define UNM_PEG_2_HALT ( UNM_CRB_PEG_2 + 0x0003c ) -#define UNM_FLASH_NUM_PORTS 4 -#define UNM_FLASH_NUM_MAC_PER_PORT 32 +#define UNM_CRB_PEG_3 UNM_CRB_BASE ( UNM_CRB_BLK_PEG_3 ) +#define UNM_PEG_3_HALT_STATUS ( UNM_CRB_PEG_3 + 0x00030 ) +#define UNM_PEG_3_HALT ( UNM_CRB_PEG_3 + 0x0003c ) -struct unm_user_info { - uint8_t flash_md5[16 * 64]; - uint32_t bootld_version; - uint32_t bootld_size; - uint32_t image_version; - uint32_t image_size; - uint32_t primary_status; - uint32_t secondary_present; - /* MAC address , 4 ports, 32 address per port */ - uint64_t mac_addr[UNM_FLASH_NUM_PORTS * UNM_FLASH_NUM_MAC_PER_PORT]; - uint32_t sub_sys_id; - uint8_t serial_num[32]; - uint32_t bios_version; - uint32_t pxe_enable; - uint32_t vlan_tag[UNM_FLASH_NUM_PORTS]; -}; +#define UNM_CRB_PEG_4 UNM_CRB_BASE ( UNM_CRB_BLK_PEG_4 ) +#define UNM_PEG_4_HALT_STATUS ( UNM_CRB_PEG_4 + 0x00030 ) +#define UNM_PEG_4_HALT ( UNM_CRB_PEG_4 + 0x0003c ) #endif /* _PHANTOM_H */ diff --git a/gpxe/src/drivers/net/pnic.c b/gpxe/src/drivers/net/pnic.c index c7f08670..3a4af967 100644 --- a/gpxe/src/drivers/net/pnic.c +++ b/gpxe/src/drivers/net/pnic.c @@ -14,7 +14,7 @@ Bochs Pseudo NIC driver for Etherboot #include <stdint.h> #include <stdio.h> -#include <io.h> +#include <gpxe/io.h> #include <errno.h> #include <gpxe/pci.h> #include <gpxe/if_ether.h> diff --git a/gpxe/src/drivers/net/prism2.c b/gpxe/src/drivers/net/prism2.c index aaf4c968..c54dba5d 100644 --- a/gpxe/src/drivers/net/prism2.c +++ b/gpxe/src/drivers/net/prism2.c @@ -118,7 +118,7 @@ static const char hardcoded_ssid[] = ""; typedef struct hfa384x { UINT32 iobase; - UINT32 membase; + void *membase; UINT16 lastcmd; UINT16 status; /* in host order */ UINT16 resp0; /* in host order */ diff --git a/gpxe/src/drivers/net/prism2_pci.c b/gpxe/src/drivers/net/prism2_pci.c index 63cc22e3..eda7bf50 100644 --- a/gpxe/src/drivers/net/prism2_pci.c +++ b/gpxe/src/drivers/net/prism2_pci.c @@ -22,14 +22,11 @@ $Id$ static int prism2_pci_probe ( struct nic *nic, struct pci_device *pci ) { hfa384x_t *hw = &hw_global; - uint32_t membase = 0; /* Prism2.5 Memory Base */ - pci_read_config_dword( pci, PRISM2_PCI_MEM_BASE, &membase); - membase &= PCI_BASE_ADDRESS_MEM_MASK; - hw->membase = (uint32_t) phys_to_virt(membase); - printf ( "Prism2.5 has registers at %#lx\n", hw->membase ); + printf ( "Prism2.5 has registers at %#lx\n", pci->membase ); + hw->membase = ioremap ( pci->membase, 0x100 ); - nic->ioaddr = hw->membase; + nic->ioaddr = pci->membase; nic->irqno = 0; return prism2_probe ( nic, hw ); diff --git a/gpxe/src/drivers/net/prism2_plx.c b/gpxe/src/drivers/net/prism2_plx.c index 150bbe69..a10eef29 100644 --- a/gpxe/src/drivers/net/prism2_plx.c +++ b/gpxe/src/drivers/net/prism2_plx.c @@ -48,10 +48,9 @@ static int prism2_find_plx ( hfa384x_t *hw, struct pci_device *p ) iobase &= PCI_BASE_ADDRESS_IO_MASK; /* Fill out hw structure */ - hw->membase = attr_mem; hw->iobase = iobase; - printf ( "PLX9052 has local config registers at %#lx\n", plx_lcr ); - printf ( "Prism2 has attribute memory at %#lx and I/O base at %#lx\n", attr_mem, iobase ); + printf ( "PLX9052 has local config registers at %#x\n", plx_lcr ); + printf ( "Prism2 has attribute memory at %#x and I/O base at %#x\n", attr_mem, iobase ); /* Search for CIS strings */ printf ( "Searching for PCMCIA card...\n" ); diff --git a/gpxe/src/drivers/net/r8169.c b/gpxe/src/drivers/net/r8169.c index 885f054a..4315f47a 100644 --- a/gpxe/src/drivers/net/r8169.c +++ b/gpxe/src/drivers/net/r8169.c @@ -1,1159 +1,434 @@ -/************************************************************************** -* r8169.c: Etherboot device driver for the RealTek RTL-8169 Gigabit -* Written 2003 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., 675 Mass Ave, Cambridge, MA 02139, USA. -* -* Portions of this code based on: -* r8169.c: A RealTek RTL-8169 Gigabit Ethernet driver -* for Linux kernel 2.4.x. -* -* Written 2002 ShuChen <shuchen@realtek.com.tw> -* See Linux Driver for full information -* -* Linux Driver Versions: -* 1.27a, 10.02.2002 -* RTL8169_VERSION "2.2" <2004/08/09> -* -* Thanks to: -* Jean Chen of RealTek Semiconductor Corp. for -* providing the evaluation NIC used to develop -* this driver. RealTek's support for Etherboot -* is appreciated. -* -* REVISION HISTORY: -* ================ -* -* v1.0 11-26-2003 timlegge Initial port of Linux driver -* v1.5 01-17-2004 timlegge Initial driver output cleanup -* v1.6 03-27-2004 timlegge Additional Cleanup -* v1.7 11-22-2005 timlegge Update to RealTek Driver Version 2.2 -* -* 03-19-2008 Hilko Bengen Cleanups and fixes for newer cards -* (successfully tested with 8110SC-d onboard NIC) -* -* Indent Options: indent -kr -i8 -***************************************************************************/ - -#include "etherboot.h" -#include "nic.h" -#include <gpxe/pci.h> +/* + * Copyright (c) 2008 Marty Connor <mdc@etherboot.org> + * Copyright (c) 2008 Entity Cyber, Inc. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of the + * License, or any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + * + * This driver is based on rtl8169 data sheets and work by: + * + * Copyright (c) 2002 ShuChen <shuchen@realtek.com.tw> + * Copyright (c) 2003 - 2007 Francois Romieu <romieu@fr.zoreil.com> + * Copyright (c) a lot of people too. Please respect their work. + */ + +#include <stdint.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <unistd.h> +#include <assert.h> +#include <byteswap.h> +#include <errno.h> #include <gpxe/ethernet.h> +#include <gpxe/if_ether.h> +#include <gpxe/io.h> +#include <gpxe/iobuf.h> #include <gpxe/malloc.h> +#include <gpxe/netdevice.h> +#include <gpxe/pci.h> +#include <gpxe/timer.h> -#define drv_version "v1.7+" -#define drv_date "03-19-2008" - -#define HZ 1000 - -static u32 ioaddr; - -/* 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)) - -#define ARRAY_SIZE(x) (sizeof(x) / sizeof((x)[0])) - -#undef RTL8169_DEBUG -#undef RTL8169_JUMBO_FRAME_SUPPORT -#undef RTL8169_HW_FLOW_CONTROL_SUPPORT - - -#undef RTL8169_IOCTL_SUPPORT -#undef RTL8169_DYNAMIC_CONTROL -#define RTL8169_USE_IO - -#if 0 -/* Maximum events (Rx packets, etc.) to handle at each interrupt. */ -static int max_interrupt_work = 20; -#endif - -#if 0 -/* Maximum number of multicast addresses to filter (vs. Rx-all-multicast). - The RTL chips use a 64 element hash table based on the Ethernet CRC. */ -static int multicast_filter_limit = 32; -#endif - -/* MAC address length*/ -#define MAC_ADDR_LEN 6 - -/* max supported gigabit ethernet frame size -- must be at least (dev->mtu+14+4).*/ -#define MAX_ETH_FRAME_SIZE 1536 - -#define TX_FIFO_THRESH 256 /* In bytes */ - -#define RX_FIFO_THRESH 7 /* 7 means NO threshold, Rx buffer level before first PCI xfer. */ -#define RX_DMA_BURST 7 /* Maximum PCI burst, '6' is 1024 */ -#define TX_DMA_BURST 7 /* Maximum PCI burst, '6' is 1024 */ -#define ETTh 0x3F /* 0x3F means NO threshold */ - -#define EarlyTxThld 0x3F /* 0x3F means NO early transmit */ -#define RxPacketMaxSize 0x0800 /* Maximum size supported is 16K-1 */ -#define InterFrameGap 0x03 /* 3 means InterFrameGap = the shortest one */ - -#define NUM_TX_DESC 1 /* Number of Tx descriptor registers */ -#define NUM_RX_DESC 4 /* Number of Rx descriptor registers */ -#define RX_BUF_SIZE 1536 /* Rx Buffer size */ - -#define RTL_MIN_IO_SIZE 0x80 -#define TX_TIMEOUT (6*HZ) - -#define RTL8169_TIMER_EXPIRE_TIME 100 //100 - -#define ETH_HDR_LEN 14 -#define DEFAULT_MTU 1500 -#define DEFAULT_RX_BUF_LEN 1536 - - -#ifdef RTL8169_JUMBO_FRAME_SUPPORT -#define MAX_JUMBO_FRAME_MTU ( 10000 ) -#define MAX_RX_SKBDATA_SIZE ( MAX_JUMBO_FRAME_MTU + ETH_HDR_LEN ) -#else -#define MAX_RX_SKBDATA_SIZE 1600 -#endif //end #ifdef RTL8169_JUMBO_FRAME_SUPPORT - -#ifdef RTL8169_USE_IO -#define RTL_W8(reg, val8) outb ((val8), ioaddr + (reg)) -#define RTL_W16(reg, val16) outw ((val16), ioaddr + (reg)) -#define RTL_W32(reg, val32) outl ((val32), ioaddr + (reg)) -#define RTL_R8(reg) inb (ioaddr + (reg)) -#define RTL_R16(reg) inw (ioaddr + (reg)) -#define RTL_R32(reg) ((unsigned long) inl (ioaddr + (reg))) -#else -/* write/read MMIO register */ -#define RTL_W8(reg, val8) writeb ((val8), ioaddr + (reg)) -#define RTL_W16(reg, val16) writew ((val16), ioaddr + (reg)) -#define RTL_W32(reg, val32) writel ((val32), ioaddr + (reg)) -#define RTL_R8(reg) readb (ioaddr + (reg)) -#define RTL_R16(reg) readw (ioaddr + (reg)) -#define RTL_R32(reg) ((unsigned long) readl (ioaddr + (reg))) -#endif - -enum mac_version { - RTL_GIGA_MAC_VER_01 = 0x01, // 8169 - RTL_GIGA_MAC_VER_02 = 0x02, // 8169S - RTL_GIGA_MAC_VER_03 = 0x03, // 8110S - RTL_GIGA_MAC_VER_04 = 0x04, // 8169SB - RTL_GIGA_MAC_VER_05 = 0x05, // 8110SCd - RTL_GIGA_MAC_VER_06 = 0x06, // 8110SCe - RTL_GIGA_MAC_VER_11 = 0x0b, // 8168Bb - RTL_GIGA_MAC_VER_12 = 0x0c, // 8168Be - RTL_GIGA_MAC_VER_13 = 0x0d, // 8101Eb - RTL_GIGA_MAC_VER_14 = 0x0e, // 8101 ? - RTL_GIGA_MAC_VER_15 = 0x0f, // 8101 ? - RTL_GIGA_MAC_VER_16 = 0x11, // 8101Ec - RTL_GIGA_MAC_VER_17 = 0x10, // 8168Bf - RTL_GIGA_MAC_VER_18 = 0x12, // 8168CP - RTL_GIGA_MAC_VER_19 = 0x13, // 8168C - RTL_GIGA_MAC_VER_20 = 0x14 // 8168C -}; - -enum cfg_version { - RTL_CFG_0 = 0x00, - RTL_CFG_1, - RTL_CFG_2 -}; - -static struct { - const char *name; - u8 mac_version; /* depend on RTL8169 docs */ - u32 RxConfigMask; /* should clear the bits supported by this chip */ -} rtl_chip_info[] = { - {"RTL8169", RTL_GIGA_MAC_VER_01, 0xff7e1880}, // 8169 - {"RTL8169s", RTL_GIGA_MAC_VER_02, 0xff7e1880}, // 8169S - {"RTL8110s", RTL_GIGA_MAC_VER_03, 0xff7e1880}, // 8110S - {"RTL8169sb/8110sb", RTL_GIGA_MAC_VER_04, 0xff7e1880}, // 8169SB - {"RTL8169sc/8110sc-d",RTL_GIGA_MAC_VER_05, 0xff7e1880}, // 8110SCd - {"RTL8169sc/8110sc-e",RTL_GIGA_MAC_VER_06, 0xff7e1880}, // 8110SCe - {"RTL8168b/8111b", RTL_GIGA_MAC_VER_11, 0xff7e1880}, // PCI-E - {"RTL8168b/8111b", RTL_GIGA_MAC_VER_12, 0xff7e1880}, // PCI-E - {"RTL8101e", RTL_GIGA_MAC_VER_13, 0xff7e1880}, // PCI-E 8139 - {"RTL8100e", RTL_GIGA_MAC_VER_14, 0xff7e1880}, // PCI-E 8139 - {"RTL8100e", RTL_GIGA_MAC_VER_15, 0xff7e1880}, // PCI-E 8139 - {"RTL8168b/8111b", RTL_GIGA_MAC_VER_17, 0xff7e1880}, // PCI-E - {"RTL8101e", RTL_GIGA_MAC_VER_16, 0xff7e1880}, // PCI-E - {"RTL8168cp/8111cp", RTL_GIGA_MAC_VER_18, 0xff7e1880}, // PCI-E - {"RTL8168c/8111c", RTL_GIGA_MAC_VER_19, 0xff7e1880}, // PCI-E - {"RTL8168c/8111c", RTL_GIGA_MAC_VER_20, 0xff7e1880}, // PCI-E -}; - -enum RTL8169_registers { - MAC0 = 0x0, /* Ethernet hardware address. */ - MAR0 = 0x8, /* Multicast filter. */ - TxDescAddrLow = 0x20, - TxDescAddrHigh = 0x24, - TxHDescStartAddr = 0x28, - FLASH = 0x30, - ERSR = 0x36, - ChipCmd = 0x37, - TxPoll = 0x38, - IntrMask = 0x3C, - IntrStatus = 0x3E, - TxConfig = 0x40, - RxConfig = 0x44, - RxMissed = 0x4C, - Cfg9346 = 0x50, - Config0 = 0x51, - Config1 = 0x52, - Config2 = 0x53, - Config3 = 0x54, - Config4 = 0x55, - Config5 = 0x56, - MultiIntr = 0x5C, - PHYAR = 0x60, - TBICSR = 0x64, - TBI_ANAR = 0x68, - TBI_LPAR = 0x6A, - PHYstatus = 0x6C, - RxMaxSize = 0xda, - CPlusCmd = 0xe0, - IntrMitigate = 0xe2, - RxDescAddrLow = 0xe4, - RxDescAddrHigh = 0xe8, - ETThReg = 0xEC, - FuncEvent = 0xF0, - FuncEventMask = 0xF4, - FuncPresetState = 0xF8, - FuncForceEvent = 0xFC, -}; - -enum RTL8169_register_content { - /*InterruptStatusBits */ - SYSErr = 0x8000, - PCSTimeout = 0x4000, - SWInt = 0x0100, - TxDescUnavail = 0x80, - RxFIFOOver = 0x40, - LinkChg = 0x20, - RxOverflow = 0x10, - TxErr = 0x08, - TxOK = 0x04, - RxErr = 0x02, - RxOK = 0x01, - - /*RxStatusDesc */ - RxRES = 0x00200000, - RxCRC = 0x00080000, - RxRUNT = 0x00100000, - RxRWT = 0x00400000, - - /*ChipCmdBits */ - CmdReset = 0x10, - CmdRxEnb = 0x08, - CmdTxEnb = 0x04, - RxBufEmpty = 0x01, - - /*Cfg9346Bits */ - Cfg9346_Lock = 0x00, - Cfg9346_Unlock = 0xC0, - - /*rx_mode_bits */ - AcceptErr = 0x20, - AcceptRunt = 0x10, - AcceptBroadcast = 0x08, - AcceptMulticast = 0x04, - AcceptMyPhys = 0x02, - AcceptAllPhys = 0x01, - - /*RxConfigBits */ - RxCfgFIFOShift = 13, - RxCfgDMAShift = 8, - - /*TxConfigBits */ - TxInterFrameGapShift = 24, - TxDMAShift = 8, /* DMA burst value (0-7) is shift this many bits */ - - /*rtl8169_PHYstatus */ - TBI_Enable = 0x80, - TxFlowCtrl = 0x40, - RxFlowCtrl = 0x20, - _1000bpsF = 0x10, - _100bps = 0x08, - _10bps = 0x04, - LinkStatus = 0x02, - FullDup = 0x01, - - /*GIGABIT_PHY_registers */ - PHY_CTRL_REG = 0, - PHY_STAT_REG = 1, - PHY_AUTO_NEGO_REG = 4, - PHY_1000_CTRL_REG = 9, - - /*GIGABIT_PHY_REG_BIT */ - PHY_Restart_Auto_Nego = 0x0200, - PHY_Enable_Auto_Nego = 0x1000, - - /* PHY_STAT_REG = 1; */ - PHY_Auto_Neco_Comp = 0x0020, - - /* PHY_AUTO_NEGO_REG = 4; */ - PHY_Cap_10_Half = 0x0020, - PHY_Cap_10_Full = 0x0040, - PHY_Cap_100_Half = 0x0080, - PHY_Cap_100_Full = 0x0100, - - /* PHY_1000_CTRL_REG = 9; */ - PHY_Cap_1000_Full = 0x0200, - PHY_Cap_1000_Half = 0x0100, - - PHY_Cap_PAUSE = 0x0400, - PHY_Cap_ASYM_PAUSE = 0x0800, - - PHY_Cap_Null = 0x0, - - /*_MediaType*/ - _10_Half = 0x01, - _10_Full = 0x02, - _100_Half = 0x04, - _100_Full = 0x08, - _1000_Full = 0x10, - - /*_TBICSRBit*/ - TBILinkOK = 0x02000000, -}; - -enum _DescStatusBit { - OWNbit = 0x80000000, - EORbit = 0x40000000, - FSbit = 0x20000000, - LSbit = 0x10000000, -}; - -struct TxDesc { - u32 status; - u32 vlan_tag; - u32 buf_addr; - u32 buf_Haddr; -}; - -struct RxDesc { - u32 status; - u32 vlan_tag; - u32 buf_addr; - u32 buf_Haddr; -}; +#include "r8169.h" -/* The descriptors for this card are required to be aligned on 256 - * byte boundaries. As the align attribute does not do more than 16 - * bytes of alignment it requires some extra steps. Add 256 to the - * size of the array and the init_ring adjusts the alignment. - * - * UPDATE: This is no longer true; we can request arbitrary alignment. - */ +/*** Low level hardware routines ***/ -/* Define the TX and RX Descriptors and Buffers */ -#define __align_256 __attribute__ (( aligned ( 256 ) )) -struct { - struct TxDesc tx_ring[NUM_TX_DESC] __align_256; - unsigned char txb[NUM_TX_DESC * RX_BUF_SIZE]; - struct RxDesc rx_ring[NUM_RX_DESC] __align_256; - unsigned char rxb[NUM_RX_DESC * RX_BUF_SIZE]; -} *r8169_bufs; -#define tx_ring r8169_bufs->tx_ring -#define rx_ring r8169_bufs->rx_ring -#define txb r8169_bufs->txb -#define rxb r8169_bufs->rxb - -static struct rtl8169_private { - void *mmio_addr; /* memory map physical address */ - int chipset; - int pcfg; - int mac_version; - unsigned long cur_rx; /* Index into the Rx descriptor buffer of next Rx pkt. */ - unsigned long cur_tx; /* Index into the Tx descriptor buffer of next Rx pkt. */ - struct TxDesc *TxDescArray; /* Index of 256-alignment Tx Descriptor buffer */ - struct RxDesc *RxDescArray; /* Index of 256-alignment Rx Descriptor buffer */ - unsigned char *RxBufferRing[NUM_RX_DESC]; /* Index of Rx Buffer array */ - unsigned char *Tx_skbuff[NUM_TX_DESC]; -} tpx; - -static const u16 rtl8169_intr_mask = - LinkChg | RxOverflow | RxFIFOOver | TxErr | TxOK | RxErr | RxOK; -static const unsigned int rtl8169_rx_config = - (RX_FIFO_THRESH << RxCfgFIFOShift) | (RX_DMA_BURST << RxCfgDMAShift) | - 0x0000000E; - -static void rtl8169_hw_phy_config(struct nic *nic __unused); -//static void rtl8169_hw_phy_reset(struct net_device *dev); - -#define RTL8169_WRITE_GMII_REG_BIT( ioaddr, reg, bitnum, bitval )\ -{ \ - int val; \ - if( bitval == 1 ){ val = ( RTL8169_READ_GMII_REG( ioaddr, reg ) | (bitval<<bitnum) ) & 0xffff ; } \ - else{ val = ( RTL8169_READ_GMII_REG( ioaddr, reg ) & (~(0x0001<<bitnum)) ) & 0xffff ; } \ - RTL8169_WRITE_GMII_REG( ioaddr, reg, val ); \ - } - -//================================================================= -// PHYAR -// bit Symbol -// 31 Flag -// 30-21 reserved -// 20-16 5-bit GMII/MII register address -// 15-0 16-bit GMII/MII register data -//================================================================= -static void RTL8169_WRITE_GMII_REG(unsigned long ioaddr, int RegAddr, int value) +static void mdio_write(void *ioaddr, int reg_addr, int value) { int i; - RTL_W32(PHYAR, 0x80000000 | (RegAddr & 0xFF) << 16 | value); - udelay(1000); + DBGP ( "mdio_write\n" ); - for (i = 2000; i > 0; i--) { - // Check if the RTL8169 has completed writing to the specified MII register - if (!(RTL_R32(PHYAR) & 0x80000000)) { + RTL_W32(PHYAR, 0x80000000 | (reg_addr & 0x1f) << 16 | (value & 0xffff)); + + for (i = 20; i > 0; i--) { + /* + * Check if the RTL8169 has completed writing to the specified + * MII register. + */ + if (!(RTL_R32(PHYAR) & 0x80000000)) break; - } else { - udelay(100); - } // end of if( ! (RTL_R32(PHYAR)&0x80000000) ) - } // end of for() loop + udelay(25); + } } -//================================================================= -static int RTL8169_READ_GMII_REG(unsigned long ioaddr, int RegAddr) +static int mdio_read(void *ioaddr, int reg_addr) { int i, value = -1; - RTL_W32(PHYAR, 0x0 | (RegAddr & 0xFF) << 16); - udelay(1000); + DBGP ( "mdio_read\n" ); + + RTL_W32(PHYAR, 0x0 | (reg_addr & 0x1f) << 16); - for (i = 2000; i > 0; i--) { - // Check if the RTL8169 has completed retrieving data from the specified MII register + for (i = 20; i > 0; i--) { + /* + * Check if the RTL8169 has completed retrieving data from + * the specified MII register. + */ if (RTL_R32(PHYAR) & 0x80000000) { - value = (int) (RTL_R32(PHYAR) & 0xFFFF); + value = RTL_R32(PHYAR) & 0xffff; break; - } else { - udelay(100); - } // end of if( RTL_R32(PHYAR) & 0x80000000 ) - } // end of for() loop + } + udelay(25); + } return value; } +static void mdio_patch(void *ioaddr, int reg_addr, int value) +{ + DBGP ( "mdio_patch\n" ); + + mdio_write(ioaddr, reg_addr, mdio_read(ioaddr, reg_addr) | value); +} -#if 0 -static void mdio_write(int RegAddr, int value) +static void rtl_ephy_write(void *ioaddr, int reg_addr, int value) { - int i; + unsigned int i; + + DBGP ( "rtl_ephy_write\n" ); - RTL_W32(PHYAR, 0x80000000 | (RegAddr & 0xFF) << 16 | value); - udelay(1000); + RTL_W32(EPHYAR, EPHYAR_WRITE_CMD | (value & EPHYAR_DATA_MASK) | + (reg_addr & EPHYAR_REG_MASK) << EPHYAR_REG_SHIFT); - for (i = 2000; i > 0; i--) { - /* Check if the RTL8169 has completed writing to the specified MII register */ - if (!(RTL_R32(PHYAR) & 0x80000000)) { + for (i = 0; i < 100; i++) { + if (!(RTL_R32(EPHYAR) & EPHYAR_FLAG)) break; - } else { - udelay(100); - } + udelay(10); } } -static int mdio_read(int RegAddr) +static u16 rtl_ephy_read(void *ioaddr, int reg_addr) { - int i, value = -1; + u16 value = 0xffff; + unsigned int i; - RTL_W32(PHYAR, 0x0 | (RegAddr & 0xFF) << 16); - udelay(1000); + DBGP ( "rtl_ephy_read\n" ); - for (i = 2000; i > 0; i--) { - /* Check if the RTL8169 has completed retrieving data from the specified MII register */ - if (RTL_R32(PHYAR) & 0x80000000) { - value = (int) (RTL_R32(PHYAR) & 0xFFFF); + RTL_W32(EPHYAR, (reg_addr & EPHYAR_REG_MASK) << EPHYAR_REG_SHIFT); + + for (i = 0; i < 100; i++) { + if (RTL_R32(EPHYAR) & EPHYAR_FLAG) { + value = RTL_R32(EPHYAR) & EPHYAR_DATA_MASK; break; - } else { - udelay(100); } + udelay(10); } + return value; } -#endif -static void rtl8169_get_mac_version( struct rtl8169_private *tp, - u32 ioaddr ) +static void rtl_csi_write(void *ioaddr, int addr, int value) { - /* - * The driver currently handles the 8168Bf and the 8168Be identically - * but they can be identified more specifically through the test below - * if needed: - * - * (RTL_R32(TxConfig) & 0x700000) == 0x500000 ? 8168Bf : 8168Be - * - * Same thing for the 8101Eb and the 8101Ec: - * - * (RTL_R32(TxConfig) & 0x700000) == 0x200000 ? 8101Eb : 8101Ec - */ - const struct { - u32 mask; - u32 val; - int mac_version; - } mac_info[] = { - /* 8168B family. */ - { 0x7c800000, 0x3c800000, RTL_GIGA_MAC_VER_18 }, - { 0x7cf00000, 0x3c000000, RTL_GIGA_MAC_VER_19 }, - { 0x7cf00000, 0x3c200000, RTL_GIGA_MAC_VER_20 }, - { 0x7c800000, 0x3c000000, RTL_GIGA_MAC_VER_20 }, - /* 8168B family. */ - { 0x7cf00000, 0x38000000, RTL_GIGA_MAC_VER_12 }, - { 0x7cf00000, 0x38500000, RTL_GIGA_MAC_VER_17 }, - { 0x7c800000, 0x38000000, RTL_GIGA_MAC_VER_17 }, - { 0x7c800000, 0x30000000, RTL_GIGA_MAC_VER_11 }, - /* 8101 family. */ - { 0x7cf00000, 0x34000000, RTL_GIGA_MAC_VER_13 }, - { 0x7cf00000, 0x34200000, RTL_GIGA_MAC_VER_16 }, - { 0x7c800000, 0x34000000, RTL_GIGA_MAC_VER_16 }, - /* FIXME: where did these entries come from ? -- FR */ - { 0xfc800000, 0x38800000, RTL_GIGA_MAC_VER_15 }, - { 0xfc800000, 0x30800000, RTL_GIGA_MAC_VER_14 }, - /* 8110 family. */ - { 0xfc800000, 0x98000000, RTL_GIGA_MAC_VER_06 }, - { 0xfc800000, 0x18000000, RTL_GIGA_MAC_VER_05 }, - { 0xfc800000, 0x10000000, RTL_GIGA_MAC_VER_04 }, - { 0xfc800000, 0x04000000, RTL_GIGA_MAC_VER_03 }, - { 0xfc800000, 0x00800000, RTL_GIGA_MAC_VER_02 }, - { 0xfc800000, 0x00000000, RTL_GIGA_MAC_VER_01 }, - { 0x00000000, 0x00000000, RTL_GIGA_MAC_VER_01 } /* Catch-all */ - }, *p = mac_info; + unsigned int i; - unsigned long rv; + DBGP ( "rtl_csi_write\n" ); - rv = (RTL_R32(TxConfig)); + RTL_W32(CSIDR, value); + RTL_W32(CSIAR, CSIAR_WRITE_CMD | (addr & CSIAR_ADDR_MASK) | + CSIAR_BYTE_ENABLE << CSIAR_BYTE_ENABLE_SHIFT); - while ((rv & p->mask) != p->val) - p++; - tp->mac_version = p->mac_version; - - if (p->mask == 0x00000000) { - DBG("unknown MAC (%08lx)\n", rv); + for (i = 0; i < 100; i++) { + if (!(RTL_R32(CSIAR) & CSIAR_FLAG)) + break; + udelay(10); } } -#define IORESOURCE_MEM 0x00000200 - -static int rtl8169_init_board(struct pci_device *pdev) +static u32 rtl_csi_read(void *ioaddr, int addr) { - int i; -// unsigned long mmio_end, mmio_flags - unsigned long mmio_start, mmio_len; - struct rtl8169_private *tp = &tpx; - - adjust_pci_device(pdev); - - mmio_start = pci_bar_start(pdev, PCI_BASE_ADDRESS_1); -// mmio_end = pci_resource_end (pdev, 1); -// mmio_flags = pci_resource_flags (pdev, PCI_BASE_ADDRESS_1); - mmio_len = pci_bar_size(pdev, PCI_BASE_ADDRESS_1); - - // make sure PCI base addr 1 is MMIO -// if (!(mmio_flags & IORESOURCE_MEM)) { -// printf ("region #1 not an MMIO resource, aborting\n"); -// return 0; -// } - - // check for weird/broken PCI region reporting - if (mmio_len < RTL_MIN_IO_SIZE) { - printf("Invalid PCI region size(s), aborting\n"); - return 0; - } -#ifdef RTL8169_USE_IO - ioaddr = pci_bar_start(pdev, PCI_BASE_ADDRESS_0); -#else - // ioremap MMIO region - ioaddr = (unsigned long) ioremap(mmio_start, mmio_len); - if (ioaddr == 0) { - printk("cannot remap MMIO, aborting\n"); - return 0; - } -#endif + u32 value = ~0x00; + unsigned int i; - tp->mmio_addr = (void*)ioaddr; - /* Soft reset the chip. */ - RTL_W8(ChipCmd, CmdReset); + DBGP ( "rtl_csi_read\n" ); - /* Check that the chip has finished the reset. */ - for (i = 1000; i > 0; i--) - if ((RTL_R8(ChipCmd) & CmdReset) == 0) - break; - else - udelay(10); + RTL_W32(CSIAR, (addr & CSIAR_ADDR_MASK) | + CSIAR_BYTE_ENABLE << CSIAR_BYTE_ENABLE_SHIFT); - /* Identify chip attached to board */ - rtl8169_get_mac_version( tp, ioaddr ); - - // rtl8169_print_mac_version(tp); - - { - unsigned char val8 = - (unsigned char) (RTL8169_READ_GMII_REG(ioaddr, 3) & - 0x000f); - if (val8 == 0x00) { - tp->pcfg = RTL_CFG_0; - } else if (val8 == 0x01) { - tp->pcfg = RTL_CFG_1; - } else if (val8 == 0x02) { - tp->pcfg = RTL_CFG_2; - } else { - tp->pcfg = RTL_CFG_2; + for (i = 0; i < 100; i++) { + if (RTL_R32(CSIAR) & CSIAR_FLAG) { + value = RTL_R32(CSIDR); + break; } + udelay(10); } - /* identify chip attached to board */ - - for (i = ARRAY_SIZE(rtl_chip_info) - 1; i >= 0; i--) - if (tp->mac_version == rtl_chip_info[i].mac_version) { - tp->chipset = i; - goto match; - } - /* if unknown chip, assume array element #0, original RTL-8169 in this case */ - DBG ( "PCI device: unknown chip version, assuming RTL-8169\n" ); - DBG ( "PCI device: TxConfig = %#lX\n", ( unsigned long ) RTL_R32 ( TxConfig ) ); + return value; +} - tp->chipset = 0; - return 1; +static void rtl8169_irq_mask_and_ack(void *ioaddr) +{ + DBGP ( "rtl8169_irq_mask_and_ack\n" ); - match: - return 0; + RTL_W16(IntrMask, 0x0000); + RTL_W16(IntrStatus, 0xffff); } -/************************************************************************** -IRQ - Wait for a frame -***************************************************************************/ -static void r8169_irq(struct nic *nic __unused, irq_action_t action) +static unsigned int rtl8169_tbi_reset_pending(void *ioaddr) { - int intr_status = 0; - int interested = RxOverflow | RxFIFOOver | RxErr | RxOK; + DBGP ( "rtl8169_tbi_reset_pending\n" ); - switch (action) { - case DISABLE: - case ENABLE: - intr_status = RTL_R16(IntrStatus); - /* h/w no longer present (hotplug?) or major error, - bail */ - if (intr_status == 0xFFFF) - break; - - intr_status = intr_status & ~interested; - if (action == ENABLE) - intr_status = intr_status | interested; - RTL_W16(IntrMask, intr_status); - break; - case FORCE: - RTL_W8(TxPoll, (RTL_R8(TxPoll) | 0x01)); - break; - } + return RTL_R32(TBICSR) & TBIReset; } -/************************************************************************** -POLL - Wait for a frame -***************************************************************************/ -static int r8169_poll(struct nic *nic, int retrieve) -{ - /* return true if there's an ethernet packet ready to read */ - /* nic->packet should contain data on return */ - /* nic->packetlen should contain length of data */ - int cur_rx; - unsigned int intr_status = 0; - struct rtl8169_private *tp = &tpx; - - cur_rx = tp->cur_rx; - if ((tp->RxDescArray[cur_rx].status & OWNbit) == 0) { - /* There is a packet ready */ - DBG("r8169_poll(): packet ready\n"); - if (!retrieve) - return 1; - intr_status = RTL_R16(IntrStatus); - /* h/w no longer present (hotplug?) or major error, - bail */ - if (intr_status == 0xFFFF) { - DBG("r8169_poll(): unknown error\n"); - return 0; - } - RTL_W16(IntrStatus, intr_status & - ~(RxFIFOOver | RxOverflow | RxOK)); - - if (!(tp->RxDescArray[cur_rx].status & RxRES)) { - nic->packetlen = (int) (tp->RxDescArray[cur_rx]. - status & 0x00001FFF) - 4; - memcpy(nic->packet, tp->RxBufferRing[cur_rx], - nic->packetlen); - if (cur_rx == NUM_RX_DESC - 1) - tp->RxDescArray[cur_rx].status = - (OWNbit | EORbit) + RX_BUF_SIZE; - else - tp->RxDescArray[cur_rx].status = - OWNbit + RX_BUF_SIZE; - tp->RxDescArray[cur_rx].buf_addr = - virt_to_bus(tp->RxBufferRing[cur_rx]); - tp->RxDescArray[cur_rx].buf_Haddr = 0; - } else - printf("Error Rx"); - /* FIXME: shouldn't I reset the status on an error */ - cur_rx = (cur_rx + 1) % NUM_RX_DESC; - tp->cur_rx = cur_rx; - RTL_W16(IntrStatus, intr_status & - (RxFIFOOver | RxOverflow | RxOK)); - - return 1; +static unsigned int rtl8169_xmii_reset_pending(void *ioaddr) +{ + DBGP ( "rtl8169_xmii_reset_pending\n" ); - } - tp->cur_rx = cur_rx; - /* FIXME: There is no reason to do this as cur_rx did not change */ - - return (0); /* initially as this is called to flush the input */ - -} - -/************************************************************************** -TRANSMIT - Transmit a frame -***************************************************************************/ -static void r8169_transmit(struct nic *nic, const char *d, /* Destination */ - unsigned int t, /* Type */ - unsigned int s, /* size */ - const char *p) -{ /* Packet */ - /* send the packet to destination */ - - u16 nstype; - u32 to; - u8 *ptxb; - struct rtl8169_private *tp = &tpx; - int entry = tp->cur_tx % NUM_TX_DESC; - - /* point to the current txb incase multiple tx_rings are used */ - ptxb = tp->Tx_skbuff[entry * MAX_ETH_FRAME_SIZE]; - memcpy(ptxb, d, ETH_ALEN); - memcpy(ptxb + ETH_ALEN, nic->node_addr, ETH_ALEN); - nstype = htons((u16) t); - memcpy(ptxb + 2 * ETH_ALEN, (u8 *) & nstype, 2); - memcpy(ptxb + ETH_HLEN, p, s); - s += ETH_HLEN; - s &= 0x0FFF; - while (s < ETH_ZLEN) - ptxb[s++] = '\0'; - - tp->TxDescArray[entry].buf_addr = virt_to_bus(ptxb); - tp->TxDescArray[entry].buf_Haddr = 0; - if (entry != (NUM_TX_DESC - 1)) - tp->TxDescArray[entry].status = - (OWNbit | FSbit | LSbit) | ((s > ETH_ZLEN) ? s : - ETH_ZLEN); - else - tp->TxDescArray[entry].status = - (OWNbit | EORbit | FSbit | LSbit) | ((s > ETH_ZLEN) ? s - : ETH_ZLEN); - RTL_W8(TxPoll, 0x40); /* set polling bit */ - - tp->cur_tx++; - to = currticks() + TX_TIMEOUT; - while ((tp->TxDescArray[entry].status & OWNbit) && (currticks() < to)); /* wait */ - - if (currticks() >= to) { - printf("TX Time Out"); - } + return mdio_read(ioaddr, MII_BMCR) & BMCR_RESET; } -static void rtl8169_set_rx_mode(struct nic *nic __unused) +static unsigned int rtl8169_tbi_link_ok(void *ioaddr) { - u32 mc_filter[2]; /* Multicast hash filter */ - int rx_mode; - u32 tmp = 0; - struct rtl8169_private *tp = &tpx; + DBGP ( "rtl8169_tbi_link_ok\n" ); - /* IFF_ALLMULTI */ - /* Too many to filter perfectly -- accept all multicasts. */ - rx_mode = AcceptBroadcast | AcceptMulticast | AcceptMyPhys; - mc_filter[1] = mc_filter[0] = 0xffffffff; + return RTL_R32(TBICSR) & TBILinkOk; +} - tmp = - rtl8169_rx_config | rx_mode | (RTL_R32(RxConfig) & - rtl_chip_info[tp->chipset]. - RxConfigMask); +static unsigned int rtl8169_xmii_link_ok(void *ioaddr) +{ + DBGP ( "rtl8169_xmii_link_ok\n" ); - RTL_W32(RxConfig, tmp); - RTL_W32(MAR0 + 0, mc_filter[0]); - RTL_W32(MAR0 + 4, mc_filter[1]); + return RTL_R8(PHYstatus) & LinkStatus; } -static void rtl8169_hw_start(struct nic *nic) + +static void rtl8169_tbi_reset_enable(void *ioaddr) { - u32 i; - struct rtl8169_private *tp = &tpx; + DBGP ( "rtl8169_tbi_reset_enable\n" ); - /* Soft reset the chip. */ - RTL_W8(ChipCmd, CmdReset); + RTL_W32(TBICSR, RTL_R32(TBICSR) | TBIReset); +} - /* Check that the chip has finished the reset. */ - for (i = 1000; i > 0; i--) { - if ((RTL_R8(ChipCmd) & CmdReset) == 0) - break; - else - udelay(10); - } +static void rtl8169_xmii_reset_enable(void *ioaddr) +{ + unsigned int val; - RTL_W8(Cfg9346, Cfg9346_Unlock); - RTL_W8(ChipCmd, CmdTxEnb | CmdRxEnb); - RTL_W8(ETThReg, ETTh); + DBGP ( "rtl8169_xmii_reset_enable\n" ); - /* For gigabit rtl8169 */ - RTL_W16(RxMaxSize, RxPacketMaxSize); + val = mdio_read(ioaddr, MII_BMCR) | BMCR_RESET; + mdio_write(ioaddr, MII_BMCR, val & 0xffff); +} - /* Set Rx Config register */ - i = rtl8169_rx_config | (RTL_R32(RxConfig) & - rtl_chip_info[tp->chipset].RxConfigMask); - RTL_W32(RxConfig, i); +static int rtl8169_set_speed_tbi(struct net_device *dev, + u8 autoneg, u16 speed, u8 duplex) +{ + struct rtl8169_private *tp = netdev_priv(dev); + void *ioaddr = tp->mmio_addr; + int ret = 0; + u32 reg; + + DBGP ( "rtl8169_set_speed_tbi\n" ); + + reg = RTL_R32(TBICSR); + if ((autoneg == AUTONEG_DISABLE) && (speed == SPEED_1000) && + (duplex == DUPLEX_FULL)) { + RTL_W32(TBICSR, reg & ~(TBINwEnable | TBINwRestart)); + } else if (autoneg == AUTONEG_ENABLE) + RTL_W32(TBICSR, reg | TBINwEnable | TBINwRestart); + else { + DBG ( "incorrect speed setting refused in TBI mode\n" ); + ret = -EOPNOTSUPP; + } + return ret; +} - /* Set DMA burst size and Interframe Gap Time */ - RTL_W32(TxConfig, - (TX_DMA_BURST << TxDMAShift) | (InterFrameGap << - TxInterFrameGapShift)); +static int rtl8169_set_speed_xmii(struct net_device *dev, + u8 autoneg, u16 speed, u8 duplex) +{ + struct rtl8169_private *tp = netdev_priv(dev); + void *ioaddr = tp->mmio_addr; + int auto_nego, giga_ctrl; + DBGP ( "rtl8169_set_speed_xmii\n" ); - RTL_W16(CPlusCmd, RTL_R16(CPlusCmd)); + auto_nego = mdio_read(ioaddr, MII_ADVERTISE); + auto_nego &= ~(ADVERTISE_10HALF | ADVERTISE_10FULL | + ADVERTISE_100HALF | ADVERTISE_100FULL); + giga_ctrl = mdio_read(ioaddr, MII_CTRL1000); + giga_ctrl &= ~(ADVERTISE_1000FULL | ADVERTISE_1000HALF); - if (tp->mac_version == RTL_GIGA_MAC_VER_02 || tp->mac_version == RTL_GIGA_MAC_VER_03) { - RTL_W16(CPlusCmd, - (RTL_R16(CPlusCmd) | (1 << 14) | (1 << 3))); - DBG - ("Set MAC Reg C+CR Offset 0xE0: bit-3 and bit-14\n"); + if (autoneg == AUTONEG_ENABLE) { + auto_nego |= (ADVERTISE_10HALF | ADVERTISE_10FULL | + ADVERTISE_100HALF | ADVERTISE_100FULL); + giga_ctrl |= ADVERTISE_1000FULL | ADVERTISE_1000HALF; } else { - RTL_W16(CPlusCmd, (RTL_R16(CPlusCmd) | (1 << 3))); - DBG("Set MAC Reg C+CR Offset 0xE0: bit-3.\n"); + if (speed == SPEED_10) + auto_nego |= ADVERTISE_10HALF | ADVERTISE_10FULL; + else if (speed == SPEED_100) + auto_nego |= ADVERTISE_100HALF | ADVERTISE_100FULL; + else if (speed == SPEED_1000) + giga_ctrl |= ADVERTISE_1000FULL | ADVERTISE_1000HALF; + + if (duplex == DUPLEX_HALF) + auto_nego &= ~(ADVERTISE_10FULL | ADVERTISE_100FULL); + + if (duplex == DUPLEX_FULL) + auto_nego &= ~(ADVERTISE_10HALF | ADVERTISE_100HALF); + + /* This tweak comes straight from Realtek's driver. */ + if ((speed == SPEED_100) && (duplex == DUPLEX_HALF) && + ((tp->mac_version == RTL_GIGA_MAC_VER_13) || + (tp->mac_version == RTL_GIGA_MAC_VER_16))) { + auto_nego = ADVERTISE_100HALF | ADVERTISE_CSMA; + } } - { - //RTL_W16(IntrMitigate, 0x1517); - //RTL_W16(IntrMitigate, 0x152a); - //RTL_W16(IntrMitigate, 0x282a); - RTL_W16(IntrMitigate, 0x0000); + /* The 8100e/8101e/8102e do Fast Ethernet only. */ + if ((tp->mac_version == RTL_GIGA_MAC_VER_07) || + (tp->mac_version == RTL_GIGA_MAC_VER_08) || + (tp->mac_version == RTL_GIGA_MAC_VER_09) || + (tp->mac_version == RTL_GIGA_MAC_VER_10) || + (tp->mac_version == RTL_GIGA_MAC_VER_13) || + (tp->mac_version == RTL_GIGA_MAC_VER_14) || + (tp->mac_version == RTL_GIGA_MAC_VER_15) || + (tp->mac_version == RTL_GIGA_MAC_VER_16)) { + if ((giga_ctrl & (ADVERTISE_1000FULL | ADVERTISE_1000HALF))) { + DBG ( "PHY does not support 1000Mbps.\n" ); + } + giga_ctrl &= ~(ADVERTISE_1000FULL | ADVERTISE_1000HALF); } - tp->cur_rx = 0; - - RTL_W32(TxDescAddrLow, virt_to_le32desc(tp->TxDescArray)); - RTL_W32(TxDescAddrHigh, virt_to_le32desc(NULL)); - RTL_W32(RxDescAddrLow, virt_to_le32desc(tp->RxDescArray)); - RTL_W32(RxDescAddrHigh, virt_to_le32desc(NULL)); - RTL_W8(Cfg9346, Cfg9346_Lock); - udelay(10); - - RTL_W32(RxMissed, 0); - - rtl8169_set_rx_mode(nic); - - /* no early-rx interrupts */ - RTL_W16(MultiIntr, RTL_R16(MultiIntr) & 0xF000); + auto_nego |= ADVERTISE_PAUSE_CAP | ADVERTISE_PAUSE_ASYM; + + if ((tp->mac_version == RTL_GIGA_MAC_VER_11) || + (tp->mac_version == RTL_GIGA_MAC_VER_12) || + (tp->mac_version >= RTL_GIGA_MAC_VER_17)) { + /* + * Wake up the PHY. + * Vendor specific (0x1f) and reserved (0x0e) MII registers. + */ + mdio_write(ioaddr, 0x1f, 0x0000); + mdio_write(ioaddr, 0x0e, 0x0000); + } - RTL_W16(IntrMask, rtl8169_intr_mask); + tp->phy_auto_nego_reg = auto_nego; + tp->phy_1000_ctrl_reg = giga_ctrl; + mdio_write(ioaddr, MII_ADVERTISE, auto_nego); + mdio_write(ioaddr, MII_CTRL1000, giga_ctrl); + mdio_write(ioaddr, MII_BMCR, BMCR_ANENABLE | BMCR_ANRESTART); + return 0; } -static void rtl8169_init_ring(struct nic *nic __unused) +static int rtl8169_set_speed(struct net_device *dev, + u8 autoneg, u16 speed, u8 duplex) { - int i; - struct rtl8169_private *tp = &tpx; + struct rtl8169_private *tp = netdev_priv(dev); + int ret; - tp->cur_rx = 0; - tp->cur_tx = 0; - memset(tp->TxDescArray, 0x0, NUM_TX_DESC * sizeof(struct TxDesc)); - memset(tp->RxDescArray, 0x0, NUM_RX_DESC * sizeof(struct RxDesc)); + DBGP ( "rtl8169_set_speed\n" ); - for (i = 0; i < NUM_TX_DESC; i++) { - tp->Tx_skbuff[i] = &txb[i]; - } + ret = tp->set_speed(dev, autoneg, speed, duplex); - for (i = 0; i < NUM_RX_DESC; i++) { - if (i == (NUM_RX_DESC - 1)) - tp->RxDescArray[i].status = - (OWNbit | EORbit) | RX_BUF_SIZE; - else - tp->RxDescArray[i].status = OWNbit | RX_BUF_SIZE; - - tp->RxBufferRing[i] = &rxb[i * RX_BUF_SIZE]; - tp->RxDescArray[i].buf_addr = - virt_to_bus(tp->RxBufferRing[i]); - tp->RxDescArray[i].buf_Haddr = 0; - } + return ret; } -/************************************************************************** -RESET - Finish setting up the ethernet interface -***************************************************************************/ -static void r8169_reset(struct nic *nic) +static void rtl8169_write_gmii_reg_bit(void *ioaddr, int reg, + int bitnum, int bitval) { - int i; - struct rtl8169_private *tp = &tpx; - - tp->TxDescArray = tx_ring; - tp->RxDescArray = rx_ring; - - rtl8169_init_ring(nic); - rtl8169_hw_start(nic); - /* Construct a perfect filter frame with the mac address as first match - * and broadcast for all others */ - for (i = 0; i < 192; i++) - txb[i] = 0xFF; - - txb[0] = nic->node_addr[0]; - txb[1] = nic->node_addr[1]; - txb[2] = nic->node_addr[2]; - txb[3] = nic->node_addr[3]; - txb[4] = nic->node_addr[4]; - txb[5] = nic->node_addr[5]; -} - -/************************************************************************** -DISABLE - Turn off ethernet interface -***************************************************************************/ -static void r8169_disable ( struct nic *nic __unused ) { - int i; - struct rtl8169_private *tp = &tpx; + int val; - /* Stop the chip's Tx and Rx DMA processes. */ - RTL_W8(ChipCmd, 0x00); - - /* Disable interrupts by clearing the interrupt mask. */ - RTL_W16(IntrMask, 0x0000); + DBGP ( "rtl8169_write_gmii_reg_bit\n" ); - RTL_W32(RxMissed, 0); - - tp->TxDescArray = NULL; - tp->RxDescArray = NULL; - for (i = 0; i < NUM_RX_DESC; i++) { - tp->RxBufferRing[i] = NULL; - } + val = mdio_read(ioaddr, reg); + val = (bitval == 1) ? + val | (bitval << bitnum) : val & ~(0x0001 << bitnum); + mdio_write(ioaddr, reg, val & 0xffff); } -static struct nic_operations r8169_operations = { - .connect = dummy_connect, - .poll = r8169_poll, - .transmit = r8169_transmit, - .irq = r8169_irq, - -}; - -static struct pci_device_id r8169_nics[] = { - PCI_ROM(0x10ec, 0x8169, "r8169", "RealTek RTL8169 Gigabit Ethernet"), - PCI_ROM(0x16ec, 0x0116, "usr-r8169", "US Robotics RTL8169 Gigabit Ethernet"), - PCI_ROM(0x1186, 0x4300, "dlink-r8169", "D-Link RTL8169 Gigabit Ethernet"), - PCI_ROM(0x1737, 0x1032, "linksys-r8169", "Linksys RTL8169 Gigabit Ethernet"), - PCI_ROM(0x10ec, 0x8129, "r8169-8129", "RealTek RT8129 Fast Ethernet Adapter"), - PCI_ROM(0x10ec, 0x8136, "r8169-8101e", "RealTek RTL8101E PCI Express Fast Ethernet controller"), - PCI_ROM(0x10ec, 0x8167, "r8169-8110sc/8169sc", "RealTek RTL-8110SC/8169SC Gigabit Ethernet"), - PCI_ROM(0x10ec, 0x8168, "r8169-8168b", "RealTek RTL8111/8168B PCI Express Gigabit Ethernet controller"), -}; - -PCI_DRIVER ( r8169_driver, r8169_nics, PCI_NO_CLASS ); - -/************************************************************************** -PROBE - Look for an adapter, this routine's visible to the outside -***************************************************************************/ - -#define board_found 1 -#define valid_link 0 -static int r8169_probe ( struct nic *nic, struct pci_device *pci ) { - - static int board_idx = -1; - static int printed_version = 0; - struct rtl8169_private *tp = &tpx; - int i, rc; - int option = -1, Cap10_100 = 0, Cap1000 = 0; - - printf ( "r8169.c: Found %s, Vendor=%hX Device=%hX\n", - pci->driver_name, pci->vendor, pci->device ); - - board_idx++; - - printed_version = 1; - - /* Quick and very dirty hack to get r8169 driver working - * again, pre-rewrite +static void rtl8169_get_mac_version(struct rtl8169_private *tp, + void *ioaddr) +{ + /* + * The driver currently handles the 8168Bf and the 8168Be identically + * but they can be identified more specifically through the test below + * if needed: + * + * (RTL_R32(TxConfig) & 0x700000) == 0x500000 ? 8168Bf : 8168Be + * + * Same thing for the 8101Eb and the 8101Ec: + * + * (RTL_R32(TxConfig) & 0x700000) == 0x200000 ? 8101Eb : 8101Ec */ - if ( ! r8169_bufs ) - r8169_bufs = malloc_dma ( sizeof ( *r8169_bufs ), 256 ); - if ( ! r8169_bufs ) - return 0; - memset ( r8169_bufs, 0, sizeof ( *r8169_bufs ) ); - - rc = rtl8169_init_board(pci); /* Return code is meaningless */ - - /* Get MAC address. FIXME: read EEPROM */ - for (i = 0; i < MAC_ADDR_LEN; i++) - nic->node_addr[i] = RTL_R8(MAC0 + i); - - DBG ( "%s: Identified chip type is '%s'.\n", pci->driver_name, - rtl_chip_info[tp->chipset].name ); - - /* Print out some hardware info */ - DBG ( "%s: %s at ioaddr %#hx, ", pci->driver_name, eth_ntoa ( nic->node_addr ), - (unsigned int) ioaddr ); + const struct { + u32 mask; + u32 val; + int mac_version; + } mac_info[] = { + /* 8168D family. */ + { 0x7c800000, 0x28000000, RTL_GIGA_MAC_VER_25 }, + + /* 8168C family. */ + { 0x7cf00000, 0x3ca00000, RTL_GIGA_MAC_VER_24 }, + { 0x7cf00000, 0x3c900000, RTL_GIGA_MAC_VER_23 }, + { 0x7cf00000, 0x3c800000, RTL_GIGA_MAC_VER_18 }, + { 0x7c800000, 0x3c800000, RTL_GIGA_MAC_VER_24 }, + { 0x7cf00000, 0x3c000000, RTL_GIGA_MAC_VER_19 }, + { 0x7cf00000, 0x3c200000, RTL_GIGA_MAC_VER_20 }, + { 0x7cf00000, 0x3c300000, RTL_GIGA_MAC_VER_21 }, + { 0x7cf00000, 0x3c400000, RTL_GIGA_MAC_VER_22 }, + { 0x7c800000, 0x3c000000, RTL_GIGA_MAC_VER_22 }, - /* Config PHY */ - rtl8169_hw_phy_config(nic); - - DBG("Set MAC Reg C+CR Offset 0x82h = 0x01h\n"); - RTL_W8(0x82, 0x01); + /* 8168B family. */ + { 0x7cf00000, 0x38000000, RTL_GIGA_MAC_VER_12 }, + { 0x7cf00000, 0x38500000, RTL_GIGA_MAC_VER_17 }, + { 0x7c800000, 0x38000000, RTL_GIGA_MAC_VER_17 }, + { 0x7c800000, 0x30000000, RTL_GIGA_MAC_VER_11 }, - pci_write_config_byte(pci, PCI_LATENCY_TIMER, 0x40); + /* 8101 family. */ + { 0x7cf00000, 0x34a00000, RTL_GIGA_MAC_VER_09 }, + { 0x7cf00000, 0x24a00000, RTL_GIGA_MAC_VER_09 }, + { 0x7cf00000, 0x34900000, RTL_GIGA_MAC_VER_08 }, + { 0x7cf00000, 0x24900000, RTL_GIGA_MAC_VER_08 }, + { 0x7cf00000, 0x34800000, RTL_GIGA_MAC_VER_07 }, + { 0x7cf00000, 0x24800000, RTL_GIGA_MAC_VER_07 }, + { 0x7cf00000, 0x34000000, RTL_GIGA_MAC_VER_13 }, + { 0x7cf00000, 0x34300000, RTL_GIGA_MAC_VER_10 }, + { 0x7cf00000, 0x34200000, RTL_GIGA_MAC_VER_16 }, + { 0x7c800000, 0x34800000, RTL_GIGA_MAC_VER_09 }, + { 0x7c800000, 0x24800000, RTL_GIGA_MAC_VER_09 }, + { 0x7c800000, 0x34000000, RTL_GIGA_MAC_VER_16 }, + /* FIXME: where did these entries come from ? -- FR */ + { 0xfc800000, 0x38800000, RTL_GIGA_MAC_VER_15 }, + { 0xfc800000, 0x30800000, RTL_GIGA_MAC_VER_14 }, - if (tp->mac_version <= RTL_GIGA_MAC_VER_06) - pci_write_config_byte(pci, PCI_CACHE_LINE_SIZE, 0x08); + /* 8110 family. */ + { 0xfc800000, 0x98000000, RTL_GIGA_MAC_VER_06 }, + { 0xfc800000, 0x18000000, RTL_GIGA_MAC_VER_05 }, + { 0xfc800000, 0x10000000, RTL_GIGA_MAC_VER_04 }, + { 0xfc800000, 0x04000000, RTL_GIGA_MAC_VER_03 }, + { 0xfc800000, 0x00800000, RTL_GIGA_MAC_VER_02 }, + { 0xfc800000, 0x00000000, RTL_GIGA_MAC_VER_01 }, - if (tp->mac_version == RTL_GIGA_MAC_VER_02) { - DBG("Set MAC Reg C+CR Offset 0x82h = 0x01h\n"); - RTL_W8(0x82, 0x01); - DBG("Set PHY Reg 0x0bh = 0x00h\n"); - RTL8169_WRITE_GMII_REG(ioaddr, 0x0b, 0x0000); //w 0x0b 15 0 0 - } + { 0x00000000, 0x00000000, RTL_GIGA_MAC_VER_01 } /* Catch-all */ + }, *p = mac_info; + u32 reg; - r8169_reset(nic); - - /* if TBI is not endbled */ - if (!(RTL_R8(PHYstatus) & TBI_Enable)) { - int val = RTL8169_READ_GMII_REG(ioaddr, PHY_AUTO_NEGO_REG); - -#ifdef RTL8169_HW_FLOW_CONTROL_SUPPORT - val |= PHY_Cap_PAUSE | PHY_Cap_ASYM_PAUSE; -#endif //end #define RTL8169_HW_FLOW_CONTROL_SUPPORT - - /* Force RTL8169 in 10/100/1000 Full/Half mode. */ - if (option > 0) { - printf(" Force-mode Enabled.\n"); - Cap10_100 = 0, Cap1000 = 0; - switch (option) { - case _10_Half: - Cap10_100 = PHY_Cap_10_Half; - Cap1000 = PHY_Cap_Null; - break; - case _10_Full: - Cap10_100 = PHY_Cap_10_Full; - Cap1000 = PHY_Cap_Null; - break; - case _100_Half: - Cap10_100 = PHY_Cap_100_Half; - Cap1000 = PHY_Cap_Null; - break; - case _100_Full: - Cap10_100 = PHY_Cap_100_Full; - Cap1000 = PHY_Cap_Null; - break; - case _1000_Full: - Cap10_100 = PHY_Cap_Null; - Cap1000 = PHY_Cap_1000_Full; - break; - default: - break; - } - RTL8169_WRITE_GMII_REG(ioaddr, PHY_AUTO_NEGO_REG, Cap10_100 | (val & 0xC1F)); //leave PHY_AUTO_NEGO_REG bit4:0 unchanged - RTL8169_WRITE_GMII_REG(ioaddr, PHY_1000_CTRL_REG, - Cap1000); - } else { - DBG ( "%s: Auto-negotiation Enabled.\n", pci->driver_name ); - - // enable 10/100 Full/Half Mode, leave PHY_AUTO_NEGO_REG bit4:0 unchanged - RTL8169_WRITE_GMII_REG(ioaddr, PHY_AUTO_NEGO_REG, - PHY_Cap_10_Half | - PHY_Cap_10_Full | - PHY_Cap_100_Half | - PHY_Cap_100_Full | (val & - 0xC1F)); - - // enable 1000 Full Mode -// RTL8169_WRITE_GMII_REG( ioaddr, PHY_1000_CTRL_REG, PHY_Cap_1000_Full ); - RTL8169_WRITE_GMII_REG(ioaddr, PHY_1000_CTRL_REG, PHY_Cap_1000_Full | PHY_Cap_1000_Half); //rtl8168 - - } // end of if( option > 0 ) - - // Enable auto-negotiation and restart auto-nigotiation - RTL8169_WRITE_GMII_REG(ioaddr, PHY_CTRL_REG, - PHY_Enable_Auto_Nego | - PHY_Restart_Auto_Nego); - udelay(100); - - // wait for auto-negotiation process - for (i = 10000; i > 0; i--) { - //check if auto-negotiation complete - if (RTL8169_READ_GMII_REG(ioaddr, PHY_STAT_REG) & - PHY_Auto_Neco_Comp) { - udelay(100); - option = RTL_R8(PHYstatus); - if (option & _1000bpsF) { - printf - ("1000Mbps Full-duplex operation.\n"); - } else { - printf - ("%sMbps %s-duplex operation.\n", - (option & _100bps) ? "100" : - "10", - (option & FullDup) ? "Full" : - "Half"); - } - break; - } else { - udelay(100); - } // end of if( RTL8169_READ_GMII_REG(ioaddr, 1) & 0x20 ) - } // end for-loop to wait for auto-negotiation process + DBGP ( "rtl8169_get_mac_version\n" ); + reg = RTL_R32(TxConfig); + while ((reg & p->mask) != p->val) + p++; + tp->mac_version = p->mac_version; - } else { - udelay(100); - printf - ("%s: 1000Mbps Full-duplex operation, TBI Link %s!\n", - pci->driver_name, - (RTL_R32(TBICSR) & TBILinkOK) ? "OK" : "Failed"); + DBG ( "tp->mac_version = %d\n", tp->mac_version ); + if (p->mask == 0x00000000) { + DBG ( "unknown MAC (%08x)\n", reg ); } - - r8169_reset(nic); - - /* point to NIC specific routines */ - nic->nic_op = &r8169_operations; - - nic->irqno = pci->irq; - nic->ioaddr = ioaddr; - - return 1; -} - -//====================================================================================================== -/* -static void rtl8169_hw_PHY_reset(struct nic *nic __unused) -{ - int val, phy_reset_expiretime = 50; - struct rtl8169_private *priv = dev->priv; - unsigned long ioaddr = priv->ioaddr; - - DBG("%s: Reset RTL8169s PHY\n", dev->name); - - val = ( RTL8169_READ_GMII_REG( ioaddr, 0 ) | 0x8000 ) & 0xffff; - RTL8169_WRITE_GMII_REG( ioaddr, 0, val ); - - do //waiting for phy reset - { - if( RTL8169_READ_GMII_REG( ioaddr, 0 ) & 0x8000 ){ - phy_reset_expiretime --; - udelay(100); - } - else{ - break; - } - }while( phy_reset_expiretime >= 0 ); - - assert( phy_reset_expiretime > 0 ); } -*/ - struct phy_reg { u16 reg; u16 val; @@ -1161,8 +436,10 @@ struct phy_reg { static void rtl_phy_write(void *ioaddr, struct phy_reg *regs, int len) { + DBGP ( "rtl_phy_write\n" ); + while (len-- > 0) { - RTL8169_WRITE_GMII_REG((u32)ioaddr, regs->reg, regs->val); + mdio_write(ioaddr, regs->reg, regs->val); regs++; } } @@ -1201,22 +478,24 @@ static void rtl8169s_hw_phy_config(void *ioaddr) }, *p = phy_magic; unsigned int i; - RTL8169_WRITE_GMII_REG((u32)ioaddr, 0x1f, 0x0001); //w 31 2 0 1 - RTL8169_WRITE_GMII_REG((u32)ioaddr, 0x15, 0x1000); //w 21 15 0 1000 - RTL8169_WRITE_GMII_REG((u32)ioaddr, 0x18, 0x65c7); //w 24 15 0 65c7 - RTL8169_WRITE_GMII_REG_BIT((u32)ioaddr, 4, 11, 0); //w 4 11 11 0 + DBGP ( "rtl8169s_hw_phy_config\n" ); + + mdio_write(ioaddr, 0x1f, 0x0001); //w 31 2 0 1 + mdio_write(ioaddr, 0x15, 0x1000); //w 21 15 0 1000 + mdio_write(ioaddr, 0x18, 0x65c7); //w 24 15 0 65c7 + rtl8169_write_gmii_reg_bit(ioaddr, 4, 11, 0); //w 4 11 11 0 for (i = 0; i < ARRAY_SIZE(phy_magic); i++, p++) { int val, pos = 4; - val = (RTL8169_READ_GMII_REG((u32)ioaddr, pos) & 0x0fff) | (p->regs[0] & 0xffff); - RTL8169_WRITE_GMII_REG((u32)ioaddr, pos, val); + val = (mdio_read(ioaddr, pos) & 0x0fff) | (p->regs[0] & 0xffff); + mdio_write(ioaddr, pos, val); while (--pos >= 0) - RTL8169_WRITE_GMII_REG((u32)ioaddr, pos, p->regs[4 - pos] & 0xffff); - RTL8169_WRITE_GMII_REG_BIT((u32)ioaddr, 4, 11, 1); //w 4 11 11 1 - RTL8169_WRITE_GMII_REG_BIT((u32)ioaddr, 4, 11, 0); //w 4 11 11 0 + mdio_write(ioaddr, pos, p->regs[4 - pos] & 0xffff); + rtl8169_write_gmii_reg_bit(ioaddr, 4, 11, 1); //w 4 11 11 1 + rtl8169_write_gmii_reg_bit(ioaddr, 4, 11, 0); //w 4 11 11 0 } - RTL8169_WRITE_GMII_REG((u32)ioaddr, 0x1f, 0x0000); //w 31 2 0 0 + mdio_write(ioaddr, 0x1f, 0x0000); //w 31 2 0 0 } static void rtl8169sb_hw_phy_config(void *ioaddr) @@ -1227,10 +506,40 @@ static void rtl8169sb_hw_phy_config(void *ioaddr) { 0x1f, 0x0000 } }; + DBGP ( "rtl8169sb_hw_phy_config\n" ); + + rtl_phy_write(ioaddr, phy_reg_init, ARRAY_SIZE(phy_reg_init)); +} + +static void rtl8168bb_hw_phy_config(void *ioaddr) +{ + struct phy_reg phy_reg_init[] = { + { 0x10, 0xf41b }, + { 0x1f, 0x0000 } + }; + + mdio_write(ioaddr, 0x1f, 0x0001); + mdio_patch(ioaddr, 0x16, 1 << 0); + + DBGP ( "rtl8168bb_hw_phy_config\n" ); + + rtl_phy_write(ioaddr, phy_reg_init, ARRAY_SIZE(phy_reg_init)); +} + +static void rtl8168bef_hw_phy_config(void *ioaddr) +{ + struct phy_reg phy_reg_init[] = { + { 0x1f, 0x0001 }, + { 0x10, 0xf41b }, + { 0x1f, 0x0000 } + }; + + DBGP ( "rtl8168bef_hw_phy_config\n" ); + rtl_phy_write(ioaddr, phy_reg_init, ARRAY_SIZE(phy_reg_init)); } -static void rtl8168cp_hw_phy_config(void *ioaddr) +static void rtl8168cp_1_hw_phy_config(void *ioaddr) { struct phy_reg phy_reg_init[] = { { 0x1f, 0x0000 }, @@ -1240,10 +549,29 @@ static void rtl8168cp_hw_phy_config(void *ioaddr) { 0x1f, 0x0000 } }; + DBGP ( "rtl8168cp_1_hw_phy_config\n" ); + + rtl_phy_write(ioaddr, phy_reg_init, ARRAY_SIZE(phy_reg_init)); +} + +static void rtl8168cp_2_hw_phy_config(void *ioaddr) +{ + struct phy_reg phy_reg_init[] = { + { 0x1f, 0x0001 }, + { 0x1d, 0x3d98 }, + { 0x1f, 0x0000 } + }; + + DBGP ( "rtl8168cp_2_hw_phy_config\n" ); + + mdio_write(ioaddr, 0x1f, 0x0000); + mdio_patch(ioaddr, 0x14, 1 << 5); + mdio_patch(ioaddr, 0x0d, 1 << 5); + rtl_phy_write(ioaddr, phy_reg_init, ARRAY_SIZE(phy_reg_init)); } -static void rtl8168c_hw_phy_config(void *ioaddr) +static void rtl8168c_1_hw_phy_config(void *ioaddr) { struct phy_reg phy_reg_init[] = { { 0x1f, 0x0001 }, @@ -1259,33 +587,180 @@ static void rtl8168c_hw_phy_config(void *ioaddr) { 0x1f, 0x0003 }, { 0x12, 0xc096 }, { 0x16, 0x000a }, - { 0x1f, 0x0000 } + { 0x1f, 0x0000 }, + { 0x1f, 0x0000 }, + { 0x09, 0x2000 }, + { 0x09, 0x0000 } }; + DBGP ( "rtl8168c_1_hw_phy_config\n" ); + rtl_phy_write(ioaddr, phy_reg_init, ARRAY_SIZE(phy_reg_init)); + + mdio_patch(ioaddr, 0x14, 1 << 5); + mdio_patch(ioaddr, 0x0d, 1 << 5); + mdio_write(ioaddr, 0x1f, 0x0000); } -static void rtl8168cx_hw_phy_config(void *ioaddr) +static void rtl8168c_2_hw_phy_config(void *ioaddr) { struct phy_reg phy_reg_init[] = { - { 0x1f, 0x0000 }, + { 0x1f, 0x0001 }, { 0x12, 0x2300 }, + { 0x03, 0x802f }, + { 0x02, 0x4f02 }, + { 0x01, 0x0409 }, + { 0x00, 0xf099 }, + { 0x04, 0x9800 }, + { 0x04, 0x9000 }, + { 0x1d, 0x3d98 }, + { 0x1f, 0x0002 }, + { 0x0c, 0x7eb8 }, + { 0x06, 0x0761 }, { 0x1f, 0x0003 }, { 0x16, 0x0f0a }, - { 0x1f, 0x0000 }, + { 0x1f, 0x0000 } + }; + + DBGP ( "rtl8168c_2_hw_phy_config\n" ); + + rtl_phy_write(ioaddr, phy_reg_init, ARRAY_SIZE(phy_reg_init)); + + mdio_patch(ioaddr, 0x16, 1 << 0); + mdio_patch(ioaddr, 0x14, 1 << 5); + mdio_patch(ioaddr, 0x0d, 1 << 5); + mdio_write(ioaddr, 0x1f, 0x0000); +} + +static void rtl8168c_3_hw_phy_config(void *ioaddr) +{ + struct phy_reg phy_reg_init[] = { + { 0x1f, 0x0001 }, + { 0x12, 0x2300 }, + { 0x1d, 0x3d98 }, { 0x1f, 0x0002 }, { 0x0c, 0x7eb8 }, + { 0x06, 0x5461 }, + { 0x1f, 0x0003 }, + { 0x16, 0x0f0a }, { 0x1f, 0x0000 } }; + DBGP ( "rtl8168c_3_hw_phy_config\n" ); + + rtl_phy_write(ioaddr, phy_reg_init, ARRAY_SIZE(phy_reg_init)); + + mdio_patch(ioaddr, 0x16, 1 << 0); + mdio_patch(ioaddr, 0x14, 1 << 5); + mdio_patch(ioaddr, 0x0d, 1 << 5); + mdio_write(ioaddr, 0x1f, 0x0000); +} + +static void rtl8168c_4_hw_phy_config(void *ioaddr) +{ + DBGP ( "rtl8168c_4_hw_phy_config\n" ); + + rtl8168c_3_hw_phy_config(ioaddr); +} + +static void rtl8168d_hw_phy_config(void *ioaddr) +{ + struct phy_reg phy_reg_init_0[] = { + { 0x1f, 0x0001 }, + { 0x09, 0x2770 }, + { 0x08, 0x04d0 }, + { 0x0b, 0xad15 }, + { 0x0c, 0x5bf0 }, + { 0x1c, 0xf101 }, + { 0x1f, 0x0003 }, + { 0x14, 0x94d7 }, + { 0x12, 0xf4d6 }, + { 0x09, 0xca0f }, + { 0x1f, 0x0002 }, + { 0x0b, 0x0b10 }, + { 0x0c, 0xd1f7 }, + { 0x1f, 0x0002 }, + { 0x06, 0x5461 }, + { 0x1f, 0x0002 }, + { 0x05, 0x6662 }, + { 0x1f, 0x0000 }, + { 0x14, 0x0060 }, + { 0x1f, 0x0000 }, + { 0x0d, 0xf8a0 }, + { 0x1f, 0x0005 }, + { 0x05, 0xffc2 } + }; + + DBGP ( "rtl8168d_hw_phy_config\n" ); + + rtl_phy_write(ioaddr, phy_reg_init_0, ARRAY_SIZE(phy_reg_init_0)); + + if (mdio_read(ioaddr, 0x06) == 0xc400) { + struct phy_reg phy_reg_init_1[] = { + { 0x1f, 0x0005 }, + { 0x01, 0x0300 }, + { 0x1f, 0x0000 }, + { 0x11, 0x401c }, + { 0x16, 0x4100 }, + { 0x1f, 0x0005 }, + { 0x07, 0x0010 }, + { 0x05, 0x83dc }, + { 0x06, 0x087d }, + { 0x05, 0x8300 }, + { 0x06, 0x0101 }, + { 0x06, 0x05f8 }, + { 0x06, 0xf9fa }, + { 0x06, 0xfbef }, + { 0x06, 0x79e2 }, + { 0x06, 0x835f }, + { 0x06, 0xe0f8 }, + { 0x06, 0x9ae1 }, + { 0x06, 0xf89b }, + { 0x06, 0xef31 }, + { 0x06, 0x3b65 }, + { 0x06, 0xaa07 }, + { 0x06, 0x81e4 }, + { 0x06, 0xf89a }, + { 0x06, 0xe5f8 }, + { 0x06, 0x9baf }, + { 0x06, 0x06ae }, + { 0x05, 0x83dc }, + { 0x06, 0x8300 }, + }; + + rtl_phy_write(ioaddr, phy_reg_init_1, + ARRAY_SIZE(phy_reg_init_1)); + } + + mdio_write(ioaddr, 0x1f, 0x0000); +} + +static void rtl8102e_hw_phy_config(void *ioaddr) +{ + struct phy_reg phy_reg_init[] = { + { 0x1f, 0x0003 }, + { 0x08, 0x441d }, + { 0x01, 0x9100 }, + { 0x1f, 0x0000 } + }; + + DBGP ( "rtl8102e_hw_phy_config\n" ); + + mdio_write(ioaddr, 0x1f, 0x0000); + mdio_patch(ioaddr, 0x11, 1 << 12); + mdio_patch(ioaddr, 0x19, 1 << 13); + rtl_phy_write(ioaddr, phy_reg_init, ARRAY_SIZE(phy_reg_init)); } -static void rtl8169_hw_phy_config(struct nic *nic __unused) +static void rtl_hw_phy_config(struct net_device *dev) { - struct rtl8169_private *tp = &tpx; + struct rtl8169_private *tp = netdev_priv(dev); void *ioaddr = tp->mmio_addr; - DBG("rtl8169_hw_phy_config(): card at addr=0x%lx: priv->mac_version=%d, priv->pcfg=%d\n", (unsigned long) ioaddr, tp->mac_version, tp->pcfg); + + DBGP ( "rtl_hw_phy_config\n" ); + + DBG ( "mac_version = 0x%02x\n", tp->mac_version ); switch (tp->mac_version) { case RTL_GIGA_MAC_VER_01: @@ -1297,22 +772,1506 @@ static void rtl8169_hw_phy_config(struct nic *nic __unused) case RTL_GIGA_MAC_VER_04: rtl8169sb_hw_phy_config(ioaddr); break; + case RTL_GIGA_MAC_VER_07: + case RTL_GIGA_MAC_VER_08: + case RTL_GIGA_MAC_VER_09: + rtl8102e_hw_phy_config(ioaddr); + break; + case RTL_GIGA_MAC_VER_11: + rtl8168bb_hw_phy_config(ioaddr); + break; + case RTL_GIGA_MAC_VER_12: + rtl8168bef_hw_phy_config(ioaddr); + break; + case RTL_GIGA_MAC_VER_17: + rtl8168bef_hw_phy_config(ioaddr); + break; case RTL_GIGA_MAC_VER_18: - rtl8168cp_hw_phy_config(ioaddr); + rtl8168cp_1_hw_phy_config(ioaddr); break; case RTL_GIGA_MAC_VER_19: - rtl8168c_hw_phy_config(ioaddr); + rtl8168c_1_hw_phy_config(ioaddr); break; case RTL_GIGA_MAC_VER_20: - rtl8168cx_hw_phy_config(ioaddr); + rtl8168c_2_hw_phy_config(ioaddr); + break; + case RTL_GIGA_MAC_VER_21: + rtl8168c_3_hw_phy_config(ioaddr); + break; + case RTL_GIGA_MAC_VER_22: + rtl8168c_4_hw_phy_config(ioaddr); break; + case RTL_GIGA_MAC_VER_23: + case RTL_GIGA_MAC_VER_24: + rtl8168cp_2_hw_phy_config(ioaddr); + break; + case RTL_GIGA_MAC_VER_25: + rtl8168d_hw_phy_config(ioaddr); + break; + + default: + break; + } +} + +static void rtl8169_phy_reset(struct net_device *dev __unused, + struct rtl8169_private *tp) +{ + void *ioaddr = tp->mmio_addr; + unsigned int i; + + DBGP ( "rtl8169_phy_reset\n" ); + + tp->phy_reset_enable(ioaddr); + for (i = 0; i < 100; i++) { + if (!tp->phy_reset_pending(ioaddr)) + return; + mdelay ( 1 ); + } + DBG ( "PHY reset failed.\n" ); +} + +static void rtl8169_init_phy(struct net_device *dev, struct rtl8169_private *tp) +{ + void *ioaddr = tp->mmio_addr; + + DBGP ( "rtl8169_init_phy\n" ); + + rtl_hw_phy_config(dev); + + if (tp->mac_version <= RTL_GIGA_MAC_VER_06) { + DBG ( "Set MAC Reg C+CR Offset 0x82h = 0x01h\n" ); + RTL_W8(0x82, 0x01); + } + + pci_write_config_byte(tp->pci_dev, PCI_LATENCY_TIMER, 0x40); + + if (tp->mac_version <= RTL_GIGA_MAC_VER_06) + pci_write_config_byte(tp->pci_dev, PCI_CACHE_LINE_SIZE, 0x08); + + if (tp->mac_version == RTL_GIGA_MAC_VER_02) { + DBG ( "Set MAC Reg C+CR Offset 0x82h = 0x01h\n" ); + RTL_W8(0x82, 0x01); + DBG ( "Set PHY Reg 0x0bh = 0x00h\n" ); + mdio_write(ioaddr, 0x0b, 0x0000); //w 0x0b 15 0 0 + } + + rtl8169_phy_reset(dev, tp); + + /* + * rtl8169_set_speed_xmii takes good care of the Fast Ethernet + * only 8101. Don't panic. + */ + rtl8169_set_speed(dev, AUTONEG_ENABLE, SPEED_1000, DUPLEX_FULL); + + if ((RTL_R8(PHYstatus) & TBI_Enable)) + DBG ( "TBI auto-negotiating\n" ); +} + +static const struct rtl_cfg_info { + void (*hw_start)(struct net_device *); + unsigned int region; + unsigned int align; + u16 intr_event; + u16 napi_event; + unsigned features; +} rtl_cfg_infos [] = { + [RTL_CFG_0] = { + .hw_start = rtl_hw_start_8169, + .region = 1, + .align = 0, + .intr_event = SYSErr | LinkChg | RxOverflow | + RxFIFOOver | TxErr | TxOK | RxOK | RxErr, + .napi_event = RxFIFOOver | TxErr | TxOK | RxOK | RxOverflow, + .features = RTL_FEATURE_GMII + }, + [RTL_CFG_1] = { + .hw_start = rtl_hw_start_8168, + .region = 2, + .align = 8, + .intr_event = SYSErr | LinkChg | RxOverflow | + TxErr | TxOK | RxOK | RxErr, + .napi_event = TxErr | TxOK | RxOK | RxOverflow, + .features = RTL_FEATURE_GMII + }, + [RTL_CFG_2] = { + .hw_start = rtl_hw_start_8101, + .region = 2, + .align = 8, + .intr_event = SYSErr | LinkChg | RxOverflow | PCSTimeout | + RxFIFOOver | TxErr | TxOK | RxOK | RxErr, + .napi_event = RxFIFOOver | TxErr | TxOK | RxOK | RxOverflow, + } +}; + +static void rtl8169_hw_reset(void *ioaddr) +{ + DBGP ( "rtl8169_hw_reset\n" ); + + /* Disable interrupts */ + rtl8169_irq_mask_and_ack(ioaddr); + + /* Reset the chipset */ + RTL_W8(ChipCmd, CmdReset); + + /* PCI commit */ + RTL_R8(ChipCmd); +} + +static void rtl_set_rx_tx_config_registers(struct rtl8169_private *tp) +{ + void *ioaddr = tp->mmio_addr; + u32 cfg = rtl8169_rx_config; + + DBGP ( "rtl_set_rx_tx_config_registers\n" ); + + cfg |= (RTL_R32(RxConfig) & rtl_chip_info[tp->chipset].RxConfigMask); + RTL_W32(RxConfig, cfg); + + /* Set DMA burst size and Interframe Gap Time */ + RTL_W32(TxConfig, (TX_DMA_BURST << TxDMAShift) | + (InterFrameGap << TxInterFrameGapShift)); +} + +static void rtl_soft_reset ( struct net_device *dev ) +{ + struct rtl8169_private *tp = netdev_priv(dev); + void *ioaddr = tp->mmio_addr; + unsigned int i; + + DBGP ( "rtl_hw_soft_reset\n" ); + + /* Soft reset the chip. */ + RTL_W8(ChipCmd, CmdReset); + + /* Check that the chip has finished the reset. */ + for (i = 0; i < 100; i++) { + if ((RTL_R8(ChipCmd) & CmdReset) == 0) + break; + mdelay ( 1 ); + } + + if ( i == 100 ) { + DBG ( "Reset Failed! (> 100 iterations)\n" ); + } +} + +static void rtl_hw_start ( struct net_device *dev ) +{ + struct rtl8169_private *tp = netdev_priv ( dev ); + + DBGP ( "rtl_hw_start\n" ); + + /* Soft reset NIC */ + rtl_soft_reset ( dev ); + + tp->hw_start ( dev ); +} + +static void rtl_set_rx_tx_desc_registers(struct rtl8169_private *tp, + void *ioaddr) +{ + DBGP ( "rtl_set_rx_tx_desc_registers\n" ); + + /* + * Magic spell: some iop3xx ARM board needs the TxDescAddrHigh + * register to be written before TxDescAddrLow to work. + * Switching from MMIO to I/O access fixes the issue as well. + */ + RTL_W32 ( TxDescStartAddrHigh, 0 ); + RTL_W32 ( TxDescStartAddrLow, virt_to_bus ( tp->tx_base ) ); + RTL_W32 ( RxDescAddrHigh, 0 ); + RTL_W32 ( RxDescAddrLow, virt_to_bus ( tp->rx_base ) ); +} + +static u16 rtl_rw_cpluscmd(void *ioaddr) +{ + u16 cmd; + + DBGP ( "rtl_rw_cpluscmd\n" ); + + cmd = RTL_R16(CPlusCmd); + RTL_W16(CPlusCmd, cmd); + return cmd; +} + +static void rtl_set_rx_max_size(void *ioaddr) +{ + DBGP ( "rtl_set_rx_max_size\n" ); + + RTL_W16 ( RxMaxSize, RX_BUF_SIZE ); +} + +static void rtl8169_set_magic_reg(void *ioaddr, unsigned mac_version) +{ + struct { + u32 mac_version; + u32 clk; + u32 val; + } cfg2_info [] = { + { RTL_GIGA_MAC_VER_05, PCI_Clock_33MHz, 0x000fff00 }, // 8110SCd + { RTL_GIGA_MAC_VER_05, PCI_Clock_66MHz, 0x000fffff }, + { RTL_GIGA_MAC_VER_06, PCI_Clock_33MHz, 0x00ffff00 }, // 8110SCe + { RTL_GIGA_MAC_VER_06, PCI_Clock_66MHz, 0x00ffffff } + }, *p = cfg2_info; + unsigned int i; + u32 clk; + + DBGP ( "rtl8169_set_magic_reg\n" ); + + clk = RTL_R8(Config2) & PCI_Clock_66MHz; + for (i = 0; i < ARRAY_SIZE(cfg2_info); i++, p++) { + if ((p->mac_version == mac_version) && (p->clk == clk)) { + RTL_W32(0x7c, p->val); + break; + } + } +} + +static void rtl_set_rx_mode ( struct net_device *netdev ) +{ + struct rtl8169_private *tp = netdev_priv ( netdev ); + void *ioaddr = tp->mmio_addr; + u32 tmp; + + DBGP ( "rtl_set_rx_mode\n" ); + + /* Accept all Multicast Packets */ + + RTL_W32 ( MAR0 + 0, 0xffffffff ); + RTL_W32 ( MAR0 + 4, 0xffffffff ); + + tmp = rtl8169_rx_config | AcceptBroadcast | AcceptMulticast | AcceptMyPhys | + ( RTL_R32 ( RxConfig ) & rtl_chip_info[tp->chipset].RxConfigMask ); + + RTL_W32 ( RxConfig, tmp ); +} + +static void rtl_hw_start_8169(struct net_device *dev) +{ + struct rtl8169_private *tp = netdev_priv(dev); + void *ioaddr = tp->mmio_addr; + struct pci_device *pdev = tp->pci_dev; + + DBGP ( "rtl_hw_start_8169\n" ); + + if (tp->mac_version == RTL_GIGA_MAC_VER_05) { + RTL_W16(CPlusCmd, RTL_R16(CPlusCmd) | PCIMulRW); + pci_write_config_byte(pdev, PCI_CACHE_LINE_SIZE, 0x08); + } + + RTL_W8(Cfg9346, Cfg9346_Unlock); + + if ((tp->mac_version == RTL_GIGA_MAC_VER_01) || + (tp->mac_version == RTL_GIGA_MAC_VER_02) || + (tp->mac_version == RTL_GIGA_MAC_VER_03) || + (tp->mac_version == RTL_GIGA_MAC_VER_04)) + RTL_W8(ChipCmd, CmdTxEnb | CmdRxEnb); + + RTL_W8(EarlyTxThres, EarlyTxThld); + + rtl_set_rx_max_size(ioaddr); + + if ((tp->mac_version == RTL_GIGA_MAC_VER_01) || + (tp->mac_version == RTL_GIGA_MAC_VER_02) || + (tp->mac_version == RTL_GIGA_MAC_VER_03) || + (tp->mac_version == RTL_GIGA_MAC_VER_04)) + rtl_set_rx_tx_config_registers(tp); + + tp->cp_cmd |= rtl_rw_cpluscmd(ioaddr) | PCIMulRW; + + if ((tp->mac_version == RTL_GIGA_MAC_VER_02) || + (tp->mac_version == RTL_GIGA_MAC_VER_03)) { + DBG ( "Set MAC Reg C+CR Offset 0xE0. " + "Bit-3 and bit-14 MUST be 1\n" ); + tp->cp_cmd |= (1 << 14); + } + + RTL_W16(CPlusCmd, tp->cp_cmd); + + rtl8169_set_magic_reg(ioaddr, tp->mac_version); + + /* + * Undocumented corner. Supposedly: + * (TxTimer << 12) | (TxPackets << 8) | (RxTimer << 4) | RxPackets + */ + RTL_W16(IntrMitigate, 0x0000); + + rtl_set_rx_tx_desc_registers(tp, ioaddr); + + if ((tp->mac_version != RTL_GIGA_MAC_VER_01) && + (tp->mac_version != RTL_GIGA_MAC_VER_02) && + (tp->mac_version != RTL_GIGA_MAC_VER_03) && + (tp->mac_version != RTL_GIGA_MAC_VER_04)) { + RTL_W8(ChipCmd, CmdTxEnb | CmdRxEnb); + rtl_set_rx_tx_config_registers(tp); + } + + RTL_W8(Cfg9346, Cfg9346_Lock); + + /* Initially a 10 us delay. Turned it into a PCI commit. - FR */ + RTL_R8(IntrMask); + + RTL_W32(RxMissed, 0); + + rtl_set_rx_mode(dev); + + /* no early-rx interrupts */ + RTL_W16(MultiIntr, RTL_R16(MultiIntr) & 0xF000); + + // RTL_W16(IntrMask, tp->intr_event); +} + +static void rtl_tx_performance_tweak(struct pci_device *pdev, u16 force) +{ + struct net_device *dev = pci_get_drvdata(pdev); + struct rtl8169_private *tp = netdev_priv(dev); + int cap = tp->pcie_cap; + + DBGP ( "rtl_tx_performance_tweak\n" ); + + if (cap) { + u16 ctl; + + pci_read_config_word(pdev, cap + PCI_EXP_DEVCTL, &ctl); + ctl = (ctl & ~PCI_EXP_DEVCTL_READRQ) | force; + pci_write_config_word(pdev, cap + PCI_EXP_DEVCTL, ctl); + } +} + +static void rtl_csi_access_enable(void *ioaddr) +{ + u32 csi; + + DBGP ( "rtl_csi_access_enable\n" ); + + csi = rtl_csi_read(ioaddr, 0x070c) & 0x00ffffff; + rtl_csi_write(ioaddr, 0x070c, csi | 0x27000000); +} + +struct ephy_info { + unsigned int offset; + u16 mask; + u16 bits; +}; + +static void rtl_ephy_init(void *ioaddr, struct ephy_info *e, int len) +{ + u16 w; + + DBGP ( "rtl_ephy_init\n" ); + + while (len-- > 0) { + w = (rtl_ephy_read(ioaddr, e->offset) & ~e->mask) | e->bits; + rtl_ephy_write(ioaddr, e->offset, w); + e++; + } +} + +static void rtl_disable_clock_request(struct pci_device *pdev) +{ + struct net_device *dev = pci_get_drvdata(pdev); + struct rtl8169_private *tp = netdev_priv(dev); + int cap = tp->pcie_cap; + + DBGP ( "rtl_disable_clock_request\n" ); + + if (cap) { + u16 ctl; + + pci_read_config_word(pdev, cap + PCI_EXP_LNKCTL, &ctl); + ctl &= ~PCI_EXP_LNKCTL_CLKREQ_EN; + pci_write_config_word(pdev, cap + PCI_EXP_LNKCTL, ctl); + } +} + +#define R8168_CPCMD_QUIRK_MASK (\ + EnableBist | \ + Mac_dbgo_oe | \ + Force_half_dup | \ + Force_rxflow_en | \ + Force_txflow_en | \ + Cxpl_dbg_sel | \ + ASF | \ + PktCntrDisable | \ + Mac_dbgo_sel) + +static void rtl_hw_start_8168bb(void *ioaddr, struct pci_device *pdev) +{ + DBGP ( "rtl_hw_start_8168bb\n" ); + + RTL_W8(Config3, RTL_R8(Config3) & ~Beacon_en); + + RTL_W16(CPlusCmd, RTL_R16(CPlusCmd) & ~R8168_CPCMD_QUIRK_MASK); + + rtl_tx_performance_tweak(pdev, + (0x5 << MAX_READ_REQUEST_SHIFT) | PCI_EXP_DEVCTL_NOSNOOP_EN); +} + +static void rtl_hw_start_8168bef(void *ioaddr, struct pci_device *pdev) +{ + DBGP ( "rtl_hw_start_8168bef\n" ); + + rtl_hw_start_8168bb(ioaddr, pdev); + + RTL_W8(EarlyTxThres, EarlyTxThld); + + RTL_W8(Config4, RTL_R8(Config4) & ~(1 << 0)); +} + +static void __rtl_hw_start_8168cp(void *ioaddr, struct pci_device *pdev) +{ + DBGP ( "__rtl_hw_start_8168cp\n" ); + + RTL_W8(Config1, RTL_R8(Config1) | Speed_down); + + RTL_W8(Config3, RTL_R8(Config3) & ~Beacon_en); + + rtl_tx_performance_tweak(pdev, 0x5 << MAX_READ_REQUEST_SHIFT); + + rtl_disable_clock_request(pdev); + + RTL_W16(CPlusCmd, RTL_R16(CPlusCmd) & ~R8168_CPCMD_QUIRK_MASK); +} + +static void rtl_hw_start_8168cp_1(void *ioaddr, struct pci_device *pdev) +{ + static struct ephy_info e_info_8168cp[] = { + { 0x01, 0, 0x0001 }, + { 0x02, 0x0800, 0x1000 }, + { 0x03, 0, 0x0042 }, + { 0x06, 0x0080, 0x0000 }, + { 0x07, 0, 0x2000 } + }; + + DBGP ( "rtl_hw_start_8168cp_1\n" ); + + rtl_csi_access_enable(ioaddr); + + rtl_ephy_init(ioaddr, e_info_8168cp, ARRAY_SIZE(e_info_8168cp)); + + __rtl_hw_start_8168cp(ioaddr, pdev); +} + +static void rtl_hw_start_8168cp_2(void *ioaddr, struct pci_device *pdev) +{ + DBGP ( "rtl_hw_start_8168cp_2\n" ); + + rtl_csi_access_enable(ioaddr); + + RTL_W8(Config3, RTL_R8(Config3) & ~Beacon_en); + + rtl_tx_performance_tweak(pdev, 0x5 << MAX_READ_REQUEST_SHIFT); + + RTL_W16(CPlusCmd, RTL_R16(CPlusCmd) & ~R8168_CPCMD_QUIRK_MASK); +} + +static void rtl_hw_start_8168cp_3(void *ioaddr, struct pci_device *pdev) +{ + DBGP ( "rtl_hw_start_8168cp_3\n" ); + + rtl_csi_access_enable(ioaddr); + + RTL_W8(Config3, RTL_R8(Config3) & ~Beacon_en); + + /* Magic. */ + RTL_W8(DBG_REG, 0x20); + + RTL_W8(EarlyTxThres, EarlyTxThld); + + rtl_tx_performance_tweak(pdev, 0x5 << MAX_READ_REQUEST_SHIFT); + + RTL_W16(CPlusCmd, RTL_R16(CPlusCmd) & ~R8168_CPCMD_QUIRK_MASK); +} + +static void rtl_hw_start_8168c_1(void *ioaddr, struct pci_device *pdev) +{ + static struct ephy_info e_info_8168c_1[] = { + { 0x02, 0x0800, 0x1000 }, + { 0x03, 0, 0x0002 }, + { 0x06, 0x0080, 0x0000 } + }; + + DBGP ( "rtl_hw_start_8168c_1\n" ); + + rtl_csi_access_enable(ioaddr); + + RTL_W8(DBG_REG, 0x06 | FIX_NAK_1 | FIX_NAK_2); + + rtl_ephy_init(ioaddr, e_info_8168c_1, ARRAY_SIZE(e_info_8168c_1)); + + __rtl_hw_start_8168cp(ioaddr, pdev); +} + +static void rtl_hw_start_8168c_2(void *ioaddr, struct pci_device *pdev) +{ + static struct ephy_info e_info_8168c_2[] = { + { 0x01, 0, 0x0001 }, + { 0x03, 0x0400, 0x0220 } + }; + + DBGP ( "rtl_hw_start_8168c_2\n" ); + + rtl_csi_access_enable(ioaddr); + + rtl_ephy_init(ioaddr, e_info_8168c_2, ARRAY_SIZE(e_info_8168c_2)); + + __rtl_hw_start_8168cp(ioaddr, pdev); +} + +static void rtl_hw_start_8168c_3(void *ioaddr, struct pci_device *pdev) +{ + DBGP ( "rtl_hw_start_8168c_3\n" ); + + rtl_hw_start_8168c_2(ioaddr, pdev); +} + +static void rtl_hw_start_8168c_4(void *ioaddr, struct pci_device *pdev) +{ + DBGP ( "rtl_hw_start_8168c_4\n" ); + + rtl_csi_access_enable(ioaddr); + + __rtl_hw_start_8168cp(ioaddr, pdev); +} + +static void rtl_hw_start_8168d(void *ioaddr, struct pci_device *pdev) +{ + DBGP ( "rtl_hw_start_8168d\n" ); + + rtl_csi_access_enable(ioaddr); + + rtl_disable_clock_request(pdev); + + RTL_W8(EarlyTxThres, EarlyTxThld); + + rtl_tx_performance_tweak(pdev, 0x5 << MAX_READ_REQUEST_SHIFT); + + RTL_W16(CPlusCmd, RTL_R16(CPlusCmd) & ~R8168_CPCMD_QUIRK_MASK); +} + +static void rtl_hw_start_8168(struct net_device *dev) +{ + struct rtl8169_private *tp = netdev_priv(dev); + void *ioaddr = tp->mmio_addr; + struct pci_device *pdev = tp->pci_dev; + + DBGP ( "rtl_hw_start_8168\n" ); + + RTL_W8(Cfg9346, Cfg9346_Unlock); + + RTL_W8(EarlyTxThres, EarlyTxThld); + + rtl_set_rx_max_size(ioaddr); + + tp->cp_cmd |= RTL_R16(CPlusCmd) | PktCntrDisable | INTT_1; + + RTL_W16(CPlusCmd, tp->cp_cmd); + + RTL_W16(IntrMitigate, 0x5151); + + /* Work around for RxFIFO overflow. */ + if (tp->mac_version == RTL_GIGA_MAC_VER_11) { + tp->intr_event |= RxFIFOOver | PCSTimeout; + tp->intr_event &= ~RxOverflow; + } + + rtl_set_rx_tx_desc_registers(tp, ioaddr); + + rtl_set_rx_mode(dev); + + RTL_W32(TxConfig, (TX_DMA_BURST << TxDMAShift) | + (InterFrameGap << TxInterFrameGapShift)); + + RTL_R8(IntrMask); + + switch (tp->mac_version) { + case RTL_GIGA_MAC_VER_11: + rtl_hw_start_8168bb(ioaddr, pdev); + break; + + case RTL_GIGA_MAC_VER_12: + case RTL_GIGA_MAC_VER_17: + rtl_hw_start_8168bef(ioaddr, pdev); + break; + + case RTL_GIGA_MAC_VER_18: + rtl_hw_start_8168cp_1(ioaddr, pdev); + break; + + case RTL_GIGA_MAC_VER_19: + rtl_hw_start_8168c_1(ioaddr, pdev); + break; + + case RTL_GIGA_MAC_VER_20: + rtl_hw_start_8168c_2(ioaddr, pdev); + break; + + case RTL_GIGA_MAC_VER_21: + rtl_hw_start_8168c_3(ioaddr, pdev); + break; + + case RTL_GIGA_MAC_VER_22: + rtl_hw_start_8168c_4(ioaddr, pdev); + break; + + case RTL_GIGA_MAC_VER_23: + rtl_hw_start_8168cp_2(ioaddr, pdev); + break; + + case RTL_GIGA_MAC_VER_24: + rtl_hw_start_8168cp_3(ioaddr, pdev); + break; + + case RTL_GIGA_MAC_VER_25: + rtl_hw_start_8168d(ioaddr, pdev); + break; + default: + DBG ( "Unknown chipset (mac_version = %d).\n", + tp->mac_version ); + break; + } + + RTL_W8(ChipCmd, CmdTxEnb | CmdRxEnb); + + RTL_W8(Cfg9346, Cfg9346_Lock); + + RTL_W16(MultiIntr, RTL_R16(MultiIntr) & 0xF000); + + // RTL_W16(IntrMask, tp->intr_event); +} + +#define R810X_CPCMD_QUIRK_MASK (\ + EnableBist | \ + Mac_dbgo_oe | \ + Force_half_dup | \ + Force_half_dup | \ + Force_txflow_en | \ + Cxpl_dbg_sel | \ + ASF | \ + PktCntrDisable | \ + PCIDAC | \ + PCIMulRW) + +static void rtl_hw_start_8102e_1(void *ioaddr, struct pci_device *pdev) +{ + static struct ephy_info e_info_8102e_1[] = { + { 0x01, 0, 0x6e65 }, + { 0x02, 0, 0x091f }, + { 0x03, 0, 0xc2f9 }, + { 0x06, 0, 0xafb5 }, + { 0x07, 0, 0x0e00 }, + { 0x19, 0, 0xec80 }, + { 0x01, 0, 0x2e65 }, + { 0x01, 0, 0x6e65 } + }; + u8 cfg1; + + DBGP ( "rtl_hw_start_8102e_1\n" ); + + rtl_csi_access_enable(ioaddr); + + RTL_W8(DBG_REG, FIX_NAK_1); + + rtl_tx_performance_tweak(pdev, 0x5 << MAX_READ_REQUEST_SHIFT); + + RTL_W8(Config1, + LEDS1 | LEDS0 | Speed_down | MEMMAP | IOMAP | VPD | PMEnable); + RTL_W8(Config3, RTL_R8(Config3) & ~Beacon_en); + + cfg1 = RTL_R8(Config1); + if ((cfg1 & LEDS0) && (cfg1 & LEDS1)) + RTL_W8(Config1, cfg1 & ~LEDS0); + + RTL_W16(CPlusCmd, RTL_R16(CPlusCmd) & ~R810X_CPCMD_QUIRK_MASK); + + rtl_ephy_init(ioaddr, e_info_8102e_1, ARRAY_SIZE(e_info_8102e_1)); +} + +static void rtl_hw_start_8102e_2(void *ioaddr, struct pci_device *pdev) +{ + DBGP ( "rtl_hw_start_8102e_2\n" ); + + rtl_csi_access_enable(ioaddr); + + rtl_tx_performance_tweak(pdev, 0x5 << MAX_READ_REQUEST_SHIFT); + + RTL_W8(Config1, MEMMAP | IOMAP | VPD | PMEnable); + RTL_W8(Config3, RTL_R8(Config3) & ~Beacon_en); + + RTL_W16(CPlusCmd, RTL_R16(CPlusCmd) & ~R810X_CPCMD_QUIRK_MASK); +} + +static void rtl_hw_start_8102e_3(void *ioaddr, struct pci_device *pdev) +{ + DBGP ( "rtl_hw_start_8102e_3\n" ); + + rtl_hw_start_8102e_2(ioaddr, pdev); + + rtl_ephy_write(ioaddr, 0x03, 0xc2f9); +} + +static void rtl_hw_start_8101(struct net_device *dev) +{ + struct rtl8169_private *tp = netdev_priv(dev); + void *ioaddr = tp->mmio_addr; + struct pci_device *pdev = tp->pci_dev; + + DBGP ( "rtl_hw_start_8101\n" ); + + if ((tp->mac_version == RTL_GIGA_MAC_VER_13) || + (tp->mac_version == RTL_GIGA_MAC_VER_16)) { + int cap = tp->pcie_cap; + + if (cap) { + pci_write_config_word(pdev, cap + PCI_EXP_DEVCTL, + PCI_EXP_DEVCTL_NOSNOOP_EN); + } + } + + switch (tp->mac_version) { + case RTL_GIGA_MAC_VER_07: + rtl_hw_start_8102e_1(ioaddr, pdev); + break; + + case RTL_GIGA_MAC_VER_08: + rtl_hw_start_8102e_3(ioaddr, pdev); + break; + + case RTL_GIGA_MAC_VER_09: + rtl_hw_start_8102e_2(ioaddr, pdev); + break; + } + + RTL_W8(Cfg9346, Cfg9346_Unlock); + + RTL_W8(EarlyTxThres, EarlyTxThld); + + rtl_set_rx_max_size(ioaddr); + + tp->cp_cmd |= rtl_rw_cpluscmd(ioaddr) | PCIMulRW; + + RTL_W16(CPlusCmd, tp->cp_cmd); + + RTL_W16(IntrMitigate, 0x0000); + + rtl_set_rx_tx_desc_registers(tp, ioaddr); + + RTL_W8(ChipCmd, CmdTxEnb | CmdRxEnb); + rtl_set_rx_tx_config_registers(tp); + + RTL_W8(Cfg9346, Cfg9346_Lock); + + RTL_R8(IntrMask); + + rtl_set_rx_mode(dev); + + RTL_W8(ChipCmd, CmdTxEnb | CmdRxEnb); + + RTL_W16(MultiIntr, RTL_R16(MultiIntr) & 0xf000); + + // RTL_W16(IntrMask, tp->intr_event); +} + +/*** gPXE API Support Routines ***/ + +/** + * setup_tx_resources - allocate tx resources (descriptors) + * + * @v tp Driver private storage + * + * @ret rc Returns 0 on success, negative on failure + **/ +static int +rtl8169_setup_tx_resources ( struct rtl8169_private *tp ) +{ + DBGP ( "rtl8169_setup_tx_resources\n" ); + + tp->tx_base = malloc_dma ( R8169_TX_RING_BYTES, TX_RING_ALIGN ); + + if ( ! tp->tx_base ) { + return -ENOMEM; + } + + memset ( tp->tx_base, 0, R8169_TX_RING_BYTES ); + + DBG ( "tp->tx_base = %#08lx\n", virt_to_bus ( tp->tx_base ) ); + + tp->tx_fill_ctr = 0; + tp->tx_curr = 0; + tp->tx_tail = 0; + + return 0; +} + +static void +rtl8169_process_tx_packets ( struct net_device *netdev ) +{ + struct rtl8169_private *tp = netdev_priv ( netdev ); + + uint32_t tx_status; + struct TxDesc *tx_curr_desc; + + DBGP ( "rtl8169_process_tx_packets\n" ); + + while ( tp->tx_tail != tp->tx_curr ) { + + tx_curr_desc = tp->tx_base + tp->tx_tail; + + tx_status = tx_curr_desc->opts1; + + DBG2 ( "Before DescOwn check tx_status: %#08x\n", tx_status ); + + /* if the packet at tx_tail is not owned by hardware it is for us */ + if ( tx_status & DescOwn ) + break; + + DBG ( "Transmitted packet.\n" ); + DBG ( "tp->tx_fill_ctr = %d\n", tp->tx_fill_ctr ); + DBG ( "tp->tx_tail = %d\n", tp->tx_tail ); + DBG ( "tp->tx_curr = %d\n", tp->tx_curr ); + DBG ( "tx_status = %d\n", tx_status ); + DBG ( "tx_curr_desc = %#08lx\n", virt_to_bus ( tx_curr_desc ) ); + + /* Pass packet to core for processing */ + netdev_tx_complete ( netdev, tp->tx_iobuf[tp->tx_tail] ); + + memset ( tx_curr_desc, 0, sizeof ( *tx_curr_desc ) ); + + /* Decrement count of used descriptors */ + tp->tx_fill_ctr--; + + /* Increment sent packets index */ + tp->tx_tail = ( tp->tx_tail + 1 ) % NUM_TX_DESC; + } +} + +static void +rtl8169_free_tx_resources ( struct rtl8169_private *tp ) +{ + DBGP ( "rtl8169_free_tx_resources\n" ); + + free_dma ( tp->tx_base, R8169_TX_RING_BYTES ); +} + +static void +rtl8169_populate_rx_descriptor ( struct rtl8169_private *tp, struct RxDesc *rx_desc, uint32_t index ) +{ + DBGP ( "rtl8169_populate_rx_descriptor\n" ); + + DBG ( "Populating rx descriptor %d\n", index ); + + memset ( rx_desc, 0, sizeof ( *rx_desc ) ); + + rx_desc->addr_hi = 0; + rx_desc->addr_lo = virt_to_bus ( tp->rx_iobuf[index]->data ); + rx_desc->opts2 = 0; + rx_desc->opts1 = ( index == ( NUM_RX_DESC - 1 ) ? RingEnd : 0 ) | + RX_BUF_SIZE; + rx_desc->opts1 |= DescOwn; +} + +/** + * Refill descriptor ring + * + * @v netdev Net device + */ +static void rtl8169_refill_rx_ring ( struct rtl8169_private *tp ) +{ + struct RxDesc *rx_curr_desc; + int i; + + DBGP ( "rtl8169_refill_rx_ring\n" ); + + for ( i = 0; i < NUM_RX_DESC; i++ ) { + + rx_curr_desc = ( tp->rx_base ) + i; + + /* Don't touch descriptors owned by the NIC */ + if ( rx_curr_desc->opts1 & DescOwn ) + continue; + + /* Don't touch descriptors with iobufs, they still need to be + processed by the poll routine */ + if ( tp->rx_iobuf[tp->rx_curr] != NULL ) + continue; + + /** If we can't get an iobuf for this descriptor + try again later (next poll). + */ + if ( ! ( tp->rx_iobuf[i] = alloc_iob ( RX_BUF_SIZE ) ) ) { + DBG ( "Refill rx ring failed!!\n" ); + break; + } + + rtl8169_populate_rx_descriptor ( tp, rx_curr_desc, i ); + } +} + +/** + * setup_rx_resources - allocate Rx resources (Descriptors) + * + * @v tp: Driver private structure + * + * @ret rc Returns 0 on success, negative on failure + * + **/ +static int +rtl8169_setup_rx_resources ( struct rtl8169_private *tp ) +{ + DBGP ( "rtl8169_setup_rx_resources\n" ); + + tp->rx_base = malloc_dma ( R8169_RX_RING_BYTES, RX_RING_ALIGN ); + + DBG ( "tp->rx_base = %#08lx\n", virt_to_bus ( tp->rx_base ) ); + + if ( ! tp->rx_base ) { + return -ENOMEM; + } + memset ( tp->rx_base, 0, R8169_RX_RING_BYTES ); + + rtl8169_refill_rx_ring ( tp ); + + tp->rx_curr = 0; + + return 0; +} + +static void +rtl8169_process_rx_packets ( struct net_device *netdev ) +{ + struct rtl8169_private *tp = netdev_priv ( netdev ); + uint32_t rx_status; + uint16_t rx_len; + struct RxDesc *rx_curr_desc; + int i; + + DBGP ( "rtl8169_process_rx_packets\n" ); + + for ( i = 0; i < NUM_RX_DESC; i++ ) { + + rx_curr_desc = tp->rx_base + tp->rx_curr; + + rx_status = rx_curr_desc->opts1; + + DBG2 ( "Before DescOwn check rx_status: %#08x\n", rx_status ); + + /* Hardware still owns the descriptor */ + if ( rx_status & DescOwn ) + break; + + /* We own the descriptor, but it has not been refilled yet */ + if ( tp->rx_iobuf[tp->rx_curr] == NULL ) + break; + + rx_len = rx_status & 0x3fff; + + DBG ( "Received packet.\n" ); + DBG ( "tp->rx_curr = %d\n", tp->rx_curr ); + DBG ( "rx_len = %d\n", rx_len ); + DBG ( "rx_status = %#08x\n", rx_status ); + DBG ( "rx_curr_desc = %#08lx\n", virt_to_bus ( rx_curr_desc ) ); + + if ( rx_status & RxRES ) { + + netdev_rx_err ( netdev, tp->rx_iobuf[tp->rx_curr], -EINVAL ); + + DBG ( "rtl8169_poll: Corrupted packet received!\n" + " rx_status: %#08x\n", rx_status ); + + } else { + + /* Adjust size of the iobuf to reflect received data */ + iob_put ( tp->rx_iobuf[tp->rx_curr], rx_len ); + + /* Add this packet to the receive queue. */ + netdev_rx ( netdev, tp->rx_iobuf[tp->rx_curr] ); + } + + /* Invalidate this iobuf and descriptor */ + tp->rx_iobuf[tp->rx_curr] = NULL; + memset ( rx_curr_desc, 0, sizeof ( *rx_curr_desc ) ); + + /* Update pointer to next available rx descriptor */ + tp->rx_curr = ( tp->rx_curr + 1 ) % NUM_RX_DESC; + } + rtl8169_refill_rx_ring ( tp ); +} + +static void +rtl8169_free_rx_resources ( struct rtl8169_private *tp ) +{ + int i; + + DBGP ( "rtl8169_free_rx_resources\n" ); + + free_dma ( tp->rx_base, R8169_RX_RING_BYTES ); + + for ( i = 0; i < NUM_RX_DESC; i++ ) { + free_iob ( tp->rx_iobuf[i] ); + tp->rx_iobuf[i] = NULL; + } +} + +/** + FIXME: Because gPXE's pci_device_id structure does not contain a + field to contain arbitrary data, we need the following table to + associate PCI IDs with nic variants, because a lot of driver + routines depend on knowing which kind of variant they are dealing + with. --mdc + **/ + +#define _R(VENDOR,DEVICE,INDEX) \ + { .vendor = VENDOR, .device = DEVICE, .index = INDEX } + +static const struct { + uint16_t vendor; + uint16_t device; + int index; +} nic_variant_table[] = { + _R(0x10ec, 0x8129, RTL_CFG_0), + _R(0x10ec, 0x8136, RTL_CFG_2), + _R(0x10ec, 0x8167, RTL_CFG_0), + _R(0x10ec, 0x8168, RTL_CFG_1), + _R(0x10ec, 0x8169, RTL_CFG_0), + _R(0x1186, 0x4300, RTL_CFG_0), + _R(0x1259, 0xc107, RTL_CFG_0), + _R(0x16ec, 0x0116, RTL_CFG_0), + _R(0x1737, 0x1032, RTL_CFG_0), + _R(0x0001, 0x8168, RTL_CFG_2), +}; +#undef _R + +static int +rtl8169_get_nic_variant ( uint16_t vendor, uint16_t device ) +{ + u32 i; + + DBGP ( "rtl8169_get_nic_variant\n" ); + + for (i = 0; i < ARRAY_SIZE(nic_variant_table); i++) { + if ( ( nic_variant_table[i].vendor == vendor ) && + ( nic_variant_table[i].device == device ) ) { + return ( nic_variant_table[i].index ); + } + } + DBG ( "No matching NIC variant found!\n" ); + return ( RTL_CFG_0 ); +} + +static void rtl8169_irq_enable ( struct rtl8169_private *tp ) +{ + void *ioaddr = tp->mmio_addr; + + DBGP ( "rtl8169_irq_enable\n" ); + + RTL_W16 ( IntrMask, tp->intr_event ); +} + +static void rtl8169_irq_disable ( struct rtl8169_private *tp ) +{ + void *ioaddr = tp->mmio_addr; + + DBGP ( "rtl8169_irq_disable\n" ); + + rtl8169_irq_mask_and_ack ( ioaddr ); +} + +/*** gPXE Core API Routines ***/ + +/** + * open - Called when a network interface is made active + * + * @v netdev network interface device structure + * @ret rc Return status code, 0 on success, negative value on failure + * + **/ +static int +rtl8169_open ( struct net_device *netdev ) +{ + struct rtl8169_private *tp = netdev_priv ( netdev ); + void *ioaddr = tp->mmio_addr; + int rc; + + DBGP ( "rtl8169_open\n" ); + + /* allocate transmit descriptors */ + rc = rtl8169_setup_tx_resources ( tp ); + if ( rc ) { + DBG ( "Error setting up TX resources!\n" ); + goto err_setup_tx; + } + + /* allocate receive descriptors */ + rc = rtl8169_setup_rx_resources ( tp ); + if ( rc ) { + DBG ( "Error setting up RX resources!\n" ); + goto err_setup_rx; + } + + rtl_hw_start ( netdev ); + + DBG ( "TxDescStartAddrHigh = %#08lx\n", RTL_R32 ( TxDescStartAddrHigh ) ); + DBG ( "TxDescStartAddrLow = %#08lx\n", RTL_R32 ( TxDescStartAddrLow ) ); + DBG ( "RxDescAddrHigh = %#08lx\n", RTL_R32 ( RxDescAddrHigh ) ); + DBG ( "RxDescAddrLow = %#08lx\n", RTL_R32 ( RxDescAddrLow ) ); + + return 0; + +err_setup_rx: + rtl8169_free_tx_resources ( tp ); +err_setup_tx: + rtl8169_hw_reset ( ioaddr ); + + return rc; +} + +/** + * transmit - Transmit a packet + * + * @v netdev Network device + * @v iobuf I/O buffer + * + * @ret rc Returns 0 on success, negative on failure + */ +static int +rtl8169_transmit ( struct net_device *netdev, struct io_buffer *iobuf ) +{ + struct rtl8169_private *tp = netdev_priv ( netdev ); + void *ioaddr = tp->mmio_addr; + uint32_t tx_len = iob_len ( iobuf ); + + struct TxDesc *tx_curr_desc; + + DBGP ("rtl8169_transmit\n"); + + if ( tp->tx_fill_ctr == NUM_TX_DESC ) { + DBG ("TX overflow\n"); + return -ENOBUFS; + } + + /** + * The rtl8169 family automatically pads short packets to a + * minimum size, but if it did not, like some older cards, + * we could do: + * iob_pad ( iobuf, ETH_ZLEN ); + */ + + /* Save pointer to this iobuf we have been given to transmit so + we can pass it to netdev_tx_complete() later */ + tp->tx_iobuf[tp->tx_curr] = iobuf; + + tx_curr_desc = tp->tx_base + tp->tx_curr; + + DBG ( "tp->tx_fill_ctr = %d\n", tp->tx_fill_ctr ); + DBG ( "tp->tx_curr = %d\n", tp->tx_curr ); + DBG ( "tx_curr_desc = %#08lx\n", virt_to_bus ( tx_curr_desc ) ); + DBG ( "iobuf->data = %#08lx\n", virt_to_bus ( iobuf->data ) ); + DBG ( "tx_len = %d\n", tx_len ); + + /* Configure current descriptor to transmit supplied packet */ + tx_curr_desc->addr_hi = 0; + tx_curr_desc->addr_lo = virt_to_bus ( iobuf->data ); + tx_curr_desc->opts2 = 0; + tx_curr_desc->opts1 = FirstFrag | LastFrag | + ( tp->tx_curr == ( NUM_TX_DESC - 1 ) ? RingEnd : 0 ) | + tx_len; + + /* Mark descriptor as owned by NIC */ + tx_curr_desc->opts1 |= DescOwn; + + DBG ( "tx_curr_desc->opts1 = %#08x\n", tx_curr_desc->opts1 ); + DBG ( "tx_curr_desc->opts2 = %#08x\n", tx_curr_desc->opts2 ); + DBG ( "tx_curr_desc->addr_hi = %#08x\n", tx_curr_desc->addr_hi ); + DBG ( "tx_curr_desc->addr_lo = %#08x\n", tx_curr_desc->addr_lo ); + + RTL_W8 ( TxPoll, NPQ ); /* set polling bit */ + + /* Point to next free descriptor */ + tp->tx_curr = ( tp->tx_curr + 1 ) % NUM_TX_DESC; + + /* Increment number of tx descriptors in use */ + tp->tx_fill_ctr++; + + return 0; +} + +/** + * poll - Poll for received packets + * + * @v netdev Network device + */ +static void +rtl8169_poll ( struct net_device *netdev ) +{ + struct rtl8169_private *tp = netdev_priv ( netdev ); + void *ioaddr = tp->mmio_addr; + + uint16_t intr_status; + uint16_t intr_mask; + + DBGP ( "rtl8169_poll\n" ); + + intr_status = RTL_R16 ( IntrStatus ); + intr_mask = RTL_R16 ( IntrMask ); + + DBG2 ( "rtl8169_poll (before): intr_mask = %#04x intr_status = %#04x\n", + intr_mask, intr_status ); + + RTL_W16 ( IntrStatus, 0xffff ); + + /* hotplug / major error / no more work / shared irq */ + if ( intr_status == 0xffff ) + return; + + /* Process transmitted packets */ + rtl8169_process_tx_packets ( netdev ); + + /* Process received packets */ + rtl8169_process_rx_packets ( netdev ); +} + +/** + * close - Disable network interface + * + * @v netdev network interface device structure + * + **/ +static void +rtl8169_close ( struct net_device *netdev ) +{ + struct rtl8169_private *tp = netdev_priv ( netdev ); + void *ioaddr = tp->mmio_addr; + + DBGP ( "r8169_close\n" ); + + rtl8169_hw_reset ( ioaddr ); + + rtl8169_free_tx_resources ( tp ); + rtl8169_free_rx_resources ( tp ); +} + +/** + * irq - enable or Disable interrupts + * + * @v netdev network adapter + * @v action requested interrupt action + * + **/ +static void +rtl8169_irq ( struct net_device *netdev, int action ) +{ + struct rtl8169_private *tp = netdev_priv ( netdev ); + + DBGP ( "rtl8169_irq\n" ); + + switch ( action ) { + case 0 : + rtl8169_irq_disable ( tp ); + break; + default : + rtl8169_irq_enable ( tp ); break; } } -DRIVER ( "r8169/PCI", nic_driver, pci_driver, r8169_driver, - r8169_probe, r8169_disable ); +static struct net_device_operations rtl8169_operations = { + .open = rtl8169_open, + .transmit = rtl8169_transmit, + .poll = rtl8169_poll, + .close = rtl8169_close, + .irq = rtl8169_irq, +}; + +/** + * probe - Initial configuration of NIC + * + * @v pci PCI device + * @v id PCI IDs + * + * @ret rc Return status code + **/ +static int +rtl8169_probe ( struct pci_device *pdev, const struct pci_device_id *ent ) +{ + int i, rc; + struct net_device *netdev; + struct rtl8169_private *tp; + void *ioaddr; + + /** FIXME: This lookup is necessary because gPXE does not have a "data" + element in the structure pci_device_id which can pass an arbitrary + piece of data to the driver. It might be useful to add it. Then we + could just use ent->data instead of having to look up cfg_index. + **/ + int cfg_index = rtl8169_get_nic_variant ( ent->vendor, ent->device ); + const struct rtl_cfg_info *cfg = rtl_cfg_infos + cfg_index; + + DBGP ( "rtl8169_probe\n" ); + + DBG ( "ent->vendor = %#04x, ent->device = %#04x\n", ent->vendor, ent->device ); + + DBG ( "cfg_index = %d\n", cfg_index ); + DBG ( "cfg->intr_event = %#04x\n", cfg->intr_event ); + + rc = -ENOMEM; + + /* Allocate net device ( also allocates memory for netdev->priv + and makes netdev-priv point to it ) + */ + netdev = alloc_etherdev ( sizeof ( *tp ) ); + + if ( ! netdev ) + goto err_alloc_etherdev; + + /* Associate driver-specific network operations with + generic network device layer + */ + netdev_init ( netdev, &rtl8169_operations ); + + /* Associate this network device with the given PCI device */ + pci_set_drvdata ( pdev, netdev ); + netdev->dev = &pdev->dev; + + /* Initialize driver private storage */ + tp = netdev_priv ( netdev ); + memset ( tp, 0, ( sizeof ( *tp ) ) ); + + tp->pci_dev = pdev; + tp->irqno = pdev->irq; + tp->netdev = netdev; + tp->cfg_index = cfg_index; + tp->intr_event = cfg->intr_event; + tp->cp_cmd = PCIMulRW; + + tp->hw_start = cfg->hw_start; + + rc = -EIO; + + adjust_pci_device ( pdev ); + + /* ioremap MMIO region */ + ioaddr = ioremap ( pdev->membase, R8169_REGS_SIZE ); + + if ( ! ioaddr ) { + DBG ( "cannot remap MMIO\n" ); + rc = -EIO; + goto err_ioremap; + } + + tp->mmio_addr = ioaddr; + + tp->pcie_cap = pci_find_capability ( pdev, PCI_CAP_ID_EXP ); + if ( tp->pcie_cap ) { + DBG ( "PCI Express capability\n" ); + } else { + DBG ( "No PCI Express capability\n" ); + } + + /* Mask interrupts just in case */ + rtl8169_irq_mask_and_ack ( ioaddr ); + + /* Soft reset NIC */ + rtl_soft_reset ( netdev ); + + /* Identify chip attached to board */ + rtl8169_get_mac_version ( tp, ioaddr ); + + for ( i = 0; (u32) i < ARRAY_SIZE ( rtl_chip_info ); i++ ) { + if ( tp->mac_version == rtl_chip_info[i].mac_version ) + break; + } + if ( i == ARRAY_SIZE(rtl_chip_info ) ) { + /* Unknown chip: assume array element #0, original RTL-8169 */ + DBG ( "Unknown chip version, assuming %s\n", rtl_chip_info[0].name ); + i = 0; + } + tp->chipset = i; + + if ((tp->mac_version <= RTL_GIGA_MAC_VER_06) && + (RTL_R8(PHYstatus) & TBI_Enable)) { + tp->set_speed = rtl8169_set_speed_tbi; + tp->phy_reset_enable = rtl8169_tbi_reset_enable; + tp->phy_reset_pending = rtl8169_tbi_reset_pending; + tp->link_ok = rtl8169_tbi_link_ok; + + tp->phy_1000_ctrl_reg = ADVERTISE_1000FULL; /* Implied by TBI */ + } else { + tp->set_speed = rtl8169_set_speed_xmii; + tp->phy_reset_enable = rtl8169_xmii_reset_enable; + tp->phy_reset_pending = rtl8169_xmii_reset_pending; + tp->link_ok = rtl8169_xmii_link_ok; + } + + /* Get MAC address */ + for ( i = 0; i < MAC_ADDR_LEN; i++ ) + netdev->ll_addr[i] = RTL_R8 ( MAC0 + i ); + + DBG ( "%s\n", eth_ntoa ( netdev->ll_addr ) ); + + rtl8169_init_phy ( netdev, tp ); + + if ( ( rc = register_netdev ( netdev ) ) != 0 ) + goto err_register; + + /* Mark as link up; we don't yet handle link state */ + netdev_link_up ( netdev ); + + DBG ( "rtl8169_probe succeeded!\n" ); + + /* No errors, return success */ + return 0; + +/* Error return paths */ +err_register: +err_ioremap: + netdev_put ( netdev ); +err_alloc_etherdev: + return rc; +} + +/** + * remove - Device Removal Routine + * + * @v pdev PCI device information struct + * + **/ +static void +rtl8169_remove ( struct pci_device *pdev ) +{ + struct net_device *netdev = pci_get_drvdata ( pdev ); + struct rtl8169_private *tp = netdev_priv ( netdev ); + void *ioaddr = tp->mmio_addr; + + DBGP ( "rtl8169_remove\n" ); + + rtl8169_hw_reset ( ioaddr ); + + unregister_netdev ( netdev ); + netdev_nullify ( netdev ); + netdev_put ( netdev ); +} + +static struct pci_device_id rtl8169_nics[] = { + PCI_ROM(0x10ec, 0x8129, "rtl8169-0x8129", "rtl8169-0x8129"), + PCI_ROM(0x10ec, 0x8136, "rtl8169-0x8136", "rtl8169-0x8136"), + PCI_ROM(0x10ec, 0x8167, "rtl8169-0x8167", "rtl8169-0x8167"), + PCI_ROM(0x10ec, 0x8168, "rtl8169-0x8168", "rtl8169-0x8168"), + PCI_ROM(0x10ec, 0x8169, "rtl8169-0x8169", "rtl8169-0x8169"), + PCI_ROM(0x1186, 0x4300, "rtl8169-0x4300", "rtl8169-0x4300"), + PCI_ROM(0x1259, 0xc107, "rtl8169-0xc107", "rtl8169-0xc107"), + PCI_ROM(0x16ec, 0x0116, "rtl8169-0x0116", "rtl8169-0x0116"), + PCI_ROM(0x1737, 0x1032, "rtl8169-0x1032", "rtl8169-0x1032"), + PCI_ROM(0x0001, 0x8168, "rtl8169-0x8168", "rtl8169-0x8168"), +}; + +struct pci_driver rtl8169_driver __pci_driver = { + .ids = rtl8169_nics, + .id_count = ( sizeof ( rtl8169_nics ) / sizeof ( rtl8169_nics[0] ) ), + .probe = rtl8169_probe, + .remove = rtl8169_remove, +}; /* * Local variables: diff --git a/gpxe/src/drivers/net/r8169.h b/gpxe/src/drivers/net/r8169.h new file mode 100644 index 00000000..d3536326 --- /dev/null +++ b/gpxe/src/drivers/net/r8169.h @@ -0,0 +1,566 @@ +/* + * Copyright (c) 2008 Marty Connor <mdc@etherboot.org> + * Copyright (c) 2008 Entity Cyber, Inc. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of the + * License, or any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + * + * This driver is based on rtl8169 data sheets and work by: + * + * Copyright (c) 2002 ShuChen <shuchen@realtek.com.tw> + * Copyright (c) 2003 - 2007 Francois Romieu <romieu@fr.zoreil.com> + * Copyright (c) a lot of people too. Please respect their work. + * + */ + +#ifndef _R8169_H_ +#define _R8169_H_ + +#define ARRAY_SIZE(x) (sizeof(x) / sizeof((x)[0])) + +/** FIXME: include/linux/pci_regs.h has these PCI regs, maybe + we need such a file in gPXE? +**/ +#define PCI_EXP_DEVCTL 8 /* Device Control */ +#define PCI_EXP_DEVCTL_READRQ 0x7000 /* Max_Read_Request_Size */ +#define PCI_EXP_LNKCTL 16 /* Link Control */ +#define PCI_EXP_LNKCTL_CLKREQ_EN 0x100 /* Enable clkreq */ +#define PCI_EXP_DEVCTL_NOSNOOP_EN 0x0800 /* Enable No Snoop */ + +/** FIXME: update mii.h in src/include/mii.h from Linux sources + so we don't have to include these definitiions. +**/ +/* The forced speed, 10Mb, 100Mb, gigabit, 2.5Gb, 10GbE. */ +#define SPEED_10 10 +#define SPEED_100 100 +#define SPEED_1000 1000 +#define SPEED_2500 2500 +#define SPEED_10000 10000 + +/* Duplex, half or full. */ +#define DUPLEX_HALF 0x00 +#define DUPLEX_FULL 0x01 + +/* Generic MII registers. */ + +#define MII_BMCR 0x00 /* Basic mode control register */ +#define MII_BMSR 0x01 /* Basic mode status register */ +#define MII_PHYSID1 0x02 /* PHYS ID 1 */ +#define MII_PHYSID2 0x03 /* PHYS ID 2 */ +#define MII_ADVERTISE 0x04 /* Advertisement control reg */ +#define MII_LPA 0x05 /* Link partner ability reg */ +#define MII_EXPANSION 0x06 /* Expansion register */ +#define MII_CTRL1000 0x09 /* 1000BASE-T control */ +#define MII_STAT1000 0x0a /* 1000BASE-T status */ +#define MII_ESTATUS 0x0f /* Extended Status */ +#define MII_DCOUNTER 0x12 /* Disconnect counter */ +#define MII_FCSCOUNTER 0x13 /* False carrier counter */ +#define MII_NWAYTEST 0x14 /* N-way auto-neg test reg */ +#define MII_RERRCOUNTER 0x15 /* Receive error counter */ +#define MII_SREVISION 0x16 /* Silicon revision */ +#define MII_RESV1 0x17 /* Reserved... */ +#define MII_LBRERROR 0x18 /* Lpback, rx, bypass error */ +#define MII_PHYADDR 0x19 /* PHY address */ +#define MII_RESV2 0x1a /* Reserved... */ +#define MII_TPISTATUS 0x1b /* TPI status for 10mbps */ +#define MII_NCONFIG 0x1c /* Network interface config */ + +/* Basic mode control register. */ +#define BMCR_RESV 0x003f /* Unused... */ +#define BMCR_SPEED1000 0x0040 /* MSB of Speed (1000) */ +#define BMCR_CTST 0x0080 /* Collision test */ +#define BMCR_FULLDPLX 0x0100 /* Full duplex */ +#define BMCR_ANRESTART 0x0200 /* Auto negotiation restart */ +#define BMCR_ISOLATE 0x0400 /* Disconnect DP83840 from MII */ +#define BMCR_PDOWN 0x0800 /* Powerdown the DP83840 */ +#define BMCR_ANENABLE 0x1000 /* Enable auto negotiation */ +#define BMCR_SPEED100 0x2000 /* Select 100Mbps */ +#define BMCR_LOOPBACK 0x4000 /* TXD loopback bits */ +#define BMCR_RESET 0x8000 /* Reset the DP83840 */ + +/* Basic mode status register. */ +#define BMSR_ERCAP 0x0001 /* Ext-reg capability */ +#define BMSR_JCD 0x0002 /* Jabber detected */ +#define BMSR_LSTATUS 0x0004 /* Link status */ +#define BMSR_ANEGCAPABLE 0x0008 /* Able to do auto-negotiation */ +#define BMSR_RFAULT 0x0010 /* Remote fault detected */ +#define BMSR_ANEGCOMPLETE 0x0020 /* Auto-negotiation complete */ +#define BMSR_RESV 0x00c0 /* Unused... */ +#define BMSR_ESTATEN 0x0100 /* Extended Status in R15 */ +#define BMSR_100HALF2 0x0200 /* Can do 100BASE-T2 HDX */ +#define BMSR_100FULL2 0x0400 /* Can do 100BASE-T2 FDX */ +#define BMSR_10HALF 0x0800 /* Can do 10mbps, half-duplex */ +#define BMSR_10FULL 0x1000 /* Can do 10mbps, full-duplex */ +#define BMSR_100HALF 0x2000 /* Can do 100mbps, half-duplex */ +#define BMSR_100FULL 0x4000 /* Can do 100mbps, full-duplex */ +#define BMSR_100BASE4 0x8000 /* Can do 100mbps, 4k packets */ + +#define AUTONEG_DISABLE 0x00 +#define AUTONEG_ENABLE 0x01 + +#define MII_ADVERTISE 0x04 /* Advertisement control reg */ +#define ADVERTISE_SLCT 0x001f /* Selector bits */ +#define ADVERTISE_CSMA 0x0001 /* Only selector supported */ +#define ADVERTISE_10HALF 0x0020 /* Try for 10mbps half-duplex */ +#define ADVERTISE_1000XFULL 0x0020 /* Try for 1000BASE-X full-duplex */ +#define ADVERTISE_10FULL 0x0040 /* Try for 10mbps full-duplex */ +#define ADVERTISE_1000XHALF 0x0040 /* Try for 1000BASE-X half-duplex */ +#define ADVERTISE_100HALF 0x0080 /* Try for 100mbps half-duplex */ +#define ADVERTISE_1000XPAUSE 0x0080 /* Try for 1000BASE-X pause */ +#define ADVERTISE_100FULL 0x0100 /* Try for 100mbps full-duplex */ +#define ADVERTISE_1000XPSE_ASYM 0x0100 /* Try for 1000BASE-X asym pause */ +#define ADVERTISE_100BASE4 0x0200 /* Try for 100mbps 4k packets */ +#define ADVERTISE_PAUSE_CAP 0x0400 /* Try for pause */ +#define ADVERTISE_PAUSE_ASYM 0x0800 /* Try for asymetric pause */ +#define ADVERTISE_RESV 0x1000 /* Unused... */ +#define ADVERTISE_RFAULT 0x2000 /* Say we can detect faults */ +#define ADVERTISE_LPACK 0x4000 /* Ack link partners response */ +#define ADVERTISE_NPAGE 0x8000 /* Next page bit */ +#define ADVERTISE_FULL (ADVERTISE_100FULL | ADVERTISE_10FULL | \ + ADVERTISE_CSMA) +#define ADVERTISE_ALL (ADVERTISE_10HALF | ADVERTISE_10FULL | \ + ADVERTISE_100HALF | ADVERTISE_100FULL) + +/* 1000BASE-T Control register */ +#define ADVERTISE_1000FULL 0x0200 /* Advertise 1000BASE-T full duplex */ +#define ADVERTISE_1000HALF 0x0100 /* Advertise 1000BASE-T half duplex */ + +/* MAC address length */ +#define MAC_ADDR_LEN 6 + +#define MAX_READ_REQUEST_SHIFT 12 +#define RX_FIFO_THRESH 7 /* 7 means NO threshold, Rx buffer level before first PCI xfer. */ +#define RX_DMA_BURST 6 /* Maximum PCI burst, '6' is 1024 */ +#define TX_DMA_BURST 6 /* Maximum PCI burst, '6' is 1024 */ +#define EarlyTxThld 0x3F /* 0x3F means NO early transmit */ +#define RxPacketMaxSize 0x3FE8 /* 16K - 1 - ETH_HLEN - VLAN - CRC... */ +#define SafeMtu 0x1c20 /* ... actually life sucks beyond ~7k */ +#define InterFrameGap 0x03 /* 3 means InterFrameGap = the shortest one */ + +#define R8169_REGS_SIZE 256 +#define R8169_NAPI_WEIGHT 64 +#define NUM_TX_DESC 8 /* Number of Tx descriptor registers */ +#define NUM_RX_DESC 8 /* Number of Rx descriptor registers */ +#define RX_BUF_SIZE 1536 /* Rx Buffer size */ +#define R8169_TX_RING_BYTES (NUM_TX_DESC * sizeof(struct TxDesc)) +#define R8169_RX_RING_BYTES (NUM_RX_DESC * sizeof(struct RxDesc)) + +#define TX_RING_ALIGN 256 +#define RX_RING_ALIGN 256 + +#define RTL8169_TX_TIMEOUT (6*HZ) +#define RTL8169_PHY_TIMEOUT (10*HZ) + +#define RTL_EEPROM_SIG cpu_to_le32(0x8129) +#define RTL_EEPROM_SIG_MASK cpu_to_le32(0xffff) +#define RTL_EEPROM_SIG_ADDR 0x0000 + +/* write/read MMIO register */ +#define RTL_W8(reg, val8) writeb ((val8), ioaddr + (reg)) +#define RTL_W16(reg, val16) writew ((val16), ioaddr + (reg)) +#define RTL_W32(reg, val32) writel ((val32), ioaddr + (reg)) +#define RTL_R8(reg) readb (ioaddr + (reg)) +#define RTL_R16(reg) readw (ioaddr + (reg)) +#define RTL_R32(reg) ((unsigned long) readl (ioaddr + (reg))) + +enum mac_version { + RTL_GIGA_MAC_VER_01 = 0x01, // 8169 + RTL_GIGA_MAC_VER_02 = 0x02, // 8169S + RTL_GIGA_MAC_VER_03 = 0x03, // 8110S + RTL_GIGA_MAC_VER_04 = 0x04, // 8169SB + RTL_GIGA_MAC_VER_05 = 0x05, // 8110SCd + RTL_GIGA_MAC_VER_06 = 0x06, // 8110SCe + RTL_GIGA_MAC_VER_07 = 0x07, // 8102e + RTL_GIGA_MAC_VER_08 = 0x08, // 8102e + RTL_GIGA_MAC_VER_09 = 0x09, // 8102e + RTL_GIGA_MAC_VER_10 = 0x0a, // 8101e + RTL_GIGA_MAC_VER_11 = 0x0b, // 8168Bb + RTL_GIGA_MAC_VER_12 = 0x0c, // 8168Be + RTL_GIGA_MAC_VER_13 = 0x0d, // 8101Eb + RTL_GIGA_MAC_VER_14 = 0x0e, // 8101 ? + RTL_GIGA_MAC_VER_15 = 0x0f, // 8101 ? + RTL_GIGA_MAC_VER_16 = 0x11, // 8101Ec + RTL_GIGA_MAC_VER_17 = 0x10, // 8168Bf + RTL_GIGA_MAC_VER_18 = 0x12, // 8168CP + RTL_GIGA_MAC_VER_19 = 0x13, // 8168C + RTL_GIGA_MAC_VER_20 = 0x14, // 8168C + RTL_GIGA_MAC_VER_21 = 0x15, // 8168C + RTL_GIGA_MAC_VER_22 = 0x16, // 8168C + RTL_GIGA_MAC_VER_23 = 0x17, // 8168CP + RTL_GIGA_MAC_VER_24 = 0x18, // 8168CP + RTL_GIGA_MAC_VER_25 = 0x19, // 8168D +}; + +#define _R(NAME,MAC,MASK) \ + { .name = NAME, .mac_version = MAC, .RxConfigMask = MASK } + +static const struct { + const char *name; + u8 mac_version; + u32 RxConfigMask; /* Clears the bits supported by this chip */ +} rtl_chip_info[] = { + _R("RTL8169", RTL_GIGA_MAC_VER_01, 0xff7e1880), // 8169 + _R("RTL8169s", RTL_GIGA_MAC_VER_02, 0xff7e1880), // 8169S + _R("RTL8110s", RTL_GIGA_MAC_VER_03, 0xff7e1880), // 8110S + _R("RTL8169sb/8110sb", RTL_GIGA_MAC_VER_04, 0xff7e1880), // 8169SB + _R("RTL8169sc/8110sc", RTL_GIGA_MAC_VER_05, 0xff7e1880), // 8110SCd + _R("RTL8169sc/8110sc", RTL_GIGA_MAC_VER_06, 0xff7e1880), // 8110SCe + _R("RTL8102e", RTL_GIGA_MAC_VER_07, 0xff7e1880), // PCI-E + _R("RTL8102e", RTL_GIGA_MAC_VER_08, 0xff7e1880), // PCI-E + _R("RTL8102e", RTL_GIGA_MAC_VER_09, 0xff7e1880), // PCI-E + _R("RTL8101e", RTL_GIGA_MAC_VER_10, 0xff7e1880), // PCI-E + _R("RTL8168b/8111b", RTL_GIGA_MAC_VER_11, 0xff7e1880), // PCI-E + _R("RTL8168b/8111b", RTL_GIGA_MAC_VER_12, 0xff7e1880), // PCI-E + _R("RTL8101e", RTL_GIGA_MAC_VER_13, 0xff7e1880), // PCI-E 8139 + _R("RTL8100e", RTL_GIGA_MAC_VER_14, 0xff7e1880), // PCI-E 8139 + _R("RTL8100e", RTL_GIGA_MAC_VER_15, 0xff7e1880), // PCI-E 8139 + _R("RTL8168b/8111b", RTL_GIGA_MAC_VER_17, 0xff7e1880), // PCI-E + _R("RTL8101e", RTL_GIGA_MAC_VER_16, 0xff7e1880), // PCI-E + _R("RTL8168cp/8111cp", RTL_GIGA_MAC_VER_18, 0xff7e1880), // PCI-E + _R("RTL8168c/8111c", RTL_GIGA_MAC_VER_19, 0xff7e1880), // PCI-E + _R("RTL8168c/8111c", RTL_GIGA_MAC_VER_20, 0xff7e1880), // PCI-E + _R("RTL8168c/8111c", RTL_GIGA_MAC_VER_21, 0xff7e1880), // PCI-E + _R("RTL8168c/8111c", RTL_GIGA_MAC_VER_22, 0xff7e1880), // PCI-E + _R("RTL8168cp/8111cp", RTL_GIGA_MAC_VER_23, 0xff7e1880), // PCI-E + _R("RTL8168cp/8111cp", RTL_GIGA_MAC_VER_24, 0xff7e1880), // PCI-E + _R("RTL8168d/8111d", RTL_GIGA_MAC_VER_25, 0xff7e1880) // PCI-E +}; +#undef _R + +enum cfg_version { + RTL_CFG_0 = 0x00, + RTL_CFG_1, + RTL_CFG_2 +}; + +#if 0 +/** Device Table from Linux Driver **/ +static struct pci_device_id rtl8169_pci_tbl[] = { + { PCI_DEVICE(PCI_VENDOR_ID_REALTEK, 0x8129), 0, 0, RTL_CFG_0 }, + { PCI_DEVICE(PCI_VENDOR_ID_REALTEK, 0x8136), 0, 0, RTL_CFG_2 }, + { PCI_DEVICE(PCI_VENDOR_ID_REALTEK, 0x8167), 0, 0, RTL_CFG_0 }, + { PCI_DEVICE(PCI_VENDOR_ID_REALTEK, 0x8168), 0, 0, RTL_CFG_1 }, + { PCI_DEVICE(PCI_VENDOR_ID_REALTEK, 0x8169), 0, 0, RTL_CFG_0 }, + { PCI_DEVICE(PCI_VENDOR_ID_DLINK, 0x4300), 0, 0, RTL_CFG_0 }, + { PCI_DEVICE(PCI_VENDOR_ID_AT, 0xc107), 0, 0, RTL_CFG_0 }, + { PCI_DEVICE(0x16ec, 0x0116), 0, 0, RTL_CFG_0 }, + { PCI_VENDOR_ID_LINKSYS, 0x1032, + PCI_ANY_ID, 0x0024, 0, 0, RTL_CFG_0 }, + { 0x0001, 0x8168, + PCI_ANY_ID, 0x2410, 0, 0, RTL_CFG_2 }, + {0,}, +}; +#endif + +enum rtl_registers { + MAC0 = 0, /* Ethernet hardware address. */ + MAC4 = 4, + MAR0 = 8, /* Multicast filter. */ + CounterAddrLow = 0x10, + CounterAddrHigh = 0x14, + TxDescStartAddrLow = 0x20, + TxDescStartAddrHigh = 0x24, + TxHDescStartAddrLow = 0x28, + TxHDescStartAddrHigh = 0x2c, + FLASH = 0x30, + ERSR = 0x36, + ChipCmd = 0x37, + TxPoll = 0x38, + IntrMask = 0x3c, + IntrStatus = 0x3e, + TxConfig = 0x40, + RxConfig = 0x44, + RxMissed = 0x4c, + Cfg9346 = 0x50, + Config0 = 0x51, + Config1 = 0x52, + Config2 = 0x53, + Config3 = 0x54, + Config4 = 0x55, + Config5 = 0x56, + MultiIntr = 0x5c, + PHYAR = 0x60, + PHYstatus = 0x6c, + RxMaxSize = 0xda, + CPlusCmd = 0xe0, + IntrMitigate = 0xe2, + RxDescAddrLow = 0xe4, + RxDescAddrHigh = 0xe8, + EarlyTxThres = 0xec, + FuncEvent = 0xf0, + FuncEventMask = 0xf4, + FuncPresetState = 0xf8, + FuncForceEvent = 0xfc, +}; + +enum rtl8110_registers { + TBICSR = 0x64, + TBI_ANAR = 0x68, + TBI_LPAR = 0x6a, +}; + +enum rtl8168_8101_registers { + CSIDR = 0x64, + CSIAR = 0x68, +#define CSIAR_FLAG 0x80000000 +#define CSIAR_WRITE_CMD 0x80000000 +#define CSIAR_BYTE_ENABLE 0x0f +#define CSIAR_BYTE_ENABLE_SHIFT 12 +#define CSIAR_ADDR_MASK 0x0fff + + EPHYAR = 0x80, +#define EPHYAR_FLAG 0x80000000 +#define EPHYAR_WRITE_CMD 0x80000000 +#define EPHYAR_REG_MASK 0x1f +#define EPHYAR_REG_SHIFT 16 +#define EPHYAR_DATA_MASK 0xffff + DBG_REG = 0xd1, +#define FIX_NAK_1 (1 << 4) +#define FIX_NAK_2 (1 << 3) +}; + +enum rtl_register_content { + /* InterruptStatusBits */ + SYSErr = 0x8000, + PCSTimeout = 0x4000, + SWInt = 0x0100, + TxDescUnavail = 0x0080, + RxFIFOOver = 0x0040, + LinkChg = 0x0020, + RxOverflow = 0x0010, + TxErr = 0x0008, + TxOK = 0x0004, + RxErr = 0x0002, + RxOK = 0x0001, + + /* RxStatusDesc */ + RxFOVF = (1 << 23), + RxRWT = (1 << 22), + RxRES = (1 << 21), + RxRUNT = (1 << 20), + RxCRC = (1 << 19), + + /* ChipCmdBits */ + CmdReset = 0x10, + CmdRxEnb = 0x08, + CmdTxEnb = 0x04, + RxBufEmpty = 0x01, + + /* TXPoll register p.5 */ + HPQ = 0x80, /* Poll cmd on the high prio queue */ + NPQ = 0x40, /* Poll cmd on the low prio queue */ + FSWInt = 0x01, /* Forced software interrupt */ + + /* Cfg9346Bits */ + Cfg9346_Lock = 0x00, + Cfg9346_Unlock = 0xc0, + + /* rx_mode_bits */ + AcceptErr = 0x20, + AcceptRunt = 0x10, + AcceptBroadcast = 0x08, + AcceptMulticast = 0x04, + AcceptMyPhys = 0x02, + AcceptAllPhys = 0x01, + + /* RxConfigBits */ + RxCfgFIFOShift = 13, + RxCfgDMAShift = 8, + + /* TxConfigBits */ + TxInterFrameGapShift = 24, + TxDMAShift = 8, /* DMA burst value (0-7) is shift this many bits */ + + /* Config1 register p.24 */ + LEDS1 = (1 << 7), + LEDS0 = (1 << 6), + MSIEnable = (1 << 5), /* Enable Message Signaled Interrupt */ + Speed_down = (1 << 4), + MEMMAP = (1 << 3), + IOMAP = (1 << 2), + VPD = (1 << 1), + PMEnable = (1 << 0), /* Power Management Enable */ + + /* Config2 register p. 25 */ + PCI_Clock_66MHz = 0x01, + PCI_Clock_33MHz = 0x00, + + /* Config3 register p.25 */ + MagicPacket = (1 << 5), /* Wake up when receives a Magic Packet */ + LinkUp = (1 << 4), /* Wake up when the cable connection is re-established */ + Beacon_en = (1 << 0), /* 8168 only. Reserved in the 8168b */ + + /* Config5 register p.27 */ + BWF = (1 << 6), /* Accept Broadcast wakeup frame */ + MWF = (1 << 5), /* Accept Multicast wakeup frame */ + UWF = (1 << 4), /* Accept Unicast wakeup frame */ + LanWake = (1 << 1), /* LanWake enable/disable */ + PMEStatus = (1 << 0), /* PME status can be reset by PCI RST# */ + + /* TBICSR p.28 */ + TBIReset = 0x80000000, + TBILoopback = 0x40000000, + TBINwEnable = 0x20000000, + TBINwRestart = 0x10000000, + TBILinkOk = 0x02000000, + TBINwComplete = 0x01000000, + + /* CPlusCmd p.31 */ + EnableBist = (1 << 15), // 8168 8101 + Mac_dbgo_oe = (1 << 14), // 8168 8101 + Normal_mode = (1 << 13), // unused + Force_half_dup = (1 << 12), // 8168 8101 + Force_rxflow_en = (1 << 11), // 8168 8101 + Force_txflow_en = (1 << 10), // 8168 8101 + Cxpl_dbg_sel = (1 << 9), // 8168 8101 + ASF = (1 << 8), // 8168 8101 + PktCntrDisable = (1 << 7), // 8168 8101 + Mac_dbgo_sel = 0x001c, // 8168 + RxVlan = (1 << 6), + RxChkSum = (1 << 5), + PCIDAC = (1 << 4), + PCIMulRW = (1 << 3), + INTT_0 = 0x0000, // 8168 + INTT_1 = 0x0001, // 8168 + INTT_2 = 0x0002, // 8168 + INTT_3 = 0x0003, // 8168 + + /* rtl8169_PHYstatus */ + TBI_Enable = 0x80, + TxFlowCtrl = 0x40, + RxFlowCtrl = 0x20, + _1000bpsF = 0x10, + _100bps = 0x08, + _10bps = 0x04, + LinkStatus = 0x02, + FullDup = 0x01, + + /* _TBICSRBit */ + TBILinkOK = 0x02000000, + + /* DumpCounterCommand */ + CounterDump = 0x8, +}; + +enum desc_status_bit { + DescOwn = (1 << 31), /* Descriptor is owned by NIC */ + RingEnd = (1 << 30), /* End of descriptor ring */ + FirstFrag = (1 << 29), /* First segment of a packet */ + LastFrag = (1 << 28), /* Final segment of a packet */ + + /* Tx private */ + LargeSend = (1 << 27), /* TCP Large Send Offload (TSO) */ + MSSShift = 16, /* MSS value position */ + MSSMask = 0xfff, /* MSS value + LargeSend bit: 12 bits */ + IPCS = (1 << 18), /* Calculate IP checksum */ + UDPCS = (1 << 17), /* Calculate UDP/IP checksum */ + TCPCS = (1 << 16), /* Calculate TCP/IP checksum */ + TxVlanTag = (1 << 17), /* Add VLAN tag */ + + /* Rx private */ + PID1 = (1 << 18), /* Protocol ID bit 1/2 */ + PID0 = (1 << 17), /* Protocol ID bit 2/2 */ + +#define RxProtoUDP (PID1) +#define RxProtoTCP (PID0) +#define RxProtoIP (PID1 | PID0) +#define RxProtoMask RxProtoIP + + IPFail = (1 << 16), /* IP checksum failed */ + UDPFail = (1 << 15), /* UDP/IP checksum failed */ + TCPFail = (1 << 14), /* TCP/IP checksum failed */ + RxVlanTag = (1 << 16), /* VLAN tag available */ +}; + +#define RsvdMask 0x3fffc000 + +struct TxDesc { + volatile uint32_t opts1; + volatile uint32_t opts2; + volatile uint32_t addr_lo; + volatile uint32_t addr_hi; +}; + +struct RxDesc { + volatile uint32_t opts1; + volatile uint32_t opts2; + volatile uint32_t addr_lo; + volatile uint32_t addr_hi; +}; + +enum features { + RTL_FEATURE_WOL = (1 << 0), + RTL_FEATURE_MSI = (1 << 1), + RTL_FEATURE_GMII = (1 << 2), +}; + +static void rtl_hw_start_8169(struct net_device *); +static void rtl_hw_start_8168(struct net_device *); +static void rtl_hw_start_8101(struct net_device *); + +struct rtl8169_private { + + struct pci_device *pci_dev; + struct net_device *netdev; + uint8_t *hw_addr; + void *mmio_addr; + uint32_t irqno; + + int chipset; + int mac_version; + int cfg_index; + u16 intr_event; + + struct io_buffer *tx_iobuf[NUM_TX_DESC]; + struct io_buffer *rx_iobuf[NUM_RX_DESC]; + + struct TxDesc *tx_base; + struct RxDesc *rx_base; + + uint32_t tx_curr; + uint32_t rx_curr; + + uint32_t tx_tail; + + uint32_t tx_fill_ctr; + + u16 cp_cmd; + + int phy_auto_nego_reg; + int phy_1000_ctrl_reg; + + int ( *set_speed ) (struct net_device *, u8 autoneg, u16 speed, u8 duplex ); + void ( *phy_reset_enable ) ( void *ioaddr ); + void ( *hw_start ) ( struct net_device * ); + unsigned int ( *phy_reset_pending ) ( void *ioaddr ); + unsigned int ( *link_ok ) ( void *ioaddr ); + + int pcie_cap; + + unsigned features; + +}; + +static const unsigned int rtl8169_rx_config = + (RX_FIFO_THRESH << RxCfgFIFOShift) | (RX_DMA_BURST << RxCfgDMAShift); + +#endif /* _R8169_H_ */ + +/* + * Local variables: + * c-basic-offset: 8 + * c-indent-level: 8 + * tab-width: 8 + * End: + */ diff --git a/gpxe/src/drivers/net/rtl8139.c b/gpxe/src/drivers/net/rtl8139.c index 509047a9..2dff324c 100644 --- a/gpxe/src/drivers/net/rtl8139.c +++ b/gpxe/src/drivers/net/rtl8139.c @@ -69,7 +69,8 @@ #include <stdint.h> #include <stdlib.h> #include <stdio.h> -#include <io.h> +#include <string.h> +#include <gpxe/io.h> #include <errno.h> #include <unistd.h> #include <byteswap.h> diff --git a/gpxe/src/drivers/net/sis900.c b/gpxe/src/drivers/net/sis900.c index 58526506..008b9cf7 100644 --- a/gpxe/src/drivers/net/sis900.c +++ b/gpxe/src/drivers/net/sis900.c @@ -695,7 +695,7 @@ sis900_init_rxfilter(struct nic *nic) outl(w, ioaddr + rfdr); if (sis900_debug > 0) - printf("sis900_init_rxfilter: Receive Filter Addrss[%d]=%lX\n", + printf("sis900_init_rxfilter: Receive Filter Addrss[%d]=%X\n", i, inl(ioaddr + rfdr)); } @@ -724,7 +724,7 @@ sis900_init_txd(struct nic *nic __unused) /* load Transmit Descriptor Register */ outl(virt_to_bus(&txd), ioaddr + txdp); if (sis900_debug > 0) - printf("sis900_init_txd: TX descriptor register loaded with: %lX\n", + printf("sis900_init_txd: TX descriptor register loaded with: %X\n", inl(ioaddr + txdp)); } @@ -760,7 +760,7 @@ sis900_init_rxd(struct nic *nic __unused) outl(virt_to_bus(&rxd[0]), ioaddr + rxdp); if (sis900_debug > 0) - printf("sis900_init_rxd: RX descriptor register loaded with: %lX\n", + printf("sis900_init_rxd: RX descriptor register loaded with: %X\n", inl(ioaddr + rxdp)); } @@ -1114,7 +1114,7 @@ sis900_transmit(struct nic *nic, /* load Transmit Descriptor Register */ outl(virt_to_bus(&txd), ioaddr + txdp); if (sis900_debug > 1) - printf("sis900_transmit: TX descriptor register loaded with: %lX\n", + printf("sis900_transmit: TX descriptor register loaded with: %X\n", inl(ioaddr + txdp)); memcpy(txb, d, ETH_ALEN); diff --git a/gpxe/src/drivers/net/sundance.c b/gpxe/src/drivers/net/sundance.c index 3b6f5a88..eb750fb1 100644 --- a/gpxe/src/drivers/net/sundance.c +++ b/gpxe/src/drivers/net/sundance.c @@ -689,9 +689,9 @@ static int sundance_probe ( struct nic *nic, struct pci_device *pci ) { } /* Reset the chip to erase previous misconfiguration */ - DBG ( "ASIC Control is %#lx\n", inl(BASE + ASICCtrl) ); + DBG ( "ASIC Control is %#x\n", inl(BASE + ASICCtrl) ); outw(0x007f, BASE + ASICCtrl + 2); - DBG ( "ASIC Control is now %#lx.\n", inl(BASE + ASICCtrl) ); + DBG ( "ASIC Control is now %#x.\n", inl(BASE + ASICCtrl) ); sundance_reset(nic); if (sdc->an_enable) { @@ -869,6 +869,7 @@ static void set_rx_mode(struct nic *nic __unused) static struct pci_device_id sundance_nics[] = { PCI_ROM(0x13f0, 0x0201, "sundance", "ST201 Sundance 'Alta' based Adaptor"), PCI_ROM(0x1186, 0x1002, "dfe530txs", "D-Link DFE530TXS (Sundance ST201 Alta)"), + PCI_ROM(0x13f0, 0x0200, "ip100a", "IC+ IP100A"), }; PCI_DRIVER ( sundance_driver, sundance_nics, PCI_NO_CLASS ); diff --git a/gpxe/src/drivers/net/tg3.c b/gpxe/src/drivers/net/tg3.c index bda832e8..14093bb2 100644 --- a/gpxe/src/drivers/net/tg3.c +++ b/gpxe/src/drivers/net/tg3.c @@ -1460,7 +1460,7 @@ static int tg3_stop_block(struct tg3 *tp, unsigned long ofs, uint32_t enable_bit } if (i == MAX_WAIT_CNT) { - printf( "tg3_stop_block timed out, ofs=%#lx enable_bit=%3lx\n", + printf( "tg3_stop_block timed out, ofs=%#lx enable_bit=%3x\n", ofs, enable_bit ); return -ENODEV; } @@ -1665,7 +1665,7 @@ static int tg3_restart_fw(struct tg3 *tp, uint32_t state) if (i >= 100000 && !(tp->tg3_flags2 & TG3_FLG2_SUN_5704) && !(GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5787)) { - printf ( "Firmware will not restart magic=%#lx\n", + printf ( "Firmware will not restart magic=%#x\n", val ); return -ENODEV; } @@ -3399,6 +3399,7 @@ PCI_ROM(0x14e4, 0x1677, "tg3-5751", "Broadcom Tigon 3 5751"), PCI_ROM(0x14e4, 0x167a, "tg3-5754", "Broadcom Tigon 3 5754"), PCI_ROM(0x14e4, 0x1693, "tg3-5787", "Broadcom Tigon 3 5787"), PCI_ROM(0x14e4, 0x1696, "tg3-5782", "Broadcom Tigon 3 5782"), +PCI_ROM(0x14e4, 0x169a, "tg3-5786", "Broadcom Tigon 3 5786"), PCI_ROM(0x14e4, 0x169c, "tg3-5788", "Broadcom Tigon 3 5788"), PCI_ROM(0x14e4, 0x169d, "tg3-5789", "Broadcom Tigon 3 5789"), PCI_ROM(0x14e4, 0x16a6, "tg3-5702X", "Broadcom Tigon 3 5702X"), diff --git a/gpxe/src/drivers/net/tulip.c b/gpxe/src/drivers/net/tulip.c index 53cfb85f..afd7d45b 100644 --- a/gpxe/src/drivers/net/tulip.c +++ b/gpxe/src/drivers/net/tulip.c @@ -1201,7 +1201,7 @@ static void tulip_disable ( struct nic *nic ) { outl(inl(ioaddr + CSR6) & ~0x00002002, ioaddr + CSR6); /* Clear the missed-packet counter. */ - (volatile unsigned long)inl(ioaddr + CSR8); + inl(ioaddr + CSR8); } /*********************************************************************/ @@ -1265,7 +1265,7 @@ static int tulip_probe ( struct nic *nic, struct pci_device *pci ) { outl(inl(ioaddr + CSR6) & ~0x00002002, ioaddr + CSR6); /* Clear the missed-packet counter. */ - (volatile unsigned long)inl(ioaddr + CSR8); + inl(ioaddr + CSR8); printf("\n"); /* so we start on a fresh line */ #ifdef TULIP_DEBUG_WHERE diff --git a/gpxe/src/drivers/net/via-rhine.c b/gpxe/src/drivers/net/via-rhine.c index fb43a924..d9880c32 100644 --- a/gpxe/src/drivers/net/via-rhine.c +++ b/gpxe/src/drivers/net/via-rhine.c @@ -784,7 +784,7 @@ ReadMII (int byMIIIndex, int ioaddr) char byMIIAdrbak; char byMIICRbak; char byMIItemp; - tick_t ct; + unsigned long ct; byMIIAdrbak = inb (byMIIAD); byMIICRbak = inb (byMIICR); @@ -800,7 +800,7 @@ ReadMII (int byMIIIndex, int ioaddr) byMIItemp = byMIItemp & 0x40; ct = currticks(); - while (byMIItemp != 0 && ct + 2*USECS_IN_MSEC < currticks()) + while (byMIItemp != 0 && ct + 2*1000 < currticks()) { byMIItemp = inb (byMIICR); byMIItemp = byMIItemp & 0x40; @@ -825,7 +825,7 @@ WriteMII (char byMIISetByte, char byMIISetBit, char byMIIOP, int ioaddr) char byMIIAdrbak; char byMIICRbak; char byMIItemp; - tick_t ct; + unsigned long ct; byMIIAdrbak = inb (byMIIAD); @@ -842,7 +842,7 @@ WriteMII (char byMIISetByte, char byMIISetBit, char byMIIOP, int ioaddr) byMIItemp = byMIItemp & 0x40; ct = currticks(); - while (byMIItemp != 0 && ct + 2*USECS_IN_MSEC < currticks()) + while (byMIItemp != 0 && ct + 2*1000 < currticks()) { byMIItemp = inb (byMIICR); byMIItemp = byMIItemp & 0x40; @@ -872,7 +872,7 @@ WriteMII (char byMIISetByte, char byMIISetBit, char byMIIOP, int ioaddr) byMIItemp = byMIItemp & 0x20; ct = currticks(); - while (byMIItemp != 0 && ct + 2*USECS_IN_MSEC < currticks()) + while (byMIItemp != 0 && ct + 2*1000 < currticks()) { byMIItemp = inb (byMIICR); byMIItemp = byMIItemp & 0x20; @@ -1008,7 +1008,7 @@ rhine_probe1 (struct nic *nic, struct pci_device *pci, int ioaddr, int chip_id, unsigned char mode3_reg; if (rhine_debug > 0 && did_version++ == 0) - printf (version); + printf ("%s",version); // get revision id. pci_read_config_byte(pci, PCI_REVISION, &revision_id); @@ -1194,40 +1194,44 @@ rhine_reset (struct nic *nic) int ioaddr = tp->ioaddr; int i, j; int FDXFlag, CRbak; - int rx_ring_tmp, rx_ring_tmp1; - int tx_ring_tmp, tx_ring_tmp1; - int rx_bufs_tmp, rx_bufs_tmp1; - int tx_bufs_tmp, tx_bufs_tmp1; + 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 = (int) rhine_buffers.txbuf; - tx_ring_tmp = (int) rhine_buffers.txdesc; - rx_bufs_tmp = (int) rhine_buffers.rxbuf; - rx_ring_tmp = (int) rhine_buffers.rxdesc; + 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 = (int) virt_to_bus ((char *) rx_ring_tmp); + 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 = (int) virt_to_bus ((char *) tx_ring_tmp); + 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 = (int) virt_to_bus ((char *) tx_bufs_tmp); + tx_bufs_tmp1 = virt_to_bus ( tx_bufs_tmp ); j = (int) (tx_bufs_tmp1 + 32) & (~0x1f); - tx_bufs_tmp = (int) bus_to_virt (j); + tx_bufs_tmp = bus_to_virt (j); /* printf ("txb[%X]", j); */ - rx_bufs_tmp1 = (int) virt_to_bus ((char *) rx_bufs_tmp); + rx_bufs_tmp1 = virt_to_bus ( rx_bufs_tmp ); j = (int) (rx_bufs_tmp1 + 32) & (~0x1f); - rx_bufs_tmp = (int) bus_to_virt (j); + rx_bufs_tmp = bus_to_virt (j); /* printf ("rxb[%X][%X]", rx_bufs_tmp1, j); */ for (i = 0; i < RX_RING_SIZE; i++) @@ -1346,7 +1350,7 @@ rhine_transmit (struct nic *nic, unsigned char CR1bak; unsigned char CR0bak; unsigned int nstype; - tick_t ct; + unsigned long ct; /*printf ("rhine_transmit\n"); */ @@ -1390,7 +1394,7 @@ rhine_transmit (struct nic *nic, ct = currticks(); /* Wait until transmit is finished or timeout*/ while((tp->tx_ring[entry].tx_status.bits.own_bit !=0) && - ct + 10*USECS_IN_MSEC < currticks()) + ct + 10*1000 < currticks()) ; if(tp->tx_ring[entry].tx_status.bits.terr == 0) diff --git a/gpxe/src/drivers/net/via-velocity.c b/gpxe/src/drivers/net/via-velocity.c index 428f609c..4473ed15 100644 --- a/gpxe/src/drivers/net/via-velocity.c +++ b/gpxe/src/drivers/net/via-velocity.c @@ -550,7 +550,7 @@ static void velocity_transmit(struct nic *nic, const char *dest, /* Destination 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(0xffff0000L); + 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; @@ -1234,7 +1234,7 @@ static int velocity_open(struct nic *nic, struct pci_device *pci __unused) /* Tx Descriptor needs 64 bytes alignment; */ TxPhyAddr = virt_to_bus(vptr->TxDescArrays); - printf("Unaligned Address : %lX\n", TxPhyAddr); + printf("Unaligned Address : %X\n", TxPhyAddr); diff = 64 - (TxPhyAddr - ((TxPhyAddr >> 6) << 6)); TxPhyAddr += diff; vptr->td_rings = (struct tx_desc *) (vptr->TxDescArrays + diff); diff --git a/gpxe/src/drivers/net/virtio-net.c b/gpxe/src/drivers/net/virtio-net.c index 4ec154df..f0afd3f6 100644 --- a/gpxe/src/drivers/net/virtio-net.c +++ b/gpxe/src/drivers/net/virtio-net.c @@ -21,8 +21,8 @@ #include "etherboot.h" #include "nic.h" -#include "virtio-ring.h" -#include "virtio-pci.h" +#include "gpxe/virtio-ring.h" +#include "gpxe/virtio-pci.h" #include "virtio-net.h" #define BUG() do { \ @@ -45,8 +45,6 @@ struct eth_frame { unsigned char data[ETH_FRAME_LEN]; }; -typedef unsigned char virtio_queue_t[PAGE_MASK + vring_size(MAX_QUEUE_NUM)]; - /* TX: virtio header and eth buffer */ static struct virtio_net_hdr tx_virtio_hdr; @@ -66,209 +64,7 @@ enum { QUEUE_NB }; -static virtio_queue_t queue[QUEUE_NB]; -static struct vring vring[QUEUE_NB]; -static u16 free_head[QUEUE_NB]; -static u16 last_used_idx[QUEUE_NB]; -static u16 vdata[QUEUE_NB][MAX_QUEUE_NUM]; - -/* - * Virtio PCI interface - * - */ - -static int vp_find_vq(struct nic *nic, int queue_index) -{ - struct vring * vr = &vring[queue_index]; - u16 num; - - /* select the queue */ - - outw(queue_index, nic->ioaddr + VIRTIO_PCI_QUEUE_SEL); - - /* check if the queue is available */ - - num = inw(nic->ioaddr + VIRTIO_PCI_QUEUE_NUM); - if (!num) { - printf("ERROR: queue size is 0\n"); - return -1; - } - - if (num > MAX_QUEUE_NUM) { - printf("ERROR: queue size %d > %d\n", num, MAX_QUEUE_NUM); - return -1; - } - - /* check if the queue is already active */ - - if (inl(nic->ioaddr + VIRTIO_PCI_QUEUE_PFN)) { - printf("ERROR: queue already active\n"); - return -1; - } - - /* initialize the queue */ - - vring_init(vr, num, (unsigned char*)&queue[queue_index]); - - /* activate the queue - * - * NOTE: vr->desc is initialized by vring_init() - */ - - outl((unsigned long)virt_to_phys(vr->desc) >> PAGE_SHIFT, - nic->ioaddr + VIRTIO_PCI_QUEUE_PFN); - - return num; -} - -/* - * Virtual ring management - * - */ - -static void vring_enable_cb(int queue_index) -{ - vring[queue_index].avail->flags &= ~VRING_AVAIL_F_NO_INTERRUPT; -} - -static void vring_disable_cb(int queue_index) -{ - vring[queue_index].avail->flags |= VRING_AVAIL_F_NO_INTERRUPT; -} - -/* - * vring_free - * - * put at the begin of the free list the current desc[head] - */ - -static void vring_detach(int queue_index, unsigned int head) -{ - struct vring *vr = &vring[queue_index]; - unsigned int i; - - /* find end of given descriptor */ - - i = head; - while (vr->desc[i].flags & VRING_DESC_F_NEXT) - i = vr->desc[i].next; - - /* link it with free list and point to it */ - - vr->desc[i].next = free_head[queue_index]; - wmb(); - free_head[queue_index] = head; -} - -/* - * vring_more_used - * - * is there some used buffers ? - * - */ - -static inline int vring_more_used(int queue_index) -{ - wmb(); - return last_used_idx[queue_index] != vring[queue_index].used->idx; -} - -/* - * vring_get_buf - * - * get a buffer from the used list - * - */ - -static int vring_get_buf(int queue_index, unsigned int *len) -{ - struct vring *vr = &vring[queue_index]; - struct vring_used_elem *elem; - u32 id; - int ret; - - elem = &vr->used->ring[last_used_idx[queue_index] % vr->num]; - wmb(); - id = elem->id; - if (len != NULL) - *len = elem->len; - - ret = vdata[queue_index][id]; - - vring_detach(queue_index, id); - - last_used_idx[queue_index]++; - - return ret; -} - -static void vring_add_buf(int queue_index, int index, int num_added) -{ - struct vring *vr = &vring[queue_index]; - int i, avail, head; - - BUG_ON(queue_index >= QUEUE_NB); - - head = free_head[queue_index]; - i = head; - - if (queue_index == TX_INDEX) { - - BUG_ON(index != 0); - - /* add header into vring */ - - vr->desc[i].flags = VRING_DESC_F_NEXT; - vr->desc[i].addr = (u64)virt_to_phys(&tx_virtio_hdr); - vr->desc[i].len = sizeof(struct virtio_net_hdr); - i = vr->desc[i].next; - - /* add frame buffer into vring */ - - vr->desc[i].flags = 0; - vr->desc[i].addr = (u64)virt_to_phys(&tx_eth_frame); - vr->desc[i].len = ETH_FRAME_LEN; - i = vr->desc[i].next; - - } else if (queue_index == RX_INDEX) { - - BUG_ON(index >= RX_BUF_NB); - - /* add header into vring */ - - vr->desc[i].flags = VRING_DESC_F_NEXT|VRING_DESC_F_WRITE; - vr->desc[i].addr = (u64)virt_to_phys(&rx_hdr[index]); - vr->desc[i].len = sizeof(struct virtio_net_hdr); - i = vr->desc[i].next; - - /* add frame buffer into vring */ - - vr->desc[i].flags = VRING_DESC_F_WRITE; - vr->desc[i].addr = (u64)virt_to_phys(&rx_buffer[index]); - vr->desc[i].len = ETH_FRAME_LEN; - i = vr->desc[i].next; - } - - free_head[queue_index] = i; - - vdata[queue_index][head] = index; - - avail = (vr->avail->idx + num_added) % vr->num; - vr->avail->ring[avail] = head; - wmb(); -} - -static void vring_kick(struct nic *nic, int queue_index, int num_added) -{ - struct vring *vr = &vring[queue_index]; - - wmb(); - vr->avail->idx += num_added; - - mb(); - if (!(vr->used->flags & VRING_USED_F_NO_NOTIFY)) - vp_notify(nic, queue_index); -} +static struct vring_virtqueue virtqueue[QUEUE_NB]; /* * virtnet_disable @@ -282,10 +78,10 @@ static void virtnet_disable(struct nic *nic) int i; for (i = 0; i < QUEUE_NB; i++) { - vring_disable_cb(i); - vp_del_vq(nic, i); + vring_disable_cb(&virtqueue[i]); + vp_del_vq(nic->ioaddr, i); } - vp_reset(nic); + vp_reset(nic->ioaddr); } /* @@ -304,27 +100,33 @@ static int virtnet_poll(struct nic *nic, int retrieve) unsigned int len; u16 token; struct virtio_net_hdr *hdr; + struct vring_list list[2]; - if (!vring_more_used(RX_INDEX)) + if (!vring_more_used(&virtqueue[RX_INDEX])) return 0; if (!retrieve) return 1; - token = vring_get_buf(RX_INDEX, &len); + token = vring_get_buf(&virtqueue[RX_INDEX], &len); BUG_ON(len > sizeof(struct virtio_net_hdr) + ETH_FRAME_LEN); hdr = &rx_hdr[token]; /* FIXME: check flags */ len -= sizeof(struct virtio_net_hdr); - nic->packetlen = len; + nic->packetlen = len; memcpy(nic->packet, (char *)rx_buffer[token], nic->packetlen); /* add buffer to desc */ - vring_add_buf(RX_INDEX, token, 0); - vring_kick(nic, RX_INDEX, 1); + list[0].addr = (char*)&rx_hdr[token]; + list[0].length = sizeof(struct virtio_net_hdr); + list[1].addr = (char*)&rx_buffer[token]; + list[1].length = ETH_FRAME_LEN; + + vring_add_buf(&virtqueue[RX_INDEX], list, 0, 2, token, 0); + vring_kick(nic->ioaddr, &virtqueue[RX_INDEX], 1); return 1; } @@ -340,6 +142,8 @@ static int virtnet_poll(struct nic *nic, int retrieve) static void virtnet_transmit(struct nic *nic, const char *destaddr, unsigned int type, unsigned int len, const char *data) { + struct vring_list list[2]; + /* * from http://www.etherboot.org/wiki/dev/devmanual : * "You do not need more than one transmit buffer." @@ -363,7 +167,14 @@ static void virtnet_transmit(struct nic *nic, const char *destaddr, tx_eth_frame.hdr.type = htons(type); memcpy(tx_eth_frame.data, data, len); - vring_add_buf(TX_INDEX, 0, 0); + list[0].addr = (char*)&tx_virtio_hdr; + list[0].length = sizeof(struct virtio_net_hdr); + list[1].addr = (char*)&tx_eth_frame; + list[1].length = ETH_FRAME_LEN; + + vring_add_buf(&virtqueue[TX_INDEX], list, 2, 0, 0, 0); + + vring_kick(nic->ioaddr, &virtqueue[TX_INDEX], 1); /* * http://www.etherboot.org/wiki/dev/devmanual @@ -372,28 +183,26 @@ static void virtnet_transmit(struct nic *nic, const char *destaddr, * before returning from this routine" */ - while (vring_more_used(TX_INDEX)) { + while (!vring_more_used(&virtqueue[TX_INDEX])) { mb(); udelay(10); } - vring_kick(nic, TX_INDEX, 1); - /* free desc */ - (void)vring_get_buf(TX_INDEX, NULL); + (void)vring_get_buf(&virtqueue[TX_INDEX], NULL); } static void virtnet_irq(struct nic *nic __unused, irq_action_t action) { switch ( action ) { case DISABLE : - vring_disable_cb(RX_INDEX); - vring_disable_cb(TX_INDEX); + vring_disable_cb(&virtqueue[RX_INDEX]); + vring_disable_cb(&virtqueue[TX_INDEX]); break; case ENABLE : - vring_enable_cb(RX_INDEX); - vring_enable_cb(TX_INDEX); + vring_enable_cb(&virtqueue[RX_INDEX]); + vring_enable_cb(&virtqueue[TX_INDEX]); break; case FORCE : break; @@ -403,13 +212,19 @@ static void virtnet_irq(struct nic *nic __unused, irq_action_t action) static void provide_buffers(struct nic *nic) { int i; - - for (i = 0; i < RX_BUF_NB; i++) - vring_add_buf(RX_INDEX, i, i); + struct vring_list list[2]; + + for (i = 0; i < RX_BUF_NB; i++) { + list[0].addr = (char*)&rx_hdr[i]; + list[0].length = sizeof(struct virtio_net_hdr); + list[1].addr = (char*)&rx_buffer[i]; + list[1].length = ETH_FRAME_LEN; + vring_add_buf(&virtqueue[RX_INDEX], list, 0, 2, i, i); + } /* nofify */ - vring_kick(nic, RX_INDEX, i); + vring_kick(nic->ioaddr, &virtqueue[RX_INDEX], i); } static struct nic_operations virtnet_operations = { @@ -443,11 +258,11 @@ static int virtnet_probe(struct nic *nic, struct pci_device *pci) adjust_pci_device(pci); - vp_reset(nic); + vp_reset(nic->ioaddr); - features = vp_get_features(nic); + features = vp_get_features(nic->ioaddr); if (features & (1 << VIRTIO_NET_F_MAC)) { - vp_get(nic, offsetof(struct virtio_net_config, mac), + vp_get(nic->ioaddr, offsetof(struct virtio_net_config, mac), nic->node_addr, ETH_ALEN); printf("MAC address "); for (i = 0; i < ETH_ALEN; i++) { @@ -459,10 +274,10 @@ static int virtnet_probe(struct nic *nic, struct pci_device *pci) /* initialize emit/receive queue */ for (i = 0; i < QUEUE_NB; i++) { - free_head[i] = 0; - last_used_idx[i] = 0; - memset((char*)&queue[i], 0, sizeof(queue[i])); - if (vp_find_vq(nic, i) == -1) + virtqueue[i].free_head = 0; + virtqueue[i].last_used_idx = 0; + memset((char*)&virtqueue[i].queue, 0, sizeof(virtqueue[i].queue)); + if (vp_find_vq(nic->ioaddr, i, &virtqueue[i]) == -1) printf("Cannot register queue #%d\n", i); } @@ -476,8 +291,8 @@ static int virtnet_probe(struct nic *nic, struct pci_device *pci) /* driver is ready */ - vp_set_features(nic, features & (1 << VIRTIO_NET_F_MAC)); - vp_set_status(nic, VIRTIO_CONFIG_S_DRIVER | VIRTIO_CONFIG_S_DRIVER_OK); + vp_set_features(nic->ioaddr, features & (1 << VIRTIO_NET_F_MAC)); + vp_set_status(nic->ioaddr, VIRTIO_CONFIG_S_DRIVER | VIRTIO_CONFIG_S_DRIVER_OK); return 1; } diff --git a/gpxe/src/drivers/net/w89c840.c b/gpxe/src/drivers/net/w89c840.c index 14497640..5abc0b35 100644 --- a/gpxe/src/drivers/net/w89c840.c +++ b/gpxe/src/drivers/net/w89c840.c @@ -112,7 +112,7 @@ static const char *w89c840_version = "driver Version 0.94 - December 12, 2003"; /* Operational parameters that usually are not changed. */ /* Time in jiffies before concluding the transmitter is hung. */ -#define TX_TIMEOUT (10*USECS_IN_MSEC) +#define TX_TIMEOUT (10*1000) #define PKT_BUF_SZ 1536 /* Size of each temporary Rx buffer.*/ @@ -486,7 +486,7 @@ static void w89c840_transmit( /* send the packet to destination */ unsigned entry; int transmit_status; - tick_t ct; + unsigned long ct; /* Caution: the write order is important here, set the field with the "ownership" bits last. */ diff --git a/gpxe/src/hci/commands/config_cmd.c b/gpxe/src/hci/commands/config_cmd.c index 660c6423..87abb05a 100644 --- a/gpxe/src/hci/commands/config_cmd.c +++ b/gpxe/src/hci/commands/config_cmd.c @@ -16,7 +16,7 @@ static int config_exec ( int argc, char **argv ) { } settings_name = ( ( argc == 2 ) ? argv[1] : "" ); - settings = find_settings ( argv[1] ); + settings = find_settings ( settings_name ); if ( ! settings ) { printf ( "No such scope \"%s\"\n", settings_name ); return 1; diff --git a/gpxe/src/hci/commands/dhcp_cmd.c b/gpxe/src/hci/commands/dhcp_cmd.c index 07acc615..9b577c86 100644 --- a/gpxe/src/hci/commands/dhcp_cmd.c +++ b/gpxe/src/hci/commands/dhcp_cmd.c @@ -26,6 +26,7 @@ #include <assert.h> #include <getopt.h> #include <gpxe/netdevice.h> +#include <gpxe/in.h> #include <gpxe/command.h> #include <usr/dhcpmgmt.h> @@ -60,7 +61,7 @@ static int dhcp_exec ( int argc, char **argv ) { { "help", 0, NULL, 'h' }, { NULL, 0, NULL, 0 }, }; - const char *name; + const char *netdev_txt; struct net_device *netdev; int c; int rc; @@ -82,14 +83,16 @@ static int dhcp_exec ( int argc, char **argv ) { dhcp_syntax ( argv ); return 1; } - name = argv[optind]; + netdev_txt = argv[optind]; - /* Perform DHCP */ - netdev = find_netdev ( name ); + /* Parse arguments */ + netdev = find_netdev ( netdev_txt ); if ( ! netdev ) { - printf ( "No such interface: %s\n", name ); + printf ( "No such interface: %s\n", netdev_txt ); return 1; } + + /* Perform DHCP */ if ( ( rc = dhcp ( netdev ) ) != 0 ) { printf ( "Could not configure %s: %s\n", netdev->name, strerror ( rc ) ); @@ -99,10 +102,87 @@ static int dhcp_exec ( int argc, char **argv ) { return 0; } +/** + * "pxebs" command syntax message + * + * @v argv Argument list + */ +static void pxebs_syntax ( char **argv ) { + printf ( "Usage:\n" + " %s <interface> <server_type>\n" + "\n" + "Perform PXE Boot Server discovery\n", + argv[0] ); +} + +/** + * The "pxebs" command + * + * @v argc Argument count + * @v argv Argument list + * @ret rc Exit code + */ +static int pxebs_exec ( int argc, char **argv ) { + static struct option longopts[] = { + { "help", 0, NULL, 'h' }, + { NULL, 0, NULL, 0 }, + }; + const char *netdev_txt; + const char *pxe_type_txt; + struct net_device *netdev; + unsigned int pxe_type; + char *end; + int c; + int rc; + + /* Parse options */ + while ( ( c = getopt_long ( argc, argv, "h", longopts, NULL ) ) >= 0 ){ + switch ( c ) { + case 'h': + /* Display help text */ + default: + /* Unrecognised/invalid option */ + pxebs_syntax ( argv ); + return 1; + } + } + if ( optind != ( argc - 2 ) ) { + pxebs_syntax ( argv ); + return 1; + } + netdev_txt = argv[optind]; + pxe_type_txt = argv[ optind + 1 ]; + + /* Parse arguments */ + netdev = find_netdev ( netdev_txt ); + if ( ! netdev ) { + printf ( "No such interface: %s\n", netdev_txt ); + return 1; + } + pxe_type = strtoul ( pxe_type_txt, &end, 0 ); + if ( *end ) { + printf ( "Bad server type: %s\n", pxe_type_txt ); + return 1; + } + + /* Perform Boot Server Discovery */ + if ( ( rc = pxebs ( netdev, pxe_type ) ) != 0 ) { + printf ( "Could not discover boot server on %s: %s\n", + netdev->name, strerror ( rc ) ); + return 1; + } + + return 0; +} + /** DHCP management commands */ struct command dhcp_commands[] __command = { { .name = "dhcp", .exec = dhcp_exec, }, + { + .name = "pxebs", + .exec = pxebs_exec, + }, }; diff --git a/gpxe/src/hci/commands/login_cmd.c b/gpxe/src/hci/commands/login_cmd.c new file mode 100644 index 00000000..e425247d --- /dev/null +++ b/gpxe/src/hci/commands/login_cmd.c @@ -0,0 +1,27 @@ +#include <string.h> +#include <stdio.h> +#include <gpxe/command.h> +#include <gpxe/login_ui.h> + +static int login_exec ( int argc, char **argv ) { + int rc; + + if ( argc > 1 ) { + printf ( "Usage: %s\n" + "Prompt for login credentials\n", argv[0] ); + return 1; + } + + if ( ( rc = login_ui() ) != 0 ) { + printf ( "Could not set credentials: %s\n", + strerror ( rc ) ); + return 1; + } + + return 0; +} + +struct command login_command __command = { + .name = "login", + .exec = login_exec, +}; diff --git a/gpxe/src/hci/mucurses/ansi_screen.c b/gpxe/src/hci/mucurses/ansi_screen.c index 0742a7d4..468bac02 100644 --- a/gpxe/src/hci/mucurses/ansi_screen.c +++ b/gpxe/src/hci/mucurses/ansi_screen.c @@ -15,7 +15,7 @@ static void ansiscr_reset ( struct _curses_screen *scr ) { scr->attrs = 0; scr->curs_x = 0; scr->curs_y = 0; - printf ( "\033[0m\033[2J\033[1;1H" ); + printf ( "\033[0m" ); } static void ansiscr_movetoyx ( struct _curses_screen *scr, diff --git a/gpxe/src/hci/mucurses/widgets/editbox.c b/gpxe/src/hci/mucurses/widgets/editbox.c index 5c066fda..a52089ce 100644 --- a/gpxe/src/hci/mucurses/widgets/editbox.c +++ b/gpxe/src/hci/mucurses/widgets/editbox.c @@ -38,11 +38,11 @@ * @v row Row * @v col Starting column * @v width Width - * + * @v flags Flags */ void init_editbox ( struct edit_box *box, char *buf, size_t len, WINDOW *win, unsigned int row, unsigned int col, - unsigned int width ) { + unsigned int width, unsigned int flags ) { memset ( box, 0, sizeof ( *box ) ); box->string.buf = buf; box->string.len = len; @@ -51,6 +51,7 @@ void init_editbox ( struct edit_box *box, char *buf, size_t len, box->row = row; box->col = col; box->width = width; + box->flags = flags; } /** @@ -86,7 +87,11 @@ void draw_editbox ( struct edit_box *box ) { len = ( strlen ( box->string.buf ) - first ); if ( len > width ) len = width; - memcpy ( buf, ( box->string.buf + first ), len ); + if ( box->flags & EDITBOX_STARS ) { + memset ( buf, '*', len ); + } else { + memcpy ( buf, ( box->string.buf + first ), len ); + } /* Print box content and move cursor */ if ( ! box->win ) diff --git a/gpxe/src/hci/mucurses/wininit.c b/gpxe/src/hci/mucurses/wininit.c index dfd0ca0a..cd27f9fe 100644 --- a/gpxe/src/hci/mucurses/wininit.c +++ b/gpxe/src/hci/mucurses/wininit.c @@ -18,7 +18,7 @@ WINDOW *initscr ( void ) { stdscr->scr->init( stdscr->scr ); stdscr->height = LINES; stdscr->width = COLS; - erase(); + move ( 0, 0 ); return stdscr; } @@ -29,7 +29,7 @@ WINDOW *initscr ( void ) { int endwin ( void ) { attrset ( 0 ); color_set ( 0, NULL ); - erase(); + mvprintw ( ( LINES - 1 ), 0, "\n" ); stdscr->scr->exit( stdscr->scr ); return OK; } diff --git a/gpxe/src/hci/tui/login_ui.c b/gpxe/src/hci/tui/login_ui.c new file mode 100644 index 00000000..c14a2c03 --- /dev/null +++ b/gpxe/src/hci/tui/login_ui.c @@ -0,0 +1,135 @@ +/* + * Copyright (C) 2009 Michael Brown <mbrown@fensystems.co.uk>. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of the + * License, or any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +/** @file + * + * Login UI + * + */ + +#include <string.h> +#include <errno.h> +#include <curses.h> +#include <console.h> +#include <gpxe/settings.h> +#include <gpxe/editbox.h> +#include <gpxe/keys.h> +#include <gpxe/login_ui.h> + +/* Colour pairs */ +#define CPAIR_NORMAL 1 +#define CPAIR_LABEL 2 +#define CPAIR_EDITBOX 3 + +/* 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 + +int login_ui ( void ) { + char username[64]; + char password[64]; + struct edit_box username_box; + struct edit_box password_box; + struct edit_box *current_box = &username_box; + int key; + int rc = -EINPROGRESS; + + /* Fetch current setting values */ + fetch_string_setting ( NULL, &username_setting, username, + sizeof ( username ) ); + fetch_string_setting ( NULL, &password_setting, password, + sizeof ( password ) ); + + /* Initialise UI */ + initscr(); + start_color(); + init_pair ( CPAIR_NORMAL, COLOR_WHITE, COLOR_BLACK ); + init_pair ( CPAIR_LABEL, COLOR_WHITE, COLOR_BLACK ); + init_pair ( CPAIR_EDITBOX, COLOR_WHITE, COLOR_BLUE ); + init_editbox ( &username_box, username, sizeof ( username ), NULL, + USERNAME_ROW, EDITBOX_COL, EDITBOX_WIDTH, 0 ); + init_editbox ( &password_box, password, sizeof ( password ), NULL, + PASSWORD_ROW, EDITBOX_COL, EDITBOX_WIDTH, + EDITBOX_STARS ); + + /* Draw initial UI */ + erase(); + color_set ( CPAIR_LABEL, NULL ); + mvprintw ( USERNAME_LABEL_ROW, LABEL_COL, "Username:" ); + mvprintw ( PASSWORD_LABEL_ROW, LABEL_COL, "Password:" ); + color_set ( CPAIR_EDITBOX, NULL ); + draw_editbox ( &username_box ); + draw_editbox ( &password_box ); + + /* Main loop */ + while ( rc == -EINPROGRESS ) { + + draw_editbox ( current_box ); + + key = getkey(); + switch ( key ) { + case KEY_DOWN: + current_box = &password_box; + break; + case KEY_UP: + current_box = &username_box; + break; + case TAB: + current_box = ( ( current_box == &username_box ) ? + &password_box : &username_box ); + break; + case KEY_ENTER: + if ( current_box == &username_box ) { + current_box = &password_box; + } else { + rc = 0; + } + break; + case CTRL_C: + case ESC: + rc = -ECANCELED; + break; + default: + edit_editbox ( current_box, key ); + break; + } + } + + /* Terminate UI */ + color_set ( CPAIR_NORMAL, NULL ); + erase(); + endwin(); + + if ( rc != 0 ) + return rc; + + /* Store settings */ + if ( ( rc = store_setting ( NULL, &username_setting, username, + strlen ( username ) ) ) != 0 ) + return rc; + if ( ( rc = store_setting ( NULL, &password_setting, password, + strlen ( password ) ) ) != 0 ) + return rc; + + return 0; +} diff --git a/gpxe/src/hci/tui/settings_ui.c b/gpxe/src/hci/tui/settings_ui.c index 0907bfd3..4ab38270 100644 --- a/gpxe/src/hci/tui/settings_ui.c +++ b/gpxe/src/hci/tui/settings_ui.c @@ -123,7 +123,7 @@ static void load_setting ( struct setting_widget *widget ) { init_editbox ( &widget->editbox, widget->value, sizeof ( widget->value ), NULL, widget->row, ( widget->col + offsetof ( struct setting_row, value )), - sizeof ( ( ( struct setting_row * ) NULL )->value ) ); + sizeof ( ( ( struct setting_row * ) NULL )->value ), 0); } /** diff --git a/gpxe/src/image/default.gpxe b/gpxe/src/image/default.gpxe new file mode 100644 index 00000000..0b080b58 --- /dev/null +++ b/gpxe/src/image/default.gpxe @@ -0,0 +1,2 @@ +#!gpxe +autoboot diff --git a/gpxe/src/image/efi_image.c b/gpxe/src/image/efi_image.c new file mode 100644 index 00000000..ae95debc --- /dev/null +++ b/gpxe/src/image/efi_image.c @@ -0,0 +1,106 @@ +/* + * 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., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +#include <errno.h> +#include <gpxe/efi/efi.h> +#include <gpxe/image.h> +#include <gpxe/features.h> + +FEATURE ( FEATURE_IMAGE, "EFI", DHCP_EB_FEATURE_EFI, 1 ); + +struct image_type efi_image_type __image_type ( PROBE_NORMAL ); + +/** + * Execute EFI image + * + * @v image EFI image + * @ret rc Return status code + */ +static int efi_image_exec ( struct image *image ) { + EFI_BOOT_SERVICES *bs = efi_systab->BootServices; + EFI_HANDLE handle; + UINTN exit_data_size; + CHAR16 *exit_data; + EFI_STATUS efirc; + + /* 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 */ + DBGC ( image, "EFIIMAGE %p could not load: %s\n", + image, efi_strerror ( efirc ) ); + return -ENOEXEC; + } + + /* Start the image */ + if ( ( efirc = bs->StartImage ( handle, &exit_data_size, + &exit_data ) ) != 0 ) { + DBGC ( image, "EFIIMAGE %p returned with status %s\n", + image, efi_strerror ( efirc ) ); + goto done; + } + + done: + /* Unload the image. We can't leave it loaded, because we + * have no "unload" operation. + */ + bs->UnloadImage ( handle ); + + return EFIRC_TO_RC ( efirc ); +} + +/** + * Load EFI image into memory + * + * @v image EFI file + * @ret rc Return status code + */ +static int efi_image_load ( struct image *image ) { + EFI_BOOT_SERVICES *bs = efi_systab->BootServices; + EFI_HANDLE handle; + EFI_STATUS efirc; + + /* 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 */ + DBGC ( image, "EFIIMAGE %p could not load: %s\n", + image, efi_strerror ( efirc ) ); + return -ENOEXEC; + } + + /* This is an EFI image */ + if ( ! image->type ) + image->type = &efi_image_type; + + /* Unload the image. We can't leave it loaded, because we + * have no "unload" operation. + */ + bs->UnloadImage ( handle ); + + return 0; +} + +/** EFI image type */ +struct image_type efi_image_type __image_type ( PROBE_NORMAL ) = { + .name = "EFI", + .load = efi_image_load, + .exec = efi_image_exec, +}; diff --git a/gpxe/src/image/elf.c b/gpxe/src/image/elf.c index b932ff58..cb2b0f5b 100644 --- a/gpxe/src/image/elf.c +++ b/gpxe/src/image/elf.c @@ -72,7 +72,7 @@ static int elf_load_segment ( struct image *image, Elf_Phdr *phdr ) { } buffer = phys_to_user ( dest ); - DBG ( "ELF loading segment [%lx,%lx) to [%lx,%lx,%lx)\n", + DBG ( "ELF loading segment [%x,%x) to [%x,%x,%x)\n", phdr->p_offset, ( phdr->p_offset + phdr->p_filesz ), phdr->p_paddr, ( phdr->p_paddr + phdr->p_filesz ), ( phdr->p_paddr + phdr->p_memsz ) ); diff --git a/gpxe/src/image/embed.S b/gpxe/src/image/embed.S deleted file mode 100644 index 4541bfdc..00000000 --- a/gpxe/src/image/embed.S +++ /dev/null @@ -1,7 +0,0 @@ - .section ".data", "aw" - .balign 4 - .globl _embedded_image_start -_embedded_image_start: - .incbin EMBEDIMG - .globl _embedded_image_end -_embedded_image_end: diff --git a/gpxe/src/image/embedded.c b/gpxe/src/image/embedded.c index 0ce09783..f76ca11b 100644 --- a/gpxe/src/image/embedded.c +++ b/gpxe/src/image/embedded.c @@ -1,49 +1,94 @@ /** @file * - * Take a possible embedded image and put it in a struct image - * data structure. + * Embedded image support + * + * Embedded images are images built into the gPXE binary and do not require + * fetching over the network. */ +#include <string.h> #include <gpxe/image.h> -#include <gpxe/malloc.h> #include <gpxe/uaccess.h> -#include <gpxe/umalloc.h> -#include <gpxe/embedded.h> +#include <gpxe/init.h> -extern char _embedded_image_start[], _embedded_image_end[]; +/** + * Free embedded image + * + * @v refcnt Reference counter + */ +static void embedded_image_free ( struct refcnt *refcnt __unused ) { + /* Do nothing */ +} -struct image *embedded_image(void) -{ - static int reclaimed = 0; - struct image *image; - size_t eisize = _embedded_image_end - _embedded_image_start; +/* Raw image data for all embedded images */ +#undef EMBED +#define EMBED( _index, _path, _name ) \ + extern char embedded_image_ ## _index ## _data[]; \ + extern char embedded_image_ ## _index ## _len[]; \ + __asm__ ( ".section \".rodata\", \"a\", @progbits\n\t" \ + "\nembedded_image_" #_index "_data:\n\t" \ + ".incbin \"" _path "\"\n\t" \ + "\nembedded_image_" #_index "_end:\n\t" \ + ".equ embedded_image_" #_index "_len, " \ + "( embedded_image_" #_index "_end - " \ + " embedded_image_" #_index "_data )\n\t" \ + ".previous\n\t" ); +EMBED_ALL - if ( !eisize ) - return NULL; /* No embedded image */ +/* Image structures for all embedded images */ +#undef EMBED +#define EMBED( _index, _path, _name ) { \ + .refcnt = { .free = embedded_image_free, }, \ + .name = _name, \ + .data = ( userptr_t ) ( embedded_image_ ## _index ## _data ), \ + .len = ( size_t ) embedded_image_ ## _index ## _len, \ +}, +static struct image embedded_images[] = { + EMBED_ALL +}; - if ( reclaimed ) - return NULL; /* Already reclaimed */ +/** + * Register all embedded images + */ +static void embedded_init ( void ) { + unsigned int i; + struct image *image; + void *data; + int rc; - DBG ( "Embedded image: %zd bytes at %p\n", - eisize, _embedded_image_start ); + /* Fix up data pointers and register images */ + for ( i = 0 ; i < ( sizeof ( embedded_images ) / + sizeof ( embedded_images[0] ) ) ; i++ ) { + image = &embedded_images[i]; - image = alloc_image(); - if (!image) - return NULL; + /* virt_to_user() cannot be used in a static + * initialiser, so we cast the pointer to a userptr_t + * in the initialiser and fix it up here. (This will + * actually be a no-op on most platforms.) + */ + data = ( ( void * ) image->data ); + image->data = virt_to_user ( data ); - image->len = eisize; - image->data = umalloc(eisize); - if (image->data == UNULL) { - image_put(image); - return image = NULL; - } - copy_to_user(image->data, 0, _embedded_image_start, eisize); - register_image(image); + DBG ( "Embedded image \"%s\": %zd bytes at %p\n", + image->name, image->len, data ); - /* Reclaim embedded image memory */ - reclaimed = 1; - mpopulate(_embedded_image_start, eisize); + if ( ( rc = register_image ( image ) ) != 0 ) { + DBG ( "Could not register embedded image \"%s\": " + "%s\n", image->name, strerror ( rc ) ); + return; + } + } - return image; + /* Load the first image */ + image = &embedded_images[0]; + if ( ( rc = image_autoload ( image ) ) != 0 ) { + DBG ( "Could not load embedded image \"%s\": %s\n", + image->name, strerror ( rc ) ); + return; + } } +/** Embedded image initialisation function */ +struct init_fn embedded_init_fn __init_fn ( INIT_NORMAL ) = { + .initialise = embedded_init, +}; diff --git a/gpxe/src/image/script.c b/gpxe/src/image/script.c index 749131d6..2d242746 100644 --- a/gpxe/src/image/script.c +++ b/gpxe/src/image/script.c @@ -43,10 +43,8 @@ static int script_exec ( struct image *image ) { int rc; /* Temporarily de-register image, so that a "boot" command - * doesn't throw us into an execution loop. Hold a reference - * to avoid the image's being freed. + * doesn't throw us into an execution loop. */ - image_get ( image ); unregister_image ( image ); while ( offset < image->len ) { @@ -80,7 +78,6 @@ static int script_exec ( struct image *image ) { done: /* Re-register image and return */ register_image ( image ); - image_put ( image ); return rc; } @@ -94,6 +91,12 @@ static int script_load ( struct image *image ) { static const char magic[] = "#!gpxe\n"; char test[ sizeof ( magic ) - 1 ]; + /* Sanity check */ + if ( image->len < sizeof ( test ) ) { + DBG ( "Too short to be a script\n" ); + return -ENOEXEC; + } + /* Check for magic signature */ copy_from_user ( test, image->data, 0, sizeof ( test ) ); if ( memcmp ( test, magic, sizeof ( test ) ) != 0 ) { diff --git a/gpxe/src/include/byteswap.h b/gpxe/src/include/byteswap.h index 72b5a01d..6c3ced25 100644 --- a/gpxe/src/include/byteswap.h +++ b/gpxe/src/include/byteswap.h @@ -4,6 +4,41 @@ #include "endian.h" #include "bits/byteswap.h" +#define __bswap_constant_16(x) \ + ((uint16_t)((((uint16_t)(x) & 0x00ff) << 8) | \ + (((uint16_t)(x) & 0xff00) >> 8))) + +#define __bswap_constant_32(x) \ + ((uint32_t)((((uint32_t)(x) & 0x000000ffU) << 24) | \ + (((uint32_t)(x) & 0x0000ff00U) << 8) | \ + (((uint32_t)(x) & 0x00ff0000U) >> 8) | \ + (((uint32_t)(x) & 0xff000000U) >> 24))) + +#define __bswap_constant_64(x) \ + ((uint64_t)((((uint64_t)(x) & 0x00000000000000ffULL) << 56) | \ + (((uint64_t)(x) & 0x000000000000ff00ULL) << 40) | \ + (((uint64_t)(x) & 0x0000000000ff0000ULL) << 24) | \ + (((uint64_t)(x) & 0x00000000ff000000ULL) << 8) | \ + (((uint64_t)(x) & 0x000000ff00000000ULL) >> 8) | \ + (((uint64_t)(x) & 0x0000ff0000000000ULL) >> 24) | \ + (((uint64_t)(x) & 0x00ff000000000000ULL) >> 40) | \ + (((uint64_t)(x) & 0xff00000000000000ULL) >> 56))) + +#define __bswap_16(x) \ + ((uint16_t)(__builtin_constant_p(x) ? \ + __bswap_constant_16(x) : \ + __bswap_variable_16(x))) + +#define __bswap_32(x) \ + ((uint32_t)(__builtin_constant_p(x) ? \ + __bswap_constant_32(x) : \ + __bswap_variable_32(x))) + +#define __bswap_64(x) \ + ((uint64_t)(__builtin_constant_p(x) ? \ + __bswap_constant_64(x) : \ + __bswap_variable_64(x))) + #if __BYTE_ORDER == __LITTLE_ENDIAN #include "little_bswap.h" #endif diff --git a/gpxe/src/include/compiler.h b/gpxe/src/include/compiler.h index 8ab7b8ae..889c2404 100644 --- a/gpxe/src/include/compiler.h +++ b/gpxe/src/include/compiler.h @@ -59,6 +59,17 @@ __asm__ ( ".equ\t" OBJECT_SYMBOL_STR ", 0" ); #define REQUIRE_OBJECT(object) \ __asm__ ( ".equ\tneed_" #object ", obj_" #object ); +/* Force visibility of all symbols to "hidden", i.e. inform gcc that + * all symbol references resolve strictly within our final binary. + * This avoids unnecessary PLT/GOT entries on x86_64. + * + * This is a stronger claim than specifying "-fvisibility=hidden", + * since it also affects symbols marked with "extern". + */ +#if __GNUC__ >= 4 +#pragma GCC visibility push(hidden) +#endif + /** @def DBG * * Print a debugging message. @@ -131,11 +142,26 @@ extern void dbg_decolourise ( void ); extern void dbg_hex_dump_da ( unsigned long dispaddr, const void *data, unsigned long len ); -/* Compatibility with existing Makefile */ #if DEBUG_SYMBOL -#define DBGLVL 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; +#define DBGLVL ( DBGLVL_MAX & ~__debug_disable ) +#define DBG_DISABLE( level ) do { \ + __debug_disable |= ( (level) & DBGLVL_MAX ); \ + } while ( 0 ) +#define DBG_ENABLE( level ) do { \ + __debug_disable &= ~( (level) & DBGLVL_MAX ); \ + } while ( 0 ) #else #define DBGLVL 0 +#define DBG_DISABLE( level ) do { } while ( 0 ) +#define DBG_ENABLE( level ) do { } while ( 0 ) #endif #define DBGLVL_LOG 1 @@ -287,9 +313,6 @@ extern void dbg_hex_dump_da ( unsigned long dispaddr, /** Declare a variable or data structure as unused. */ #define __unused __attribute__ (( unused )) -/** Apply standard C calling conventions */ -#define __cdecl __attribute__ (( cdecl , regparm(0) )) - /** * Declare a function as pure - i.e. without side effects */ @@ -325,6 +348,9 @@ extern void dbg_hex_dump_da ( unsigned long dispaddr, /** Declare a data structure to be aligned with 16-byte alignment */ #define __aligned __attribute__ (( aligned ( 16 ) )) +/** Declare a function to be always inline */ +#define __always_inline __attribute__ (( always_inline )) + /** * Shared data. * @@ -354,4 +380,6 @@ extern void dbg_hex_dump_da ( unsigned long dispaddr, #endif /* ASSEMBLY */ +#include <bits/compiler.h> + #endif /* COMPILER_H */ diff --git a/gpxe/src/include/elf.h b/gpxe/src/include/elf.h index a6eb5d9c..fadc0bdb 100644 --- a/gpxe/src/include/elf.h +++ b/gpxe/src/include/elf.h @@ -227,10 +227,6 @@ typedef struct { /* Standardized Elf image notes for booting... The name for all of these is ELFBoot */ - -/* ELF Defines for the current architecture */ -#include "bits/elf.h" - #endif /* ASSEMBLY */ #endif /* ELF_H */ diff --git a/gpxe/src/include/gpxe/aoe.h b/gpxe/src/include/gpxe/aoe.h index 4aab4291..6de6b965 100644 --- a/gpxe/src/include/gpxe/aoe.h +++ b/gpxe/src/include/gpxe/aoe.h @@ -13,8 +13,24 @@ #include <gpxe/retry.h> #include <gpxe/ata.h> +/** An AoE config command */ +struct aoecfg { + /** AoE Queue depth */ + uint16_t bufcnt; + /** ATA target firmware version */ + uint16_t fwver; + /** ATA target sector count */ + uint8_t scnt; + /** AoE config string subcommand */ + uint8_t aoeccmd; + /** AoE config string length */ + uint16_t cfglen; + /** AoE config string */ + uint8_t data[0]; +} __attribute__ (( packed )); + /** An AoE ATA command */ -struct aoecmd { +struct aoeata { /** AoE command flags */ uint8_t aflags; /** ATA error/feature register */ @@ -37,6 +53,14 @@ struct aoecmd { #define AOE_FL_ASYNC 0x02 /**< Asynchronous write */ #define AOE_FL_WRITE 0x01 /**< Write command */ +/** An AoE command */ +union aoecmd { + /** Config command */ + struct aoecfg cfg; + /** ATA command */ + struct aoeata ata; +}; + /** An AoE header */ struct aoehdr { /** Protocol version number and flags */ @@ -52,10 +76,7 @@ struct aoehdr { /** Tag, in network byte order */ uint32_t tag; /** Payload */ - union { - /** ATA command */ - struct aoecmd command[0]; - } arg; + union aoecmd cmd[0]; } __attribute__ (( packed )); #define AOE_VERSION 0x10 /**< Version 1 */ @@ -99,6 +120,8 @@ struct aoe_session { /** Tag for current AoE command */ uint32_t tag; + /** Current AOE command */ + uint8_t aoe_cmd_type; /** Current ATA command */ struct ata_command *command; /** Overall status of current ATA command */ diff --git a/gpxe/src/include/gpxe/api.h b/gpxe/src/include/gpxe/api.h new file mode 100644 index 00000000..df5d1ae3 --- /dev/null +++ b/gpxe/src/include/gpxe/api.h @@ -0,0 +1,82 @@ +#ifndef _GPXE_API_H +#define _GPXE_API_H + +/** @file + * + * gPXE internal APIs + * + * There are various formally-defined APIs internal to gPXE, with + * several differing implementations specific to particular execution + * environments (e.g. PC BIOS, EFI, LinuxBIOS). + * + */ + +/** @defgroup Single-implementation APIs + * + * These are APIs for which only a single implementation may be + * compiled in at any given time. + * + * @{ + */ + +/** + * Calculate function implementation name + * + * @v _prefix Subsystem prefix + * @v _api_func API function + * @ret _subsys_func Subsystem API function + * + * The subsystem prefix should be an empty string for the currently + * selected subsystem, and should be a subsystem-unique string for all + * other subsystems. + */ +#define SINGLE_API_NAME( _prefix, _api_func ) _prefix ## _api_func + +/** + * Calculate static inline function name + * + * @v _prefix Subsystem prefix + * @v _api_func API function + * @ret _subsys_func Subsystem API function + */ +#define SINGLE_API_INLINE( _prefix, _api_func ) \ + SINGLE_API_NAME ( _prefix, _api_func ) + +/** + * Provide an API implementation + * + * @v _prefix Subsystem prefix + * @v _api_func API function + * @v _func Implementing function + */ +#define PROVIDE_SINGLE_API( _prefix, _api_func, _func ) \ + /* Ensure that _api_func exists */ \ + typeof ( _api_func ) _api_func; \ + /* Ensure that _func exists */ \ + typeof ( _func ) _func; \ + /* Ensure that _func is type-compatible with _api_func */ \ + typeof ( _api_func ) _func; \ + /* Ensure that _subsys_func is non-static */ \ + extern typeof ( _api_func ) SINGLE_API_NAME ( _prefix, _api_func ); \ + /* Provide symbol alias from _subsys_func to _func */ \ + typeof ( _api_func ) SINGLE_API_NAME ( _prefix, _api_func ) \ + __attribute__ (( alias ( #_func ) )); + +/** + * Provide a static inline API implementation + * + * @v _prefix Subsystem prefix + * @v _api_func API function + */ +#define PROVIDE_SINGLE_API_INLINE( _prefix, _api_func ) \ + /* Ensure that _api_func exists */ \ + typeof ( _api_func ) _api_func; \ + /* Ensure that _subsys_func exists and is static */ \ + static typeof ( SINGLE_API_INLINE ( _prefix, _api_func ) ) \ + SINGLE_API_INLINE ( _prefix, _api_func ); \ + /* Ensure that _subsys_func is type-compatible with _api_func */ \ + typeof ( _api_func ) SINGLE_API_INLINE ( _prefix, _api_func ); + +/** @} */ + +#endif /* _GPXE_API_H */ diff --git a/gpxe/src/include/gpxe/asn1.h b/gpxe/src/include/gpxe/asn1.h index 1ad90050..5440c48c 100644 --- a/gpxe/src/include/gpxe/asn1.h +++ b/gpxe/src/include/gpxe/asn1.h @@ -21,12 +21,12 @@ */ struct asn1_cursor { /** Start of data */ - uint8_t *data; + void *data; /** Length of data */ size_t len; }; -extern int asn1_enter_object ( struct asn1_cursor *cursor, unsigned int type ); -extern int asn1_skip_object ( struct asn1_cursor *cursor, unsigned int type ); +extern int asn1_enter ( struct asn1_cursor *cursor, unsigned int type ); +extern int asn1_skip ( struct asn1_cursor *cursor, unsigned int type ); #endif /* _GPXE_ASN1_H */ diff --git a/gpxe/src/include/gpxe/base64.h b/gpxe/src/include/gpxe/base64.h new file mode 100644 index 00000000..3321971a --- /dev/null +++ b/gpxe/src/include/gpxe/base64.h @@ -0,0 +1,24 @@ +#ifndef _GPXE_BASE64_H +#define _GPXE_BASE64_H + +/** @file + * + * Base64 encoding + * + */ + +#include <stdint.h> + +/** + * Calculate length of base64-encoded string + * + * @v raw_len Raw string length (excluding NUL) + * @ret encoded_len Encoded string length (excluding NUL) + */ +static inline size_t base64_encoded_len ( size_t raw_len ) { + return ( ( ( raw_len + 3 - 1 ) / 3 ) * 4 ); +} + +extern void base64_encode ( const char *raw, char *encoded ); + +#endif /* _GPXE_BASE64_H */ diff --git a/gpxe/src/include/gpxe/bitops.h b/gpxe/src/include/gpxe/bitops.h index f95af7d3..5405c854 100644 --- a/gpxe/src/include/gpxe/bitops.h +++ b/gpxe/src/include/gpxe/bitops.h @@ -1,27 +1,228 @@ #ifndef _GPXE_BITOPS_H #define _GPXE_BITOPS_H -/** @file +/* + * 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., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +/** + * @file * * Bit operations + * */ #include <stdint.h> +#include <byteswap.h> + +/* Endianness selection. + * + * This is a property of the NIC, not a property of the host CPU. + */ +#ifdef BITOPS_LITTLE_ENDIAN +#define cpu_to_BIT64 cpu_to_le64 +#define cpu_to_BIT32 cpu_to_le32 +#define BIT64_to_cpu le64_to_cpu +#define BIT32_to_cpu le32_to_cpu +#endif +#ifdef BITOPS_BIG_ENDIAN +#define cpu_to_BIT64 cpu_to_be64 +#define cpu_to_BIT32 cpu_to_be32 +#define BIT64_to_cpu be64_to_cpu +#define BIT32_to_cpu be32_to_cpu +#endif + +/** Datatype used to represent a bit in the pseudo-structures */ +typedef unsigned char pseudo_bit_t; + +/** + * Wrapper structure for pseudo_bit_t structures + * + * This structure provides a wrapper around pseudo_bit_t structures. + * It has the correct size, and also encapsulates type information + * about the underlying pseudo_bit_t-based structure, which allows the + * BIT_FILL() etc. macros to work without requiring explicit type + * information. + */ +#define PSEUDO_BIT_STRUCT( _structure ) \ + union { \ + uint8_t bytes[ sizeof ( _structure ) / 8 ]; \ + uint32_t dwords[ sizeof ( _structure ) / 32 ]; \ + uint64_t qwords[ sizeof ( _structure ) / 64 ]; \ + _structure *dummy[0]; \ + } u + +/** Get pseudo_bit_t structure type from wrapper structure pointer */ +#define PSEUDO_BIT_STRUCT_TYPE( _ptr ) \ + typeof ( *((_ptr)->u.dummy[0]) ) + +/** Bit offset of a field within a pseudo_bit_t structure */ +#define BIT_OFFSET( _ptr, _field ) \ + offsetof ( PSEUDO_BIT_STRUCT_TYPE ( _ptr ), _field ) + +/** Bit width of a field within a pseudo_bit_t structure */ +#define BIT_WIDTH( _ptr, _field ) \ + sizeof ( ( ( PSEUDO_BIT_STRUCT_TYPE ( _ptr ) * ) NULL )->_field ) + +/** Qword offset of a field within a pseudo_bit_t structure */ +#define QWORD_OFFSET( _ptr, _field ) \ + ( BIT_OFFSET ( _ptr, _field ) / 64 ) + +/** Qword bit offset of a field within a pseudo_bit_t structure */ +#define QWORD_BIT_OFFSET( _ptr, _index, _field ) \ + ( BIT_OFFSET ( _ptr, _field ) - ( 64 * (_index) ) ) + +/** Bit mask for a field within a pseudo_bit_t structure */ +#define BIT_MASK( _ptr, _field ) \ + ( ( ~( ( uint64_t ) 0 ) ) >> \ + ( 64 - BIT_WIDTH ( _ptr, _field ) ) ) + +/* + * Assemble native-endian qword from named fields and values + * + */ + +#define BIT_ASSEMBLE_1( _ptr, _index, _field, _value ) \ + ( ( ( uint64_t) (_value) ) << \ + QWORD_BIT_OFFSET ( _ptr, _index, _field ) ) + +#define BIT_ASSEMBLE_2( _ptr, _index, _field, _value, ... ) \ + ( BIT_ASSEMBLE_1 ( _ptr, _index, _field, _value ) | \ + BIT_ASSEMBLE_1 ( _ptr, _index, __VA_ARGS__ ) ) + +#define BIT_ASSEMBLE_3( _ptr, _index, _field, _value, ... ) \ + ( BIT_ASSEMBLE_1 ( _ptr, _index, _field, _value ) | \ + BIT_ASSEMBLE_2 ( _ptr, _index, __VA_ARGS__ ) ) + +#define BIT_ASSEMBLE_4( _ptr, _index, _field, _value, ... ) \ + ( BIT_ASSEMBLE_1 ( _ptr, _index, _field, _value ) | \ + BIT_ASSEMBLE_3 ( _ptr, _index, __VA_ARGS__ ) ) + +#define BIT_ASSEMBLE_5( _ptr, _index, _field, _value, ... ) \ + ( BIT_ASSEMBLE_1 ( _ptr, _index, _field, _value ) | \ + BIT_ASSEMBLE_4 ( _ptr, _index, __VA_ARGS__ ) ) + +#define BIT_ASSEMBLE_6( _ptr, _index, _field, _value, ... ) \ + ( BIT_ASSEMBLE_1 ( _ptr, _index, _field, _value ) | \ + BIT_ASSEMBLE_5 ( _ptr, _index, __VA_ARGS__ ) ) + +#define BIT_ASSEMBLE_7( _ptr, _index, _field, _value, ... ) \ + ( BIT_ASSEMBLE_1 ( _ptr, _index, _field, _value ) | \ + BIT_ASSEMBLE_6 ( _ptr, _index, __VA_ARGS__ ) ) + +/* + * Build native-endian (positive) qword bitmasks from named fields + * + */ + +#define BIT_MASK_1( _ptr, _index, _field ) \ + ( BIT_MASK ( _ptr, _field ) << \ + QWORD_BIT_OFFSET ( _ptr, _index, _field ) ) + +#define BIT_MASK_2( _ptr, _index, _field, ... ) \ + ( BIT_MASK_1 ( _ptr, _index, _field ) | \ + BIT_MASK_1 ( _ptr, _index, __VA_ARGS__ ) ) + +#define BIT_MASK_3( _ptr, _index, _field, ... ) \ + ( BIT_MASK_1 ( _ptr, _index, _field ) | \ + BIT_MASK_2 ( _ptr, _index, __VA_ARGS__ ) ) + +#define BIT_MASK_4( _ptr, _index, _field, ... ) \ + ( BIT_MASK_1 ( _ptr, _index, _field ) | \ + BIT_MASK_3 ( _ptr, _index, __VA_ARGS__ ) ) + +#define BIT_MASK_5( _ptr, _index, _field, ... ) \ + ( BIT_MASK_1 ( _ptr, _index, _field ) | \ + BIT_MASK_4 ( _ptr, _index, __VA_ARGS__ ) ) + +#define BIT_MASK_6( _ptr, _index, _field, ... ) \ + ( BIT_MASK_1 ( _ptr, _index, _field ) | \ + BIT_MASK_5 ( _ptr, _index, __VA_ARGS__ ) ) + +#define BIT_MASK_7( _ptr, _index, _field, ... ) \ + ( BIT_MASK_1 ( _ptr, _index, _field ) | \ + BIT_MASK_6 ( _ptr, _index, __VA_ARGS__ ) ) + +/* + * Populate little-endian qwords from named fields and values + * + */ + +#define BIT_FILL( _ptr, _index, _assembled ) do { \ + uint64_t *__ptr = &(_ptr)->u.qwords[(_index)]; \ + uint64_t __assembled = (_assembled); \ + *__ptr = cpu_to_BIT64 ( __assembled ); \ + } while ( 0 ) + +#define BIT_FILL_1( _ptr, _field1, ... ) \ + BIT_FILL ( _ptr, QWORD_OFFSET ( _ptr, _field1 ), \ + BIT_ASSEMBLE_1 ( _ptr, QWORD_OFFSET ( _ptr, _field1 ), \ + _field1, __VA_ARGS__ ) ) + +#define BIT_FILL_2( _ptr, _field1, ... ) \ + BIT_FILL ( _ptr, QWORD_OFFSET ( _ptr, _field1 ), \ + BIT_ASSEMBLE_2 ( _ptr, QWORD_OFFSET ( _ptr, _field1 ), \ + _field1, __VA_ARGS__ ) ) + +#define BIT_FILL_3( _ptr, _field1, ... ) \ + BIT_FILL ( _ptr, QWORD_OFFSET ( _ptr, _field1 ), \ + BIT_ASSEMBLE_3 ( _ptr, QWORD_OFFSET ( _ptr, _field1 ), \ + _field1, __VA_ARGS__ ) ) + +#define BIT_FILL_4( _ptr, _field1, ... ) \ + BIT_FILL ( _ptr, QWORD_OFFSET ( _ptr, _field1 ), \ + BIT_ASSEMBLE_4 ( _ptr, QWORD_OFFSET ( _ptr, _field1 ), \ + _field1, __VA_ARGS__ ) ) + +#define BIT_FILL_5( _ptr, _field1, ... ) \ + BIT_FILL ( _ptr, QWORD_OFFSET ( _ptr, _field1 ), \ + BIT_ASSEMBLE_5 ( _ptr, QWORD_OFFSET ( _ptr, _field1 ), \ + _field1, __VA_ARGS__ ) ) -static inline uint32_t rol32 ( uint32_t data, unsigned int rotation ) { - return ( ( data << rotation ) | ( data >> ( 32 - rotation ) ) ); -} +#define BIT_FILL_6( _ptr, _field1, ... ) \ + BIT_FILL ( _ptr, QWORD_OFFSET ( _ptr, _field1 ), \ + BIT_ASSEMBLE_6 ( _ptr, QWORD_OFFSET ( _ptr, _field1 ), \ + _field1, __VA_ARGS__ ) ) -static inline uint32_t ror32 ( uint32_t data, unsigned int rotation ) { - return ( ( data >> rotation ) | ( data << ( 32 - rotation ) ) ); -} +/** Extract value of named field */ +#define BIT_GET64( _ptr, _field ) \ + ( { \ + unsigned int __index = QWORD_OFFSET ( _ptr, _field ); \ + uint64_t *__ptr = &(_ptr)->u.qwords[__index]; \ + uint64_t __value = BIT64_to_cpu ( *__ptr ); \ + __value >>= \ + QWORD_BIT_OFFSET ( _ptr, __index, _field ); \ + __value &= BIT_MASK ( _ptr, _field ); \ + __value; \ + } ) -static inline uint64_t rol64 ( uint64_t data, unsigned int rotation ) { - return ( ( data << rotation ) | ( data >> ( 64 - rotation ) ) ); -} +/** Extract value of named field (for fields up to the size of a long) */ +#define BIT_GET( _ptr, _field ) \ + ( ( unsigned long ) BIT_GET64 ( _ptr, _field ) ) -static inline uint64_t ror64 ( uint64_t data, unsigned int rotation ) { - return ( ( data >> rotation ) | ( data << ( 64 - rotation ) ) ); -} +#define BIT_SET( _ptr, _field, _value ) do { \ + unsigned int __index = QWORD_OFFSET ( _ptr, _field ); \ + uint64_t *__ptr = &(_ptr)->u.qwords[__index]; \ + unsigned int __shift = \ + QWORD_BIT_OFFSET ( _ptr, __index, _field ); \ + uint64_t __value = (_value); \ + *__ptr &= cpu_to_BIT64 ( ~( BIT_MASK ( _ptr, _field ) << \ + __shift ) ); \ + *__ptr |= cpu_to_BIT64 ( __value << __shift ); \ + } while ( 0 ) #endif /* _GPXE_BITOPS_H */ diff --git a/gpxe/src/include/gpxe/blockdev.h b/gpxe/src/include/gpxe/blockdev.h index 467ed1d9..8222984a 100644 --- a/gpxe/src/include/gpxe/blockdev.h +++ b/gpxe/src/include/gpxe/blockdev.h @@ -10,12 +10,10 @@ #include <gpxe/uaccess.h> -/** A block device */ -struct block_device { - /** Block size */ - size_t blksize; - /** Total number of blocks */ - uint64_t blocks; +struct block_device; + +/** Block device operations */ +struct block_device_operations { /** * Read block * @@ -40,4 +38,14 @@ struct block_device { unsigned long count, userptr_t buffer ); }; +/** A block device */ +struct block_device { + /** Block device operations */ + struct block_device_operations *op; + /** Block size */ + size_t blksize; + /** Total number of blocks */ + uint64_t blocks; +}; + #endif /* _GPXE_BLOCKDEV_H */ diff --git a/gpxe/src/include/gpxe/dhcp.h b/gpxe/src/include/gpxe/dhcp.h index e89503d3..33e0c5d4 100644 --- a/gpxe/src/include/gpxe/dhcp.h +++ b/gpxe/src/include/gpxe/dhcp.h @@ -12,8 +12,9 @@ #include <gpxe/list.h> #include <gpxe/refcnt.h> #include <gpxe/tables.h> +#include <gpxe/uuid.h> +#include <gpxe/netdevice.h> -struct net_device; struct job_interface; struct dhcp_options; struct dhcp_packet; @@ -24,8 +25,8 @@ struct dhcp_packet; /** BOOTP/DHCP client port */ #define BOOTPC_PORT 68 -/** ProxyDHCP server port */ -#define PROXYDHCP_PORT 4011 +/** PXE server port */ +#define PXE_PORT 4011 /** Construct a tag value for an encapsulated option * @@ -81,6 +82,87 @@ struct dhcp_packet; /** Vendor encapsulated options */ #define DHCP_VENDOR_ENCAP 43 +/** PXE boot server discovery control */ +#define DHCP_PXE_DISCOVERY_CONTROL DHCP_ENCAP_OPT ( DHCP_VENDOR_ENCAP, 6 ) + +/** PXE boot server discovery control bits */ +enum dhcp_pxe_discovery_control { + /** Inhibit broadcast discovery */ + PXEBS_NO_BROADCAST = 1, + /** Inhibit multicast discovery */ + PXEBS_NO_MULTICAST = 2, + /** Accept only servers in DHCP_PXE_BOOT_SERVERS list */ + PXEBS_NO_UNKNOWN_SERVERS = 4, + /** Skip discovery if filename present */ + PXEBS_SKIP = 8, +}; + +/** PXE boot server multicast address */ +#define DHCP_PXE_BOOT_SERVER_MCAST DHCP_ENCAP_OPT ( DHCP_VENDOR_ENCAP, 7 ) + +/** PXE boot servers */ +#define DHCP_PXE_BOOT_SERVERS DHCP_ENCAP_OPT ( DHCP_VENDOR_ENCAP, 8 ) + +/** PXE boot server */ +struct dhcp_pxe_boot_server { + /** "Type" */ + uint16_t type; + /** Number of IPv4 addresses */ + uint8_t num_ip; + /** IPv4 addresses */ + struct in_addr ip[0]; +} __attribute__ (( packed )); + +/** PXE boot menu */ +#define DHCP_PXE_BOOT_MENU DHCP_ENCAP_OPT ( DHCP_VENDOR_ENCAP, 9 ) + +/** PXE boot menu */ +struct dhcp_pxe_boot_menu { + /** "Type" */ + uint16_t type; + /** Description length */ + uint8_t desc_len; + /** Description */ + char desc[0]; +} __attribute__ (( packed )); + +/** PXE boot menu prompt */ +#define DHCP_PXE_BOOT_MENU_PROMPT DHCP_ENCAP_OPT ( DHCP_VENDOR_ENCAP, 10 ) + +/** PXE boot menu prompt */ +struct dhcp_pxe_boot_menu_prompt { + /** Timeout + * + * A value of 0 means "time out immediately and select first + * boot item, without displaying the prompt". A value of 255 + * means "display menu immediately with no timeout". Any + * other value means "display prompt, wait this many seconds + * for keypress, if key is F8, display menu, otherwise select + * first boot item". + */ + uint8_t timeout; + /** Prompt to press F8 */ + char prompt[0]; +} __attribute__ (( packed )); + +/** PXE boot menu item */ +#define DHCP_PXE_BOOT_MENU_ITEM DHCP_ENCAP_OPT ( DHCP_VENDOR_ENCAP, 71 ) + +/** PXE boot menu item */ +struct dhcp_pxe_boot_menu_item { + /** "Type" + * + * This field actually identifies the specific boot server (or + * cluster of boot servers offering identical boot files). + */ + uint16_t type; + /** "Layer" + * + * Just don't ask. + */ + uint16_t layer; +} __attribute__ (( packed )); + /** Requested IP address */ #define DHCP_REQUESTED_ADDRESS 50 @@ -127,6 +209,14 @@ struct dhcp_packet; /** Client identifier */ #define DHCP_CLIENT_ID 61 +/** Client identifier */ +struct dhcp_client_id { + /** Link-layer protocol */ + uint8_t ll_proto; + /** Link-layer address */ + uint8_t ll_addr[MAX_LL_ADDR_LEN]; +} __attribute__ (( packed )); + /** TFTP server name * * This option replaces the fixed "sname" field, when that field is @@ -141,6 +231,9 @@ struct dhcp_packet; */ #define DHCP_BOOTFILE_NAME 67 +/** User class identifier */ +#define DHCP_USER_CLASS_ID 77 + /** Client system architecture */ #define DHCP_CLIENT_ARCHITECTURE 93 @@ -150,6 +243,16 @@ struct dhcp_packet; /** UUID client identifier */ #define DHCP_CLIENT_UUID 97 +/** UUID client identifier */ +struct dhcp_client_uuid { + /** Identifier type */ + uint8_t type; + /** UUID */ + union uuid uuid; +} __attribute__ (( packed )); + +#define DHCP_CLIENT_UUID_TYPE 0 + /** Etherboot-specific encapsulated options * * This encapsulated options field is used to contain all options @@ -197,12 +300,12 @@ struct dhcp_packet; * */ -/** Ignore ProxyDHCP +/** Skip PXE DHCP protocol extensions such as ProxyDHCP * * If set to a non-zero value, gPXE will not wait for ProxyDHCP offers - * and will ignore any ProxyDHCP offers that it receives. + * and will ignore any PXE-specific DHCP options that it receives. */ -#define DHCP_EB_NO_PROXYDHCP DHCP_ENCAP_OPT ( DHCP_EB_ENCAP, 0xb0 ) +#define DHCP_EB_NO_PXEDHCP DHCP_ENCAP_OPT ( DHCP_EB_ENCAP, 0xb0 ) /** Network device descriptor * @@ -217,6 +320,16 @@ struct dhcp_packet; */ #define DHCP_EB_BUS_ID DHCP_ENCAP_OPT ( DHCP_EB_ENCAP, 0xb1 ) +/** Network device descriptor */ +struct dhcp_netdev_desc { + /** Bus type ID */ + uint8_t type; + /** Vendor ID */ + uint16_t vendor; + /** Device ID */ + uint16_t device; +} __attribute__ (( packed )); + /** BIOS drive number * * This is the drive number for a drive emulated via INT 13. 0x80 is @@ -260,6 +373,9 @@ struct dhcp_packet; */ #define DHCP_EB_REVERSE_PASSWORD DHCP_ENCAP_OPT ( DHCP_EB_ENCAP, 0xc1 ) +/** gPXE version number */ +#define DHCP_EB_VERSION DHCP_ENCAP_OPT ( DHCP_EB_ENCAP, 0xeb ) + /** iSCSI primary target IQN */ #define DHCP_ISCSI_PRIMARY_TARGET_IQN 201 @@ -464,28 +580,35 @@ struct dhcphdr { */ #define DHCP_MIN_LEN 552 -/** Maximum time that we will wait for ProxyDHCP responses */ -#define PROXYDHCP_WAIT_TIME ( TICKS_PER_SEC * 1 ) - /** Timeouts for sending DHCP packets */ #define DHCP_MIN_TIMEOUT ( 1 * TICKS_PER_SEC ) #define DHCP_MAX_TIMEOUT ( 10 * TICKS_PER_SEC ) +/** Maximum time that we will wait for ProxyDHCP responses */ +#define PROXYDHCP_MAX_TIMEOUT ( 2 * TICKS_PER_SEC ) + +/** Maximum time that we will wait for Boot Server responses */ +#define PXEBS_MAX_TIMEOUT ( 3 * TICKS_PER_SEC ) + /** Settings block name used for DHCP responses */ #define DHCP_SETTINGS_NAME "dhcp" /** Settings block name used for ProxyDHCP responses */ #define PROXYDHCP_SETTINGS_NAME "proxydhcp" +/** Setting block name used for BootServerDHCP responses */ +#define PXEBS_SETTINGS_NAME "pxebs" + extern int dhcp_create_packet ( struct dhcp_packet *dhcppkt, struct net_device *netdev, uint8_t msgtype, - struct dhcp_options *options, + const void *options, size_t options_len, void *data, size_t max_len ); extern int dhcp_create_request ( struct dhcp_packet *dhcppkt, struct net_device *netdev, - struct in_addr ciaddr, - struct dhcp_packet *dhcpoffer, + unsigned int msgtype, struct in_addr ciaddr, void *data, size_t max_len ); extern int start_dhcp ( struct job_interface *job, struct net_device *netdev ); +extern int start_pxebs ( struct job_interface *job, struct net_device *netdev, + unsigned int pxe_type ); #endif /* _GPXE_DHCP_H */ diff --git a/gpxe/src/include/gpxe/dhcppkt.h b/gpxe/src/include/gpxe/dhcppkt.h index 179be2f8..e8f8fafd 100644 --- a/gpxe/src/include/gpxe/dhcppkt.h +++ b/gpxe/src/include/gpxe/dhcppkt.h @@ -9,27 +9,54 @@ #include <gpxe/dhcp.h> #include <gpxe/dhcpopts.h> +#include <gpxe/refcnt.h> /** * A DHCP packet * */ struct dhcp_packet { + /** Reference counter */ + struct refcnt refcnt; /** The DHCP packet contents */ struct dhcphdr *dhcphdr; /** Maximum length of the DHCP packet buffer */ size_t max_len; /** Used length of the DHCP packet buffer */ size_t len; - /** DHCP option blocks */ + /** DHCP options */ struct dhcp_options options; + /** Settings interface */ + struct settings settings; }; +/** + * Increment reference count on DHCP packet + * + * @v dhcppkt DHCP packet + * @ret dhcppkt DHCP packet + */ +static inline __attribute__ (( always_inline )) struct dhcp_packet * +dhcppkt_get ( struct dhcp_packet *dhcppkt ) { + ref_get ( &dhcppkt->refcnt ); + return dhcppkt; +} + +/** + * Decrement reference count on DHCP packet + * + * @v dhcppkt DHCP packet + */ +static inline __attribute__ (( always_inline )) void +dhcppkt_put ( struct dhcp_packet *dhcppkt ) { + ref_put ( &dhcppkt->refcnt ); +} + extern int dhcppkt_store ( struct dhcp_packet *dhcppkt, unsigned int tag, const void *data, size_t len ); extern int dhcppkt_fetch ( struct dhcp_packet *dhcppkt, unsigned int tag, void *data, size_t len ); extern void dhcppkt_init ( struct dhcp_packet *dhcppkt, - void *data, size_t len ); + struct dhcphdr *data, size_t len ); #endif /* _GPXE_DHCPPKT_H */ diff --git a/gpxe/src/include/gpxe/editbox.h b/gpxe/src/include/gpxe/editbox.h index 47b07c25..007b042f 100644 --- a/gpxe/src/include/gpxe/editbox.h +++ b/gpxe/src/include/gpxe/editbox.h @@ -24,14 +24,22 @@ struct edit_box { unsigned int width; /** First displayed character */ unsigned int first; + /** Flags */ + unsigned int flags; +}; + +/** Editable text box widget flags */ +enum edit_box_flags { + /** Show stars instead of contents (for password widgets) */ + EDITBOX_STARS = 0x0001, }; extern void init_editbox ( struct edit_box *box, char *buf, size_t len, WINDOW *win, unsigned int row, unsigned int col, - unsigned int width ) + unsigned int width, unsigned int flags ) __attribute__ (( nonnull (1, 2) )); extern void draw_editbox ( struct edit_box *box ) __nonnull; -static inline int __pure edit_editbox ( struct edit_box *box, int key ) __nonnull; +static inline int edit_editbox ( struct edit_box *box, int key ) __nonnull; /** * Edit text box widget diff --git a/gpxe/src/include/gpxe/efi/Base.h b/gpxe/src/include/gpxe/efi/Base.h new file mode 100644 index 00000000..b2552d80 --- /dev/null +++ b/gpxe/src/include/gpxe/efi/Base.h @@ -0,0 +1,329 @@ +/** @file + Root include file for Mde Package Base type modules + + This is the include file for any module of type base. Base modules only use + types defined via this include file and can be ported easily to any + environment. There are a set of base libraries in the Mde Package that can + be used to implement base modules. + +Copyright (c) 2006 - 2008, Intel Corporation +All rights reserved. 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 __BASE_H__ +#define __BASE_H__ + +// +// Include processor specific binding +// +#include <gpxe/efi/ProcessorBind.h> + +typedef struct { + UINT32 Data1; + UINT16 Data2; + UINT16 Data3; + UINT8 Data4[8]; +} GUID; + +typedef UINT64 PHYSICAL_ADDRESS; + +/// +/// LIST_ENTRY definition +/// +typedef struct _LIST_ENTRY LIST_ENTRY; + +struct _LIST_ENTRY { + LIST_ENTRY *ForwardLink; + LIST_ENTRY *BackLink; +}; + +// +// Modifiers to absract standard types to aid in debug of problems +// +#define CONST const +#define STATIC static +#define VOID void + +// +// Modifiers for Data Types used to self document code. +// This concept is borrowed for UEFI specification. +// +#define IN +#define OUT +#define OPTIONAL + +// +// UEFI specification claims 1 and 0. We are concerned about the +// complier portability so we did it this way. +// +#define TRUE ((BOOLEAN)(1==1)) +#define FALSE ((BOOLEAN)(0==1)) + +#define NULL ((VOID *) 0) + +#define BIT0 0x00000001 +#define BIT1 0x00000002 +#define BIT2 0x00000004 +#define BIT3 0x00000008 +#define BIT4 0x00000010 +#define BIT5 0x00000020 +#define BIT6 0x00000040 +#define BIT7 0x00000080 +#define BIT8 0x00000100 +#define BIT9 0x00000200 +#define BIT10 0x00000400 +#define BIT11 0x00000800 +#define BIT12 0x00001000 +#define BIT13 0x00002000 +#define BIT14 0x00004000 +#define BIT15 0x00008000 +#define BIT16 0x00010000 +#define BIT17 0x00020000 +#define BIT18 0x00040000 +#define BIT19 0x00080000 +#define BIT20 0x00100000 +#define BIT21 0x00200000 +#define BIT22 0x00400000 +#define BIT23 0x00800000 +#define BIT24 0x01000000 +#define BIT25 0x02000000 +#define BIT26 0x04000000 +#define BIT27 0x08000000 +#define BIT28 0x10000000 +#define BIT29 0x20000000 +#define BIT30 0x40000000 +#define BIT31 0x80000000 +#define BIT32 0x0000000100000000UL +#define BIT33 0x0000000200000000UL +#define BIT34 0x0000000400000000UL +#define BIT35 0x0000000800000000UL +#define BIT36 0x0000001000000000UL +#define BIT37 0x0000002000000000UL +#define BIT38 0x0000004000000000UL +#define BIT39 0x0000008000000000UL +#define BIT40 0x0000010000000000UL +#define BIT41 0x0000020000000000UL +#define BIT42 0x0000040000000000UL +#define BIT43 0x0000080000000000UL +#define BIT44 0x0000100000000000UL +#define BIT45 0x0000200000000000UL +#define BIT46 0x0000400000000000UL +#define BIT47 0x0000800000000000UL +#define BIT48 0x0001000000000000UL +#define BIT49 0x0002000000000000UL +#define BIT50 0x0004000000000000UL +#define BIT51 0x0008000000000000UL +#define BIT52 0x0010000000000000UL +#define BIT53 0x0020000000000000UL +#define BIT54 0x0040000000000000UL +#define BIT55 0x0080000000000000UL +#define BIT56 0x0100000000000000UL +#define BIT57 0x0200000000000000UL +#define BIT58 0x0400000000000000UL +#define BIT59 0x0800000000000000UL +#define BIT60 0x1000000000000000UL +#define BIT61 0x2000000000000000UL +#define BIT62 0x4000000000000000UL +#define BIT63 0x8000000000000000UL + +// +// Support for variable length argument lists using the ANSI standard. +// +// Since we are using the ANSI standard we used the standard nameing and +// did not folow the coding convention +// +// VA_LIST - typedef for argument list. +// VA_START (VA_LIST Marker, argument before the ...) - Init Marker for use. +// VA_END (VA_LIST Marker) - Clear Marker +// VA_ARG (VA_LIST Marker, var arg size) - Use Marker to get an argumnet from +// the ... list. You must know the size and pass it in this macro. +// +// example: +// +// UINTN +// ExampleVarArg ( +// IN UINTN NumberOfArgs, +// ... +// ) +// { +// VA_LIST Marker; +// UINTN Index; +// UINTN Result; +// +// // +// // Initialize the Marker +// // +// VA_START (Marker, NumberOfArgs); +// for (Index = 0, Result = 0; Index < NumberOfArgs; Index++) { +// // +// // The ... list is a series of UINTN values, so average them up. +// // +// Result += VA_ARG (Marker, UINTN); +// } +// +// VA_END (Marker); +// return Result +// } +// + +#define _INT_SIZE_OF(n) ((sizeof (n) + sizeof (UINTN) - 1) &~(sizeof (UINTN) - 1)) + +// +// Also support coding convention rules for var arg macros +// +typedef CHAR8 *VA_LIST; +#define VA_START(ap, v) (ap = (VA_LIST) & (v) + _INT_SIZE_OF (v)) +#define VA_ARG(ap, t) (*(t *) ((ap += _INT_SIZE_OF (t)) - _INT_SIZE_OF (t))) +#define VA_END(ap) (ap = (VA_LIST) 0) + +// +// Macro that returns the byte offset of a field in a data structure. +// +#define OFFSET_OF(TYPE, Field) ((UINTN) &(((TYPE *)0)->Field)) + +/// +/// CONTAINING_RECORD - returns a pointer to the structure +/// from one of it's elements. +/// +#define _CR(Record, TYPE, Field) ((TYPE *) ((CHAR8 *) (Record) - (CHAR8 *) &(((TYPE *) 0)->Field))) + +/// +/// ALIGN_VALUE - aligns a value up to the next boundary of the given alignment. +/// +#define ALIGN_VALUE(Value, Alignment) ((Value) + (((Alignment) - (Value)) & ((Alignment) - 1))) + +/// +/// ALIGN_POINTER - aligns a pointer to the lowest boundry +/// +#define ALIGN_POINTER(Pointer, Alignment) ((VOID *) (ALIGN_VALUE ((UINTN)(Pointer), (Alignment)))) + +/// +/// ALIGN_VARIABLE - aligns a variable up to the next natural boundry for int size of a processor +/// +#define ALIGN_VARIABLE(Value) ALIGN_VALUE ((Value), sizeof (UINTN)) + + +// +// Return the maximum of two operands. +// This macro returns the maximum of two operand specified by a and b. +// Both a and b must be the same numerical types, signed or unsigned. +// +#define MAX(a, b) \ + (((a) > (b)) ? (a) : (b)) + + +// +// Return the minimum of two operands. +// This macro returns the minimal of two operand specified by a and b. +// Both a and b must be the same numerical types, signed or unsigned. +// +#define MIN(a, b) \ + (((a) < (b)) ? (a) : (b)) + + +// +// EFI Error Codes common to all execution phases +// + +typedef INTN RETURN_STATUS; + +/// +/// Set the upper bit to indicate EFI Error. +/// +#define ENCODE_ERROR(a) (MAX_BIT | (a)) + +#define ENCODE_WARNING(a) (a) +#define RETURN_ERROR(a) ((INTN) (a) < 0) + +#define RETURN_SUCCESS 0 +#define RETURN_LOAD_ERROR ENCODE_ERROR (1) +#define RETURN_INVALID_PARAMETER ENCODE_ERROR (2) +#define RETURN_UNSUPPORTED ENCODE_ERROR (3) +#define RETURN_BAD_BUFFER_SIZE ENCODE_ERROR (4) +#define RETURN_BUFFER_TOO_SMALL ENCODE_ERROR (5) +#define RETURN_NOT_READY ENCODE_ERROR (6) +#define RETURN_DEVICE_ERROR ENCODE_ERROR (7) +#define RETURN_WRITE_PROTECTED ENCODE_ERROR (8) +#define RETURN_OUT_OF_RESOURCES ENCODE_ERROR (9) +#define RETURN_VOLUME_CORRUPTED ENCODE_ERROR (10) +#define RETURN_VOLUME_FULL ENCODE_ERROR (11) +#define RETURN_NO_MEDIA ENCODE_ERROR (12) +#define RETURN_MEDIA_CHANGED ENCODE_ERROR (13) +#define RETURN_NOT_FOUND ENCODE_ERROR (14) +#define RETURN_ACCESS_DENIED ENCODE_ERROR (15) +#define RETURN_NO_RESPONSE ENCODE_ERROR (16) +#define RETURN_NO_MAPPING ENCODE_ERROR (17) +#define RETURN_TIMEOUT ENCODE_ERROR (18) +#define RETURN_NOT_STARTED ENCODE_ERROR (19) +#define RETURN_ALREADY_STARTED ENCODE_ERROR (20) +#define RETURN_ABORTED ENCODE_ERROR (21) +#define RETURN_ICMP_ERROR ENCODE_ERROR (22) +#define RETURN_TFTP_ERROR ENCODE_ERROR (23) +#define RETURN_PROTOCOL_ERROR ENCODE_ERROR (24) +#define RETURN_INCOMPATIBLE_VERSION ENCODE_ERROR (25) +#define RETURN_SECURITY_VIOLATION ENCODE_ERROR (26) +#define RETURN_CRC_ERROR ENCODE_ERROR (27) +#define RETURN_END_OF_MEDIA ENCODE_ERROR (28) +#define RETURN_END_OF_FILE ENCODE_ERROR (31) +#define RETURN_INVALID_LANGUAGE ENCODE_ERROR (32) + + +#define RETURN_WARN_UNKNOWN_GLYPH ENCODE_WARNING (1) +#define RETURN_WARN_DELETE_FAILURE ENCODE_WARNING (2) +#define RETURN_WARN_WRITE_FAILURE ENCODE_WARNING (3) +#define RETURN_WARN_BUFFER_TOO_SMALL ENCODE_WARNING (4) + +/** + Returns a 16-bit signature built from 2 ASCII characters. + + @param A The first ASCII character. + @param B The second ASCII character. + + @return A 16-bit value built from the two ASCII characters specified by A and B. + +**/ +#define SIGNATURE_16(A, B) ((A) | (B << 8)) + +/** + Returns a 32-bit signature built from 4 ASCII characters. + + @param A The first ASCII character. + @param B The second ASCII character. + @param C The third ASCII character. + @param D The fourth ASCII character. + + @return A 32-bit value built from the two ASCII characters specified by A, B, + C and D. + +**/ +#define SIGNATURE_32(A, B, C, D) (SIGNATURE_16 (A, B) | (SIGNATURE_16 (C, D) << 16)) + +/** + Returns a 64-bit signature built from 8 ASCII characters. + + @param A The first ASCII character. + @param B The second ASCII character. + @param C The third ASCII character. + @param D The fourth ASCII character. + @param E The fifth ASCII character. + @param F The sixth ASCII character. + @param G The seventh ASCII character. + @param H The eighth ASCII character. + + @return A 64-bit value built from the two ASCII characters specified by A, B, + C, D, E, F, G and H. + +**/ +#define SIGNATURE_64(A, B, C, D, E, F, G, H) \ + (SIGNATURE_32 (A, B, C, D) | ((UINT64) (SIGNATURE_32 (E, F, G, H)) << 32)) + +#endif + diff --git a/gpxe/src/include/gpxe/efi/Guid/PcAnsi.h b/gpxe/src/include/gpxe/efi/Guid/PcAnsi.h new file mode 100644 index 00000000..1dab3109 --- /dev/null +++ b/gpxe/src/include/gpxe/efi/Guid/PcAnsi.h @@ -0,0 +1,58 @@ +/** @file + Terminal Device Path Vendor Guid. + + Copyright (c) 2006, Intel Corporation + All rights reserved. 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: + GUIDs defined in UEFI 2.0 spec. + +**/ + +#ifndef __PC_ANSI_H__ +#define __PC_ANSI_H__ + +#define EFI_PC_ANSI_GUID \ + { \ + 0xe0c14753, 0xf9be, 0x11d2, {0x9a, 0x0c, 0x00, 0x90, 0x27, 0x3f, 0xc1, 0x4d } \ + } + +#define EFI_VT_100_GUID \ + { \ + 0xdfa66065, 0xb419, 0x11d3, {0x9a, 0x2d, 0x00, 0x90, 0x27, 0x3f, 0xc1, 0x4d } \ + } + +#define EFI_VT_100_PLUS_GUID \ + { \ + 0x7baec70b, 0x57e0, 0x4c76, {0x8e, 0x87, 0x2f, 0x9e, 0x28, 0x08, 0x83, 0x43 } \ + } + +#define EFI_VT_UTF8_GUID \ + { \ + 0xad15a0d6, 0x8bec, 0x4acf, {0xa0, 0x73, 0xd0, 0x1d, 0xe7, 0x7e, 0x2d, 0x88 } \ + } + +#define EFI_UART_DEVICE_PATH_GUID \ + { \ + 0x37499a9d, 0x542f, 0x4c89, {0xa0, 0x26, 0x35, 0xda, 0x14, 0x20, 0x94, 0xe4 } \ + } + +#define EFI_SAS_DEVICE_PATH_GUID \ + { \ + 0xd487ddb4, 0x008b, 0x11d9, {0xaf, 0xdc, 0x00, 0x10, 0x83, 0xff, 0xca, 0x4d } \ + } + +extern EFI_GUID gEfiPcAnsiGuid; +extern EFI_GUID gEfiVT100Guid; +extern EFI_GUID gEfiVT100PlusGuid; +extern EFI_GUID gEfiVTUTF8Guid; +extern EFI_GUID gEfiUartDevicePathGuid; +extern EFI_GUID gEfiSasDevicePathGuid; + +#endif diff --git a/gpxe/src/include/gpxe/efi/Guid/SmBios.h b/gpxe/src/include/gpxe/efi/Guid/SmBios.h new file mode 100644 index 00000000..c6c7f776 --- /dev/null +++ b/gpxe/src/include/gpxe/efi/Guid/SmBios.h @@ -0,0 +1,34 @@ +/** @file + GUIDs used to locate the SMBIOS tables in the UEFI 2.0 system table. + + This GUID in the system table is the only legal way to search for and + locate the SMBIOS tables. Do not search the 0xF0000 segment to find SMBIOS + tables. + + Copyright (c) 2006, Intel Corporation + All rights reserved. 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: + GUIDs defined in UEFI 2.0 spec. + +**/ + +#ifndef __SMBIOS_GUID_H__ +#define __SMBIOS_GUID_H__ + +#define EFI_SMBIOS_TABLE_GUID \ + { \ + 0xeb9d2d31, 0x2d88, 0x11d3, {0x9a, 0x16, 0x0, 0x90, 0x27, 0x3f, 0xc1, 0x4d } \ + } + +#define SMBIOS_TABLE_GUID EFI_SMBIOS_TABLE_GUID + +extern EFI_GUID gEfiSmbiosTableGuid; + +#endif diff --git a/gpxe/src/include/gpxe/efi/Ia32/ProcessorBind.h b/gpxe/src/include/gpxe/efi/Ia32/ProcessorBind.h new file mode 100644 index 00000000..5a3a9182 --- /dev/null +++ b/gpxe/src/include/gpxe/efi/Ia32/ProcessorBind.h @@ -0,0 +1,215 @@ +/** @file + Processor or Compiler specific defines and types for Ia32 architecture. + + Copyright (c) 2006, Intel Corporation + All rights reserved. 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 __PROCESSOR_BIND_H__ +#define __PROCESSOR_BIND_H__ + +/// +/// Define the processor type so other code can make processor based choices +/// +#define MDE_CPU_IA32 + +// +// Make sure we are useing the correct packing rules per EFI specification +// +#ifndef __GNUC__ +#pragma pack() +#endif + +#if __INTEL_COMPILER +// +// Disable ICC's remark #869: "Parameter" was never referenced warning. +// This is legal ANSI C code so we disable the remark that is turned on with -Wall +// +#pragma warning ( disable : 869 ) + +// +// Disable ICC's remark #1418: external function definition with no prior declaration. +// This is legal ANSI C code so we disable the remark that is turned on with /W4 +// +#pragma warning ( disable : 1418 ) + +// +// Disable ICC's remark #1419: external declaration in primary source file +// This is legal ANSI C code so we disable the remark that is turned on with /W4 +// +#pragma warning ( disable : 1419 ) + +#endif + + +#if _MSC_EXTENSIONS + +// +// Disable warning that make it impossible to compile at /W4 +// This only works for Microsoft* tools +// + +// +// Disabling bitfield type checking warnings. +// +#pragma warning ( disable : 4214 ) + +// +// Disabling the unreferenced formal parameter warnings. +// +#pragma warning ( disable : 4100 ) + +// +// Disable slightly different base types warning as CHAR8 * can not be set +// to a constant string. +// +#pragma warning ( disable : 4057 ) + +// +// ASSERT(FALSE) or while (TRUE) are legal constructes so supress this warning +// +#pragma warning ( disable : 4127 ) + +// +// This warning is caused by functions defined but not used. For precompiled header only. +// +#pragma warning ( disable : 4505 ) + +// +// This warning is caused by empty (after preprocessing) souce file. For precompiled header only. +// +#pragma warning ( disable : 4206 ) + +#endif + + +#if !defined(__GNUC__) && (__STDC_VERSION__ < 199901L) + // + // No ANSI C 2000 stdint.h integer width declarations, so define equivalents + // + + #if _MSC_EXTENSIONS + + // + // use Microsoft* C complier dependent interger width types + // + typedef unsigned __int64 UINT64; + typedef __int64 INT64; + typedef unsigned __int32 UINT32; + typedef __int32 INT32; + typedef unsigned short UINT16; + typedef unsigned short CHAR16; + typedef short INT16; + typedef unsigned char BOOLEAN; + typedef unsigned char UINT8; + typedef char CHAR8; + typedef char INT8; + #else + + // + // Assume standard IA-32 alignment. + // Need to check portability of long long + // + typedef unsigned long long UINT64; + typedef long long INT64; + typedef unsigned int UINT32; + typedef int INT32; + typedef unsigned short UINT16; + typedef unsigned short CHAR16; + typedef short INT16; + typedef unsigned char BOOLEAN; + typedef unsigned char UINT8; + typedef char CHAR8; + typedef char INT8; + #endif + + #define UINT8_MAX 0xff + +#else + // + // Use ANSI C 2000 stdint.h integer width declarations + // + #include "stdint.h" + typedef uint8_t BOOLEAN; + typedef int8_t INT8; + typedef uint8_t UINT8; + typedef int16_t INT16; + typedef uint16_t UINT16; + typedef int32_t INT32; + typedef uint32_t UINT32; + typedef int64_t INT64; + typedef uint64_t UINT64; + typedef char CHAR8; + typedef uint16_t CHAR16; + +#endif + +typedef UINT32 UINTN; +typedef INT32 INTN; + + +/// +/// Processor specific defines +/// +#define MAX_BIT 0x80000000 +#define MAX_2_BITS 0xC0000000 + +/// +/// Maximum legal IA-32 address +/// +#define MAX_ADDRESS 0xFFFFFFFF + +/// +/// The stack alignment required for IA-32 +/// +#define CPU_STACK_ALIGNMENT sizeof(UINTN) + +// +// Modifier to ensure that all protocol member functions and EFI intrinsics +// use the correct C calling convention. All protocol member functions and +// EFI intrinsics are required to modify thier member functions with EFIAPI. +// +#if _MSC_EXTENSIONS + /// + /// Microsoft* compiler requires _EFIAPI useage, __cdecl is Microsoft* specific C. + /// + #define EFIAPI __cdecl +#else + #if __GNUC__ + #define EFIAPI __attribute__((cdecl,regparm(0))) + #endif +#endif + +// +// The Microsoft* C compiler can removed references to unreferenced data items +// if the /OPT:REF linker option is used. We defined a macro as this is a +// a non standard extension +// +#if _MSC_EXTENSIONS + #define GLOBAL_REMOVE_IF_UNREFERENCED __declspec(selectany) +#else + #define GLOBAL_REMOVE_IF_UNREFERENCED +#endif + +// +// For symbol name in GNU assembly code, an extra "_" is necessary +// +#if __GNUC__ + #if defined(linux) + #define ASM_PFX(name) name + #else + #define ASM_PFX(name) _##name + #endif +#endif + +#define FUNCTION_ENTRY_POINT(p) (p) + +#endif + diff --git a/gpxe/src/include/gpxe/efi/IndustryStandard/Pci22.h b/gpxe/src/include/gpxe/efi/IndustryStandard/Pci22.h new file mode 100644 index 00000000..5b96a56d --- /dev/null +++ b/gpxe/src/include/gpxe/efi/IndustryStandard/Pci22.h @@ -0,0 +1,601 @@ +/** @file + Support for PCI 2.2 standard. + + This file includes the definitions in the following specifications, + PCI Local Bus Specification, 2.0 + PCI-to-PCI Bridge Architecture Specification, + PC Card Standard, 8.0 + + Copyright (c) 2006 - 2008, Intel Corporation + All rights reserved. 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 _PCI22_H_ +#define _PCI22_H_ + +#define PCI_MAX_SEGMENT 0 +#define PCI_MAX_BUS 255 +#define PCI_MAX_DEVICE 31 +#define PCI_MAX_FUNC 7 + + +#pragma pack(1) +typedef struct { + UINT16 VendorId; + UINT16 DeviceId; + UINT16 Command; + UINT16 Status; + UINT8 RevisionID; + UINT8 ClassCode[3]; + UINT8 CacheLineSize; + UINT8 LatencyTimer; + UINT8 HeaderType; + UINT8 BIST; +} PCI_DEVICE_INDEPENDENT_REGION; + +typedef struct { + UINT32 Bar[6]; + UINT32 CISPtr; + UINT16 SubsystemVendorID; + UINT16 SubsystemID; + UINT32 ExpansionRomBar; + UINT8 CapabilityPtr; + UINT8 Reserved1[3]; + UINT32 Reserved2; + UINT8 InterruptLine; + UINT8 InterruptPin; + UINT8 MinGnt; + UINT8 MaxLat; +} PCI_DEVICE_HEADER_TYPE_REGION; + +typedef struct { + PCI_DEVICE_INDEPENDENT_REGION Hdr; + PCI_DEVICE_HEADER_TYPE_REGION Device; +} PCI_TYPE00; + +/// +/// defined in PCI-to-PCI Bridge Architecture Specification +/// +typedef struct { + UINT32 Bar[2]; + UINT8 PrimaryBus; + UINT8 SecondaryBus; + UINT8 SubordinateBus; + UINT8 SecondaryLatencyTimer; + UINT8 IoBase; + UINT8 IoLimit; + UINT16 SecondaryStatus; + UINT16 MemoryBase; + UINT16 MemoryLimit; + UINT16 PrefetchableMemoryBase; + UINT16 PrefetchableMemoryLimit; + UINT32 PrefetchableBaseUpper32; + UINT32 PrefetchableLimitUpper32; + UINT16 IoBaseUpper16; + UINT16 IoLimitUpper16; + UINT8 CapabilityPtr; + UINT8 Reserved[3]; + UINT32 ExpansionRomBAR; + UINT8 InterruptLine; + UINT8 InterruptPin; + UINT16 BridgeControl; +} PCI_BRIDGE_CONTROL_REGISTER; + +typedef struct { + PCI_DEVICE_INDEPENDENT_REGION Hdr; + PCI_BRIDGE_CONTROL_REGISTER Bridge; +} PCI_TYPE01; + +typedef union { + PCI_TYPE00 Device; + PCI_TYPE01 Bridge; +} PCI_TYPE_GENERIC; + +/// +/// CardBus Conroller Configuration Space, defined in PC Card Standard. 8.0 +/// +typedef struct { + UINT32 CardBusSocketReg; ///< Cardus Socket/ExCA Base + UINT8 Cap_Ptr; + UINT8 Reserved; + UINT16 SecondaryStatus; ///< Secondary Status + UINT8 PciBusNumber; ///< PCI Bus Number + UINT8 CardBusBusNumber; ///< CardBus Bus Number + UINT8 SubordinateBusNumber; ///< Subordinate Bus Number + UINT8 CardBusLatencyTimer; ///< CardBus Latency Timer + UINT32 MemoryBase0; ///< Memory Base Register 0 + UINT32 MemoryLimit0; ///< Memory Limit Register 0 + UINT32 MemoryBase1; + UINT32 MemoryLimit1; + UINT32 IoBase0; + UINT32 IoLimit0; ///< I/O Base Register 0 + UINT32 IoBase1; ///< I/O Limit Register 0 + UINT32 IoLimit1; + UINT8 InterruptLine; ///< Interrupt Line + UINT8 InterruptPin; ///< Interrupt Pin + UINT16 BridgeControl; ///< Bridge Control +} PCI_CARDBUS_CONTROL_REGISTER; + +/// +/// Definitions of PCI class bytes and manipulation macros. +/// +#define PCI_CLASS_OLD 0x00 +#define PCI_CLASS_OLD_OTHER 0x00 +#define PCI_CLASS_OLD_VGA 0x01 + +#define PCI_CLASS_MASS_STORAGE 0x01 +#define PCI_CLASS_MASS_STORAGE_SCSI 0x00 +#define PCI_CLASS_MASS_STORAGE_IDE 0x01 +#define PCI_CLASS_MASS_STORAGE_FLOPPY 0x02 +#define PCI_CLASS_MASS_STORAGE_IPI 0x03 +#define PCI_CLASS_MASS_STORAGE_RAID 0x04 +#define PCI_CLASS_MASS_STORAGE_OTHER 0x80 + +#define PCI_CLASS_NETWORK 0x02 +#define PCI_CLASS_NETWORK_ETHERNET 0x00 +#define PCI_CLASS_NETWORK_TOKENRING 0x01 +#define PCI_CLASS_NETWORK_FDDI 0x02 +#define PCI_CLASS_NETWORK_ATM 0x03 +#define PCI_CLASS_NETWORK_ISDN 0x04 +#define PCI_CLASS_NETWORK_OTHER 0x80 + +#define PCI_CLASS_DISPLAY 0x03 +#define PCI_CLASS_DISPLAY_VGA 0x00 +#define PCI_IF_VGA_VGA 0x00 +#define PCI_IF_VGA_8514 0x01 +#define PCI_CLASS_DISPLAY_XGA 0x01 +#define PCI_CLASS_DISPLAY_3D 0x02 +#define PCI_CLASS_DISPLAY_OTHER 0x80 +#define PCI_CLASS_DISPLAY_GFX 0x80 + +#define PCI_CLASS_MEDIA 0x04 +#define PCI_CLASS_MEDIA_VIDEO 0x00 +#define PCI_CLASS_MEDIA_AUDIO 0x01 +#define PCI_CLASS_MEDIA_TELEPHONE 0x02 +#define PCI_CLASS_MEDIA_OTHER 0x80 + +#define PCI_CLASS_MEMORY_CONTROLLER 0x05 +#define PCI_CLASS_MEMORY_RAM 0x00 +#define PCI_CLASS_MEMORY_FLASH 0x01 +#define PCI_CLASS_MEMORY_OTHER 0x80 + +#define PCI_CLASS_BRIDGE 0x06 +#define PCI_CLASS_BRIDGE_HOST 0x00 +#define PCI_CLASS_BRIDGE_ISA 0x01 +#define PCI_CLASS_BRIDGE_EISA 0x02 +#define PCI_CLASS_BRIDGE_MCA 0x03 +#define PCI_CLASS_BRIDGE_P2P 0x04 +#define PCI_IF_BRIDGE_P2P 0x00 +#define PCI_IF_BRIDGE_P2P_SUBTRACTIVE 0x01 +#define PCI_CLASS_BRIDGE_PCMCIA 0x05 +#define PCI_CLASS_BRIDGE_NUBUS 0x06 +#define PCI_CLASS_BRIDGE_CARDBUS 0x07 +#define PCI_CLASS_BRIDGE_RACEWAY 0x08 +#define PCI_CLASS_BRIDGE_OTHER 0x80 +#define PCI_CLASS_BRIDGE_ISA_PDECODE 0x80 + +#define PCI_CLASS_SCC 0x07 ///< Simple communications controllers +#define PCI_SUBCLASS_SERIAL 0x00 +#define PCI_IF_GENERIC_XT 0x00 +#define PCI_IF_16450 0x01 +#define PCI_IF_16550 0x02 +#define PCI_IF_16650 0x03 +#define PCI_IF_16750 0x04 +#define PCI_IF_16850 0x05 +#define PCI_IF_16950 0x06 +#define PCI_SUBCLASS_PARALLEL 0x01 +#define PCI_IF_PARALLEL_PORT 0x00 +#define PCI_IF_BI_DIR_PARALLEL_PORT 0x01 +#define PCI_IF_ECP_PARALLEL_PORT 0x02 +#define PCI_IF_1284_CONTROLLER 0x03 +#define PCI_IF_1284_DEVICE 0xFE +#define PCI_SUBCLASS_MULTIPORT_SERIAL 0x02 +#define PCI_SUBCLASS_MODEM 0x03 +#define PCI_IF_GENERIC_MODEM 0x00 +#define PCI_IF_16450_MODEM 0x01 +#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_CLASS_SYSTEM_PERIPHERAL 0x08 +#define PCI_SUBCLASS_PIC 0x00 +#define PCI_IF_8259_PIC 0x00 +#define PCI_IF_ISA_PIC 0x01 +#define PCI_IF_EISA_PIC 0x02 +#define PCI_IF_APIC_CONTROLLER 0x10 ///< I/O APIC interrupt controller , 32 bye none-prefectable memory. +#define PCI_IF_APIC_CONTROLLER2 0x20 +#define PCI_SUBCLASS_DMA 0x01 +#define PCI_IF_8237_DMA 0x00 +#define PCI_IF_ISA_DMA 0x01 +#define PCI_IF_EISA_DMA 0x02 +#define PCI_SUBCLASS_TIMER 0x02 +#define PCI_IF_8254_TIMER 0x00 +#define PCI_IF_ISA_TIMER 0x01 +#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_SUBCLASS_PNP_CONTROLLER 0x04 ///< HotPlug Controller +#define PCI_SUBCLASS_PERIPHERAL_OTHER 0x80 + +#define PCI_CLASS_INPUT_DEVICE 0x09 +#define PCI_SUBCLASS_KEYBOARD 0x00 +#define PCI_SUBCLASS_PEN 0x01 +#define PCI_SUBCLASS_MOUSE_CONTROLLER 0x02 +#define PCI_SUBCLASS_SCAN_CONTROLLER 0x03 +#define PCI_SUBCLASS_GAMEPORT 0x04 +#define PCI_IF_GAMEPORT 0x00 +#define PCI_IF_GAMEPORT1 0x01 +#define PCI_SUBCLASS_INPUT_OTHER 0x80 + +#define PCI_CLASS_DOCKING_STATION 0x0A + +#define PCI_CLASS_PROCESSOR 0x0B +#define PCI_SUBCLASS_PROC_386 0x00 +#define PCI_SUBCLASS_PROC_486 0x01 +#define PCI_SUBCLASS_PROC_PENTIUM 0x02 +#define PCI_SUBCLASS_PROC_ALPHA 0x10 +#define PCI_SUBCLASS_PROC_POWERPC 0x20 +#define PCI_SUBCLASS_PROC_MIPS 0x30 +#define PCI_SUBCLASS_PROC_CO_PORC 0x40 ///< Co-Processor + +#define PCI_CLASS_SERIAL 0x0C +#define PCI_CLASS_SERIAL_FIREWIRE 0x00 +#define PCI_IF_1394 0x00 +#define PCI_IF_1394_OPEN_HCI 0x10 +#define PCI_CLASS_SERIAL_ACCESS_BUS 0x01 +#define PCI_CLASS_SERIAL_SSA 0x02 +#define PCI_CLASS_SERIAL_USB 0x03 +#define PCI_IF_UHCI 0x00 +#define PCI_IF_OHCI 0x10 +#define PCI_IF_USB_OTHER 0x80 +#define PCI_IF_USB_DEVICE 0xFE +#define PCI_CLASS_SERIAL_FIBRECHANNEL 0x04 +#define PCI_CLASS_SERIAL_SMB 0x05 + +#define PCI_CLASS_WIRELESS 0x0D +#define PCI_SUBCLASS_IRDA 0x00 +#define PCI_SUBCLASS_IR 0x01 +#define PCI_SUBCLASS_RF 0x02 +#define PCI_SUBCLASS_WIRELESS_OTHER 0x80 + +#define PCI_CLASS_INTELLIGENT_IO 0x0E + +#define PCI_CLASS_SATELLITE 0x0F +#define PCI_SUBCLASS_TV 0x01 +#define PCI_SUBCLASS_AUDIO 0x02 +#define PCI_SUBCLASS_VOICE 0x03 +#define PCI_SUBCLASS_DATA 0x04 + +#define PCI_SECURITY_CONTROLLER 0x10 ///< Encryption and decryption controller +#define PCI_SUBCLASS_NET_COMPUT 0x00 +#define PCI_SUBCLASS_ENTERTAINMENT 0x10 +#define PCI_SUBCLASS_SECURITY_OTHER 0x80 + +#define PCI_CLASS_DPIO 0x11 +#define PCI_SUBCLASS_DPIO 0x00 +#define PCI_SUBCLASS_DPIO_OTHER 0x80 + +#define IS_CLASS1(_p, c) ((_p)->Hdr.ClassCode[2] == (c)) +#define IS_CLASS2(_p, c, s) (IS_CLASS1 (_p, c) && ((_p)->Hdr.ClassCode[1] == (s))) +#define IS_CLASS3(_p, c, s, p) (IS_CLASS2 (_p, c, s) && ((_p)->Hdr.ClassCode[0] == (p))) + +#define IS_PCI_DISPLAY(_p) IS_CLASS1 (_p, PCI_CLASS_DISPLAY) +#define IS_PCI_VGA(_p) IS_CLASS3 (_p, PCI_CLASS_DISPLAY, PCI_CLASS_DISPLAY_VGA, 0) +#define IS_PCI_8514(_p) IS_CLASS3 (_p, PCI_CLASS_DISPLAY, PCI_CLASS_DISPLAY_VGA, 1) +#define IS_PCI_GFX(_p) IS_CLASS3 (_p, PCI_CLASS_DISPLAY, PCI_CLASS_DISPLAY_GFX, 0) +#define IS_PCI_OLD(_p) IS_CLASS1 (_p, PCI_CLASS_OLD) +#define IS_PCI_OLD_VGA(_p) IS_CLASS2 (_p, PCI_CLASS_OLD, PCI_CLASS_OLD_VGA) +#define IS_PCI_IDE(_p) IS_CLASS2 (_p, PCI_CLASS_MASS_STORAGE, PCI_CLASS_MASS_STORAGE_IDE) +#define IS_PCI_SCSI(_p) IS_CLASS3 (_p, PCI_CLASS_MASS_STORAGE, PCI_CLASS_MASS_STORAGE_SCSI, 0) +#define IS_PCI_RAID(_p) IS_CLASS3 (_p, PCI_CLASS_MASS_STORAGE, PCI_CLASS_MASS_STORAGE_RAID, 0) +#define IS_PCI_LPC(_p) IS_CLASS3 (_p, PCI_CLASS_BRIDGE, PCI_CLASS_BRIDGE_ISA, 0) +#define IS_PCI_P2P(_p) IS_CLASS3 (_p, PCI_CLASS_BRIDGE, PCI_CLASS_BRIDGE_P2P, 0) +#define IS_PCI_P2P_SUB(_p) IS_CLASS3 (_p, PCI_CLASS_BRIDGE, PCI_CLASS_BRIDGE_P2P, 1) +#define IS_PCI_16550_SERIAL(_p) IS_CLASS3 (_p, PCI_CLASS_SCC, PCI_SUBCLASS_SERIAL, PCI_IF_16550) +#define IS_PCI_USB(_p) IS_CLASS2 (_p, PCI_CLASS_SERIAL, PCI_CLASS_SERIAL_USB) + +// +// the definition of Header Type +// +#define HEADER_TYPE_DEVICE 0x00 +#define HEADER_TYPE_PCI_TO_PCI_BRIDGE 0x01 +#define HEADER_TYPE_CARDBUS_BRIDGE 0x02 +#define HEADER_TYPE_MULTI_FUNCTION 0x80 +// +// Mask of Header type +// +#define HEADER_LAYOUT_CODE 0x7f + +#define IS_PCI_BRIDGE(_p) (((_p)->Hdr.HeaderType & HEADER_LAYOUT_CODE) == (HEADER_TYPE_PCI_TO_PCI_BRIDGE)) +#define IS_CARDBUS_BRIDGE(_p) (((_p)->Hdr.HeaderType & HEADER_LAYOUT_CODE) == (HEADER_TYPE_CARDBUS_BRIDGE)) +#define IS_PCI_MULTI_FUNC(_p) ((_p)->Hdr.HeaderType & HEADER_TYPE_MULTI_FUNCTION) + +/// +/// Rom Base Address in Bridge, defined in PCI-to-PCI Bridge Architecure Specification, +/// +#define PCI_BRIDGE_ROMBAR 0x38 + +#define PCI_MAX_BAR 0x0006 +#define PCI_MAX_CONFIG_OFFSET 0x0100 + +#define PCI_VENDOR_ID_OFFSET 0x00 +#define PCI_DEVICE_ID_OFFSET 0x02 +#define PCI_COMMAND_OFFSET 0x04 +#define PCI_PRIMARY_STATUS_OFFSET 0x06 +#define PCI_REVISION_ID_OFFSET 0x08 +#define PCI_CLASSCODE_OFFSET 0x09 +#define PCI_CACHELINE_SIZE_OFFSET 0x0C +#define PCI_LATENCY_TIMER_OFFSET 0x0D +#define PCI_HEADER_TYPE_OFFSET 0x0E +#define PCI_BIST_OFFSET 0x0F +#define PCI_BASE_ADDRESSREG_OFFSET 0x10 +#define PCI_CARDBUS_CIS_OFFSET 0x28 +#define PCI_SVID_OFFSET 0x2C ///< SubSystem Vendor id +#define PCI_SUBSYSTEM_VENDOR_ID_OFFSET 0x2C +#define PCI_SID_OFFSET 0x2E ///< SubSystem ID +#define PCI_SUBSYSTEM_ID_OFFSET 0x2E +#define PCI_EXPANSION_ROM_BASE 0x30 +#define PCI_CAPBILITY_POINTER_OFFSET 0x34 +#define PCI_INT_LINE_OFFSET 0x3C ///< Interrupt Line Register +#define PCI_INT_PIN_OFFSET 0x3D ///< Interrupt Pin Register +#define PCI_MAXGNT_OFFSET 0x3E ///< Max Grant Register +#define PCI_MAXLAT_OFFSET 0x3F ///< Max Latency Register + +/// +/// defined in PCI-to-PCI Bridge Architecture Specification +/// +#define PCI_BRIDGE_PRIMARY_BUS_REGISTER_OFFSET 0x18 +#define PCI_BRIDGE_SECONDARY_BUS_REGISTER_OFFSET 0x19 +#define PCI_BRIDGE_SUBORDINATE_BUS_REGISTER_OFFSET 0x1a +#define PCI_BRIDGE_STATUS_REGISTER_OFFSET 0x1E +#define PCI_BRIDGE_CONTROL_REGISTER_OFFSET 0x3E + +/// +/// Interrupt Line "Unknown" or "No connection" value defined for x86 based system +/// +#define PCI_INT_LINE_UNKNOWN 0xFF + +typedef union { + struct { + UINT32 Reg : 8; + UINT32 Func : 3; + UINT32 Dev : 5; + UINT32 Bus : 8; + UINT32 Reserved : 7; + UINT32 Enable : 1; + } Bits; + UINT32 Uint32; +} PCI_CONFIG_ACCESS_CF8; + +#pragma pack() + +#define EFI_PCI_COMMAND_IO_SPACE BIT0 ///< 0x0001 +#define EFI_PCI_COMMAND_MEMORY_SPACE BIT1 ///< 0x0002 +#define EFI_PCI_COMMAND_BUS_MASTER BIT2 ///< 0x0004 +#define EFI_PCI_COMMAND_SPECIAL_CYCLE BIT3 ///< 0x0008 +#define EFI_PCI_COMMAND_MEMORY_WRITE_AND_INVALIDATE BIT4 ///< 0x0010 +#define EFI_PCI_COMMAND_VGA_PALETTE_SNOOP BIT5 ///< 0x0020 +#define EFI_PCI_COMMAND_PARITY_ERROR_RESPOND BIT6 ///< 0x0040 +#define EFI_PCI_COMMAND_STEPPING_CONTROL BIT7 ///< 0x0080 +#define EFI_PCI_COMMAND_SERR BIT8 ///< 0x0100 +#define EFI_PCI_COMMAND_FAST_BACK_TO_BACK BIT9 ///< 0x0200 + +/// +/// defined in PCI-to-PCI Bridge Architecture Specification +/// +#define EFI_PCI_BRIDGE_CONTROL_PARITY_ERROR_RESPONSE BIT0 ///< 0x0001 +#define EFI_PCI_BRIDGE_CONTROL_SERR BIT1 ///< 0x0002 +#define EFI_PCI_BRIDGE_CONTROL_ISA BIT2 ///< 0x0004 +#define EFI_PCI_BRIDGE_CONTROL_VGA BIT3 ///< 0x0008 +#define EFI_PCI_BRIDGE_CONTROL_VGA_16 BIT4 ///< 0x0010 +#define EFI_PCI_BRIDGE_CONTROL_MASTER_ABORT BIT5 ///< 0x0020 +#define EFI_PCI_BRIDGE_CONTROL_RESET_SECONDARY_BUS BIT6 ///< 0x0040 +#define EFI_PCI_BRIDGE_CONTROL_FAST_BACK_TO_BACK BIT7 ///< 0x0080 +#define EFI_PCI_BRIDGE_CONTROL_PRIMARY_DISCARD_TIMER BIT8 ///< 0x0100 +#define EFI_PCI_BRIDGE_CONTROL_SECONDARY_DISCARD_TIMER BIT9 ///< 0x0200 +#define EFI_PCI_BRIDGE_CONTROL_TIMER_STATUS BIT10 ///< 0x0400 +#define EFI_PCI_BRIDGE_CONTROL_DISCARD_TIMER_SERR BIT11 ///< 0x0800 + +/// +/// Following are the PCI-CARDBUS bridge control bit, defined in PC Card Standard +/// +#define EFI_PCI_BRIDGE_CONTROL_IREQINT_ENABLE BIT7 ///< 0x0080 +#define EFI_PCI_BRIDGE_CONTROL_RANGE0_MEMORY_TYPE BIT8 ///< 0x0100 +#define EFI_PCI_BRIDGE_CONTROL_RANGE1_MEMORY_TYPE BIT9 ///< 0x0200 +#define EFI_PCI_BRIDGE_CONTROL_WRITE_POSTING_ENABLE BIT10 ///< 0x0400 + +// +// Following are the PCI status control bit +// +#define EFI_PCI_STATUS_CAPABILITY BIT4 ///< 0x0010 +#define EFI_PCI_STATUS_66MZ_CAPABLE BIT5 ///< 0x0020 +#define EFI_PCI_FAST_BACK_TO_BACK_CAPABLE BIT7 ///< 0x0080 +#define EFI_PCI_MASTER_DATA_PARITY_ERROR BIT8 ///< 0x0100 + +/// +/// defined in PC Card Standard +/// +#define EFI_PCI_CARDBUS_BRIDGE_CAPABILITY_PTR 0x14 + +#pragma pack(1) +// +// PCI Capability List IDs and records +// +#define EFI_PCI_CAPABILITY_ID_PMI 0x01 +#define EFI_PCI_CAPABILITY_ID_AGP 0x02 +#define EFI_PCI_CAPABILITY_ID_VPD 0x03 +#define EFI_PCI_CAPABILITY_ID_SLOTID 0x04 +#define EFI_PCI_CAPABILITY_ID_MSI 0x05 +#define EFI_PCI_CAPABILITY_ID_HOTPLUG 0x06 +typedef struct { + UINT8 CapabilityID; + UINT8 NextItemPtr; +} EFI_PCI_CAPABILITY_HDR; + +/// +/// Capability EFI_PCI_CAPABILITY_ID_PMI, defined in PCI Power Management Interface Specifiction +/// +typedef struct { + EFI_PCI_CAPABILITY_HDR Hdr; + UINT16 PMC; + UINT16 PMCSR; + UINT8 BridgeExtention; + UINT8 Data; +} EFI_PCI_CAPABILITY_PMI; + +/// +/// Capability EFI_PCI_CAPABILITY_ID_AGP, defined in Accelerated Graphics Port Interface Specification +/// +typedef struct { + EFI_PCI_CAPABILITY_HDR Hdr; + UINT8 Rev; + UINT8 Reserved; + UINT32 Status; + UINT32 Command; +} EFI_PCI_CAPABILITY_AGP; + +/// +/// Capability EFI_PCI_CAPABILITY_ID_VPD, in PCI2.2 Spec. +/// +typedef struct { + EFI_PCI_CAPABILITY_HDR Hdr; + UINT16 AddrReg; + UINT32 DataReg; +} EFI_PCI_CAPABILITY_VPD; + +/// +/// Capability EFI_PCI_CAPABILITY_ID_SLOTID, defined in PCI-to-PCI Bridge Architeture Specification +/// +typedef struct { + EFI_PCI_CAPABILITY_HDR Hdr; + UINT8 ExpnsSlotReg; + UINT8 ChassisNo; +} EFI_PCI_CAPABILITY_SLOTID; + +/// +/// Capability EFI_PCI_CAPABILITY_ID_MSI, defined in PCI2.2 +/// +typedef struct { + EFI_PCI_CAPABILITY_HDR Hdr; + UINT16 MsgCtrlReg; + UINT32 MsgAddrReg; + UINT16 MsgDataReg; +} EFI_PCI_CAPABILITY_MSI32; + +typedef struct { + EFI_PCI_CAPABILITY_HDR Hdr; + UINT16 MsgCtrlReg; + UINT32 MsgAddrRegLsdw; + UINT32 MsgAddrRegMsdw; + UINT16 MsgDataReg; +} EFI_PCI_CAPABILITY_MSI64; + +/// +/// Capability EFI_PCI_CAPABILITY_ID_HOTPLUG, defined in CompactPCI Hot Swap Specification PICMG 2.1, R1.0 +/// +typedef struct { + EFI_PCI_CAPABILITY_HDR Hdr; + /// + /// not finished - fields need to go here + /// +} EFI_PCI_CAPABILITY_HOTPLUG; + +#define DEVICE_ID_NOCARE 0xFFFF + +#define PCI_ACPI_UNUSED 0 +#define PCI_BAR_NOCHANGE 0 +#define PCI_BAR_OLD_ALIGN 0xFFFFFFFFFFFFFFFFULL +#define PCI_BAR_EVEN_ALIGN 0xFFFFFFFFFFFFFFFEULL +#define PCI_BAR_SQUAD_ALIGN 0xFFFFFFFFFFFFFFFDULL +#define PCI_BAR_DQUAD_ALIGN 0xFFFFFFFFFFFFFFFCULL + +#define PCI_BAR_IDX0 0x00 +#define PCI_BAR_IDX1 0x01 +#define PCI_BAR_IDX2 0x02 +#define PCI_BAR_IDX3 0x03 +#define PCI_BAR_IDX4 0x04 +#define PCI_BAR_IDX5 0x05 +#define PCI_BAR_ALL 0xFF + +/// +/// EFI PCI Option ROM definitions +/// +#define EFI_ROOT_BRIDGE_LIST 'eprb' +#define EFI_PCI_EXPANSION_ROM_HEADER_EFISIGNATURE 0x0EF1 ///< defined in UEFI Spec. + +typedef struct { + UINT8 Register; + UINT8 Function; + UINT8 Device; + UINT8 Bus; + UINT8 Reserved[4]; +} DEFIO_PCI_ADDR; + +#define PCI_EXPANSION_ROM_HEADER_SIGNATURE 0xaa55 +#define PCI_DATA_STRUCTURE_SIGNATURE SIGNATURE_32 ('P', 'C', 'I', 'R') +#define PCI_CODE_TYPE_PCAT_IMAGE 0x00 +#define EFI_PCI_EXPANSION_ROM_HEADER_COMPRESSED 0x0001 ///<defined in UEFI spec. + +typedef struct { + UINT16 Signature; ///< 0xaa55 + UINT8 Reserved[0x16]; + UINT16 PcirOffset; +} PCI_EXPANSION_ROM_HEADER; + +typedef struct { + UINT16 Signature; ///< 0xaa55 + UINT8 Size512; + UINT8 InitEntryPoint[3]; + UINT8 Reserved[0x12]; + UINT16 PcirOffset; +} EFI_LEGACY_EXPANSION_ROM_HEADER; + +typedef struct { + UINT32 Signature; ///< "PCIR" + UINT16 VendorId; + UINT16 DeviceId; + UINT16 Reserved0; + UINT16 Length; + UINT8 Revision; + UINT8 ClassCode[3]; + UINT16 ImageLength; + UINT16 CodeRevision; + UINT8 CodeType; + UINT8 Indicator; + UINT16 Reserved1; +} PCI_DATA_STRUCTURE; + +/// +/// defined in EFI/UEFI Spec +/// +typedef struct { + UINT16 Signature; ///< 0xaa55 + UINT16 InitializationSize; + UINT32 EfiSignature; ///< 0x0EF1 + UINT16 EfiSubsystem; + UINT16 EfiMachineType; + UINT16 CompressionType; + UINT8 Reserved[8]; + UINT16 EfiImageHeaderOffset; + UINT16 PcirOffset; +} EFI_PCI_EXPANSION_ROM_HEADER; + +typedef union { + UINT8 *Raw; + PCI_EXPANSION_ROM_HEADER *Generic; + EFI_PCI_EXPANSION_ROM_HEADER *Efi; + EFI_LEGACY_EXPANSION_ROM_HEADER *PcAt; +} EFI_PCI_ROM_HEADER; + +#pragma pack() + +#endif diff --git a/gpxe/src/include/gpxe/efi/IndustryStandard/PeImage.h b/gpxe/src/include/gpxe/efi/IndustryStandard/PeImage.h new file mode 100644 index 00000000..73b3a5ad --- /dev/null +++ b/gpxe/src/include/gpxe/efi/IndustryStandard/PeImage.h @@ -0,0 +1,752 @@ +/** @file + EFI image format for PE32, PE32+ and TE. Please note some data structures are + different for PE32 and PE32+. EFI_IMAGE_NT_HEADERS32 is for PE32 and + EFI_IMAGE_NT_HEADERS64 is for PE32+. + + This file is coded to the Visual Studio, Microsoft Portable Executable and + Common Object File Format Specification, Revision 8.0 - May 16, 2006. + This file also includes some definitions in PI Specification, Revision 1.0. + + Copyright (c) 2006 - 2008, Intel Corporation + All rights reserved. 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 __PE_IMAGE_H__ +#define __PE_IMAGE_H__ + +/// +/// PE32+ Subsystem type for EFI images +/// +#define EFI_IMAGE_SUBSYSTEM_EFI_APPLICATION 10 +#define EFI_IMAGE_SUBSYSTEM_EFI_BOOT_SERVICE_DRIVER 11 +#define EFI_IMAGE_SUBSYSTEM_EFI_RUNTIME_DRIVER 12 +#define EFI_IMAGE_SUBSYSTEM_EFI_EFI_ROM 13 + +#define EFI_IMAGE_SUBSYSTEM_SAL_RUNTIME_DRIVER 13 ///< defined PI Specification, 1.0 + + +/// +/// PE32+ Machine type for EFI images +/// +#define IMAGE_FILE_MACHINE_I386 0x014c +#define IMAGE_FILE_MACHINE_IA64 0x0200 +#define IMAGE_FILE_MACHINE_EBC 0x0EBC +#define IMAGE_FILE_MACHINE_X64 0x8664 +// +// Support old names for backward compatible +// +#define EFI_IMAGE_MACHINE_IA32 IMAGE_FILE_MACHINE_I386 +#define EFI_IMAGE_MACHINE_IA64 IMAGE_FILE_MACHINE_IA64 +#define EFI_IMAGE_MACHINE_IPF IMAGE_FILE_MACHINE_IA64 +#define EFI_IMAGE_MACHINE_EBC IMAGE_FILE_MACHINE_EBC +#define EFI_IMAGE_MACHINE_X64 IMAGE_FILE_MACHINE_X64 + +/// +/// EXE file formats +/// +#define EFI_IMAGE_DOS_SIGNATURE SIGNATURE_16('M', 'Z') +#define EFI_IMAGE_OS2_SIGNATURE SIGNATURE_16('N', 'E') +#define EFI_IMAGE_OS2_SIGNATURE_LE SIGNATURE_16('L', 'E') +#define EFI_IMAGE_NT_SIGNATURE SIGNATURE_32('P', 'E', '\0', '\0') + +/// +/// PE images can start with an optional DOS header, so if an image is run +/// under DOS it can print an error message. +/// +typedef struct { + UINT16 e_magic; ///< Magic number + UINT16 e_cblp; ///< Bytes on last page of file + UINT16 e_cp; ///< Pages in file + UINT16 e_crlc; ///< Relocations + UINT16 e_cparhdr; ///< Size of header in paragraphs + UINT16 e_minalloc; ///< Minimum extra paragraphs needed + UINT16 e_maxalloc; ///< Maximum extra paragraphs needed + UINT16 e_ss; ///< Initial (relative) SS value + UINT16 e_sp; ///< Initial SP value + UINT16 e_csum; ///< Checksum + UINT16 e_ip; ///< Initial IP value + UINT16 e_cs; ///< Initial (relative) CS value + UINT16 e_lfarlc; ///< File address of relocation table + UINT16 e_ovno; ///< Overlay number + UINT16 e_res[4]; ///< Reserved words + UINT16 e_oemid; ///< OEM identifier (for e_oeminfo) + UINT16 e_oeminfo; ///< OEM information; e_oemid specific + UINT16 e_res2[10]; ///< Reserved words + UINT32 e_lfanew; ///< File address of new exe header +} EFI_IMAGE_DOS_HEADER; + +/// +/// COFF File Header (Object and Image) +/// +typedef struct { + UINT16 Machine; + UINT16 NumberOfSections; + UINT32 TimeDateStamp; + UINT32 PointerToSymbolTable; + UINT32 NumberOfSymbols; + UINT16 SizeOfOptionalHeader; + UINT16 Characteristics; +} EFI_IMAGE_FILE_HEADER; + +/// +/// Size of EFI_IMAGE_FILE_HEADER +/// +#define EFI_IMAGE_SIZEOF_FILE_HEADER 20 + +/// +/// Characteristics +/// +#define EFI_IMAGE_FILE_RELOCS_STRIPPED BIT0 ///< 0x0001 Relocation info stripped from file. +#define EFI_IMAGE_FILE_EXECUTABLE_IMAGE BIT1 ///< 0x0002 File is executable (i.e. no unresolved externel references). +#define EFI_IMAGE_FILE_LINE_NUMS_STRIPPED BIT2 ///< 0x0004 Line nunbers stripped from file. +#define EFI_IMAGE_FILE_LOCAL_SYMS_STRIPPED BIT3 ///< 0x0008 Local symbols stripped from file. +#define EFI_IMAGE_FILE_BYTES_REVERSED_LO BIT7 ///< 0x0080 Bytes of machine word are reversed. +#define EFI_IMAGE_FILE_32BIT_MACHINE BIT8 ///< 0x0100 32 bit word machine. +#define EFI_IMAGE_FILE_DEBUG_STRIPPED BIT9 ///< 0x0200 Debugging info stripped from file in .DBG file +#define EFI_IMAGE_FILE_SYSTEM BIT12 ///< 0x1000 System File. +#define EFI_IMAGE_FILE_DLL BIT13 ///< 0x2000 File is a DLL. +#define EFI_IMAGE_FILE_BYTES_REVERSED_HI BIT15 ///< 0x8000 Bytes of machine word are reversed. + +/// +/// Other Machine Types +/// +#define EFI_IMAGE_FILE_MACHINE_UNKNOWN 0 ///< Any machine type +#define EFI_IMAGE_FILE_MACHINE_I386 0x14c ///< Intel 386. +#define EFI_IMAGE_FILE_MACHINE_R3000 0x162 ///< MIPS* little-endian, 0540 big-endian +#define EFI_IMAGE_FILE_MACHINE_R4000 0x166 ///< MIPS* little-endian +#define EFI_IMAGE_FILE_MACHINE_POWERPC 0x1F0 ///< IBM* PowerPC Little-Endian +// +// * Other names and brands may be claimed as the property of others. +// + +/// +/// Header Data Directories +/// +typedef struct { + UINT32 VirtualAddress; + UINT32 Size; +} EFI_IMAGE_DATA_DIRECTORY; + +#define EFI_IMAGE_ROM_OPTIONAL_HDR_MAGIC 0x107 + +/// +/// Directory Entries +/// +#define EFI_IMAGE_DIRECTORY_ENTRY_EXPORT 0 +#define EFI_IMAGE_DIRECTORY_ENTRY_IMPORT 1 +#define EFI_IMAGE_DIRECTORY_ENTRY_RESOURCE 2 +#define EFI_IMAGE_DIRECTORY_ENTRY_EXCEPTION 3 +#define EFI_IMAGE_DIRECTORY_ENTRY_SECURITY 4 +#define EFI_IMAGE_DIRECTORY_ENTRY_BASERELOC 5 +#define EFI_IMAGE_DIRECTORY_ENTRY_DEBUG 6 +#define EFI_IMAGE_DIRECTORY_ENTRY_COPYRIGHT 7 +#define EFI_IMAGE_DIRECTORY_ENTRY_GLOBALPTR 8 +#define EFI_IMAGE_DIRECTORY_ENTRY_TLS 9 +#define EFI_IMAGE_DIRECTORY_ENTRY_LOAD_CONFIG 10 + +#define EFI_IMAGE_NUMBER_OF_DIRECTORY_ENTRIES 16 + +/// +/// @attention +/// EFI_IMAGE_NT_OPTIONAL_HDR32_MAGIC means PE32 and +/// EFI_IMAGE_OPTIONAL_HEADER32 must be used. The data structures only vary +/// after NT additional fields. +/// +#define EFI_IMAGE_NT_OPTIONAL_HDR32_MAGIC 0x10b + +typedef struct { + /// + /// Standard fields. + /// + UINT16 Magic; + UINT8 MajorLinkerVersion; + UINT8 MinorLinkerVersion; + UINT32 SizeOfCode; + UINT32 SizeOfInitializedData; + UINT32 SizeOfUninitializedData; + UINT32 AddressOfEntryPoint; + UINT32 BaseOfCode; + UINT32 BaseOfData; ///< PE32 contains this additional field, which is absent in PE32+ + /// + /// NT additional fields. + /// + UINT32 ImageBase; + UINT32 SectionAlignment; + UINT32 FileAlignment; + UINT16 MajorOperatingSystemVersion; + UINT16 MinorOperatingSystemVersion; + UINT16 MajorImageVersion; + UINT16 MinorImageVersion; + UINT16 MajorSubsystemVersion; + UINT16 MinorSubsystemVersion; + UINT32 Win32VersionValue; + UINT32 SizeOfImage; + UINT32 SizeOfHeaders; + UINT32 CheckSum; + UINT16 Subsystem; + UINT16 DllCharacteristics; + UINT32 SizeOfStackReserve; + UINT32 SizeOfStackCommit; + UINT32 SizeOfHeapReserve; + UINT32 SizeOfHeapCommit; + UINT32 LoaderFlags; + UINT32 NumberOfRvaAndSizes; + EFI_IMAGE_DATA_DIRECTORY DataDirectory[EFI_IMAGE_NUMBER_OF_DIRECTORY_ENTRIES]; +} EFI_IMAGE_OPTIONAL_HEADER32; + +/// +/// @attention +/// EFI_IMAGE_NT_OPTIONAL_HDR64_MAGIC means PE32+ and +/// EFI_IMAGE_OPTIONAL_HEADER64 must be used. The data structures only vary +/// after NT additional fields. +/// +#define EFI_IMAGE_NT_OPTIONAL_HDR64_MAGIC 0x20b + +typedef struct { + // + // Standard fields. + // + UINT16 Magic; + UINT8 MajorLinkerVersion; + UINT8 MinorLinkerVersion; + UINT32 SizeOfCode; + UINT32 SizeOfInitializedData; + UINT32 SizeOfUninitializedData; + UINT32 AddressOfEntryPoint; + UINT32 BaseOfCode; + // + // NT additional fields. + // + UINT64 ImageBase; + UINT32 SectionAlignment; + UINT32 FileAlignment; + UINT16 MajorOperatingSystemVersion; + UINT16 MinorOperatingSystemVersion; + UINT16 MajorImageVersion; + UINT16 MinorImageVersion; + UINT16 MajorSubsystemVersion; + UINT16 MinorSubsystemVersion; + UINT32 Win32VersionValue; + UINT32 SizeOfImage; + UINT32 SizeOfHeaders; + UINT32 CheckSum; + UINT16 Subsystem; + UINT16 DllCharacteristics; + UINT64 SizeOfStackReserve; + UINT64 SizeOfStackCommit; + UINT64 SizeOfHeapReserve; + UINT64 SizeOfHeapCommit; + UINT32 LoaderFlags; + UINT32 NumberOfRvaAndSizes; + EFI_IMAGE_DATA_DIRECTORY DataDirectory[EFI_IMAGE_NUMBER_OF_DIRECTORY_ENTRIES]; +} EFI_IMAGE_OPTIONAL_HEADER64; + + +/// +/// @attention +/// EFI_IMAGE_NT_HEADERS32 and EFI_IMAGE_HEADERS64 are for use ONLY +/// by tools. All proper EFI code MUST use EFI_IMAGE_NT_HEADERS ONLY!!! +/// +typedef struct { + UINT32 Signature; + EFI_IMAGE_FILE_HEADER FileHeader; + EFI_IMAGE_OPTIONAL_HEADER32 OptionalHeader; +} EFI_IMAGE_NT_HEADERS32; + +#define EFI_IMAGE_SIZEOF_NT_OPTIONAL32_HEADER sizeof (EFI_IMAGE_NT_HEADERS32) + +typedef struct { + UINT32 Signature; + EFI_IMAGE_FILE_HEADER FileHeader; + EFI_IMAGE_OPTIONAL_HEADER64 OptionalHeader; +} EFI_IMAGE_NT_HEADERS64; + +#define EFI_IMAGE_SIZEOF_NT_OPTIONAL64_HEADER sizeof (EFI_IMAGE_NT_HEADERS64) + + +/// +/// Processor specific definition of EFI_IMAGE_OPTIONAL_HEADER so the +/// type name EFI_IMAGE_OPTIONAL_HEADER is appropriate to the build. Same for +/// EFI_IMAGE_NT_HEADERS. These definitions MUST be used by ALL EFI code. +/// +#if defined (MDE_CPU_IA32) + +#define EFI_IMAGE_MACHINE_TYPE_SUPPORTED(Machine) \ + (((Machine) == EFI_IMAGE_MACHINE_IA32) || ((Machine) == EFI_IMAGE_MACHINE_EBC)) + +#define EFI_IMAGE_MACHINE_CROSS_TYPE_SUPPORTED(Machine) ((Machine) == EFI_IMAGE_MACHINE_X64) + +typedef EFI_IMAGE_NT_HEADERS32 EFI_IMAGE_NT_HEADERS; + +#elif defined (MDE_CPU_IPF) + +#define EFI_IMAGE_MACHINE_TYPE_SUPPORTED(Machine) \ + (((Machine) == EFI_IMAGE_MACHINE_IPF) || ((Machine) == EFI_IMAGE_MACHINE_EBC)) + +#define EFI_IMAGE_MACHINE_CROSS_TYPE_SUPPORTED(Machine) (FALSE) + +typedef EFI_IMAGE_NT_HEADERS64 EFI_IMAGE_NT_HEADERS; + +#elif defined (MDE_CPU_X64) + +#define EFI_IMAGE_MACHINE_TYPE_SUPPORTED(Machine) \ + (((Machine) == EFI_IMAGE_MACHINE_X64) || ((Machine) == EFI_IMAGE_MACHINE_EBC)) + +#define EFI_IMAGE_MACHINE_CROSS_TYPE_SUPPORTED(Machine) ((Machine) == EFI_IMAGE_MACHINE_IA32) + +typedef EFI_IMAGE_NT_HEADERS64 EFI_IMAGE_NT_HEADERS; + +#elif defined (MDE_CPU_EBC) + +/// +/// This is just to make sure you can cross compile with the EBC compiiler. +/// It does not make sense to have a PE loader coded in EBC. You need to +/// understand the basic +/// +#define EFI_IMAGE_MACHINE_TYPE_SUPPORTED(Machine) ((Machine) == EFI_IMAGE_MACHINE_EBC) + +#define EFI_IMAGE_MACHINE_CROSS_TYPE_SUPPORTED(Machine) (FALSE) + +typedef EFI_IMAGE_NT_HEADERS64 EFI_IMAGE_NT_HEADERS; + +#else +#error Unknown Processor Type +#endif + + +#define EFI_IMAGE_FIRST_SECTION(ntheader) \ + ( \ + (EFI_IMAGE_SECTION_HEADER *) \ + ( \ + (UINT32) ntheader + \ + FIELD_OFFSET (EFI_IMAGE_NT_HEADERS, OptionalHeader) + \ + ((EFI_IMAGE_NT_HEADERS *) (ntheader))->FileHeader.SizeOfOptionalHeader \ + ) \ + ) + +/// +/// Other Windows Subsystem Values +/// +#define EFI_IMAGE_SUBSYSTEM_UNKNOWN 0 +#define EFI_IMAGE_SUBSYSTEM_NATIVE 1 +#define EFI_IMAGE_SUBSYSTEM_WINDOWS_GUI 2 +#define EFI_IMAGE_SUBSYSTEM_WINDOWS_CUI 3 +#define EFI_IMAGE_SUBSYSTEM_OS2_CUI 5 +#define EFI_IMAGE_SUBSYSTEM_POSIX_CUI 7 + +/// +/// Section header format. +/// +#define EFI_IMAGE_SIZEOF_SHORT_NAME 8 + +typedef struct { + UINT8 Name[EFI_IMAGE_SIZEOF_SHORT_NAME]; + union { + UINT32 PhysicalAddress; + UINT32 VirtualSize; + } Misc; + UINT32 VirtualAddress; + UINT32 SizeOfRawData; + UINT32 PointerToRawData; + UINT32 PointerToRelocations; + UINT32 PointerToLinenumbers; + UINT16 NumberOfRelocations; + UINT16 NumberOfLinenumbers; + UINT32 Characteristics; +} EFI_IMAGE_SECTION_HEADER; + +/// +/// Size of EFI_IMAGE_SECTION_HEADER +/// +#define EFI_IMAGE_SIZEOF_SECTION_HEADER 40 + +/// +/// Section Flags Values +/// +#define EFI_IMAGE_SCN_TYPE_NO_PAD BIT3 ///< 0x00000008 ///< Reserved. +#define EFI_IMAGE_SCN_CNT_CODE BIT5 ///< 0x00000020 +#define EFI_IMAGE_SCN_CNT_INITIALIZED_DATA BIT6 ///< 0x00000040 +#define EFI_IMAGE_SCN_CNT_UNINITIALIZED_DATA BIT7 ///< 0x00000080 + +#define EFI_IMAGE_SCN_LNK_OTHER BIT8 ///< 0x00000100 ///< Reserved. +#define EFI_IMAGE_SCN_LNK_INFO BIT9 ///< 0x00000200 ///< Section contains comments or some other type of information. +#define EFI_IMAGE_SCN_LNK_REMOVE BIT10 ///< 0x00000800 ///< Section contents will not become part of image. +#define EFI_IMAGE_SCN_LNK_COMDAT BIT12 ///< 0x00001000 + +#define EFI_IMAGE_SCN_ALIGN_1BYTES BIT20 ///< 0x00100000 +#define EFI_IMAGE_SCN_ALIGN_2BYTES BIT21 ///< 0x00200000 +#define EFI_IMAGE_SCN_ALIGN_4BYTES (BIT20|BIT21) ///< 0x00300000 +#define EFI_IMAGE_SCN_ALIGN_8BYTES BIT22 ///< 0x00400000 +#define EFI_IMAGE_SCN_ALIGN_16BYTES (BIT20|BIT22) ///< 0x00500000 +#define EFI_IMAGE_SCN_ALIGN_32BYTES (BIT21|BIT22) ///< 0x00600000 +#define EFI_IMAGE_SCN_ALIGN_64BYTES (BIT20|BIT21|BIT22) ///< 0x00700000 + +#define EFI_IMAGE_SCN_MEM_DISCARDABLE BIT25 ///< 0x02000000 +#define EFI_IMAGE_SCN_MEM_NOT_CACHED BIT26 ///< 0x04000000 +#define EFI_IMAGE_SCN_MEM_NOT_PAGED BIT27 ///< 0x08000000 +#define EFI_IMAGE_SCN_MEM_SHARED BIT28 ///< 0x10000000 +#define EFI_IMAGE_SCN_MEM_EXECUTE BIT29 ///< 0x20000000 +#define EFI_IMAGE_SCN_MEM_READ BIT30 ///< 0x40000000 +#define EFI_IMAGE_SCN_MEM_WRITE BIT31 ///< 0x80000000 + +/// +/// Size of a Symbol Table Record +/// +#define EFI_IMAGE_SIZEOF_SYMBOL 18 + +/// +/// Symbols have a section number of the section in which they are +/// defined. Otherwise, section numbers have the following meanings: +/// +#define EFI_IMAGE_SYM_UNDEFINED (UINT16) 0 ///< Symbol is undefined or is common. +#define EFI_IMAGE_SYM_ABSOLUTE (UINT16) -1 ///< Symbol is an absolute value. +#define EFI_IMAGE_SYM_DEBUG (UINT16) -2 ///< Symbol is a special debug item. + +/// +/// Symbol Type (fundamental) values. +/// +#define EFI_IMAGE_SYM_TYPE_NULL 0 ///< no type. +#define EFI_IMAGE_SYM_TYPE_VOID 1 ///< no valid type. +#define EFI_IMAGE_SYM_TYPE_CHAR 2 ///< type character. +#define EFI_IMAGE_SYM_TYPE_SHORT 3 ///< type short integer. +#define EFI_IMAGE_SYM_TYPE_INT 4 +#define EFI_IMAGE_SYM_TYPE_LONG 5 +#define EFI_IMAGE_SYM_TYPE_FLOAT 6 +#define EFI_IMAGE_SYM_TYPE_DOUBLE 7 +#define EFI_IMAGE_SYM_TYPE_STRUCT 8 +#define EFI_IMAGE_SYM_TYPE_UNION 9 +#define EFI_IMAGE_SYM_TYPE_ENUM 10 ///< enumeration. +#define EFI_IMAGE_SYM_TYPE_MOE 11 ///< member of enumeration. +#define EFI_IMAGE_SYM_TYPE_BYTE 12 +#define EFI_IMAGE_SYM_TYPE_WORD 13 +#define EFI_IMAGE_SYM_TYPE_UINT 14 +#define EFI_IMAGE_SYM_TYPE_DWORD 15 + +/// +/// Symbol Type (derived) values. +/// +#define EFI_IMAGE_SYM_DTYPE_NULL 0 ///< no derived type. +#define EFI_IMAGE_SYM_DTYPE_POINTER 1 +#define EFI_IMAGE_SYM_DTYPE_FUNCTION 2 +#define EFI_IMAGE_SYM_DTYPE_ARRAY 3 + +/// +/// Storage classes. +/// +#define EFI_IMAGE_SYM_CLASS_END_OF_FUNCTION ((UINT8) -1) +#define EFI_IMAGE_SYM_CLASS_NULL 0 +#define EFI_IMAGE_SYM_CLASS_AUTOMATIC 1 +#define EFI_IMAGE_SYM_CLASS_EXTERNAL 2 +#define EFI_IMAGE_SYM_CLASS_STATIC 3 +#define EFI_IMAGE_SYM_CLASS_REGISTER 4 +#define EFI_IMAGE_SYM_CLASS_EXTERNAL_DEF 5 +#define EFI_IMAGE_SYM_CLASS_LABEL 6 +#define EFI_IMAGE_SYM_CLASS_UNDEFINED_LABEL 7 +#define EFI_IMAGE_SYM_CLASS_MEMBER_OF_STRUCT 8 +#define EFI_IMAGE_SYM_CLASS_ARGUMENT 9 +#define EFI_IMAGE_SYM_CLASS_STRUCT_TAG 10 +#define EFI_IMAGE_SYM_CLASS_MEMBER_OF_UNION 11 +#define EFI_IMAGE_SYM_CLASS_UNION_TAG 12 +#define EFI_IMAGE_SYM_CLASS_TYPE_DEFINITION 13 +#define EFI_IMAGE_SYM_CLASS_UNDEFINED_STATIC 14 +#define EFI_IMAGE_SYM_CLASS_ENUM_TAG 15 +#define EFI_IMAGE_SYM_CLASS_MEMBER_OF_ENUM 16 +#define EFI_IMAGE_SYM_CLASS_REGISTER_PARAM 17 +#define EFI_IMAGE_SYM_CLASS_BIT_FIELD 18 +#define EFI_IMAGE_SYM_CLASS_BLOCK 100 +#define EFI_IMAGE_SYM_CLASS_FUNCTION 101 +#define EFI_IMAGE_SYM_CLASS_END_OF_STRUCT 102 +#define EFI_IMAGE_SYM_CLASS_FILE 103 +#define EFI_IMAGE_SYM_CLASS_SECTION 104 +#define EFI_IMAGE_SYM_CLASS_WEAK_EXTERNAL 105 + +// +// type packing constants +// +#define EFI_IMAGE_N_BTMASK 017 +#define EFI_IMAGE_N_TMASK 060 +#define EFI_IMAGE_N_TMASK1 0300 +#define EFI_IMAGE_N_TMASK2 0360 +#define EFI_IMAGE_N_BTSHFT 4 +#define EFI_IMAGE_N_TSHIFT 2 + +/// +/// Communal selection types. +/// +#define EFI_IMAGE_COMDAT_SELECT_NODUPLICATES 1 +#define EFI_IMAGE_COMDAT_SELECT_ANY 2 +#define EFI_IMAGE_COMDAT_SELECT_SAME_SIZE 3 +#define EFI_IMAGE_COMDAT_SELECT_EXACT_MATCH 4 +#define EFI_IMAGE_COMDAT_SELECT_ASSOCIATIVE 5 + +/// +/// the following values only be referred in PeCoff, not defined in PECOFF. +/// +#define EFI_IMAGE_WEAK_EXTERN_SEARCH_NOLIBRARY 1 +#define EFI_IMAGE_WEAK_EXTERN_SEARCH_LIBRARY 2 +#define EFI_IMAGE_WEAK_EXTERN_SEARCH_ALIAS 3 + +/// +/// Relocation format. +/// +typedef struct { + UINT32 VirtualAddress; + UINT32 SymbolTableIndex; + UINT16 Type; +} EFI_IMAGE_RELOCATION; + +/// +/// Size of EFI_IMAGE_RELOCATION +/// +#define EFI_IMAGE_SIZEOF_RELOCATION 10 + +/// +/// I386 relocation types. +/// +#define EFI_IMAGE_REL_I386_ABSOLUTE 0x0000 ///< Reference is absolute, no relocation is necessary +#define EFI_IMAGE_REL_I386_DIR16 0x0001 ///< Direct 16-bit reference to the symbols virtual address +#define EFI_IMAGE_REL_I386_REL16 0x0002 ///< PC-relative 16-bit reference to the symbols virtual address +#define EFI_IMAGE_REL_I386_DIR32 0x0006 ///< Direct 32-bit reference to the symbols virtual address +#define EFI_IMAGE_REL_I386_DIR32NB 0x0007 ///< Direct 32-bit reference to the symbols virtual address, base not included +#define EFI_IMAGE_REL_I386_SEG12 0x0009 ///< Direct 16-bit reference to the segment-selector bits of a 32-bit virtual address +#define EFI_IMAGE_REL_I386_SECTION 0x000A +#define EFI_IMAGE_REL_I386_SECREL 0x000B +#define EFI_IMAGE_REL_I386_REL32 0x0014 ///< PC-relative 32-bit reference to the symbols virtual address + +/// +/// x64 processor relocation types. +/// +#define IMAGE_REL_AMD64_ABSOLUTE 0x0000 +#define IMAGE_REL_AMD64_ADDR64 0x0001 +#define IMAGE_REL_AMD64_ADDR32 0x0002 +#define IMAGE_REL_AMD64_ADDR32NB 0x0003 +#define IMAGE_REL_AMD64_REL32 0x0004 +#define IMAGE_REL_AMD64_REL32_1 0x0005 +#define IMAGE_REL_AMD64_REL32_2 0x0006 +#define IMAGE_REL_AMD64_REL32_3 0x0007 +#define IMAGE_REL_AMD64_REL32_4 0x0008 +#define IMAGE_REL_AMD64_REL32_5 0x0009 +#define IMAGE_REL_AMD64_SECTION 0x000A +#define IMAGE_REL_AMD64_SECREL 0x000B +#define IMAGE_REL_AMD64_SECREL7 0x000C +#define IMAGE_REL_AMD64_TOKEN 0x000D +#define IMAGE_REL_AMD64_SREL32 0x000E +#define IMAGE_REL_AMD64_PAIR 0x000F +#define IMAGE_REL_AMD64_SSPAN32 0x0010 + +/// +/// Based relocation format. +/// +typedef struct { + UINT32 VirtualAddress; + UINT32 SizeOfBlock; +} EFI_IMAGE_BASE_RELOCATION; + +/// +/// Size of EFI_IMAGE_BASE_RELOCATION +/// +#define EFI_IMAGE_SIZEOF_BASE_RELOCATION 8 + +/// +/// Based relocation types. +/// +#define EFI_IMAGE_REL_BASED_ABSOLUTE 0 +#define EFI_IMAGE_REL_BASED_HIGH 1 +#define EFI_IMAGE_REL_BASED_LOW 2 +#define EFI_IMAGE_REL_BASED_HIGHLOW 3 +#define EFI_IMAGE_REL_BASED_HIGHADJ 4 +#define EFI_IMAGE_REL_BASED_MIPS_JMPADDR 5 +#define EFI_IMAGE_REL_BASED_IA64_IMM64 9 +#define IMAGE_REL_BASED_MIPS_JMPADDR16 9 +#define EFI_IMAGE_REL_BASED_DIR64 10 + +/// +/// Line number format. +/// +typedef struct { + union { + UINT32 SymbolTableIndex; // Symbol table index of function name if Linenumber is 0. + UINT32 VirtualAddress; // Virtual address of line number. + } Type; + UINT16 Linenumber; // Line number. +} EFI_IMAGE_LINENUMBER; + +/// +/// Size of EFI_IMAGE_LINENUMBER +/// +#define EFI_IMAGE_SIZEOF_LINENUMBER 6 + +/// +/// Archive format. +/// +#define EFI_IMAGE_ARCHIVE_START_SIZE 8 +#define EFI_IMAGE_ARCHIVE_START "!<arch>\n" +#define EFI_IMAGE_ARCHIVE_END "`\n" +#define EFI_IMAGE_ARCHIVE_PAD "\n" +#define EFI_IMAGE_ARCHIVE_LINKER_MEMBER "/ " +#define EFI_IMAGE_ARCHIVE_LONGNAMES_MEMBER "// " + +typedef struct { + UINT8 Name[16]; ///< File member name - `/' terminated. + UINT8 Date[12]; ///< File member date - decimal. + UINT8 UserID[6]; ///< File member user id - decimal. + UINT8 GroupID[6]; ///< File member group id - decimal. + UINT8 Mode[8]; ///< File member mode - octal. + UINT8 Size[10]; ///< File member size - decimal. + UINT8 EndHeader[2]; ///< String to end header. (0x60 0x0A) +} EFI_IMAGE_ARCHIVE_MEMBER_HEADER; + +/// +/// Size of EFI_IMAGE_ARCHIVE_MEMBER_HEADER +/// +#define EFI_IMAGE_SIZEOF_ARCHIVE_MEMBER_HDR 60 + + +/// +/// DLL Support +/// + +/// +/// Export Directory Table +/// +typedef struct { + UINT32 Characteristics; + UINT32 TimeDateStamp; + UINT16 MajorVersion; + UINT16 MinorVersion; + UINT32 Name; + UINT32 Base; + UINT32 NumberOfFunctions; + UINT32 NumberOfNames; + UINT32 AddressOfFunctions; + UINT32 AddressOfNames; + UINT32 AddressOfNameOrdinals; +} EFI_IMAGE_EXPORT_DIRECTORY; + +/// +/// Hint/Name Table +/// +typedef struct { + UINT16 Hint; + UINT8 Name[1]; +} EFI_IMAGE_IMPORT_BY_NAME; + +typedef struct { + union { + UINT32 Function; + UINT32 Ordinal; + EFI_IMAGE_IMPORT_BY_NAME *AddressOfData; + } u1; +} EFI_IMAGE_THUNK_DATA; + +#define EFI_IMAGE_ORDINAL_FLAG BIT31 ///< Flag for PE32 +#define EFI_IMAGE_SNAP_BY_ORDINAL(Ordinal) ((Ordinal & EFI_IMAGE_ORDINAL_FLAG) != 0) +#define EFI_IMAGE_ORDINAL(Ordinal) (Ordinal & 0xffff) + +/// +/// Import Directory Table +/// +typedef struct { + UINT32 Characteristics; + UINT32 TimeDateStamp; + UINT32 ForwarderChain; + UINT32 Name; + EFI_IMAGE_THUNK_DATA *FirstThunk; +} EFI_IMAGE_IMPORT_DESCRIPTOR; + + +/// +/// Debug Direcotry Format +/// +typedef struct { + UINT32 Characteristics; + UINT32 TimeDateStamp; + UINT16 MajorVersion; + UINT16 MinorVersion; + UINT32 Type; + UINT32 SizeOfData; + UINT32 RVA; ///< The address of the debug data when loaded, relative to the image base + UINT32 FileOffset; ///< The file pointer to the debug data +} EFI_IMAGE_DEBUG_DIRECTORY_ENTRY; + +#define EFI_IMAGE_DEBUG_TYPE_CODEVIEW 2 ///< The Visual C++ debug information + +/// +/// Debug Data Structure defined in Microsoft C++ +/// +#define CODEVIEW_SIGNATURE_NB10 SIGNATURE_32('N', 'B', '1', '0') +typedef struct { + UINT32 Signature; ///< "NB10" + UINT32 Unknown; + UINT32 Unknown2; + UINT32 Unknown3; + // + // Filename of .PDB goes here + // +} EFI_IMAGE_DEBUG_CODEVIEW_NB10_ENTRY; + +/// +/// Debug Data Structure defined in Microsoft C++ +/// +#define CODEVIEW_SIGNATURE_RSDS SIGNATURE_32('R', 'S', 'D', 'S') +typedef struct { + UINT32 Signature; ///< "RSDS" + UINT32 Unknown; + UINT32 Unknown2; + UINT32 Unknown3; + UINT32 Unknown4; + UINT32 Unknown5; + // + // Filename of .PDB goes here + // +} EFI_IMAGE_DEBUG_CODEVIEW_RSDS_ENTRY; + +/// +/// Header format for TE images, defined in PI Specification, 1.0 +/// +typedef struct { + UINT16 Signature; ///< signature for TE format = "VZ" + UINT16 Machine; ///< from the original file header + UINT8 NumberOfSections; ///< from the original file header + UINT8 Subsystem; ///< from original optional header + UINT16 StrippedSize; ///< how many bytes we removed from the header + UINT32 AddressOfEntryPoint; ///< offset to entry point -- from original optional header + UINT32 BaseOfCode; ///< from original image -- required for ITP debug + UINT64 ImageBase; ///< from original file header + EFI_IMAGE_DATA_DIRECTORY DataDirectory[2]; ///< only base relocation and debug directory +} EFI_TE_IMAGE_HEADER; + + +#define EFI_TE_IMAGE_HEADER_SIGNATURE SIGNATURE_16('V', 'Z') + +// +// Data directory indexes in our TE image header +// +#define EFI_TE_IMAGE_DIRECTORY_ENTRY_BASERELOC 0 +#define EFI_TE_IMAGE_DIRECTORY_ENTRY_DEBUG 1 + + +/// +/// Union of PE32, PE32+, and TE headers +/// +typedef union { + EFI_IMAGE_NT_HEADERS32 Pe32; + EFI_IMAGE_NT_HEADERS64 Pe32Plus; + EFI_TE_IMAGE_HEADER Te; +} EFI_IMAGE_OPTIONAL_HEADER_UNION; + +typedef union { + EFI_IMAGE_NT_HEADERS32 *Pe32; + EFI_IMAGE_NT_HEADERS64 *Pe32Plus; + EFI_TE_IMAGE_HEADER *Te; + EFI_IMAGE_OPTIONAL_HEADER_UNION *Union; +} EFI_IMAGE_OPTIONAL_HEADER_PTR_UNION; + +#endif diff --git a/gpxe/src/include/gpxe/efi/LICENCE b/gpxe/src/include/gpxe/efi/LICENCE new file mode 100644 index 00000000..6aa2b2ff --- /dev/null +++ b/gpxe/src/include/gpxe/efi/LICENCE @@ -0,0 +1,40 @@ +The EFI headers contained herein are copied from the EFI Development +Kit, available from http://www.tianocore.org and published under the +following licence: + + BSD License from Intel + Copyright (c) 2004, Intel Corporation + All rights reserved. + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions + are met: + + Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + + Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + + Neither the name of the Intel Corporation nor the names of its + contributors may be used to endorse or promote products derived from + this software without specific prior written permission. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN + ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + POSSIBILITY OF SUCH DAMAGE. + + +This licence applies only to files that are part of the EFI +Development Kit. Other files may contain their own licence terms, or +may fall under the standard gPXE GPL licence. diff --git a/gpxe/src/include/gpxe/efi/Pi/PiBootMode.h b/gpxe/src/include/gpxe/efi/Pi/PiBootMode.h new file mode 100644 index 00000000..bebca227 --- /dev/null +++ b/gpxe/src/include/gpxe/efi/Pi/PiBootMode.h @@ -0,0 +1,43 @@ +/** @file + Present the boot mode values in PI. + + Copyright (c) 2006 - 2008, Intel Corporation + All rights reserved. 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: + PI Version 1.0 + +**/ + +#ifndef __PI_BOOT_MODE_H__ +#define __PI_BOOT_MODE_H__ + +#include <gpxe/efi/ProcessorBind.h> + +/// +/// EFI boot mode +/// +typedef UINT32 EFI_BOOT_MODE; + +// +// 0x21 - 0xf..f are reserved. +// +#define BOOT_WITH_FULL_CONFIGURATION 0x00 +#define BOOT_WITH_MINIMAL_CONFIGURATION 0x01 +#define BOOT_ASSUMING_NO_CONFIGURATION_CHANGES 0x02 +#define BOOT_WITH_FULL_CONFIGURATION_PLUS_DIAGNOSTICS 0x03 +#define BOOT_WITH_DEFAULT_SETTINGS 0x04 +#define BOOT_ON_S4_RESUME 0x05 +#define BOOT_ON_S5_RESUME 0x06 +#define BOOT_ON_S2_RESUME 0x10 +#define BOOT_ON_S3_RESUME 0x11 +#define BOOT_ON_FLASH_UPDATE 0x12 +#define BOOT_IN_RECOVERY_MODE 0x20 + +#endif diff --git a/gpxe/src/include/gpxe/efi/Pi/PiDependency.h b/gpxe/src/include/gpxe/efi/Pi/PiDependency.h new file mode 100644 index 00000000..73f6027e --- /dev/null +++ b/gpxe/src/include/gpxe/efi/Pi/PiDependency.h @@ -0,0 +1,47 @@ +/** @file + Present the dependency expression values in PI. + + Copyright (c) 2006 - 2008, Intel Corporation + All rights reserved. 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: + PI Version 1.0 + +**/ +#ifndef __PI_DEPENDENCY_H__ +#define __PI_DEPENDENCY_H__ + +/// +/// If present, this must be the first and only opcode, +/// EFI_DEP_BEFORE is only used by DXE driver. +/// +#define EFI_DEP_BEFORE 0x00 + +/// +/// If present, this must be the first and only opcode, +/// EFI_DEP_AFTER is only used by DXE driver. +/// +#define EFI_DEP_AFTER 0x01 + +#define EFI_DEP_PUSH 0x02 +#define EFI_DEP_AND 0x03 +#define EFI_DEP_OR 0x04 +#define EFI_DEP_NOT 0x05 +#define EFI_DEP_TRUE 0x06 +#define EFI_DEP_FALSE 0x07 +#define EFI_DEP_END 0x08 + + +/// +/// If present, this must be the first opcode, +/// EFI_DEP_SOR is only used by DXE driver. +/// +#define EFI_DEP_SOR 0x09 + +#endif diff --git a/gpxe/src/include/gpxe/efi/Pi/PiDxeCis.h b/gpxe/src/include/gpxe/efi/Pi/PiDxeCis.h new file mode 100644 index 00000000..a9248883 --- /dev/null +++ b/gpxe/src/include/gpxe/efi/Pi/PiDxeCis.h @@ -0,0 +1,642 @@ +/** @file + Include file matches things in PI. + + Copyright (c) 2006 - 2008, Intel Corporation + All rights reserved. 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: + PI Version 1.0 + +**/ + +#ifndef __PI_DXECIS_H__ +#define __PI_DXECIS_H__ + +#include <gpxe/efi/Pi/PiMultiPhase.h> + +/// +/// Global Coherencey Domain types - Memory type +/// +typedef enum { + EfiGcdMemoryTypeNonExistent, + EfiGcdMemoryTypeReserved, + EfiGcdMemoryTypeSystemMemory, + EfiGcdMemoryTypeMemoryMappedIo, + EfiGcdMemoryTypeMaximum +} EFI_GCD_MEMORY_TYPE; + +/// +/// Global Coherencey Domain types - IO type +/// +typedef enum { + EfiGcdIoTypeNonExistent, + EfiGcdIoTypeReserved, + EfiGcdIoTypeIo, + EfiGcdIoTypeMaximum +} EFI_GCD_IO_TYPE; + +/// +/// The type of allocation to perform. +/// +typedef enum { + EfiGcdAllocateAnySearchBottomUp, + EfiGcdAllocateMaxAddressSearchBottomUp, + EfiGcdAllocateAddress, + EfiGcdAllocateAnySearchTopDown, + EfiGcdAllocateMaxAddressSearchTopDown, + EfiGcdMaxAllocateType +} EFI_GCD_ALLOCATE_TYPE; + +/// +/// EFI_GCD_MEMORY_SPACE_DESCRIPTOR +/// +typedef struct { + /// + /// The physical address of the first byte in the memory region. Type + /// EFI_PHYSICAL_ADDRESS is defined in the AllocatePages() function + /// description in the UEFI 2.0 specification + /// + EFI_PHYSICAL_ADDRESS BaseAddress; + + /// + /// The number of bytes in the memory region. + /// + UINT64 Length; + + /// + /// The bit mask of attributes that the memory region is capable of supporting. The bit + /// mask of available attributes is defined in the GetMemoryMap() function description + /// in the UEFI 2.0 specification. + /// + UINT64 Capabilities; + /// + /// The bit mask of attributes that the memory region is currently using. The bit mask of + /// available attributes is defined in GetMemoryMap(). + /// + UINT64 Attributes; + /// + /// Type of the memory region. Type EFI_GCD_MEMORY_TYPE is defined in the + /// AddMemorySpace() function description + /// + EFI_GCD_MEMORY_TYPE GcdMemoryType; + + /// + /// The image handle of the agent that allocated the memory resource described by + /// PhysicalStart and NumberOfBytes. If this field is NULL, then the memory + /// resource is not currently allocated. Type EFI_HANDLE is defined in + /// InstallProtocolInterface() in the UEFI 2.0 specification. + /// + EFI_HANDLE ImageHandle; + + /// + /// The device handle for which the memory resource has been allocated. If + /// ImageHandle is NULL, then the memory resource is not currently allocated. If this + /// field is NULL, then the memory resource is not associated with a device that is + /// described by a device handle. Type EFI_HANDLE is defined in + /// InstallProtocolInterface() in the UEFI 2.0 specification. + /// + EFI_HANDLE DeviceHandle; +} EFI_GCD_MEMORY_SPACE_DESCRIPTOR; + +/// +/// EFI_GCD_IO_SPACE_DESCRIPTOR +/// +typedef struct { + /// + /// Physical address of the first byte in the I/O region. Type + /// EFI_PHYSICAL_ADDRESS is defined in the AllocatePages() function + /// description in the UEFI 2.0 specification. + /// + EFI_PHYSICAL_ADDRESS BaseAddress; + + /// + /// Number of bytes in the I/O region. + /// + UINT64 Length; + + /// + /// Type of the I/O region. Type EFI_GCD_IO_TYPE is defined in the + /// AddIoSpace() function description. + /// + EFI_GCD_IO_TYPE GcdIoType; + + /// + /// The image handle of the agent that allocated the I/O resource described by + /// PhysicalStart and NumberOfBytes. If this field is NULL, then the I/O + /// resource is not currently allocated. Type EFI_HANDLE is defined in + /// InstallProtocolInterface() in the UEFI 2.0 specification. + /// + EFI_HANDLE ImageHandle; + + /// + /// The device handle for which the I/O resource has been allocated. If ImageHandle + /// is NULL, then the I/O resource is not currently allocated. If this field is NULL, then + /// the I/O resource is not associated with a device that is described by a device handle. + /// Type EFI_HANDLE is defined in InstallProtocolInterface() in the UEFI + /// 2.0 specification. + /// + EFI_HANDLE DeviceHandle; +} EFI_GCD_IO_SPACE_DESCRIPTOR; + + +/** + Adds reserved memory, system memory, or memory-mapped I/O resources to the + global coherency domain of the processor. + + @param GcdMemoryType The type of memory resource being added. + @param BaseAddress The physical address that is the start address + of the memory resource being added. + @param Length The size, in bytes, of the memory resource that + is being added. + @param Capabilities The bit mask of attributes that the memory + resource region supports. + + @retval EFI_SUCCESS The memory resource was added to the global + coherency domain of the processor. + @retval EFI_INVALID_PARAMETER GcdMemoryType is invalid. + @retval EFI_INVALID_PARAMETER Length is zero. + @retval EFI_OUT_OF_RESOURCES There are not enough system resources to add + the memory resource to the global coherency + domain of the processor. + @retval EFI_UNSUPPORTED The processor does not support one or more bytes + of the memory resource range specified by + BaseAddress and Length. + @retval EFI_ACCESS_DENIED One or more bytes of the memory resource range + specified by BaseAddress and Length conflicts + with a memory resource range that was previously + added to the global coherency domain of the processor. + @retval EFI_ACCESS_DENIED One or more bytes of the memory resource range + specified by BaseAddress and Length was allocated + in a prior call to AllocateMemorySpace().. + +**/ +typedef +EFI_STATUS +(EFIAPI *EFI_ADD_MEMORY_SPACE)( + IN EFI_GCD_MEMORY_TYPE GcdMemoryType, + IN EFI_PHYSICAL_ADDRESS BaseAddress, + IN UINT64 Length, + IN UINT64 Capabilities + ); + +/** + Allocates nonexistent memory, reserved memory, system memory, or memorymapped + I/O resources from the global coherency domain of the processor. + + @param GcdAllocateType The type of allocation to perform. + @param GcdMemoryType The type of memory resource being allocated. + @param Alignment The log base 2 of the boundary that BaseAddress must + be aligned on output. Align with 2^Alignment. + @param Length The size in bytes of the memory resource range that + is being allocated. + @param BaseAddress A pointer to a physical address to allocate. + @param Imagehandle The image handle of the agent that is allocating + the memory resource. + @param DeviceHandle The device handle for which the memory resource + is being allocated. + + @retval EFI_INVALID_PARAMETER GcdAllocateType is invalid. + @retval EFI_INVALID_PARAMETER GcdMemoryType is invalid. + @retval EFI_INVALID_PARAMETER Length is zero. + @retval EFI_INVALID_PARAMETER BaseAddress is NULL. + @retval EFI_INVALID_PARAMETER ImageHandle is NULL. + @retval EFI_NOT_FOUND The memory resource request could not be satisfied. + No descriptor contains the desired space. + @retval EFI_OUT_OF_RESOURCES There are not enough system resources to allocate the memory + resource from the global coherency domain of the processor. + @retval EFI_SUCCESS The memory resource was allocated from the global coherency + domain of the processor. + + +**/ +typedef +EFI_STATUS +(EFIAPI *EFI_ALLOCATE_MEMORY_SPACE)( + IN EFI_GCD_ALLOCATE_TYPE GcdAllocateType, + IN EFI_GCD_MEMORY_TYPE GcdMemoryType, + IN UINTN Alignment, + IN UINT64 Length, + IN OUT EFI_PHYSICAL_ADDRESS *BaseAddress, + IN EFI_HANDLE ImageHandle, + IN EFI_HANDLE DeviceHandle OPTIONAL + ); + +/** + Frees nonexistent memory, reserved memory, system memory, or memory-mapped + I/O resources from the global coherency domain of the processor. + + @param BaseAddress The physical address that is the start address of the memory resource being freed. + @param Length The size in bytes of the memory resource range that is being freed. + + @retval EFI_SUCCESS The memory resource was freed from the global coherency domain of + the processor. + @retval EFI_INVALID_PARAMETER Length is zero. + @retval EFI_UNSUPPORTED The processor does not support one or more bytes of the memory + resource range specified by BaseAddress and Length. + @retval EFI_NOT_FOUND The memory resource range specified by BaseAddress and + Length was not allocated with previous calls to AllocateMemorySpace(). + @retval EFI_OUT_OF_RESOURCES There are not enough system resources to free the memory resource + from the global coherency domain of the processor. + +**/ +typedef +EFI_STATUS +(EFIAPI *EFI_FREE_MEMORY_SPACE)( + IN EFI_PHYSICAL_ADDRESS BaseAddress, + IN UINT64 Length + ); + +/** + Removes reserved memory, system memory, or memory-mapped I/O resources from + the global coherency domain of the processor. + + @param BaseAddress The physical address that is the start address of the memory resource being removed. + @param Length The size in bytes of the memory resource that is being removed. + + @retval EFI_SUCCESS The memory resource was removed from the global coherency + domain of the processor. + @retval EFI_INVALID_PARAMETER Length is zero. + @retval EFI_UNSUPPORTED The processor does not support one or more bytes of the memory + resource range specified by BaseAddress and Length. + @retval EFI_NOT_FOUND One or more bytes of the memory resource range specified by + BaseAddress and Length was not added with previous calls to + AddMemorySpace(). + @retval EFI_ACCESS_DEFINED One or more bytes of the memory resource range specified by + BaseAddress and Length has been allocated with AllocateMemorySpace(). + @retval EFI_OUT_OF_RESOURCES There are not enough system resources to remove the memory + resource from the global coherency domain of the processor. + +**/ +typedef +EFI_STATUS +(EFIAPI *EFI_REMOVE_MEMORY_SPACE)( + IN EFI_PHYSICAL_ADDRESS BaseAddress, + IN UINT64 Length + ); + +/** + Retrieves the descriptor for a memory region containing a specified address. + + @param BaseAddress The physical address that is the start address of a memory region. + @param Descriptor A pointer to a caller allocated descriptor. + + @retval EFI_SUCCESS The descriptor for the memory resource region containing + BaseAddress was returned in Descriptor. + @retval EFI_INVALID_PARAMETER Descriptor is NULL. + @retval EFI_NOT_FOUND A memory resource range containing BaseAddress was not found. + +**/ +typedef +EFI_STATUS +(EFIAPI *EFI_GET_MEMORY_SPACE_DESCRIPTOR)( + IN EFI_PHYSICAL_ADDRESS BaseAddress, + OUT EFI_GCD_MEMORY_SPACE_DESCRIPTOR *Descriptor + ); + +/** + Modifies the attributes for a memory region in the global coherency domain of the + processor. + + @param BaseAddress The physical address that is the start address of a memory region. + @param Length The size in bytes of the memory region. + @param Attributes The bit mask of attributes to set for the memory region. + + @retval EFI_SUCCESS The attributes were set for the memory region. + @retval EFI_INVALID_PARAMETER Length is zero. + @retval EFI_UNSUPPORTED The processor does not support one or more bytes of the memory + resource range specified by BaseAddress and Length. + @retval EFI_UNSUPPORTED The bit mask of attributes is not support for the memory resource + range specified by BaseAddress and Length. + @retval EFI_ACCESS_DEFINED The attributes for the memory resource range specified by + BaseAddress and Length cannot be modified. + @retval EFI_OUT_OF_RESOURCES There are not enough system resources to modify the attributes of + the memory resource range. + +**/ +typedef +EFI_STATUS +(EFIAPI *EFI_SET_MEMORY_SPACE_ATTRIBUTES)( + IN EFI_PHYSICAL_ADDRESS BaseAddress, + IN UINT64 Length, + IN UINT64 Attributes + ); + +/** + Returns a map of the memory resources in the global coherency domain of the + processor. + + @param NumberOfDescriptors A pointer to number of descriptors returned in the MemorySpaceMap buffer. + @param MemorySpaceMap A pointer to the array of EFI_GCD_MEMORY_SPACE_DESCRIPTORs. + + @retval EFI_SUCCESS The memory space map was returned in the MemorySpaceMap + buffer, and the number of descriptors in MemorySpaceMap was + returned in NumberOfDescriptors. + @retval EFI_INVALID_PARAMETER NumberOfDescriptors is NULL. + @retval EFI_INVALID_PARAMETER MemorySpaceMap is NULL. + @retval EFI_OUT_OF_RESOURCES There are not enough resources to allocate MemorySpaceMap. + +**/ +typedef +EFI_STATUS +(EFIAPI *EFI_GET_MEMORY_SPACE_MAP)( + OUT UINTN *NumberOfDescriptors, + OUT EFI_GCD_MEMORY_SPACE_DESCRIPTOR **MemorySpaceMap + ); + +/** + Adds reserved I/O or I/O resources to the global coherency domain of the processor. + + @param GcdIoType The type of I/O resource being added. + @param BaseAddress The physical address that is the start address of the I/O resource being added. + @param Length The size in bytes of the I/O resource that is being added. + + @retval EFI_SUCCESS The I/O resource was added to the global coherency domain of + the processor. + @retval EFI_INVALID_PARAMETER GcdIoType is invalid. + @retval EFI_INVALID_PARAMETER Length is zero. + @retval EFI_OUT_OF_RESOURCES There are not enough system resources to add the I/O resource to + the global coherency domain of the processor. + @retval EFI_UNSUPPORTED The processor does not support one or more bytes of the I/O + resource range specified by BaseAddress and Length. + @retval EFI_ACCESS_DENIED One or more bytes of the I/O resource range specified by + BaseAddress and Length conflicts with an I/O resource + range that was previously added to the global coherency domain + of the processor. + @retval EFI_ACCESS_DENIED One or more bytes of the I/O resource range specified by + BaseAddress and Length was allocated in a prior call to + AllocateIoSpace(). + +**/ +typedef +EFI_STATUS +(EFIAPI *EFI_ADD_IO_SPACE)( + IN EFI_GCD_IO_TYPE GcdIoType, + IN EFI_PHYSICAL_ADDRESS BaseAddress, + IN UINT64 Length + ); + +/** + Allocates nonexistent I/O, reserved I/O, or I/O resources from the global coherency + domain of the processor. + + @param GcdAllocateType The type of allocation to perform. + @param GcdIoType The type of I/O resource being allocated. + @param Alignment The log base 2 of the boundary that BaseAddress must be aligned on output. + @param Length The size in bytes of the I/O resource range that is being allocated. + @param BaseAddress A pointer to a physical address. + @param Imagehandle The image handle of the agent that is allocating the I/O resource. + @param DeviceHandle The device handle for which the I/O resource is being allocated. + + @retval EFI_SUCCESS The I/O resource was allocated from the global coherency domain + of the processor. + @retval EFI_INVALID_PARAMETER GcdAllocateType is invalid. + @retval EFI_INVALID_PARAMETER GcdIoType is invalid. + @retval EFI_INVALID_PARAMETER Length is zero. + @retval EFI_INVALID_PARAMETER BaseAddress is NULL. + @retval EFI_INVALID_PARAMETER ImageHandle is NULL. + @retval EFI_OUT_OF_RESOURCES There are not enough system resources to allocate the I/O + resource from the global coherency domain of the processor. + @retval EFI_NOT_FOUND The I/O resource request could not be satisfied. + +**/ +typedef +EFI_STATUS +(EFIAPI *EFI_ALLOCATE_IO_SPACE)( + IN EFI_GCD_ALLOCATE_TYPE GcdAllocateType, + IN EFI_GCD_IO_TYPE GcdIoType, + IN UINTN Alignment, + IN UINT64 Length, + IN OUT EFI_PHYSICAL_ADDRESS *BaseAddress, + IN EFI_HANDLE ImageHandle, + IN EFI_HANDLE DeviceHandle OPTIONAL + ); + +/** + Frees nonexistent I/O, reserved I/O, or I/O resources from the global coherency + domain of the processor. + + @param BaseAddress The physical address that is the start address of the I/O resource being freed. + @param Length The size in bytes of the I/O resource range that is being freed. + + @retval EFI_SUCCESS The I/O resource was freed from the global coherency domain of the + processor. + @retval EFI_INVALID_PARAMETER Length is zero. + @retval EFI_UNSUPPORTED The processor does not support one or more bytes of the I/O resource + range specified by BaseAddress and Length. + @retval EFI_NOT_FOUND The I/O resource range specified by BaseAddress and Length + was not allocated with previous calls to AllocateIoSpace(). + @retval EFI_OUT_OF_RESOURCES There are not enough system resources to free the I/O resource from + the global coherency domain of the processor. + +**/ +typedef +EFI_STATUS +(EFIAPI *EFI_FREE_IO_SPACE)( + IN EFI_PHYSICAL_ADDRESS BaseAddress, + IN UINT64 Length + ); + +/** + Removes reserved I/O or I/O resources from the global coherency domain of the + processor. + + @param BaseAddress A pointer to a physical address that is the start address of the I/O resource being + removed. + @param Length The size in bytes of the I/O resource that is being removed. + + @retval EFI_SUCCESS The I/O resource was removed from the global coherency domain + of the processor. + @retval EFI_INVALID_PARAMETER Length is zero. + @retval EFI_UNSUPPORTED The processor does not support one or more bytes of the I/O + resource range specified by BaseAddress and Length. + @retval EFI_NOT_FOUND One or more bytes of the I/O resource range specified by + BaseAddress and Length was not added with previous + calls to AddIoSpace(). + @retval EFI_ACCESS_DENIED One or more bytes of the I/O resource range specified by + BaseAddress and Length has been allocated with + AllocateIoSpace(). + @retval EFI_OUT_OF_RESOURCES There are not enough system resources to remove the I/O + resource from the global coherency domain of the processor. + +**/ +typedef +EFI_STATUS +(EFIAPI *EFI_REMOVE_IO_SPACE)( + IN EFI_PHYSICAL_ADDRESS BaseAddress, + IN UINT64 Length + ); + +/** + Retrieves the descriptor for an I/O region containing a specified address. + + @param BaseAddress The physical address that is the start address of an I/O region. + @param Descriptor A pointer to a caller allocated descriptor. + + @retval EFI_SUCCESS The descriptor for the I/O resource region containing + BaseAddress was returned in Descriptor. + @retval EFI_INVALID_PARAMETER Descriptor is NULL. + @retval EFI_NOT_FOUND An I/O resource range containing BaseAddress was not found. + +**/ +typedef +EFI_STATUS +(EFIAPI *EFI_GET_IO_SPACE_DESCRIPTOR)( + IN EFI_PHYSICAL_ADDRESS BaseAddress, + OUT EFI_GCD_IO_SPACE_DESCRIPTOR *Descriptor + ); + +/** + Returns a map of the I/O resources in the global coherency domain of the processor. + + @param NumberOfDescriptors A pointer to number of descriptors returned in the IoSpaceMap buffer. + @param MemorySpaceMap A pointer to the array of EFI_GCD_IO_SPACE_DESCRIPTORs. + + @retval EFI_SUCCESS The I/O space map was returned in the IoSpaceMap buffer, and + the number of descriptors in IoSpaceMap was returned in + NumberOfDescriptors. + @retval EFI_INVALID_PARAMETER NumberOfDescriptors is NULL. + @retval EFI_INVALID_PARAMETER IoSpaceMap is NULL. + @retval EFI_OUT_OF_RESOURCES There are not enough resources to allocate IoSpaceMap. + + +**/ +typedef +EFI_STATUS +(EFIAPI *EFI_GET_IO_SPACE_MAP)( + OUT UINTN *NumberOfDescriptors, + OUT EFI_GCD_IO_SPACE_DESCRIPTOR **IoSpaceMap + ); + + + +/** + Loads and executed DXE drivers from firmware volumes. + + The Dispatch() function searches for DXE drivers in firmware volumes that have been + installed since the last time the Dispatch() service was called. It then evaluates + the dependency expressions of all the DXE drivers and loads and executes those DXE + drivers whose dependency expression evaluate to TRUE. This service must interact with + the Security Architectural Protocol to authenticate DXE drivers before they are executed. + This process is continued until no more DXE drivers can be executed. + + @retval EFI_SUCCESS One or more DXE driver were dispatched. + @retval EFI_NOT_FOUND No DXE drivers were dispatched. + @retval EFI_ALREADY_STARTED An attempt is being made to start the DXE Dispatcher recursively. + Thus no action was taken. + +**/ +typedef +EFI_STATUS +(EFIAPI *EFI_DISPATCH)( + VOID + ); + +/** + Clears the Schedule on Request (SOR) flag for a component that is stored in a firmware volume. + + @param FirmwareVolumeHandle The handle of the firmware volume that contains the file specified by FileName. + @param FileName A pointer to the name of the file in a firmware volume. + + @retval EFI_SUCCESS The DXE driver was found and its SOR bit was cleared. + @retval EFI_NOT_FOUND The DXE driver does not exist, or the DXE driver exists and its SOR + bit is not set. + +**/ +typedef +EFI_STATUS +(EFIAPI *EFI_SCHEDULE)( + IN EFI_HANDLE FirmwareVolumeHandle, + IN CONST EFI_GUID *FileName + ); + +/** + Promotes a file stored in a firmware volume from the untrusted to the trusted state. + + @param FirmwareVolumeHandle The handle of the firmware volume that contains the file specified by FileName. + @param DriverName A pointer to the name of the file in a firmware volume. + + @return Status of promoting FFS from untrusted to trusted + state. + @retval EFI_NOT_FOUND The file was not found in the untrusted state. + +**/ +typedef +EFI_STATUS +(EFIAPI *EFI_TRUST)( + IN EFI_HANDLE FirmwareVolumeHandle, + IN CONST EFI_GUID *FileName + ); + +/** + Creates a firmware volume handle for a firmware volume that is present in system memory. + + @param FirmwareVolumeHeader A pointer to the header of the firmware volume. + @param Size The size, in bytes, of the firmware volume. + @param FirmwareVolumeHandle On output, a pointer to the created handle. + + @retval EFI_SUCCESS The EFI_FIRMWARE_VOLUME_PROTOCOL and + EFI_DEVICE_PATH_PROTOCOL were installed onto + FirmwareVolumeHandle for the firmware volume described + by FirmwareVolumeHeader and Size. + @retval EFI_VOLUME_CORRUPTED The firmware volume described by FirmwareVolumeHeader + and Size is corrupted. + @retval EFI_OUT_OF_RESOURCES There are not enough system resources available to produce the + EFI_FIRMWARE_VOLUME_PROTOCOL and EFI_DEVICE_PATH_PROTOCOL + for the firmware volume described by FirmwareVolumeHeader and Size. + +**/ +typedef +EFI_STATUS +(EFIAPI *EFI_PROCESS_FIRMWARE_VOLUME)( + IN CONST VOID *FirmwareVolumeHeader, + IN UINTN Size, + OUT EFI_HANDLE *FirmwareVolumeHandle + ); + +// +// DXE Services Table +// +#define DXE_SERVICES_SIGNATURE 0x565245535f455844ULL +#define DXE_SERVICES_REVISION ((1<<16) | (00)) + +typedef struct { + EFI_TABLE_HEADER Hdr; + + // + // Global Coherency Domain Services + // + EFI_ADD_MEMORY_SPACE AddMemorySpace; + EFI_ALLOCATE_MEMORY_SPACE AllocateMemorySpace; + EFI_FREE_MEMORY_SPACE FreeMemorySpace; + EFI_REMOVE_MEMORY_SPACE RemoveMemorySpace; + EFI_GET_MEMORY_SPACE_DESCRIPTOR GetMemorySpaceDescriptor; + EFI_SET_MEMORY_SPACE_ATTRIBUTES SetMemorySpaceAttributes; + EFI_GET_MEMORY_SPACE_MAP GetMemorySpaceMap; + EFI_ADD_IO_SPACE AddIoSpace; + EFI_ALLOCATE_IO_SPACE AllocateIoSpace; + EFI_FREE_IO_SPACE FreeIoSpace; + EFI_REMOVE_IO_SPACE RemoveIoSpace; + EFI_GET_IO_SPACE_DESCRIPTOR GetIoSpaceDescriptor; + EFI_GET_IO_SPACE_MAP GetIoSpaceMap; + + // + // Dispatcher Services + // + EFI_DISPATCH Dispatch; + EFI_SCHEDULE Schedule; + EFI_TRUST Trust; + // + // Service to process a single firmware volume found in a capsule + // + EFI_PROCESS_FIRMWARE_VOLUME ProcessFirmwareVolume; +} DXE_SERVICES; + +typedef DXE_SERVICES EFI_DXE_SERVICES; + +#endif diff --git a/gpxe/src/include/gpxe/efi/Pi/PiFirmwareFile.h b/gpxe/src/include/gpxe/efi/Pi/PiFirmwareFile.h new file mode 100644 index 00000000..be6f8bd2 --- /dev/null +++ b/gpxe/src/include/gpxe/efi/Pi/PiFirmwareFile.h @@ -0,0 +1,242 @@ +/** @file + The firmware file related definitions in PI. + + Copyright (c) 2006 - 2008, Intel Corporation + All rights reserved. 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: + PI Version 1.0 + +**/ + + +#ifndef __PI_FIRMWARE_FILE_H__ +#define __PI_FIRMWARE_FILE_H__ + +#include <gpxe/efi/ProcessorBind.h> + +#pragma pack(1) +/// +/// Used to verify the integrity of the file. +/// +typedef union { + struct { + UINT8 Header; + UINT8 File; + } Checksum; + UINT16 Checksum16; +} EFI_FFS_INTEGRITY_CHECK; + +typedef UINT8 EFI_FV_FILETYPE; +typedef UINT8 EFI_FFS_FILE_ATTRIBUTES; +typedef UINT8 EFI_FFS_FILE_STATE; + +/// +/// File Types Definitions +/// +#define EFI_FV_FILETYPE_ALL 0x00 +#define EFI_FV_FILETYPE_RAW 0x01 +#define EFI_FV_FILETYPE_FREEFORM 0x02 +#define EFI_FV_FILETYPE_SECURITY_CORE 0x03 +#define EFI_FV_FILETYPE_PEI_CORE 0x04 +#define EFI_FV_FILETYPE_DXE_CORE 0x05 +#define EFI_FV_FILETYPE_PEIM 0x06 +#define EFI_FV_FILETYPE_DRIVER 0x07 +#define EFI_FV_FILETYPE_COMBINED_PEIM_DRIVER 0x08 +#define EFI_FV_FILETYPE_APPLICATION 0x09 +#define EFI_FV_FILETYPE_FIRMWARE_VOLUME_IMAGE 0x0B +#define EFI_FV_FILETYPE_OEM_MIN 0xc0 +#define EFI_FV_FILETYPE_OEM_MAX 0xdf +#define EFI_FV_FILETYPE_DEBUG_MIN 0xe0 +#define EFI_FV_FILETYPE_DEBUG_MAX 0xef +#define EFI_FV_FILETYPE_FFS_MIN 0xf0 +#define EFI_FV_FILETYPE_FFS_MAX 0xff +#define EFI_FV_FILETYPE_FFS_PAD 0xf0 +/// +/// FFS File Attributes. +/// +#define FFS_ATTRIB_FIXED 0x04 +#define FFS_ATTRIB_DATA_ALIGNMENT 0x38 +#define FFS_ATTRIB_CHECKSUM 0x40 + +/// +/// FFS File State Bits. +/// +#define EFI_FILE_HEADER_CONSTRUCTION 0x01 +#define EFI_FILE_HEADER_VALID 0x02 +#define EFI_FILE_DATA_VALID 0x04 +#define EFI_FILE_MARKED_FOR_UPDATE 0x08 +#define EFI_FILE_DELETED 0x10 +#define EFI_FILE_HEADER_INVALID 0x20 + + +/// +/// Each file begins with the header that describe the +/// contents and state of the files. +/// +typedef struct { + EFI_GUID Name; + EFI_FFS_INTEGRITY_CHECK IntegrityCheck; + EFI_FV_FILETYPE Type; + EFI_FFS_FILE_ATTRIBUTES Attributes; + UINT8 Size[3]; + EFI_FFS_FILE_STATE State; +} EFI_FFS_FILE_HEADER; + + +typedef UINT8 EFI_SECTION_TYPE; + +/// +/// Pseudo type. It is +/// used as a wild card when retrieving sections. The section +/// type EFI_SECTION_ALL matches all section types. +/// +#define EFI_SECTION_ALL 0x00 + +/// +/// Encapsulation section Type values +/// +#define EFI_SECTION_COMPRESSION 0x01 + +#define EFI_SECTION_GUID_DEFINED 0x02 + +/// +/// Leaf section Type values +/// +#define EFI_SECTION_PE32 0x10 +#define EFI_SECTION_PIC 0x11 +#define EFI_SECTION_TE 0x12 +#define EFI_SECTION_DXE_DEPEX 0x13 +#define EFI_SECTION_VERSION 0x14 +#define EFI_SECTION_USER_INTERFACE 0x15 +#define EFI_SECTION_COMPATIBILITY16 0x16 +#define EFI_SECTION_FIRMWARE_VOLUME_IMAGE 0x17 +#define EFI_SECTION_FREEFORM_SUBTYPE_GUID 0x18 +#define EFI_SECTION_RAW 0x19 +#define EFI_SECTION_PEI_DEPEX 0x1B + +/// +/// Common section header +/// +typedef struct { + UINT8 Size[3]; + EFI_SECTION_TYPE Type; +} EFI_COMMON_SECTION_HEADER; + +/// +/// Leaf section type that contains an +/// IA-32 16-bit executable image. +/// +typedef EFI_COMMON_SECTION_HEADER EFI_COMPATIBILITY16_SECTION; + +/// +/// CompressionType of EFI_COMPRESSION_SECTION. +/// +#define EFI_NOT_COMPRESSED 0x00 +#define EFI_STANDARD_COMPRESSION 0x01 +/// +/// An encapsulation section type in which the +/// section data is compressed. +/// +typedef struct { + EFI_COMMON_SECTION_HEADER CommonHeader; + UINT32 UncompressedLength; + UINT8 CompressionType; +} EFI_COMPRESSION_SECTION; + +/// +/// Leaf section which could be used to determine the dispatch order of DXEs. +/// +typedef EFI_COMMON_SECTION_HEADER EFI_DXE_DEPEX_SECTION; + +/// +/// Leaf section which contains a PI FV. +/// +typedef EFI_COMMON_SECTION_HEADER EFI_FIRMWARE_VOLUME_IMAGE_SECTION; + +/// +/// Leaf section which contains a single GUID. +/// +typedef struct { + EFI_COMMON_SECTION_HEADER CommonHeader; + EFI_GUID SubTypeGuid; +} EFI_FREEFORM_SUBTYPE_GUID_SECTION; + +/// +/// Attributes of EFI_GUID_DEFINED_SECTION +/// +#define EFI_GUIDED_SECTION_PROCESSING_REQUIRED 0x01 +#define EFI_GUIDED_SECTION_AUTH_STATUS_VALID 0x02 +/// +/// Leaf section which is encapsulation defined by specific GUID +/// +typedef struct { + EFI_COMMON_SECTION_HEADER CommonHeader; + EFI_GUID SectionDefinitionGuid; + UINT16 DataOffset; + UINT16 Attributes; +} EFI_GUID_DEFINED_SECTION; + +/// +/// Leaf section which contains PE32+ image. +/// +typedef EFI_COMMON_SECTION_HEADER EFI_PE32_SECTION; + + +/// +/// Leaf section which used to determine the dispatch order of PEIMs. +/// +typedef EFI_COMMON_SECTION_HEADER EFI_PEI_DEPEX_SECTION; + +/// +/// Leaf section which constains the position-independent-code image. +/// +typedef EFI_COMMON_SECTION_HEADER EFI_TE_SECTION; + +/// +/// Leaf section which contains an array of zero or more bytes. +/// +typedef EFI_COMMON_SECTION_HEADER EFI_RAW_SECTION; + +/// +/// Leaf section which contains a unicode string that +/// is human readable file name. +/// +typedef struct { + EFI_COMMON_SECTION_HEADER CommonHeader; + + /// + /// Array of unicode string. + /// + CHAR16 FileNameString[1]; +} EFI_USER_INTERFACE_SECTION; + + +/// +/// Leaf section which contains a numeric build number and +/// an optional unicode string that represents the file revision. +/// +typedef struct { + EFI_COMMON_SECTION_HEADER CommonHeader; + UINT16 BuildNumber; + + /// + /// Array of unicode string. + /// + CHAR16 VersionString[1]; +} EFI_VERSION_SECTION; + + +#define SECTION_SIZE(SectionHeaderPtr) \ + ((UINT32) (*((UINT32 *) ((EFI_COMMON_SECTION_HEADER *) SectionHeaderPtr)->Size) & 0x00ffffff)) + +#pragma pack() + +#endif + diff --git a/gpxe/src/include/gpxe/efi/Pi/PiFirmwareVolume.h b/gpxe/src/include/gpxe/efi/Pi/PiFirmwareVolume.h new file mode 100644 index 00000000..277b7045 --- /dev/null +++ b/gpxe/src/include/gpxe/efi/Pi/PiFirmwareVolume.h @@ -0,0 +1,154 @@ +/** @file + The firmware volume related definitions in PI. + + Copyright (c) 2006 - 2008, Intel Corporation + All rights reserved. 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: + PI Version 1.0 + +**/ + +#ifndef __PI_FIRMWAREVOLUME_H__ +#define __PI_FIRMWAREVOLUME_H__ + +#include <gpxe/efi/ProcessorBind.h> + +/// +/// EFI_FV_FILE_ATTRIBUTES +/// +typedef UINT32 EFI_FV_FILE_ATTRIBUTES; + +// +// Value of EFI_FV_FILE_ATTRIBUTES. +// +#define EFI_FV_FILE_ATTRIB_ALIGNMENT 0x0000001F +#define EFI_FV_FILE_ATTRIB_FIXED 0x00000100 +#define EFI_FV_FILE_ATTRIB_MEMORY_MAPPED 0x00000200 + +/// +/// type of EFI FVB attribute +/// +typedef UINT32 EFI_FVB_ATTRIBUTES_2; + +// +// Attributes bit definitions +// +#define EFI_FVB2_READ_DISABLED_CAP 0x00000001 +#define EFI_FVB2_READ_ENABLED_CAP 0x00000002 +#define EFI_FVB2_READ_STATUS 0x00000004 +#define EFI_FVB2_WRITE_DISABLED_CAP 0x00000008 +#define EFI_FVB2_WRITE_ENABLED_CAP 0x00000010 +#define EFI_FVB2_WRITE_STATUS 0x00000020 +#define EFI_FVB2_LOCK_CAP 0x00000040 +#define EFI_FVB2_LOCK_STATUS 0x00000080 +#define EFI_FVB2_STICKY_WRITE 0x00000200 +#define EFI_FVB2_MEMORY_MAPPED 0x00000400 +#define EFI_FVB2_ERASE_POLARITY 0x00000800 +#define EFI_FVB2_READ_LOCK_CAP 0x00001000 +#define EFI_FVB2_READ_LOCK_STATUS 0x00002000 +#define EFI_FVB2_WRITE_LOCK_CAP 0x00004000 +#define EFI_FVB2_WRITE_LOCK_STATUS 0x00008000 +#define EFI_FVB2_ALIGNMENT 0x001F0000 +#define EFI_FVB2_ALIGNMENT_1 0x00000000 +#define EFI_FVB2_ALIGNMENT_2 0x00010000 +#define EFI_FVB2_ALIGNMENT_4 0x00020000 +#define EFI_FVB2_ALIGNMENT_8 0x00030000 +#define EFI_FVB2_ALIGNMENT_16 0x00040000 +#define EFI_FVB2_ALIGNMENT_32 0x00050000 +#define EFI_FVB2_ALIGNMENT_64 0x00060000 +#define EFI_FVB2_ALIGNMENT_128 0x00070000 +#define EFI_FVB2_ALIGNMENT_256 0x00080000 +#define EFI_FVB2_ALIGNMENT_512 0x00090000 +#define EFI_FVB2_ALIGNMENT_1K 0x000A0000 +#define EFI_FVB2_ALIGNMENT_2K 0x000B0000 +#define EFI_FVB2_ALIGNMENT_4K 0x000C0000 +#define EFI_FVB2_ALIGNMENT_8K 0x000D0000 +#define EFI_FVB2_ALIGNMENT_16K 0x000E0000 +#define EFI_FVB2_ALIGNMENT_32K 0x000F0000 +#define EFI_FVB2_ALIGNMENT_64K 0x00100000 +#define EFI_FVB2_ALIGNMENT_128K 0x00110000 +#define EFI_FVB2_ALIGNMENT_256K 0x00120000 +#define EFI_FVB2_ALIGNMNET_512K 0x00130000 +#define EFI_FVB2_ALIGNMENT_1M 0x00140000 +#define EFI_FVB2_ALIGNMENT_2M 0x00150000 +#define EFI_FVB2_ALIGNMENT_4M 0x00160000 +#define EFI_FVB2_ALIGNMENT_8M 0x00170000 +#define EFI_FVB2_ALIGNMENT_16M 0x00180000 +#define EFI_FVB2_ALIGNMENT_32M 0x00190000 +#define EFI_FVB2_ALIGNMENT_64M 0x001A0000 +#define EFI_FVB2_ALIGNMENT_128M 0x001B0000 +#define EFI_FVB2_ALIGNMENT_256M 0x001C0000 +#define EFI_FVB2_ALIGNMENT_512M 0x001D0000 +#define EFI_FVB2_ALIGNMENT_1G 0x001E0000 +#define EFI_FVB2_ALIGNMENT_2G 0x001F0000 + + +typedef struct { + UINT32 NumBlocks; + UINT32 Length; +} EFI_FV_BLOCK_MAP_ENTRY; + +/// +/// Describes the features and layout of the firmware volume. +/// +typedef struct { + UINT8 ZeroVector[16]; + EFI_GUID FileSystemGuid; + UINT64 FvLength; + UINT32 Signature; + EFI_FVB_ATTRIBUTES_2 Attributes; + UINT16 HeaderLength; + UINT16 Checksum; + UINT16 ExtHeaderOffset; + UINT8 Reserved[1]; + UINT8 Revision; + EFI_FV_BLOCK_MAP_ENTRY BlockMap[1]; +} EFI_FIRMWARE_VOLUME_HEADER; + +#define EFI_FVH_SIGNATURE EFI_SIGNATURE_32 ('_', 'F', 'V', 'H') + +/// +/// Firmware Volume Header Revision definition +/// +#define EFI_FVH_REVISION 0x02 + +/// +/// Extension header pointed by ExtHeaderOffset of volume header. +/// +typedef struct { + EFI_GUID FvName; + UINT32 ExtHeaderSize; +} EFI_FIRMWARE_VOLUME_EXT_HEADER; + +/// +/// Entry struture for describing FV extension header +/// +typedef struct { + UINT16 ExtEntrySize; + UINT16 ExtEntryType; +} EFI_FIRMWARE_VOLUME_EXT_ENTRY; + +#define EFI_FV_EXT_TYPE_OEM_TYPE 0x01 +/// +/// This extension header provides a mapping between a GUID and an OEM file type. +/// +typedef struct { + EFI_FIRMWARE_VOLUME_EXT_ENTRY Hdr; + UINT32 TypeMask; + + // + // Array of GUIDs. + // Each GUID represents an OEM file type. + // + EFI_GUID Types[1]; +} EFI_FIRMWARE_VOLUME_EXT_ENTRY_OEM_TYPE; + + +#endif diff --git a/gpxe/src/include/gpxe/efi/Pi/PiHob.h b/gpxe/src/include/gpxe/efi/Pi/PiHob.h new file mode 100644 index 00000000..0c8df1f2 --- /dev/null +++ b/gpxe/src/include/gpxe/efi/Pi/PiHob.h @@ -0,0 +1,295 @@ +/** @file + HOB related definitions in PI. + + Copyright (c) 2006 - 2008, Intel Corporation + All rights reserved. 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: + PI Version 1.0 + +**/ + +#ifndef __PI_HOB_H__ +#define __PI_HOB_H__ + +#include <gpxe/efi/ProcessorBind.h> +#include <gpxe/efi/Pi/PiBootMode.h> +#include <gpxe/efi/Uefi/UefiBaseType.h> +#include <gpxe/efi/Uefi/UefiMultiPhase.h> + +// +// HobType of EFI_HOB_GENERIC_HEADER. +// +#define EFI_HOB_TYPE_HANDOFF 0x0001 +#define EFI_HOB_TYPE_MEMORY_ALLOCATION 0x0002 +#define EFI_HOB_TYPE_RESOURCE_DESCRIPTOR 0x0003 +#define EFI_HOB_TYPE_GUID_EXTENSION 0x0004 +#define EFI_HOB_TYPE_FV 0x0005 +#define EFI_HOB_TYPE_CPU 0x0006 +#define EFI_HOB_TYPE_MEMORY_POOL 0x0007 +#define EFI_HOB_TYPE_FV2 0x0009 +#define EFI_HOB_TYPE_LOAD_PEIM 0x000A +#define EFI_HOB_TYPE_UNUSED 0xFFFE +#define EFI_HOB_TYPE_END_OF_HOB_LIST 0xFFFF + +/// +/// Describes the format and size of the data inside the HOB. +/// All HOBs must contain this generic HOB header. +/// +typedef struct { + UINT16 HobType; + UINT16 HobLength; + UINT32 Reserved; +} EFI_HOB_GENERIC_HEADER; + + +/// +/// Value of version ofinEFI_HOB_HANDOFF_INFO_TABLE. +/// +#define EFI_HOB_HANDOFF_TABLE_VERSION 0x0009 + +/// +/// Contains general state information used by the HOB producer phase. +/// This HOB must be the first one in the HOB list. +/// +typedef struct { + EFI_HOB_GENERIC_HEADER Header; + UINT32 Version; + EFI_BOOT_MODE BootMode; + EFI_PHYSICAL_ADDRESS EfiMemoryTop; + EFI_PHYSICAL_ADDRESS EfiMemoryBottom; + EFI_PHYSICAL_ADDRESS EfiFreeMemoryTop; + EFI_PHYSICAL_ADDRESS EfiFreeMemoryBottom; + EFI_PHYSICAL_ADDRESS EfiEndOfHobList; +} EFI_HOB_HANDOFF_INFO_TABLE; + +/// +/// EFI_HOB_MEMORY_ALLOCATION_HEADER describes the +/// various attributes of the logical memory allocation. The type field will be used for +/// subsequent inclusion in the UEFI memory map. +/// +typedef struct { + /// + /// A GUID that defines the memory allocation region's type and purpose, as well as + /// other fields within the memory allocation HOB. This GUID is used to define the + /// additional data within the HOB that may be present for the memory allocation HOB. + /// Type EFI_GUID is defined in InstallProtocolInterface() in the UEFI 2.0 + /// specification. + /// + EFI_GUID Name; + + /// + /// The base address of memory allocated by this HOB. Type + /// EFI_PHYSICAL_ADDRESS is defined in AllocatePages() in the UEFI 2.0 + /// specification. + /// + EFI_PHYSICAL_ADDRESS MemoryBaseAddress; + + /// + /// The length in bytes of memory allocated by this HOB. + /// + UINT64 MemoryLength; + + /// + /// Defines the type of memory allocated by this HOB. The memory type definition + /// follows the EFI_MEMORY_TYPE definition. Type EFI_MEMORY_TYPE is defined + /// in AllocatePages() in the UEFI 2.0 specification. + /// + EFI_MEMORY_TYPE MemoryType; + + /// + /// Padding for Itanium processor family + /// + UINT8 Reserved[4]; +} EFI_HOB_MEMORY_ALLOCATION_HEADER; + +/// +/// Describes all memory ranges used during the HOB producer +/// phase that exist outside the HOB list. This HOB type +/// describes how memory is used, +/// not the physical attributes of memory. +/// +typedef struct { + EFI_HOB_GENERIC_HEADER Header; + EFI_HOB_MEMORY_ALLOCATION_HEADER AllocDescriptor; + // + // Additional data pertaining to the "Name" Guid memory + // may go here. + // +} EFI_HOB_MEMORY_ALLOCATION; + + +/// +/// Describes the memory stack that is produced by the HOB producer +/// phase and upon which all postmemory-installed executable +/// content in the HOB producer phase is executing. +/// +typedef struct { + EFI_HOB_GENERIC_HEADER Header; + EFI_HOB_MEMORY_ALLOCATION_HEADER AllocDescriptor; +} EFI_HOB_MEMORY_ALLOCATION_STACK; + +/// +/// Defines the location of the boot-strap +/// processor (BSP) BSPStore ("Backing Store Pointer Store"). +/// This HOB is valid for the Itanium processor family only +/// register overflow store. +/// +typedef struct { + EFI_HOB_GENERIC_HEADER Header; + EFI_HOB_MEMORY_ALLOCATION_HEADER AllocDescriptor; +} EFI_HOB_MEMORY_ALLOCATION_BSP_STORE; + +/// +/// Defines the location and entry point of the HOB consumer phase. +/// +typedef struct { + EFI_HOB_GENERIC_HEADER Header; + EFI_HOB_MEMORY_ALLOCATION_HEADER MemoryAllocationHeader; + EFI_GUID ModuleName; + EFI_PHYSICAL_ADDRESS EntryPoint; +} EFI_HOB_MEMORY_ALLOCATION_MODULE; + +/// +/// Resource type +/// +typedef UINT32 EFI_RESOURCE_TYPE; + +// +// Value of ResourceType in EFI_HOB_RESOURCE_DESCRIPTOR. +// +#define EFI_RESOURCE_SYSTEM_MEMORY 0x00000000 +#define EFI_RESOURCE_MEMORY_MAPPED_IO 0x00000001 +#define EFI_RESOURCE_IO 0x00000002 +#define EFI_RESOURCE_FIRMWARE_DEVICE 0x00000003 +#define EFI_RESOURCE_MEMORY_MAPPED_IO_PORT 0x00000004 +#define EFI_RESOURCE_MEMORY_RESERVED 0x00000005 +#define EFI_RESOURCE_IO_RESERVED 0x00000006 +#define EFI_RESOURCE_MAX_MEMORY_TYPE 0x00000007 + +/// +/// type of recount attribute type +/// +typedef UINT32 EFI_RESOURCE_ATTRIBUTE_TYPE; + +// +// These types can be ORed together as needed. +// +// The first three enumerations describe settings +// +#define EFI_RESOURCE_ATTRIBUTE_PRESENT 0x00000001 +#define EFI_RESOURCE_ATTRIBUTE_INITIALIZED 0x00000002 +#define EFI_RESOURCE_ATTRIBUTE_TESTED 0x00000004 +// +// The rest of the settings describe capabilities +// +#define EFI_RESOURCE_ATTRIBUTE_SINGLE_BIT_ECC 0x00000008 +#define EFI_RESOURCE_ATTRIBUTE_MULTIPLE_BIT_ECC 0x00000010 +#define EFI_RESOURCE_ATTRIBUTE_ECC_RESERVED_1 0x00000020 +#define EFI_RESOURCE_ATTRIBUTE_ECC_RESERVED_2 0x00000040 +#define EFI_RESOURCE_ATTRIBUTE_READ_PROTECTED 0x00000080 +#define EFI_RESOURCE_ATTRIBUTE_WRITE_PROTECTED 0x00000100 +#define EFI_RESOURCE_ATTRIBUTE_EXECUTION_PROTECTED 0x00000200 +#define EFI_RESOURCE_ATTRIBUTE_UNCACHEABLE 0x00000400 +#define EFI_RESOURCE_ATTRIBUTE_WRITE_COMBINEABLE 0x00000800 +#define EFI_RESOURCE_ATTRIBUTE_WRITE_THROUGH_CACHEABLE 0x00001000 +#define EFI_RESOURCE_ATTRIBUTE_WRITE_BACK_CACHEABLE 0x00002000 +#define EFI_RESOURCE_ATTRIBUTE_16_BIT_IO 0x00004000 +#define EFI_RESOURCE_ATTRIBUTE_32_BIT_IO 0x00008000 +#define EFI_RESOURCE_ATTRIBUTE_64_BIT_IO 0x00010000 +#define EFI_RESOURCE_ATTRIBUTE_UNCACHED_EXPORTED 0x00020000 + +/// +/// Describes the resource properties of all fixed, +/// nonrelocatable resource ranges found on the processor +/// host bus during the HOB producer phase. +/// +typedef struct { + EFI_HOB_GENERIC_HEADER Header; + EFI_GUID Owner; + EFI_RESOURCE_TYPE ResourceType; + EFI_RESOURCE_ATTRIBUTE_TYPE ResourceAttribute; + EFI_PHYSICAL_ADDRESS PhysicalStart; + UINT64 ResourceLength; +} EFI_HOB_RESOURCE_DESCRIPTOR; + +/// +/// Allows writers of executable content in the HOB producer phase to +/// maintain and manage HOBs with specific GUID. +/// +typedef struct { + EFI_HOB_GENERIC_HEADER Header; + EFI_GUID Name; + + /// + /// Guid specific data goes here + /// +} EFI_HOB_GUID_TYPE; + +/// +/// Details the location of firmware volumes that contain firmware files. +/// +typedef struct { + EFI_HOB_GENERIC_HEADER Header; + EFI_PHYSICAL_ADDRESS BaseAddress; + UINT64 Length; +} EFI_HOB_FIRMWARE_VOLUME; + +/// +/// Details the location of a firmware volume which was extracted +/// from a file within another firmware volume. +/// +typedef struct { + EFI_HOB_GENERIC_HEADER Header; + EFI_PHYSICAL_ADDRESS BaseAddress; + UINT64 Length; + EFI_GUID FvName; + EFI_GUID FileName; +} EFI_HOB_FIRMWARE_VOLUME2; + + +/// +/// Describes processor information, such as address space and I/O space capabilities. +/// +typedef struct { + EFI_HOB_GENERIC_HEADER Header; + UINT8 SizeOfMemorySpace; + UINT8 SizeOfIoSpace; + UINT8 Reserved[6]; +} EFI_HOB_CPU; + + +/// +/// Describes pool memory allocations. +/// +typedef struct { + EFI_HOB_GENERIC_HEADER Header; +} EFI_HOB_MEMORY_POOL; + +/// +/// Union of all the possible HOB Types +/// +typedef union { + EFI_HOB_GENERIC_HEADER *Header; + EFI_HOB_HANDOFF_INFO_TABLE *HandoffInformationTable; + EFI_HOB_MEMORY_ALLOCATION *MemoryAllocation; + EFI_HOB_MEMORY_ALLOCATION_BSP_STORE *MemoryAllocationBspStore; + EFI_HOB_MEMORY_ALLOCATION_STACK *MemoryAllocationStack; + EFI_HOB_MEMORY_ALLOCATION_MODULE *MemoryAllocationModule; + EFI_HOB_RESOURCE_DESCRIPTOR *ResourceDescriptor; + EFI_HOB_GUID_TYPE *Guid; + EFI_HOB_FIRMWARE_VOLUME *FirmwareVolume; + EFI_HOB_FIRMWARE_VOLUME2 *FirmwareVolume2; + EFI_HOB_CPU *Cpu; + EFI_HOB_MEMORY_POOL *Pool; + UINT8 *Raw; +} EFI_PEI_HOB_POINTERS; + + +#endif diff --git a/gpxe/src/include/gpxe/efi/Pi/PiMultiPhase.h b/gpxe/src/include/gpxe/efi/Pi/PiMultiPhase.h new file mode 100644 index 00000000..3ab6421f --- /dev/null +++ b/gpxe/src/include/gpxe/efi/Pi/PiMultiPhase.h @@ -0,0 +1,104 @@ +/** @file + Include file matches things in PI for multiple module types. + + Copyright (c) 2006 - 2008, Intel Corporation + All rights reserved. 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: + PI Version 1.0 + +**/ + +#ifndef __PI_MULTIPHASE_H__ +#define __PI_MULTIPHASE_H__ + +#include <gpxe/efi/Uefi/UefiMultiPhase.h> + +#include <gpxe/efi/Pi/PiFirmwareVolume.h> +#include <gpxe/efi/Pi/PiFirmwareFile.h> +#include <gpxe/efi/Pi/PiBootMode.h> + +#include <gpxe/efi/Pi/PiHob.h> +#include <gpxe/efi/Pi/PiDependency.h> + + +#define EFI_NOT_AVAILABLE_YET EFIERR (32) + +/// +/// Status Code Type Definition +/// +typedef UINT32 EFI_STATUS_CODE_TYPE; + +// +// A Status Code Type is made up of the code type and severity +// All values masked by EFI_STATUS_CODE_RESERVED_MASK are +// reserved for use by this specification. +// +#define EFI_STATUS_CODE_TYPE_MASK 0x000000FF +#define EFI_STATUS_CODE_SEVERITY_MASK 0xFF000000 +#define EFI_STATUS_CODE_RESERVED_MASK 0x00FFFF00 + +// +// Definition of code types, all other values masked by +// EFI_STATUS_CODE_TYPE_MASK are reserved for use by +// this specification. +// +#define EFI_PROGRESS_CODE 0x00000001 +#define EFI_ERROR_CODE 0x00000002 +#define EFI_DEBUG_CODE 0x00000003 + +// +// Definitions of severities, all other values masked by +// EFI_STATUS_CODE_SEVERITY_MASK are reserved for use by +// this specification. +// Uncontained errors are major errors that could not contained +// to the specific component that is reporting the error +// For example, if a memory error was not detected early enough, +// the bad data could be consumed by other drivers. +// +#define EFI_ERROR_MINOR 0x40000000 +#define EFI_ERROR_MAJOR 0x80000000 +#define EFI_ERROR_UNRECOVERED 0x90000000 +#define EFI_ERROR_UNCONTAINED 0xa0000000 + +/// +/// Status Code Value Definition +/// +typedef UINT32 EFI_STATUS_CODE_VALUE; + +// +// A Status Code Value is made up of the class, subclass, and +// an operation. +// +#define EFI_STATUS_CODE_CLASS_MASK 0xFF000000 +#define EFI_STATUS_CODE_SUBCLASS_MASK 0x00FF0000 +#define EFI_STATUS_CODE_OPERATION_MASK 0x0000FFFF + +/// +/// Definition of Status Code extended data header. +/// The data will follow HeaderSize bytes from the beginning of +/// the structure and is Size bytes long. +/// +typedef struct { + UINT16 HeaderSize; + UINT16 Size; + EFI_GUID Type; +} EFI_STATUS_CODE_DATA; + + +// +// Bit values for Authentication Status +// +#define EFI_AUTH_STATUS_PLATFORM_OVERRIDE 0x01 +#define EFI_AUTH_STATUS_IMAGE_SIGNED 0x02 +#define EFI_AUTH_STATUS_NOT_TESTED 0x04 +#define EFI_AUTH_STATUS_TEST_FAILED 0x08 +#define EFI_AUTH_STATUS_ALL 0x0f + +#endif diff --git a/gpxe/src/include/gpxe/efi/PiDxe.h b/gpxe/src/include/gpxe/efi/PiDxe.h new file mode 100644 index 00000000..c3263029 --- /dev/null +++ b/gpxe/src/include/gpxe/efi/PiDxe.h @@ -0,0 +1,25 @@ +/** @file + + Root include file for Mde Package DXE_CORE, DXE, SMM, SAL type modules. + +Copyright (c) 2006 - 2007, Intel Corporation +All rights reserved. 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 __PI_DXE_H__ +#define __PI_DXE_H__ + +#include <gpxe/efi/Uefi/UefiBaseType.h> +#include <gpxe/efi/Uefi/UefiSpec.h> + +#include <gpxe/efi/Pi/PiDxeCis.h> + +#endif + diff --git a/gpxe/src/include/gpxe/efi/ProcessorBind.h b/gpxe/src/include/gpxe/efi/ProcessorBind.h new file mode 100644 index 00000000..3dbaf1b8 --- /dev/null +++ b/gpxe/src/include/gpxe/efi/ProcessorBind.h @@ -0,0 +1,14 @@ +/* + * EFI header files rely on having the CPU architecture directory + * present in the search path in order to pick up ProcessorBind.h. We + * use this header file as a quick indirection layer. + * - mcb30 + */ + +#if __i386__ +#include <gpxe/efi/Ia32/ProcessorBind.h> +#endif + +#if __x86_64__ +#include <gpxe/efi/X64/ProcessorBind.h> +#endif diff --git a/gpxe/src/include/gpxe/efi/Protocol/ComponentName2.h b/gpxe/src/include/gpxe/efi/Protocol/ComponentName2.h new file mode 100644 index 00000000..0f010142 --- /dev/null +++ b/gpxe/src/include/gpxe/efi/Protocol/ComponentName2.h @@ -0,0 +1,174 @@ +/** @file + UEFI Component Name 2 Protocol as defined in the UEFI 2.1 specification. + This protocol is used to retrieve user readable names of drivers + and controllers managed by UEFI Drivers. + + Copyright (c) 2006 - 2008, Intel Corporation + All rights reserved. This program and the accompanying materials + are licensed and made available under the terms and conditions of the BSD License + which accompanies this distribution. The full text of the license may be found at + http://opensource.org/licenses/bsd-license.php + + THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, + WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + +**/ + +#ifndef __EFI_COMPONENT_NAME2_H__ +#define __EFI_COMPONENT_NAME2_H__ + +/// +/// Global ID for the Component Name Protocol +/// +#define EFI_COMPONENT_NAME2_PROTOCOL_GUID \ + {0x6a7a5cff, 0xe8d9, 0x4f70, { 0xba, 0xda, 0x75, 0xab, 0x30, 0x25, 0xce, 0x14 } } + +typedef struct _EFI_COMPONENT_NAME2_PROTOCOL EFI_COMPONENT_NAME2_PROTOCOL; + + +/** + Retrieves a Unicode string that is the user readable name of + the EFI Driver. + + @param This A pointer to the + EFI_COMPONENT_NAME2_PROTOCOL instance. + + @param Language A pointer to a Null-terminated ASCII string + array indicating the language. This is the + language of the driver name that the caller + is requesting, and it must match one of the + languages specified in SupportedLanguages. + The number of languages supported by a + driver is up to the driver writer. Language + is specified in RFC 3066 language code + format. + + @param DriverName A pointer to the Unicode string to return. + This Unicode string is the name of the + driver specified by This in the language + specified by Language. + + @retval EFI_SUCCESS The Unicode string for the + Driver specified by This and the + language specified by Language + was returned in DriverName. + + @retval EFI_INVALID_PARAMETER Language is NULL. + + @retval EFI_INVALID_PARAMETER DriverName is NULL. + + @retval EFI_UNSUPPORTED The driver specified by This + does not support the language + specified by Language. + +**/ +typedef +EFI_STATUS +(EFIAPI *EFI_COMPONENT_NAME2_GET_DRIVER_NAME)( + IN EFI_COMPONENT_NAME2_PROTOCOL *This, + IN CHAR8 *Language, + OUT CHAR16 **DriverName + ); + + +/** + Retrieves a Unicode string that is the user readable name of + the controller that is being managed by an EFI Driver. + + @param This A pointer to the + EFI_COMPONENT_NAME2_PROTOCOL instance. + + @param ControllerHandle The handle of a controller that the + driver specified by This is managing. + This handle specifies the controller + whose name is to be returned. + + @param ChildHandle The handle of the child controller to + retrieve the name of. This is an + optional parameter that may be NULL. + It will be NULL for device drivers. + It will also be NULL for a bus + drivers that wish to retrieve the + name of the bus controller. It will + not be NULL for a bus driver that + wishes to retrieve the name of a + child controller. + + @param Language A pointer to a Null-terminated ASCII + string array indicating the language. + This is the language of the driver + name that the caller is requesting, + and it must match one of the + languages specified in + SupportedLanguages. The number of + languages supported by a driver is up + to the driver writer. Language is + specified in RFC 3066 language code + format. + + @param ControllerName A pointer to the Unicode string to + return. This Unicode string is the + name of the controller specified by + ControllerHandle and ChildHandle in + the language specified by Language + from the point of view of the driver + specified by This. + + @retval EFI_SUCCESS The Unicode string for the user + readable name in the language + specified by Language for the + driver specified by This was + returned in DriverName. + + @retval EFI_INVALID_PARAMETER ControllerHandle is not a valid + EFI_HANDLE. + + @retval EFI_INVALID_PARAMETER ChildHandle is not NULL and it + is not a valid EFI_HANDLE. + + @retval EFI_INVALID_PARAMETER Language is NULL. + + @retval EFI_INVALID_PARAMETER ControllerName is NULL. + + @retval EFI_UNSUPPORTED The driver specified by This is + not currently managing the + controller specified by + ControllerHandle and + ChildHandle. + + @retval EFI_UNSUPPORTED The driver specified by This + does not support the language + specified by Language. + +**/ +typedef +EFI_STATUS +(EFIAPI *EFI_COMPONENT_NAME2_GET_CONTROLLER_NAME)( + IN EFI_COMPONENT_NAME2_PROTOCOL *This, + IN EFI_HANDLE ControllerHandle, + IN EFI_HANDLE ChildHandle OPTIONAL, + IN CHAR8 *Language, + OUT CHAR16 **ControllerName + ); + +/// +/// This protocol is used to retrieve user readable names of drivers +/// and controllers managed by UEFI Drivers. +/// +struct _EFI_COMPONENT_NAME2_PROTOCOL { + EFI_COMPONENT_NAME2_GET_DRIVER_NAME GetDriverName; + EFI_COMPONENT_NAME2_GET_CONTROLLER_NAME GetControllerName; + + /// + /// A Null-terminated ASCII string array that contains one or more + /// supported language codes. This is the list of language codes that + /// this protocol supports. The number of languages supported by a + /// driver is up to the driver writer. SupportedLanguages is + /// specified in RFC 3066 format. + /// + CHAR8 *SupportedLanguages; +}; + +extern EFI_GUID gEfiComponentName2ProtocolGuid; + +#endif diff --git a/gpxe/src/include/gpxe/efi/Protocol/Cpu.h b/gpxe/src/include/gpxe/efi/Protocol/Cpu.h new file mode 100644 index 00000000..da3d0fda --- /dev/null +++ b/gpxe/src/include/gpxe/efi/Protocol/Cpu.h @@ -0,0 +1,291 @@ +/** @file + CPU Architectural Protocol as defined in PI spec Volume 2 DXE + + This code abstracts the DXE core from processor implementation details. + + Copyright (c) 2006 - 2008, Intel Corporation + All rights reserved. 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 __ARCH_PROTOCOL_CPU_H__ +#define __ARCH_PROTOCOL_CPU_H__ + +#include <gpxe/efi/Protocol/DebugSupport.h> + +#define EFI_CPU_ARCH_PROTOCOL_GUID \ + { 0x26baccb1, 0x6f42, 0x11d4, {0xbc, 0xe7, 0x0, 0x80, 0xc7, 0x3c, 0x88, 0x81 } } + +typedef struct _EFI_CPU_ARCH_PROTOCOL EFI_CPU_ARCH_PROTOCOL; + +typedef enum { + EfiCpuFlushTypeWriteBackInvalidate, + EfiCpuFlushTypeWriteBack, + EfiCpuFlushTypeInvalidate, + EfiCpuMaxFlushType +} EFI_CPU_FLUSH_TYPE; + +typedef enum { + EfiCpuInit, + EfiCpuMaxInitType +} EFI_CPU_INIT_TYPE; + +/** + EFI_CPU_INTERRUPT_HANDLER that is called when a processor interrupt occurs. + + @param InterruptType Defines the type of interrupt or exception that + occurred on the processor.This parameter is processor architecture specific. + @param SystemContext A pointer to the processor context when + the interrupt occurred on the processor. + + @return None + +**/ +typedef +VOID +(EFIAPI *EFI_CPU_INTERRUPT_HANDLER)( + IN CONST EFI_EXCEPTION_TYPE InterruptType, + IN CONST EFI_SYSTEM_CONTEXT SystemContext + ); + +/** + This function flushes the range of addresses from Start to Start+Length + from the processor's data cache. If Start is not aligned to a cache line + boundary, then the bytes before Start to the preceding cache line boundary + are also flushed. If Start+Length is not aligned to a cache line boundary, + then the bytes past Start+Length to the end of the next cache line boundary + are also flushed. The FlushType of EfiCpuFlushTypeWriteBackInvalidate must be + supported. If the data cache is fully coherent with all DMA operations, then + this function can just return EFI_SUCCESS. If the processor does not support + flushing a range of the data cache, then the entire data cache can be flushed. + + @param This The EFI_CPU_ARCH_PROTOCOL instance. + @param Start The beginning physical address to flush from the processor's data + cache. + @param Length The number of bytes to flush from the processor's data cache. This + function may flush more bytes than Length specifies depending upon + the granularity of the flush operation that the processor supports. + @param FlushType Specifies the type of flush operation to perform. + + @retval EFI_SUCCESS The address range from Start to Start+Length was flushed from + the processor's data cache. + @retval EFI_UNSUPPORTEDT The processor does not support the cache flush type specified + by FlushType. + @retval EFI_DEVICE_ERROR The address range from Start to Start+Length could not be flushed + from the processor's data cache. + +**/ +typedef +EFI_STATUS +(EFIAPI *EFI_CPU_FLUSH_DATA_CACHE)( + IN EFI_CPU_ARCH_PROTOCOL *This, + IN EFI_PHYSICAL_ADDRESS Start, + IN UINT64 Length, + IN EFI_CPU_FLUSH_TYPE FlushType + ); + + +/** + This function enables interrupt processing by the processor. + + @param This The EFI_CPU_ARCH_PROTOCOL instance. + + @retval EFI_SUCCESS Interrupts are enabled on the processor. + @retval EFI_DEVICE_ERROR Interrupts could not be enabled on the processor. + +**/ +typedef +EFI_STATUS +(EFIAPI *EFI_CPU_ENABLE_INTERRUPT)( + IN EFI_CPU_ARCH_PROTOCOL *This + ); + + +/** + This function disables interrupt processing by the processor. + + @param This The EFI_CPU_ARCH_PROTOCOL instance. + + @retval EFI_SUCCESS Interrupts are disabled on the processor. + @retval EFI_DEVICE_ERROR Interrupts could not be disabled on the processor. + +**/ +typedef +EFI_STATUS +(EFIAPI *EFI_CPU_DISABLE_INTERRUPT)( + IN EFI_CPU_ARCH_PROTOCOL *This + ); + + +/** + This function retrieves the processor's current interrupt state a returns it in + State. If interrupts are currently enabled, then TRUE is returned. If interrupts + are currently disabled, then FALSE is returned. + + @param This The EFI_CPU_ARCH_PROTOCOL instance. + @param State A pointer to the processor's current interrupt state. Set to TRUE if + interrupts are enabled and FALSE if interrupts are disabled. + + @retval EFI_SUCCESS The processor's current interrupt state was returned in State. + @retval EFI_INVALID_PARAMETER State is NULL. + +**/ +typedef +EFI_STATUS +(EFIAPI *EFI_CPU_GET_INTERRUPT_STATE)( + IN EFI_CPU_ARCH_PROTOCOL *This, + OUT BOOLEAN *State + ); + + +/** + This function generates an INIT on the processor. If this function succeeds, then the + processor will be reset, and control will not be returned to the caller. If InitType is + not supported by this processor, or the processor cannot programmatically generate an + INIT without help from external hardware, then EFI_UNSUPPORTED is returned. If an error + occurs attempting to generate an INIT, then EFI_DEVICE_ERROR is returned. + + @param This The EFI_CPU_ARCH_PROTOCOL instance. + @param InitType The type of processor INIT to perform. + + @retval EFI_SUCCESS The processor INIT was performed. This return code should never be seen. + @retval EFI_UNSUPPORTED The processor INIT operation specified by InitType is not supported + by this processor. + @retval EFI_DEVICE_ERROR The processor INIT failed. + +**/ +typedef +EFI_STATUS +(EFIAPI *EFI_CPU_INIT)( + IN EFI_CPU_ARCH_PROTOCOL *This, + IN EFI_CPU_INIT_TYPE InitType + ); + + +/** + This function registers and enables the handler specified by InterruptHandler for a processor + interrupt or exception type specified by InterruptType. If InterruptHandler is NULL, then the + handler for the processor interrupt or exception type specified by InterruptType is uninstalled. + The installed handler is called once for each processor interrupt or exception. + + @param This The EFI_CPU_ARCH_PROTOCOL instance. + @param InterruptType A pointer to the processor's current interrupt state. Set to TRUE if interrupts + are enabled and FALSE if interrupts are disabled. + @param InterruptHandler A pointer to a function of type EFI_CPU_INTERRUPT_HANDLER that is called + when a processor interrupt occurs. If this parameter is NULL, then the handler + will be uninstalled. + + @retval EFI_SUCCESS The handler for the processor interrupt was successfully installed or uninstalled. + @retval EFI_ALREADY_STARTED InterruptHandler is not NULL, and a handler for InterruptType was + previously installed. + @retval EFI_INVALID_PARAMETER InterruptHandler is NULL, and a handler for InterruptType was not + previously installed. + @retval EFI_UNSUPPORTED The interrupt specified by InterruptType is not supported. + +**/ +typedef +EFI_STATUS +(EFIAPI *EFI_CPU_REGISTER_INTERRUPT_HANDLER)( + IN EFI_CPU_ARCH_PROTOCOL *This, + IN EFI_EXCEPTION_TYPE InterruptType, + IN EFI_CPU_INTERRUPT_HANDLER InterruptHandler + ); + + +/** + This function reads the processor timer specified by TimerIndex and returns it in TimerValue. + + @param This The EFI_CPU_ARCH_PROTOCOL instance. + @param TimerIndex Specifies which processor timer is to be returned in TimerValue. This parameter + must be between 0 and NumberOfTimers-1. + @param TimerValue Pointer to the returned timer value. + @param TimerPeriod A pointer to the amount of time that passes in femtoseconds for each increment + of TimerValue. + + @retval EFI_SUCCESS The processor timer value specified by TimerIndex was returned in TimerValue. + @retval EFI_DEVICE_ERROR An error occurred attempting to read one of the processor's timers. + @retval EFI_INVALID_PARAMETER TimerValue is NULL or TimerIndex is not valid. + @retval EFI_UNSUPPORTED The processor does not have any readable timers. + +**/ +typedef +EFI_STATUS +(EFIAPI *EFI_CPU_GET_TIMER_VALUE)( + IN EFI_CPU_ARCH_PROTOCOL *This, + IN UINT32 TimerIndex, + OUT UINT64 *TimerValue, + OUT UINT64 *TimerPeriod OPTIONAL + ); + + +/** + This function modifies the attributes for the memory region specified by BaseAddress and + Length from their current attributes to the attributes specified by Attributes. + + @param This The EFI_CPU_ARCH_PROTOCOL instance. + @param BaseAddress The physical address that is the start address of a memory region. + @param Length The size in bytes of the memory region. + @param Attributes The bit mask of attributes to set for the memory region. + + @retval EFI_SUCCESS The attributes were set for the memory region. + @retval EFI_ACCESS_DENIED The attributes for the memory resource range specified by + BaseAddress and Length cannot be modified. + @retval EFI_INVALID_PARAMETER Length is zero. + @retval EFI_OUT_OF_RESOURCES There are not enough system resources to modify the attributes of + the memory resource range. + @retval EFI_UNSUPPORTED The processor does not support one or more bytes of the memory + resource range specified by BaseAddress and Length. + The bit mask of attributes is not support for the memory resource + range specified by BaseAddress and Length. + +**/ +typedef +EFI_STATUS +(EFIAPI *EFI_CPU_SET_MEMORY_ATTRIBUTES)( + IN EFI_CPU_ARCH_PROTOCOL *This, + IN EFI_PHYSICAL_ADDRESS BaseAddress, + IN UINT64 Length, + IN UINT64 Attributes + ); + + +/// +/// The EFI_CPU_ARCH_PROTOCOL is used to abstract processor-specific functions from the DXE +/// Foundation. This includes flushing caches, enabling and disabling interrupts, hooking interrupt +/// vectors and exception vectors, reading internal processor timers, resetting the processor, and +/// determining the processor frequency. +/// +struct _EFI_CPU_ARCH_PROTOCOL { + EFI_CPU_FLUSH_DATA_CACHE FlushDataCache; + EFI_CPU_ENABLE_INTERRUPT EnableInterrupt; + EFI_CPU_DISABLE_INTERRUPT DisableInterrupt; + EFI_CPU_GET_INTERRUPT_STATE GetInterruptState; + EFI_CPU_INIT Init; + EFI_CPU_REGISTER_INTERRUPT_HANDLER RegisterInterruptHandler; + EFI_CPU_GET_TIMER_VALUE GetTimerValue; + EFI_CPU_SET_MEMORY_ATTRIBUTES SetMemoryAttributes; + /// + /// The number of timers that are available in a processor. The value in this + /// field is a constant that must not be modified after the CPU Architectural + /// Protocol is installed. All consumers must treat this as a read-only field. + /// + UINT32 NumberOfTimers; + /// + /// The size, in bytes, of the alignment required for DMA buffer allocations. + /// This is typically the size of the largest data cache line in the platform. + /// The value in this field is a constant that must not be modified after the + /// CPU Architectural Protocol is installed. All consumers must treat this as + /// a read-only field. + /// + UINT32 DmaBufferAlignment; +}; + +extern EFI_GUID gEfiCpuArchProtocolGuid; + +#endif diff --git a/gpxe/src/include/gpxe/efi/Protocol/CpuIo.h b/gpxe/src/include/gpxe/efi/Protocol/CpuIo.h new file mode 100644 index 00000000..8d35c6cd --- /dev/null +++ b/gpxe/src/include/gpxe/efi/Protocol/CpuIo.h @@ -0,0 +1,128 @@ +/** @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. + + Copyright (c) 2007, Intel Corporation + All rights reserved. This program and the accompanying materials + are licensed and made available under the terms and conditions of the BSD License + which accompanies this distribution. The full text of the license may be found at + http://opensource.org/licenses/bsd-license.php + + THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, + WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + + Module Name: CpuIO.h + + @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_ + +#include <gpxe/efi/PiDxe.h> + +#define EFI_CPU_IO_PROTOCOL_GUID \ + { \ + 0xB0732526, 0x38C8, 0x4b40, {0x88, 0x77, 0x61, 0xC7, 0xB0, 0x6A, 0xAC, 0x45 } \ + } + +typedef struct _EFI_CPU_IO_PROTOCOL EFI_CPU_IO_PROTOCOL; + +// +// ******************************************************* +// EFI_CPU_IO_PROTOCOL_WIDTH +// ******************************************************* +// +typedef enum { + EfiCpuIoWidthUint8, + EfiCpuIoWidthUint16, + EfiCpuIoWidthUint32, + EfiCpuIoWidthUint64, + EfiCpuIoWidthFifoUint8, + EfiCpuIoWidthFifoUint16, + EfiCpuIoWidthFifoUint32, + EfiCpuIoWidthFifoUint64, + EfiCpuIoWidthFillUint8, + EfiCpuIoWidthFillUint16, + EfiCpuIoWidthFillUint32, + EfiCpuIoWidthFillUint64, + EfiCpuIoWidthMaximum +} EFI_CPU_IO_PROTOCOL_WIDTH; + +// +// ******************************************************* +// EFI_CPU_IO_PROTOCOL_IO_MEM +// ******************************************************* +// +/** + Enables a driver to access memory-mapped registers in the EFI system memory space. + Or, Enables a driver to access registers in the EFI CPU I/O space. + + @param This A pointer to the EFI_CPU_IO_PROTOCOL instance. + @param Width Signifies the width of the I/O or Memory operation. + @param Address The base address of the I/O or Memoryoperation. + @param Count The number of I/O or Memory operations to perform. + The number of bytes moved is Width size * Count, starting at Address. + @param 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 EFI system. + @retval EFI_INVALID_PARAMETER Width is invalid for this EFI system.Or Buffer is NULL. + @retval EFI_UNSUPPORTED The Buffer is not aligned for the given Width. + Or,The address range specified by Address, Width, and Count is not valid for this EFI system. + +**/ +typedef +EFI_STATUS +(EFIAPI *EFI_CPU_IO_PROTOCOL_IO_MEM)( + IN EFI_CPU_IO_PROTOCOL *This, + IN EFI_CPU_IO_PROTOCOL_WIDTH Width, + IN UINT64 Address, + IN UINTN Count, + IN OUT VOID *Buffer + ); + +// +// ******************************************************* +// EFI_CPU_IO_PROTOCOL_ACCESS +// ******************************************************* +// +typedef struct { + EFI_CPU_IO_PROTOCOL_IO_MEM Read; + EFI_CPU_IO_PROTOCOL_IO_MEM Write; +} EFI_CPU_IO_PROTOCOL_ACCESS; + +// +// ******************************************************* +// EFI_CPU_IO_PROTOCOL +// ******************************************************* +// +/** + @par Protocol Description: + Provides the basic memory and I/O interfaces that are used to abstract + accesses to devices in a system. + + @param Mem.Read + Allows reads from memory-mapped I/O space. + + @param Mem.Write + Allows writes to memory-mapped I/O space. + + @param Io.Read + Allows reads from I/O space. + + @param Io.Write + Allows writes to I/O space. + +**/ +struct _EFI_CPU_IO_PROTOCOL { + EFI_CPU_IO_PROTOCOL_ACCESS Mem; + EFI_CPU_IO_PROTOCOL_ACCESS Io; +}; + +extern EFI_GUID gEfiCpuIoProtocolGuid; + +#endif diff --git a/gpxe/src/include/gpxe/efi/Protocol/DebugSupport.h b/gpxe/src/include/gpxe/efi/Protocol/DebugSupport.h new file mode 100644 index 00000000..c8db2498 --- /dev/null +++ b/gpxe/src/include/gpxe/efi/Protocol/DebugSupport.h @@ -0,0 +1,634 @@ +/** @file + DebugSupport protocol and supporting definitions as defined in the UEFI2.0 + specification. + + The DebugSupport protocol is used by source level debuggers to abstract the + processor and handle context save and restore operations. + + Copyright (c) 2006 - 2008, Intel Corporation + All rights reserved. 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 __DEBUG_SUPPORT_H__ +#define __DEBUG_SUPPORT_H__ + +#include <gpxe/efi/ProcessorBind.h> +#include <gpxe/efi/IndustryStandard/PeImage.h> + +typedef struct _EFI_DEBUG_SUPPORT_PROTOCOL EFI_DEBUG_SUPPORT_PROTOCOL; + +/// +/// Debug Support protocol {2755590C-6F3C-42FA-9EA4-A3BA543CDA25} +/// +#define EFI_DEBUG_SUPPORT_PROTOCOL_GUID \ + { \ + 0x2755590C, 0x6F3C, 0x42FA, {0x9E, 0xA4, 0xA3, 0xBA, 0x54, 0x3C, 0xDA, 0x25 } \ + } + +/// +/// Debug Support definitions +/// +typedef INTN EFI_EXCEPTION_TYPE; + +// +// IA-32 processor exception types +// +#define EXCEPT_IA32_DIVIDE_ERROR 0 +#define EXCEPT_IA32_DEBUG 1 +#define EXCEPT_IA32_NMI 2 +#define EXCEPT_IA32_BREAKPOINT 3 +#define EXCEPT_IA32_OVERFLOW 4 +#define EXCEPT_IA32_BOUND 5 +#define EXCEPT_IA32_INVALID_OPCODE 6 +#define EXCEPT_IA32_DOUBLE_FAULT 8 +#define EXCEPT_IA32_INVALID_TSS 10 +#define EXCEPT_IA32_SEG_NOT_PRESENT 11 +#define EXCEPT_IA32_STACK_FAULT 12 +#define EXCEPT_IA32_GP_FAULT 13 +#define EXCEPT_IA32_PAGE_FAULT 14 +#define EXCEPT_IA32_FP_ERROR 16 +#define EXCEPT_IA32_ALIGNMENT_CHECK 17 +#define EXCEPT_IA32_MACHINE_CHECK 18 +#define EXCEPT_IA32_SIMD 19 + +/// +/// IA-32 processor context definition +/// +/// +/// FXSAVE_STATE +/// FP / MMX / XMM registers (see fxrstor instruction definition) +/// +typedef struct { + UINT16 Fcw; + UINT16 Fsw; + UINT16 Ftw; + UINT16 Opcode; + UINT32 Eip; + UINT16 Cs; + UINT16 Reserved1; + UINT32 DataOffset; + UINT16 Ds; + UINT8 Reserved2[10]; + UINT8 St0Mm0[10], Reserved3[6]; + UINT8 St1Mm1[10], Reserved4[6]; + UINT8 St2Mm2[10], Reserved5[6]; + UINT8 St3Mm3[10], Reserved6[6]; + UINT8 St4Mm4[10], Reserved7[6]; + UINT8 St5Mm5[10], Reserved8[6]; + UINT8 St6Mm6[10], Reserved9[6]; + UINT8 St7Mm7[10], Reserved10[6]; + UINT8 Xmm0[16]; + UINT8 Xmm1[16]; + UINT8 Xmm2[16]; + UINT8 Xmm3[16]; + UINT8 Xmm4[16]; + UINT8 Xmm5[16]; + UINT8 Xmm6[16]; + UINT8 Xmm7[16]; + UINT8 Reserved11[14 * 16]; +} EFI_FX_SAVE_STATE_IA32; + +typedef struct { + UINT32 ExceptionData; + EFI_FX_SAVE_STATE_IA32 FxSaveState; + UINT32 Dr0; + UINT32 Dr1; + UINT32 Dr2; + UINT32 Dr3; + UINT32 Dr6; + UINT32 Dr7; + UINT32 Cr0; + UINT32 Cr1; /* Reserved */ + UINT32 Cr2; + UINT32 Cr3; + UINT32 Cr4; + UINT32 Eflags; + UINT32 Ldtr; + UINT32 Tr; + UINT32 Gdtr[2]; + UINT32 Idtr[2]; + UINT32 Eip; + UINT32 Gs; + UINT32 Fs; + UINT32 Es; + UINT32 Ds; + UINT32 Cs; + UINT32 Ss; + UINT32 Edi; + UINT32 Esi; + UINT32 Ebp; + UINT32 Esp; + UINT32 Ebx; + UINT32 Edx; + UINT32 Ecx; + UINT32 Eax; +} EFI_SYSTEM_CONTEXT_IA32; + +// +// X64 processor exception types +// +#define EXCEPT_X64_DIVIDE_ERROR 0 +#define EXCEPT_X64_DEBUG 1 +#define EXCEPT_X64_NMI 2 +#define EXCEPT_X64_BREAKPOINT 3 +#define EXCEPT_X64_OVERFLOW 4 +#define EXCEPT_X64_BOUND 5 +#define EXCEPT_X64_INVALID_OPCODE 6 +#define EXCEPT_X64_DOUBLE_FAULT 8 +#define EXCEPT_X64_INVALID_TSS 10 +#define EXCEPT_X64_SEG_NOT_PRESENT 11 +#define EXCEPT_X64_STACK_FAULT 12 +#define EXCEPT_X64_GP_FAULT 13 +#define EXCEPT_X64_PAGE_FAULT 14 +#define EXCEPT_X64_FP_ERROR 16 +#define EXCEPT_X64_ALIGNMENT_CHECK 17 +#define EXCEPT_X64_MACHINE_CHECK 18 +#define EXCEPT_X64_SIMD 19 + +/// +/// X64 processor context definition +/// +/// FXSAVE_STATE +/// FP / MMX / XMM registers (see fxrstor instruction definition) +/// +typedef struct { + UINT16 Fcw; + UINT16 Fsw; + UINT16 Ftw; + UINT16 Opcode; + UINT64 Rip; + UINT64 DataOffset; + UINT8 Reserved1[8]; + UINT8 St0Mm0[10], Reserved2[6]; + UINT8 St1Mm1[10], Reserved3[6]; + UINT8 St2Mm2[10], Reserved4[6]; + UINT8 St3Mm3[10], Reserved5[6]; + UINT8 St4Mm4[10], Reserved6[6]; + UINT8 St5Mm5[10], Reserved7[6]; + UINT8 St6Mm6[10], Reserved8[6]; + UINT8 St7Mm7[10], Reserved9[6]; + UINT8 Xmm0[16]; + UINT8 Xmm1[16]; + UINT8 Xmm2[16]; + UINT8 Xmm3[16]; + UINT8 Xmm4[16]; + UINT8 Xmm5[16]; + UINT8 Xmm6[16]; + UINT8 Xmm7[16]; + // + // NOTE: UEFI 2.0 spec definition as follows. + // + UINT8 Reserved11[14 * 16]; +} EFI_FX_SAVE_STATE_X64; + +typedef struct { + UINT64 ExceptionData; + EFI_FX_SAVE_STATE_X64 FxSaveState; + UINT64 Dr0; + UINT64 Dr1; + UINT64 Dr2; + UINT64 Dr3; + UINT64 Dr6; + UINT64 Dr7; + UINT64 Cr0; + UINT64 Cr1; /* Reserved */ + UINT64 Cr2; + UINT64 Cr3; + UINT64 Cr4; + UINT64 Cr8; + UINT64 Rflags; + UINT64 Ldtr; + UINT64 Tr; + UINT64 Gdtr[2]; + UINT64 Idtr[2]; + UINT64 Rip; + UINT64 Gs; + UINT64 Fs; + UINT64 Es; + UINT64 Ds; + UINT64 Cs; + UINT64 Ss; + UINT64 Rdi; + UINT64 Rsi; + UINT64 Rbp; + UINT64 Rsp; + UINT64 Rbx; + UINT64 Rdx; + UINT64 Rcx; + UINT64 Rax; + UINT64 R8; + UINT64 R9; + UINT64 R10; + UINT64 R11; + UINT64 R12; + UINT64 R13; + UINT64 R14; + UINT64 R15; +} EFI_SYSTEM_CONTEXT_X64; + +// +// IPF processor exception types +// +#define EXCEPT_IPF_VHTP_TRANSLATION 0 +#define EXCEPT_IPF_INSTRUCTION_TLB 1 +#define EXCEPT_IPF_DATA_TLB 2 +#define EXCEPT_IPF_ALT_INSTRUCTION_TLB 3 +#define EXCEPT_IPF_ALT_DATA_TLB 4 +#define EXCEPT_IPF_DATA_NESTED_TLB 5 +#define EXCEPT_IPF_INSTRUCTION_KEY_MISSED 6 +#define EXCEPT_IPF_DATA_KEY_MISSED 7 +#define EXCEPT_IPF_DIRTY_BIT 8 +#define EXCEPT_IPF_INSTRUCTION_ACCESS_BIT 9 +#define EXCEPT_IPF_DATA_ACCESS_BIT 10 +#define EXCEPT_IPF_BREAKPOINT 11 +#define EXCEPT_IPF_EXTERNAL_INTERRUPT 12 +// +// 13 - 19 reserved +// +#define EXCEPT_IPF_PAGE_NOT_PRESENT 20 +#define EXCEPT_IPF_KEY_PERMISSION 21 +#define EXCEPT_IPF_INSTRUCTION_ACCESS_RIGHTS 22 +#define EXCEPT_IPF_DATA_ACCESS_RIGHTS 23 +#define EXCEPT_IPF_GENERAL_EXCEPTION 24 +#define EXCEPT_IPF_DISABLED_FP_REGISTER 25 +#define EXCEPT_IPF_NAT_CONSUMPTION 26 +#define EXCEPT_IPF_SPECULATION 27 +// +// 28 reserved +// +#define EXCEPT_IPF_DEBUG 29 +#define EXCEPT_IPF_UNALIGNED_REFERENCE 30 +#define EXCEPT_IPF_UNSUPPORTED_DATA_REFERENCE 31 +#define EXCEPT_IPF_FP_FAULT 32 +#define EXCEPT_IPF_FP_TRAP 33 +#define EXCEPT_IPF_LOWER_PRIVILEGE_TRANSFER_TRAP 34 +#define EXCEPT_IPF_TAKEN_BRANCH 35 +#define EXCEPT_IPF_SINGLE_STEP 36 +// +// 37 - 44 reserved +// +#define EXCEPT_IPF_IA32_EXCEPTION 45 +#define EXCEPT_IPF_IA32_INTERCEPT 46 +#define EXCEPT_IPF_IA32_INTERRUPT 47 + +/// +/// IPF processor context definition +/// +typedef struct { + // + // The first reserved field is necessary to preserve alignment for the correct + // bits in UNAT and to insure F2 is 16 byte aligned.. + // + UINT64 Reserved; + UINT64 R1; + UINT64 R2; + UINT64 R3; + UINT64 R4; + UINT64 R5; + UINT64 R6; + UINT64 R7; + UINT64 R8; + UINT64 R9; + UINT64 R10; + UINT64 R11; + UINT64 R12; + UINT64 R13; + UINT64 R14; + UINT64 R15; + UINT64 R16; + UINT64 R17; + UINT64 R18; + UINT64 R19; + UINT64 R20; + UINT64 R21; + UINT64 R22; + UINT64 R23; + UINT64 R24; + UINT64 R25; + UINT64 R26; + UINT64 R27; + UINT64 R28; + UINT64 R29; + UINT64 R30; + UINT64 R31; + + UINT64 F2[2]; + UINT64 F3[2]; + UINT64 F4[2]; + UINT64 F5[2]; + UINT64 F6[2]; + UINT64 F7[2]; + UINT64 F8[2]; + UINT64 F9[2]; + UINT64 F10[2]; + UINT64 F11[2]; + UINT64 F12[2]; + UINT64 F13[2]; + UINT64 F14[2]; + UINT64 F15[2]; + UINT64 F16[2]; + UINT64 F17[2]; + UINT64 F18[2]; + UINT64 F19[2]; + UINT64 F20[2]; + UINT64 F21[2]; + UINT64 F22[2]; + UINT64 F23[2]; + UINT64 F24[2]; + UINT64 F25[2]; + UINT64 F26[2]; + UINT64 F27[2]; + UINT64 F28[2]; + UINT64 F29[2]; + UINT64 F30[2]; + UINT64 F31[2]; + + UINT64 Pr; + + UINT64 B0; + UINT64 B1; + UINT64 B2; + UINT64 B3; + UINT64 B4; + UINT64 B5; + UINT64 B6; + UINT64 B7; + + // + // application registers + // + UINT64 ArRsc; + UINT64 ArBsp; + UINT64 ArBspstore; + UINT64 ArRnat; + + UINT64 ArFcr; + + UINT64 ArEflag; + UINT64 ArCsd; + UINT64 ArSsd; + UINT64 ArCflg; + UINT64 ArFsr; + UINT64 ArFir; + UINT64 ArFdr; + + UINT64 ArCcv; + + UINT64 ArUnat; + + UINT64 ArFpsr; + + UINT64 ArPfs; + UINT64 ArLc; + UINT64 ArEc; + + // + // control registers + // + UINT64 CrDcr; + UINT64 CrItm; + UINT64 CrIva; + UINT64 CrPta; + UINT64 CrIpsr; + UINT64 CrIsr; + UINT64 CrIip; + UINT64 CrIfa; + UINT64 CrItir; + UINT64 CrIipa; + UINT64 CrIfs; + UINT64 CrIim; + UINT64 CrIha; + + // + // debug registers + // + UINT64 Dbr0; + UINT64 Dbr1; + UINT64 Dbr2; + UINT64 Dbr3; + UINT64 Dbr4; + UINT64 Dbr5; + UINT64 Dbr6; + UINT64 Dbr7; + + UINT64 Ibr0; + UINT64 Ibr1; + UINT64 Ibr2; + UINT64 Ibr3; + UINT64 Ibr4; + UINT64 Ibr5; + UINT64 Ibr6; + UINT64 Ibr7; + + // + // virtual registers - nat bits for R1-R31 + // + UINT64 IntNat; + +} EFI_SYSTEM_CONTEXT_IPF; + +// +// EBC processor exception types +// +#define EXCEPT_EBC_UNDEFINED 0 +#define EXCEPT_EBC_DIVIDE_ERROR 1 +#define EXCEPT_EBC_DEBUG 2 +#define EXCEPT_EBC_BREAKPOINT 3 +#define EXCEPT_EBC_OVERFLOW 4 +#define EXCEPT_EBC_INVALID_OPCODE 5 // opcode out of range +#define EXCEPT_EBC_STACK_FAULT 6 +#define EXCEPT_EBC_ALIGNMENT_CHECK 7 +#define EXCEPT_EBC_INSTRUCTION_ENCODING 8 // malformed instruction +#define EXCEPT_EBC_BAD_BREAK 9 // BREAK 0 or undefined BREAK +#define EXCEPT_EBC_STEP 10 // to support debug stepping +/// +/// For coding convenience, define the maximum valid EBC exception. +/// +#define MAX_EBC_EXCEPTION EXCEPT_EBC_STEP + +/// +/// EBC processor context definition +/// +typedef struct { + UINT64 R0; + UINT64 R1; + UINT64 R2; + UINT64 R3; + UINT64 R4; + UINT64 R5; + UINT64 R6; + UINT64 R7; + UINT64 Flags; + UINT64 ControlFlags; + UINT64 Ip; +} EFI_SYSTEM_CONTEXT_EBC; + +/// +/// Universal EFI_SYSTEM_CONTEXT definition +/// +typedef union { + EFI_SYSTEM_CONTEXT_EBC *SystemContextEbc; + EFI_SYSTEM_CONTEXT_IA32 *SystemContextIa32; + EFI_SYSTEM_CONTEXT_X64 *SystemContextX64; + EFI_SYSTEM_CONTEXT_IPF *SystemContextIpf; +} EFI_SYSTEM_CONTEXT; + +// +// DebugSupport callback function prototypes +// + +/** + Registers and enables an exception callback function for the specified exception. + + @param ExceptionType Exception types in EBC, IA-32, X64, or IPF + @param SystemContext Exception content. + +**/ +typedef +VOID +(*EFI_EXCEPTION_CALLBACK)( + IN EFI_EXCEPTION_TYPE ExceptionType, + IN OUT EFI_SYSTEM_CONTEXT SystemContext + ); + +/** + Registers and enables the on-target debug agent's periodic entry point. + + @param SystemContext Exception content. + +**/ +typedef +VOID +(*EFI_PERIODIC_CALLBACK)( + IN OUT EFI_SYSTEM_CONTEXT SystemContext + ); + +/// +/// Machine type definition +/// +typedef enum { + IsaIa32 = IMAGE_FILE_MACHINE_I386, ///< 0x014C + IsaX64 = IMAGE_FILE_MACHINE_X64, ///< 0x8664 + IsaIpf = IMAGE_FILE_MACHINE_IA64, ///< 0x0200 + IsaEbc = IMAGE_FILE_MACHINE_EBC ///< 0x0EBC +} EFI_INSTRUCTION_SET_ARCHITECTURE; + + +// +// DebugSupport member function definitions +// + +/** + Returns the maximum value that may be used for the ProcessorIndex parameter in + RegisterPeriodicCallback() and RegisterExceptionCallback(). + + @param This A pointer to the EFI_DEBUG_SUPPORT_PROTOCOL instance. + @param MaxProcessorIndex Pointer to a caller-allocated UINTN in which the maximum supported + processor index is returned. + + @retval EFI_SUCCESS The function completed successfully. + +**/ +typedef +EFI_STATUS +(EFIAPI *EFI_GET_MAXIMUM_PROCESSOR_INDEX)( + IN EFI_DEBUG_SUPPORT_PROTOCOL *This, + OUT UINTN *MaxProcessorIndex + ); + +/** + Registers a function to be called back periodically in interrupt context. + + @param This A pointer to the EFI_DEBUG_SUPPORT_PROTOCOL instance. + @param ProcessorIndex Specifies which processor the callback function applies to. + @param PeriodicCallback A pointer to a function of type PERIODIC_CALLBACK that is the main + periodic entry point of the debug agent. + + @retval EFI_SUCCESS The function completed successfully. + @retval EFI_ALREADY_STARTED Non-NULL PeriodicCallback parameter when a callback + function was previously registered. + @retval EFI_OUT_OF_RESOURCES System has insufficient memory resources to register new callback + function. + +**/ +typedef +EFI_STATUS +(EFIAPI *EFI_REGISTER_PERIODIC_CALLBACK)( + IN EFI_DEBUG_SUPPORT_PROTOCOL *This, + IN UINTN ProcessorIndex, + IN EFI_PERIODIC_CALLBACK PeriodicCallback + ); + +/** + Registers a function to be called when a given processor exception occurs. + + @param This A pointer to the EFI_DEBUG_SUPPORT_PROTOCOL instance. + @param ProcessorIndex Specifies which processor the callback function applies to. + @param PeriodicCallback A pointer to a function of type EXCEPTION_CALLBACK that is called + when the processor exception specified by ExceptionType occurs. + @param ExceptionType Specifies which processor exception to hook. + + @retval EFI_SUCCESS The function completed successfully. + @retval EFI_ALREADY_STARTED Non-NULL PeriodicCallback parameter when a callback + function was previously registered. + @retval EFI_OUT_OF_RESOURCES System has insufficient memory resources to register new callback + function. + +**/ +typedef +EFI_STATUS +(EFIAPI *EFI_REGISTER_EXCEPTION_CALLBACK)( + IN EFI_DEBUG_SUPPORT_PROTOCOL *This, + IN UINTN ProcessorIndex, + IN EFI_EXCEPTION_CALLBACK ExceptionCallback, + IN EFI_EXCEPTION_TYPE ExceptionType + ); + +/** + Invalidates processor instruction cache for a memory range. Subsequent execution in this range + causes a fresh memory fetch to retrieve code to be executed. + + @param This A pointer to the EFI_DEBUG_SUPPORT_PROTOCOL instance. + @param ProcessorIndex Specifies which processor's instruction cache is to be invalidated. + @param Start Specifies the physical base of the memory range to be invalidated. + @param Length Specifies the minimum number of bytes in the processor's instruction + cache to invalidate. + + @retval EFI_SUCCESS The function completed successfully. + +**/ +typedef +EFI_STATUS +(EFIAPI *EFI_INVALIDATE_INSTRUCTION_CACHE)( + IN EFI_DEBUG_SUPPORT_PROTOCOL *This, + IN UINTN ProcessorIndex, + IN VOID *Start, + IN UINT64 Length + ); + +/// +/// This protocol provides the services to allow the debug agent to register +/// callback functions that are called either periodically or when specific +/// processor exceptions occur. +/// +struct _EFI_DEBUG_SUPPORT_PROTOCOL { + /// + /// Declares the processor architecture for this instance of the EFI Debug Support protocol. + /// + EFI_INSTRUCTION_SET_ARCHITECTURE Isa; + EFI_GET_MAXIMUM_PROCESSOR_INDEX GetMaximumProcessorIndex; + EFI_REGISTER_PERIODIC_CALLBACK RegisterPeriodicCallback; + EFI_REGISTER_EXCEPTION_CALLBACK RegisterExceptionCallback; + EFI_INVALIDATE_INSTRUCTION_CACHE InvalidateInstructionCache; +}; + +extern EFI_GUID gEfiDebugSupportProtocolGuid; + +#endif diff --git a/gpxe/src/include/gpxe/efi/Protocol/DevicePath.h b/gpxe/src/include/gpxe/efi/Protocol/DevicePath.h new file mode 100644 index 00000000..e847668f --- /dev/null +++ b/gpxe/src/include/gpxe/efi/Protocol/DevicePath.h @@ -0,0 +1,535 @@ +/** @file + The device path protocol as defined in UEFI 2.0. + + The device path represents a programatic path to a device. It's the view + from a software point of view. It also must persist from boot to boot, so + it can not contain things like PCI bus numbers that change from boot to boot. + + Copyright (c) 2006 - 2008, Intel Corporation + All rights reserved. This program and the accompanying materials + are licensed and made available under the terms and conditions of the BSD License + which accompanies this distribution. The full text of the license may be found at + http://opensource.org/licenses/bsd-license.php + + THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, + WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + +**/ + +#ifndef __EFI_DEVICE_PATH_PROTOCOL_H__ +#define __EFI_DEVICE_PATH_PROTOCOL_H__ + +#include <gpxe/efi/Guid/PcAnsi.h> + +/// +/// Device Path protocol +/// +#define EFI_DEVICE_PATH_PROTOCOL_GUID \ + { \ + 0x9576e91, 0x6d3f, 0x11d2, {0x8e, 0x39, 0x0, 0xa0, 0xc9, 0x69, 0x72, 0x3b } \ + } + +// +// Protocol GUID defined in EFI1.1. +// + +/// +/// Device Path information +/// +#define DEVICE_PATH_PROTOCOL EFI_DEVICE_PATH_PROTOCOL_GUID + +#pragma pack(1) + +/** + This protocol can be used on any device handle to obtain generic path/location + information concerning the physical device or logical device. If the handle does + not logically map to a physical device, the handle may not necessarily support + the device path protocol. The device path describes the location of the device + the handle is for. The size of the Device Path can be determined from the structures + that make up the Device Path. +**/ +typedef struct { + UINT8 Type; ///< 0x01 Hardware Device Path + ///< 0x02 ACPI Device Path + ///< 0x03 Messaging Device Path + ///< 0x04 Media Device Path + ///< 0x05 BIOS Boot Specification Device Path + ///< 0x7F End of Hardware Device Path + + UINT8 SubType; ///< Varies by Type + ///< 0xFF End Entire Device Path, or + ///< 0x01 End This Instance of a Device Path and start a new + ///< Device Path + + UINT8 Length[2]; ///< Specific Device Path data. Type and Sub-Type define + ///< type of data. Size of data is included in Length. + +} EFI_DEVICE_PATH_PROTOCOL; + +/// +/// For backward-compatible with EFI1.1. +/// +typedef EFI_DEVICE_PATH_PROTOCOL EFI_DEVICE_PATH; + +/// +/// Hardware Device Paths +/// +#define HARDWARE_DEVICE_PATH 0x01 + +#define HW_PCI_DP 0x01 +typedef struct { + EFI_DEVICE_PATH_PROTOCOL Header; + UINT8 Function; + UINT8 Device; +} PCI_DEVICE_PATH; + +#define HW_PCCARD_DP 0x02 +typedef struct { + EFI_DEVICE_PATH_PROTOCOL Header; + UINT8 FunctionNumber; +} PCCARD_DEVICE_PATH; + +#define HW_MEMMAP_DP 0x03 +typedef struct { + EFI_DEVICE_PATH_PROTOCOL Header; + UINT32 MemoryType; + EFI_PHYSICAL_ADDRESS StartingAddress; + EFI_PHYSICAL_ADDRESS EndingAddress; +} MEMMAP_DEVICE_PATH; + +#define HW_VENDOR_DP 0x04 +typedef struct { + EFI_DEVICE_PATH_PROTOCOL Header; + EFI_GUID Guid; +} VENDOR_DEVICE_PATH; + +#define HW_CONTROLLER_DP 0x05 +typedef struct { + EFI_DEVICE_PATH_PROTOCOL Header; + UINT32 ControllerNumber; +} CONTROLLER_DEVICE_PATH; + +/// +/// ACPI Device Paths +/// +#define ACPI_DEVICE_PATH 0x02 + +#define ACPI_DP 0x01 +typedef struct { + EFI_DEVICE_PATH_PROTOCOL Header; + UINT32 HID; + UINT32 UID; +} ACPI_HID_DEVICE_PATH; + +#define ACPI_EXTENDED_DP 0x02 +typedef struct { + EFI_DEVICE_PATH_PROTOCOL Header; + UINT32 HID; + UINT32 UID; + UINT32 CID; + /// + /// Optional variable length _HIDSTR + /// Optional variable length _UIDSTR + /// Optional variable length _CIDSTR + /// +} ACPI_EXTENDED_HID_DEVICE_PATH; + +// +// EISA ID Macro +// EISA ID Definition 32-bits +// bits[15:0] - three character compressed ASCII EISA ID. +// bits[31:16] - binary number +// Compressed ASCII is 5 bits per character 0b00001 = 'A' 0b11010 = 'Z' +// +#define PNP_EISA_ID_CONST 0x41d0 +#define EISA_ID(_Name, _Num) ((UINT32)((_Name) | (_Num) << 16)) +#define EISA_PNP_ID(_PNPId) (EISA_ID(PNP_EISA_ID_CONST, (_PNPId))) +#define EFI_PNP_ID(_PNPId) (EISA_ID(PNP_EISA_ID_CONST, (_PNPId))) + +#define PNP_EISA_ID_MASK 0xffff +#define EISA_ID_TO_NUM(_Id) ((_Id) >> 16) + + +#define ACPI_ADR_DP 0x03 +typedef struct { + EFI_DEVICE_PATH_PROTOCOL Header; + UINT32 ADR; +} ACPI_ADR_DEVICE_PATH; + +#define ACPI_ADR_DISPLAY_TYPE_OTHER 0 +#define ACPI_ADR_DISPLAY_TYPE_VGA 1 +#define ACPI_ADR_DISPLAY_TYPE_TV 2 +#define ACPI_ADR_DISPLAY_TYPE_EXTERNAL_DIGITAL 3 +#define ACPI_ADR_DISPLAY_TYPE_INTERNAL_DIGITAL 4 + +#define ACPI_DISPLAY_ADR(_DeviceIdScheme, _HeadId, _NonVgaOutput, _BiosCanDetect, _VendorInfo, _Type, _Port, _Index) \ + ((UINT32)( (((_DeviceIdScheme) & 0x1) << 31) | \ + (((_HeadId) & 0x7) << 18) | \ + (((_NonVgaOutput) & 0x1) << 17) | \ + (((_BiosCanDetect) & 0x1) << 16) | \ + (((_VendorInfo) & 0xf) << 12) | \ + (((_Type) & 0xf) << 8) | \ + (((_Port) & 0xf) << 4) | \ + ((_Index) & 0xf) )) + +/// +/// Messaging Device Paths +/// +#define MESSAGING_DEVICE_PATH 0x03 + +#define MSG_ATAPI_DP 0x01 +typedef struct { + EFI_DEVICE_PATH_PROTOCOL Header; + UINT8 PrimarySecondary; + UINT8 SlaveMaster; + UINT16 Lun; +} ATAPI_DEVICE_PATH; + +#define MSG_SCSI_DP 0x02 +typedef struct { + EFI_DEVICE_PATH_PROTOCOL Header; + UINT16 Pun; + UINT16 Lun; +} SCSI_DEVICE_PATH; + +#define MSG_FIBRECHANNEL_DP 0x03 +typedef struct { + EFI_DEVICE_PATH_PROTOCOL Header; + UINT32 Reserved; + UINT64 WWN; + UINT64 Lun; +} FIBRECHANNEL_DEVICE_PATH; + +#define MSG_1394_DP 0x04 +typedef struct { + EFI_DEVICE_PATH_PROTOCOL Header; + UINT32 Reserved; + UINT64 Guid; +} F1394_DEVICE_PATH; + +#define MSG_USB_DP 0x05 +typedef struct { + EFI_DEVICE_PATH_PROTOCOL Header; + UINT8 ParentPortNumber; + UINT8 InterfaceNumber; +} USB_DEVICE_PATH; + +#define MSG_USB_CLASS_DP 0x0f +typedef struct { + EFI_DEVICE_PATH_PROTOCOL Header; + UINT16 VendorId; + UINT16 ProductId; + UINT8 DeviceClass; + UINT8 DeviceSubClass; + UINT8 DeviceProtocol; +} USB_CLASS_DEVICE_PATH; + +#define MSG_USB_WWID_DP 0x10 +typedef struct { + EFI_DEVICE_PATH_PROTOCOL Header; + UINT16 InterfaceNumber; + UINT16 VendorId; + UINT16 ProductId; + // CHAR16 SerialNumber[...]; +} USB_WWID_DEVICE_PATH; + + +#define MSG_DEVICE_LOGICAL_UNIT_DP 0x11 +typedef struct { + EFI_DEVICE_PATH_PROTOCOL Header; + UINT8 Lun; +} DEVICE_LOGICAL_UNIT_DEVICE_PATH; + +#define MSG_SATA_DP 0x12 +typedef struct { + EFI_DEVICE_PATH_PROTOCOL Header; + UINT16 HBAPortNumber; + UINT16 PortMultiplierPortNumber; + UINT16 Lun; +} SATA_DEVICE_PATH; + +#define MSG_I2O_DP 0x06 +typedef struct { + EFI_DEVICE_PATH_PROTOCOL Header; + UINT32 Tid; +} I2O_DEVICE_PATH; + +#define MSG_MAC_ADDR_DP 0x0b +typedef struct { + EFI_DEVICE_PATH_PROTOCOL Header; + EFI_MAC_ADDRESS MacAddress; + UINT8 IfType; +} MAC_ADDR_DEVICE_PATH; + +#define MSG_IPv4_DP 0x0c +typedef struct { + EFI_DEVICE_PATH_PROTOCOL Header; + EFI_IPv4_ADDRESS LocalIpAddress; + EFI_IPv4_ADDRESS RemoteIpAddress; + UINT16 LocalPort; + UINT16 RemotePort; + UINT16 Protocol; + BOOLEAN StaticIpAddress; +} IPv4_DEVICE_PATH; + +#define MSG_IPv6_DP 0x0d +typedef struct { + EFI_DEVICE_PATH_PROTOCOL Header; + EFI_IPv6_ADDRESS LocalIpAddress; + EFI_IPv6_ADDRESS RemoteIpAddress; + UINT16 LocalPort; + UINT16 RemotePort; + UINT16 Protocol; + BOOLEAN StaticIpAddress; +} IPv6_DEVICE_PATH; + +#define MSG_INFINIBAND_DP 0x09 +typedef struct { + EFI_DEVICE_PATH_PROTOCOL Header; + UINT32 ResourceFlags; + UINT8 PortGid[16]; + UINT64 ServiceId; + UINT64 TargetPortId; + UINT64 DeviceId; +} INFINIBAND_DEVICE_PATH; + +#define INFINIBAND_RESOURCE_FLAG_IOC_SERVICE 0x01 +#define INFINIBAND_RESOURCE_FLAG_EXTENDED_BOOT_ENVIRONMENT 0x02 +#define INFINIBAND_RESOURCE_FLAG_CONSOLE_PROTOCOL 0x04 +#define INFINIBAND_RESOURCE_FLAG_STORAGE_PROTOCOL 0x08 +#define INFINIBAND_RESOURCE_FLAG_NETWORK_PROTOCOL 0x10 + +#define MSG_UART_DP 0x0e +typedef struct { + EFI_DEVICE_PATH_PROTOCOL Header; + UINT32 Reserved; + UINT64 BaudRate; + UINT8 DataBits; + UINT8 Parity; + UINT8 StopBits; +} UART_DEVICE_PATH; + +// +// Use VENDOR_DEVICE_PATH struct +// +#define MSG_VENDOR_DP 0x0a +typedef VENDOR_DEVICE_PATH VENDOR_DEFINED_DEVICE_PATH; + +#define DEVICE_PATH_MESSAGING_PC_ANSI EFI_PC_ANSI_GUID +#define DEVICE_PATH_MESSAGING_VT_100 EFI_VT_100_GUID +#define DEVICE_PATH_MESSAGING_VT_100_PLUS EFI_VT_100_PLUS_GUID +#define DEVICE_PATH_MESSAGING_VT_UTF8 EFI_VT_UTF8_GUID + +#define DEVICE_PATH_MESSAGING_UART_FLOW_CONTROL EFI_UART_DEVICE_PATH_GUID + +typedef struct { + EFI_DEVICE_PATH_PROTOCOL Header; + EFI_GUID Guid; + UINT32 FlowControlMap; +} UART_FLOW_CONTROL_DEVICE_PATH; + +#define DEVICE_PATH_MESSAGING_SAS EFI_SAS_DEVICE_PATH_GUID + +typedef struct { + EFI_DEVICE_PATH_PROTOCOL Header; + EFI_GUID Guid; + UINT32 Reserved; + UINT64 SasAddress; + UINT64 Lun; + UINT16 DeviceTopology; + UINT16 RelativeTargetPort; +} SAS_DEVICE_PATH; + +#define MSG_ISCSI_DP 0x13 +typedef struct { + EFI_DEVICE_PATH_PROTOCOL Header; + UINT16 NetworkProtocol; + UINT16 LoginOption; + UINT64 Lun; + UINT16 TargetPortalGroupTag; + // CHAR8 iSCSI Target Name +} ISCSI_DEVICE_PATH; + +#define ISCSI_LOGIN_OPTION_NO_HEADER_DIGEST 0x0000 +#define ISCSI_LOGIN_OPTION_HEADER_DIGEST_USING_CRC32C 0x0002 +#define ISCSI_LOGIN_OPTION_NO_DATA_DIGEST 0x0000 +#define ISCSI_LOGIN_OPTION_DATA_DIGEST_USING_CRC32C 0x0008 +#define ISCSI_LOGIN_OPTION_AUTHMETHOD_CHAP 0x0000 +#define ISCSI_LOGIN_OPTION_AUTHMETHOD_NON 0x1000 +#define ISCSI_LOGIN_OPTION_CHAP_BI 0x0000 +#define ISCSI_LOGIN_OPTION_CHAP_UNI 0x2000 + +// +// Media Device Path +// +#define MEDIA_DEVICE_PATH 0x04 + +#define MEDIA_HARDDRIVE_DP 0x01 +typedef struct { + EFI_DEVICE_PATH_PROTOCOL Header; + UINT32 PartitionNumber; + UINT64 PartitionStart; + UINT64 PartitionSize; + UINT8 Signature[16]; + UINT8 MBRType; + UINT8 SignatureType; +} HARDDRIVE_DEVICE_PATH; + +#define MBR_TYPE_PCAT 0x01 +#define MBR_TYPE_EFI_PARTITION_TABLE_HEADER 0x02 + +#define SIGNATURE_TYPE_MBR 0x01 +#define SIGNATURE_TYPE_GUID 0x02 + +#define MEDIA_CDROM_DP 0x02 +typedef struct { + EFI_DEVICE_PATH_PROTOCOL Header; + UINT32 BootEntry; + UINT64 PartitionStart; + UINT64 PartitionSize; +} CDROM_DEVICE_PATH; + +// +// Use VENDOR_DEVICE_PATH struct +// +#define MEDIA_VENDOR_DP 0x03 + +#define MEDIA_FILEPATH_DP 0x04 +typedef struct { + EFI_DEVICE_PATH_PROTOCOL Header; + CHAR16 PathName[1]; +} FILEPATH_DEVICE_PATH; + +#define SIZE_OF_FILEPATH_DEVICE_PATH EFI_FIELD_OFFSET(FILEPATH_DEVICE_PATH,PathName) + +#define MEDIA_PROTOCOL_DP 0x05 +typedef struct { + EFI_DEVICE_PATH_PROTOCOL Header; + EFI_GUID Protocol; +} MEDIA_PROTOCOL_DEVICE_PATH; + + +#define MEDIA_PIWG_FW_VOL_DP 0x7 +typedef struct { + EFI_DEVICE_PATH_PROTOCOL Header; + EFI_GUID FvName; +} MEDIA_FW_VOL_DEVICE_PATH; + + +#define MEDIA_PIWG_FW_FILE_DP 0x6 +typedef struct { + EFI_DEVICE_PATH_PROTOCOL Header; + EFI_GUID FvFileName; +} MEDIA_FW_VOL_FILEPATH_DEVICE_PATH; + +// +// BBS Device Path +// +#define BBS_DEVICE_PATH 0x05 +#define BBS_BBS_DP 0x01 +typedef struct { + EFI_DEVICE_PATH_PROTOCOL Header; + UINT16 DeviceType; + UINT16 StatusFlag; + CHAR8 String[1]; +} BBS_BBS_DEVICE_PATH; + +// +// DeviceType definitions - from BBS specification +// +#define BBS_TYPE_FLOPPY 0x01 +#define BBS_TYPE_HARDDRIVE 0x02 +#define BBS_TYPE_CDROM 0x03 +#define BBS_TYPE_PCMCIA 0x04 +#define BBS_TYPE_USB 0x05 +#define BBS_TYPE_EMBEDDED_NETWORK 0x06 +#define BBS_TYPE_BEV 0x80 +#define BBS_TYPE_UNKNOWN 0xFF + + +/// +/// Union of all possible Device Paths and pointers to Device Paths +/// + +typedef union { + EFI_DEVICE_PATH_PROTOCOL DevPath; + PCI_DEVICE_PATH Pci; + PCCARD_DEVICE_PATH PcCard; + MEMMAP_DEVICE_PATH MemMap; + VENDOR_DEVICE_PATH Vendor; + + CONTROLLER_DEVICE_PATH Controller; + ACPI_HID_DEVICE_PATH Acpi; + + ATAPI_DEVICE_PATH Atapi; + SCSI_DEVICE_PATH Scsi; + ISCSI_DEVICE_PATH Iscsi; + FIBRECHANNEL_DEVICE_PATH FibreChannel; + + F1394_DEVICE_PATH F1394; + USB_DEVICE_PATH Usb; + SATA_DEVICE_PATH Sata; + USB_CLASS_DEVICE_PATH UsbClass; + I2O_DEVICE_PATH I2O; + MAC_ADDR_DEVICE_PATH MacAddr; + IPv4_DEVICE_PATH Ipv4; + IPv6_DEVICE_PATH Ipv6; + INFINIBAND_DEVICE_PATH InfiniBand; + UART_DEVICE_PATH Uart; + + HARDDRIVE_DEVICE_PATH HardDrive; + CDROM_DEVICE_PATH CD; + + FILEPATH_DEVICE_PATH FilePath; + MEDIA_PROTOCOL_DEVICE_PATH MediaProtocol; + + BBS_BBS_DEVICE_PATH Bbs; +} EFI_DEV_PATH; + + + +typedef union { + EFI_DEVICE_PATH_PROTOCOL *DevPath; + PCI_DEVICE_PATH *Pci; + PCCARD_DEVICE_PATH *PcCard; + MEMMAP_DEVICE_PATH *MemMap; + VENDOR_DEVICE_PATH *Vendor; + + CONTROLLER_DEVICE_PATH *Controller; + ACPI_HID_DEVICE_PATH *Acpi; + ACPI_EXTENDED_HID_DEVICE_PATH *ExtendedAcpi; + + ATAPI_DEVICE_PATH *Atapi; + SCSI_DEVICE_PATH *Scsi; + FIBRECHANNEL_DEVICE_PATH *FibreChannel; + + F1394_DEVICE_PATH *F1394; + USB_DEVICE_PATH *Usb; + SATA_DEVICE_PATH *Sata; + USB_CLASS_DEVICE_PATH *UsbClass; + I2O_DEVICE_PATH *I2O; + MAC_ADDR_DEVICE_PATH *MacAddr; + IPv4_DEVICE_PATH *Ipv4; + IPv6_DEVICE_PATH *Ipv6; + INFINIBAND_DEVICE_PATH *InfiniBand; + UART_DEVICE_PATH *Uart; + + HARDDRIVE_DEVICE_PATH *HardDrive; + CDROM_DEVICE_PATH *CD; + + FILEPATH_DEVICE_PATH *FilePath; + MEDIA_PROTOCOL_DEVICE_PATH *MediaProtocol; + + BBS_BBS_DEVICE_PATH *Bbs; + UINT8 *Raw; +} EFI_DEV_PATH_PTR; + +#pragma pack() + +#define END_DEVICE_PATH_TYPE 0x7f +#define END_ENTIRE_DEVICE_PATH_SUBTYPE 0xFF +#define END_INSTANCE_DEVICE_PATH_SUBTYPE 0x01 + +extern EFI_GUID gEfiDevicePathProtocolGuid; + +#endif diff --git a/gpxe/src/include/gpxe/efi/Protocol/DriverBinding.h b/gpxe/src/include/gpxe/efi/Protocol/DriverBinding.h new file mode 100644 index 00000000..510cb7ce --- /dev/null +++ b/gpxe/src/include/gpxe/efi/Protocol/DriverBinding.h @@ -0,0 +1,153 @@ +/** @file + UEFI DriverBinding Protocol is defined in UEFI specification. + + This protocol is produced by every driver that follows the UEFI Driver Model, + and it is the central component that allows drivers and controllers to be managed. + + Copyright (c) 2006 - 2008, Intel Corporation + All rights reserved. This program and the accompanying materials + are licensed and made available under the terms and conditions of the BSD License + which accompanies this distribution. The full text of the license may be found at + http://opensource.org/licenses/bsd-license.php + + THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, + WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + +**/ + +#ifndef __EFI_DRIVER_BINDING_H__ +#define __EFI_DRIVER_BINDING_H__ + +#include <gpxe/efi/Protocol/DevicePath.h> +/// +/// Global ID for the ControllerHandle Driver Protocol +/// +#define EFI_DRIVER_BINDING_PROTOCOL_GUID \ + { \ + 0x18a031ab, 0xb443, 0x4d1a, {0xa5, 0xc0, 0xc, 0x9, 0x26, 0x1e, 0x9f, 0x71 } \ + } + +typedef struct _EFI_DRIVER_BINDING_PROTOCOL EFI_DRIVER_BINDING_PROTOCOL; + +/** + Test to see if this driver supports ControllerHandle. This service + is called by the EFI boot service ConnectController(). In + order to make drivers as small as possible, there are a few calling + restrictions for this service. ConnectController() must + follow these calling restrictions. If any other agent wishes to call + Supported() it must also follow these calling restrictions. + + @param This Protocol instance pointer. + @param ControllerHandle Handle of device to test + @param RemainingDevicePath Optional parameter use to pick a specific child + device to start. + + @retval EFI_SUCCESS This driver supports this device + @retval EFI_ALREADY_STARTED This driver is already running on this device + @retval other This driver does not support this device + +**/ +typedef +EFI_STATUS +(EFIAPI *EFI_DRIVER_BINDING_SUPPORTED)( + IN EFI_DRIVER_BINDING_PROTOCOL *This, + IN EFI_HANDLE ControllerHandle, + IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath OPTIONAL + ); + +/** + Start this driver on ControllerHandle. This service is called by the + EFI boot service ConnectController(). In order to make + drivers as small as possible, there are a few calling restrictions for + this service. ConnectController() must follow these + calling restrictions. If any other agent wishes to call Start() it + must also follow these calling restrictions. + + @param This Protocol instance pointer. + @param ControllerHandle Handle of device to bind driver to + @param RemainingDevicePath Optional parameter use to pick a specific child + device to start. + + @retval EFI_SUCCESS This driver is added to ControllerHandle + @retval EFI_ALREADY_STARTED This driver is already running on ControllerHandle + @retval other This driver does not support this device + +**/ +typedef +EFI_STATUS +(EFIAPI *EFI_DRIVER_BINDING_START)( + IN EFI_DRIVER_BINDING_PROTOCOL *This, + IN EFI_HANDLE ControllerHandle, + IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath OPTIONAL + ); + +/** + Stop this driver on ControllerHandle. This service is called by the + EFI boot service DisconnectController(). In order to + make drivers as small as possible, there are a few calling + restrictions for this service. DisconnectController() + must follow these calling restrictions. If any other agent wishes + to call Stop() it must also follow these calling restrictions. + + @param This Protocol instance pointer. + @param ControllerHandle Handle of device to stop driver on + @param NumberOfChildren Number of Handles in ChildHandleBuffer. If number of + children is zero stop the entire bus driver. + @param ChildHandleBuffer List of Child Handles to Stop. + + @retval EFI_SUCCESS This driver is removed ControllerHandle + @retval other This driver was not removed from this device + +**/ +typedef +EFI_STATUS +(EFIAPI *EFI_DRIVER_BINDING_STOP)( + IN EFI_DRIVER_BINDING_PROTOCOL *This, + IN EFI_HANDLE ControllerHandle, + IN UINTN NumberOfChildren, + IN EFI_HANDLE *ChildHandleBuffer OPTIONAL + ); + +/// +/// This protocol provides the services required to determine if a driver supports a given controller. +/// If a controller is supported, then it also provides routines to start and stop the controller. +/// +struct _EFI_DRIVER_BINDING_PROTOCOL { + EFI_DRIVER_BINDING_SUPPORTED Supported; + EFI_DRIVER_BINDING_START Start; + EFI_DRIVER_BINDING_STOP Stop; + + /// + /// The version number of the UEFI driver that produced the + /// EFI_DRIVER_BINDING_PROTOCOL. This field is used by + /// the EFI boot service ConnectController() to determine + /// the order that driver's Supported() service will be used when + /// a controller needs to be started. EFI Driver Binding Protocol + /// instances with higher Version values will be used before ones + /// with lower Version values. The Version values of 0x0- + /// 0x0f and 0xfffffff0-0xffffffff are reserved for + /// platform/OEM specific drivers. The Version values of 0x10- + /// 0xffffffef are reserved for IHV-developed drivers. + /// + UINT32 Version; + + /// + /// The image handle of the UEFI driver that produced this instance + /// of the EFI_DRIVER_BINDING_PROTOCOL. + /// + EFI_HANDLE ImageHandle; + + /// + /// The handle on which this instance of the + /// EFI_DRIVER_BINDING_PROTOCOL is installed. In most + /// cases, this is the same handle as ImageHandle. However, for + /// UEFI drivers that produce more than one instance of the + /// EFI_DRIVER_BINDING_PROTOCOL, this value may not be + /// the same as ImageHandle. + /// + EFI_HANDLE DriverBindingHandle; +}; + +extern EFI_GUID gEfiDriverBindingProtocolGuid; + +#endif diff --git a/gpxe/src/include/gpxe/efi/Protocol/NetworkInterfaceIdentifier.h b/gpxe/src/include/gpxe/efi/Protocol/NetworkInterfaceIdentifier.h new file mode 100644 index 00000000..e99ec38e --- /dev/null +++ b/gpxe/src/include/gpxe/efi/Protocol/NetworkInterfaceIdentifier.h @@ -0,0 +1,74 @@ +/** @file + EFI Network Interface Identifier Protocol + + Copyright (c) 2006 - 2008, Intel Corporation + All rights reserved. This program and the accompanying materials + are licensed and made available under the terms and conditions of the BSD License + which accompanies this distribution. The full text of the license may be found at + http://opensource.org/licenses/bsd-license.php + + THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, + WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + + +**/ + +#ifndef __EFI_NETWORK_INTERFACE_IDENTIFER_H__ +#define __EFI_NETWORK_INTERFACE_IDENTIFER_H__ + + +#define EFI_NETWORK_INTERFACE_IDENTIFIER_PROTOCOL_GUID \ + { \ + 0xE18541CD, 0xF755, 0x4f73, {0x92, 0x8D, 0x64, 0x3C, 0x8A, 0x79, 0xB2, 0x29 } \ + } + +#define EFI_NETWORK_INTERFACE_IDENTIFIER_PROTOCOL_REVISION 0x00010000 + +/// +/// Revision defined in EFI1.1. +/// +#define EFI_NETWORK_INTERFACE_IDENTIFIER_INTERFACE_REVISION EFI_NETWORK_INTERFACE_IDENTIFIER_PROTOCOL_REVISION + +/// +/// Forward reference for pure ANSI compatability +/// +typedef struct _EFI_NETWORK_INTERFACE_IDENTIFIER_PROTOCOL EFI_NETWORK_INTERFACE_IDENTIFIER_PROTOCOL; + +/// +/// Protocol defined in EFI1.1. +/// +typedef EFI_NETWORK_INTERFACE_IDENTIFIER_PROTOCOL EFI_NETWORK_INTERFACE_IDENTIFIER_INTERFACE; + +typedef enum { + EfiNetworkInterfaceUndi = 1 +} EFI_NETWORK_PROTOCOL_TYPE; + +/// +/// An optional protocol that is used to describe details about the software +/// layer that is used to produce the Simple Network Protocol. +/// +struct _EFI_NETWORK_INTERFACE_IDENTIFIER_PROTOCOL { + UINT64 Revision; ///< The revision of the EFI_NETWORK_INTERFACE_IDENTIFIER protocol. + UINT64 ID; ///< Address of the first byte of the identifying structure for this network + ///< interface. This is only valid when the network interface is started + ///< (see Start()). When the network interface is not started, this field is set to zero. + UINT64 ImageAddr; ///< Address of the first byte of the identifying structure for this + ///< network interface. This is set to zero if there is no structure. + UINT32 ImageSize; ///< Size of unrelocated network interface image. + CHAR8 StringId[4];///< A four-character ASCII string that is sent in the class identifier field of + ///< option 60 in DHCP. For a Type of EfiNetworkInterfaceUndi, this field is UNDI. + UINT8 Type; ///< Network interface type. This will be set to one of the values + ///< in EFI_NETWORK_INTERFACE_TYPE. + UINT8 MajorVer; ///< Major version number. + UINT8 MinorVer; ///< Minor version number. + BOOLEAN Ipv6Supported; ///< TRUE if the network interface supports IPv6; otherwise FALSE. + UINT8 IfNum; ///< The network interface number that is being identified by this Network + ///< Interface Identifier Protocol. This field must be less than or equal + ///< to the IFcnt field in the !PXE structure. + +}; + +extern EFI_GUID gEfiNetworkInterfaceIdentifierProtocolGuid; +extern EFI_GUID gEfiNetworkInterfaceIdentifierProtocolGuid_31; + +#endif // _EFI_NII_H diff --git a/gpxe/src/include/gpxe/efi/Protocol/PciIo.h b/gpxe/src/include/gpxe/efi/Protocol/PciIo.h new file mode 100644 index 00000000..5aea5b4a --- /dev/null +++ b/gpxe/src/include/gpxe/efi/Protocol/PciIo.h @@ -0,0 +1,519 @@ +/** @file + EFI PCI I/O Protocol provides the basic Memory, I/O, PCI configuration, + and DMA interfaces that a driver uses to access its PCI controller. + + Copyright (c) 2006 - 2008, Intel Corporation + All rights reserved. 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 __PCI_IO_H__ +#define __PCI_IO_H__ + +/// +/// Global ID for the PCI I/O Protocol +/// +#define EFI_PCI_IO_PROTOCOL_GUID \ + { \ + 0x4cf5b200, 0x68b8, 0x4ca5, {0x9e, 0xec, 0xb2, 0x3e, 0x3f, 0x50, 0x2, 0x9a } \ + } + +typedef struct _EFI_PCI_IO_PROTOCOL EFI_PCI_IO_PROTOCOL; + +/// +/// Prototypes for the PCI I/O Protocol +/// +typedef enum { + EfiPciIoWidthUint8 = 0, + EfiPciIoWidthUint16, + EfiPciIoWidthUint32, + EfiPciIoWidthUint64, + EfiPciIoWidthFifoUint8, + EfiPciIoWidthFifoUint16, + EfiPciIoWidthFifoUint32, + EfiPciIoWidthFifoUint64, + EfiPciIoWidthFillUint8, + EfiPciIoWidthFillUint16, + EfiPciIoWidthFillUint32, + EfiPciIoWidthFillUint64, + EfiPciIoWidthMaximum +} EFI_PCI_IO_PROTOCOL_WIDTH; + +// +// Complete PCI address generater +// +#define EFI_PCI_IO_PASS_THROUGH_BAR 0xff ///< Special BAR that passes a memory or I/O cycle through unchanged +#define EFI_PCI_IO_ATTRIBUTE_MASK 0x077f ///< All the following I/O and Memory cycles +#define EFI_PCI_IO_ATTRIBUTE_ISA_MOTHERBOARD_IO 0x0001 ///< I/O cycles 0x0000-0x00FF (10 bit decode) +#define EFI_PCI_IO_ATTRIBUTE_ISA_IO 0x0002 ///< I/O cycles 0x0100-0x03FF or greater (10 bit decode) +#define EFI_PCI_IO_ATTRIBUTE_VGA_PALETTE_IO 0x0004 ///< I/O cycles 0x3C6, 0x3C8, 0x3C9 (10 bit decode) +#define EFI_PCI_IO_ATTRIBUTE_VGA_MEMORY 0x0008 ///< MEM cycles 0xA0000-0xBFFFF (24 bit decode) +#define EFI_PCI_IO_ATTRIBUTE_VGA_IO 0x0010 ///< I/O cycles 0x3B0-0x3BB and 0x3C0-0x3DF (10 bit decode) +#define EFI_PCI_IO_ATTRIBUTE_IDE_PRIMARY_IO 0x0020 ///< I/O cycles 0x1F0-0x1F7, 0x3F6, 0x3F7 (10 bit decode) +#define EFI_PCI_IO_ATTRIBUTE_IDE_SECONDARY_IO 0x0040 ///< I/O cycles 0x170-0x177, 0x376, 0x377 (10 bit decode) +#define EFI_PCI_IO_ATTRIBUTE_MEMORY_WRITE_COMBINE 0x0080 ///< Map a memory range so write are combined +#define EFI_PCI_IO_ATTRIBUTE_IO 0x0100 ///< Enable the I/O decode bit in the PCI Config Header +#define EFI_PCI_IO_ATTRIBUTE_MEMORY 0x0200 ///< Enable the Memory decode bit in the PCI Config Header +#define EFI_PCI_IO_ATTRIBUTE_BUS_MASTER 0x0400 ///< Enable the DMA bit in the PCI Config Header +#define EFI_PCI_IO_ATTRIBUTE_MEMORY_CACHED 0x0800 ///< Map a memory range so all r/w accesses are cached +#define EFI_PCI_IO_ATTRIBUTE_MEMORY_DISABLE 0x1000 ///< Disable a memory range +#define EFI_PCI_IO_ATTRIBUTE_EMBEDDED_DEVICE 0x2000 ///< Clear for an add-in PCI Device +#define EFI_PCI_IO_ATTRIBUTE_EMBEDDED_ROM 0x4000 ///< Clear for a physical PCI Option ROM accessed through ROM BAR +#define EFI_PCI_IO_ATTRIBUTE_DUAL_ADDRESS_CYCLE 0x8000 ///< Clear for PCI controllers that can not genrate a DAC +#define EFI_PCI_IO_ATTRIBUTE_ISA_IO_16 0x10000 ///< I/O cycles 0x0100-0x03FF or greater (16 bit decode) +#define EFI_PCI_IO_ATTRIBUTE_VGA_PALETTE_IO_16 0x20000 ///< I/O cycles 0x3C6, 0x3C8, 0x3C9 (16 bit decode) +#define EFI_PCI_IO_ATTRIBUTE_VGA_IO_16 0x30000 ///< I/O cycles 0x3B0-0x3BB and 0x3C0-0x3DF (16 bit decode) + +#define EFI_PCI_DEVICE_ENABLE (EFI_PCI_IO_ATTRIBUTE_IO | EFI_PCI_IO_ATTRIBUTE_MEMORY | EFI_PCI_IO_ATTRIBUTE_BUS_MASTER) +#define EFI_VGA_DEVICE_ENABLE (EFI_PCI_IO_ATTRIBUTE_VGA_PALETTE_IO | EFI_PCI_IO_ATTRIBUTE_VGA_MEMORY | EFI_PCI_IO_ATTRIBUTE_VGA_IO | EFI_PCI_IO_ATTRIBUTE_IO) + +/// +/// ******************************************************* +/// EFI_PCI_IO_PROTOCOL_OPERATION +/// ******************************************************* +/// +typedef enum { + EfiPciIoOperationBusMasterRead, + EfiPciIoOperationBusMasterWrite, + EfiPciIoOperationBusMasterCommonBuffer, + EfiPciIoOperationMaximum +} EFI_PCI_IO_PROTOCOL_OPERATION; + +/// +/// ******************************************************* +/// EFI_PCI_IO_PROTOCOL_ATTRIBUTE_OPERATION +/// ******************************************************* +/// +typedef enum { + EfiPciIoAttributeOperationGet, + EfiPciIoAttributeOperationSet, + EfiPciIoAttributeOperationEnable, + EfiPciIoAttributeOperationDisable, + EfiPciIoAttributeOperationSupported, + EfiPciIoAttributeOperationMaximum +} EFI_PCI_IO_PROTOCOL_ATTRIBUTE_OPERATION; + +/** + Reads from the memory space of a PCI controller. Returns when either the polling exit criteria is + satisfied or after a defined duration. + + @param This A pointer to the EFI_PCI_IO_PROTOCOL instance. + @param Width Signifies the width of the memory or I/O operations. + @param BarIndex The BAR index of the standard PCI Configuration header to use as the + base address for the memory operation to perform. + @param Offset The offset within the selected BAR to start the memory operation. + @param Mask Mask used for the polling criteria. + @param Value The comparison value used for the polling exit criteria. + @param Delay The number of 100 ns units to poll. + @param Result Pointer to the last value read from the memory location. + + @retval EFI_SUCCESS The last data returned from the access matched the poll exit criteria. + @retval EFI_UNSUPPORTED BarIndex not valid for this PCI controller. + @retval EFI_UNSUPPORTED Offset is not valid for the BarIndex of this PCI controller. + @retval EFI_TIMEOUT Delay expired before a match occurred. + @retval EFI_OUT_OF_RESOURCES The request could not be completed due to a lack of resources. + @retval EFI_INVALID_PARAMETER One or more parameters are invalid. + +**/ +typedef +EFI_STATUS +(EFIAPI *EFI_PCI_IO_PROTOCOL_POLL_IO_MEM)( + IN EFI_PCI_IO_PROTOCOL *This, + IN EFI_PCI_IO_PROTOCOL_WIDTH Width, + IN UINT8 BarIndex, + IN UINT64 Offset, + IN UINT64 Mask, + IN UINT64 Value, + IN UINT64 Delay, + OUT UINT64 *Result + ); + +/** + Enable a PCI driver to access PCI controller registers in the PCI memory or I/O space. + + @param This A pointer to the EFI_PCI_IO_PROTOCOL instance. + @param Width Signifies the width of the memory or I/O operations. + @param BarIndex The BAR index of the standard PCI Configuration header to use as the + base address for the memory or I/O operation to perform. + @param Offset The offset within the selected BAR to start the memory or I/O operation. + @param Count The number of memory or I/O operations to perform. + @param Buffer For read operations, the destination buffer to store the results. For write + operations, the source buffer to write data from. + + @retval EFI_SUCCESS The data was read from or written to the PCI controller. + @retval EFI_UNSUPPORTED BarIndex not valid for this PCI controller. + @retval EFI_UNSUPPORTED The address range specified by Offset, Width, and Count is not + valid for the PCI BAR specified by BarIndex. + @retval EFI_OUT_OF_RESOURCES The request could not be completed due to a lack of resources. + @retval EFI_INVALID_PARAMETER One or more parameters are invalid. + +**/ +typedef +EFI_STATUS +(EFIAPI *EFI_PCI_IO_PROTOCOL_IO_MEM)( + IN EFI_PCI_IO_PROTOCOL *This, + IN EFI_PCI_IO_PROTOCOL_WIDTH Width, + IN UINT8 BarIndex, + IN UINT64 Offset, + IN UINTN Count, + IN OUT VOID *Buffer + ); + +typedef struct { + EFI_PCI_IO_PROTOCOL_IO_MEM Read; + EFI_PCI_IO_PROTOCOL_IO_MEM Write; +} EFI_PCI_IO_PROTOCOL_ACCESS; + +/** + Enable a PCI driver to access PCI controller registers in PCI configuration space. + + @param This A pointer to the EFI_PCI_IO_PROTOCOL instance. + @param Width Signifies the width of the memory operations. + @param Offset The offset within the PCI configuration space for the PCI controller. + @param Count The number of PCI configuration operations to perform. + @param Buffer For read operations, the destination buffer to store the results. For write + operations, the source buffer to write data from. + + + @retval EFI_SUCCESS The data was read from or written to the PCI controller. + @retval EFI_UNSUPPORTED The address range specified by Offset, Width, and Count is not + valid for the PCI configuration header of the PCI controller. + @retval EFI_OUT_OF_RESOURCES The request could not be completed due to a lack of resources. + @retval EFI_INVALID_PARAMETER Buffer is NULL or Width is invalid. + +**/ +typedef +EFI_STATUS +(EFIAPI *EFI_PCI_IO_PROTOCOL_CONFIG)( + IN EFI_PCI_IO_PROTOCOL *This, + IN EFI_PCI_IO_PROTOCOL_WIDTH Width, + IN UINT32 Offset, + IN UINTN Count, + IN OUT VOID *Buffer + ); + +typedef struct { + EFI_PCI_IO_PROTOCOL_CONFIG Read; + EFI_PCI_IO_PROTOCOL_CONFIG Write; +} EFI_PCI_IO_PROTOCOL_CONFIG_ACCESS; + +/** + Enables a PCI driver to copy one region of PCI memory space to another region of PCI + memory space. + + @param This A pointer to the EFI_PCI_IO_PROTOCOL instance. + @param Width Signifies the width of the memory operations. + @param DestBarIndex The BAR index in the standard PCI Configuration header to use as the + base address for the memory operation to perform. + @param DestOffset The destination offset within the BAR specified by DestBarIndex to + start the memory writes for the copy operation. + @param SrcBarIndex The BAR index in the standard PCI Configuration header to use as the + base address for the memory operation to perform. + @param SrcOffset The source offset within the BAR specified by SrcBarIndex to start + the memory reads for the copy operation. + @param Count The number of memory operations to perform. Bytes moved is Width + size * Count, starting at DestOffset and SrcOffset. + + @retval EFI_SUCCESS The data was copied from one memory region to another memory region. + @retval EFI_UNSUPPORTED DestBarIndex not valid for this PCI controller. + @retval EFI_UNSUPPORTED SrcBarIndex not valid for this PCI controller. + @retval EFI_UNSUPPORTED The address range specified by DestOffset, Width, and Count + is not valid for the PCI BAR specified by DestBarIndex. + @retval EFI_UNSUPPORTED The address range specified by SrcOffset, Width, and Count is + not valid for the PCI BAR specified by SrcBarIndex. + @retval EFI_INVALID_PARAMETER Width is invalid. + @retval EFI_OUT_OF_RESOURCES The request could not be completed due to a lack of resources. + +**/ +typedef +EFI_STATUS +(EFIAPI *EFI_PCI_IO_PROTOCOL_COPY_MEM)( + IN EFI_PCI_IO_PROTOCOL *This, + IN EFI_PCI_IO_PROTOCOL_WIDTH Width, + IN UINT8 DestBarIndex, + IN UINT64 DestOffset, + IN UINT8 SrcBarIndex, + IN UINT64 SrcOffset, + IN UINTN Count + ); + +/** + Provides the PCI controller-Cspecific addresses needed to access system memory. + + @param This A pointer to the EFI_PCI_IO_PROTOCOL instance. + @param Operation Indicates if the bus master is going to read or write to system memory. + @param HostAddress The system memory address to map to the PCI controller. + @param NumberOfBytes On input the number of bytes to map. On output the number of bytes + that were mapped. + @param DeviceAddress The resulting map address for the bus master PCI controller to use to + access the hosts HostAddress. + @param Mapping A resulting value to pass to Unmap(). + + @retval EFI_SUCCESS The range was mapped for the returned NumberOfBytes. + @retval EFI_UNSUPPORTED The HostAddress cannot be mapped as a common buffer. + @retval EFI_INVALID_PARAMETER One or more parameters are invalid. + @retval EFI_OUT_OF_RESOURCES The request could not be completed due to a lack of resources. + @retval EFI_DEVICE_ERROR The system hardware could not map the requested address. + +**/ +typedef +EFI_STATUS +(EFIAPI *EFI_PCI_IO_PROTOCOL_MAP)( + IN EFI_PCI_IO_PROTOCOL *This, + IN EFI_PCI_IO_PROTOCOL_OPERATION Operation, + IN VOID *HostAddress, + IN OUT UINTN *NumberOfBytes, + OUT EFI_PHYSICAL_ADDRESS *DeviceAddress, + OUT VOID **Mapping + ); + +/** + Completes the Map() operation and releases any corresponding resources. + + @param This A pointer to the EFI_PCI_IO_PROTOCOL instance. + @param Mapping The mapping value returned from Map(). + + @retval EFI_SUCCESS The range was unmapped. + @retval EFI_DEVICE_ERROR The data was not committed to the target system memory. + +**/ +typedef +EFI_STATUS +(EFIAPI *EFI_PCI_IO_PROTOCOL_UNMAP)( + IN EFI_PCI_IO_PROTOCOL *This, + IN VOID *Mapping + ); + +/** + Allocates pages that are suitable for an EfiPciIoOperationBusMasterCommonBuffer + mapping. + + @param This A pointer to the EFI_PCI_IO_PROTOCOL instance. + @param Type This parameter is not used and must be ignored. + @param MemoryType The type of memory to allocate, EfiBootServicesData or + EfiRuntimeServicesData. + @param Pages The number of pages to allocate. + @param HostAddress A pointer to store the base system memory address of the + allocated range. + @param Attributes The requested bit mask of attributes for the allocated range. + + @retval EFI_SUCCESS The requested memory pages were allocated. + @retval EFI_UNSUPPORTED Attributes is unsupported. The only legal attribute bits are + MEMORY_WRITE_COMBINE and MEMORY_CACHED. + @retval EFI_INVALID_PARAMETER One or more parameters are invalid. + @retval EFI_OUT_OF_RESOURCES The memory pages could not be allocated. + +**/ +typedef +EFI_STATUS +(EFIAPI *EFI_PCI_IO_PROTOCOL_ALLOCATE_BUFFER)( + IN EFI_PCI_IO_PROTOCOL *This, + IN EFI_ALLOCATE_TYPE Type, + IN EFI_MEMORY_TYPE MemoryType, + IN UINTN Pages, + OUT VOID **HostAddress, + IN UINT64 Attributes + ); + +/** + Frees memory that was allocated with AllocateBuffer(). + + @param This A pointer to the EFI_PCI_IO_PROTOCOL instance. + @param Pages The number of pages to free. + @param HostAddress The base system memory address of the allocated range. + + @retval EFI_SUCCESS The requested memory pages were freed. + @retval EFI_INVALID_PARAMETER The memory range specified by HostAddress and Pages + was not allocated with AllocateBuffer(). + +**/ +typedef +EFI_STATUS +(EFIAPI *EFI_PCI_IO_PROTOCOL_FREE_BUFFER)( + IN EFI_PCI_IO_PROTOCOL *This, + IN UINTN Pages, + IN VOID *HostAddress + ); + +/** + Flushes all PCI posted write transactions from a PCI host bridge to system memory. + + @param This A pointer to the EFI_PCI_IO_PROTOCOL instance. + + @retval EFI_SUCCESS The PCI posted write transactions were flushed from the PCI host + bridge to system memory. + @retval EFI_DEVICE_ERROR The PCI posted write transactions were not flushed from the PCI + host bridge due to a hardware error. + +**/ +typedef +EFI_STATUS +(EFIAPI *EFI_PCI_IO_PROTOCOL_FLUSH)( + IN EFI_PCI_IO_PROTOCOL *This + ); + +/** + Retrieves this PCI controller's current PCI bus number, device number, and function number. + + @param This A pointer to the EFI_PCI_IO_PROTOCOL instance. + @param SegmentNumber The PCI controller's current PCI segment number. + @param BusNumber The PCI controller's current PCI bus number. + @param DeviceNumber The PCI controller's current PCI device number. + @param FunctionNumber The PCI controller's current PCI function number. + + @retval EFI_SUCCESS The PCI controller location was returned. + @retval EFI_INVALID_PARAMETER One or more parameters are invalid. + +**/ +typedef +EFI_STATUS +(EFIAPI *EFI_PCI_IO_PROTOCOL_GET_LOCATION)( + IN EFI_PCI_IO_PROTOCOL *This, + OUT UINTN *SegmentNumber, + OUT UINTN *BusNumber, + OUT UINTN *DeviceNumber, + OUT UINTN *FunctionNumber + ); + +/** + Performs an operation on the attributes that this PCI controller supports. The operations include + getting the set of supported attributes, retrieving the current attributes, setting the current + attributes, enabling attributes, and disabling attributes. + + @param This A pointer to the EFI_PCI_IO_PROTOCOL instance. + @param Operation The operation to perform on the attributes for this PCI controller. + @param Attributes The mask of attributes that are used for Set, Enable, and Disable + operations. + @param Result A pointer to the result mask of attributes that are returned for the Get + and Supported operations. + + @retval EFI_SUCCESS The operation on the PCI controller's attributes was completed. + @retval EFI_INVALID_PARAMETER One or more parameters are invalid. + @retval EFI_UNSUPPORTED one or more of the bits set in + Attributes are not supported by this PCI controller or one of + its parent bridges when Operation is Set, Enable or Disable. + +**/ +typedef +EFI_STATUS +(EFIAPI *EFI_PCI_IO_PROTOCOL_ATTRIBUTES)( + IN EFI_PCI_IO_PROTOCOL *This, + IN EFI_PCI_IO_PROTOCOL_ATTRIBUTE_OPERATION Operation, + IN UINT64 Attributes, + OUT UINT64 *Result OPTIONAL + ); + +/** + Gets the attributes that this PCI controller supports setting on a BAR using + SetBarAttributes(), and retrieves the list of resource descriptors for a BAR. + + @param This A pointer to the EFI_PCI_IO_PROTOCOL instance. + @param BarIndex The BAR index of the standard PCI Configuration header to use as the + base address for resource range. The legal range for this field is 0..5. + @param Supports A pointer to the mask of attributes that this PCI controller supports + setting for this BAR with SetBarAttributes(). + @param Resources A pointer to the ACPI 2.0 resource descriptors that describe the current + configuration of this BAR of the PCI controller. + + @retval EFI_SUCCESS If Supports is not NULL, then the attributes that the PCI + controller supports are returned in Supports. If Resources + is not NULL, then the ACPI 2.0 resource descriptors that the PCI + controller is currently using are returned in Resources. + @retval EFI_INVALID_PARAMETER Both Supports and Attributes are NULL. + @retval EFI_UNSUPPORTED BarIndex not valid for this PCI controller. + @retval EFI_OUT_OF_RESOURCES There are not enough resources available to allocate + Resources. + +**/ +typedef +EFI_STATUS +(EFIAPI *EFI_PCI_IO_PROTOCOL_GET_BAR_ATTRIBUTES)( + IN EFI_PCI_IO_PROTOCOL *This, + IN UINT8 BarIndex, + OUT UINT64 *Supports, OPTIONAL + OUT VOID **Resources OPTIONAL + ); + +/** + Sets the attributes for a range of a BAR on a PCI controller. + + @param This A pointer to the EFI_PCI_IO_PROTOCOL instance. + @param Attributes The mask of attributes to set for the resource range specified by + BarIndex, Offset, and Length. + @param BarIndex The BAR index of the standard PCI Configuration header to use as the + base address for resource range. The legal range for this field is 0..5. + @param Offset A pointer to the BAR relative base address of the resource range to be + modified by the attributes specified by Attributes. + @param Length A pointer to the length of the resource range to be modified by the + attributes specified by Attributes. + + @retval EFI_SUCCESS The set of attributes specified by Attributes for the resource + range specified by BarIndex, Offset, and Length were + set on the PCI controller, and the actual resource range is returned + in Offset and Length. + @retval EFI_INVALID_PARAMETER Offset or Length is NULL. + @retval EFI_UNSUPPORTED BarIndex not valid for this PCI controller. + @retval EFI_OUT_OF_RESOURCES There are not enough resources to set the attributes on the + resource range specified by BarIndex, Offset, and + Length. + +**/ +typedef +EFI_STATUS +(EFIAPI *EFI_PCI_IO_PROTOCOL_SET_BAR_ATTRIBUTES)( + IN EFI_PCI_IO_PROTOCOL *This, + IN UINT64 Attributes, + IN UINT8 BarIndex, + IN OUT UINT64 *Offset, + IN OUT UINT64 *Length + ); + +/// +/// The EFI_PCI_IO_PROTOCOL provides the basic Memory, I/O, PCI configuration, +/// and DMA interfaces that are used to abstract accesses to PCI controllers. +/// There is one EFI_PCI_IO_PROTOCOL instance for each PCI controller on a PCI bus. +/// A device driver that wishes to manage a PCI controller in a system will have to +/// retrieve the EFI_PCI_IO_PROTOCOL instance that is associated with the PCI controller. +/// +struct _EFI_PCI_IO_PROTOCOL { + EFI_PCI_IO_PROTOCOL_POLL_IO_MEM PollMem; + EFI_PCI_IO_PROTOCOL_POLL_IO_MEM PollIo; + EFI_PCI_IO_PROTOCOL_ACCESS Mem; + EFI_PCI_IO_PROTOCOL_ACCESS Io; + EFI_PCI_IO_PROTOCOL_CONFIG_ACCESS Pci; + EFI_PCI_IO_PROTOCOL_COPY_MEM CopyMem; + EFI_PCI_IO_PROTOCOL_MAP Map; + EFI_PCI_IO_PROTOCOL_UNMAP Unmap; + EFI_PCI_IO_PROTOCOL_ALLOCATE_BUFFER AllocateBuffer; + EFI_PCI_IO_PROTOCOL_FREE_BUFFER FreeBuffer; + EFI_PCI_IO_PROTOCOL_FLUSH Flush; + EFI_PCI_IO_PROTOCOL_GET_LOCATION GetLocation; + EFI_PCI_IO_PROTOCOL_ATTRIBUTES Attributes; + EFI_PCI_IO_PROTOCOL_GET_BAR_ATTRIBUTES GetBarAttributes; + EFI_PCI_IO_PROTOCOL_SET_BAR_ATTRIBUTES SetBarAttributes; + + /// + /// The size, in bytes, of the ROM image. + /// + UINT64 RomSize; + + /// + /// A pointer to the in memory copy of the ROM image. The PCI Bus Driver is responsible + /// for allocating memory for the ROM image, and copying the contents of the ROM to memory. + /// The contents of this buffer are either from the PCI option ROM that can be accessed + /// through the ROM BAR of the PCI controller, or it is from a platform-specific location. + /// The Attributes() function can be used to determine from which of these two sources + /// the RomImage buffer was initialized. + /// + VOID *RomImage; +}; + +extern EFI_GUID gEfiPciIoProtocolGuid; + +#endif diff --git a/gpxe/src/include/gpxe/efi/Protocol/PciRootBridgeIo.h b/gpxe/src/include/gpxe/efi/Protocol/PciRootBridgeIo.h new file mode 100644 index 00000000..a1150f08 --- /dev/null +++ b/gpxe/src/include/gpxe/efi/Protocol/PciRootBridgeIo.h @@ -0,0 +1,393 @@ +/** @file + PCI Root Bridge I/O protocol as defined in the UEFI 2.0 specification. + + PCI Root Bridge I/O protocol is used by PCI Bus Driver to perform PCI Memory, PCI I/O, + and PCI Configuration cycles on a PCI Root Bridge. It also provides services to perform + defferent types of bus mastering DMA + + Copyright (c) 2006 - 2008, Intel Corporation + All rights reserved. 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 __PCI_ROOT_BRIDGE_IO_H__ +#define __PCI_ROOT_BRIDGE_IO_H__ + +#define EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL_GUID \ + { \ + 0x2f707ebb, 0x4a1a, 0x11d4, {0x9a, 0x38, 0x00, 0x90, 0x27, 0x3f, 0xc1, 0x4d } \ + } + +typedef struct _EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL; + +typedef enum { + EfiPciWidthUint8, + EfiPciWidthUint16, + EfiPciWidthUint32, + EfiPciWidthUint64, + EfiPciWidthFifoUint8, + EfiPciWidthFifoUint16, + EfiPciWidthFifoUint32, + EfiPciWidthFifoUint64, + EfiPciWidthFillUint8, + EfiPciWidthFillUint16, + EfiPciWidthFillUint32, + EfiPciWidthFillUint64, + EfiPciWidthMaximum +} EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL_WIDTH; + +typedef enum { + EfiPciOperationBusMasterRead, + EfiPciOperationBusMasterWrite, + EfiPciOperationBusMasterCommonBuffer, + EfiPciOperationBusMasterRead64, + EfiPciOperationBusMasterWrite64, + EfiPciOperationBusMasterCommonBuffer64, + EfiPciOperationMaximum +} EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL_OPERATION; + +#define EFI_PCI_ATTRIBUTE_ISA_MOTHERBOARD_IO 0x0001 +#define EFI_PCI_ATTRIBUTE_ISA_IO 0x0002 +#define EFI_PCI_ATTRIBUTE_VGA_PALETTE_IO 0x0004 +#define EFI_PCI_ATTRIBUTE_VGA_MEMORY 0x0008 +#define EFI_PCI_ATTRIBUTE_VGA_IO 0x0010 +#define EFI_PCI_ATTRIBUTE_IDE_PRIMARY_IO 0x0020 +#define EFI_PCI_ATTRIBUTE_IDE_SECONDARY_IO 0x0040 +#define EFI_PCI_ATTRIBUTE_MEMORY_WRITE_COMBINE 0x0080 +#define EFI_PCI_ATTRIBUTE_MEMORY_CACHED 0x0800 +#define EFI_PCI_ATTRIBUTE_MEMORY_DISABLE 0x1000 +#define EFI_PCI_ATTRIBUTE_DUAL_ADDRESS_CYCLE 0x8000 + +#define EFI_PCI_ATTRIBUTE_VALID_FOR_ALLOCATE_BUFFER (EFI_PCI_ATTRIBUTE_MEMORY_WRITE_COMBINE | EFI_PCI_ATTRIBUTE_MEMORY_CACHED | EFI_PCI_ATTRIBUTE_DUAL_ADDRESS_CYCLE) + +#define EFI_PCI_ATTRIBUTE_INVALID_FOR_ALLOCATE_BUFFER (~EFI_PCI_ATTRIBUTE_VALID_FOR_ALLOCATE_BUFFER) + +#define EFI_PCI_ADDRESS(bus, dev, func, reg) \ + ((UINT64) ((((UINTN) bus) << 24) + (((UINTN) dev) << 16) + (((UINTN) func) << 8) + ((UINTN) reg))) + +typedef struct { + UINT8 Register; + UINT8 Function; + UINT8 Device; + UINT8 Bus; + UINT32 ExtendedRegister; +} EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL_PCI_ADDRESS; + +/** + Reads from the I/O space of a PCI Root Bridge. Returns when either the polling exit criteria is + satisfied or after a defined duration. + + @param This A pointer to the EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL. + @param Width Signifies the width of the memory or I/O operations. + @param Address The base address of the memory or I/O operations. + @param Mask Mask used for the polling criteria. + @param Value The comparison value used for the polling exit criteria. + @param Delay The number of 100 ns units to poll. + @param Result Pointer to the last value read from the memory location. + + @retval EFI_SUCCESS The last data returned from the access matched the poll exit criteria. + @retval EFI_TIMEOUT Delay expired before a match occurred. + @retval EFI_OUT_OF_RESOURCES The request could not be completed due to a lack of resources. + @retval EFI_INVALID_PARAMETER One or more parameters are invalid. + +**/ +typedef +EFI_STATUS +(EFIAPI *EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL_POLL_IO_MEM)( + IN EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL *This, + IN EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL_WIDTH Width, + IN UINT64 Address, + IN UINT64 Mask, + IN UINT64 Value, + IN UINT64 Delay, + OUT UINT64 *Result + ); + +/** + Enables a PCI driver to access PCI controller registers in the PCI root bridge memory space. + + @param This A pointer to the EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL. + @param Width Signifies the width of the memory operations. + @param Address The base address of the memory operations. + @param Count The number of memory operations to perform. + @param Buffer For read operations, the destination buffer to store the results. For write + operations, the source buffer to write data from. + + @retval EFI_SUCCESS The data was read from or written to the PCI root bridge. + @retval EFI_OUT_OF_RESOURCES The request could not be completed due to a lack of resources. + @retval EFI_INVALID_PARAMETER One or more parameters are invalid. + +**/ +typedef +EFI_STATUS +(EFIAPI *EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL_IO_MEM)( + IN EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL *This, + IN EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL_WIDTH Width, + IN UINT64 Address, + IN UINTN Count, + IN OUT VOID *Buffer + ); + +typedef struct { + EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL_IO_MEM Read; + EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL_IO_MEM Write; +} EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL_ACCESS; + +/** + Enables a PCI driver to copy one region of PCI root bridge memory space to another region of PCI + root bridge memory space. + + @param This A pointer to the EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL instance. + @param Width Signifies the width of the memory operations. + @param DestAddress The destination address of the memory operation. + @param SrcAddress The source address of the memory operation. + @param Count The number of memory operations to perform. + + @retval EFI_SUCCESS The data was copied from one memory region to another memory region. + @retval EFI_INVALID_PARAMETER Width is invalid for this PCI root bridge. + @retval EFI_OUT_OF_RESOURCES The request could not be completed due to a lack of resources. + +**/ +typedef +EFI_STATUS +(EFIAPI *EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL_COPY_MEM)( + IN EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL *This, + IN EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL_WIDTH Width, + IN UINT64 DestAddress, + IN UINT64 SrcAddress, + IN UINTN Count + ); + +/** + Provides the PCI controller-Cspecific addresses required to access system memory from a + DMA bus master. + + @param This A pointer to the EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL. + @param Operation Indicates if the bus master is going to read or write to system memory. + @param HostAddress The system memory address to map to the PCI controller. + @param NumberOfBytes On input the number of bytes to map. On output the number of bytes + that were mapped. + @param DeviceAddress The resulting map address for the bus master PCI controller to use to + access the hosts HostAddress. + @param Mapping A resulting value to pass to Unmap(). + + @retval EFI_SUCCESS The range was mapped for the returned NumberOfBytes. + @retval EFI_UNSUPPORTED The HostAddress cannot be mapped as a common buffer. + @retval EFI_INVALID_PARAMETER One or more parameters are invalid. + @retval EFI_OUT_OF_RESOURCES The request could not be completed due to a lack of resources. + @retval EFI_DEVICE_ERROR The system hardware could not map the requested address. + +**/ +typedef +EFI_STATUS +(EFIAPI *EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL_MAP)( + IN EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL *This, + IN EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL_OPERATION Operation, + IN VOID *HostAddress, + IN OUT UINTN *NumberOfBytes, + OUT EFI_PHYSICAL_ADDRESS *DeviceAddress, + OUT VOID **Mapping + ); + +/** + Completes the Map() operation and releases any corresponding resources. + + @param This A pointer to the EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL. + @param Mapping The mapping value returned from Map(). + + @retval EFI_SUCCESS The range was unmapped. + @retval EFI_INVALID_PARAMETER Mapping is not a value that was returned by Map(). + @retval EFI_DEVICE_ERROR The data was not committed to the target system memory. + +**/ +typedef +EFI_STATUS +(EFIAPI *EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL_UNMAP)( + IN EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL *This, + IN VOID *Mapping + ); + +/** + Allocates pages that are suitable for an EfiPciOperationBusMasterCommonBuffer or + EfiPciOperationBusMasterCommonBuffer64 mapping. + + @param This A pointer to the EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL. + @param Type This parameter is not used and must be ignored. + @param MemoryType The type of memory to allocate, EfiBootServicesData or + EfiRuntimeServicesData. + @param Pages The number of pages to allocate. + @param HostAddress A pointer to store the base system memory address of the + allocated range. + @param Attributes The requested bit mask of attributes for the allocated range. + + @retval EFI_SUCCESS The requested memory pages were allocated. + @retval EFI_UNSUPPORTED Attributes is unsupported. The only legal attribute bits are + MEMORY_WRITE_COMBINE and MEMORY_CACHED. + @retval EFI_INVALID_PARAMETER One or more parameters are invalid. + @retval EFI_OUT_OF_RESOURCES The memory pages could not be allocated. + +**/ +typedef +EFI_STATUS +(EFIAPI *EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL_ALLOCATE_BUFFER)( + IN EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL *This, + IN EFI_ALLOCATE_TYPE Type, + IN EFI_MEMORY_TYPE MemoryType, + IN UINTN Pages, + IN OUT VOID **HostAddress, + IN UINT64 Attributes + ); + +/** + Frees memory that was allocated with AllocateBuffer(). + + @param This A pointer to the EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL. + @param Pages The number of pages to free. + @param HostAddress The base system memory address of the allocated range. + + @retval EFI_SUCCESS The requested memory pages were freed. + @retval EFI_INVALID_PARAMETER The memory range specified by HostAddress and Pages + was not allocated with AllocateBuffer(). + +**/ +typedef +EFI_STATUS +(EFIAPI *EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL_FREE_BUFFER)( + IN EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL *This, + IN UINTN Pages, + IN VOID *HostAddress + ); + +/** + Flushes all PCI posted write transactions from a PCI host bridge to system memory. + + @param This A pointer to the EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL. + + @retval EFI_SUCCESS The PCI posted write transactions were flushed from the PCI host + bridge to system memory. + @retval EFI_DEVICE_ERROR The PCI posted write transactions were not flushed from the PCI + host bridge due to a hardware error. + +**/ +typedef +EFI_STATUS +(EFIAPI *EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL_FLUSH)( + IN EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL *This + ); + +/** + Gets the attributes that a PCI root bridge supports setting with SetAttributes(), and the + attributes that a PCI root bridge is currently using. + + @param This A pointer to the EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL. + @param Supports A pointer to the mask of attributes that this PCI root bridge supports + setting with SetAttributes(). + @param Attributes A pointer to the mask of attributes that this PCI root bridge is currently + using. + + @retval EFI_SUCCESS If Supports is not NULL, then the attributes that the PCI root + bridge supports is returned in Supports. If Attributes is + not NULL, then the attributes that the PCI root bridge is currently + using is returned in Attributes. + @retval EFI_INVALID_PARAMETER Both Supports and Attributes are NULL. + + +**/ +typedef +EFI_STATUS +(EFIAPI *EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL_GET_ATTRIBUTES)( + IN EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL *This, + OUT UINT64 *Supports, + OUT UINT64 *Attributes + ); + +/** + Sets attributes for a resource range on a PCI root bridge. + + @param This A pointer to the EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL. + @param Attributes The mask of attributes to set. + @param ResourceBase A pointer to the base address of the resource range to be modified by the + attributes specified by Attributes. + @param ResourceLength A pointer to the length of the resource range to be modified by the + attributes specified by Attributes. + + @retval EFI_SUCCESS The set of attributes specified by Attributes for the resource + range specified by ResourceBase and ResourceLength + were set on the PCI root bridge, and the actual resource range is + returned in ResuourceBase and ResourceLength. + @retval EFI_UNSUPPORTED A bit is set in Attributes that is not supported by the PCI Root + Bridge. + @retval EFI_OUT_OF_RESOURCES There are not enough resources to set the attributes on the + resource range specified by BaseAddress and Length. + @retval EFI_INVALID_PARAMETER One or more parameters are invalid. + +**/ +typedef +EFI_STATUS +(EFIAPI *EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL_SET_ATTRIBUTES)( + IN EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL *This, + IN UINT64 Attributes, + IN OUT UINT64 *ResourceBase, + IN OUT UINT64 *ResourceLength + ); + +/** + Retrieves the current resource settings of this PCI root bridge in the form of a set of ACPI 2.0 + resource descriptors. + + @param This A pointer to the EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL. + @param Resources A pointer to the ACPI 2.0 resource descriptors that describe the current + configuration of this PCI root bridge. + + @retval EFI_SUCCESS The current configuration of this PCI root bridge was returned in + Resources. + @retval EFI_UNSUPPORTED The current configuration of this PCI root bridge could not be + retrieved. + +**/ +typedef +EFI_STATUS +(EFIAPI *EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL_CONFIGURATION)( + IN EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL *This, + OUT VOID **Resources + ); + +/// +/// Provides the basic Memory, I/O, PCI configuration, and DMA interfaces that are +/// used to abstract accesses to PCI controllers behind a PCI Root Bridge Controller. +/// +struct _EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL { + /// + /// The EFI_HANDLE of the PCI Host Bridge of which this PCI Root Bridge is a member. + /// + EFI_HANDLE ParentHandle; + EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL_POLL_IO_MEM PollMem; + EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL_POLL_IO_MEM PollIo; + EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL_ACCESS Mem; + EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL_ACCESS Io; + EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL_ACCESS Pci; + EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL_COPY_MEM CopyMem; + EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL_MAP Map; + EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL_UNMAP Unmap; + EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL_ALLOCATE_BUFFER AllocateBuffer; + EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL_FREE_BUFFER FreeBuffer; + EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL_FLUSH Flush; + EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL_GET_ATTRIBUTES GetAttributes; + EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL_SET_ATTRIBUTES SetAttributes; + EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL_CONFIGURATION Configuration; + + /// + /// The segment number that this PCI root bridge resides. + /// + UINT32 SegmentNumber; +}; + +extern EFI_GUID gEfiPciRootBridgeIoProtocolGuid; + +#endif diff --git a/gpxe/src/include/gpxe/efi/Protocol/SimpleNetwork.h b/gpxe/src/include/gpxe/efi/Protocol/SimpleNetwork.h new file mode 100644 index 00000000..d3d2afc7 --- /dev/null +++ b/gpxe/src/include/gpxe/efi/Protocol/SimpleNetwork.h @@ -0,0 +1,593 @@ +/** @file + Simple Network protocol as defined in the UEFI 2.0 specification. + + Basic network device abstraction. + + Rx - Received + Tx - Transmit + MCast - MultiCast + ... + + Copyright (c) 2006 - 2008, Intel Corporation + All rights reserved. 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 __SIMPLE_NETWORK_H__ +#define __SIMPLE_NETWORK_H__ + +#define EFI_SIMPLE_NETWORK_PROTOCOL_GUID \ + { \ + 0xA19832B9, 0xAC25, 0x11D3, {0x9A, 0x2D, 0x00, 0x90, 0x27, 0x3F, 0xC1, 0x4D } \ + } + +typedef struct _EFI_SIMPLE_NETWORK_PROTOCOL EFI_SIMPLE_NETWORK_PROTOCOL; + + +/// +/// Protocol defined in EFI1.1. +/// +typedef EFI_SIMPLE_NETWORK_PROTOCOL EFI_SIMPLE_NETWORK; + +/// +/// Simple Network Protocol data structures +/// +typedef struct { + /// + /// Total number of frames received. Includes frames with errors and + /// dropped frames. + /// + UINT64 RxTotalFrames; + + /// + /// Number of valid frames received and copied into receive buffers. + /// + UINT64 RxGoodFrames; + + /// + /// Number of frames below the minimum length for the media. + /// This would be <64 for ethernet. + /// + UINT64 RxUndersizeFrames; + + /// + /// Number of frames longer than the maxminum length for the + /// media. This would be >1500 for ethernet. + /// + UINT64 RxOversizeFrames; + + /// + /// Valid frames that were dropped because receive buffers were full. + /// + UINT64 RxDroppedFrames; + + /// + /// Number of valid unicast frames received and not dropped. + /// + UINT64 RxUnicastFrames; + + /// + /// Number of valid broadcast frames received and not dropped. + /// + UINT64 RxBroadcastFrames; + + /// + /// Number of valid mutlicast frames received and not dropped. + /// + UINT64 RxMulticastFrames; + + /// + /// Number of frames w/ CRC or alignment errors. + /// + UINT64 RxCrcErrorFrames; + + /// + /// Total number of bytes received. Includes frames with errors + /// and dropped frames. + // + UINT64 RxTotalBytes; + + /// + /// Transmit statistics. + /// + UINT64 TxTotalFrames; + UINT64 TxGoodFrames; + UINT64 TxUndersizeFrames; + UINT64 TxOversizeFrames; + UINT64 TxDroppedFrames; + UINT64 TxUnicastFrames; + UINT64 TxBroadcastFrames; + UINT64 TxMulticastFrames; + UINT64 TxCrcErrorFrames; + UINT64 TxTotalBytes; + + /// + /// Number of collisions detection on this subnet. + /// + UINT64 Collisions; + + /// + /// Number of frames destined for unsupported protocol. + /// + UINT64 UnsupportedProtocol; + +} EFI_NETWORK_STATISTICS; + +typedef enum { + EfiSimpleNetworkStopped, + EfiSimpleNetworkStarted, + EfiSimpleNetworkInitialized, + EfiSimpleNetworkMaxState +} EFI_SIMPLE_NETWORK_STATE; + +#define EFI_SIMPLE_NETWORK_RECEIVE_UNICAST 0x01 +#define EFI_SIMPLE_NETWORK_RECEIVE_MULTICAST 0x02 +#define EFI_SIMPLE_NETWORK_RECEIVE_BROADCAST 0x04 +#define EFI_SIMPLE_NETWORK_RECEIVE_PROMISCUOUS 0x08 +#define EFI_SIMPLE_NETWORK_RECEIVE_PROMISCUOUS_MULTICAST 0x10 + +#define EFI_SIMPLE_NETWORK_RECEIVE_INTERRUPT 0x01 +#define EFI_SIMPLE_NETWORK_TRANSMIT_INTERRUPT 0x02 +#define EFI_SIMPLE_NETWORK_COMMAND_INTERRUPT 0x04 +#define EFI_SIMPLE_NETWORK_SOFTWARE_INTERRUPT 0x08 + +#define MAX_MCAST_FILTER_CNT 16 +typedef struct { + UINT32 State; + UINT32 HwAddressSize; + UINT32 MediaHeaderSize; + UINT32 MaxPacketSize; + UINT32 NvRamSize; + UINT32 NvRamAccessSize; + UINT32 ReceiveFilterMask; + UINT32 ReceiveFilterSetting; + UINT32 MaxMCastFilterCount; + UINT32 MCastFilterCount; + EFI_MAC_ADDRESS MCastFilter[MAX_MCAST_FILTER_CNT]; + EFI_MAC_ADDRESS CurrentAddress; + EFI_MAC_ADDRESS BroadcastAddress; + EFI_MAC_ADDRESS PermanentAddress; + UINT8 IfType; + BOOLEAN MacAddressChangeable; + BOOLEAN MultipleTxSupported; + BOOLEAN MediaPresentSupported; + BOOLEAN MediaPresent; +} EFI_SIMPLE_NETWORK_MODE; + +// +// Protocol Member Functions +// +/** + Changes the state of a network interface from "stopped" to "started". + + @param This Protocol instance pointer. + + @retval EFI_SUCCESS The network interface was started. + @retval EFI_ALREADY_STARTED The network interface is already in the started state. + @retval EFI_INVALID_PARAMETER One or more of the parameters has an unsupported value. + @retval EFI_DEVICE_ERROR The command could not be sent to the network interface. + @retval EFI_UNSUPPORTED This function is not supported by the network interface. + +**/ +typedef +EFI_STATUS +(EFIAPI *EFI_SIMPLE_NETWORK_START)( + IN EFI_SIMPLE_NETWORK_PROTOCOL *This + ); + +/** + Changes the state of a network interface from "started" to "stopped". + + @param This Protocol instance pointer. + + @retval EFI_SUCCESS The network interface was stopped. + @retval EFI_ALREADY_STARTED The network interface is already in the stopped state. + @retval EFI_INVALID_PARAMETER One or more of the parameters has an unsupported value. + @retval EFI_DEVICE_ERROR The command could not be sent to the network interface. + @retval EFI_UNSUPPORTED This function is not supported by the network interface. + +**/ +typedef +EFI_STATUS +(EFIAPI *EFI_SIMPLE_NETWORK_STOP)( + IN EFI_SIMPLE_NETWORK_PROTOCOL *This + ); + +/** + Resets a network adapter and allocates the transmit and receive buffers + required by the network interface; optionally, also requests allocation + of additional transmit and receive buffers. + + @param This Protocol instance pointer. + @param ExtraRxBufferSize The size, in bytes, of the extra receive buffer space + that the driver should allocate for the network interface. + Some network interfaces will not be able to use the extra + buffer, and the caller will not know if it is actually + being used. + @param ExtraTxBufferSize The size, in bytes, of the extra transmit buffer space + that the driver should allocate for the network interface. + Some network interfaces will not be able to use the extra + buffer, and the caller will not know if it is actually + being used. + + @retval EFI_SUCCESS The network interface was initialized. + @retval EFI_NOT_STARTED The network interface has not been started + @retval EFI_OUT_OF_RESOURCES There was not enough memory for the transmit and + receive buffers. . + @retval EFI_INVALID_PARAMETER One or more of the parameters has an unsupported value. + @retval EFI_DEVICE_ERROR The command could not be sent to the network interface. + @retval EFI_UNSUPPORTED This function is not supported by the network interface. + +**/ +typedef +EFI_STATUS +(EFIAPI *EFI_SIMPLE_NETWORK_INITIALIZE)( + IN EFI_SIMPLE_NETWORK_PROTOCOL *This, + IN UINTN ExtraRxBufferSize OPTIONAL, + IN UINTN ExtraTxBufferSize OPTIONAL + ); + +/** + Resets a network adapter and re-initializes it with the parameters that were + provided in the previous call to Initialize(). + + @param This Protocol instance pointer. + @param ExtendedVerification Indicates that the driver may perform a more + exhaustive verification operation of the device + during reset. + + @retval EFI_SUCCESS The network interface was reset. + @retval EFI_NOT_STARTED The network interface has not been started + @retval EFI_INVALID_PARAMETER One or more of the parameters has an unsupported value. + @retval EFI_DEVICE_ERROR The command could not be sent to the network interface. + @retval EFI_UNSUPPORTED This function is not supported by the network interface. + +**/ +typedef +EFI_STATUS +(EFIAPI *EFI_SIMPLE_NETWORK_RESET)( + IN EFI_SIMPLE_NETWORK_PROTOCOL *This, + IN BOOLEAN ExtendedVerification + ); + +/** + Resets a network adapter and leaves it in a state that is safe for + another driver to initialize. + + @param This Protocol instance pointer. + + @retval EFI_SUCCESS The network interface was shutdown. + @retval EFI_NOT_STARTED The network interface has not been started + @retval EFI_INVALID_PARAMETER One or more of the parameters has an unsupported value. + @retval EFI_DEVICE_ERROR The command could not be sent to the network interface. + @retval EFI_UNSUPPORTED This function is not supported by the network interface. + +**/ +typedef +EFI_STATUS +(EFIAPI *EFI_SIMPLE_NETWORK_SHUTDOWN)( + IN EFI_SIMPLE_NETWORK_PROTOCOL *This + ); + +/** + Manages the multicast receive filters of a network interface. + + @param This Protocol instance pointer. + @param Enable A bit mask of receive filters to enable on the network interface. + @param Disable A bit mask of receive filters to disable on the network interface. + @param ResetMCastFilter Set to TRUE to reset the contents of the multicast receive + filters on the network interface to their default values. + @param McastFilterCnt Number of multicast HW MAC addresses in the new + MCastFilter list. This value must be less than or equal to + the MCastFilterCnt field of EFI_SIMPLE_NETWORK_MODE. This + field is optional if ResetMCastFilter is TRUE. + @param MCastFilter A pointer to a list of new multicast receive filter HW MAC + addresses. This list will replace any existing multicast + HW MAC address list. This field is optional if + ResetMCastFilter is TRUE. + + @retval EFI_SUCCESS The multicast receive filter list was updated. + @retval EFI_NOT_STARTED The network interface has not been started + @retval EFI_INVALID_PARAMETER One or more of the parameters has an unsupported value. + @retval EFI_DEVICE_ERROR The command could not be sent to the network interface. + @retval EFI_UNSUPPORTED This function is not supported by the network interface. + +**/ +typedef +EFI_STATUS +(EFIAPI *EFI_SIMPLE_NETWORK_RECEIVE_FILTERS)( + IN EFI_SIMPLE_NETWORK_PROTOCOL *This, + IN UINT32 Enable, + IN UINT32 Disable, + IN BOOLEAN ResetMCastFilter, + IN UINTN MCastFilterCnt OPTIONAL, + IN EFI_MAC_ADDRESS *MCastFilter OPTIONAL + ); + +/** + Modifies or resets the current station address, if supported. + + @param This Protocol instance pointer. + @param Reset Flag used to reset the station address to the network interfaces + permanent address. + @param New New station address to be used for the network interface. + + @retval EFI_SUCCESS The network interfaces station address was updated. + @retval EFI_NOT_STARTED The network interface has not been started + @retval EFI_INVALID_PARAMETER One or more of the parameters has an unsupported value. + @retval EFI_DEVICE_ERROR The command could not be sent to the network interface. + @retval EFI_UNSUPPORTED This function is not supported by the network interface. + +**/ +typedef +EFI_STATUS +(EFIAPI *EFI_SIMPLE_NETWORK_STATION_ADDRESS)( + IN EFI_SIMPLE_NETWORK_PROTOCOL *This, + IN BOOLEAN Reset, + IN EFI_MAC_ADDRESS *New OPTIONAL + ); + +/** + Resets or collects the statistics on a network interface. + + @param This Protocol instance pointer. + @param Reset Set to TRUE to reset the statistics for the network interface. + @param StatisticsSize On input the size, in bytes, of StatisticsTable. On + output the size, in bytes, of the resulting table of + statistics. + @param StatisticsTable A pointer to the EFI_NETWORK_STATISTICS structure that + contains the statistics. + + @retval EFI_SUCCESS The statistics were collected from the network interface. + @retval EFI_NOT_STARTED The network interface has not been started. + @retval EFI_BUFFER_TOO_SMALL The Statistics buffer was too small. The current buffer + size needed to hold the statistics is returned in + StatisticsSize. + @retval EFI_INVALID_PARAMETER One or more of the parameters has an unsupported value. + @retval EFI_DEVICE_ERROR The command could not be sent to the network interface. + @retval EFI_UNSUPPORTED This function is not supported by the network interface. + +**/ +typedef +EFI_STATUS +(EFIAPI *EFI_SIMPLE_NETWORK_STATISTICS)( + IN EFI_SIMPLE_NETWORK_PROTOCOL *This, + IN BOOLEAN Reset, + IN OUT UINTN *StatisticsSize OPTIONAL, + OUT EFI_NETWORK_STATISTICS *StatisticsTable OPTIONAL + ); + +/** + Converts a multicast IP address to a multicast HW MAC address. + + @param This Protocol instance pointer. + @param IPv6 Set to TRUE if the multicast IP address is IPv6 [RFC 2460]. Set + to FALSE if the multicast IP address is IPv4 [RFC 791]. + @param IP The multicast IP address that is to be converted to a multicast + HW MAC address. + @param MAC The multicast HW MAC address that is to be generated from IP. + + @retval EFI_SUCCESS The multicast IP address was mapped to the multicast + HW MAC address. + @retval EFI_NOT_STARTED The network interface has not been started. + @retval EFI_BUFFER_TOO_SMALL The Statistics buffer was too small. The current buffer + size needed to hold the statistics is returned in + StatisticsSize. + @retval EFI_INVALID_PARAMETER One or more of the parameters has an unsupported value. + @retval EFI_DEVICE_ERROR The command could not be sent to the network interface. + @retval EFI_UNSUPPORTED This function is not supported by the network interface. + +**/ +typedef +EFI_STATUS +(EFIAPI *EFI_SIMPLE_NETWORK_MCAST_IP_TO_MAC)( + IN EFI_SIMPLE_NETWORK_PROTOCOL *This, + IN BOOLEAN IPv6, + IN EFI_IP_ADDRESS *IP, + OUT EFI_MAC_ADDRESS *MAC + ); + +/** + Performs read and write operations on the NVRAM device attached to a + network interface. + + @param This Protocol instance pointer. + @param ReadWrite TRUE for read operations, FALSE for write operations. + @param Offset Byte offset in the NVRAM device at which to start the read or + write operation. This must be a multiple of NvRamAccessSize and + less than NvRamSize. + @param BufferSize The number of bytes to read or write from the NVRAM device. + This must also be a multiple of NvramAccessSize. + @param Buffer A pointer to the data buffer. + + @retval EFI_SUCCESS The NVRAM access was performed. + @retval EFI_NOT_STARTED The network interface has not been started. + @retval EFI_INVALID_PARAMETER One or more of the parameters has an unsupported value. + @retval EFI_DEVICE_ERROR The command could not be sent to the network interface. + @retval EFI_UNSUPPORTED This function is not supported by the network interface. + +**/ +typedef +EFI_STATUS +(EFIAPI *EFI_SIMPLE_NETWORK_NVDATA)( + IN EFI_SIMPLE_NETWORK_PROTOCOL *This, + IN BOOLEAN ReadWrite, + IN UINTN Offset, + IN UINTN BufferSize, + IN OUT VOID *Buffer + ); + +/** + Reads the current interrupt status and recycled transmit buffer status from + a network interface. + + @param This Protocol instance pointer. + @param InterruptStatus A pointer to the bit mask of the currently active interrupts + If this is NULL, the interrupt status will not be read from + the device. If this is not NULL, the interrupt status will + be read from the device. When the interrupt status is read, + it will also be cleared. Clearing the transmit interrupt + does not empty the recycled transmit buffer array. + @param TxBuf Recycled transmit buffer address. The network interface will + not transmit if its internal recycled transmit buffer array + is full. Reading the transmit buffer does not clear the + transmit interrupt. If this is NULL, then the transmit buffer + status will not be read. If there are no transmit buffers to + recycle and TxBuf is not NULL, * TxBuf will be set to NULL. + + @retval EFI_SUCCESS The status of the network interface was retrieved. + @retval EFI_NOT_STARTED The network interface has not been started. + @retval EFI_INVALID_PARAMETER One or more of the parameters has an unsupported value. + @retval EFI_DEVICE_ERROR The command could not be sent to the network interface. + @retval EFI_UNSUPPORTED This function is not supported by the network interface. + +**/ +typedef +EFI_STATUS +(EFIAPI *EFI_SIMPLE_NETWORK_GET_STATUS)( + IN EFI_SIMPLE_NETWORK_PROTOCOL *This, + OUT UINT32 *InterruptStatus OPTIONAL, + OUT VOID **TxBuf OPTIONAL + ); + +/** + Places a packet in the transmit queue of a network interface. + + @param This Protocol instance pointer. + @param HeaderSize The size, in bytes, of the media header to be filled in by + the Transmit() function. If HeaderSize is non-zero, then it + must be equal to This->Mode->MediaHeaderSize and the DestAddr + and Protocol parameters must not be NULL. + @param BufferSize The size, in bytes, of the entire packet (media header and + data) to be transmitted through the network interface. + @param Buffer A pointer to the packet (media header followed by data) to be + transmitted. This parameter cannot be NULL. If HeaderSize is zero, + then the media header in Buffer must already be filled in by the + caller. If HeaderSize is non-zero, then the media header will be + filled in by the Transmit() function. + @param SrcAddr The source HW MAC address. If HeaderSize is zero, then this parameter + is ignored. If HeaderSize is non-zero and SrcAddr is NULL, then + This->Mode->CurrentAddress is used for the source HW MAC address. + @param DsetAddr The destination HW MAC address. If HeaderSize is zero, then this + parameter is ignored. + @param Protocol The type of header to build. If HeaderSize is zero, then this + parameter is ignored. See RFC 1700, section "Ether Types", for + examples. + + @retval EFI_SUCCESS The packet was placed on the transmit queue. + @retval EFI_NOT_STARTED The network interface has not been started. + @retval EFI_NOT_READY The network interface is too busy to accept this transmit request. + @retval EFI_BUFFER_TOO_SMALL The BufferSize parameter is too small. + @retval EFI_INVALID_PARAMETER One or more of the parameters has an unsupported value. + @retval EFI_DEVICE_ERROR The command could not be sent to the network interface. + @retval EFI_UNSUPPORTED This function is not supported by the network interface. + +**/ +typedef +EFI_STATUS +(EFIAPI *EFI_SIMPLE_NETWORK_TRANSMIT)( + IN EFI_SIMPLE_NETWORK_PROTOCOL *This, + IN UINTN HeaderSize, + IN UINTN BufferSize, + IN VOID *Buffer, + IN EFI_MAC_ADDRESS *SrcAddr OPTIONAL, + IN EFI_MAC_ADDRESS *DestAddr OPTIONAL, + IN UINT16 *Protocol OPTIONAL + ); + +/** + Receives a packet from a network interface. + + @param This Protocol instance pointer. + @param HeaderSize The size, in bytes, of the media header received on the network + interface. If this parameter is NULL, then the media header size + will not be returned. + @param BufferSize On entry, the size, in bytes, of Buffer. On exit, the size, in + bytes, of the packet that was received on the network interface. + @param Buffer A pointer to the data buffer to receive both the media header and + the data. + @param SrcAddr The source HW MAC address. If this parameter is NULL, the + HW MAC source address will not be extracted from the media + header. + @param DsetAddr The destination HW MAC address. If this parameter is NULL, + the HW MAC destination address will not be extracted from the + media header. + @param Protocol The media header type. If this parameter is NULL, then the + protocol will not be extracted from the media header. See + RFC 1700 section "Ether Types" for examples. + + @retval EFI_SUCCESS The received data was stored in Buffer, and BufferSize has + been updated to the number of bytes received. + @retval EFI_NOT_STARTED The network interface has not been started. + @retval EFI_NOT_READY The network interface is too busy to accept this transmit + request. + @retval EFI_BUFFER_TOO_SMALL The BufferSize parameter is too small. + @retval EFI_INVALID_PARAMETER One or more of the parameters has an unsupported value. + @retval EFI_DEVICE_ERROR The command could not be sent to the network interface. + @retval EFI_UNSUPPORTED This function is not supported by the network interface. + +**/ +typedef +EFI_STATUS +(EFIAPI *EFI_SIMPLE_NETWORK_RECEIVE)( + IN EFI_SIMPLE_NETWORK_PROTOCOL *This, + OUT UINTN *HeaderSize OPTIONAL, + IN OUT UINTN *BufferSize, + OUT VOID *Buffer, + OUT EFI_MAC_ADDRESS *SrcAddr OPTIONAL, + OUT EFI_MAC_ADDRESS *DestAddr OPTIONAL, + OUT UINT16 *Protocol OPTIONAL + ); + +#define EFI_SIMPLE_NETWORK_PROTOCOL_REVISION 0x00010000 + +// +// Revision defined in EFI1.1 +// +#define EFI_SIMPLE_NETWORK_INTERFACE_REVISION EFI_SIMPLE_NETWORK_PROTOCOL_REVISION + +/// +/// The EFI_SIMPLE_NETWORK_PROTOCOL protocol is used to initialize access +/// to a network adapter. Once the network adapter initializes, +/// the EFI_SIMPLE_NETWORK_PROTOCOL protocol provides services that +/// allow packets to be transmitted and received. +/// +struct _EFI_SIMPLE_NETWORK_PROTOCOL { + /// + /// Revision of the EFI_SIMPLE_NETWORK_PROTOCOL. All future revisions must + /// be backwards compatible. If a future version is not backwards compatible + /// it is not the same GUID. + /// + UINT64 Revision; + EFI_SIMPLE_NETWORK_START Start; + EFI_SIMPLE_NETWORK_STOP Stop; + EFI_SIMPLE_NETWORK_INITIALIZE Initialize; + EFI_SIMPLE_NETWORK_RESET Reset; + EFI_SIMPLE_NETWORK_SHUTDOWN Shutdown; + EFI_SIMPLE_NETWORK_RECEIVE_FILTERS ReceiveFilters; + EFI_SIMPLE_NETWORK_STATION_ADDRESS StationAddress; + EFI_SIMPLE_NETWORK_STATISTICS Statistics; + EFI_SIMPLE_NETWORK_MCAST_IP_TO_MAC MCastIpToMac; + EFI_SIMPLE_NETWORK_NVDATA NvData; + EFI_SIMPLE_NETWORK_GET_STATUS GetStatus; + EFI_SIMPLE_NETWORK_TRANSMIT Transmit; + EFI_SIMPLE_NETWORK_RECEIVE Receive; + /// + /// Event used with WaitForEvent() to wait for a packet to be received. + /// + EFI_EVENT WaitForPacket; + /// + /// Pointer to the EFI_SIMPLE_NETWORK_MODE data for the device. + /// + EFI_SIMPLE_NETWORK_MODE *Mode; +}; + +extern EFI_GUID gEfiSimpleNetworkProtocolGuid; + +#endif diff --git a/gpxe/src/include/gpxe/efi/Protocol/SimpleTextIn.h b/gpxe/src/include/gpxe/efi/Protocol/SimpleTextIn.h new file mode 100644 index 00000000..f14f62d5 --- /dev/null +++ b/gpxe/src/include/gpxe/efi/Protocol/SimpleTextIn.h @@ -0,0 +1,136 @@ +/** @file + Simple Text In protocol from the UEFI 2.0 specification. + + Abstraction of a very simple input device like a keyboard or serial + terminal. + + Copyright (c) 2006 - 2008, Intel Corporation + All rights reserved. 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 __SIMPLE_TEXT_IN_PROTOCOL_H__ +#define __SIMPLE_TEXT_IN_PROTOCOL_H__ + +#include <gpxe/efi/ProcessorBind.h> + +#define EFI_SIMPLE_TEXT_INPUT_PROTOCOL_GUID \ + { \ + 0x387477c1, 0x69c7, 0x11d2, {0x8e, 0x39, 0x0, 0xa0, 0xc9, 0x69, 0x72, 0x3b } \ + } + +/// +/// Protocol GUID defined in EFI1.1. +/// +#define SIMPLE_INPUT_PROTOCOL EFI_SIMPLE_TEXT_INPUT_PROTOCOL_GUID + +typedef struct _EFI_SIMPLE_TEXT_INPUT_PROTOCOL EFI_SIMPLE_TEXT_INPUT_PROTOCOL; + +/// +/// Backward-compatible with EFI1.1. +/// +typedef struct _EFI_SIMPLE_TEXT_INPUT_PROTOCOL SIMPLE_INPUT_INTERFACE; +// +// Data structures +// +typedef struct { + UINT16 ScanCode; + CHAR16 UnicodeChar; +} EFI_INPUT_KEY; + +// +// Required unicode control chars +// +#define CHAR_NULL 0x0000 +#define CHAR_BACKSPACE 0x0008 +#define CHAR_TAB 0x0009 +#define CHAR_LINEFEED 0x000A +#define CHAR_CARRIAGE_RETURN 0x000D + +// +// EFI Scan codes +// +#define SCAN_NULL 0x0000 +#define SCAN_UP 0x0001 +#define SCAN_DOWN 0x0002 +#define SCAN_RIGHT 0x0003 +#define SCAN_LEFT 0x0004 +#define SCAN_HOME 0x0005 +#define SCAN_END 0x0006 +#define SCAN_INSERT 0x0007 +#define SCAN_DELETE 0x0008 +#define SCAN_PAGE_UP 0x0009 +#define SCAN_PAGE_DOWN 0x000A +#define SCAN_F1 0x000B +#define SCAN_F2 0x000C +#define SCAN_F3 0x000D +#define SCAN_F4 0x000E +#define SCAN_F5 0x000F +#define SCAN_F6 0x0010 +#define SCAN_F7 0x0011 +#define SCAN_F8 0x0012 +#define SCAN_F9 0x0013 +#define SCAN_F10 0x0014 +#define SCAN_F11 0x0015 +#define SCAN_F12 0x0016 +#define SCAN_ESC 0x0017 + +/** + Reset the input device and optionaly run diagnostics + + @param This Protocol instance pointer. + @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_INPUT_RESET)( + IN EFI_SIMPLE_TEXT_INPUT_PROTOCOL *This, + IN BOOLEAN ExtendedVerification + ); + +/** + Reads the next keystroke from the input device. The WaitForKey Event can + be used to test for existance of a keystroke via WaitForEvent () call. + + @param This Protocol instance pointer. + @param Key Driver may perform diagnostics on reset. + + @retval EFI_SUCCESS The keystroke information was returned. + @retval EFI_NOT_READY There was no keystroke data availiable. + @retval EFI_DEVICE_ERROR The keydtroke information was not returned due to + hardware errors. + +**/ +typedef +EFI_STATUS +(EFIAPI *EFI_INPUT_READ_KEY)( + IN EFI_SIMPLE_TEXT_INPUT_PROTOCOL *This, + OUT EFI_INPUT_KEY *Key + ); + +/// +/// The EFI_SIMPLE_TEXT_INPUT_PROTOCOL is used on the ConsoleIn device. +/// It is the minimum required protocol for ConsoleIn. +/// +struct _EFI_SIMPLE_TEXT_INPUT_PROTOCOL { + EFI_INPUT_RESET Reset; + EFI_INPUT_READ_KEY ReadKeyStroke; + /// + /// Event to use with WaitForEvent() to wait for a key to be available + /// + EFI_EVENT WaitForKey; +}; + +extern EFI_GUID gEfiSimpleTextInProtocolGuid; + +#endif diff --git a/gpxe/src/include/gpxe/efi/Protocol/SimpleTextOut.h b/gpxe/src/include/gpxe/efi/Protocol/SimpleTextOut.h new file mode 100644 index 00000000..426ce819 --- /dev/null +++ b/gpxe/src/include/gpxe/efi/Protocol/SimpleTextOut.h @@ -0,0 +1,404 @@ +/** @file + Simple Text Out protocol from the UEFI 2.0 specification. + + Abstraction of a very simple text based output device like VGA text mode or + a serial terminal. The Simple Text Out protocol instance can represent + a single hardware device or a virtual device that is an agregation + of multiple physical devices. + + Copyright (c) 2006 - 2008, Intel Corporation + All rights reserved. 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 __SIMPLE_TEXT_OUT_H__ +#define __SIMPLE_TEXT_OUT_H__ + +#define EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL_GUID \ + { \ + 0x387477c2, 0x69c7, 0x11d2, {0x8e, 0x39, 0x0, 0xa0, 0xc9, 0x69, 0x72, 0x3b } \ + } + +/// +/// Protocol GUID defined in EFI1.1. +/// +#define SIMPLE_TEXT_OUTPUT_PROTOCOL EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL_GUID + +typedef struct _EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL; + +/// +/// Backward-compatible with EFI1.1. +/// +typedef EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL SIMPLE_TEXT_OUTPUT_INTERFACE; + +// +// Define's for required EFI Unicode Box Draw characters +// +#define BOXDRAW_HORIZONTAL 0x2500 +#define BOXDRAW_VERTICAL 0x2502 +#define BOXDRAW_DOWN_RIGHT 0x250c +#define BOXDRAW_DOWN_LEFT 0x2510 +#define BOXDRAW_UP_RIGHT 0x2514 +#define BOXDRAW_UP_LEFT 0x2518 +#define BOXDRAW_VERTICAL_RIGHT 0x251c +#define BOXDRAW_VERTICAL_LEFT 0x2524 +#define BOXDRAW_DOWN_HORIZONTAL 0x252c +#define BOXDRAW_UP_HORIZONTAL 0x2534 +#define BOXDRAW_VERTICAL_HORIZONTAL 0x253c +#define BOXDRAW_DOUBLE_HORIZONTAL 0x2550 +#define BOXDRAW_DOUBLE_VERTICAL 0x2551 +#define BOXDRAW_DOWN_RIGHT_DOUBLE 0x2552 +#define BOXDRAW_DOWN_DOUBLE_RIGHT 0x2553 +#define BOXDRAW_DOUBLE_DOWN_RIGHT 0x2554 +#define BOXDRAW_DOWN_LEFT_DOUBLE 0x2555 +#define BOXDRAW_DOWN_DOUBLE_LEFT 0x2556 +#define BOXDRAW_DOUBLE_DOWN_LEFT 0x2557 +#define BOXDRAW_UP_RIGHT_DOUBLE 0x2558 +#define BOXDRAW_UP_DOUBLE_RIGHT 0x2559 +#define BOXDRAW_DOUBLE_UP_RIGHT 0x255a +#define BOXDRAW_UP_LEFT_DOUBLE 0x255b +#define BOXDRAW_UP_DOUBLE_LEFT 0x255c +#define BOXDRAW_DOUBLE_UP_LEFT 0x255d +#define BOXDRAW_VERTICAL_RIGHT_DOUBLE 0x255e +#define BOXDRAW_VERTICAL_DOUBLE_RIGHT 0x255f +#define BOXDRAW_DOUBLE_VERTICAL_RIGHT 0x2560 +#define BOXDRAW_VERTICAL_LEFT_DOUBLE 0x2561 +#define BOXDRAW_VERTICAL_DOUBLE_LEFT 0x2562 +#define BOXDRAW_DOUBLE_VERTICAL_LEFT 0x2563 +#define BOXDRAW_DOWN_HORIZONTAL_DOUBLE 0x2564 +#define BOXDRAW_DOWN_DOUBLE_HORIZONTAL 0x2565 +#define BOXDRAW_DOUBLE_DOWN_HORIZONTAL 0x2566 +#define BOXDRAW_UP_HORIZONTAL_DOUBLE 0x2567 +#define BOXDRAW_UP_DOUBLE_HORIZONTAL 0x2568 +#define BOXDRAW_DOUBLE_UP_HORIZONTAL 0x2569 +#define BOXDRAW_VERTICAL_HORIZONTAL_DOUBLE 0x256a +#define BOXDRAW_VERTICAL_DOUBLE_HORIZONTAL 0x256b +#define BOXDRAW_DOUBLE_VERTICAL_HORIZONTAL 0x256c + +// +// EFI Required Block Elements Code Chart +// +#define BLOCKELEMENT_FULL_BLOCK 0x2588 +#define BLOCKELEMENT_LIGHT_SHADE 0x2591 + +// +// EFI Required Geometric Shapes Code Chart +// +#define GEOMETRICSHAPE_UP_TRIANGLE 0x25b2 +#define GEOMETRICSHAPE_RIGHT_TRIANGLE 0x25ba +#define GEOMETRICSHAPE_DOWN_TRIANGLE 0x25bc +#define GEOMETRICSHAPE_LEFT_TRIANGLE 0x25c4 + +// +// EFI Required Arrow shapes +// +#define ARROW_LEFT 0x2190 +#define ARROW_UP 0x2191 +#define ARROW_RIGHT 0x2192 +#define ARROW_DOWN 0x2193 + +// +// EFI Console Colours +// +#define EFI_BLACK 0x00 +#define EFI_BLUE 0x01 +#define EFI_GREEN 0x02 +#define EFI_CYAN (EFI_BLUE | EFI_GREEN) +#define EFI_RED 0x04 +#define EFI_MAGENTA (EFI_BLUE | EFI_RED) +#define EFI_BROWN (EFI_GREEN | EFI_RED) +#define EFI_LIGHTGRAY (EFI_BLUE | EFI_GREEN | EFI_RED) +#define EFI_BRIGHT 0x08 +#define EFI_DARKGRAY (EFI_BRIGHT) +#define EFI_LIGHTBLUE (EFI_BLUE | EFI_BRIGHT) +#define EFI_LIGHTGREEN (EFI_GREEN | EFI_BRIGHT) +#define EFI_LIGHTCYAN (EFI_CYAN | EFI_BRIGHT) +#define EFI_LIGHTRED (EFI_RED | EFI_BRIGHT) +#define EFI_LIGHTMAGENTA (EFI_MAGENTA | EFI_BRIGHT) +#define EFI_YELLOW (EFI_BROWN | EFI_BRIGHT) +#define EFI_WHITE (EFI_BLUE | EFI_GREEN | EFI_RED | EFI_BRIGHT) + +#define EFI_TEXT_ATTR(f, b) ((f) | ((b) << 4)) + +#define EFI_BACKGROUND_BLACK 0x00 +#define EFI_BACKGROUND_BLUE 0x10 +#define EFI_BACKGROUND_GREEN 0x20 +#define EFI_BACKGROUND_CYAN (EFI_BACKGROUND_BLUE | EFI_BACKGROUND_GREEN) +#define EFI_BACKGROUND_RED 0x40 +#define EFI_BACKGROUND_MAGENTA (EFI_BACKGROUND_BLUE | EFI_BACKGROUND_RED) +#define EFI_BACKGROUND_BROWN (EFI_BACKGROUND_GREEN | EFI_BACKGROUND_RED) +#define EFI_BACKGROUND_LIGHTGRAY (EFI_BACKGROUND_BLUE | EFI_BACKGROUND_GREEN | EFI_BACKGROUND_RED) + +// +// We currently define attributes from 0 - 7F for color manipulations +// To internally handle the local display characteristics for a particular character, we are defining +// Bit 7 to signify the local glyph representation for a character. If turned on, glyphs will be +// pulled from the wide glyph database and will display locally as a wide character (16 X 19 versus 8 X 19) +// If bit 7 is off, the narrow glyph database will be used. This does NOT affect information that is sent to +// non-local displays (e.g. serial or LAN consoles). +// +#define EFI_WIDE_ATTRIBUTE 0x80 + +/** + Reset the text output device hardware and optionaly run diagnostics + + @param This Protocol instance pointer. + @param ExtendedVerification Driver may perform more exhaustive verfication + operation of the device during reset. + + @retval EFI_SUCCESS The text output device was reset. + @retval EFI_DEVICE_ERROR The text output device is not functioning correctly and + could not be reset. + +**/ +typedef +EFI_STATUS +(EFIAPI *EFI_TEXT_RESET)( + IN EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL *This, + IN BOOLEAN ExtendedVerification + ); + +/** + Write a Unicode string to the output device. + + @param This Protocol instance pointer. + @param String The NULL-terminated Unicode string to be displayed on the output + device(s). All output devices must also support the Unicode + drawing defined in this file. + + @retval EFI_SUCCESS The string was output to the device. + @retval EFI_DEVICE_ERROR The device reported an error while attempting to output + the text. + @retval EFI_UNSUPPORTED The output device's mode is not currently in a + defined text mode. + @retval EFI_WARN_UNKNOWN_GLYPH This warning code indicates that some of the + characters in the Unicode string could not be + rendered and were skipped. + +**/ +typedef +EFI_STATUS +(EFIAPI *EFI_TEXT_STRING)( + IN EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL *This, + IN CHAR16 *String + ); + +/** + Verifies that all characters in a Unicode string can be output to the + target device. + + @param This Protocol instance pointer. + @param String The NULL-terminated Unicode string to be examined for the output + device(s). + + @retval EFI_SUCCESS The device(s) are capable of rendering the output string. + @retval EFI_UNSUPPORTED Some of the characters in the Unicode string cannot be + rendered by one or more of the output devices mapped + by the EFI handle. + +**/ +typedef +EFI_STATUS +(EFIAPI *EFI_TEXT_TEST_STRING)( + IN EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL *This, + IN CHAR16 *String + ); + +/** + Returns information for an available text mode that the output device(s) + supports. + + @param This Protocol instance pointer. + @param ModeNumber The mode number to return information on. + @param Columns Returns the geometry of the text output device for the + requested ModeNumber. + @param Rows Returns the geometry of the text output device for the + requested ModeNumber. + + @retval EFI_SUCCESS The requested mode information was returned. + @retval EFI_DEVICE_ERROR The device had an error and could not complete the request. + @retval EFI_UNSUPPORTED The mode number was not valid. + +**/ +typedef +EFI_STATUS +(EFIAPI *EFI_TEXT_QUERY_MODE)( + IN EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL *This, + IN UINTN ModeNumber, + OUT UINTN *Columns, + OUT UINTN *Rows + ); + +/** + Sets the output device(s) to a specified mode. + + @param This Protocol instance pointer. + @param ModeNumber The mode number to set. + + @retval EFI_SUCCESS The requested text mode was set. + @retval EFI_DEVICE_ERROR The device had an error and could not complete the request. + @retval EFI_UNSUPPORTED The mode number was not valid. + +**/ +typedef +EFI_STATUS +(EFIAPI *EFI_TEXT_SET_MODE)( + IN EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL *This, + IN UINTN ModeNumber + ); + +/** + Sets the background and foreground colors for the OutputString () and + ClearScreen () functions. + + @param This Protocol instance pointer. + @param Attribute The attribute to set. Bits 0..3 are the foreground color, and + bits 4..6 are the background color. All other bits are undefined + and must be zero. The valid Attributes are defined in this file. + + @retval EFI_SUCCESS The attribute was set. + @retval EFI_DEVICE_ ERROR The device had an error and could not complete the request. + @retval EFI_UNSUPPORTED The attribute requested is not defined. + +**/ +typedef +EFI_STATUS +(EFIAPI *EFI_TEXT_SET_ATTRIBUTE)( + IN EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL *This, + IN UINTN Attribute + ); + +/** + Clears the output device(s) display to the currently selected background + color. + + @param This Protocol instance pointer. + + @retval EFI_SUCCESS The operation completed successfully. + @retval EFI_DEVICE_ERROR The device had an error and could not complete the request. + @retval EFI_UNSUPPORTED The output device is not in a valid text mode. + +**/ +typedef +EFI_STATUS +(EFIAPI *EFI_TEXT_CLEAR_SCREEN)( + IN EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL *This + ); + +/** + Sets the current coordinates of the cursor position + + @param This Protocol instance pointer. + @param Column The position to set the cursor to. Must be greater than or + equal to zero and less than the number of columns and rows + by QueryMode (). + @param Row The position to set the cursor to. Must be greater than or + equal to zero and less than the number of columns and rows + by QueryMode (). + + @retval EFI_SUCCESS The operation completed successfully. + @retval EFI_DEVICE_ERROR The device had an error and could not complete the request. + @retval EFI_UNSUPPORTED The output device is not in a valid text mode, or the + cursor position is invalid for the current mode. + +**/ +typedef +EFI_STATUS +(EFIAPI *EFI_TEXT_SET_CURSOR_POSITION)( + IN EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL *This, + IN UINTN Column, + IN UINTN Row + ); + +/** + Makes the cursor visible or invisible + + @param This Protocol instance pointer. + @param Visible If TRUE, the cursor is set to be visible. If FALSE, the cursor is + set to be invisible. + + @retval EFI_SUCCESS The operation completed successfully. + @retval EFI_DEVICE_ERROR The device had an error and could not complete the + request, or the device does not support changing + the cursor mode. + @retval EFI_UNSUPPORTED The output device is not in a valid text mode. + +**/ +typedef +EFI_STATUS +(EFIAPI *EFI_TEXT_ENABLE_CURSOR)( + IN EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL *This, + IN BOOLEAN Visible + ); + +/** + @par Data Structure Description: + Mode Structure pointed to by Simple Text Out protocol. + + @param MaxMode + The number of modes supported by QueryMode () and SetMode (). + + @param Mode + The text mode of the output device(s). + + @param Attribute + The current character output attribute + + @param CursorColumn + The cursor's column. + + @param CursorRow + The cursor's row. + + @param CursorVisible + The cursor is currently visbile or not. + +**/ +typedef struct { + INT32 MaxMode; + + // + // current settings + // + INT32 Mode; + INT32 Attribute; + INT32 CursorColumn; + INT32 CursorRow; + BOOLEAN CursorVisible; +} EFI_SIMPLE_TEXT_OUTPUT_MODE; + +/// +/// The SIMPLE_TEXT_OUTPUT protocol is used to control text-based output devices. +/// It is the minimum required protocol for any handle supplied as the ConsoleOut +/// or StandardError device. In addition, the minimum supported text mode of such +/// devices is at least 80 x 25 characters. +/// +struct _EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL { + EFI_TEXT_RESET Reset; + + EFI_TEXT_STRING OutputString; + EFI_TEXT_TEST_STRING TestString; + + EFI_TEXT_QUERY_MODE QueryMode; + EFI_TEXT_SET_MODE SetMode; + EFI_TEXT_SET_ATTRIBUTE SetAttribute; + + EFI_TEXT_CLEAR_SCREEN ClearScreen; + EFI_TEXT_SET_CURSOR_POSITION SetCursorPosition; + EFI_TEXT_ENABLE_CURSOR EnableCursor; + + /// + /// Pointer to SIMPLE_TEXT_OUTPUT_MODE data. + /// + EFI_SIMPLE_TEXT_OUTPUT_MODE *Mode; +}; + +extern EFI_GUID gEfiSimpleTextOutProtocolGuid; + +#endif diff --git a/gpxe/src/include/gpxe/efi/Uefi.h b/gpxe/src/include/gpxe/efi/Uefi.h new file mode 100644 index 00000000..58ddb11f --- /dev/null +++ b/gpxe/src/include/gpxe/efi/Uefi.h @@ -0,0 +1,27 @@ +/** @file + + Root include file for Mde Package UEFI, UEFI_APPLICATION type modules. + + This is the include file for any module of type UEFI and UEFI_APPLICATION. Uefi modules only use + types defined via this include file and can be ported easily to any + environment. + +Copyright (c) 2006 - 2007, Intel Corporation +All rights reserved. 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 __PI_UEFI_H__ +#define __PI_UEFI_H__ + +#include <gpxe/efi/Uefi/UefiBaseType.h> +#include <gpxe/efi/Uefi/UefiSpec.h> + +#endif + diff --git a/gpxe/src/include/gpxe/efi/Uefi/UefiBaseType.h b/gpxe/src/include/gpxe/efi/Uefi/UefiBaseType.h new file mode 100644 index 00000000..475ac01e --- /dev/null +++ b/gpxe/src/include/gpxe/efi/Uefi/UefiBaseType.h @@ -0,0 +1,200 @@ +/** @file + Defines data types and constants introduced in UEFI. + + Copyright (c) 2006 - 2008, Intel Corporation + All rights reserved. This program and the accompanying materials + are licensed and made available under the terms and conditions of the BSD License + which accompanies this distribution. The full text of the license may be found at + http://opensource.org/licenses/bsd-license.php + + THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, + WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + +**/ + +#ifndef __UEFI_BASETYPE_H__ +#define __UEFI_BASETYPE_H__ + +#include <gpxe/efi/Base.h> + +// +// Basical data type definitions introduced in UEFI. +// + +/// +/// 128-bit buffer containing a unique identifier value. +/// +typedef GUID EFI_GUID; +/// +/// Function return status for EFI API +/// +typedef RETURN_STATUS EFI_STATUS; +/// +/// A collection of related interfaces. +/// +typedef VOID *EFI_HANDLE; +/// +/// Handle to an event structure. +/// +typedef VOID *EFI_EVENT; +/// +/// Task priority level. +/// +typedef UINTN EFI_TPL; +/// +/// Logical block address. +/// +typedef UINT64 EFI_LBA; +typedef UINT64 EFI_PHYSICAL_ADDRESS; +typedef UINT64 EFI_VIRTUAL_ADDRESS; + +/// +/// EFI Time Abstraction: +/// Year: 1998 - 20XX +/// Month: 1 - 12 +/// Day: 1 - 31 +/// Hour: 0 - 23 +/// Minute: 0 - 59 +/// Second: 0 - 59 +/// Nanosecond: 0 - 999,999,999 +/// TimeZone: -1440 to 1440 or 2047 +/// +typedef struct { + UINT16 Year; + UINT8 Month; + UINT8 Day; + UINT8 Hour; + UINT8 Minute; + UINT8 Second; + UINT8 Pad1; + UINT32 Nanosecond; + INT16 TimeZone; + UINT8 Daylight; + UINT8 Pad2; +} EFI_TIME; + + +/// +/// 4-byte buffer. An IPv4 internet protocol address. +/// +typedef struct { + UINT8 Addr[4]; +} EFI_IPv4_ADDRESS; + +/// +/// 16-byte buffer. An IPv6 internet protocol address +/// +typedef struct { + UINT8 Addr[16]; +} EFI_IPv6_ADDRESS; + +/// +/// 32-byte buffer containing a network Media Access Control address. +/// +typedef struct { + UINT8 Addr[32]; +} EFI_MAC_ADDRESS; + +/// +/// 16-byte buffer aligned on a 4-byte boundary. +/// An IPv4 or IPv6 internet protocol address. +/// +typedef union { + UINT32 Addr[4]; + EFI_IPv4_ADDRESS v4; + EFI_IPv6_ADDRESS v6; +} EFI_IP_ADDRESS; + + +// +// Enumeration of EFI_STATUS. +// +#define EFI_SUCCESS RETURN_SUCCESS +#define EFI_LOAD_ERROR RETURN_LOAD_ERROR +#define EFI_INVALID_PARAMETER RETURN_INVALID_PARAMETER +#define EFI_UNSUPPORTED RETURN_UNSUPPORTED +#define EFI_BAD_BUFFER_SIZE RETURN_BAD_BUFFER_SIZE +#define EFI_BUFFER_TOO_SMALL RETURN_BUFFER_TOO_SMALL +#define EFI_NOT_READY RETURN_NOT_READY +#define EFI_DEVICE_ERROR RETURN_DEVICE_ERROR +#define EFI_WRITE_PROTECTED RETURN_WRITE_PROTECTED +#define EFI_OUT_OF_RESOURCES RETURN_OUT_OF_RESOURCES +#define EFI_VOLUME_CORRUPTED RETURN_VOLUME_CORRUPTED +#define EFI_VOLUME_FULL RETURN_VOLUME_FULL +#define EFI_NO_MEDIA RETURN_NO_MEDIA +#define EFI_MEDIA_CHANGED RETURN_MEDIA_CHANGED +#define EFI_NOT_FOUND RETURN_NOT_FOUND +#define EFI_ACCESS_DENIED RETURN_ACCESS_DENIED +#define EFI_NO_RESPONSE RETURN_NO_RESPONSE +#define EFI_NO_MAPPING RETURN_NO_MAPPING +#define EFI_TIMEOUT RETURN_TIMEOUT +#define EFI_NOT_STARTED RETURN_NOT_STARTED +#define EFI_ALREADY_STARTED RETURN_ALREADY_STARTED +#define EFI_ABORTED RETURN_ABORTED +#define EFI_ICMP_ERROR RETURN_ICMP_ERROR +#define EFI_TFTP_ERROR RETURN_TFTP_ERROR +#define EFI_PROTOCOL_ERROR RETURN_PROTOCOL_ERROR +#define EFI_INCOMPATIBLE_VERSION RETURN_INCOMPATIBLE_VERSION +#define EFI_SECURITY_VIOLATION RETURN_SECURITY_VIOLATION +#define EFI_CRC_ERROR RETURN_CRC_ERROR +#define EFI_END_OF_MEDIA RETURN_END_OF_MEDIA +#define EFI_END_OF_FILE RETURN_END_OF_FILE +#define EFI_INVALID_LANGUAGE RETURN_INVALID_LANGUAGE + +#define EFI_WARN_UNKNOWN_GLYPH RETURN_WARN_UNKNOWN_GLYPH +#define EFI_WARN_DELETE_FAILURE RETURN_WARN_DELETE_FAILURE +#define EFI_WARN_WRITE_FAILURE RETURN_WARN_WRITE_FAILURE +#define EFI_WARN_BUFFER_TOO_SMALL RETURN_WARN_BUFFER_TOO_SMALL + + +// +// Define macro to encode the status code. +// +#define EFIERR(_a) ENCODE_ERROR(_a) + +#define EFI_ERROR(A) RETURN_ERROR(A) + +// +// Define macros to build data structure signatures from characters. +// +#define EFI_SIGNATURE_16(A, B) SIGNATURE_16 (A, B) +#define EFI_SIGNATURE_32(A, B, C, D) SIGNATURE_32 (A, B, C, D) +#define EFI_SIGNATURE_64(A, B, C, D, E, F, G, H) SIGNATURE_64 (A, B, C, D, E, F, G, H) + + +/// +/// Returns the byte offset to a field within a structure +/// +#define EFI_FIELD_OFFSET(TYPE,Field) ((UINTN)(&(((TYPE *) 0)->Field))) + +// +// The EFI memory allocation functions work in units of EFI_PAGEs that are +// 4K. This should in no way be confused with the page size of the processor. +// An EFI_PAGE is just the quanta of memory in EFI. +// +#define EFI_PAGE_SIZE 0x1000 +#define EFI_PAGE_MASK 0xFFF +#define EFI_PAGE_SHIFT 12 + +#define EFI_SIZE_TO_PAGES(a) (((a) >> EFI_PAGE_SHIFT) + (((a) & EFI_PAGE_MASK) ? 1 : 0)) + +#define EFI_PAGES_TO_SIZE(a) ( (a) << EFI_PAGE_SHIFT) + + +#define EFI_MAX_BIT MAX_BIT +#define EFI_MAX_ADDRESS MAX_ADDRESS + + +/// +/// Limited buffer size for a language code recommended by RFC3066 +/// (42 characters plus a NULL terminator) +/// +#define RFC_3066_ENTRY_SIZE (42 + 1) + +/// +/// The size of a 3 character ISO639 language code. +/// +#define ISO_639_2_ENTRY_SIZE 3 + + +#endif diff --git a/gpxe/src/include/gpxe/efi/Uefi/UefiGpt.h b/gpxe/src/include/gpxe/efi/Uefi/UefiGpt.h new file mode 100644 index 00000000..92c3035e --- /dev/null +++ b/gpxe/src/include/gpxe/efi/Uefi/UefiGpt.h @@ -0,0 +1,62 @@ +/** @file + EFI Guid Partition Table Format Definition. + + Copyright (c) 2006 - 2008, Intel Corporation + All rights reserved. This program and the accompanying materials + are licensed and made available under the terms and conditions of the BSD License + which accompanies this distribution. The full text of the license may be found at + http://opensource.org/licenses/bsd-license.php + + THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, + WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + +**/ + +#ifndef __UEFI_GPT_H__ +#define __UEFI_GPT_H__ + +/// +/// The primary GUID Partition Table Header must be +/// located in LBA 1 (i.e., the second logical block). +/// +#define PRIMARY_PART_HEADER_LBA 1 + +/// +/// EFI Partition Table Signature: "EFI PART" +/// +#define EFI_PTAB_HEADER_ID 0x5452415020494645ULL + +#pragma pack(1) + +/// +/// GPT Partition Table Header +/// +typedef struct { + EFI_TABLE_HEADER Header; + EFI_LBA MyLBA; + EFI_LBA AlternateLBA; + EFI_LBA FirstUsableLBA; + EFI_LBA LastUsableLBA; + EFI_GUID DiskGUID; + EFI_LBA PartitionEntryLBA; + UINT32 NumberOfPartitionEntries; + UINT32 SizeOfPartitionEntry; + UINT32 PartitionEntryArrayCRC32; +} EFI_PARTITION_TABLE_HEADER; + +/// +/// GPT Partition Entry +/// +typedef struct { + EFI_GUID PartitionTypeGUID; + EFI_GUID UniquePartitionGUID; + EFI_LBA StartingLBA; + EFI_LBA EndingLBA; + UINT64 Attributes; + CHAR16 PartitionName[36]; +} EFI_PARTITION_ENTRY; + +#pragma pack() +#endif + + diff --git a/gpxe/src/include/gpxe/efi/Uefi/UefiInternalFormRepresentation.h b/gpxe/src/include/gpxe/efi/Uefi/UefiInternalFormRepresentation.h new file mode 100644 index 00000000..c6755173 --- /dev/null +++ b/gpxe/src/include/gpxe/efi/Uefi/UefiInternalFormRepresentation.h @@ -0,0 +1,1590 @@ +/** @file + This file defines the encoding for the VFR (Visual Form Representation) language. + IFR is primarily consumed by the EFI presentation engine, and produced by EFI + internal application and drivers as well as all add-in card option-ROM drivers + + Copyright (c) 2006 - 2008, Intel Corporation + All rights reserved. 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: + These definitions are from UEFI2.1. + +**/ + +#ifndef __UEFI_INTERNAL_FORMREPRESENTATION_H__ +#define __UEFI_INTERNAL_FORMREPRESENTATION_H__ + +/// +/// The following types are currently defined: +/// +typedef VOID* EFI_HII_HANDLE; +typedef CHAR16* EFI_STRING; +typedef UINT16 EFI_IMAGE_ID; +typedef UINT16 EFI_QUESTION_ID; +typedef UINT16 EFI_STRING_ID; +typedef UINT16 EFI_FORM_ID; +typedef UINT16 EFI_VARSTORE_ID; + +typedef UINT16 EFI_DEFAULT_ID; + +typedef UINT32 EFI_HII_FONT_STYLE; + + + +#pragma pack(1) + +// +// Definitions for Package Lists and Package Headers +// Section 27.3.1 +// + +/// +/// The header found at the start of each package list. +/// +typedef struct { + EFI_GUID PackageListGuid; + UINT32 PackageLength; +} EFI_HII_PACKAGE_LIST_HEADER; + +/// +/// The header found at the start of each package. +/// +typedef struct { + UINT32 Length:24; + UINT32 Type:8; + // UINT8 Data[...]; +} EFI_HII_PACKAGE_HEADER; + +// +// Value of HII package type +// +#define EFI_HII_PACKAGE_TYPE_ALL 0x00 +#define EFI_HII_PACKAGE_TYPE_GUID 0x01 +#define EFI_HII_PACKAGE_FORMS 0x02 +#define EFI_HII_PACKAGE_STRINGS 0x04 +#define EFI_HII_PACKAGE_FONTS 0x05 +#define EFI_HII_PACKAGE_IMAGES 0x06 +#define EFI_HII_PACKAGE_SIMPLE_FONTS 0x07 +#define EFI_HII_PACKAGE_DEVICE_PATH 0x08 +#define EFI_HII_PACKAGE_KEYBOARD_LAYOUT 0x09 +#define EFI_HII_PACKAGE_END 0xDF +#define EFI_HII_PACKAGE_TYPE_SYSTEM_BEGIN 0xE0 +#define EFI_HII_PACKAGE_TYPE_SYSTEM_END 0xFF + +// +// Definitions for Simplified Font Package +// Section 27.3.2 +// + +// +// Contents of EFI_NARROW_GLYPH.Attributes +// +#define EFI_GLYPH_NON_SPACING 0x01 +#define EFI_GLYPH_WIDE 0x02 +#define EFI_GLYPH_HEIGHT 19 +#define EFI_GLYPH_WIDTH 8 + +typedef struct { + CHAR16 UnicodeWeight; + UINT8 Attributes; + UINT8 GlyphCol1[EFI_GLYPH_HEIGHT]; +} EFI_NARROW_GLYPH; + +typedef struct { + CHAR16 UnicodeWeight; + UINT8 Attributes; + UINT8 GlyphCol1[EFI_GLYPH_HEIGHT]; + UINT8 GlyphCol2[EFI_GLYPH_HEIGHT]; + UINT8 Pad[3]; +} EFI_WIDE_GLYPH; + +/// +/// A simplified font package consists of a font header +/// followed by a series of glyph structures. +/// +typedef struct _EFI_HII_SIMPLE_FONT_PACKAGE_HDR { + EFI_HII_PACKAGE_HEADER Header; + UINT16 NumberOfNarrowGlyphs; + UINT16 NumberOfWideGlyphs; + // EFI_NARROW_GLYPH NarrowGlyphs[]; + // EFI_WIDE_GLYPH WideGlyphs[]; +} EFI_HII_SIMPLE_FONT_PACKAGE_HDR; + +// +// Definitions for Font Package +// Section 27.3.3 +// + +// +// Value for font style +// +#define EFI_HII_FONT_STYLE_NORMAL 0x00000000 +#define EFI_HII_FONT_STYLE_BOLD 0x00000001 +#define EFI_HII_FONT_STYLE_ITALIC 0x00000002 +#define EFI_HII_FONT_STYLE_EMBOSS 0x00010000 +#define EFI_HII_FONT_STYLE_OUTLINE 0x00020000 +#define EFI_HII_FONT_STYLE_SHADOW 0x00040000 +#define EFI_HII_FONT_STYLE_UNDERLINE 0x00080000 +#define EFI_HII_FONT_STYLE_DBL_UNDER 0x00100000 + +typedef struct _EFI_HII_GLYPH_INFO { + UINT16 Width; + UINT16 Height; + INT16 OffsetX; + INT16 OffsetY; + INT16 AdvanceX; +} EFI_HII_GLYPH_INFO; + +/// +/// The fixed header consists of a standard record header and +/// then the character values in this section, the flags +/// (including the encoding method) and the offsets of the glyph +/// information, the glyph bitmaps and the character map. +/// +typedef struct _EFI_HII_FONT_PACKAGE_HDR { + EFI_HII_PACKAGE_HEADER Header; + UINT32 HdrSize; + UINT32 GlyphBlockOffset; + EFI_HII_GLYPH_INFO Cell; + EFI_HII_FONT_STYLE FontStyle; + CHAR16 FontFamily[1]; +} EFI_HII_FONT_PACKAGE_HDR; + +// +// Value of different glyph info block types +// +#define EFI_HII_GIBT_END 0x00 +#define EFI_HII_GIBT_GLYPH 0x10 +#define EFI_HII_GIBT_GLYPHS 0x11 +#define EFI_HII_GIBT_GLYPH_DEFAULT 0x12 +#define EFI_HII_GIBT_GLYPHS_DEFAULT 0x13 +#define EFI_HII_GIBT_DUPLICATE 0x20 +#define EFI_HII_GIBT_SKIP2 0x21 +#define EFI_HII_GIBT_SKIP1 0x22 +#define EFI_HII_GIBT_DEFAULTS 0x23 +#define EFI_HII_GIBT_EXT1 0x30 +#define EFI_HII_GIBT_EXT2 0x31 +#define EFI_HII_GIBT_EXT4 0x32 + +typedef struct _EFI_HII_GLYPH_BLOCK { + UINT8 BlockType; +} EFI_HII_GLYPH_BLOCK; + +// +// Definition of different glyph info block types +// + +typedef struct _EFI_HII_GIBT_DEFAULTS_BLOCK { + EFI_HII_GLYPH_BLOCK Header; + EFI_HII_GLYPH_INFO Cell; +} EFI_HII_GIBT_DEFAULTS_BLOCK; + +typedef struct _EFI_HII_GIBT_DUPLICATE_BLOCK { + EFI_HII_GLYPH_BLOCK Header; + CHAR16 CharValue; +} EFI_HII_GIBT_DUPLICATE_BLOCK; + +typedef struct _EFI_GLYPH_GIBT_END_BLOCK { + EFI_HII_GLYPH_BLOCK Header; +} EFI_GLYPH_GIBT_END_BLOCK; + +typedef struct _EFI_HII_GIBT_EXT1_BLOCK { + EFI_HII_GLYPH_BLOCK Header; + UINT8 BlockType2; + UINT8 Length; +} EFI_HII_GIBT_EXT1_BLOCK; + +typedef struct _EFI_HII_GIBT_EXT2_BLOCK { + EFI_HII_GLYPH_BLOCK Header; + UINT8 BlockType2; + UINT16 Length; +} EFI_HII_GIBT_EXT2_BLOCK; + +typedef struct _EFI_HII_GIBT_EXT4_BLOCK { + EFI_HII_GLYPH_BLOCK Header; + UINT8 BlockType2; + UINT32 Length; +} EFI_HII_GIBT_EXT4_BLOCK; + +typedef struct _EFI_HII_GIBT_GLYPH_BLOCK { + EFI_HII_GLYPH_BLOCK Header; + EFI_HII_GLYPH_INFO Cell; + UINT8 BitmapData[1]; +} EFI_HII_GIBT_GLYPH_BLOCK; + +typedef struct _EFI_HII_GIBT_GLYPHS_BLOCK { + EFI_HII_GLYPH_BLOCK Header; + EFI_HII_GLYPH_INFO Cell; + UINT16 Count; + UINT8 BitmapData[1]; +} EFI_HII_GIBT_GLYPHS_BLOCK; + +typedef struct _EFI_HII_GIBT_GLYPH_DEFAULT_BLOCK { + EFI_HII_GLYPH_BLOCK Header; + UINT8 BitmapData[1]; +} EFI_HII_GIBT_GLYPH_DEFAULT_BLOCK; + +typedef struct _EFI_HII_GIBT_GLYPHS_DEFAULT_BLOCK { + EFI_HII_GLYPH_BLOCK Header; + UINT16 Count; + UINT8 BitmapData[1]; +} EFI_HII_GIBT_GLYPHS_DEFAULT_BLOCK; + +typedef struct _EFI_HII_GIBT_SKIP1_BLOCK { + EFI_HII_GLYPH_BLOCK Header; + UINT8 SkipCount; +} EFI_HII_GIBT_SKIP1_BLOCK; + +typedef struct _EFI_HII_GIBT_SKIP2_BLOCK { + EFI_HII_GLYPH_BLOCK Header; + UINT16 SkipCount; +} EFI_HII_GIBT_SKIP2_BLOCK; + +// +// Definitions for Device Path Package +// Section 27.3.4 +// + +/// +/// The device path package is used to carry a device path +/// associated with the package list. +/// +typedef struct _EFI_HII_DEVICE_PATH_PACKAGE { + EFI_HII_PACKAGE_HEADER Header; + // EFI_DEVICE_PATH_PROTOCOL DevicePath[]; +} EFI_HII_DEVICE_PATH_PACKAGE; + +// +// Definitions for GUID Package +// Section 27.3.5 +// + +/// +/// The GUID package is used to carry data where the format is defined by a GUID. +/// +typedef struct _EFI_HII_GUID_PACKAGE_HDR { + EFI_HII_PACKAGE_HEADER Header; + EFI_GUID Guid; + // Data per GUID definition may follow +} EFI_HII_GUID_PACKAGE_HDR; + +// +// Definitions for String Package +// Section 27.3.6 +// + +#define UEFI_CONFIG_LANG L"x-UEFI" +#define UEFI_CONFIG_LANG2 L"x-i-UEFI" + +/// +/// The fixed header consists of a standard record header and then the string identifiers +/// contained in this section and the offsets of the string and language information. +/// +typedef struct _EFI_HII_STRING_PACKAGE_HDR { + EFI_HII_PACKAGE_HEADER Header; + UINT32 HdrSize; + UINT32 StringInfoOffset; + CHAR16 LanguageWindow[16]; + EFI_STRING_ID LanguageName; + CHAR8 Language[1]; +} EFI_HII_STRING_PACKAGE_HDR; + +typedef struct { + UINT8 BlockType; +} EFI_HII_STRING_BLOCK; + +// +// Value of different string information block types +// +#define EFI_HII_SIBT_END 0x00 +#define EFI_HII_SIBT_STRING_SCSU 0x10 +#define EFI_HII_SIBT_STRING_SCSU_FONT 0x11 +#define EFI_HII_SIBT_STRINGS_SCSU 0x12 +#define EFI_HII_SIBT_STRINGS_SCSU_FONT 0x13 +#define EFI_HII_SIBT_STRING_UCS2 0x14 +#define EFI_HII_SIBT_STRING_UCS2_FONT 0x15 +#define EFI_HII_SIBT_STRINGS_UCS2 0x16 +#define EFI_HII_SIBT_STRINGS_UCS2_FONT 0x17 +#define EFI_HII_SIBT_DUPLICATE 0x20 +#define EFI_HII_SIBT_SKIP2 0x21 +#define EFI_HII_SIBT_SKIP1 0x22 +#define EFI_HII_SIBT_EXT1 0x30 +#define EFI_HII_SIBT_EXT2 0x31 +#define EFI_HII_SIBT_EXT4 0x32 +#define EFI_HII_SIBT_FONT 0x40 + +// +// Definition of different string information block types +// + +typedef struct _EFI_HII_SIBT_DUPLICATE_BLOCK { + EFI_HII_STRING_BLOCK Header; + EFI_STRING_ID StringId; +} EFI_HII_SIBT_DUPLICATE_BLOCK; + +typedef struct _EFI_HII_SIBT_END_BLOCK { + EFI_HII_STRING_BLOCK Header; +} EFI_HII_SIBT_END_BLOCK; + +typedef struct _EFI_HII_SIBT_EXT1_BLOCK { + EFI_HII_STRING_BLOCK Header; + UINT8 BlockType2; + UINT8 Length; +} EFI_HII_SIBT_EXT1_BLOCK; + +typedef struct _EFI_HII_SIBT_EXT2_BLOCK { + EFI_HII_STRING_BLOCK Header; + UINT8 BlockType2; + UINT16 Length; +} EFI_HII_SIBT_EXT2_BLOCK; + +typedef struct _EFI_HII_SIBT_EXT4_BLOCK { + EFI_HII_STRING_BLOCK Header; + UINT8 BlockType2; + UINT32 Length; +} EFI_HII_SIBT_EXT4_BLOCK; + +typedef struct _EFI_HII_SIBT_FONT_BLOCK { + EFI_HII_SIBT_EXT2_BLOCK Header; + UINT8 FontId; + UINT16 FontSize; + EFI_HII_FONT_STYLE FontStyle; + CHAR16 FontName[1]; +} EFI_HII_SIBT_FONT_BLOCK; + +typedef struct _EFI_HII_SIBT_SKIP1_BLOCK { + EFI_HII_STRING_BLOCK Header; + UINT8 SkipCount; +} EFI_HII_SIBT_SKIP1_BLOCK; + +typedef struct _EFI_HII_SIBT_SKIP2_BLOCK { + EFI_HII_STRING_BLOCK Header; + UINT16 SkipCount; +} EFI_HII_SIBT_SKIP2_BLOCK; + +typedef struct _EFI_HII_SIBT_STRING_SCSU_BLOCK { + EFI_HII_STRING_BLOCK Header; + UINT8 StringText[1]; +} EFI_HII_SIBT_STRING_SCSU_BLOCK; + +typedef struct _EFI_HII_SIBT_STRING_SCSU_FONT_BLOCK { + EFI_HII_STRING_BLOCK Header; + UINT8 FontIdentifier; + UINT8 StringText[1]; +} EFI_HII_SIBT_STRING_SCSU_FONT_BLOCK; + +typedef struct _EFI_HII_SIBT_STRINGS_SCSU_BLOCK { + EFI_HII_STRING_BLOCK Header; + UINT16 StringCount; + UINT8 StringText[1]; +} EFI_HII_SIBT_STRINGS_SCSU_BLOCK; + +typedef struct _EFI_HII_SIBT_STRINGS_SCSU_FONT_BLOCK { + EFI_HII_STRING_BLOCK Header; + UINT8 FontIdentifier; + UINT16 StringCount; + UINT8 StringText[1]; +} EFI_HII_SIBT_STRINGS_SCSU_FONT_BLOCK; + +typedef struct _EFI_HII_SIBT_STRING_UCS2_BLOCK { + EFI_HII_STRING_BLOCK Header; + CHAR16 StringText[1]; +} EFI_HII_SIBT_STRING_UCS2_BLOCK; + +typedef struct _EFI_HII_SIBT_STRING_UCS2_FONT_BLOCK { + EFI_HII_STRING_BLOCK Header; + UINT8 FontIdentifier; + CHAR16 StringText[1]; +} EFI_HII_SIBT_STRING_UCS2_FONT_BLOCK; + +typedef struct _EFI_HII_SIBT_STRINGS_UCS2_BLOCK { + EFI_HII_STRING_BLOCK Header; + UINT16 StringCount; + CHAR16 StringText[1]; +} EFI_HII_SIBT_STRINGS_UCS2_BLOCK; + +typedef struct _EFI_HII_SIBT_STRINGS_UCS2_FONT_BLOCK { + EFI_HII_STRING_BLOCK Header; + UINT8 FontIdentifier; + UINT16 StringCount; + CHAR16 StringText[1]; +} EFI_HII_SIBT_STRINGS_UCS2_FONT_BLOCK; + +// +// Definitions for Image Package +// Section 27.3.7 +// + +typedef struct _EFI_HII_IMAGE_PACKAGE_HDR { + EFI_HII_PACKAGE_HEADER Header; + UINT32 ImageInfoOffset; + UINT32 PaletteInfoOffset; +} EFI_HII_IMAGE_PACKAGE_HDR; + +typedef struct _EFI_HII_IMAGE_BLOCK { + UINT8 BlockType; +} EFI_HII_IMAGE_BLOCK; + +// +// Value of different image information block types +// +#define EFI_HII_IIBT_END 0x00 +#define EFI_HII_IIBT_IMAGE_1BIT 0x10 +#define EFI_HII_IIBT_IMAGE_1BIT_TRANS 0x11 +#define EFI_HII_IIBT_IMAGE_4BIT 0x12 +#define EFI_HII_IIBT_IMAGE_4BIT_TRANS 0x13 +#define EFI_HII_IIBT_IMAGE_8BIT 0x14 +#define EFI_HII_IIBT_IMAGE_8BIT_TRANS 0x15 +#define EFI_HII_IIBT_IMAGE_24BIT 0x16 +#define EFI_HII_IIBT_IMAGE_24BIT_TRANS 0x17 +#define EFI_HII_IIBT_IMAGE_JPEG 0x18 +#define EFI_HII_IIBT_DUPLICATE 0x20 +#define EFI_HII_IIBT_SKIP2 0x21 +#define EFI_HII_IIBT_SKIP1 0x22 +#define EFI_HII_IIBT_EXT1 0x30 +#define EFI_HII_IIBT_EXT2 0x31 +#define EFI_HII_IIBT_EXT4 0x32 + +// +// Definition of different image information block types +// + +typedef struct _EFI_HII_IIBT_END_BLOCK { + EFI_HII_IMAGE_BLOCK Header; +} EFI_HII_IIBT_END_BLOCK; + +typedef struct _EFI_HII_IIBT_EXT1_BLOCK { + EFI_HII_IMAGE_BLOCK Header; + UINT8 BlockType2; + UINT8 Length; +} EFI_HII_IIBT_EXT1_BLOCK; + +typedef struct _EFI_HII_IIBT_EXT2_BLOCK { + EFI_HII_IMAGE_BLOCK Header; + UINT8 BlockType2; + UINT16 Length; +} EFI_HII_IIBT_EXT2_BLOCK; + +typedef struct _EFI_HII_IIBT_EXT4_BLOCK { + EFI_HII_IMAGE_BLOCK Header; + UINT8 BlockType2; + UINT32 Length; +} EFI_HII_IIBT_EXT4_BLOCK; + +typedef struct _EFI_HII_IIBT_IMAGE_1BIT_BASE { + UINT16 Width; + UINT16 Height; + UINT8 Data[1]; +} EFI_HII_IIBT_IMAGE_1BIT_BASE; + +typedef struct _EFI_HII_IIBT_IMAGE_1BIT_BLOCK { + EFI_HII_IMAGE_BLOCK Header; + UINT8 PaletteIndex; + EFI_HII_IIBT_IMAGE_1BIT_BASE Bitmap; +} EFI_HII_IIBT_IMAGE_1BIT_BLOCK; + +typedef struct _EFI_HII_IIBT_IMAGE_1BIT_TRANS_BLOCK { + EFI_HII_IMAGE_BLOCK Header; + UINT8 PaletteIndex; + EFI_HII_IIBT_IMAGE_1BIT_BASE Bitmap; +} EFI_HII_IIBT_IMAGE_1BIT_TRANS_BLOCK; + +typedef struct _EFI_HII_RGB_PIXEL { + UINT8 b; + UINT8 g; + UINT8 r; +} EFI_HII_RGB_PIXEL; + +typedef struct _EFI_HII_IIBT_IMAGE_24BIT_BASE { + UINT16 Width; + UINT16 Height; + EFI_HII_RGB_PIXEL Bitmap[1]; +} EFI_HII_IIBT_IMAGE_24BIT_BASE; + +typedef struct _EFI_HII_IIBT_IMAGE_24BIT_BLOCK { + EFI_HII_IMAGE_BLOCK Header; + EFI_HII_IIBT_IMAGE_24BIT_BASE Bitmap; +} EFI_HII_IIBT_IMAGE_24BIT_BLOCK; + +typedef struct _EFI_HII_IIBT_IMAGE_24BIT_TRANS_BLOCK { + EFI_HII_IMAGE_BLOCK Header; + EFI_HII_IIBT_IMAGE_24BIT_BASE Bitmap; +} EFI_HII_IIBT_IMAGE_24BIT_TRANS_BLOCK; + +typedef struct _EFI_HII_IIBT_IMAGE_4BIT_BASE { + UINT16 Width; + UINT16 Height; + UINT8 Data[1]; +} EFI_HII_IIBT_IMAGE_4BIT_BASE; + +typedef struct _EFI_HII_IIBT_IMAGE_4BIT_BLOCK { + EFI_HII_IMAGE_BLOCK Header; + UINT8 PaletteIndex; + EFI_HII_IIBT_IMAGE_4BIT_BASE Bitmap; +} EFI_HII_IIBT_IMAGE_4BIT_BLOCK; + +typedef struct _EFI_HII_IIBT_IMAGE_4BIT_TRANS_BLOCK { + EFI_HII_IMAGE_BLOCK Header; + UINT8 PaletteIndex; + EFI_HII_IIBT_IMAGE_4BIT_BASE Bitmap; +} EFI_HII_IIBT_IMAGE_4BIT_TRANS_BLOCK; + +typedef struct _EFI_HII_IIBT_IMAGE_8BIT_BASE { + UINT16 Width; + UINT16 Height; + UINT8 Data[1]; +} EFI_HII_IIBT_IMAGE_8BIT_BASE; + +typedef struct _EFI_HII_IIBT_IMAGE_8BIT_PALETTE_BLOCK { + EFI_HII_IMAGE_BLOCK Header; + UINT8 PaletteIndex; + EFI_HII_IIBT_IMAGE_8BIT_BASE Bitmap; +} EFI_HII_IIBT_IMAGE_8BIT_BLOCK; + +typedef struct _EFI_HII_IIBT_IMAGE_8BIT_TRANS_BLOCK { + EFI_HII_IMAGE_BLOCK Header; + UINT8 PaletteIndex; + EFI_HII_IIBT_IMAGE_8BIT_BASE Bitmap; +} EFI_HII_IIBT_IMAGE_8BIT_TRAN_BLOCK; + +typedef struct _EFI_HII_IIBT_DUPLICATE_BLOCK { + EFI_HII_IMAGE_BLOCK Header; + EFI_IMAGE_ID ImageId; +} EFI_HII_IIBT_DUPLICATE_BLOCK; + +typedef struct _EFI_HII_IIBT_JPEG_BLOCK { + EFI_HII_IMAGE_BLOCK Header; + UINT32 Size; + UINT8 Data[1]; +} EFI_HII_IIBT_JPEG_BLOCK; + +typedef struct _EFI_HII_IIBT_SKIP1_BLOCK { + EFI_HII_IMAGE_BLOCK Header; + UINT8 SkipCount; +} EFI_HII_IIBT_SKIP1_BLOCK; + +typedef struct _EFI_HII_IIBT_SKIP2_BLOCK { + EFI_HII_IMAGE_BLOCK Header; + UINT16 SkipCount; +} EFI_HII_IIBT_SKIP2_BLOCK; + +// +// Definitions for Palette Information +// + +typedef struct _EFI_HII_IMAGE_PALETTE_INFO_HEADER { + UINT16 PaletteCount; +} EFI_HII_IMAGE_PALETTE_INFO_HEADER; + +typedef struct _EFI_HII_IMAGE_PALETTE_INFO { + UINT16 PaletteSize; + EFI_HII_RGB_PIXEL PaletteValue[1]; +} EFI_HII_IMAGE_PALETTE_INFO; + +// +// Definitions for Forms Package +// Section 27.3.8 +// + +/// +/// The Forms package is used to carry forms-based encoding data. +/// +typedef struct _EFI_HII_FORM_PACKAGE { + EFI_HII_PACKAGE_HEADER Header; + // EFI_IFR_OP_HEADER OpCodeHeader; + // More op-codes follow +} EFI_HII_FORM_PACKAGE; + +typedef struct { + UINT8 Hour; + UINT8 Minute; + UINT8 Second; +} EFI_HII_TIME; + +typedef struct { + UINT16 Year; + UINT8 Month; + UINT8 Day; +} EFI_HII_DATE; + +typedef union { + UINT8 u8; + UINT16 u16; + UINT32 u32; + UINT64 u64; + BOOLEAN b; + EFI_HII_TIME time; + EFI_HII_DATE date; + EFI_STRING_ID string; +} EFI_IFR_TYPE_VALUE; + +// +// IFR Opcodes +// +#define EFI_IFR_FORM_OP 0x01 +#define EFI_IFR_SUBTITLE_OP 0x02 +#define EFI_IFR_TEXT_OP 0x03 +#define EFI_IFR_IMAGE_OP 0x04 +#define EFI_IFR_ONE_OF_OP 0x05 +#define EFI_IFR_CHECKBOX_OP 0x06 +#define EFI_IFR_NUMERIC_OP 0x07 +#define EFI_IFR_PASSWORD_OP 0x08 +#define EFI_IFR_ONE_OF_OPTION_OP 0x09 +#define EFI_IFR_SUPPRESS_IF_OP 0x0A +#define EFI_IFR_LOCKED_OP 0x0B +#define EFI_IFR_ACTION_OP 0x0C +#define EFI_IFR_RESET_BUTTON_OP 0x0D +#define EFI_IFR_FORM_SET_OP 0x0E +#define EFI_IFR_REF_OP 0x0F +#define EFI_IFR_NO_SUBMIT_IF_OP 0x10 +#define EFI_IFR_INCONSISTENT_IF_OP 0x11 +#define EFI_IFR_EQ_ID_VAL_OP 0x12 +#define EFI_IFR_EQ_ID_ID_OP 0x13 +#define EFI_IFR_EQ_ID_LIST_OP 0x14 +#define EFI_IFR_AND_OP 0x15 +#define EFI_IFR_OR_OP 0x16 +#define EFI_IFR_NOT_OP 0x17 +#define EFI_IFR_RULE_OP 0x18 +#define EFI_IFR_GRAY_OUT_IF_OP 0x19 +#define EFI_IFR_DATE_OP 0x1A +#define EFI_IFR_TIME_OP 0x1B +#define EFI_IFR_STRING_OP 0x1C +#define EFI_IFR_REFRESH_OP 0x1D +#define EFI_IFR_DISABLE_IF_OP 0x1E +#define EFI_IFR_TO_LOWER_OP 0x20 +#define EFI_IFR_TO_UPPER_OP 0x21 +#define EFI_IFR_ORDERED_LIST_OP 0x23 +#define EFI_IFR_VARSTORE_OP 0x24 +#define EFI_IFR_VARSTORE_NAME_VALUE_OP 0x25 +#define EFI_IFR_VARSTORE_EFI_OP 0x26 +#define EFI_IFR_VARSTORE_DEVICE_OP 0x27 +#define EFI_IFR_VERSION_OP 0x28 +#define EFI_IFR_END_OP 0x29 +#define EFI_IFR_MATCH_OP 0x2A +#define EFI_IFR_EQUAL_OP 0x2F +#define EFI_IFR_NOT_EQUAL_OP 0x30 +#define EFI_IFR_GREATER_THAN_OP 0x31 +#define EFI_IFR_GREATER_EQUAL_OP 0x32 +#define EFI_IFR_LESS_THAN_OP 0x33 +#define EFI_IFR_LESS_EQUAL_OP 0x34 +#define EFI_IFR_BITWISE_AND_OP 0x35 +#define EFI_IFR_BITWISE_OR_OP 0x36 +#define EFI_IFR_BITWISE_NOT_OP 0x37 +#define EFI_IFR_SHIFT_LEFT_OP 0x38 +#define EFI_IFR_SHIFT_RIGHT_OP 0x39 +#define EFI_IFR_ADD_OP 0x3A +#define EFI_IFR_SUBTRACT_OP 0x3B +#define EFI_IFR_MULTIPLY_OP 0x3C +#define EFI_IFR_DIVIDE_OP 0x3D +#define EFI_IFR_MODULO_OP 0x3E +#define EFI_IFR_RULE_REF_OP 0x3F +#define EFI_IFR_QUESTION_REF1_OP 0x40 +#define EFI_IFR_QUESTION_REF2_OP 0x41 +#define EFI_IFR_UINT8_OP 0x42 +#define EFI_IFR_UINT16_OP 0x43 +#define EFI_IFR_UINT32_OP 0x44 +#define EFI_IFR_UINT64_OP 0x45 +#define EFI_IFR_TRUE_OP 0x46 +#define EFI_IFR_FALSE_OP 0x47 +#define EFI_IFR_TO_UINT_OP 0x48 +#define EFI_IFR_TO_STRING_OP 0x49 +#define EFI_IFR_TO_BOOLEAN_OP 0x4A +#define EFI_IFR_MID_OP 0x4B +#define EFI_IFR_FIND_OP 0x4C +#define EFI_IFR_TOKEN_OP 0x4D +#define EFI_IFR_STRING_REF1_OP 0x4E +#define EFI_IFR_STRING_REF2_OP 0x4F +#define EFI_IFR_CONDITIONAL_OP 0x50 +#define EFI_IFR_QUESTION_REF3_OP 0x51 +#define EFI_IFR_ZERO_OP 0x52 +#define EFI_IFR_ONE_OP 0x53 +#define EFI_IFR_ONES_OP 0x54 +#define EFI_IFR_UNDEFINED_OP 0x55 +#define EFI_IFR_LENGTH_OP 0x56 +#define EFI_IFR_DUP_OP 0x57 +#define EFI_IFR_THIS_OP 0x58 +#define EFI_IFR_SPAN_OP 0x59 +#define EFI_IFR_VALUE_OP 0x5A +#define EFI_IFR_DEFAULT_OP 0x5B +#define EFI_IFR_DEFAULTSTORE_OP 0x5C +#define EFI_IFR_CATENATE_OP 0x5E +#define EFI_IFR_GUID_OP 0x5F + +// +// Definitions of IFR Standard Headers +// Section 27.3.8.2 +// + +typedef struct _EFI_IFR_OP_HEADER { + UINT8 OpCode; + UINT8 Length:7; + UINT8 Scope:1; +} EFI_IFR_OP_HEADER; + +typedef struct _EFI_IFR_STATEMENT_HEADER { + EFI_STRING_ID Prompt; + EFI_STRING_ID Help; +} EFI_IFR_STATEMENT_HEADER; + +typedef struct _EFI_IFR_QUESTION_HEADER { + EFI_IFR_STATEMENT_HEADER Header; + EFI_QUESTION_ID QuestionId; + EFI_VARSTORE_ID VarStoreId; + union { + EFI_STRING_ID VarName; + UINT16 VarOffset; + } VarStoreInfo; + UINT8 Flags; +} EFI_IFR_QUESTION_HEADER; + +// +// Flag values of EFI_IFR_QUESTION_HEADER +// +#define EFI_IFR_FLAG_READ_ONLY 0x01 +#define EFI_IFR_FLAG_CALLBACK 0x04 +#define EFI_IFR_FLAG_RESET_REQUIRED 0x10 +#define EFI_IFR_FLAG_OPTIONS_ONLY 0x80 + +// +// Definition for Opcode Reference +// Section 27.3.8.3 +// +typedef struct _EFI_IFR_DEFAULTSTORE { + EFI_IFR_OP_HEADER Header; + EFI_STRING_ID DefaultName; + UINT16 DefaultId; +} EFI_IFR_DEFAULTSTORE; + +// +// Default Identifier of default store +// +#define EFI_HII_DEFAULT_CLASS_STANDARD 0x0000 +#define EFI_HII_DEFAULT_CLASS_MANUFACTURING 0x0001 +#define EFI_HII_DEFAULT_CLASS_SAFE 0x0002 +#define EFI_HII_DEFAULT_CLASS_PLATFORM_BEGIN 0x4000 +#define EFI_HII_DEFAULT_CLASS_PLATFORM_END 0x7fff +#define EFI_HII_DEFAULT_CLASS_HARDWARE_BEGIN 0x8000 +#define EFI_HII_DEFAULT_CLASS_HARDWARE_END 0xbfff +#define EFI_HII_DEFAULT_CLASS_FIRMWARE_BEGIN 0xc000 +#define EFI_HII_DEFAULT_CLASS_FIRMWARE_END 0xffff + +typedef struct _EFI_IFR_VARSTORE { + EFI_IFR_OP_HEADER Header; + EFI_GUID Guid; + EFI_VARSTORE_ID VarStoreId; + UINT16 Size; + UINT8 Name[1]; +} EFI_IFR_VARSTORE; + +typedef struct _EFI_IFR_VARSTORE_EFI { + EFI_IFR_OP_HEADER Header; + EFI_VARSTORE_ID VarStoreId; + EFI_GUID Guid; + UINT32 Attributes; +} EFI_IFR_VARSTORE_EFI; + +typedef struct _EFI_IFR_VARSTORE_NAME_VALUE { + EFI_IFR_OP_HEADER Header; + EFI_VARSTORE_ID VarStoreId; + EFI_GUID Guid; +} EFI_IFR_VARSTORE_NAME_VALUE; + +typedef struct _EFI_IFR_FORM_SET { + EFI_IFR_OP_HEADER Header; + EFI_GUID Guid; + EFI_STRING_ID FormSetTitle; + EFI_STRING_ID Help; +} EFI_IFR_FORM_SET; + +typedef struct _EFI_IFR_END { + EFI_IFR_OP_HEADER Header; +} EFI_IFR_END; + +typedef struct _EFI_IFR_FORM { + EFI_IFR_OP_HEADER Header; + UINT16 FormId; + EFI_STRING_ID FormTitle; +} EFI_IFR_FORM; + +typedef struct _EFI_IFR_IMAGE { + EFI_IFR_OP_HEADER Header; + EFI_IMAGE_ID Id; +} EFI_IFR_IMAGE; + +typedef struct _EFI_IFR_LOCKED { + EFI_IFR_OP_HEADER Header; +} EFI_IFR_LOCKED; + +typedef struct _EFI_IFR_RULE { + EFI_IFR_OP_HEADER Header; + UINT8 RuleId; +} EFI_IFR_RULE; + +typedef struct _EFI_IFR_DEFAULT { + EFI_IFR_OP_HEADER Header; + UINT16 DefaultId; + UINT8 Type; + EFI_IFR_TYPE_VALUE Value; +} EFI_IFR_DEFAULT; + +typedef struct _EFI_IFR_VALUE { + EFI_IFR_OP_HEADER Header; +} EFI_IFR_VALUE; + +typedef struct _EFI_IFR_SUBTITLE { + EFI_IFR_OP_HEADER Header; + EFI_IFR_STATEMENT_HEADER Statement; + UINT8 Flags; +} EFI_IFR_SUBTITLE; + +#define EFI_IFR_FLAGS_HORIZONTAL 0x01 + +typedef struct _EFI_IFR_CHECKBOX { + EFI_IFR_OP_HEADER Header; + EFI_IFR_QUESTION_HEADER Question; + UINT8 Flags; +} EFI_IFR_CHECKBOX; + +#define EFI_IFR_CHECKBOX_DEFAULT 0x01 +#define EFI_IFR_CHECKBOX_DEFAULT_MFG 0x02 + +typedef struct _EFI_IFR_TEXT { + EFI_IFR_OP_HEADER Header; + EFI_IFR_STATEMENT_HEADER Statement; + EFI_STRING_ID TextTwo; +} EFI_IFR_TEXT; + +typedef struct _EFI_IFR_REF { + EFI_IFR_OP_HEADER Header; + EFI_IFR_QUESTION_HEADER Question; + EFI_FORM_ID FormId; +} EFI_IFR_REF; + +typedef struct _EFI_IFR_REF2 { + EFI_IFR_OP_HEADER Header; + EFI_IFR_QUESTION_HEADER Question; + EFI_FORM_ID FormId; + EFI_QUESTION_ID QuestionId; +} EFI_IFR_REF2; + +typedef struct _EFI_IFR_REF3 { + EFI_IFR_OP_HEADER Header; + EFI_IFR_QUESTION_HEADER Question; + EFI_FORM_ID FormId; + EFI_QUESTION_ID QuestionId; + EFI_GUID FormSetId; +} EFI_IFR_REF3; + +typedef struct _EFI_IFR_REF4 { + EFI_IFR_OP_HEADER Header; + EFI_IFR_QUESTION_HEADER Question; + EFI_FORM_ID FormId; + EFI_QUESTION_ID QuestionId; + EFI_GUID FormSetId; + EFI_STRING_ID DevicePath; +} EFI_IFR_REF4; + +typedef struct _EFI_IFR_RESET_BUTTON { + EFI_IFR_OP_HEADER Header; + EFI_IFR_QUESTION_HEADER Question; + EFI_DEFAULT_ID DefaultId; +} EFI_IFR_RESET_BUTTON; + +typedef struct _EFI_IFR_ACTION { + EFI_IFR_OP_HEADER Header; + EFI_IFR_QUESTION_HEADER Question; + EFI_STRING_ID QuestionConfig; +} EFI_IFR_ACTION; + +typedef struct _EFI_IFR_ACTION_1 { + EFI_IFR_OP_HEADER Header; + EFI_IFR_QUESTION_HEADER Question; +} EFI_IFR_ACTION_1; + +typedef struct _EFI_IFR_DATE { + EFI_IFR_OP_HEADER Header; + EFI_IFR_QUESTION_HEADER Question; + UINT8 Flags; +} EFI_IFR_DATE; + +// +// Flags that describe the behavior of the question. +// +#define EFI_QF_DATE_YEAR_SUPPRESS 0x01 +#define EFI_QF_DATE_MONTH_SUPPRESS 0x02 +#define EFI_QF_DATE_DAY_SUPPRESS 0x04 + +#define EFI_QF_DATE_STORAGE 0x30 +#define QF_DATE_STORAGE_NORMAL 0x00 +#define QF_DATE_STORAGE_TIME 0x10 +#define QF_DATE_STORAGE_WAKEUP 0x20 + +typedef union { + struct { + UINT8 MinValue; + UINT8 MaxValue; + UINT8 Step; + } u8; + struct { + UINT16 MinValue; + UINT16 MaxValue; + UINT16 Step; + } u16; + struct { + UINT32 MinValue; + UINT32 MaxValue; + UINT32 Step; + } u32; + struct { + UINT64 MinValue; + UINT64 MaxValue; + UINT64 Step; + } u64; +} MINMAXSTEP_DATA; + +typedef struct _EFI_IFR_NUMERIC { + EFI_IFR_OP_HEADER Header; + EFI_IFR_QUESTION_HEADER Question; + UINT8 Flags; + MINMAXSTEP_DATA data; +} EFI_IFR_NUMERIC; + +// +// Flags related to the numeric question +// +#define EFI_IFR_NUMERIC_SIZE 0x03 +#define EFI_IFR_NUMERIC_SIZE_1 0x00 +#define EFI_IFR_NUMERIC_SIZE_2 0x01 +#define EFI_IFR_NUMERIC_SIZE_4 0x02 +#define EFI_IFR_NUMERIC_SIZE_8 0x03 + +#define EFI_IFR_DISPLAY 0x30 +#define EFI_IFR_DISPLAY_INT_DEC 0x00 +#define EFI_IFR_DISPLAY_UINT_DEC 0x10 +#define EFI_IFR_DISPLAY_UINT_HEX 0x20 + +typedef struct _EFI_IFR_ONE_OF { + EFI_IFR_OP_HEADER Header; + EFI_IFR_QUESTION_HEADER Question; + UINT8 Flags; + MINMAXSTEP_DATA data; +} EFI_IFR_ONE_OF; + +typedef struct _EFI_IFR_STRING { + EFI_IFR_OP_HEADER Header; + EFI_IFR_QUESTION_HEADER Question; + UINT8 MinSize; + UINT8 MaxSize; + UINT8 Flags; +} EFI_IFR_STRING; + +#define EFI_IFR_STRING_MULTI_LINE 0x01 + +typedef struct _EFI_IFR_PASSWORD { + EFI_IFR_OP_HEADER Header; + EFI_IFR_QUESTION_HEADER Question; + UINT16 MinSize; + UINT16 MaxSize; +} EFI_IFR_PASSWORD; + +typedef struct _EFI_IFR_ORDERED_LIST { + EFI_IFR_OP_HEADER Header; + EFI_IFR_QUESTION_HEADER Question; + UINT8 MaxContainers; + UINT8 Flags; +} EFI_IFR_ORDERED_LIST; + +#define EFI_IFR_UNIQUE_SET 0x01 +#define EFI_IFR_NO_EMPTY_SET 0x02 + +typedef struct _EFI_IFR_TIME { + EFI_IFR_OP_HEADER Header; + EFI_IFR_QUESTION_HEADER Question; + UINT8 Flags; +} EFI_IFR_TIME; + +// +// A bit-mask that determines which unique settings are active for this opcode. +// +#define QF_TIME_HOUR_SUPPRESS 0x01 +#define QF_TIME_MINUTE_SUPPRESS 0x02 +#define QF_TIME_SECOND_SUPPRESS 0x04 + +#define QF_TIME_STORAGE 0x30 +#define QF_TIME_STORAGE_NORMAL 0x00 +#define QF_TIME_STORAGE_TIME 0x10 +#define QF_TIME_STORAGE_WAKEUP 0x20 + +typedef struct _EFI_IFR_DISABLE_IF { + EFI_IFR_OP_HEADER Header; +} EFI_IFR_DISABLE_IF; + +typedef struct _EFI_IFR_SUPPRESS_IF { + EFI_IFR_OP_HEADER Header; +} EFI_IFR_SUPPRESS_IF; + +typedef struct _EFI_IFR_GRAY_OUT_IF { + EFI_IFR_OP_HEADER Header; +} EFI_IFR_GRAY_OUT_IF; + +typedef struct _EFI_IFR_INCONSISTENT_IF { + EFI_IFR_OP_HEADER Header; + EFI_STRING_ID Error; +} EFI_IFR_INCONSISTENT_IF; + +typedef struct _EFI_IFR_NO_SUBMIT_IF { + EFI_IFR_OP_HEADER Header; + EFI_STRING_ID Error; +} EFI_IFR_NO_SUBMIT_IF; + +typedef struct _EFI_IFR_REFRESH { + EFI_IFR_OP_HEADER Header; + UINT8 RefreshInterval; +} EFI_IFR_REFRESH; + +typedef struct _EFI_IFR_VARSTORE_DEVICE { + EFI_IFR_OP_HEADER Header; + EFI_STRING_ID DevicePath; +} EFI_IFR_VARSTORE_DEVICE; + +typedef struct _EFI_IFR_ONE_OF_OPTION { + EFI_IFR_OP_HEADER Header; + EFI_STRING_ID Option; + UINT8 Flags; + UINT8 Type; + EFI_IFR_TYPE_VALUE Value; +} EFI_IFR_ONE_OF_OPTION; + +// +// Types of the option's value. +// +#define EFI_IFR_TYPE_NUM_SIZE_8 0x00 +#define EFI_IFR_TYPE_NUM_SIZE_16 0x01 +#define EFI_IFR_TYPE_NUM_SIZE_32 0x02 +#define EFI_IFR_TYPE_NUM_SIZE_64 0x03 +#define EFI_IFR_TYPE_BOOLEAN 0x04 +#define EFI_IFR_TYPE_TIME 0x05 +#define EFI_IFR_TYPE_DATE 0x06 +#define EFI_IFR_TYPE_STRING 0x07 +#define EFI_IFR_TYPE_OTHER 0x08 + +#define EFI_IFR_OPTION_DEFAULT 0x10 +#define EFI_IFR_OPTION_DEFAULT_MFG 0x20 + +typedef struct _EFI_IFR_GUID { + EFI_IFR_OP_HEADER Header; + EFI_GUID Guid; + //Optional Data Follows +} EFI_IFR_GUID; + +typedef struct _EFI_IFR_DUP { + EFI_IFR_OP_HEADER Header; +} EFI_IFR_DUP; + +typedef struct _EFI_IFR_EQ_ID_ID { + EFI_IFR_OP_HEADER Header; + EFI_QUESTION_ID QuestionId1; + EFI_QUESTION_ID QuestionId2; +} EFI_IFR_EQ_ID_ID; + +typedef struct _EFI_IFR_EQ_ID_VAL { + EFI_IFR_OP_HEADER Header; + EFI_QUESTION_ID QuestionId; + UINT16 Value; +} EFI_IFR_EQ_ID_VAL; + +typedef struct _EFI_IFR_EQ_ID_LIST { + EFI_IFR_OP_HEADER Header; + EFI_QUESTION_ID QuestionId; + UINT16 ListLength; + UINT16 ValueList[1]; +} EFI_IFR_EQ_ID_LIST; + +typedef struct _EFI_IFR_UINT8 { + EFI_IFR_OP_HEADER Header; + UINT8 Value; +} EFI_IFR_UINT8; + +typedef struct _EFI_IFR_UINT16 { + EFI_IFR_OP_HEADER Header; + UINT16 Value; +} EFI_IFR_UINT16; + +typedef struct _EFI_IFR_UINT32 { + EFI_IFR_OP_HEADER Header; + UINT32 Value; +} EFI_IFR_UINT32; + +typedef struct _EFI_IFR_UINT64 { + EFI_IFR_OP_HEADER Header; + UINT64 Value; +} EFI_IFR_UINT64; + +typedef struct _EFI_IFR_QUESTION_REF1 { + EFI_IFR_OP_HEADER Header; + EFI_QUESTION_ID QuestionId; +} EFI_IFR_QUESTION_REF1; + +typedef struct _EFI_IFR_QUESTION_REF2 { + EFI_IFR_OP_HEADER Header; +} EFI_IFR_QUESTION_REF2; + +typedef struct _EFI_IFR_QUESTION_REF3 { + EFI_IFR_OP_HEADER Header; +} EFI_IFR_QUESTION_REF3; + +typedef struct _EFI_IFR_QUESTION_REF3_2 { + EFI_IFR_OP_HEADER Header; + EFI_STRING_ID DevicePath; +} EFI_IFR_QUESTION_REF3_2; + +typedef struct _EFI_IFR_QUESTION_REF3_3 { + EFI_IFR_OP_HEADER Header; + EFI_STRING_ID DevicePath; + EFI_GUID Guid; +} EFI_IFR_QUESTION_REF3_3; + +typedef struct _EFI_IFR_RULE_REF { + EFI_IFR_OP_HEADER Header; + UINT8 RuleId; +} EFI_IFR_RULE_REF; + +typedef struct _EFI_IFR_STRING_REF1 { + EFI_IFR_OP_HEADER Header; + EFI_STRING_ID StringId; +} EFI_IFR_STRING_REF1; + +typedef struct _EFI_IFR_STRING_REF2 { + EFI_IFR_OP_HEADER Header; +} EFI_IFR_STRING_REF2; + +typedef struct _EFI_IFR_THIS { + EFI_IFR_OP_HEADER Header; +} EFI_IFR_THIS; + +typedef struct _EFI_IFR_TRUE { + EFI_IFR_OP_HEADER Header; +} EFI_IFR_TRUE; + +typedef struct _EFI_IFR_FALSE { + EFI_IFR_OP_HEADER Header; +} EFI_IFR_FALSE; + +typedef struct _EFI_IFR_ONE { + EFI_IFR_OP_HEADER Header; +} EFI_IFR_ONE; + +typedef struct _EFI_IFR_ONES { + EFI_IFR_OP_HEADER Header; +} EFI_IFR_ONES; + +typedef struct _EFI_IFR_ZERO { + EFI_IFR_OP_HEADER Header; +} EFI_IFR_ZERO; + +typedef struct _EFI_IFR_UNDEFINED { + EFI_IFR_OP_HEADER Header; +} EFI_IFR_UNDEFINED; + +typedef struct _EFI_IFR_VERSION { + EFI_IFR_OP_HEADER Header; +} EFI_IFR_VERSION; + +typedef struct _EFI_IFR_LENGTH { + EFI_IFR_OP_HEADER Header; +} EFI_IFR_LENGTH; + +typedef struct _EFI_IFR_NOT { + EFI_IFR_OP_HEADER Header; +} EFI_IFR_NOT; + +typedef struct _EFI_IFR_BITWISE_NOT { + EFI_IFR_OP_HEADER Header; +} EFI_IFR_BITWISE_NOT; + +typedef struct _EFI_IFR_TO_BOOLEAN { + EFI_IFR_OP_HEADER Header; +} EFI_IFR_TO_BOOLEAN; + +// +// For EFI_IFR_TO_STRING, when converting from +// unsigned integers, these flags control the format: +// 0 = unsigned decimal +// 1 = signed decimal +// 2 = hexadecimal (lower-case alpha) +// 3 = hexadecimal (upper-case alpha) +// +#define EFI_IFR_STRING_UNSIGNED_DEC 0 +#define EFI_IFR_STRING_SIGNED_DEC 1 +#define EFI_IFR_STRING_LOWERCASE_HEX 2 +#define EFI_IFR_STRING_UPPERCASE_HEX 3 +// +// When converting from a buffer, these flags control the format: +// 0 = ASCII +// 8 = Unicode +// +#define EFI_IFR_STRING_ASCII 0 +#define EFI_IFR_STRING_UNICODE 8 + +typedef struct _EFI_IFR_TO_STRING { + EFI_IFR_OP_HEADER Header; + UINT8 Format; +} EFI_IFR_TO_STRING; + +typedef struct _EFI_IFR_TO_UINT { + EFI_IFR_OP_HEADER Header; +} EFI_IFR_TO_UINT; + +typedef struct _EFI_IFR_TO_UPPER { + EFI_IFR_OP_HEADER Header; +} EFI_IFR_TO_UPPER; + +typedef struct _EFI_IFR_TO_LOWER { + EFI_IFR_OP_HEADER Header; +} EFI_IFR_TO_LOWER; + +typedef struct _EFI_IFR_ADD { + EFI_IFR_OP_HEADER Header; +} EFI_IFR_ADD; + +typedef struct _EFI_IFR_AND { + EFI_IFR_OP_HEADER Header; +} EFI_IFR_AND; + +typedef struct _EFI_IFR_BITWISE_AND { + EFI_IFR_OP_HEADER Header; +} EFI_IFR_BITWISE_AND; + +typedef struct _EFI_IFR_BITWISE_OR { + EFI_IFR_OP_HEADER Header; +} EFI_IFR_BITWISE_OR; + +typedef struct _EFI_IFR_CATENATE { + EFI_IFR_OP_HEADER Header; +} EFI_IFR_CATENATE; + +typedef struct _EFI_IFR_DIVIDE { + EFI_IFR_OP_HEADER Header; +} EFI_IFR_DIVIDE; + +typedef struct _EFI_IFR_EQUAL { + EFI_IFR_OP_HEADER Header; +} EFI_IFR_EQUAL; + +typedef struct _EFI_IFR_GREATER_EQUAL { + EFI_IFR_OP_HEADER Header; +} EFI_IFR_GREATER_EQUAL; + +typedef struct _EFI_IFR_GREATER_THAN { + EFI_IFR_OP_HEADER Header; +} EFI_IFR_GREATER_THAN; + +typedef struct _EFI_IFR_LESS_EQUAL { + EFI_IFR_OP_HEADER Header; +} EFI_IFR_LESS_EQUAL; + +typedef struct _EFI_IFR_LESS_THAN { + EFI_IFR_OP_HEADER Header; +} EFI_IFR_LESS_THAN; + +typedef struct _EFI_IFR_MATCH { + EFI_IFR_OP_HEADER Header; +} EFI_IFR_MATCH; + +typedef struct _EFI_IFR_MULTIPLY { + EFI_IFR_OP_HEADER Header; +} EFI_IFR_MULTIPLY; + +typedef struct _EFI_IFR_MODULO { + EFI_IFR_OP_HEADER Header; +} EFI_IFR_MODULO; + +typedef struct _EFI_IFR_NOT_EQUAL { + EFI_IFR_OP_HEADER Header; +} EFI_IFR_NOT_EQUAL; + +typedef struct _EFI_IFR_OR { + EFI_IFR_OP_HEADER Header; +} EFI_IFR_OR; + +typedef struct _EFI_IFR_SHIFT_LEFT { + EFI_IFR_OP_HEADER Header; +} EFI_IFR_SHIFT_LEFT; + +typedef struct _EFI_IFR_SHIFT_RIGHT { + EFI_IFR_OP_HEADER Header; +} EFI_IFR_SHIFT_RIGHT; + +typedef struct _EFI_IFR_SUBTRACT { + EFI_IFR_OP_HEADER Header; +} EFI_IFR_SUBTRACT; + +typedef struct _EFI_IFR_CONDITIONAL { + EFI_IFR_OP_HEADER Header; +} EFI_IFR_CONDITIONAL; + +// +// Flags governing the matching criteria of EFI_IFR_FIND +// +#define EFI_IFR_FF_CASE_SENSITIVE 0x00 +#define EFI_IFR_FF_CASE_INSENSITIVE 0x01 + +typedef struct _EFI_IFR_FIND { + EFI_IFR_OP_HEADER Header; + UINT8 Format; +} EFI_IFR_FIND; + +typedef struct _EFI_IFR_MID { + EFI_IFR_OP_HEADER Header; +} EFI_IFR_MID; + +typedef struct _EFI_IFR_TOKEN { + EFI_IFR_OP_HEADER Header; +} EFI_IFR_TOKEN; + +// +// Flags specifying whether to find the first matching string +// or the first non-matching string. +// +#define EFI_IFR_FLAGS_FIRST_MATCHING 0x00 +#define EFI_IFR_FLAGS_FIRST_NON_MATCHING 0x01 + +typedef struct _EFI_IFR_SPAN { + EFI_IFR_OP_HEADER Header; + UINT8 Flags; +} EFI_IFR_SPAN; + +// +// Definitions for Keyboard Package +// Section 27.3.9 +// Releated definitions are in Section of EFI_HII_DATABASE_PROTOCOL +// + +typedef enum { + EfiKeyLCtrl, + EfiKeyA0, + EfiKeyLAlt, + EfiKeySpaceBar, + EfiKeyA2, + EfiKeyA3, + EfiKeyA4, + EfiKeyRCtrl, + EfiKeyLeftArrow, + EfiKeyDownArrow, + EfiKeyRightArrow, + EfiKeyZero, + EfiKeyPeriod, + EfiKeyEnter, + EfiKeyLShift, + EfiKeyB0, + EfiKeyB1, + EfiKeyB2, + EfiKeyB3, + EfiKeyB4, + EfiKeyB5, + EfiKeyB6, + EfiKeyB7, + EfiKeyB8, + EfiKeyB9, + EfiKeyB10, + EfiKeyRShift, + EfiKeyUpArrow, + EfiKeyOne, + EfiKeyTwo, + EfiKeyThree, + EfiKeyCapsLock, + EfiKeyC1, + EfiKeyC2, + EfiKeyC3, + EfiKeyC4, + EfiKeyC5, + EfiKeyC6, + EfiKeyC7, + EfiKeyC8, + EfiKeyC9, + EfiKeyC10, + EfiKeyC11, + EfiKeyC12, + EfiKeyFour, + EfiKeyFive, + EfiKeySix, + EfiKeyPlus, + EfiKeyTab, + EfiKeyD1, + EfiKeyD2, + EfiKeyD3, + EfiKeyD4, + EfiKeyD5, + EfiKeyD6, + EfiKeyD7, + EfiKeyD8, + EfiKeyD9, + EfiKeyD10, + EfiKeyD11, + EfiKeyD12, + EfiKeyD13, + EfiKeyDel, + EfiKeyEnd, + EfiKeyPgDn, + EfiKeySeven, + EfiKeyEight, + EfiKeyNine, + EfiKeyE0, + EfiKeyE1, + EfiKeyE2, + EfiKeyE3, + EfiKeyE4, + EfiKeyE5, + EfiKeyE6, + EfiKeyE7, + EfiKeyE8, + EfiKeyE9, + EfiKeyE10, + EfiKeyE11, + EfiKeyE12, + EfiKeyBackSpace, + EfiKeyIns, + EfiKeyHome, + EfiKeyPgUp, + EfiKeyNLck, + EfiKeySlash, + EfiKeyAsterisk, + EfiKeyMinus, + EfiKeyEsc, + EfiKeyF1, + EfiKeyF2, + EfiKeyF3, + EfiKeyF4, + EfiKeyF5, + EfiKeyF6, + EfiKeyF7, + EfiKeyF8, + EfiKeyF9, + EfiKeyF10, + EfiKeyF11, + EfiKeyF12, + EfiKeyPrint, + EfiKeySLck, + EfiKeyPause +} EFI_KEY; + +typedef struct { + EFI_KEY Key; + CHAR16 Unicode; + CHAR16 ShiftedUnicode; + CHAR16 AltGrUnicode; + CHAR16 ShiftedAltGrUnicode; + UINT16 Modifier; + UINT16 AffectedAttribute; +} EFI_KEY_DESCRIPTOR; + +/// +/// A key which is affected by all the standard shift modifiers. +/// Most keys would be expected to have this bit active. +/// +#define EFI_AFFECTED_BY_STANDARD_SHIFT 0x0001 + +/// +/// This key is affected by the caps lock so that if a keyboard driver +/// would need to disambiguate between a key which had a "1" defined +/// versus a "a" character. Having this bit turned on would tell +/// the keyboard driver to use the appropriate shifted state or not. +/// +#define EFI_AFFECTED_BY_CAPS_LOCK 0x0002 + +/// +/// Similar to the case of CAPS lock, if this bit is active, the key +/// is affected by the num lock being turned on. +/// +#define EFI_AFFECTED_BY_NUM_LOCK 0x0004 + +typedef struct { + UINT16 LayoutLength; + EFI_GUID Guid; + UINT32 LayoutDescriptorStringOffset; + UINT8 DescriptorCount; + // EFI_KEY_DESCRIPTOR Descriptors[]; +} EFI_HII_KEYBOARD_LAYOUT; + +typedef struct { + EFI_HII_PACKAGE_HEADER Header; + UINT16 LayoutCount; + // EFI_HII_KEYBOARD_LAYOUT Layout[]; +} EFI_HII_KEYBOARD_PACKAGE_HDR; + +// +// Modifier values +// +#define EFI_NULL_MODIFIER 0x0000 +#define EFI_LEFT_CONTROL_MODIFIER 0x0001 +#define EFI_RIGHT_CONTROL_MODIFIER 0x0002 +#define EFI_LEFT_ALT_MODIFIER 0x0003 +#define EFI_RIGHT_ALT_MODIFIER 0x0004 +#define EFI_ALT_GR_MODIFIER 0x0005 +#define EFI_INSERT_MODIFIER 0x0006 +#define EFI_DELETE_MODIFIER 0x0007 +#define EFI_PAGE_DOWN_MODIFIER 0x0008 +#define EFI_PAGE_UP_MODIFIER 0x0009 +#define EFI_HOME_MODIFIER 0x000A +#define EFI_END_MODIFIER 0x000B +#define EFI_LEFT_SHIFT_MODIFIER 0x000C +#define EFI_RIGHT_SHIFT_MODIFIER 0x000D +#define EFI_CAPS_LOCK_MODIFIER 0x000E +#define EFI_NUM_LOCK_MODIFIER 0x000F +#define EFI_LEFT_ARROW_MODIFIER 0x0010 +#define EFI_RIGHT_ARROW_MODIFIER 0x0011 +#define EFI_DOWN_ARROW_MODIFIER 0x0012 +#define EFI_UP_ARROW_MODIFIER 0x0013 +#define EFI_NS_KEY_MODIFIER 0x0014 +#define EFI_NS_KEY_DEPENDENCY_MODIFIER 0x0015 +#define EFI_FUNCTION_KEY_ONE_MODIFIER 0x0016 +#define EFI_FUNCTION_KEY_TWO_MODIFIER 0x0017 +#define EFI_FUNCTION_KEY_THREE_MODIFIER 0x0018 +#define EFI_FUNCTION_KEY_FOUR_MODIFIER 0x0019 +#define EFI_FUNCTION_KEY_FIVE_MODIFIER 0x001A +#define EFI_FUNCTION_KEY_SIX_MODIFIER 0x001B +#define EFI_FUNCTION_KEY_SEVEN_MODIFIER 0x001C +#define EFI_FUNCTION_KEY_EIGHT_MODIFIER 0x001D +#define EFI_FUNCTION_KEY_NINE_MODIFIER 0x001E +#define EFI_FUNCTION_KEY_TEN_MODIFIER 0x001F +#define EFI_FUNCTION_KEY_ELEVEN_MODIFIER 0x0020 +#define EFI_FUNCTION_KEY_TWELVE_MODIFIER 0x0021 + +// +// Keys that have multiple control functions based on modifier +// settings are handled in the keyboard driver implementation. +// For instance PRINT_KEY might have a modifier held down and +// is still a nonprinting character, but might have an alternate +// control function like SYSREQUEST +// +#define EFI_PRINT_MODIFIER 0x0022 +#define EFI_SYS_REQUEST_MODIFIER 0x0023 +#define EFI_SCROLL_LOCK_MODIFIER 0x0024 +#define EFI_PAUSE_MODIFIER 0x0025 +#define EFI_BREAK_MODIFIER 0x0026 + +#define EFI_LEFT_LOGO_MODIFIER 0x0027 +#define EFI_RIGHT_LOGO_MODIFIER 0x0028 +#define EFI_MENU_MODIFIER 0x0029 + +#pragma pack() + + + +/// +/// References to string tokens must use this macro to enable scanning for +/// token usages. +/// +/// +/// STRING_TOKEN is not defined in UEFI specification. But it is placed +/// here for the easy access by C files and VFR source files. +/// +#define STRING_TOKEN(t) t + +#endif diff --git a/gpxe/src/include/gpxe/efi/Uefi/UefiMultiPhase.h b/gpxe/src/include/gpxe/efi/Uefi/UefiMultiPhase.h new file mode 100644 index 00000000..2d1af5ed --- /dev/null +++ b/gpxe/src/include/gpxe/efi/Uefi/UefiMultiPhase.h @@ -0,0 +1,210 @@ +/** @file + This includes some definitions introduced in UEFI that will be used in both PEI and DXE phases. + + Copyright (c) 2006 - 2008, Intel Corporation + All rights reserved. This program and the accompanying materials + are licensed and made available under the terms and conditions of the BSD License + which accompanies this distribution. The full text of the license may be found at + http://opensource.org/licenses/bsd-license.php + + THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, + WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + +**/ + +#ifndef __UEFI_MULTIPHASE_H__ +#define __UEFI_MULTIPHASE_H__ + +#include <gpxe/efi/ProcessorBind.h> + +/// +/// Enumeration of memory types introduced in UEFI. +/// +typedef enum { + EfiReservedMemoryType, + EfiLoaderCode, + EfiLoaderData, + EfiBootServicesCode, + EfiBootServicesData, + EfiRuntimeServicesCode, + EfiRuntimeServicesData, + EfiConventionalMemory, + EfiUnusableMemory, + EfiACPIReclaimMemory, + EfiACPIMemoryNVS, + EfiMemoryMappedIO, + EfiMemoryMappedIOPortSpace, + EfiPalCode, + EfiMaxMemoryType +} EFI_MEMORY_TYPE; + + +/// +/// Data structure that precedes all of the standard EFI table types. +/// +typedef struct { + UINT64 Signature; + UINT32 Revision; + UINT32 HeaderSize; + UINT32 CRC32; + UINT32 Reserved; +} EFI_TABLE_HEADER; + +/// +/// Attributes of variable. +/// +#define EFI_VARIABLE_NON_VOLATILE 0x00000001 +#define EFI_VARIABLE_BOOTSERVICE_ACCESS 0x00000002 +#define EFI_VARIABLE_RUNTIME_ACCESS 0x00000004 +#define EFI_VARIABLE_HARDWARE_ERROR_RECORD 0x00000008 + +/// +/// This attribute is identified by the mnemonic 'HR' +/// elsewhere in this specification. +/// +#define EFI_VARIABLE_AUTHENTICATED_WRITE_ACCESS 0x00000010 + +// +// _WIN_CERTIFICATE.wCertificateType +// +#define WIN_CERT_TYPE_EFI_PKCS115 0x0EF0 +#define WIN_CERT_TYPE_EFI_GUID 0x0EF1 + +/// +/// The WIN_CERTIFICATE structure is part of the PE/COFF specification. +/// +typedef struct _WIN_CERTIFICATE { + /// + /// The length of the entire certificate, + /// including the length of the header, in bytes. + /// + UINT32 dwLength; + /// + /// The revision level of the WIN_CERTIFICATE + /// structure. The current revision level is 0x0200. + /// + UINT16 wRevision; + /// + /// The certificate type. See WIN_CERT_TYPE_xxx for the UEFI + /// certificate types. The UEFI specification reserves the range of + /// certificate type values from 0x0EF0 to 0x0EFF. + /// + UINT16 wCertificateType; + /// + /// The following is the actual certificate. The format of + /// the certificate depends on wCertificateType. + /// + /// UINT8 bCertificate[ANYSIZE_ARRAY]; + /// +} WIN_CERTIFICATE; + +/// +/// WIN_CERTIFICATE_UEFI_GUID.CertType +/// +#define EFI_CERT_TYPE_RSA2048_SHA256_GUID \ + {0xa7717414, 0xc616, 0x4977, {0x94, 0x20, 0x84, 0x47, 0x12, 0xa7, 0x35, 0xbf } } + +// +// WIN_CERTIFICATE_UEFI_GUID.CertData +// +typedef struct _EFI_CERT_BLOCK_RSA_2048_SHA256 { + UINT32 HashType; + UINT8 PublicKey[256]; + UINT8 Signature[256]; +} EFI_CERT_BLOCK_RSA_2048_SHA256; + + +/// +/// Certificate which encapsulates a GUID-specific digital signature +/// +typedef struct _WIN_CERTIFICATE_UEFI_GUID { + /// + /// This is the standard WIN_CERTIFICATE header, where + /// wCertificateType is set to WIN_CERT_TYPE_UEFI_GUID. + /// + WIN_CERTIFICATE Hdr; + /// + /// This is the unique id which determines the + /// format of the CertData. In this case, the + /// value is EFI_CERT_TYPE_RSA2048_SHA256_GUID. + /// + EFI_GUID CertType; + /// + /// The following is the certificate data. The format of + /// the data is determined by the CertType. In this case the value is + /// EFI_CERT_BLOCK_RSA_2048_SHA256. + /// + /// UINT8 CertData[ANYSIZE_ARRAY]; + /// +} WIN_CERTIFICATE_UEFI_GUID; + + +/// +/// Certificate which encapsulates the RSASSA_PKCS1-v1_5 digital signature. +/// +/// The WIN_CERTIFICATE_UEFI_PKCS1_15 structure is derived from +/// WIN_CERTIFICATE and encapsulate the information needed to +/// implement the RSASSA-PKCS1-v1_5 digital signature algorithm as +/// specified in RFC2437. +/// +typedef struct _WIN_CERTIFICATE_EFI_PKCS1_15 { + /// + /// This is the standard WIN_CERTIFICATE header, where + /// wCertificateType is set to WIN_CERT_TYPE_UEFI_PKCS1_15. + /// + WIN_CERTIFICATE Hdr; + /// + /// This is the hashing algorithm which was performed on the + /// UEFI executable when creating the digital signature. + /// + EFI_GUID HashAlgorithm; + /// + /// The following is the actual digital signature. The + /// size of the signature is the same size as the key + /// (1024-bit key is 128 bytes) and can be determined by + /// subtracting the length of the other parts of this header + /// from the total length of the certificate as found in + /// Hdr.dwLength. + /// + /// UINT8 Signature[ANYSIZE_ARRAY]; + /// +} WIN_CERTIFICATE_EFI_PKCS1_15; + + + +/// +/// AuthInfo is a WIN_CERTIFICATE using the wCertificateType +/// WIN_CERTIFICATE_UEFI_GUID and the CertType +/// EFI_CERT_TYPE_RSA2048_SHA256. If the attribute specifies +/// authenticated access, then the Data buffer should begin with an +/// authentication descriptor prior to the data payload and DataSize +/// should reflect the the data.and descriptor size. The caller +/// shall digest the Monotonic Count value and the associated data +/// for the variable update using the SHA-256 1-way hash algorithm. +/// The ensuing the 32-byte digest will be signed using the private +/// key associated w/ the public/private 2048-bit RSA key-pair. The +/// WIN_CERTIFICATE shall be used to describe the signature of the +/// Variable data *Data. In addition, the signature will also +/// include the MonotonicCount value to guard against replay attacks +/// +typedef struct { + /// + /// Included in the signature of + /// AuthInfo.Used to ensure freshness/no + /// replay. Incremented during each + /// "Write" access. + /// + UINT64 MonotonicCount; + /// + /// Provides the authorization for the variable + /// access. It is a signature across the + /// variable data and the Monotonic Count + /// value. Caller uses Private key that is + /// associated with a public key that has been + /// provisioned via the key exchange. + /// + WIN_CERTIFICATE_UEFI_GUID AuthInfo; +} EFI_VARIABLE_AUTHENTICATION; + +#endif + diff --git a/gpxe/src/include/gpxe/efi/Uefi/UefiPxe.h b/gpxe/src/include/gpxe/efi/Uefi/UefiPxe.h new file mode 100644 index 00000000..bb8ab410 --- /dev/null +++ b/gpxe/src/include/gpxe/efi/Uefi/UefiPxe.h @@ -0,0 +1,1756 @@ +/** @file + This header file contains all of the PXE type definitions, + structure prototypes, global variables and constants that + are needed for porting PXE to EFI. + + Copyright (c) 2006 - 2008, Intel Corporation + All rights reserved. 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: + 32/64-bit PXE specification: + alpha-4, 99-Dec-17 + +**/ + +#ifndef __EFI_PXE_H__ +#define __EFI_PXE_H__ + +#pragma pack(1) + +#define PXE_BUSTYPE(a, b, c, d) \ + ( \ + (((PXE_UINT32) (d) & 0xFF) << 24) | (((PXE_UINT32) (c) & 0xFF) << 16) | (((PXE_UINT32) (b) & 0xFF) << 8) | \ + ((PXE_UINT32) (a) & 0xFF) \ + ) + +/// +/// UNDI ROM ID and devive ID signature +/// +#define PXE_BUSTYPE_PXE PXE_BUSTYPE ('!', 'P', 'X', 'E') + +/// +/// BUS ROM ID signatures +/// +#define PXE_BUSTYPE_PCI PXE_BUSTYPE ('P', 'C', 'I', 'R') +#define PXE_BUSTYPE_PC_CARD PXE_BUSTYPE ('P', 'C', 'C', 'R') +#define PXE_BUSTYPE_USB PXE_BUSTYPE ('U', 'S', 'B', 'R') +#define PXE_BUSTYPE_1394 PXE_BUSTYPE ('1', '3', '9', '4') + +#define PXE_SWAP_UINT16(n) ((((PXE_UINT16) (n) & 0x00FF) << 8) | (((PXE_UINT16) (n) & 0xFF00) >> 8)) + +#define PXE_SWAP_UINT32(n) \ + ((((PXE_UINT32)(n) & 0x000000FF) << 24) | \ + (((PXE_UINT32)(n) & 0x0000FF00) << 8) | \ + (((PXE_UINT32)(n) & 0x00FF0000) >> 8) | \ + (((PXE_UINT32)(n) & 0xFF000000) >> 24)) + +#define PXE_SWAP_UINT64(n) \ + ((((PXE_UINT64)(n) & 0x00000000000000FFULL) << 56) | \ + (((PXE_UINT64)(n) & 0x000000000000FF00ULL) << 40) | \ + (((PXE_UINT64)(n) & 0x0000000000FF0000ULL) << 24) | \ + (((PXE_UINT64)(n) & 0x00000000FF000000ULL) << 8) | \ + (((PXE_UINT64)(n) & 0x000000FF00000000ULL) >> 8) | \ + (((PXE_UINT64)(n) & 0x0000FF0000000000ULL) >> 24) | \ + (((PXE_UINT64)(n) & 0x00FF000000000000ULL) >> 40) | \ + (((PXE_UINT64)(n) & 0xFF00000000000000ULL) >> 56)) + + +#define PXE_CPBSIZE_NOT_USED 0 ///< zero +#define PXE_DBSIZE_NOT_USED 0 ///< zero +#define PXE_CPBADDR_NOT_USED (PXE_UINT64) 0 ///< zero +#define PXE_DBADDR_NOT_USED (PXE_UINT64) 0 ///< zero +#define PXE_CONST CONST + +#define PXE_VOLATILE volatile + +typedef VOID PXE_VOID; +typedef UINT8 PXE_UINT8; +typedef UINT16 PXE_UINT16; +typedef UINT32 PXE_UINT32; +typedef UINTN PXE_UINTN; + +/// +/// typedef unsigned long PXE_UINT64; +/// +typedef UINT64 PXE_UINT64; + +typedef PXE_UINT8 PXE_BOOL; +#define PXE_FALSE 0 ///< zero +#define PXE_TRUE (!PXE_FALSE) + +typedef PXE_UINT16 PXE_OPCODE; + +/// +/// Return UNDI operational state. +/// +#define PXE_OPCODE_GET_STATE 0x0000 + +/// +/// Change UNDI operational state from Stopped to Started. +/// +#define PXE_OPCODE_START 0x0001 + +/// +/// Change UNDI operational state from Started to Stopped. +/// +#define PXE_OPCODE_STOP 0x0002 + +/// +/// Get UNDI initialization information. +/// +#define PXE_OPCODE_GET_INIT_INFO 0x0003 + +/// +/// Get NIC configuration information. +/// +#define PXE_OPCODE_GET_CONFIG_INFO 0x0004 + +/// +/// Changed UNDI operational state from Started to Initialized. +/// +#define PXE_OPCODE_INITIALIZE 0x0005 + +/// +/// Re-initialize the NIC H/W. +/// +#define PXE_OPCODE_RESET 0x0006 + +/// +/// Change the UNDI operational state from Initialized to Started. +/// +#define PXE_OPCODE_SHUTDOWN 0x0007 + +/// +/// Read & change state of external interrupt enables. +/// +#define PXE_OPCODE_INTERRUPT_ENABLES 0x0008 + +/// +/// Read & change state of packet receive filters. +/// +#define PXE_OPCODE_RECEIVE_FILTERS 0x0009 + +/// +/// Read & change station MAC address. +/// +#define PXE_OPCODE_STATION_ADDRESS 0x000A + +/// +/// Read traffic statistics. +/// +#define PXE_OPCODE_STATISTICS 0x000B + +/// +/// Convert multicast IP address to multicast MAC address. +/// +#define PXE_OPCODE_MCAST_IP_TO_MAC 0x000C + +/// +/// Read or change non-volatile storage on the NIC. +/// +#define PXE_OPCODE_NVDATA 0x000D + +/// +/// Get & clear interrupt status. +/// +#define PXE_OPCODE_GET_STATUS 0x000E + +/// +/// Fill media header in packet for transmit. +/// +#define PXE_OPCODE_FILL_HEADER 0x000F + +/// +/// Transmit packet(s). +/// +#define PXE_OPCODE_TRANSMIT 0x0010 + +/// +/// Receive packet. +/// +#define PXE_OPCODE_RECEIVE 0x0011 + +/// +/// Last valid PXE UNDI OpCode number. +/// +#define PXE_OPCODE_LAST_VALID 0x0011 + +typedef PXE_UINT16 PXE_OPFLAGS; + +#define PXE_OPFLAGS_NOT_USED 0x0000 + +// +// ////////////////////////////////////// +// UNDI Get State +// +// No OpFlags + +//////////////////////////////////////// +// UNDI Start +// +// No OpFlags + +//////////////////////////////////////// +// UNDI Stop +// +// No OpFlags + +//////////////////////////////////////// +// UNDI Get Init Info +// +// No Opflags + +//////////////////////////////////////// +// UNDI Get Config Info +// +// No Opflags + +/// +/// UNDI Initialize +/// +#define PXE_OPFLAGS_INITIALIZE_CABLE_DETECT_MASK 0x0001 +#define PXE_OPFLAGS_INITIALIZE_DETECT_CABLE 0x0000 +#define PXE_OPFLAGS_INITIALIZE_DO_NOT_DETECT_CABLE 0x0001 + +/// +/// +/// UNDI Reset +/// +#define PXE_OPFLAGS_RESET_DISABLE_INTERRUPTS 0x0001 +#define PXE_OPFLAGS_RESET_DISABLE_FILTERS 0x0002 + +/// +/// UNDI Shutdown +/// +/// No OpFlags + +/// +/// UNDI Interrupt Enables +/// +/// +/// Select whether to enable or disable external interrupt signals. +/// Setting both enable and disable will return PXE_STATCODE_INVALID_OPFLAGS. +/// +#define PXE_OPFLAGS_INTERRUPT_OPMASK 0xC000 +#define PXE_OPFLAGS_INTERRUPT_ENABLE 0x8000 +#define PXE_OPFLAGS_INTERRUPT_DISABLE 0x4000 +#define PXE_OPFLAGS_INTERRUPT_READ 0x0000 + +/// +/// Enable receive interrupts. An external interrupt will be generated +/// after a complete non-error packet has been received. +/// +#define PXE_OPFLAGS_INTERRUPT_RECEIVE 0x0001 + +/// +/// Enable transmit interrupts. An external interrupt will be generated +/// after a complete non-error packet has been transmitted. +/// +#define PXE_OPFLAGS_INTERRUPT_TRANSMIT 0x0002 + +/// +/// Enable command interrupts. An external interrupt will be generated +/// when command execution stops. +/// +#define PXE_OPFLAGS_INTERRUPT_COMMAND 0x0004 + +/// +/// Generate software interrupt. Setting this bit generates an external +/// interrupt, if it is supported by the hardware. +/// +#define PXE_OPFLAGS_INTERRUPT_SOFTWARE 0x0008 + +/// +/// UNDI Receive Filters +/// +/// +/// Select whether to enable or disable receive filters. +/// Setting both enable and disable will return PXE_STATCODE_INVALID_OPCODE. +/// +#define PXE_OPFLAGS_RECEIVE_FILTER_OPMASK 0xC000 +#define PXE_OPFLAGS_RECEIVE_FILTER_ENABLE 0x8000 +#define PXE_OPFLAGS_RECEIVE_FILTER_DISABLE 0x4000 +#define PXE_OPFLAGS_RECEIVE_FILTER_READ 0x0000 + +/// +/// To reset the contents of the multicast MAC address filter list, +/// set this OpFlag: +/// +#define PXE_OPFLAGS_RECEIVE_FILTER_RESET_MCAST_LIST 0x2000 + +/// +/// Enable unicast packet receiving. Packets sent to the current station +/// MAC address will be received. +/// +#define PXE_OPFLAGS_RECEIVE_FILTER_UNICAST 0x0001 + +/// +/// Enable broadcast packet receiving. Packets sent to the broadcast +/// MAC address will be received. +/// +#define PXE_OPFLAGS_RECEIVE_FILTER_BROADCAST 0x0002 + +/// +/// Enable filtered multicast packet receiving. Packets sent to any +/// of the multicast MAC addresses in the multicast MAC address filter +/// list will be received. If the filter list is empty, no multicast +/// +#define PXE_OPFLAGS_RECEIVE_FILTER_FILTERED_MULTICAST 0x0004 + +/// +/// Enable promiscuous packet receiving. All packets will be received. +/// +#define PXE_OPFLAGS_RECEIVE_FILTER_PROMISCUOUS 0x0008 + +/// +/// Enable promiscuous multicast packet receiving. All multicast +/// packets will be received. +/// +#define PXE_OPFLAGS_RECEIVE_FILTER_ALL_MULTICAST 0x0010 + +/// +/// UNDI Station Address +/// +#define PXE_OPFLAGS_STATION_ADDRESS_READ 0x0000 +#define PXE_OPFLAGS_STATION_ADDRESS_WRITE 0x0000 +#define PXE_OPFLAGS_STATION_ADDRESS_RESET 0x0001 + +/// +/// UNDI Statistics +/// +#define PXE_OPFLAGS_STATISTICS_READ 0x0000 +#define PXE_OPFLAGS_STATISTICS_RESET 0x0001 + +/// +/// UNDI MCast IP to MAC +/// +/// +/// Identify the type of IP address in the CPB. +/// +#define PXE_OPFLAGS_MCAST_IP_TO_MAC_OPMASK 0x0003 +#define PXE_OPFLAGS_MCAST_IPV4_TO_MAC 0x0000 +#define PXE_OPFLAGS_MCAST_IPV6_TO_MAC 0x0001 + +/// +/// UNDI NvData +/// +/// +/// Select the type of non-volatile data operation. +/// +#define PXE_OPFLAGS_NVDATA_OPMASK 0x0001 +#define PXE_OPFLAGS_NVDATA_READ 0x0000 +#define PXE_OPFLAGS_NVDATA_WRITE 0x0001 + +/// +/// UNDI Get Status +/// +/// +/// Return current interrupt status. This will also clear any interrupts +/// that are currently set. This can be used in a polling routine. The +/// interrupt flags are still set and cleared even when the interrupts +/// are disabled. +/// +#define PXE_OPFLAGS_GET_INTERRUPT_STATUS 0x0001 + +/// +/// Return list of transmitted buffers for recycling. Transmit buffers +/// must not be changed or unallocated until they have recycled. After +/// issuing a transmit command, wait for a transmit complete interrupt. +/// When a transmit complete interrupt is received, read the transmitted +/// buffers. Do not plan on getting one buffer per interrupt. Some +/// NICs and UNDIs may transmit multiple buffers per interrupt. +/// +#define PXE_OPFLAGS_GET_TRANSMITTED_BUFFERS 0x0002 + +/// +/// UNDI Fill Header +/// +#define PXE_OPFLAGS_FILL_HEADER_OPMASK 0x0001 +#define PXE_OPFLAGS_FILL_HEADER_FRAGMENTED 0x0001 +#define PXE_OPFLAGS_FILL_HEADER_WHOLE 0x0000 + +/// +/// UNDI Transmit +/// +/// +/// S/W UNDI only. Return after the packet has been transmitted. A +/// transmit complete interrupt will still be generated and the transmit +/// buffer will have to be recycled. +/// +#define PXE_OPFLAGS_SWUNDI_TRANSMIT_OPMASK 0x0001 +#define PXE_OPFLAGS_TRANSMIT_BLOCK 0x0001 +#define PXE_OPFLAGS_TRANSMIT_DONT_BLOCK 0x0000 + +#define PXE_OPFLAGS_TRANSMIT_OPMASK 0x0002 +#define PXE_OPFLAGS_TRANSMIT_FRAGMENTED 0x0002 +#define PXE_OPFLAGS_TRANSMIT_WHOLE 0x0000 + +/// +/// UNDI Receive +/// +/// No OpFlags +/// + +/// +/// PXE STATFLAGS +/// +typedef PXE_UINT16 PXE_STATFLAGS; + +#define PXE_STATFLAGS_INITIALIZE 0x0000 + +/// +/// Common StatFlags that can be returned by all commands. +/// +/// +/// The COMMAND_COMPLETE and COMMAND_FAILED status flags must be +/// implemented by all UNDIs. COMMAND_QUEUED is only needed by UNDIs +/// that support command queuing. +/// +#define PXE_STATFLAGS_STATUS_MASK 0xC000 +#define PXE_STATFLAGS_COMMAND_COMPLETE 0xC000 +#define PXE_STATFLAGS_COMMAND_FAILED 0x8000 +#define PXE_STATFLAGS_COMMAND_QUEUED 0x4000 + +/// +/// UNDI Get State +/// +#define PXE_STATFLAGS_GET_STATE_MASK 0x0003 +#define PXE_STATFLAGS_GET_STATE_INITIALIZED 0x0002 +#define PXE_STATFLAGS_GET_STATE_STARTED 0x0001 +#define PXE_STATFLAGS_GET_STATE_STOPPED 0x0000 + +/// +/// UNDI Start +/// +/// No additional StatFlags +/// + +/// +/// UNDI Get Init Info +/// +#define PXE_STATFLAGS_CABLE_DETECT_MASK 0x0001 +#define PXE_STATFLAGS_CABLE_DETECT_NOT_SUPPORTED 0x0000 +#define PXE_STATFLAGS_CABLE_DETECT_SUPPORTED 0x0001 + +/// +/// UNDI Initialize +/// +#define PXE_STATFLAGS_INITIALIZED_NO_MEDIA 0x0001 + +/// +/// UNDI Reset +/// +#define PXE_STATFLAGS_RESET_NO_MEDIA 0x0001 + +/// +/// UNDI Shutdown +/// +/// No additional StatFlags + +/// +/// UNDI Interrupt Enables +/// +/// +/// If set, receive interrupts are enabled. +/// +#define PXE_STATFLAGS_INTERRUPT_RECEIVE 0x0001 + +/// +/// If set, transmit interrupts are enabled. +/// +#define PXE_STATFLAGS_INTERRUPT_TRANSMIT 0x0002 + +/// +/// If set, command interrupts are enabled. +/// +#define PXE_STATFLAGS_INTERRUPT_COMMAND 0x0004 + +/// +/// UNDI Receive Filters +/// + +/// +/// If set, unicast packets will be received. +/// +#define PXE_STATFLAGS_RECEIVE_FILTER_UNICAST 0x0001 + +/// +/// If set, broadcast packets will be received. +/// +#define PXE_STATFLAGS_RECEIVE_FILTER_BROADCAST 0x0002 + +/// +/// If set, multicast packets that match up with the multicast address +/// filter list will be received. +/// +#define PXE_STATFLAGS_RECEIVE_FILTER_FILTERED_MULTICAST 0x0004 + +/// +/// If set, all packets will be received. +/// +#define PXE_STATFLAGS_RECEIVE_FILTER_PROMISCUOUS 0x0008 + +/// +/// If set, all multicast packets will be received. +/// +#define PXE_STATFLAGS_RECEIVE_FILTER_ALL_MULTICAST 0x0010 + +/// +/// UNDI Station Address +/// +/// No additional StatFlags +/// + +/// +/// UNDI Statistics +/// +/// No additional StatFlags +/// + +/// +//// UNDI MCast IP to MAC +//// +//// No additional StatFlags + +/// +/// UNDI NvData +/// +/// No additional StatFlags +/// + +/// +/// UNDI Get Status +/// + +/// +/// Use to determine if an interrupt has occurred. +/// +#define PXE_STATFLAGS_GET_STATUS_INTERRUPT_MASK 0x000F +#define PXE_STATFLAGS_GET_STATUS_NO_INTERRUPTS 0x0000 + +/// +/// If set, at least one receive interrupt occurred. +/// +#define PXE_STATFLAGS_GET_STATUS_RECEIVE 0x0001 + +/// +/// If set, at least one transmit interrupt occurred. +/// +#define PXE_STATFLAGS_GET_STATUS_TRANSMIT 0x0002 + +/// +/// If set, at least one command interrupt occurred. +/// +#define PXE_STATFLAGS_GET_STATUS_COMMAND 0x0004 + +/// +/// If set, at least one software interrupt occurred. +/// +#define PXE_STATFLAGS_GET_STATUS_SOFTWARE 0x0008 + +/// +/// This flag is set if the transmitted buffer queue is empty. This flag +/// will be set if all transmitted buffer addresses get written into the DB. +/// +#define PXE_STATFLAGS_GET_STATUS_TXBUF_QUEUE_EMPTY 0x0010 + +/// +/// This flag is set if no transmitted buffer addresses were written +/// into the DB. (This could be because DBsize was too small.) +/// +#define PXE_STATFLAGS_GET_STATUS_NO_TXBUFS_WRITTEN 0x0020 + +/// +/// UNDI Fill Header +/// +/// No additional StatFlags +/// + +/// +/// UNDI Transmit +/// +/// No additional StatFlags. + +/// +/// UNDI Receive +/// + +/// +/// No additional StatFlags. +/// +typedef PXE_UINT16 PXE_STATCODE; + +#define PXE_STATCODE_INITIALIZE 0x0000 + +/// +/// Common StatCodes returned by all UNDI commands, UNDI protocol functions +/// and BC protocol functions. +/// +#define PXE_STATCODE_SUCCESS 0x0000 + +#define PXE_STATCODE_INVALID_CDB 0x0001 +#define PXE_STATCODE_INVALID_CPB 0x0002 +#define PXE_STATCODE_BUSY 0x0003 +#define PXE_STATCODE_QUEUE_FULL 0x0004 +#define PXE_STATCODE_ALREADY_STARTED 0x0005 +#define PXE_STATCODE_NOT_STARTED 0x0006 +#define PXE_STATCODE_NOT_SHUTDOWN 0x0007 +#define PXE_STATCODE_ALREADY_INITIALIZED 0x0008 +#define PXE_STATCODE_NOT_INITIALIZED 0x0009 +#define PXE_STATCODE_DEVICE_FAILURE 0x000A +#define PXE_STATCODE_NVDATA_FAILURE 0x000B +#define PXE_STATCODE_UNSUPPORTED 0x000C +#define PXE_STATCODE_BUFFER_FULL 0x000D +#define PXE_STATCODE_INVALID_PARAMETER 0x000E +#define PXE_STATCODE_INVALID_UNDI 0x000F +#define PXE_STATCODE_IPV4_NOT_SUPPORTED 0x0010 +#define PXE_STATCODE_IPV6_NOT_SUPPORTED 0x0011 +#define PXE_STATCODE_NOT_ENOUGH_MEMORY 0x0012 +#define PXE_STATCODE_NO_DATA 0x0013 + +typedef PXE_UINT16 PXE_IFNUM; + +/// +/// This interface number must be passed to the S/W UNDI Start command. +/// +#define PXE_IFNUM_START 0x0000 + +/// +/// This interface number is returned by the S/W UNDI Get State and +/// Start commands if information in the CDB, CPB or DB is invalid. +/// +#define PXE_IFNUM_INVALID 0x0000 + +typedef PXE_UINT16 PXE_CONTROL; + +/// +/// Setting this flag directs the UNDI to queue this command for later +/// execution if the UNDI is busy and it supports command queuing. +/// If queuing is not supported, a PXE_STATCODE_INVALID_CONTROL error +/// is returned. If the queue is full, a PXE_STATCODE_CDB_QUEUE_FULL +/// error is returned. +/// +#define PXE_CONTROL_QUEUE_IF_BUSY 0x0002 + +/// +/// These two bit values are used to determine if there are more UNDI +/// CDB structures following this one. If the link bit is set, there +/// must be a CDB structure following this one. Execution will start +/// on the next CDB structure as soon as this one completes successfully. +/// If an error is generated by this command, execution will stop. +/// +#define PXE_CONTROL_LINK 0x0001 +#define PXE_CONTROL_LAST_CDB_IN_LIST 0x0000 + +typedef PXE_UINT8 PXE_FRAME_TYPE; + +#define PXE_FRAME_TYPE_NONE 0x00 +#define PXE_FRAME_TYPE_UNICAST 0x01 +#define PXE_FRAME_TYPE_BROADCAST 0x02 +#define PXE_FRAME_TYPE_FILTERED_MULTICAST 0x03 +#define PXE_FRAME_TYPE_PROMISCUOUS 0x04 +#define PXE_FRAME_TYPE_PROMISCUOUS_MULTICAST 0x05 + +#define PXE_FRAME_TYPE_MULTICAST PXE_FRAME_TYPE_FILTERED_MULTICAST + +typedef PXE_UINT32 PXE_IPV4; + +typedef PXE_UINT32 PXE_IPV6[4]; +#define PXE_MAC_LENGTH 32 + +typedef PXE_UINT8 PXE_MAC_ADDR[PXE_MAC_LENGTH]; + +typedef PXE_UINT8 PXE_IFTYPE; +typedef UINT16 PXE_MEDIA_PROTOCOL; + +/// +/// This information is from the ARP section of RFC 1700. +/// +/// 1 Ethernet (10Mb) [JBP] +/// 2 Experimental Ethernet (3Mb) [JBP] +/// 3 Amateur Radio AX.25 [PXK] +/// 4 Proteon ProNET Token Ring [JBP] +/// 5 Chaos [GXP] +/// 6 IEEE 802 Networks [JBP] +/// 7 ARCNET [JBP] +/// 8 Hyperchannel [JBP] +/// 9 Lanstar [TU] +/// 10 Autonet Short Address [MXB1] +/// 11 LocalTalk [JKR1] +/// 12 LocalNet (IBM* PCNet or SYTEK* LocalNET) [JXM] +/// 13 Ultra link [RXD2] +/// 14 SMDS [GXC1] +/// 15 Frame Relay [AGM] +/// 16 Asynchronous Transmission Mode (ATM) [JXB2] +/// 17 HDLC [JBP] +/// 18 Fibre Channel [Yakov Rekhter] +/// 19 Asynchronous Transmission Mode (ATM) [Mark Laubach] +/// 20 Serial Line [JBP] +/// 21 Asynchronous Transmission Mode (ATM) [MXB1] +/// +/// * Other names and brands may be claimed as the property of others. +/// +#define PXE_IFTYPE_ETHERNET 0x01 +#define PXE_IFTYPE_TOKENRING 0x04 +#define PXE_IFTYPE_FIBRE_CHANNEL 0x12 + +typedef struct s_pxe_hw_undi { + PXE_UINT32 Signature; ///< PXE_ROMID_SIGNATURE + PXE_UINT8 Len; ///< sizeof(PXE_HW_UNDI) + PXE_UINT8 Fudge; ///< makes 8-bit cksum equal zero + PXE_UINT8 Rev; ///< PXE_ROMID_REV + PXE_UINT8 IFcnt; ///< physical connector count + PXE_UINT8 MajorVer; ///< PXE_ROMID_MAJORVER + PXE_UINT8 MinorVer; ///< PXE_ROMID_MINORVER + PXE_UINT16 reserved; ///< zero, not used + PXE_UINT32 Implementation; ///< implementation flags + ///< reserved ///< vendor use + ///< UINT32 Status; ///< status port + ///< UINT32 Command; ///< command port + ///< UINT64 CDBaddr; ///< CDB address port + ///< +} PXE_HW_UNDI; + +/// +/// Status port bit definitions +/// + +/// +/// UNDI operation state +/// +#define PXE_HWSTAT_STATE_MASK 0xC0000000 +#define PXE_HWSTAT_BUSY 0xC0000000 +#define PXE_HWSTAT_INITIALIZED 0x80000000 +#define PXE_HWSTAT_STARTED 0x40000000 +#define PXE_HWSTAT_STOPPED 0x00000000 + +/// +/// If set, last command failed +/// +#define PXE_HWSTAT_COMMAND_FAILED 0x20000000 + +/// +/// If set, identifies enabled receive filters +/// +#define PXE_HWSTAT_PROMISCUOUS_MULTICAST_RX_ENABLED 0x00001000 +#define PXE_HWSTAT_PROMISCUOUS_RX_ENABLED 0x00000800 +#define PXE_HWSTAT_BROADCAST_RX_ENABLED 0x00000400 +#define PXE_HWSTAT_MULTICAST_RX_ENABLED 0x00000200 +#define PXE_HWSTAT_UNICAST_RX_ENABLED 0x00000100 + +/// +/// If set, identifies enabled external interrupts +/// +#define PXE_HWSTAT_SOFTWARE_INT_ENABLED 0x00000080 +#define PXE_HWSTAT_TX_COMPLETE_INT_ENABLED 0x00000040 +#define PXE_HWSTAT_PACKET_RX_INT_ENABLED 0x00000020 +#define PXE_HWSTAT_CMD_COMPLETE_INT_ENABLED 0x00000010 + +/// +/// If set, identifies pending interrupts +/// +#define PXE_HWSTAT_SOFTWARE_INT_PENDING 0x00000008 +#define PXE_HWSTAT_TX_COMPLETE_INT_PENDING 0x00000004 +#define PXE_HWSTAT_PACKET_RX_INT_PENDING 0x00000002 +#define PXE_HWSTAT_CMD_COMPLETE_INT_PENDING 0x00000001 + +/// +/// Command port definitions +/// + +/// +/// If set, CDB identified in CDBaddr port is given to UNDI. +/// If not set, other bits in this word will be processed. +/// +#define PXE_HWCMD_ISSUE_COMMAND 0x80000000 +#define PXE_HWCMD_INTS_AND_FILTS 0x00000000 + +/// +/// Use these to enable/disable receive filters. +/// +#define PXE_HWCMD_PROMISCUOUS_MULTICAST_RX_ENABLE 0x00001000 +#define PXE_HWCMD_PROMISCUOUS_RX_ENABLE 0x00000800 +#define PXE_HWCMD_BROADCAST_RX_ENABLE 0x00000400 +#define PXE_HWCMD_MULTICAST_RX_ENABLE 0x00000200 +#define PXE_HWCMD_UNICAST_RX_ENABLE 0x00000100 + +/// +/// Use these to enable/disable external interrupts +/// +#define PXE_HWCMD_SOFTWARE_INT_ENABLE 0x00000080 +#define PXE_HWCMD_TX_COMPLETE_INT_ENABLE 0x00000040 +#define PXE_HWCMD_PACKET_RX_INT_ENABLE 0x00000020 +#define PXE_HWCMD_CMD_COMPLETE_INT_ENABLE 0x00000010 + +/// +/// Use these to clear pending external interrupts +/// +#define PXE_HWCMD_CLEAR_SOFTWARE_INT 0x00000008 +#define PXE_HWCMD_CLEAR_TX_COMPLETE_INT 0x00000004 +#define PXE_HWCMD_CLEAR_PACKET_RX_INT 0x00000002 +#define PXE_HWCMD_CLEAR_CMD_COMPLETE_INT 0x00000001 + +typedef struct s_pxe_sw_undi { + PXE_UINT32 Signature; ///< PXE_ROMID_SIGNATURE + PXE_UINT8 Len; ///< sizeof(PXE_SW_UNDI) + PXE_UINT8 Fudge; ///< makes 8-bit cksum zero + PXE_UINT8 Rev; ///< PXE_ROMID_REV + PXE_UINT8 IFcnt; ///< physical connector count + PXE_UINT8 MajorVer; ///< PXE_ROMID_MAJORVER + PXE_UINT8 MinorVer; ///< PXE_ROMID_MINORVER + PXE_UINT16 reserved1; ///< zero, not used + PXE_UINT32 Implementation; ///< Implementation flags + PXE_UINT64 EntryPoint; ///< API entry point + PXE_UINT8 reserved2[3]; ///< zero, not used + PXE_UINT8 BusCnt; ///< number of bustypes supported + PXE_UINT32 BusType[1]; ///< list of supported bustypes +} PXE_SW_UNDI; + +typedef union u_pxe_undi { + PXE_HW_UNDI hw; + PXE_SW_UNDI sw; +} PXE_UNDI; + +/// +/// Signature of !PXE structure +/// +#define PXE_ROMID_SIGNATURE PXE_BUSTYPE ('!', 'P', 'X', 'E') + +/// +/// !PXE structure format revision +/// +#define PXE_ROMID_REV 0x02 + +/// +/// UNDI command interface revision. These are the values that get sent +/// in option 94 (Client Network Interface Identifier) in the DHCP Discover +/// and PXE Boot Server Request packets. +/// +#define PXE_ROMID_MAJORVER 0x03 +#define PXE_ROMID_MINORVER 0x01 + +/// +/// Implementation flags +/// +#define PXE_ROMID_IMP_HW_UNDI 0x80000000 +#define PXE_ROMID_IMP_SW_VIRT_ADDR 0x40000000 +#define PXE_ROMID_IMP_64BIT_DEVICE 0x00010000 +#define PXE_ROMID_IMP_FRAG_SUPPORTED 0x00008000 +#define PXE_ROMID_IMP_CMD_LINK_SUPPORTED 0x00004000 +#define PXE_ROMID_IMP_CMD_QUEUE_SUPPORTED 0x00002000 +#define PXE_ROMID_IMP_MULTI_FRAME_SUPPORTED 0x00001000 +#define PXE_ROMID_IMP_NVDATA_SUPPORT_MASK 0x00000C00 +#define PXE_ROMID_IMP_NVDATA_BULK_WRITABLE 0x00000C00 +#define PXE_ROMID_IMP_NVDATA_SPARSE_WRITABLE 0x00000800 +#define PXE_ROMID_IMP_NVDATA_READ_ONLY 0x00000400 +#define PXE_ROMID_IMP_NVDATA_NOT_AVAILABLE 0x00000000 +#define PXE_ROMID_IMP_STATISTICS_SUPPORTED 0x00000200 +#define PXE_ROMID_IMP_STATION_ADDR_SETTABLE 0x00000100 +#define PXE_ROMID_IMP_PROMISCUOUS_MULTICAST_RX_SUPPORTED 0x00000080 +#define PXE_ROMID_IMP_PROMISCUOUS_RX_SUPPORTED 0x00000040 +#define PXE_ROMID_IMP_BROADCAST_RX_SUPPORTED 0x00000020 +#define PXE_ROMID_IMP_FILTERED_MULTICAST_RX_SUPPORTED 0x00000010 +#define PXE_ROMID_IMP_SOFTWARE_INT_SUPPORTED 0x00000008 +#define PXE_ROMID_IMP_TX_COMPLETE_INT_SUPPORTED 0x00000004 +#define PXE_ROMID_IMP_PACKET_RX_INT_SUPPORTED 0x00000002 +#define PXE_ROMID_IMP_CMD_COMPLETE_INT_SUPPORTED 0x00000001 + +typedef struct s_pxe_cdb { + PXE_OPCODE OpCode; + PXE_OPFLAGS OpFlags; + PXE_UINT16 CPBsize; + PXE_UINT16 DBsize; + PXE_UINT64 CPBaddr; + PXE_UINT64 DBaddr; + PXE_STATCODE StatCode; + PXE_STATFLAGS StatFlags; + PXE_UINT16 IFnum; + PXE_CONTROL Control; +} PXE_CDB; + +typedef union u_pxe_ip_addr { + PXE_IPV6 IPv6; + PXE_IPV4 IPv4; +} PXE_IP_ADDR; + +typedef union pxe_device { + /// + /// PCI and PC Card NICs are both identified using bus, device + /// and function numbers. For PC Card, this may require PC + /// Card services to be loaded in the BIOS or preboot + /// environment. + /// + struct { + /// + /// See S/W UNDI ROMID structure definition for PCI and + /// PCC BusType definitions. + /// + PXE_UINT32 BusType; + + /// + /// Bus, device & function numbers that locate this device. + /// + PXE_UINT16 Bus; + PXE_UINT8 Device; + PXE_UINT8 Function; + } + PCI, PCC; + +} PXE_DEVICE; + +/// +/// cpb and db definitions +/// +#define MAX_PCI_CONFIG_LEN 64 ///< # of dwords +#define MAX_EEPROM_LEN 128 ///< # of dwords +#define MAX_XMIT_BUFFERS 32 ///< recycling Q length for xmit_done +#define MAX_MCAST_ADDRESS_CNT 8 + +typedef struct s_pxe_cpb_start_30 { + /// + /// PXE_VOID Delay(UINTN microseconds); + /// + /// UNDI will never request a delay smaller than 10 microseconds + /// and will always request delays in increments of 10 microseconds. + /// The Delay() CallBack routine must delay between n and n + 10 + /// microseconds before returning control to the UNDI. + /// + /// This field cannot be set to zero. + /// + UINT64 Delay; + + /// + /// PXE_VOID Block(UINT32 enable); + /// + /// UNDI may need to block multi-threaded/multi-processor access to + /// critical code sections when programming or accessing the network + /// device. To this end, a blocking service is needed by the UNDI. + /// When UNDI needs a block, it will call Block() passing a non-zero + /// value. When UNDI no longer needs a block, it will call Block() + /// with a zero value. When called, if the Block() is already enabled, + /// do not return control to the UNDI until the previous Block() is + /// disabled. + /// + /// This field cannot be set to zero. + /// + UINT64 Block; + + /// + /// PXE_VOID Virt2Phys(UINT64 virtual, UINT64 physical_ptr); + /// + /// UNDI will pass the virtual address of a buffer and the virtual + /// address of a 64-bit physical buffer. Convert the virtual address + /// to a physical address and write the result to the physical address + /// buffer. If virtual and physical addresses are the same, just + /// copy the virtual address to the physical address buffer. + /// + /// This field can be set to zero if virtual and physical addresses + /// are equal. + /// + UINT64 Virt2Phys; + /// + /// PXE_VOID Mem_IO(UINT8 read_write, UINT8 len, UINT64 port, + /// UINT64 buf_addr); + /// + /// UNDI will read or write the device io space using this call back + /// function. It passes the number of bytes as the len parameter and it + /// will be either 1,2,4 or 8. + /// + /// This field can not be set to zero. + /// + UINT64 Mem_IO; +} PXE_CPB_START_30; + +typedef struct s_pxe_cpb_start_31 { + /// + /// PXE_VOID Delay(UINT64 UnqId, UINTN microseconds); + /// + /// UNDI will never request a delay smaller than 10 microseconds + /// and will always request delays in increments of 10 microseconds. + /// The Delay() CallBack routine must delay between n and n + 10 + /// microseconds before returning control to the UNDI. + /// + /// This field cannot be set to zero. + /// + UINT64 Delay; + + /// + /// PXE_VOID Block(UINT64 unq_id, UINT32 enable); + /// + /// UNDI may need to block multi-threaded/multi-processor access to + /// critical code sections when programming or accessing the network + /// device. To this end, a blocking service is needed by the UNDI. + /// When UNDI needs a block, it will call Block() passing a non-zero + /// value. When UNDI no longer needs a block, it will call Block() + /// with a zero value. When called, if the Block() is already enabled, + /// do not return control to the UNDI until the previous Block() is + /// disabled. + /// + /// This field cannot be set to zero. + /// + UINT64 Block; + + /// + /// PXE_VOID Virt2Phys(UINT64 UnqId, UINT64 virtual, UINT64 physical_ptr); + /// + /// UNDI will pass the virtual address of a buffer and the virtual + /// address of a 64-bit physical buffer. Convert the virtual address + /// to a physical address and write the result to the physical address + /// buffer. If virtual and physical addresses are the same, just + /// copy the virtual address to the physical address buffer. + /// + /// This field can be set to zero if virtual and physical addresses + /// are equal. + /// + UINT64 Virt2Phys; + /// + /// PXE_VOID Mem_IO(UINT64 UnqId, UINT8 read_write, UINT8 len, UINT64 port, + /// UINT64 buf_addr); + /// + /// UNDI will read or write the device io space using this call back + /// function. It passes the number of bytes as the len parameter and it + /// will be either 1,2,4 or 8. + /// + /// This field can not be set to zero. + /// + UINT64 Mem_IO; + /// + /// PXE_VOID Map_Mem(UINT64 unq_id, UINT64 virtual_addr, UINT32 size, + /// UINT32 Direction, UINT64 mapped_addr); + /// + /// UNDI will pass the virtual address of a buffer, direction of the data + /// flow from/to the mapped buffer (the constants are defined below) + /// and a place holder (pointer) for the mapped address. + /// This call will Map the given address to a physical DMA address and write + /// the result to the mapped_addr pointer. If there is no need to + /// map the given address to a lower address (i.e. the given address is + /// associated with a physical address that is already compatible to be + /// used with the DMA, it converts the given virtual address to it's + /// physical address and write that in the mapped address pointer. + /// + /// This field can be set to zero if there is no mapping service available + /// + UINT64 Map_Mem; + + /// + /// PXE_VOID UnMap_Mem(UINT64 unq_id, UINT64 virtual_addr, UINT32 size, + /// UINT32 Direction, UINT64 mapped_addr); + /// + /// UNDI will pass the virtual and mapped addresses of a buffer + /// This call will un map the given address + /// + /// This field can be set to zero if there is no unmapping service available + /// + UINT64 UnMap_Mem; + + /// + /// PXE_VOID Sync_Mem(UINT64 unq_id, UINT64 virtual, + /// UINT32 size, UINT32 Direction, UINT64 mapped_addr); + /// + /// UNDI will pass the virtual and mapped addresses of a buffer + /// This call will synchronize the contents of both the virtual and mapped + /// buffers for the given Direction. + /// + /// This field can be set to zero if there is no service available + /// + UINT64 Sync_Mem; + + /// + /// protocol driver can provide anything for this Unique_ID, UNDI remembers + /// that as just a 64bit value assocaited to the interface specified by + /// the ifnum and gives it back as a parameter to all the call-back routines + /// when calling for that interface! + /// + UINT64 Unique_ID; +} PXE_CPB_START_31; + +#define TO_AND_FROM_DEVICE 0 +#define FROM_DEVICE 1 +#define TO_DEVICE 2 + +#define PXE_DELAY_MILLISECOND 1000 +#define PXE_DELAY_SECOND 1000000 +#define PXE_IO_READ 0 +#define PXE_IO_WRITE 1 +#define PXE_MEM_READ 2 +#define PXE_MEM_WRITE 4 + +typedef struct s_pxe_db_get_init_info { + /// + /// Minimum length of locked memory buffer that must be given to + /// the Initialize command. Giving UNDI more memory will generally + /// give better performance. + /// + /// If MemoryRequired is zero, the UNDI does not need and will not + /// use system memory to receive and transmit packets. + /// + PXE_UINT32 MemoryRequired; + + /// + /// Maximum frame data length for Tx/Rx excluding the media header. + /// + PXE_UINT32 FrameDataLen; + + /// + /// Supported link speeds are in units of mega bits. Common ethernet + /// values are 10, 100 and 1000. Unused LinkSpeeds[] entries are zero + /// filled. + /// + PXE_UINT32 LinkSpeeds[4]; + + /// + /// Number of non-volatile storage items. + /// + PXE_UINT32 NvCount; + + /// + /// Width of non-volatile storage item in bytes. 0, 1, 2 or 4 + /// + PXE_UINT16 NvWidth; + + /// + /// Media header length. This is the typical media header length for + /// this UNDI. This information is needed when allocating receive + /// and transmit buffers. + /// + PXE_UINT16 MediaHeaderLen; + + /// + /// Number of bytes in the NIC hardware (MAC) address. + /// + PXE_UINT16 HWaddrLen; + + /// + /// Maximum number of multicast MAC addresses in the multicast + /// MAC address filter list. + /// + PXE_UINT16 MCastFilterCnt; + + /// + /// Default number and size of transmit and receive buffers that will + /// be allocated by the UNDI. If MemoryRequired is non-zero, this + /// allocation will come out of the memory buffer given to the Initialize + /// command. If MemoryRequired is zero, this allocation will come out of + /// memory on the NIC. + /// + PXE_UINT16 TxBufCnt; + PXE_UINT16 TxBufSize; + PXE_UINT16 RxBufCnt; + PXE_UINT16 RxBufSize; + + /// + /// Hardware interface types defined in the Assigned Numbers RFC + /// and used in DHCP and ARP packets. + /// See the PXE_IFTYPE typedef and PXE_IFTYPE_xxx macros. + /// + PXE_UINT8 IFtype; + + /// + /// Supported duplex. See PXE_DUPLEX_xxxxx #defines below. + /// + PXE_UINT8 SupportedDuplexModes; + + /// + /// Supported loopback options. See PXE_LOOPBACK_xxxxx #defines below. + /// + PXE_UINT8 SupportedLoopBackModes; +} PXE_DB_GET_INIT_INFO; + +#define PXE_MAX_TXRX_UNIT_ETHER 1500 + +#define PXE_HWADDR_LEN_ETHER 0x0006 +#define PXE_MAC_HEADER_LEN_ETHER 0x000E + +#define PXE_DUPLEX_ENABLE_FULL_SUPPORTED 1 +#define PXE_DUPLEX_FORCE_FULL_SUPPORTED 2 + +#define PXE_LOOPBACK_INTERNAL_SUPPORTED 1 +#define PXE_LOOPBACK_EXTERNAL_SUPPORTED 2 + +typedef struct s_pxe_pci_config_info { + /// + /// This is the flag field for the PXE_DB_GET_CONFIG_INFO union. + /// For PCI bus devices, this field is set to PXE_BUSTYPE_PCI. + /// + UINT32 BusType; + + /// + /// This identifies the PCI network device that this UNDI interface + /// is bound to. + /// + UINT16 Bus; + UINT8 Device; + UINT8 Function; + + /// + /// This is a copy of the PCI configuration space for this + /// network device. + /// + union { + UINT8 Byte[256]; + UINT16 Word[128]; + UINT32 Dword[64]; + } Config; +} PXE_PCI_CONFIG_INFO; + +typedef struct s_pxe_pcc_config_info { + /// + /// This is the flag field for the PXE_DB_GET_CONFIG_INFO union. + /// For PCC bus devices, this field is set to PXE_BUSTYPE_PCC. + /// + PXE_UINT32 BusType; + + /// + /// This identifies the PCC network device that this UNDI interface + /// is bound to. + /// + PXE_UINT16 Bus; + PXE_UINT8 Device; + PXE_UINT8 Function; + + /// + /// This is a copy of the PCC configuration space for this + /// network device. + /// + union { + PXE_UINT8 Byte[256]; + PXE_UINT16 Word[128]; + PXE_UINT32 Dword[64]; + } Config; +} PXE_PCC_CONFIG_INFO; + +typedef union u_pxe_db_get_config_info { + PXE_PCI_CONFIG_INFO pci; + PXE_PCC_CONFIG_INFO pcc; +} PXE_DB_GET_CONFIG_INFO; + +typedef struct s_pxe_cpb_initialize { + /// + /// Address of first (lowest) byte of the memory buffer. This buffer must + /// be in contiguous physical memory and cannot be swapped out. The UNDI + /// will be using this for transmit and receive buffering. + /// + PXE_UINT64 MemoryAddr; + + /// + /// MemoryLength must be greater than or equal to MemoryRequired + /// returned by the Get Init Info command. + /// + PXE_UINT32 MemoryLength; + + /// + /// Desired link speed in Mbit/sec. Common ethernet values are 10, 100 + /// and 1000. Setting a value of zero will auto-detect and/or use the + /// default link speed (operation depends on UNDI/NIC functionality). + /// + PXE_UINT32 LinkSpeed; + + /// + /// Suggested number and size of receive and transmit buffers to + /// allocate. If MemoryAddr and MemoryLength are non-zero, this + /// allocation comes out of the supplied memory buffer. If MemoryAddr + /// and MemoryLength are zero, this allocation comes out of memory + /// on the NIC. + /// + /// If these fields are set to zero, the UNDI will allocate buffer + /// counts and sizes as it sees fit. + /// + PXE_UINT16 TxBufCnt; + PXE_UINT16 TxBufSize; + PXE_UINT16 RxBufCnt; + PXE_UINT16 RxBufSize; + + /// + /// The following configuration parameters are optional and must be zero + /// to use the default values. + /// + PXE_UINT8 DuplexMode; + + PXE_UINT8 LoopBackMode; +} PXE_CPB_INITIALIZE; + +#define PXE_DUPLEX_DEFAULT 0x00 +#define PXE_FORCE_FULL_DUPLEX 0x01 +#define PXE_ENABLE_FULL_DUPLEX 0x02 +#define PXE_FORCE_HALF_DUPLEX 0x04 +#define PXE_DISABLE_FULL_DUPLEX 0x08 + +#define LOOPBACK_NORMAL 0 +#define LOOPBACK_INTERNAL 1 +#define LOOPBACK_EXTERNAL 2 + +typedef struct s_pxe_db_initialize { + /// + /// Actual amount of memory used from the supplied memory buffer. This + /// may be less that the amount of memory suppllied and may be zero if + /// the UNDI and network device do not use external memory buffers. + /// + /// Memory used by the UNDI and network device is allocated from the + /// lowest memory buffer address. + /// + PXE_UINT32 MemoryUsed; + + /// + /// Actual number and size of receive and transmit buffers that were + /// allocated. + /// + PXE_UINT16 TxBufCnt; + PXE_UINT16 TxBufSize; + PXE_UINT16 RxBufCnt; + PXE_UINT16 RxBufSize; +} PXE_DB_INITIALIZE; + +typedef struct s_pxe_cpb_receive_filters { + /// + /// List of multicast MAC addresses. This list, if present, will + /// replace the existing multicast MAC address filter list. + /// + PXE_MAC_ADDR MCastList[MAX_MCAST_ADDRESS_CNT]; +} PXE_CPB_RECEIVE_FILTERS; + +typedef struct s_pxe_db_receive_filters { + /// + /// Filtered multicast MAC address list. + /// + PXE_MAC_ADDR MCastList[MAX_MCAST_ADDRESS_CNT]; +} PXE_DB_RECEIVE_FILTERS; + +typedef struct s_pxe_cpb_station_address { + /// + /// If supplied and supported, the current station MAC address + /// will be changed. + /// + PXE_MAC_ADDR StationAddr; +} PXE_CPB_STATION_ADDRESS; + +typedef struct s_pxe_dpb_station_address { + /// + /// Current station MAC address. + /// + PXE_MAC_ADDR StationAddr; + + /// + /// Station broadcast MAC address. + /// + PXE_MAC_ADDR BroadcastAddr; + + /// + /// Permanent station MAC address. + /// + PXE_MAC_ADDR PermanentAddr; +} PXE_DB_STATION_ADDRESS; + +typedef struct s_pxe_db_statistics { + /// + /// Bit field identifying what statistic data is collected by the + /// UNDI/NIC. + /// If bit 0x00 is set, Data[0x00] is collected. + /// If bit 0x01 is set, Data[0x01] is collected. + /// If bit 0x20 is set, Data[0x20] is collected. + /// If bit 0x21 is set, Data[0x21] is collected. + /// Etc. + /// + PXE_UINT64 Supported; + + /// + /// Statistic data. + /// + PXE_UINT64 Data[64]; +} PXE_DB_STATISTICS; + +/// +/// Total number of frames received. Includes frames with errors and +/// dropped frames. +/// +#define PXE_STATISTICS_RX_TOTAL_FRAMES 0x00 + +/// +/// Number of valid frames received and copied into receive buffers. +/// +#define PXE_STATISTICS_RX_GOOD_FRAMES 0x01 + +/// +/// Number of frames below the minimum length for the media. +/// This would be <64 for ethernet. +/// +#define PXE_STATISTICS_RX_UNDERSIZE_FRAMES 0x02 + +/// +/// Number of frames longer than the maxminum length for the +/// media. This would be >1500 for ethernet. +/// +#define PXE_STATISTICS_RX_OVERSIZE_FRAMES 0x03 + +/// +/// Valid frames that were dropped because receive buffers were full. +/// +#define PXE_STATISTICS_RX_DROPPED_FRAMES 0x04 + +/// +/// Number of valid unicast frames received and not dropped. +/// +#define PXE_STATISTICS_RX_UNICAST_FRAMES 0x05 + +/// +/// Number of valid broadcast frames received and not dropped. +/// +#define PXE_STATISTICS_RX_BROADCAST_FRAMES 0x06 + +/// +/// Number of valid mutlicast frames received and not dropped. +/// +#define PXE_STATISTICS_RX_MULTICAST_FRAMES 0x07 + +/// +/// Number of frames w/ CRC or alignment errors. +/// +#define PXE_STATISTICS_RX_CRC_ERROR_FRAMES 0x08 + +/// +/// Total number of bytes received. Includes frames with errors +/// and dropped frames. +/// +#define PXE_STATISTICS_RX_TOTAL_BYTES 0x09 + +/// +/// Transmit statistics. +/// +#define PXE_STATISTICS_TX_TOTAL_FRAMES 0x0A +#define PXE_STATISTICS_TX_GOOD_FRAMES 0x0B +#define PXE_STATISTICS_TX_UNDERSIZE_FRAMES 0x0C +#define PXE_STATISTICS_TX_OVERSIZE_FRAMES 0x0D +#define PXE_STATISTICS_TX_DROPPED_FRAMES 0x0E +#define PXE_STATISTICS_TX_UNICAST_FRAMES 0x0F +#define PXE_STATISTICS_TX_BROADCAST_FRAMES 0x10 +#define PXE_STATISTICS_TX_MULTICAST_FRAMES 0x11 +#define PXE_STATISTICS_TX_CRC_ERROR_FRAMES 0x12 +#define PXE_STATISTICS_TX_TOTAL_BYTES 0x13 + +/// +/// Number of collisions detection on this subnet. +/// +#define PXE_STATISTICS_COLLISIONS 0x14 + +/// +/// Number of frames destined for unsupported protocol. +/// +#define PXE_STATISTICS_UNSUPPORTED_PROTOCOL 0x15 + +typedef struct s_pxe_cpb_mcast_ip_to_mac { + /// + /// Multicast IP address to be converted to multicast MAC address. + /// + PXE_IP_ADDR IP; +} PXE_CPB_MCAST_IP_TO_MAC; + +typedef struct s_pxe_db_mcast_ip_to_mac { + /// + /// Multicast MAC address. + /// + PXE_MAC_ADDR MAC; +} PXE_DB_MCAST_IP_TO_MAC; + +typedef struct s_pxe_cpb_nvdata_sparse { + /// + /// NvData item list. Only items in this list will be updated. + /// + struct { + /// + /// Non-volatile storage address to be changed. + /// + PXE_UINT32 Addr; + + /// + /// Data item to write into above storage address. + /// + union { + PXE_UINT8 Byte; + PXE_UINT16 Word; + PXE_UINT32 Dword; + } Data; + } Item[MAX_EEPROM_LEN]; +} PXE_CPB_NVDATA_SPARSE; + +/// +/// When using bulk update, the size of the CPB structure must be +/// the same size as the non-volatile NIC storage. +/// +typedef union u_pxe_cpb_nvdata_bulk { + /// + /// Array of byte-wide data items. + /// + PXE_UINT8 Byte[MAX_EEPROM_LEN << 2]; + + /// + /// Array of word-wide data items. + /// + PXE_UINT16 Word[MAX_EEPROM_LEN << 1]; + + /// + /// Array of dword-wide data items. + /// + PXE_UINT32 Dword[MAX_EEPROM_LEN]; +} PXE_CPB_NVDATA_BULK; + +typedef struct s_pxe_db_nvdata { + /// + /// Arrays of data items from non-volatile storage. + /// + union { + /// + /// Array of byte-wide data items. + /// + PXE_UINT8 Byte[MAX_EEPROM_LEN << 2]; + + /// + /// Array of word-wide data items. + /// + PXE_UINT16 Word[MAX_EEPROM_LEN << 1]; + + /// + /// Array of dword-wide data items. + /// + PXE_UINT32 Dword[MAX_EEPROM_LEN]; + } Data; +} PXE_DB_NVDATA; + +typedef struct s_pxe_db_get_status { + /// + /// Length of next receive frame (header + data). If this is zero, + /// there is no next receive frame available. + /// + PXE_UINT32 RxFrameLen; + + /// + /// Reserved, set to zero. + /// + PXE_UINT32 reserved; + + /// + /// Addresses of transmitted buffers that need to be recycled. + /// + PXE_UINT64 TxBuffer[MAX_XMIT_BUFFERS]; +} PXE_DB_GET_STATUS; + +typedef struct s_pxe_cpb_fill_header { + /// + /// Source and destination MAC addresses. These will be copied into + /// the media header without doing byte swapping. + /// + PXE_MAC_ADDR SrcAddr; + PXE_MAC_ADDR DestAddr; + + /// + /// Address of first byte of media header. The first byte of packet data + /// follows the last byte of the media header. + /// + PXE_UINT64 MediaHeader; + + /// + /// Length of packet data in bytes (not including the media header). + /// + PXE_UINT32 PacketLen; + + /// + /// Protocol type. This will be copied into the media header without + /// doing byte swapping. Protocol type numbers can be obtained from + /// the Assigned Numbers RFC 1700. + /// + PXE_UINT16 Protocol; + + /// + /// Length of the media header in bytes. + /// + PXE_UINT16 MediaHeaderLen; +} PXE_CPB_FILL_HEADER; + +#define PXE_PROTOCOL_ETHERNET_IP 0x0800 +#define PXE_PROTOCOL_ETHERNET_ARP 0x0806 +#define MAX_XMIT_FRAGMENTS 16 + +typedef struct s_pxe_cpb_fill_header_fragmented { + /// + /// Source and destination MAC addresses. These will be copied into + /// the media header without doing byte swapping. + /// + PXE_MAC_ADDR SrcAddr; + PXE_MAC_ADDR DestAddr; + + /// + /// Length of packet data in bytes (not including the media header). + /// + PXE_UINT32 PacketLen; + + /// + /// Protocol type. This will be copied into the media header without + /// doing byte swapping. Protocol type numbers can be obtained from + /// the Assigned Numbers RFC 1700. + /// + PXE_MEDIA_PROTOCOL Protocol; + + /// + /// Length of the media header in bytes. + /// + PXE_UINT16 MediaHeaderLen; + + /// + /// Number of packet fragment descriptors. + /// + PXE_UINT16 FragCnt; + + /// + /// Reserved, must be set to zero. + /// + PXE_UINT16 reserved; + + /// + /// Array of packet fragment descriptors. The first byte of the media + /// header is the first byte of the first fragment. + /// + struct { + /// + /// Address of this packet fragment. + /// + PXE_UINT64 FragAddr; + + /// + /// Length of this packet fragment. + /// + PXE_UINT32 FragLen; + + /// + /// Reserved, must be set to zero. + /// + PXE_UINT32 reserved; + } FragDesc[MAX_XMIT_FRAGMENTS]; +} +PXE_CPB_FILL_HEADER_FRAGMENTED; + +typedef struct s_pxe_cpb_transmit { + /// + /// Address of first byte of frame buffer. This is also the first byte + /// of the media header. + /// + PXE_UINT64 FrameAddr; + + /// + /// Length of the data portion of the frame buffer in bytes. Do not + /// include the length of the media header. + /// + PXE_UINT32 DataLen; + + /// + /// Length of the media header in bytes. + /// + PXE_UINT16 MediaheaderLen; + + /// + /// Reserved, must be zero. + /// + PXE_UINT16 reserved; +} PXE_CPB_TRANSMIT; + +typedef struct s_pxe_cpb_transmit_fragments { + /// + /// Length of packet data in bytes (not including the media header). + /// + PXE_UINT32 FrameLen; + + /// + /// Length of the media header in bytes. + /// + PXE_UINT16 MediaheaderLen; + + /// + /// Number of packet fragment descriptors. + /// + PXE_UINT16 FragCnt; + + /// + /// Array of frame fragment descriptors. The first byte of the first + /// fragment is also the first byte of the media header. + /// + struct { + /// + /// Address of this frame fragment. + /// + PXE_UINT64 FragAddr; + + /// + /// Length of this frame fragment. + /// + PXE_UINT32 FragLen; + + /// + /// Reserved, must be set to zero. + /// + PXE_UINT32 reserved; + } FragDesc[MAX_XMIT_FRAGMENTS]; +} +PXE_CPB_TRANSMIT_FRAGMENTS; + +typedef struct s_pxe_cpb_receive { + /// + /// Address of first byte of receive buffer. This is also the first byte + /// of the frame header. + /// + PXE_UINT64 BufferAddr; + + /// + /// Length of receive buffer. This must be large enough to hold the + /// received frame (media header + data). If the length of smaller than + /// the received frame, data will be lost. + /// + PXE_UINT32 BufferLen; + + /// + /// Reserved, must be set to zero. + /// + PXE_UINT32 reserved; +} PXE_CPB_RECEIVE; + +typedef struct s_pxe_db_receive { + /// + /// Source and destination MAC addresses from media header. + /// + PXE_MAC_ADDR SrcAddr; + PXE_MAC_ADDR DestAddr; + + /// + /// Length of received frame. May be larger than receive buffer size. + /// The receive buffer will not be overwritten. This is how to tell + /// if data was lost because the receive buffer was too small. + /// + PXE_UINT32 FrameLen; + + /// + /// Protocol type from media header. + /// + PXE_MEDIA_PROTOCOL Protocol; + + /// + /// Length of media header in received frame. + /// + PXE_UINT16 MediaHeaderLen; + + /// + /// Type of receive frame. + /// + PXE_FRAME_TYPE Type; + + /// + /// Reserved, must be zero. + /// + PXE_UINT8 reserved[7]; + +} PXE_DB_RECEIVE; + +#pragma pack() + +#endif diff --git a/gpxe/src/include/gpxe/efi/Uefi/UefiSpec.h b/gpxe/src/include/gpxe/efi/Uefi/UefiSpec.h new file mode 100644 index 00000000..03e7b6cc --- /dev/null +++ b/gpxe/src/include/gpxe/efi/Uefi/UefiSpec.h @@ -0,0 +1,1916 @@ +/** @file + Include file that supports UEFI. + + This include file must only contain things defined in the UEFI 2.1 specification. + If a code construct is defined in the UEFI 2.1 specification it must be included + by this include file. + + Copyright (c) 2006 - 2008, Intel Corporation + All rights reserved. This program and the accompanying materials + are licensed and made available under the terms and conditions of the BSD License + which accompanies this distribution. The full text of the license may be found at + http://opensource.org/licenses/bsd-license.php + + THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, + WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + +**/ + +#ifndef __UEFI_SPEC_H__ +#define __UEFI_SPEC_H__ + +#include <gpxe/efi/Uefi/UefiMultiPhase.h> + +#include <gpxe/efi/Protocol/DevicePath.h> +#include <gpxe/efi/Protocol/SimpleTextIn.h> +#include <gpxe/efi/Protocol/SimpleTextOut.h> + +/// +/// Enumeration of memory allocation. +/// +typedef enum { + AllocateAnyPages, + AllocateMaxAddress, + AllocateAddress, + MaxAllocateType +} EFI_ALLOCATE_TYPE; + +// +// Bit definitions for EFI_TIME.Daylight +// +#define EFI_TIME_ADJUST_DAYLIGHT 0x01 +#define EFI_TIME_IN_DAYLIGHT 0x02 + +/// +/// Value definition for EFI_TIME.TimeZone +/// +#define EFI_UNSPECIFIED_TIMEZONE 0x07FF + +// +// Memory cacheability attributes +// +#define EFI_MEMORY_UC 0x0000000000000001ULL +#define EFI_MEMORY_WC 0x0000000000000002ULL +#define EFI_MEMORY_WT 0x0000000000000004ULL +#define EFI_MEMORY_WB 0x0000000000000008ULL +#define EFI_MEMORY_UCE 0x0000000000000010ULL +// +// Physical memory protection attributes +// +#define EFI_MEMORY_WP 0x0000000000001000ULL +#define EFI_MEMORY_RP 0x0000000000002000ULL +#define EFI_MEMORY_XP 0x0000000000004000ULL +// +// Runtime memory attribute +// +#define EFI_MEMORY_RUNTIME 0x8000000000000000ULL + +/// +/// Memory descriptor version number +/// +#define EFI_MEMORY_DESCRIPTOR_VERSION 1 + +/// +/// Definition of memory descriptor +/// +typedef struct { + UINT32 Type; + EFI_PHYSICAL_ADDRESS PhysicalStart; + EFI_VIRTUAL_ADDRESS VirtualStart; + UINT64 NumberOfPages; + UINT64 Attribute; +} EFI_MEMORY_DESCRIPTOR; + +/// +/// Build macros to find next EFI_MEMORY_DESCRIPTOR. +/// +#define NEXT_MEMORY_DESCRIPTOR(_Ptr, _Size) ((EFI_MEMORY_DESCRIPTOR *) (((UINT8 *) (_Ptr)) + (_Size))) + +/// +/// Declare forward referenced data structures +/// +typedef struct _EFI_SYSTEM_TABLE EFI_SYSTEM_TABLE; + +/** + Allocates memory pages from the system. + + @param Type The type of allocation to perform. + @param MemoryType The type of memory to allocate. + @param Pages The number of contiguous 4 KB pages to allocate. + @param Memory Pointer to a physical address. On input, the way in which the address is + used depends on the value of Type. + + @retval EFI_SUCCESS The requested pages were allocated. + @retval EFI_INVALID_PARAMETER 1) Type is not AllocateAnyPages or + AllocateMaxAddress or AllocateAddress. + 2) MemoryType is in the range + EfiMaxMemoryType..0x7FFFFFFF. + @retval EFI_OUT_OF_RESOURCES The pages could not be allocated. + @retval EFI_NOT_FOUND The requested pages could not be found. + +**/ +typedef +EFI_STATUS +(EFIAPI *EFI_ALLOCATE_PAGES)( + IN EFI_ALLOCATE_TYPE Type, + IN EFI_MEMORY_TYPE MemoryType, + IN UINTN Pages, + IN OUT EFI_PHYSICAL_ADDRESS *Memory + ); + +/** + Frees memory pages. + + @param Memory The base physical address of the pages to be freed. + @param Pages The number of contiguous 4 KB pages to free. + + @retval EFI_SUCCESS The requested pages were freed. + @retval EFI_INVALID_PARAMETER Memory is not a page-aligned address or Pages is invalid. + @retval EFI_NOT_FOUND The requested memory pages were not allocated with + AllocatePages(). + +**/ +typedef +EFI_STATUS +(EFIAPI *EFI_FREE_PAGES)( + IN EFI_PHYSICAL_ADDRESS Memory, + IN UINTN Pages + ); + +/** + Returns the current memory map. + + @param MemoryMapSize A pointer to the size, in bytes, of the MemoryMap buffer. + On input, this is the size of the buffer allocated by the caller. + On output, it is the size of the buffer returned by the firmware if + the buffer was large enough, or the size of the buffer needed to contain + the map if the buffer was too small. + @param MemoryMap A pointer to the buffer in which firmware places the current memory + map. + @param MapKey A pointer to the location in which firmware returns the key for the + current memory map. + @param DescriptorSize A pointer to the location in which firmware returns the size, in bytes, of + an individual EFI_MEMORY_DESCRIPTOR. + @param DescriptorVersion A pointer to the location in which firmware returns the version number + associated with the EFI_MEMORY_DESCRIPTOR. + + @retval EFI_SUCCESS The memory map was returned in the MemoryMap buffer. + @retval EFI_BUFFER_TOO_SMALL The MemoryMap buffer was too small. The current buffer size + needed to hold the memory map is returned in MemoryMapSize. + @retval EFI_INVALID_PARAMETER 1) MemoryMapSize is NULL. + 2) The MemoryMap buffer is not too small and MemoryMap is + NULL. + +**/ +typedef +EFI_STATUS +(EFIAPI *EFI_GET_MEMORY_MAP)( + IN OUT UINTN *MemoryMapSize, + IN OUT EFI_MEMORY_DESCRIPTOR *MemoryMap, + OUT UINTN *MapKey, + OUT UINTN *DescriptorSize, + OUT UINT32 *DescriptorVersion + ); + +/** + Allocates pool memory. + + @param PoolType The type of pool to allocate. + @param Size The number of bytes to allocate from the pool. + @param Buffer A pointer to a pointer to the allocated buffer if the call succeeds; + undefined otherwise. + + @retval EFI_SUCCESS The requested number of bytes was allocated. + @retval EFI_OUT_OF_RESOURCES The pool requested could not be allocated. + @retval EFI_INVALID_PARAMETER PoolType was invalid. + +**/ +typedef +EFI_STATUS +(EFIAPI *EFI_ALLOCATE_POOL)( + IN EFI_MEMORY_TYPE PoolType, + IN UINTN Size, + OUT VOID **Buffer + ); + +/** + Returns pool memory to the system. + + @param Buffer Pointer to the buffer to free. + + @retval EFI_SUCCESS The memory was returned to the system. + @retval EFI_INVALID_PARAMETER Buffer was invalid. + +**/ +typedef +EFI_STATUS +(EFIAPI *EFI_FREE_POOL)( + IN VOID *Buffer + ); + +/** + Changes the runtime addressing mode of EFI firmware from physical to virtual. + + @param MemoryMapSize The size in bytes of VirtualMap. + @param DescriptorSize The size in bytes of an entry in the VirtualMap. + @param DescriptorVersion The version of the structure entries in VirtualMap. + @param VirtualMap An array of memory descriptors which contain new virtual + address mapping information for all runtime ranges. + + @retval EFI_SUCCESS The virtual address map has been applied. + @retval EFI_UNSUPPORTED EFI firmware is not at runtime, or the EFI firmware is already in + virtual address mapped mode. + @retval EFI_INVALID_PARAMETER DescriptorSize or DescriptorVersion is invalid. + @retval EFI_NO_MAPPING A virtual address was not supplied for a range in the memory + map that requires a mapping. + @retval EFI_NOT_FOUND A virtual address was supplied for an address that is not found + in the memory map. + +**/ +typedef +EFI_STATUS +(EFIAPI *EFI_SET_VIRTUAL_ADDRESS_MAP)( + IN UINTN MemoryMapSize, + IN UINTN DescriptorSize, + IN UINT32 DescriptorVersion, + IN EFI_MEMORY_DESCRIPTOR *VirtualMap + ); + +/** + Connects one or more drivers to a controller. + + @param ControllerHandle The handle of the controller to which driver(s) are to be connected. + @param DriverImageHandle A pointer to an ordered list handles that support the + EFI_DRIVER_BINDING_PROTOCOL. + @param RemainingDevicePath A pointer to the device path that specifies a child of the + controller specified by ControllerHandle. + @param Recursive If TRUE, then ConnectController() is called recursively + until the entire tree of controllers below the controller specified + by ControllerHandle have been created. If FALSE, then + the tree of controllers is only expanded one level. + + @retval EFI_SUCCESS 1) One or more drivers were connected to ControllerHandle. + 2) No drivers were connected to ControllerHandle, but + RemainingDevicePath is not NULL, and it is an End Device + Path Node. + @retval EFI_INVALID_PARAMETER ControllerHandle is not a valid EFI_HANDLE. + @retval EFI_NOT_FOUND 1) There are no EFI_DRIVER_BINDING_PROTOCOL instances + present in the system. + 2) No drivers were connected to ControllerHandle. + +**/ +typedef +EFI_STATUS +(EFIAPI *EFI_CONNECT_CONTROLLER)( + IN EFI_HANDLE ControllerHandle, + IN EFI_HANDLE *DriverImageHandle, OPTIONAL + IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath, OPTIONAL + IN BOOLEAN Recursive + ); + +/** + Disconnects one or more drivers from a controller. + + @param ControllerHandle The handle of the controller from which driver(s) are to be disconnected. + @param DriverImageHandle The driver to disconnect from ControllerHandle. + If DriverImageHandle is NULL, then all the drivers currently managing + ControllerHandle are disconnected from ControllerHandle. + @param ChildHandle The handle of the child to destroy. + If ChildHandle is NULL, then all the children of ControllerHandle are + destroyed before the drivers are disconnected from ControllerHandle. + + @retval EFI_SUCCESS 1) One or more drivers were disconnected from the controller. + 2) On entry, no drivers are managing ControllerHandle. + 3) DriverImageHandle is not NULL, and on entry + DriverImageHandle is not managing ControllerHandle. + @retval EFI_INVALID_PARAMETER 1) ControllerHandle is not a valid EFI_HANDLE. + 2) DriverImageHandle is not NULL, and it is not a valid EFI_HANDLE. + 3) ChildHandle is not NULL, and it is not a valid EFI_HANDLE. + 4) DriverImageHandle does not support the EFI_DRIVER_BINDING_PROTOCOL. + @retval EFI_OUT_OF_RESOURCES There are not enough resources available to disconnect any drivers from + ControllerHandle. + @retval EFI_DEVICE_ERROR The controller could not be disconnected because of a device error. + +**/ +typedef +EFI_STATUS +(EFIAPI *EFI_DISCONNECT_CONTROLLER)( + IN EFI_HANDLE ControllerHandle, + IN EFI_HANDLE DriverImageHandle, OPTIONAL + IN EFI_HANDLE ChildHandle OPTIONAL + ); + + + +// +// ConvertPointer DebugDisposition type. +// +#define EFI_OPTIONAL_PTR 0x00000001 +#define EFI_OPTIONAL_POINTER EFI_OPTIONAL_PTR + +/** + Determines the new virtual address that is to be used on subsequent memory accesses. + + @param DebugDisposition Supplies type information for the pointer being converted. + @param Address A pointer to a pointer that is to be fixed to be the value needed + for the new virtual address mappings being applied. + + @retval EFI_SUCCESS The pointer pointed to by Address was modified. + @retval EFI_INVALID_PARAMETER 1) Address is NULL. + 2) *Address is NULL and DebugDisposition does + not have the EFI_OPTIONAL_PTR bit set. + @retval EFI_NOT_FOUND The pointer pointed to by Address was not found to be part + of the current memory map. This is normally fatal. + +**/ +typedef +EFI_STATUS +(EFIAPI *EFI_CONVERT_POINTER)( + IN UINTN DebugDisposition, + IN OUT VOID **Address + ); + + +// +// These types can be ORed together as needed - for example, +// EVT_TIMER might be Ored with EVT_NOTIFY_WAIT or +// EVT_NOTIFY_SIGNAL. +// +#define EVT_TIMER 0x80000000 +#define EVT_RUNTIME 0x40000000 +#define EVT_NOTIFY_WAIT 0x00000100 +#define EVT_NOTIFY_SIGNAL 0x00000200 + +#define EVT_SIGNAL_EXIT_BOOT_SERVICES 0x00000201 +#define EVT_SIGNAL_VIRTUAL_ADDRESS_CHANGE 0x60000202 + +// +// The event's NotifyContext pointer points to a runtime memory +// address. +// The event is deprecated in UEFI2.0 and later specifications. +// +#define EVT_RUNTIME_CONTEXT 0x20000000 + + +/** + Invoke a notification event + + @param Event Event whose notification function is being invoked. + @param Context Pointer to the notification function's context, + which is implementation-dependent. + +**/ +typedef +VOID +(EFIAPI *EFI_EVENT_NOTIFY)( + IN EFI_EVENT Event, + IN VOID *Context + ); + +/** + Creates an event. + + @param Type The type of event to create and its mode and attributes. + @param NotifyTpl The task priority level of event notifications, if needed. + @param NotifyFunction Pointer to the event's notification function, if any. + @param NotifyContext Pointer to the notification function's context; corresponds to parameter + Context in the notification function. + @param Event Pointer to the newly created event if the call succeeds; undefined + otherwise. + + @retval EFI_SUCCESS The event structure was created. + @retval EFI_INVALID_PARAMETER One or more parameters are invalid. + @retval EFI_OUT_OF_RESOURCES The event could not be allocated. + +**/ +typedef +EFI_STATUS +(EFIAPI *EFI_CREATE_EVENT)( + IN UINT32 Type, + IN EFI_TPL NotifyTpl, + IN EFI_EVENT_NOTIFY NotifyFunction, + IN VOID *NotifyContext, + OUT EFI_EVENT *Event + ); + +/** + Creates an event in a group. + + @param Type The type of event to create and its mode and attributes. + @param NotifyTpl The task priority level of event notifications,if needed. + @param NotifyFunction Pointer to the event's notification function, if any. + @param NotifyContext Pointer to the notification function's context; corresponds to parameter + Context in the notification function. + @param EventGroup Pointer to the unique identifier of the group to which this event belongs. + If this is NULL, then the function behaves as if the parameters were passed + to CreateEvent. + @param Event Pointer to the newly created event if the call succeeds; undefined + otherwise. + + @retval EFI_SUCCESS The event structure was created. + @retval EFI_INVALID_PARAMETER One or more parameters are invalid. + @retval EFI_OUT_OF_RESOURCES The event could not be allocated. + +**/ +typedef +EFI_STATUS +(EFIAPI *EFI_CREATE_EVENT_EX)( + IN UINT32 Type, + IN EFI_TPL NotifyTpl, + IN EFI_EVENT_NOTIFY NotifyFunction OPTIONAL, + IN CONST VOID *NotifyContext OPTIONAL, + IN CONST EFI_GUID *EventGroup OPTIONAL, + OUT EFI_EVENT *Event + ); + +/// +/// Timer delay types +/// +typedef enum { + TimerCancel, + TimerPeriodic, + TimerRelative +} EFI_TIMER_DELAY; + +/** + Sets the type of timer and the trigger time for a timer event. + + @param Event The timer event that is to be signaled at the specified time. + @param Type The type of time that is specified in TriggerTime. + @param TriggerTime The number of 100ns units until the timer expires. + A TriggerTime of 0 is legal. + If Type is TimerRelative and TriggerTime is 0, then the timer + event will be signaled on the next timer tick. + If Type is TimerPeriodic and TriggerTime is 0, then the timer + event will be signaled on every timer tick. + + @retval EFI_SUCCESS The event has been set to be signaled at the requested time. + @retval EFI_INVALID_PARAMETER Event or Type is not valid. + +**/ +typedef +EFI_STATUS +(EFIAPI *EFI_SET_TIMER)( + IN EFI_EVENT Event, + IN EFI_TIMER_DELAY Type, + IN UINT64 TriggerTime + ); + +/** + Signals an event. + + @param Event The event to signal. + + @retval EFI_SUCCESS The event has been signaled. + +**/ +typedef +EFI_STATUS +(EFIAPI *EFI_SIGNAL_EVENT)( + IN EFI_EVENT Event + ); + +/** + Stops execution until an event is signaled. + + @param NumberOfEvents The number of events in the Event array. + @param Event An array of EFI_EVENT. + @param Index Pointer to the index of the event which satisfied the wait condition. + + @retval EFI_SUCCESS The event indicated by Index was signaled. + @retval EFI_INVALID_PARAMETER 1) NumberOfEvents is 0. + 2) The event indicated by Index is of type + EVT_NOTIFY_SIGNAL. + @retval EFI_UNSUPPORTED The current TPL is not TPL_APPLICATION. + +**/ +typedef +EFI_STATUS +(EFIAPI *EFI_WAIT_FOR_EVENT)( + IN UINTN NumberOfEvents, + IN EFI_EVENT *Event, + OUT UINTN *Index + ); + +/** + Closes an event. + + @param Event The event to close. + + @retval EFI_SUCCESS The event has been closed. + +**/ +typedef +EFI_STATUS +(EFIAPI *EFI_CLOSE_EVENT)( + IN EFI_EVENT Event + ); + +/** + Checks whether an event is in the signaled state. + + @param Event The event to check. + + @retval EFI_SUCCESS The event is in the signaled state. + @retval EFI_NOT_READY The event is not in the signaled state. + @retval EFI_INVALID_PARAMETER Event is of type EVT_NOTIFY_SIGNAL. + +**/ +typedef +EFI_STATUS +(EFIAPI *EFI_CHECK_EVENT)( + IN EFI_EVENT Event + ); + + +// +// Task priority level +// +#define TPL_APPLICATION 4 +#define TPL_CALLBACK 8 +#define TPL_NOTIFY 16 +#define TPL_HIGH_LEVEL 31 + + +/** + Raises a task's priority level and returns its previous level. + + @param NewTpl The new task priority level. + + @return Previous task priority level + +**/ +typedef +EFI_TPL +(EFIAPI *EFI_RAISE_TPL)( + IN EFI_TPL NewTpl + ); + +/** + Restores a task's priority level to its previous value. + + @param OldTpl The previous task priority level to restore. + +**/ +typedef +VOID +(EFIAPI *EFI_RESTORE_TPL)( + IN EFI_TPL OldTpl + ); + +/** + Returns the value of a variable. + + @param VariableName A Null-terminated Unicode string that is the name of the + vendor's variable. + @param VendorGuid A unique identifier for the vendor. + @param Attributes If not NULL, a pointer to the memory location to return the + attributes bitmask for the variable. + @param DataSize On input, the size in bytes of the return Data buffer. + On output the size of data returned in Data. + @param Data The buffer to return the contents of the variable. + + @retval EFI_SUCCESS The function completed successfully. + @retval EFI_NOT_FOUND The variable was not found. + @retval EFI_BUFFER_TOO_SMALL The DataSize is too small for the result. + @retval EFI_INVALID_PARAMETER VariableName is NULL. + @retval EFI_INVALID_PARAMETER VendorGuid is NULL. + @retval EFI_INVALID_PARAMETER DataSize is NULL. + @retval EFI_INVALID_PARAMETER The DataSize is not too small and Data is NULL. + @retval EFI_DEVICE_ERROR The variable could not be retrieved due to a hardware error. + @retval EFI_SECURITY_VIOLATION The variable could not be retrieved due to an authentication failure. + +**/ +typedef +EFI_STATUS +(EFIAPI *EFI_GET_VARIABLE)( + IN CHAR16 *VariableName, + IN EFI_GUID *VendorGuid, + OUT UINT32 *Attributes, OPTIONAL + IN OUT UINTN *DataSize, + OUT VOID *Data + ); + +/** + Enumerates the current variable names. + + @param VariableNameSize The size of the VariableName buffer. + @param VariableName On input, supplies the last VariableName that was returned + by GetNextVariableName(). On output, returns the Nullterminated + Unicode string of the current variable. + @param VendorGuid On input, supplies the last VendorGuid that was returned by + GetNextVariableName(). On output, returns the + VendorGuid of the current variable. + + @retval EFI_SUCCESS The function completed successfully. + @retval EFI_NOT_FOUND The next variable was not found. + @retval EFI_BUFFER_TOO_SMALL The VariableNameSize is too small for the result. + @retval EFI_INVALID_PARAMETER VariableNameSize is NULL. + @retval EFI_INVALID_PARAMETER VariableName is NULL. + @retval EFI_INVALID_PARAMETER VendorGuid is NULL. + @retval EFI_DEVICE_ERROR The variable could not be retrieved due to a hardware error. + +**/ +typedef +EFI_STATUS +(EFIAPI *EFI_GET_NEXT_VARIABLE_NAME)( + IN OUT UINTN *VariableNameSize, + IN OUT CHAR16 *VariableName, + IN OUT EFI_GUID *VendorGuid + ); + +/** + Sets the value of a variable. + + @param VariableName A Null-terminated Unicode string that is the name of the + vendor's variable. + @param VendorGuid A unique identifier for the vendor. + @param Attributes Attributes bitmask to set for the variable. + @param DataSize The size in bytes of the Data buffer. + @param Data The contents for the variable. + + @retval EFI_SUCCESS The firmware has successfully stored the variable and its data as + defined by the Attributes. + @retval EFI_INVALID_PARAMETER An invalid combination of attribute bits was supplied, or the + DataSize exceeds the maximum allowed. + @retval EFI_INVALID_PARAMETER VariableName is an empty Unicode string. + @retval EFI_OUT_OF_RESOURCES Not enough storage is available to hold the variable and its data. + @retval EFI_DEVICE_ERROR The variable could not be retrieved due to a hardware error. + @retval EFI_WRITE_PROTECTED The variable in question is read-only. + @retval EFI_WRITE_PROTECTED The variable in question cannot be deleted. + @retval EFI_SECURITY_VIOLATION The variable could not be retrieved due to an authentication failure. + @retval EFI_NOT_FOUND The variable trying to be updated or deleted was not found. + +**/ +typedef +EFI_STATUS +(EFIAPI *EFI_SET_VARIABLE)( + IN CHAR16 *VariableName, + IN EFI_GUID *VendorGuid, + IN UINT32 Attributes, + IN UINTN DataSize, + IN VOID *Data + ); + + +/// +/// This provides the capabilities of the +/// real time clock device as exposed through the EFI interfaces. +/// +typedef struct { + UINT32 Resolution; + UINT32 Accuracy; + BOOLEAN SetsToZero; +} EFI_TIME_CAPABILITIES; + +/** + Returns the current time and date information, and the time-keeping capabilities + of the hardware platform. + + @param Time A pointer to storage to receive a snapshot of the current time. + @param Capabilities An optional pointer to a buffer to receive the real time clock + device's capabilities. + + @retval EFI_SUCCESS The operation completed successfully. + @retval EFI_INVALID_PARAMETER Time is NULL. + @retval EFI_DEVICE_ERROR The time could not be retrieved due to hardware error. + +**/ +typedef +EFI_STATUS +(EFIAPI *EFI_GET_TIME)( + OUT EFI_TIME *Time, + OUT EFI_TIME_CAPABILITIES *Capabilities OPTIONAL + ); + +/** + Sets the current local time and date information. + + @param Time A pointer to the current time. + + @retval EFI_SUCCESS The operation completed successfully. + @retval EFI_INVALID_PARAMETER A time field is out of range. + @retval EFI_DEVICE_ERROR The time could not be set due due to hardware error. + +**/ +typedef +EFI_STATUS +(EFIAPI *EFI_SET_TIME)( + IN EFI_TIME *Time + ); + +/** + Returns the current wakeup alarm clock setting. + + @param Enabled Indicates if the alarm is currently enabled or disabled. + @param Pending Indicates if the alarm signal is pending and requires acknowledgement. + @param Time The current alarm setting. + + @retval EFI_SUCCESS The alarm settings were returned. + @retval EFI_INVALID_PARAMETER Enabled is NULL. + @retval EFI_INVALID_PARAMETER Pending is NULL. + @retval EFI_INVALID_PARAMETER Time is NULL. + @retval EFI_DEVICE_ERROR The wakeup time could not be retrieved due to a hardware error. + @retval EFI_UNSUPPORTED A wakeup timer is not supported on this platform. + +**/ +typedef +EFI_STATUS +(EFIAPI *EFI_GET_WAKEUP_TIME)( + OUT BOOLEAN *Enabled, + OUT BOOLEAN *Pending, + OUT EFI_TIME *Time + ); + +/** + Sets the system wakeup alarm clock time. + + @param Enabled Enable or disable the wakeup alarm. + @param Time If Enable is TRUE, the time to set the wakeup alarm for. + If Enable is FALSE, then this parameter is optional, and may be NULL. + + @retval EFI_SUCCESS If Enable is TRUE, then the wakeup alarm was enabled. If + Enable is FALSE, then the wakeup alarm was disabled. + @retval EFI_INVALID_PARAMETER A time field is out of range. + @retval EFI_DEVICE_ERROR The wakeup time could not be set due to a hardware error. + @retval EFI_UNSUPPORTED A wakeup timer is not supported on this platform. + +**/ +typedef +EFI_STATUS +(EFIAPI *EFI_SET_WAKEUP_TIME)( + IN BOOLEAN Enable, + IN EFI_TIME *Time OPTIONAL + ); + +/** + This is the declaration of an EFI image entry point. This entry point is + the same for UEFI Applications, UEFI OS Loaders, and UEFI Drivers including + both device drivers and bus drivers. + + @param ImageHandle The firmware allocated handle for the UEFI image. + @param SystemTable A pointer to the EFI System Table. + + @retval EFI_SUCCESS The operation completed successfully. + @retval EFI_OUT_OF_RESOURCES The request could not be completed due to a lack of resources. + +**/ +typedef +EFI_STATUS +(EFIAPI *EFI_IMAGE_ENTRY_POINT)( + IN EFI_HANDLE ImageHandle, + IN EFI_SYSTEM_TABLE *SystemTable + ); + +/** + Loads an EFI image into memory. + + @param BootPolicy If TRUE, indicates that the request originates from the boot + manager, and that the boot manager is attempting to load + FilePath as a boot selection. Ignored if SourceBuffer is + not NULL. + @param ParentImageHandle The caller's image handle. + @param DevicePath The DeviceHandle specific file path from which the image is + loaded. + @param SourceBuffer If not NULL, a pointer to the memory location containing a copy + of the image to be loaded. + @param SourceSize The size in bytes of SourceBuffer. Ignored if SourceBuffer is NULL. + @param ImageHandle Pointer to the returned image handle that is created when the + image is successfully loaded. + + @retval EFI_SUCCESS Image was loaded into memory correctly. + @retval EFI_NOT_FOUND Both SourceBuffer and DevicePath are NULL. + @retval EFI_INVALID_PARAMETER One or more parametes are invalid. + @retval EFI_UNSUPPORTED The image type is not supported. + @retval EFI_OUT_OF_RESOURCES Image was not loaded due to insufficient resources. + @retval EFI_LOAD_ERROR Image was not loaded because the image format was corrupt or not + understood. + @retval EFI_DEVICE_ERROR Image was not loaded because the device returned a read error. + +**/ +typedef +EFI_STATUS +(EFIAPI *EFI_IMAGE_LOAD)( + IN BOOLEAN BootPolicy, + IN EFI_HANDLE ParentImageHandle, + IN EFI_DEVICE_PATH_PROTOCOL *DevicePath, + IN VOID *SourceBuffer OPTIONAL, + IN UINTN SourceSize, + OUT EFI_HANDLE *ImageHandle + ); + +/** + Transfers control to a loaded image's entry point. + + @param ImageHandle Handle of image to be started. + @param ExitDataSize Pointer to the size, in bytes, of ExitData. + @param ExitData Pointer to a pointer to a data buffer that includes a Null-terminated + Unicode 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 + @return Exit code from image + +**/ +typedef +EFI_STATUS +(EFIAPI *EFI_IMAGE_START)( + IN EFI_HANDLE ImageHandle, + OUT UINTN *ExitDataSize, + OUT CHAR16 **ExitData OPTIONAL + ); + +/** + Terminates a loaded EFI image and returns control to boot services. + + @param ImageHandle Handle that identifies the image. + @param ExitStatus The image's exit code. + @param ExitDataSize The size, in bytes, of ExitData. + @param ExitData Pointer to a data buffer that includes a Null-terminated Unicode string, + optionally followed by additional binary data. + + @retval EFI_SUCCESS The image specified by ImageHandle was unloaded. + @retval EFI_INVALID_PARAMETER The image specified by ImageHandle has been loaded and + started with LoadImage() and StartImage(), but the + image is not the currently executing image. + +**/ +typedef +EFI_STATUS +(EFIAPI *EFI_EXIT)( + IN EFI_HANDLE ImageHandle, + IN EFI_STATUS ExitStatus, + IN UINTN ExitDataSize, + IN CHAR16 *ExitData OPTIONAL + ); + +/** + Unloads an image. + + @param ImageHandle Handle that identifies the image to be unloaded. + + @retval EFI_SUCCESS The image has been unloaded. + @retval EFI_INVALID_PARAMETER ImageHandle is not a valid image handle. + @retval EFI_UNSUPPORTED The image has been started, and does not support unload. + @return Exit code from the image's unload handler + +**/ +typedef +EFI_STATUS +(EFIAPI *EFI_IMAGE_UNLOAD)( + IN EFI_HANDLE ImageHandle + ); + +/** + Terminates all boot services. + + @param ImageHandle Handle that identifies the exiting image. + @param MapKey Key to the latest memory map. + + @retval EFI_SUCCESS Boot services have been terminated. + @retval EFI_INVALID_PARAMETER MapKey is incorrect. + +**/ +typedef +EFI_STATUS +(EFIAPI *EFI_EXIT_BOOT_SERVICES)( + IN EFI_HANDLE ImageHandle, + IN UINTN MapKey + ); + +/** + Induces a fine-grained stall. + + @param Microseconds The number of microseconds to stall execution. + + @retval EFI_SUCCESS Execution was stalled at least the requested number of + Microseconds. + +**/ +typedef +EFI_STATUS +(EFIAPI *EFI_STALL)( + IN UINTN Microseconds + ); + +/** + Sets the system's watchdog timer. + + @param Timeout The number of seconds to set the watchdog timer to. + @param WatchdogCode The numeric code to log on a watchdog timer timeout event. + @param DataSize The size, in bytes, of WatchdogData. + @param WatchdogData A data buffer that includes a Null-terminated Unicode string, optionally + followed by additional binary data. + + @retval EFI_SUCCESS The timeout has been set. + @retval EFI_INVALID_PARAMETER The supplied WatchdogCode is invalid. + @retval EFI_UNSUPPORTED The system does not have a watchdog timer. + @retval EFI_DEVICE_ERROR The watch dog timer could not be programmed due to a hardware + error. + +**/ +typedef +EFI_STATUS +(EFIAPI *EFI_SET_WATCHDOG_TIMER)( + IN UINTN Timeout, + IN UINT64 WatchdogCode, + IN UINTN DataSize, + IN CHAR16 *WatchdogData OPTIONAL + ); + +/// +/// Enumeration of reset types. +/// +typedef enum { + EfiResetCold, + EfiResetWarm, + EfiResetShutdown, + EfiResetUpdate +} EFI_RESET_TYPE; + +/** + Resets the entire platform. + + @param ResetType The type of reset to perform. + @param ResetStatus The status code for the reset. + @param DataSize The size, in bytes, of WatchdogData. + @param ResetData For a ResetType of EfiResetCold, EfiResetWarm, or + EfiResetShutdown the data buffer starts with a Null-terminated + Unicode string, optionally followed by additional binary data. + +**/ +typedef +VOID +(EFIAPI *EFI_RESET_SYSTEM)( + IN EFI_RESET_TYPE ResetType, + IN EFI_STATUS ResetStatus, + IN UINTN DataSize, + IN CHAR16 *ResetData OPTIONAL + ); + +/** + Returns a monotonically increasing count for the platform. + + @param Count Pointer to returned value. + + @retval EFI_SUCCESS The next monotonic count was returned. + @retval EFI_INVALID_PARAMETER Count is NULL. + @retval EFI_DEVICE_ERROR The device is not functioning properly. + +**/ +typedef +EFI_STATUS +(EFIAPI *EFI_GET_NEXT_MONOTONIC_COUNT)( + OUT UINT64 *Count + ); + +/** + Returns the next high 32 bits of the platform's monotonic counter. + + @param HighCount Pointer to returned value. + + @retval EFI_SUCCESS The next high monotonic count was returned. + @retval EFI_INVALID_PARAMETER HighCount is NULL. + @retval EFI_DEVICE_ERROR The device is not functioning properly. + +**/ +typedef +EFI_STATUS +(EFIAPI *EFI_GET_NEXT_HIGH_MONO_COUNT)( + OUT UINT32 *HighCount + ); + +/** + Computes and returns a 32-bit CRC for a data buffer. + + @param Data A pointer to the buffer on which the 32-bit CRC is to be computed. + @param DataSize The number of bytes in the buffer Data. + @param Crc32 The 32-bit CRC that was computed for the data buffer specified by Data + and DataSize. + + @retval EFI_SUCCESS The 32-bit CRC was computed for the data buffer and returned in + Crc32. + @retval EFI_INVALID_PARAMETER Data is NULL. + @retval EFI_INVALID_PARAMETER Crc32 is NULL. + @retval EFI_INVALID_PARAMETER DataSize is 0. + +**/ +typedef +EFI_STATUS +(EFIAPI *EFI_CALCULATE_CRC32)( + IN VOID *Data, + IN UINTN DataSize, + OUT UINT32 *Crc32 + ); + +/** + Copies the contents of one buffer to another buffer. + + @param Destination Pointer to the destination buffer of the memory copy. + @param Source Pointer to the source buffer of the memory copy. + @param Length Number of bytes to copy from Source to Destination. + +**/ +typedef +VOID +(EFIAPI *EFI_COPY_MEM)( + IN VOID *Destination, + IN VOID *Source, + IN UINTN Length + ); + +/** + The SetMem() function fills a buffer with a specified value. + + @param Buffer Pointer to the buffer to fill. + @param Size Number of bytes in Buffer to fill. + @param Value Value to fill Buffer with. + +**/ +typedef +VOID +(EFIAPI *EFI_SET_MEM)( + IN VOID *Buffer, + IN UINTN Size, + IN UINT8 Value + ); + + +// +// Protocol handler functions +// +typedef enum { + EFI_NATIVE_INTERFACE +} EFI_INTERFACE_TYPE; + +/** + Installs a protocol interface on a device handle. If the handle does not exist, it is created and added + to the list of handles in the system. InstallMultipleProtocolInterfaces() performs + more error checking than InstallProtocolInterface(), so it is recommended that + InstallMultipleProtocolInterfaces() be used in place of + InstallProtocolInterface() + + @param Handle A pointer to the EFI_HANDLE on which the interface is to be installed. + @param Protocol The numeric ID of the protocol interface. + @param InterfaceType Indicates whether Interface is supplied in native form. + @param Interface A pointer to the protocol interface. + + @retval EFI_SUCCESS The protocol interface was installed. + @retval EFI_OUT_OF_RESOURCES Space for a new handle could not be allocated. + @retval EFI_INVALID_PARAMETER Handle is NULL. + @retval EFI_INVALID_PARAMETER Protocol is NULL. + @retval EFI_INVALID_PARAMETER InterfaceType is not EFI_NATIVE_INTERFACE. + @retval EFI_INVALID_PARAMETER Protocol is already installed on the handle specified by Handle. + +**/ +typedef +EFI_STATUS +(EFIAPI *EFI_INSTALL_PROTOCOL_INTERFACE)( + IN OUT EFI_HANDLE *Handle, + IN EFI_GUID *Protocol, + IN EFI_INTERFACE_TYPE InterfaceType, + IN VOID *Interface + ); + +/** + 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 ... A variable argument list containing pairs of protocol GUIDs and protocol + interfaces. + + @retval EFI_SUCCESS All the protocol interface was installed. + @retval EFI_OUT_OF_RESOURCES There was not enough memory in pool to install all the protocols. + @retval EFI_ALREADY_STARTED A Device Path Protocol instance was passed in that is already present in + the handle database. + +**/ +typedef +EFI_STATUS +(EFIAPI *EFI_INSTALL_MULTIPLE_PROTOCOL_INTERFACES)( + IN OUT EFI_HANDLE *Handle, + ... + ); + +/** + Reinstalls a protocol interface on a device handle. + + @param Handle Handle on which the interface is to be reinstalled. + @param Protocol The numeric ID of the interface. + @param OldInterface A pointer to the old interface. NULL can be used if a structure is not + associated with Protocol. + @param NewInterface A pointer to the new interface. + + @retval EFI_SUCCESS The protocol interface was reinstalled. + @retval EFI_NOT_FOUND The OldInterface on the handle was not found. + @retval EFI_ACCESS_DENIED The protocol interface could not be reinstalled, + because OldInterface is still being used by a + driver that will not release it. + @retval EFI_INVALID_PARAMETER Handle is not a valid EFI_HANDLE. + @retval EFI_INVALID_PARAMETER Protocol is NULL. + +**/ +typedef +EFI_STATUS +(EFIAPI *EFI_REINSTALL_PROTOCOL_INTERFACE)( + IN EFI_HANDLE Handle, + IN EFI_GUID *Protocol, + IN VOID *OldInterface, + IN VOID *NewInterface + ); + +/** + Removes a protocol interface from a device handle. It is recommended that + UninstallMultipleProtocolInterfaces() be used in place of + UninstallProtocolInterface(). + + @param Handle The handle on which the interface was installed. + @param Protocol The numeric ID of the interface. + @param Interface A pointer to the interface. + + @retval EFI_SUCCESS The interface was removed. + @retval EFI_NOT_FOUND The interface was not found. + @retval EFI_ACCESS_DENIED The interface was not removed because the interface + is still being used by a driver. + @retval EFI_INVALID_PARAMETER Handle is not a valid EFI_HANDLE. + @retval EFI_INVALID_PARAMETER Protocol is NULL. + +**/ +typedef +EFI_STATUS +(EFIAPI *EFI_UNINSTALL_PROTOCOL_INTERFACE)( + IN EFI_HANDLE Handle, + IN EFI_GUID *Protocol, + IN VOID *Interface + ); + +/** + Removes one or more protocol interfaces into the boot services environment. + + @param Handle The handle to remove the protocol interfaces from. + @param ... A variable argument list containing pairs of protocol GUIDs and + protocol interfaces. + + @retval EFI_SUCCESS All the protocol interfaces were removed. + @retval EFI_INVALID_PARAMETER One of the protocol interfaces was not previously installed on Handle. + +**/ +typedef +EFI_STATUS +(EFIAPI *EFI_UNINSTALL_MULTIPLE_PROTOCOL_INTERFACES)( + IN EFI_HANDLE Handle, + ... + ); + +/** + Queries a handle to determine if it supports a specified protocol. + + @param Handle The handle being queried. + @param Protocol The published unique identifier of the protocol. + @param Interface Supplies the address where a pointer to the corresponding Protocol + Interface is returned. + + @retval EFI_SUCCESS The interface information for the specified protocol was returned. + @retval EFI_UNSUPPORTED The device does not support the specified protocol. + @retval EFI_INVALID_PARAMETER Handle is not a valid EFI_HANDLE. + @retval EFI_INVALID_PARAMETER Protocol is NULL. + @retval EFI_INVALID_PARAMETER Interface is NULL. + +**/ +typedef +EFI_STATUS +(EFIAPI *EFI_HANDLE_PROTOCOL)( + IN EFI_HANDLE Handle, + IN EFI_GUID *Protocol, + OUT VOID **Interface + ); + +#define EFI_OPEN_PROTOCOL_BY_HANDLE_PROTOCOL 0x00000001 +#define EFI_OPEN_PROTOCOL_GET_PROTOCOL 0x00000002 +#define EFI_OPEN_PROTOCOL_TEST_PROTOCOL 0x00000004 +#define EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER 0x00000008 +#define EFI_OPEN_PROTOCOL_BY_DRIVER 0x00000010 +#define EFI_OPEN_PROTOCOL_EXCLUSIVE 0x00000020 + +/** + Queries a handle to determine if it supports a specified protocol. If the protocol is supported by the + handle, it opens the protocol on behalf of the calling agent. + + @param Handle The handle for the protocol interface that is being opened. + @param Protocol The published unique identifier of the protocol. + @param Interface Supplies the address where a pointer to the corresponding Protocol + Interface is returned. + @param AgentHandle The handle of the agent that is opening the protocol interface + specified by Protocol and Interface. + @param ControllerHandle If the agent that is opening a protocol is a driver that follows the + UEFI Driver Model, then this parameter is the controller handle + that requires the protocol interface. If the agent does not follow + the UEFI Driver Model, then this parameter is optional and may + be NULL. + @param Attributes The open mode of the protocol interface specified by Handle + and Protocol. + + @retval EFI_SUCCESS An item was added to the open list for the protocol interface, and the + protocol interface was returned in Interface. + @retval EFI_UNSUPPORTED Handle does not support Protocol. + @retval EFI_INVALID_PARAMETER One or more parameters are invalid. + @retval EFI_ACCESS_DENIED Required attributes can't be supported in current environment. + @retval EFI_ALREADY_STARTED Item on the open list already has requierd attributes whose agent + handle is the same as AgentHandle. + +**/ +typedef +EFI_STATUS +(EFIAPI *EFI_OPEN_PROTOCOL)( + IN EFI_HANDLE Handle, + IN EFI_GUID *Protocol, + OUT VOID **Interface, OPTIONAL + IN EFI_HANDLE AgentHandle, + IN EFI_HANDLE ControllerHandle, + IN UINT32 Attributes + ); + + +/** + Closes a protocol on a handle that was opened using OpenProtocol(). + + @param Handle The handle for the protocol interface that was previously opened + with OpenProtocol(), and is now being closed. + @param Protocol The published unique identifier of the protocol. + @param AgentHandle The handle of the agent that is closing the protocol interface. + @param ControllerHandle If the agent that opened a protocol is a driver that follows the + UEFI Driver Model, then this parameter is the controller handle + that required the protocol interface. + + @retval EFI_SUCCESS The protocol instance was closed. + @retval EFI_INVALID_PARAMETER 1) Handle is not a valid EFI_HANDLE. + 2) AgentHandle is not a valid EFI_HANDLE. + 3) ControllerHandle is not NULL and ControllerHandle is not a valid EFI_HANDLE. + 4) Protocol is NULL. + @retval EFI_NOT_FOUND 1) Handle does not support the protocol specified by Protocol. + 2) The protocol interface specified by Handle and Protocol is not + currently open by AgentHandle and ControllerHandle. + +**/ +typedef +EFI_STATUS +(EFIAPI *EFI_CLOSE_PROTOCOL)( + IN EFI_HANDLE Handle, + IN EFI_GUID *Protocol, + IN EFI_HANDLE AgentHandle, + IN EFI_HANDLE ControllerHandle + ); + + +typedef struct { + EFI_HANDLE AgentHandle; + EFI_HANDLE ControllerHandle; + UINT32 Attributes; + UINT32 OpenCount; +} EFI_OPEN_PROTOCOL_INFORMATION_ENTRY; + +/** + Retrieves the list of agents that currently have a protocol interface opened. + + @param Handle The handle for the protocol interface that is being queried. + @param Protocol The published unique identifier of the protocol. + @param EntryBuffer A pointer to a buffer of open protocol information in the form of + EFI_OPEN_PROTOCOL_INFORMATION_ENTRY structures. + @param EntryCount A pointer to the number of entries in EntryBuffer. + + @retval EFI_SUCCESS The open protocol information was returned in EntryBuffer, and the + number of entries was returned EntryCount. + @retval EFI_OUT_OF_RESOURCES There are not enough resources available to allocate EntryBuffer. + @retval EFI_NOT_FOUND Handle does not support the protocol specified by Protocol. + +**/ +typedef +EFI_STATUS +(EFIAPI *EFI_OPEN_PROTOCOL_INFORMATION)( + IN EFI_HANDLE Handle, + IN EFI_GUID *Protocol, + OUT EFI_OPEN_PROTOCOL_INFORMATION_ENTRY **EntryBuffer, + OUT UINTN *EntryCount + ); + +/** + Retrieves the list of protocol interface GUIDs that are installed on a handle in a buffer allocated + from pool. + + @param Handle The handle from which to retrieve the list of protocol interface + GUIDs. + @param ProtocolBuffer A pointer to the list of protocol interface GUID pointers that are + installed on Handle. + @param ProtocolBufferCount A pointer to the number of GUID pointers present in + ProtocolBuffer. + + @retval EFI_SUCCESS The list of protocol interface GUIDs installed on Handle was returned in + ProtocolBuffer. The number of protocol interface GUIDs was + returned in ProtocolBufferCount. + @retval EFI_OUT_OF_RESOURCES There is not enough pool memory to store the results. + @retval EFI_INVALID_PARAMETER Handle is NULL. + @retval EFI_INVALID_PARAMETER Handle is not a valid EFI_HANDLE. + @retval EFI_INVALID_PARAMETER ProtocolBuffer is NULL. + @retval EFI_INVALID_PARAMETER ProtocolBufferCount is NULL. + +**/ +typedef +EFI_STATUS +(EFIAPI *EFI_PROTOCOLS_PER_HANDLE)( + IN EFI_HANDLE Handle, + OUT EFI_GUID ***ProtocolBuffer, + OUT UINTN *ProtocolBufferCount + ); + +/** + Creates an event that is to be signaled whenever an interface is installed for a specified protocol. + + @param Protocol The numeric ID of the protocol for which the event is to be registered. + @param Event Event that is to be signaled whenever a protocol interface is registered + for Protocol. + @param Registration A pointer to a memory location to receive the registration value. + + @retval EFI_SUCCESS The notification event has been registered. + @retval EFI_OUT_OF_RESOURCES Space for the notification event could not be allocated. + @retval EFI_INVALID_PARAMETER Protocol is NULL. + @retval EFI_INVALID_PARAMETER Event is NULL. + @retval EFI_INVALID_PARAMETER Registration is NULL. + +**/ +typedef +EFI_STATUS +(EFIAPI *EFI_REGISTER_PROTOCOL_NOTIFY)( + IN EFI_GUID *Protocol, + IN EFI_EVENT Event, + OUT VOID **Registration + ); + + +typedef enum { + AllHandles, + ByRegisterNotify, + ByProtocol +} EFI_LOCATE_SEARCH_TYPE; + +/** + Returns an array of handles that support a specified protocol. + + @param SearchType Specifies which handle(s) are to be returned. + @param Protocol Specifies the protocol to search by. + @param SearchKey Specifies the search key. + @param BufferSize On input, the size in bytes of Buffer. On output, the size in bytes of + the array returned in Buffer (if the buffer was large enough) or the + size, in bytes, of the buffer needed to obtain the array (if the buffer was + not large enough). + @param Buffer The buffer in which the array is returned. + + @retval EFI_SUCCESS The array of handles was returned. + @retval EFI_NOT_FOUND No handles match the search. + @retval EFI_BUFFER_TOO_SMALL The BufferSize is too small for the result. + @retval EFI_INVALID_PARAMETER SearchType is not a member of EFI_LOCATE_SEARCH_TYPE. + @retval EFI_INVALID_PARAMETER SearchType is ByRegisterNotify and SearchKey is NULL. + @retval EFI_INVALID_PARAMETER SearchType is ByProtocol and Protocol is NULL. + @retval EFI_INVALID_PARAMETER One or more matches are found and BufferSize is NULL. + @retval EFI_INVALID_PARAMETER BufferSize is large enough for the result and Buffer is NULL. + +**/ +typedef +EFI_STATUS +(EFIAPI *EFI_LOCATE_HANDLE)( + IN EFI_LOCATE_SEARCH_TYPE SearchType, + IN EFI_GUID *Protocol, OPTIONAL + IN VOID *SearchKey, OPTIONAL + IN OUT UINTN *BufferSize, + OUT EFI_HANDLE *Buffer + ); + +/** + Locates the handle to a device on the device path that supports the specified protocol. + + @param Protocol Specifies the protocol to search for. + @param DevicePath On input, a pointer to a pointer to the device path. On output, the device + path pointer is modified to point to the remaining part of the device + path. + @param Device A pointer to the returned device handle. + + @retval EFI_SUCCESS The resulting handle was returned. + @retval EFI_NOT_FOUND No handles match the search. + @retval EFI_INVALID_PARAMETER Protocol is NULL. + @retval EFI_INVALID_PARAMETER DevicePath is NULL. + @retval EFI_INVALID_PARAMETER A handle matched the search and Device is NULL. + +**/ +typedef +EFI_STATUS +(EFIAPI *EFI_LOCATE_DEVICE_PATH)( + IN EFI_GUID *Protocol, + IN OUT EFI_DEVICE_PATH_PROTOCOL **DevicePath, + OUT EFI_HANDLE *Device + ); + +/** + Adds, updates, or removes a configuration table entry from the EFI System Table. + + @param Guid A pointer to the GUID for the entry to add, update, or remove. + @param Table A pointer to the configuration table for the entry to add, update, or + remove. May be NULL. + + @retval EFI_SUCCESS The (Guid, Table) pair was added, updated, or removed. + @retval EFI_NOT_FOUND An attempt was made to delete a nonexistent entry. + @retval EFI_INVALID_PARAMETER Guid is not valid. + @retval EFI_OUT_OF_RESOURCES There is not enough memory available to complete the operation. + +**/ +typedef +EFI_STATUS +(EFIAPI *EFI_INSTALL_CONFIGURATION_TABLE)( + IN EFI_GUID *Guid, + IN VOID *Table + ); + + +/** + Returns an array of handles that support the requested protocol in a buffer allocated from pool. + + @param SearchType Specifies which handle(s) are to be returned. + @param Protocol Provides the protocol to search by. + This parameter is only valid for a SearchType of ByProtocol. + @param SearchKey Supplies the search key depending on the SearchType. + @param NoHandles The number of handles returned in Buffer. + @param Buffer A pointer to the buffer to return the requested array of handles that + support Protocol. + + @retval EFI_SUCCESS The array of handles was returned in Buffer, and the number of + handles in Buffer was returned in NoHandles. + @retval EFI_NOT_FOUND No handles match the search. + @retval EFI_OUT_OF_RESOURCES There is not enough pool memory to store the matching results. + @retval EFI_INVALID_PARAMETER NoHandles is NULL. + @retval EFI_INVALID_PARAMETER Buffer is NULL. + +**/ +typedef +EFI_STATUS +(EFIAPI *EFI_LOCATE_HANDLE_BUFFER)( + IN EFI_LOCATE_SEARCH_TYPE SearchType, + IN EFI_GUID *Protocol, OPTIONAL + IN VOID *SearchKey, OPTIONAL + IN OUT UINTN *NoHandles, + OUT EFI_HANDLE **Buffer + ); + +/** + Returns the first protocol instance that matches the given protocol. + + @param Protocol Provides the protocol to search for. + @param Registration Optional registration key returned from + RegisterProtocolNotify(). + @param Interface On return, a pointer to the first interface that matches Protocol and + Registration. + + @retval EFI_SUCCESS A protocol instance matching Protocol was found and returned in + Interface. + @retval EFI_NOT_FOUND No protocol instances were found that match Protocol and + Registration. + @retval EFI_INVALID_PARAMETER Interface is NULL. + +**/ +typedef +EFI_STATUS +(EFIAPI *EFI_LOCATE_PROTOCOL)( + IN EFI_GUID *Protocol, + IN VOID *Registration, OPTIONAL + OUT VOID **Interface + ); + +typedef struct { + UINT64 Length; + union { + EFI_PHYSICAL_ADDRESS DataBlock; + EFI_PHYSICAL_ADDRESS ContinuationPointer; + } Union; +} EFI_CAPSULE_BLOCK_DESCRIPTOR; + +typedef struct { + EFI_GUID CapsuleGuid; + UINT32 HeaderSize; + UINT32 Flags; + UINT32 CapsuleImageSize; +} EFI_CAPSULE_HEADER; + +// +// The EFI System Table entry must point to an array of capsules +// that contain the same CapsuleGuid value. The array must be +// prefixed by a UINT32 that represents the size of the array of capsules. +// +typedef struct { + UINT32 CapsuleArrayNumber; + VOID* CapsulePtr[1]; +} EFI_CAPSULE_TABLE; + +#define CAPSULE_FLAGS_PERSIST_ACROSS_RESET 0x00010000 +#define CAPSULE_FLAGS_POPULATE_SYSTEM_TABLE 0x00020000 + +/** + Passes capsules to the firmware with both virtual and physical mapping. Depending on the intended + consumption, the firmware may process the capsule immediately. If the payload should persist + across a system reset, the reset value returned from EFI_QueryCapsuleCapabilities must + be passed into ResetSystem() and will cause the capsule to be processed by the firmware as + part of the reset process. + + @param CapsuleHeaderArray Virtual pointer to an array of virtual pointers to the capsules + being passed into update capsule. + @param CapsuleCount Number of pointers to EFI_CAPSULE_HEADER in + CaspuleHeaderArray. + @param ScatterGatherList Physical pointer to a set of + EFI_CAPSULE_BLOCK_DESCRIPTOR that describes the + location in physical memory of a set of capsules. + + @retval EFI_SUCCESS Valid capsule was passed. If + CAPSULE_FLAGS_PERSIT_ACROSS_RESET is not set, the + capsule has been successfully processed by the firmware. + @retval EFI_DEVICE_ERROR The capsule update was started, but failed due to a device error. + @retval EFI_INVALID_PARAMETER CapsuleSize is NULL. + @retval EFI_UNSUPPORTED The capsule type is not supported on this platform. + @retval EFI_OUT_OF_RESOURCES There were insufficient resources to process the capsule. + +**/ +typedef +EFI_STATUS +(EFIAPI *EFI_UPDATE_CAPSULE)( + IN EFI_CAPSULE_HEADER **CapsuleHeaderArray, + IN UINTN CapsuleCount, + IN EFI_PHYSICAL_ADDRESS ScatterGatherList OPTIONAL + ); + +/** + Returns if the capsule can be supported via UpdateCapsule(). + + @param CapsuleHeaderArray Virtual pointer to an array of virtual pointers to the capsules + being passed into update capsule. + @param CapsuleCount Number of pointers to EFI_CAPSULE_HEADER in + CaspuleHeaderArray. + @param MaxiumCapsuleSize On output the maximum size that UpdateCapsule() can + support as an argument to UpdateCapsule() via + CapsuleHeaderArray and ScatterGatherList. + @param ResetType Returns the type of reset required for the capsule update. + + @retval EFI_SUCCESS Valid answer returned. + @retval EFI_UNSUPPORTED The capsule type is not supported on this platform, and + MaximumCapsuleSize and ResetType are undefined. + @retval EFI_INVALID_PARAMETER MaximumCapsuleSize is NULL. + @retval EFI_OUT_OF_RESOURCES There were insufficient resources to process the query request. + +**/ +typedef +EFI_STATUS +(EFIAPI *EFI_QUERY_CAPSULE_CAPABILITIES)( + IN EFI_CAPSULE_HEADER **CapsuleHeaderArray, + IN UINTN CapsuleCount, + OUT UINT64 *MaximumCapsuleSize, + OUT EFI_RESET_TYPE *ResetType + ); + +/** + Returns information about the EFI variables. + + @param Attributes Attributes bitmask to specify the type of variables on + which to return information. + @param MaximumVariableStorageSize On output the maximum size of the storage space + available for the EFI variables associated with the + attributes specified. + @param RemainingVariableStorageSize Returns the remaining size of the storage space + available for the EFI variables associated with the + attributes specified. + @param MaximumVariableSize Returns the maximum size of the individual EFI + variables associated with the attributes specified. + + @retval EFI_SUCCESS Valid answer returned. + @retval EFI_INVALID_PARAMETER An invalid combination of attribute bits was supplied + @retval EFI_UNSUPPORTED The attribute is not supported on this platform, and the + MaximumVariableStorageSize, + RemainingVariableStorageSize, MaximumVariableSize + are undefined. + +**/ +typedef +EFI_STATUS +(EFIAPI *EFI_QUERY_VARIABLE_INFO)( + IN UINT32 Attributes, + OUT UINT64 *MaximumVariableStorageSize, + OUT UINT64 *RemainingVariableStorageSize, + OUT UINT64 *MaximumVariableSize + ); + + +// +// EFI Runtime Services Table +// +#define EFI_SYSTEM_TABLE_SIGNATURE 0x5453595320494249ULL +#define EFI_SYSTEM_TABLE_REVISION ((2<<16) | (10)) +#define EFI_2_10_SYSTEM_TABLE_REVISION ((2<<16) | (10)) +#define EFI_2_00_SYSTEM_TABLE_REVISION ((2<<16) | (00)) +#define EFI_1_10_SYSTEM_TABLE_REVISION ((1<<16) | (10)) +#define EFI_1_02_SYSTEM_TABLE_REVISION ((1<<16) | (02)) + +#define EFI_RUNTIME_SERVICES_SIGNATURE 0x56524553544e5552ULL +#define EFI_RUNTIME_SERVICES_REVISION EFI_2_10_SYSTEM_TABLE_REVISION + +/// +/// EFI Runtime Services Table +/// +typedef struct { + /// + /// The table header for the EFI Runtime Services Table. + /// + EFI_TABLE_HEADER Hdr; + + // + // Time Services + // + EFI_GET_TIME GetTime; + EFI_SET_TIME SetTime; + EFI_GET_WAKEUP_TIME GetWakeupTime; + EFI_SET_WAKEUP_TIME SetWakeupTime; + + // + // Virtual Memory Services + // + EFI_SET_VIRTUAL_ADDRESS_MAP SetVirtualAddressMap; + EFI_CONVERT_POINTER ConvertPointer; + + // + // Variable Services + // + EFI_GET_VARIABLE GetVariable; + EFI_GET_NEXT_VARIABLE_NAME GetNextVariableName; + EFI_SET_VARIABLE SetVariable; + + // + // Miscellaneous Services + // + EFI_GET_NEXT_HIGH_MONO_COUNT GetNextHighMonotonicCount; + EFI_RESET_SYSTEM ResetSystem; + + // + // UEFI 2.0 Capsule Services + // + EFI_UPDATE_CAPSULE UpdateCapsule; + EFI_QUERY_CAPSULE_CAPABILITIES QueryCapsuleCapabilities; + + // + // Miscellaneous UEFI 2.0 Service + // + EFI_QUERY_VARIABLE_INFO QueryVariableInfo; +} EFI_RUNTIME_SERVICES; + + +#define EFI_BOOT_SERVICES_SIGNATURE 0x56524553544f4f42ULL +#define EFI_BOOT_SERVICES_REVISION EFI_2_10_SYSTEM_TABLE_REVISION + +/// +/// EFI Boot Services Table +/// +typedef struct { + /// + /// The table header for the EFI Boot Services Table. + /// + EFI_TABLE_HEADER Hdr; + + // + // Task Priority Services + // + EFI_RAISE_TPL RaiseTPL; + EFI_RESTORE_TPL RestoreTPL; + + // + // Memory Services + // + EFI_ALLOCATE_PAGES AllocatePages; + EFI_FREE_PAGES FreePages; + EFI_GET_MEMORY_MAP GetMemoryMap; + EFI_ALLOCATE_POOL AllocatePool; + EFI_FREE_POOL FreePool; + + // + // Event & Timer Services + // + EFI_CREATE_EVENT CreateEvent; + EFI_SET_TIMER SetTimer; + EFI_WAIT_FOR_EVENT WaitForEvent; + EFI_SIGNAL_EVENT SignalEvent; + EFI_CLOSE_EVENT CloseEvent; + EFI_CHECK_EVENT CheckEvent; + + // + // Protocol Handler Services + // + EFI_INSTALL_PROTOCOL_INTERFACE InstallProtocolInterface; + EFI_REINSTALL_PROTOCOL_INTERFACE ReinstallProtocolInterface; + EFI_UNINSTALL_PROTOCOL_INTERFACE UninstallProtocolInterface; + EFI_HANDLE_PROTOCOL HandleProtocol; + VOID *Reserved; + EFI_REGISTER_PROTOCOL_NOTIFY RegisterProtocolNotify; + EFI_LOCATE_HANDLE LocateHandle; + EFI_LOCATE_DEVICE_PATH LocateDevicePath; + EFI_INSTALL_CONFIGURATION_TABLE InstallConfigurationTable; + + // + // Image Services + // + EFI_IMAGE_LOAD LoadImage; + EFI_IMAGE_START StartImage; + EFI_EXIT Exit; + EFI_IMAGE_UNLOAD UnloadImage; + EFI_EXIT_BOOT_SERVICES ExitBootServices; + + // + // Miscellaneous Services + // + EFI_GET_NEXT_MONOTONIC_COUNT GetNextMonotonicCount; + EFI_STALL Stall; + EFI_SET_WATCHDOG_TIMER SetWatchdogTimer; + + // + // DriverSupport Services + // + EFI_CONNECT_CONTROLLER ConnectController; + EFI_DISCONNECT_CONTROLLER DisconnectController; + + // + // Open and Close Protocol Services + // + EFI_OPEN_PROTOCOL OpenProtocol; + EFI_CLOSE_PROTOCOL CloseProtocol; + EFI_OPEN_PROTOCOL_INFORMATION OpenProtocolInformation; + + // + // Library Services + // + EFI_PROTOCOLS_PER_HANDLE ProtocolsPerHandle; + EFI_LOCATE_HANDLE_BUFFER LocateHandleBuffer; + EFI_LOCATE_PROTOCOL LocateProtocol; + EFI_INSTALL_MULTIPLE_PROTOCOL_INTERFACES InstallMultipleProtocolInterfaces; + EFI_UNINSTALL_MULTIPLE_PROTOCOL_INTERFACES UninstallMultipleProtocolInterfaces; + + // + // 32-bit CRC Services + // + EFI_CALCULATE_CRC32 CalculateCrc32; + + // + // Miscellaneous Services + // + EFI_COPY_MEM CopyMem; + EFI_SET_MEM SetMem; + EFI_CREATE_EVENT_EX CreateEventEx; +} EFI_BOOT_SERVICES; + +/// +/// Contains a set of GUID/pointer pairs comprised of the ConfigurationTable field in the +/// EFI System Table. +/// +typedef struct{ + /// + /// The 128-bit GUID value that uniquely identifies the system configuration table. + /// + EFI_GUID VendorGuid; + /// + /// A pointer to the table associated with VendorGuid. + /// + VOID *VendorTable; +} EFI_CONFIGURATION_TABLE; + +/// +/// EFI System Table +/// +struct _EFI_SYSTEM_TABLE { + /// + /// The table header for the EFI System Table. + /// + EFI_TABLE_HEADER Hdr; + /// + /// A pointer to a null terminated Unicode string that identifies + /// the vendor that produces the system firmware for the platform. + /// + CHAR16 *FirmwareVendor; + /// + /// A firmware vendor specific value that identifies the revision + /// of the system firmware for the platform. + /// + UINT32 FirmwareRevision; + /// + /// The handle for the active console input device. + /// + EFI_HANDLE ConsoleInHandle; + /// + /// A pointer to the SIMPLE_INPUT_PROTOCOL interface that is + /// associated with ConsoleInHandle. + /// + EFI_SIMPLE_TEXT_INPUT_PROTOCOL *ConIn; + /// + /// The handle for the active console output device. + /// + EFI_HANDLE ConsoleOutHandle; + /// + /// A pointer to the SIMPLE_TEXT_OUTPUT_PROTOCOL interface + /// that is associated with ConsoleOutHandle. + /// + EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL *ConOut; + /// + /// The handle for the active standard error console device. + /// + EFI_HANDLE StandardErrorHandle; + /// + /// A pointer to the SIMPLE_TEXT_OUTPUT_PROTOCOL interface + /// that is associated with StandardErrorHandle. + /// + EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL *StdErr; + /// + /// A pointer to the EFI Runtime Services Table. + /// + EFI_RUNTIME_SERVICES *RuntimeServices; + /// + /// A pointer to the EFI Boot Services Table. + /// + EFI_BOOT_SERVICES *BootServices; + /// + /// The number of system configuration tables in the buffer ConfigurationTable. + /// + UINTN NumberOfTableEntries; + /// + /// A pointer to the system configuration tables. + /// The number of entries in the table is NumberOfTableEntries. + /// + EFI_CONFIGURATION_TABLE *ConfigurationTable; +}; + +// +// EFI Load Options Attributes +// +#define LOAD_OPTION_ACTIVE 0x00000001 +#define LOAD_OPTION_FORCE_RECONNECT 0x00000002 +#define LOAD_OPTION_HIDDEN 0x00000008 +#define LOAD_OPTION_CATEGORY 0x00001F00 + +#define LOAD_OPTION_CATEGORY_BOOT 0x00000000 +#define LOAD_OPTION_CATEGORY_APP 0x00000100 + +#define EFI_BOOT_OPTION_SUPPORT_KEY 0x00000001 +#define EFI_BOOT_OPTION_SUPPORT_APP 0x00000002 +#define EFI_BOOT_OPTION_SUPPORT_COUNT 0x00000300 + +typedef union { + struct { + UINT32 Revision : 8; + UINT32 ShiftPressed : 1; + UINT32 ControlPressed : 1; + UINT32 AltPressed : 1; + UINT32 LogoPressed : 1; + UINT32 MenuPressed : 1; + UINT32 SysReqPessed : 1; + UINT32 Reserved : 16; + UINT32 InputKeyCount : 2; + } Options; + UINT32 PackedValue; +} HOT_KEY_EFI_KEY_DATA; + +typedef struct { + HOT_KEY_EFI_KEY_DATA KeyOptions; + UINT32 BootOptionCrc; + UINT16 BootOption; +//EFI_INPUT_KEY Keys[]; +} EFI_KEY_OPTION; + +#define EFI_KEY_OPTION_SHIFT 0x00000001 +#define EFI_KEY_OPTION_CONTROL 0x00000002 +#define EFI_KEY_OPTION_ALT 0x00000004 +#define EFI_KEY_OPTION_LOGO 0x00000008 +#define EFI_KEY_OPTION_MENU 0x00000010 +#define EFI_KEY_OPTION_SYSREQ 0x00000020 +#define EFI_KEY_CODE_COUNT 0x00000300 + + +// +// EFI File location to boot from on removable media devices +// +#define EFI_REMOVABLE_MEDIA_FILE_NAME_IA32 L"\\EFI\\BOOT\\BOOTIA32.EFI" +#define EFI_REMOVABLE_MEDIA_FILE_NAME_IA64 L"\\EFI\\BOOT\\BOOTIA64.EFI" +#define EFI_REMOVABLE_MEDIA_FILE_NAME_X64 L"\\EFI\\BOOT\\BOOTX64.EFI" + +#if defined (MDE_CPU_IA32) + #define EFI_REMOVABLE_MEDIA_FILE_NAME EFI_REMOVABLE_MEDIA_FILE_NAME_IA32 +#elif defined (MDE_CPU_IPF) + #define EFI_REMOVABLE_MEDIA_FILE_NAME EFI_REMOVABLE_MEDIA_FILE_NAME_IA64 +#elif defined (MDE_CPU_X64) + #define EFI_REMOVABLE_MEDIA_FILE_NAME EFI_REMOVABLE_MEDIA_FILE_NAME_X64 +#elif defined (MDE_CPU_EBC) +#else + #error Unknown Processor Type +#endif + +#include <gpxe/efi/Uefi/UefiPxe.h> +#include <gpxe/efi/Uefi/UefiGpt.h> +#include <gpxe/efi/Uefi/UefiInternalFormRepresentation.h> + +#endif diff --git a/gpxe/src/include/gpxe/efi/X64/ProcessorBind.h b/gpxe/src/include/gpxe/efi/X64/ProcessorBind.h new file mode 100644 index 00000000..fe6c413b --- /dev/null +++ b/gpxe/src/include/gpxe/efi/X64/ProcessorBind.h @@ -0,0 +1,247 @@ +/** @file + Processor or Compiler specific defines and types x64 (Intel(r) EM64T, AMD64). + + Copyright (c) 2006, Intel Corporation + All rights reserved. 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 __PROCESSOR_BIND_H__ +#define __PROCESSOR_BIND_H__ + +/// +/// Define the processor type so other code can make processor based choices +/// +#define MDE_CPU_X64 + + +// +// Make sure we are useing the correct packing rules per EFI specification +// +#ifndef __GNUC__ +#pragma pack() +#endif + + +#if __INTEL_COMPILER +// +// Disable ICC's remark #869: "Parameter" was never referenced warning. +// This is legal ANSI C code so we disable the remark that is turned on with -Wall +// +#pragma warning ( disable : 869 ) + +// +// Disable ICC's remark #1418: external function definition with no prior declaration. +// This is legal ANSI C code so we disable the remark that is turned on with /W4 +// +#pragma warning ( disable : 1418 ) + +// +// Disable ICC's remark #1419: external declaration in primary source file +// This is legal ANSI C code so we disable the remark that is turned on with /W4 +// +#pragma warning ( disable : 1419 ) + +#endif + + +#if _MSC_EXTENSIONS + +// +// Disable warning that make it impossible to compile at /W4 +// This only works for Microsoft* tools +// + +// +// Disabling bitfield type checking warnings. +// +#pragma warning ( disable : 4214 ) + +// +// Disabling the unreferenced formal parameter warnings. +// +#pragma warning ( disable : 4100 ) + +// +// Disable slightly different base types warning as CHAR8 * can not be set +// to a constant string. +// +#pragma warning ( disable : 4057 ) + +// +// ASSERT(FALSE) or while (TRUE) are legal constructes so supress this warning +// +#pragma warning ( disable : 4127 ) + +// +// This warning is caused by functions defined but not used. For precompiled header only. +// +#pragma warning ( disable : 4505 ) + +// +// This warning is caused by empty (after preprocessing) souce file. For precompiled header only. +// +#pragma warning ( disable : 4206 ) + +#endif + + +#if !defined(__GNUC__) && (__STDC_VERSION__ < 199901L) + // + // No ANSI C 2000 stdint.h integer width declarations, so define equivalents + // + + #if _MSC_EXTENSIONS + + + // + // use Microsoft C complier dependent interger width types + // + typedef unsigned __int64 UINT64; + typedef __int64 INT64; + typedef unsigned __int32 UINT32; + typedef __int32 INT32; + typedef unsigned short UINT16; + typedef unsigned short CHAR16; + typedef short INT16; + typedef unsigned char BOOLEAN; + typedef unsigned char UINT8; + typedef char CHAR8; + typedef char INT8; + #else + #ifdef _EFI_P64 + // + // P64 - is Intel Itanium(TM) speak for pointers being 64-bit and longs and ints + // are 32-bits + // + typedef unsigned long long UINT64; + typedef long long INT64; + typedef unsigned int UINT32; + typedef int INT32; + typedef unsigned short CHAR16; + typedef unsigned short UINT16; + typedef short INT16; + typedef unsigned char BOOLEAN; + typedef unsigned char UINT8; + typedef char CHAR8; + typedef char INT8; + #else + // + // Assume LP64 - longs and pointers are 64-bit. Ints are 32-bit. + // + typedef unsigned long UINT64; + typedef long INT64; + typedef unsigned int UINT32; + typedef int INT32; + typedef unsigned short UINT16; + typedef unsigned short CHAR16; + typedef short INT16; + typedef unsigned char BOOLEAN; + typedef unsigned char UINT8; + typedef char CHAR8; + typedef char INT8; + #endif + #endif + + #define UINT8_MAX 0xff + +#else + // + // Use ANSI C 2000 stdint.h integer width declarations + // + #include <stdint.h> + typedef uint8_t BOOLEAN; + typedef int8_t INT8; + typedef uint8_t UINT8; + typedef int16_t INT16; + typedef uint16_t UINT16; + typedef int32_t INT32; + typedef uint32_t UINT32; + typedef int64_t INT64; + typedef uint64_t UINT64; + typedef char CHAR8; + typedef uint16_t CHAR16; + +#endif + +typedef UINT64 UINTN; +typedef INT64 INTN; + + +// +// Processor specific defines +// +#define MAX_BIT 0x8000000000000000ULL +#define MAX_2_BITS 0xC000000000000000ULL + +// +// Maximum legal X64 address +// +#define MAX_ADDRESS 0xFFFFFFFFFFFFFFFFULL + +// +// The stack alignment required for X64 +// +#define CPU_STACK_ALIGNMENT 16 + +// +// Modifier to ensure that all protocol member functions and EFI intrinsics +// use the correct C calling convention. All protocol member functions and +// EFI intrinsics are required to modify thier member functions with EFIAPI. +// +#if _MSC_EXTENSIONS + /// + /// Define the standard calling convention reguardless of optimization level. + /// __cdecl is Microsoft* specific C extension. + /// + #define EFIAPI __cdecl +#elif __GNUC__ + /// + /// Define the standard calling convention reguardless of optimization level. + /// The GCC support assumes a GCC compiler that supports the EFI ABI. The EFI + /// ABI is much closer to the x64 Microsoft* ABI than standard x64 (x86-64) + /// GCC ABI. Thus a standard x64 (x86-64) GCC compiler can not be used for + /// x64. Warning the assembly code in the MDE x64 does not follow the correct + /// ABI for the standard x64 (x86-64) GCC. + /// + #define EFIAPI __attribute__((ms_abi)) +#else + /// + /// The default for a non Microsoft* or GCC compiler is to assume the EFI ABI + /// is the standard. + /// + #define EFIAPI +#endif + +// +// The Microsoft* C compiler can removed references to unreferenced data items +// if the /OPT:REF linker option is used. We defined a macro as this is a +// a non standard extension +// +#if _MSC_EXTENSIONS + #define GLOBAL_REMOVE_IF_UNREFERENCED __declspec(selectany) +#else + #define GLOBAL_REMOVE_IF_UNREFERENCED +#endif + +// +// For symbol name in GNU assembly code, an extra "_" is necessary +// +#if __GNUC__ + #if defined(linux) + #define ASM_PFX(name) name + #else + #define ASM_PFX(name) _##name + #endif +#endif + +#define FUNCTION_ENTRY_POINT(p) (p) + +#endif + diff --git a/gpxe/src/include/gpxe/efi/efi.h b/gpxe/src/include/gpxe/efi/efi.h new file mode 100644 index 00000000..c7f63b6c --- /dev/null +++ b/gpxe/src/include/gpxe/efi/efi.h @@ -0,0 +1,131 @@ +#ifndef _EFI_H +#define _EFI_H + +/** @file + * + * EFI API + * + * The intention is to include near-verbatim copies of the EFI headers + * required by gPXE. This is achieved using the import.pl script in + * this directory. Run the import script to update the local copies + * of the headers: + * + * ./import.pl /path/to/edk2/edk2 + * + * where /path/to/edk2/edk2 is the path to your local checkout of the + * EFI Development Kit. + * + * Note that import.pl will modify any #include lines in each imported + * header to reflect its new location within the gPXE tree. It will + * also tidy up the file by removing carriage return characters and + * trailing whitespace. + * + * + * At the time of writing, there are a few other modifications to + * these headers that are present in my personal edk2 tree, that are + * not yet committed back to the main edk2 repository. These + * modifications are fixes for compilation on case-dependent + * filesystems, compilation under -mrtd and -mregparm=3, etc. + */ + +/* EFI headers rudely redefine NULL */ +#undef NULL + +/* Include the top-level EFI header files */ +#include <gpxe/efi/Uefi.h> +#include <gpxe/efi/PiDxe.h> + +/* Reset any trailing #pragma pack directives */ +#pragma pack() + +#include <gpxe/tables.h> +#include <gpxe/uuid.h> + +/** An EFI protocol used by gPXE */ +struct efi_protocol { + /** GUID */ + union { + /** EFI protocol GUID */ + EFI_GUID guid; + /** UUID structure understood by gPXE */ + union uuid uuid; + } u; + /** Variable containing pointer to protocol structure */ + void **protocol; +}; + +/** Declare an EFI protocol used by gPXE */ +#define __efi_protocol \ + __table ( struct efi_protocol, efi_protocols, 01 ) + +/** Declare an EFI protocol to be required by gPXE + * + * @v _protocol EFI protocol name + * @v _ptr Pointer to protocol instance + */ +#define EFI_REQUIRE_PROTOCOL( _protocol, _ptr ) \ + struct efi_protocol __ ## _protocol __efi_protocol = { \ + .u.guid = _protocol ## _GUID, \ + .protocol = ( ( void ** ) ( void * ) \ + ( ( (_ptr) == ( ( _protocol ** ) NULL ) ) ? \ + (_ptr) : (_ptr) ) ), \ + } + +/** An EFI configuration table used by gPXE */ +struct efi_config_table { + /** GUID */ + union { + /** EFI configuration table GUID */ + EFI_GUID guid; + /** UUID structure understood by gPXE */ + union uuid uuid; + } u; + /** Variable containing pointer to configuration table */ + void **table; + /** Table is required for operation */ + int required; +}; + +/** Declare an EFI configuration table used by gPXE */ +#define __efi_config_table \ + __table ( struct efi_config_table, efi_config_tables, 01 ) + +/** Declare an EFI configuration table to be used by gPXE + * + * @v _table EFI configuration table name + * @v _ptr Pointer to configuration table + * @v _required Table is required for operation + */ +#define EFI_USE_TABLE( _table, _ptr, _required ) \ + struct efi_config_table __ ## _table __efi_config_table = { \ + .u.guid = _table ## _GUID, \ + .table = ( ( void ** ) ( void * ) (_ptr) ), \ + .required = (_required), \ + } + +/** Convert a gPXE status code to an EFI status code + * + * FIXME: actually perform some kind of conversion. gPXE 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. + */ +#define RC_TO_EFIRC( rc ) (rc) + +/** Convert an EFI status code to a gPXE status code + * + * FIXME: as above + */ +#define EFIRC_TO_RC( efirc ) (efirc) + +extern EFI_HANDLE efi_image_handle; +extern EFI_SYSTEM_TABLE *efi_systab; + +extern const char * efi_strerror ( EFI_STATUS efirc ); +extern EFI_STATUS efi_init ( EFI_HANDLE image_handle, + EFI_SYSTEM_TABLE *systab ); +extern int efi_snp_install ( void ); + +#endif /* _EFI_H */ diff --git a/gpxe/src/include/gpxe/efi/efi_io.h b/gpxe/src/include/gpxe/efi/efi_io.h new file mode 100644 index 00000000..93f559db --- /dev/null +++ b/gpxe/src/include/gpxe/efi/efi_io.h @@ -0,0 +1,178 @@ +#ifndef _GPXE_EFI_IO_H +#define _GPXE_EFI_IO_H + +/** @file + * + * gPXE 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. + */ + +#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 /* _GPXE_EFI_IO_H */ diff --git a/gpxe/src/include/gpxe/efi/efi_pci.h b/gpxe/src/include/gpxe/efi/efi_pci.h new file mode 100644 index 00000000..8be331ab --- /dev/null +++ b/gpxe/src/include/gpxe/efi/efi_pci.h @@ -0,0 +1,146 @@ +#ifndef _GPXE_EFI_PCI_H +#define _GPXE_EFI_PCI_H + +/** @file + * + * gPXE PCI I/O API for EFI + * + */ + +#ifdef PCIAPI_EFI +#define PCIAPI_PREFIX_efi +#else +#define PCIAPI_PREFIX_efi __efi_ +#endif + +/* EFI PCI width codes defined by EFI spec */ +#define EFIPCI_WIDTH_BYTE 0 +#define EFIPCI_WIDTH_WORD 1 +#define EFIPCI_WIDTH_DWORD 2 + +#define EFIPCI_LOCATION( _offset, _width ) \ + ( (_offset) | ( (_width) << 16 ) ) +#define EFIPCI_OFFSET( _location ) ( (_location) & 0xffff ) +#define EFIPCI_WIDTH( _location ) ( (_location) >> 16 ) + +struct pci_device; + +extern int efipci_read ( struct pci_device *pci, unsigned long location, + void *value ); +extern int efipci_write ( struct pci_device *pci, unsigned long location, + unsigned long value ); + +/** + * Determine maximum PCI bus number within system + * + * @ret max_bus Maximum bus number + */ +static inline __always_inline int +PCIAPI_INLINE ( efi, pci_max_bus ) ( void ) { + /* No way to work this out via EFI */ + return 0xff; +} + +/** + * Read byte from PCI configuration space via EFI + * + * @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 ( efi, pci_read_config_byte ) ( struct pci_device *pci, + unsigned int where, + uint8_t *value ) { + return efipci_read ( pci, + EFIPCI_LOCATION ( where, EFIPCI_WIDTH_BYTE ), + value ); +} + +/** + * Read word from PCI configuration space via EFI + * + * @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 ( efi, pci_read_config_word ) ( struct pci_device *pci, + unsigned int where, + uint16_t *value ) { + return efipci_read ( pci, + EFIPCI_LOCATION ( where, EFIPCI_WIDTH_WORD ), + value ); +} + +/** + * Read dword from PCI configuration space via EFI + * + * @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 ( efi, pci_read_config_dword ) ( struct pci_device *pci, + unsigned int where, + uint32_t *value ) { + return efipci_read ( pci, + EFIPCI_LOCATION ( where, EFIPCI_WIDTH_DWORD ), + value ); +} + +/** + * Write byte to PCI configuration space via EFI + * + * @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 ( efi, pci_write_config_byte ) ( struct pci_device *pci, + unsigned int where, + uint8_t value ) { + return efipci_write ( pci, + EFIPCI_LOCATION ( where, EFIPCI_WIDTH_BYTE ), + value ); +} + +/** + * Write word to PCI configuration space via EFI + * + * @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 ( efi, pci_write_config_word ) ( struct pci_device *pci, + unsigned int where, + uint16_t value ) { + return efipci_write ( pci, + EFIPCI_LOCATION ( where, EFIPCI_WIDTH_WORD ), + value ); +} + +/** + * Write dword to PCI configuration space via EFI + * + * @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 ( efi, pci_write_config_dword ) ( struct pci_device *pci, + unsigned int where, + uint32_t value ) { + return efipci_write ( pci, + EFIPCI_LOCATION ( where, EFIPCI_WIDTH_DWORD ), + value ); +} + +#endif /* _GPXE_EFI_PCI_H */ diff --git a/gpxe/src/include/gpxe/efi/efi_smbios.h b/gpxe/src/include/gpxe/efi/efi_smbios.h new file mode 100644 index 00000000..df947de5 --- /dev/null +++ b/gpxe/src/include/gpxe/efi/efi_smbios.h @@ -0,0 +1,16 @@ +#ifndef _GPXE_EFI_SMBIOS_H +#define _GPXE_EFI_SMBIOS_H + +/** @file + * + * gPXE SMBIOS API for EFI + * + */ + +#ifdef SMBIOS_EFI +#define SMBIOS_PREFIX_efi +#else +#define SMBIOS_PREFIX_efi __efi_ +#endif + +#endif /* _GPXE_EFI_SMBIOS_H */ diff --git a/gpxe/src/include/gpxe/efi/efi_timer.h b/gpxe/src/include/gpxe/efi/efi_timer.h new file mode 100644 index 00000000..c332c9d6 --- /dev/null +++ b/gpxe/src/include/gpxe/efi/efi_timer.h @@ -0,0 +1,16 @@ +#ifndef _GPXE_EFI_TIMER_H +#define _GPXE_EFI_TIMER_H + +/** @file + * + * gPXE timer API for EFI + * + */ + +#ifdef TIMER_EFI +#define TIMER_PREFIX_efi +#else +#define TIMER_PREFIX_efi __efi_ +#endif + +#endif /* _GPXE_EFI_TIMER_H */ diff --git a/gpxe/src/include/gpxe/efi/efi_uaccess.h b/gpxe/src/include/gpxe/efi/efi_uaccess.h new file mode 100644 index 00000000..bae5fb41 --- /dev/null +++ b/gpxe/src/include/gpxe/efi/efi_uaccess.h @@ -0,0 +1,88 @@ +#ifndef _GPXE_EFI_UACCESS_H +#define _GPXE_EFI_UACCESS_H + +/** @file + * + * gPXE user access 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. + */ + +#ifdef UACCESS_EFI +#define UACCESS_PREFIX_efi +#else +#define UACCESS_PREFIX_efi __efi_ +#endif + +/** + * Convert physical address to user pointer + * + * @v phys_addr Physical address + * @ret userptr User pointer + */ +static inline __always_inline userptr_t +UACCESS_INLINE ( efi, phys_to_user ) ( unsigned long phys_addr ) { + return phys_addr; +} + +/** + * Convert user buffer to physical address + * + * @v userptr User pointer + * @v offset Offset from user pointer + * @ret phys_addr Physical address + */ +static inline __always_inline unsigned long +UACCESS_INLINE ( efi, user_to_phys ) ( userptr_t userptr, off_t offset ) { + return ( userptr + offset ); +} + +static inline __always_inline userptr_t +UACCESS_INLINE ( efi, virt_to_user ) ( volatile const void *addr ) { + return trivial_virt_to_user ( addr ); +} + +static inline __always_inline void * +UACCESS_INLINE ( efi, user_to_virt ) ( userptr_t userptr, off_t offset ) { + return trivial_user_to_virt ( userptr, offset ); +} + +static inline __always_inline userptr_t +UACCESS_INLINE ( efi, userptr_add ) ( userptr_t userptr, off_t offset ) { + return trivial_userptr_add ( userptr, offset ); +} + +static inline __always_inline void +UACCESS_INLINE ( efi, memcpy_user ) ( userptr_t dest, off_t dest_off, + userptr_t src, off_t src_off, + size_t len ) { + trivial_memcpy_user ( dest, dest_off, src, src_off, len ); +} + +static inline __always_inline void +UACCESS_INLINE ( efi, memmove_user ) ( userptr_t dest, off_t dest_off, + userptr_t src, off_t src_off, + size_t len ) { + trivial_memmove_user ( dest, dest_off, src, src_off, len ); +} + +static inline __always_inline void +UACCESS_INLINE ( efi, memset_user ) ( userptr_t buffer, off_t offset, + int c, size_t len ) { + trivial_memset_user ( buffer, offset, c, len ); +} + +static inline __always_inline size_t +UACCESS_INLINE ( efi, strlen_user ) ( userptr_t buffer, off_t offset ) { + return trivial_strlen_user ( buffer, offset ); +} + +static inline __always_inline off_t +UACCESS_INLINE ( efi, memchr_user ) ( userptr_t buffer, off_t offset, + int c, size_t len ) { + return trivial_memchr_user ( buffer, offset, c, len ); +} + +#endif /* _GPXE_EFI_UACCESS_H */ diff --git a/gpxe/src/include/gpxe/efi/efi_umalloc.h b/gpxe/src/include/gpxe/efi/efi_umalloc.h new file mode 100644 index 00000000..def17b2d --- /dev/null +++ b/gpxe/src/include/gpxe/efi/efi_umalloc.h @@ -0,0 +1,16 @@ +#ifndef _GPXE_EFI_UMALLOC_H +#define _GPXE_EFI_UMALLOC_H + +/** @file + * + * gPXE user memory allocation API for EFI + * + */ + +#ifdef UMALLOC_EFI +#define UMALLOC_PREFIX_efi +#else +#define UMALLOC_PREFIX_efi __efi_ +#endif + +#endif /* _GPXE_EFI_UMALLOC_H */ diff --git a/gpxe/src/include/gpxe/efi/import.pl b/gpxe/src/include/gpxe/efi/import.pl new file mode 100755 index 00000000..16993944 --- /dev/null +++ b/gpxe/src/include/gpxe/efi/import.pl @@ -0,0 +1,75 @@ +#!/usr/bin/perl -w + +use File::Spec::Functions qw ( :ALL ); +use File::Find; +use File::Path; +use FindBin; +use strict; +use warnings; + +sub try_import_file { + my $gpxedir = shift; + my $edkdirs = shift; + my $filename = shift; + + # Skip everything except headers + return unless $filename =~ /\.h$/; + print "$filename..."; + + my $outfile = catfile ( $gpxedir, $filename ); + foreach my $edkdir ( @$edkdirs ) { + my $infile = catfile ( $edkdir, $filename ); + if ( -e $infile ) { + # We have found a matching source file - import it + print "$infile\n"; + open my $infh, "<$infile" or die "Could not open $infile: $!\n"; + ( undef, my $outdir, undef ) = splitpath ( $outfile ); + mkpath ( $outdir ); + open my $outfh, ">$outfile" or die "Could not open $outfile: $!\n"; + my @dependencies = (); + while ( <$infh> ) { + # Strip CR and trailing whitespace + s/\r//g; + s/\s*$//g; + chomp; + # Update include lines, and record included files + if ( s/^\#include\s+[<\"](\S+)[>\"]/\#include <gpxe\/efi\/$1>/ ) { + push @dependencies, $1; + } + print $outfh "$_\n"; + } + close $outfh; + close $infh; + # Recurse to handle any included files that we don't already have + foreach my $dependency ( @dependencies ) { + if ( ! -e catfile ( $gpxedir, $dependency ) ) { + print "...following dependency on $dependency\n"; + try_import_file ( $gpxedir, $edkdirs, $dependency ); + } + } + return; + } + } + print "no equivalent found\n"; +} + +# Identify edk import directories +die "Syntax $0 /path/to/edk2/edk2\n" unless @ARGV == 1; +my $edktop = shift; +die "Directory \"$edktop\" does not appear to contain the EFI EDK2\n" + unless -e catfile ( $edktop, "MdePkg" ); +my $edkdirs = [ catfile ( $edktop, "MdePkg/Include" ), + catfile ( $edktop, "IntelFrameworkPkg/Include" ) ]; + +# Identify gPXE EFI includes directory +my $gpxedir = $FindBin::Bin; +die "Directory \"$gpxedir\" does not appear to contain the gPXE EFI includes\n" + unless -e catfile ( $gpxedir, "../../../include/gpxe/efi" ); + +print "Importing EFI headers into $gpxedir\nfrom "; +print join ( "\n and ", @$edkdirs )."\n"; + +# Import headers +find ( { wanted => sub { + try_import_file ( $gpxedir, $edkdirs, abs2rel ( $_, $gpxedir ) ); +}, no_chdir => 1 }, $gpxedir ); diff --git a/gpxe/src/include/gpxe/embedded.h b/gpxe/src/include/gpxe/embedded.h deleted file mode 100644 index ec457055..00000000 --- a/gpxe/src/include/gpxe/embedded.h +++ /dev/null @@ -1,9 +0,0 @@ -#ifndef _GPXE_EMBEDDED_H -#define _GPXE_EMBEDDED_H - -#include <gpxe/image.h> - -struct image *embedded_image(void); - -#endif - diff --git a/gpxe/src/include/gpxe/errfile.h b/gpxe/src/include/gpxe/errfile.h index ca0abebf..dcfd4e4a 100644 --- a/gpxe/src/include/gpxe/errfile.h +++ b/gpxe/src/include/gpxe/errfile.h @@ -106,10 +106,13 @@ #define ERRFILE_e1000_hw ( ERRFILE_DRIVER | 0x00490000 ) #define ERRFILE_mtnic ( ERRFILE_DRIVER | 0x004a0000 ) #define ERRFILE_phantom ( ERRFILE_DRIVER | 0x004b0000 ) +#define ERRFILE_ne2k_isa ( ERRFILE_DRIVER | 0x004c0000 ) +#define ERRFILE_b44 ( ERRFILE_DRIVER | 0x004d0000 ) #define ERRFILE_scsi ( ERRFILE_DRIVER | 0x00700000 ) #define ERRFILE_arbel ( ERRFILE_DRIVER | 0x00710000 ) #define ERRFILE_hermon ( ERRFILE_DRIVER | 0x00720000 ) +#define ERRFILE_linda ( ERRFILE_DRIVER | 0x00730000 ) #define ERRFILE_aoe ( ERRFILE_NET | 0x00000000 ) #define ERRFILE_arp ( ERRFILE_NET | 0x00010000 ) @@ -134,11 +137,16 @@ #define ERRFILE_netdev_settings ( ERRFILE_NET | 0x00140000 ) #define ERRFILE_dhcppkt ( ERRFILE_NET | 0x00150000 ) #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_image ( ERRFILE_IMAGE | 0x00000000 ) #define ERRFILE_elf ( ERRFILE_IMAGE | 0x00010000 ) #define ERRFILE_script ( ERRFILE_IMAGE | 0x00020000 ) #define ERRFILE_segment ( ERRFILE_IMAGE | 0x00030000 ) +#define ERRFILE_efi_image ( ERRFILE_IMAGE | 0x00040000 ) +#define ERRFILE_embedded ( ERRFILE_IMAGE | 0x00050000 ) #define ERRFILE_asn1 ( ERRFILE_OTHER | 0x00000000 ) #define ERRFILE_chap ( ERRFILE_OTHER | 0x00010000 ) @@ -156,6 +164,14 @@ #define ERRFILE_tls ( ERRFILE_OTHER | 0x000d0000 ) #define ERRFILE_ifmgmt ( ERRFILE_OTHER | 0x000e0000 ) #define ERRFILE_iscsiboot ( ERRFILE_OTHER | 0x000f0000 ) +#define ERRFILE_efi_pci ( ERRFILE_OTHER | 0x00100000 ) +#define ERRFILE_efi_snp ( ERRFILE_OTHER | 0x00110000 ) +#define ERRFILE_smbios ( ERRFILE_OTHER | 0x00120000 ) +#define ERRFILE_smbios_settings ( ERRFILE_OTHER | 0x00130000 ) +#define ERRFILE_efi_smbios ( ERRFILE_OTHER | 0x00140000 ) +#define ERRFILE_pxemenu ( ERRFILE_OTHER | 0x00150000 ) +#define ERRFILE_x509 ( ERRFILE_OTHER | 0x00160000 ) +#define ERRFILE_login_ui ( ERRFILE_OTHER | 0x00170000 ) /** @} */ diff --git a/gpxe/src/include/gpxe/ethernet.h b/gpxe/src/include/gpxe/ethernet.h index 158fe066..ff0fd6c1 100644 --- a/gpxe/src/include/gpxe/ethernet.h +++ b/gpxe/src/include/gpxe/ethernet.h @@ -9,6 +9,7 @@ #include <stdint.h> #include <gpxe/netdevice.h> +#include <gpxe/if_ether.h> extern struct ll_protocol ethernet_protocol; @@ -26,6 +27,7 @@ static inline struct net_device * alloc_etherdev ( size_t priv_size ) { netdev = alloc_netdev ( priv_size ); if ( netdev ) { netdev->ll_protocol = ðernet_protocol; + netdev->max_pkt_len = ETH_FRAME_LEN; } return netdev; } diff --git a/gpxe/src/include/gpxe/fakedhcp.h b/gpxe/src/include/gpxe/fakedhcp.h index 990b56af..550b74f7 100644 --- a/gpxe/src/include/gpxe/fakedhcp.h +++ b/gpxe/src/include/gpxe/fakedhcp.h @@ -15,7 +15,7 @@ extern int create_fakedhcpdiscover ( struct net_device *netdev, void *data, size_t max_len ); extern int create_fakedhcpack ( struct net_device *netdev, void *data, size_t max_len ); -extern int create_fakeproxydhcpack ( struct net_device *netdev, - void *data, size_t max_len ); +extern int create_fakepxebsack ( struct net_device *netdev, + void *data, size_t max_len ); #endif /* _GPXE_FAKEDHCP_H */ diff --git a/gpxe/src/include/gpxe/features.h b/gpxe/src/include/gpxe/features.h index 107ff085..32c31694 100644 --- a/gpxe/src/include/gpxe/features.h +++ b/gpxe/src/include/gpxe/features.h @@ -46,21 +46,21 @@ #define DHCP_EB_FEATURE_PXE 0x21 /**< PXE format */ #define DHCP_EB_FEATURE_ELF 0x22 /**< ELF format */ #define DHCP_EB_FEATURE_COMBOOT 0x23 /**< COMBOOT format */ +#define DHCP_EB_FEATURE_EFI 0x24 /**< EFI format */ /** @} */ /** Declare a feature code for DHCP */ -#define __dhcp_feature( category ) \ - __table ( uint8_t, dhcp_features, category ) +#define __dhcp_feature __table ( uint8_t, dhcp_features, 01 ) /** Construct a DHCP feature table entry */ -#define DHCP_FEATURE( category, feature_opt, version ) \ - _DHCP_FEATURE ( category, OBJECT, feature_opt, version ) -#define _DHCP_FEATURE( category, _name, feature_opt, version ) \ - __DHCP_FEATURE ( category, _name, feature_opt, version ) -#define __DHCP_FEATURE( category, _name, feature_opt, version ) \ - uint8_t __dhcp_feature_ ## _name [] __dhcp_feature ( category ) = { \ - feature_opt, DHCP_BYTE ( version ) \ +#define DHCP_FEATURE( feature_opt, ... ) \ + _DHCP_FEATURE ( OBJECT, feature_opt, __VA_ARGS__ ) +#define _DHCP_FEATURE( _name, feature_opt, ... ) \ + __DHCP_FEATURE ( _name, feature_opt, __VA_ARGS__ ) +#define __DHCP_FEATURE( _name, feature_opt, ... ) \ + uint8_t __dhcp_feature_ ## _name [] __dhcp_feature = { \ + feature_opt, DHCP_OPTION ( __VA_ARGS__ ) \ }; /** A named feature */ @@ -86,6 +86,10 @@ struct feature { /** Declare a feature */ #define FEATURE( category, text, feature_opt, version ) \ FEATURE_NAME ( category, text ); \ - DHCP_FEATURE ( category, feature_opt, version ); + DHCP_FEATURE ( feature_opt, version ); + +/** Declare the version number feature */ +#define FEATURE_VERSION( ... ) \ + DHCP_FEATURE ( DHCP_ENCAPSULATED ( DHCP_EB_VERSION ), __VA_ARGS__ ) #endif /* _GPXE_FEATURES_H */ diff --git a/gpxe/src/include/gpxe/i2c.h b/gpxe/src/include/gpxe/i2c.h index bfaee8fb..9d229546 100644 --- a/gpxe/src/include/gpxe/i2c.h +++ b/gpxe/src/include/gpxe/i2c.h @@ -8,6 +8,7 @@ */ #include <stdint.h> +#include <gpxe/bitbash.h> /** An I2C device * @@ -15,10 +16,35 @@ * is accessed via an I2C interface. */ struct i2c_device { - /** Address of this device */ - unsigned int address; - /** Flag indicating a ten-bit address format */ - int tenbit; + /** Address of this device + * + * The actual address sent on the bus will look like + * + * <start> <device address> <word address overflow> <r/w> + * + * The "word address overflow" is any excess bits from the + * word address, i.e. any portion that does not fit within the + * defined word address length. + */ + unsigned int dev_addr; + /** Device address length, in bytes + * + * This is the number of bytes that comprise the device + * address, defined to be the portion that terminates with the + * read/write bit. + */ + unsigned int dev_addr_len; + /** Word adddress length, in bytes + * + * This is the number of bytes that comprise the word address, + * defined to be the portion that starts after the read/write + * bit and ends before the first data byte. + * + * For some devices, this length will be zero (i.e. the word + * address is contained entirely within the "word address + * overflow"). + */ + unsigned int word_addr_len; }; /** An I2C interface @@ -91,6 +117,9 @@ enum { /** Delay required for bit-bashing operation */ #define I2C_UDELAY 5 +/** Maximum number of cycles to use when attempting a bus reset */ +#define I2C_RESET_MAX_CYCLES 32 + /** * Check presence of I2C device * @@ -106,6 +135,35 @@ static inline int i2c_check_presence ( struct i2c_interface *i2c, return i2c->write ( i2c, i2cdev, 0, NULL, 0 ); } -extern void init_i2c_bit_basher ( struct i2c_bit_basher *i2cbit ); +extern int init_i2c_bit_basher ( struct i2c_bit_basher *i2cbit, + struct bit_basher_operations *bash_op ); + +/** + * Initialise generic I2C EEPROM device + * + * @v i2cdev I2C device + */ +static inline __always_inline void +init_i2c_eeprom ( struct i2c_device *i2cdev, unsigned int dev_addr ) { + i2cdev->dev_addr = dev_addr; + i2cdev->dev_addr_len = 1; + i2cdev->word_addr_len = 1; +} + +/** + * Initialise Atmel AT24C11 + * + * @v i2cdev I2C device + */ +static inline __always_inline void +init_at24c11 ( struct i2c_device *i2cdev ) { + /* This chip has no device address; it must be the only chip + * on the bus. The word address is contained entirely within + * the device address field. + */ + i2cdev->dev_addr = 0; + i2cdev->dev_addr_len = 1; + i2cdev->word_addr_len = 0; +} #endif /* _GPXE_I2C_H */ diff --git a/gpxe/src/include/gpxe/ib_mad.h b/gpxe/src/include/gpxe/ib_mad.h new file mode 100644 index 00000000..6c4e95b7 --- /dev/null +++ b/gpxe/src/include/gpxe/ib_mad.h @@ -0,0 +1,364 @@ +#ifndef _GPXE_IB_MAD_H +#define _GPXE_IB_MAD_H + +/** @file + * + * Infiniband management datagrams + * + */ + +#include <stdint.h> +#include <gpxe/ib_packet.h> + +/***************************************************************************** + * + * Subnet management MADs + * + ***************************************************************************** + */ + +/** A subnet management header + * + * Defined in sections 14.2.1.1 and 14.2.1.2 of the IBA. + */ +struct ib_smp_hdr { + uint64_t mkey; + uint16_t slid; + uint16_t dlid; + uint8_t reserved[28]; +} __attribute__ (( packed )); + +/** Subnet management class version */ +#define IB_SMP_CLASS_VERSION 1 + +/** Subnet management direction bit + * + * This bit resides in the "status" field in the MAD header. + */ +#define IB_SMP_STATUS_D_INBOUND 0x8000 + +/* Subnet management attributes */ +#define IB_SMP_ATTR_NOTICE 0x0002 +#define IB_SMP_ATTR_NODE_DESC 0x0010 +#define IB_SMP_ATTR_NODE_INFO 0x0011 +#define IB_SMP_ATTR_SWITCH_INFO 0x0012 +#define IB_SMP_ATTR_GUID_INFO 0x0014 +#define IB_SMP_ATTR_PORT_INFO 0x0015 +#define IB_SMP_ATTR_PKEY_TABLE 0x0016 +#define IB_SMP_ATTR_SL_TO_VL_TABLE 0x0017 +#define IB_SMP_ATTR_VL_ARB_TABLE 0x0018 +#define IB_SMP_ATTR_LINEAR_FORWARD_TABLE 0x0019 +#define IB_SMP_ATTR_RANDOM_FORWARD_TABLE 0x001A +#define IB_SMP_ATTR_MCAST_FORWARD_TABLE 0x001B +#define IB_SMP_ATTR_SM_INFO 0x0020 +#define IB_SMP_ATTR_VENDOR_DIAG 0x0030 +#define IB_SMP_ATTR_LED_INFO 0x0031 +#define IB_SMP_ATTR_VENDOR_MASK 0xFF00 + +/** + * A Node Description attribute + * + * Defined in section 14.2.5.2 of the IBA + */ +struct ib_node_desc { + char node_string[64]; +} __attribute__ (( packed )); + +/** A Node Information attribute + * + * Defined in section 14.2.5.3 of the IBA. + */ +struct ib_node_info { + uint8_t base_version; + uint8_t class_version; + uint8_t node_type; + uint8_t num_ports; + uint8_t sys_guid[8]; + uint8_t node_guid[8]; + uint8_t port_guid[8]; + uint16_t partition_cap; + uint16_t device_id; + uint32_t revision; + uint8_t local_port_num; + uint8_t vendor_id[3]; +} __attribute__ ((packed)); + +#define IB_NODE_TYPE_HCA 0x01 +#define IB_NODE_TYPE_SWITCH 0x02 +#define IB_NODE_TYPE_ROUTER 0x03 + +/** A GUID Information attribute + * + * Defined in section 14.2.5.5 of the IBA. + */ +struct ib_guid_info { + uint8_t guid[8][8]; +} __attribute__ (( packed )); + +/** A Port Information attribute + * + * Defined in section 14.2.5.6 of the IBA. + */ +struct ib_port_info { + uint64_t mkey; + uint8_t gid_prefix[8]; + uint16_t lid; + uint16_t mastersm_lid; + uint32_t cap_mask; + uint16_t diag_code; + uint16_t mkey_lease_period; + uint8_t local_port_num; + uint8_t link_width_enabled; + uint8_t link_width_supported; + uint8_t link_width_active; + uint8_t link_speed_supported__port_state; + uint8_t port_phys_state__link_down_def_state; + uint8_t mkey_prot_bits__lmc; + uint8_t link_speed_active__link_speed_enabled; + uint8_t neighbour_mtu__mastersm_sl; + uint8_t vl_cap__init_type; + uint8_t vl_high_limit; + uint8_t vl_arbitration_high_cap; + uint8_t vl_arbitration_low_cap; + uint8_t init_type_reply__mtu_cap; + uint8_t vl_stall_count__hoq_life; + uint8_t operational_vls__enforcement; + uint16_t mkey_violations; + uint16_t pkey_violations; + uint16_t qkey_violations; + uint8_t guid_cap; + uint8_t client_reregister__subnet_timeout; + uint8_t resp_time_value; + uint8_t local_phy_errors__overrun_errors; + uint16_t max_credit_hint; + uint32_t link_round_trip_latency; +} __attribute__ (( packed )); + +#define IB_LINK_WIDTH_1X 0x01 +#define IB_LINK_WIDTH_4X 0x02 +#define IB_LINK_WIDTH_8X 0x04 +#define IB_LINK_WIDTH_12X 0x08 + +#define IB_LINK_SPEED_SDR 0x01 +#define IB_LINK_SPEED_DDR 0x02 +#define IB_LINK_SPEED_QDR 0x04 + +#define IB_PORT_STATE_DOWN 0x01 +#define IB_PORT_STATE_INIT 0x02 +#define IB_PORT_STATE_ARMED 0x03 +#define IB_PORT_STATE_ACTIVE 0x04 + +#define IB_PORT_PHYS_STATE_SLEEP 0x01 +#define IB_PORT_PHYS_STATE_POLLING 0x02 + +#define IB_MTU_256 0x01 +#define IB_MTU_512 0x02 +#define IB_MTU_1024 0x03 +#define IB_MTU_2048 0x04 +#define IB_MTU_4096 0x05 + +#define IB_VL_0 0x01 +#define IB_VL_0_1 0x02 +#define IB_VL_0_3 0x03 +#define IB_VL_0_7 0x04 +#define IB_VL_0_14 0x05 + +/** A Partition Key Table attribute + * + * Defined in section 14.2.5.7 of the IBA. + */ +struct ib_pkey_table { + uint16_t pkey[32]; +} __attribute__ (( packed )); + +/** A subnet management attribute */ +union ib_smp_data { + struct ib_node_desc node_desc; + struct ib_node_info node_info; + struct ib_guid_info guid_info; + struct ib_port_info port_info; + struct ib_pkey_table pkey_table; + uint8_t bytes[64]; +} __attribute__ (( packed )); + +/** A subnet management directed route path */ +struct ib_smp_dr_path { + uint8_t hops[64]; +} __attribute__ (( packed )); + +/** Subnet management MAD class-specific data */ +struct ib_smp_class_specific { + uint8_t hop_pointer; + uint8_t hop_count; +} __attribute__ (( packed )); + +/***************************************************************************** + * + * Subnet administration MADs + * + ***************************************************************************** + */ + +struct ib_rmpp_hdr { + uint32_t raw[3]; +} __attribute__ (( packed )); + +struct ib_sa_hdr { + uint32_t sm_key[2]; + uint16_t reserved; + uint16_t attrib_offset; + uint32_t comp_mask[2]; +} __attribute__ (( packed )); + +#define IB_SA_ATTR_MC_MEMBER_REC 0x38 +#define IB_SA_ATTR_PATH_REC 0x35 + +struct ib_path_record { + uint32_t reserved0[2]; + struct ib_gid dgid; + struct ib_gid sgid; + uint16_t dlid; + uint16_t slid; + uint32_t hop_limit__flow_label__raw_traffic; + uint32_t pkey__numb_path__reversible__tclass; + uint8_t reserved1; + uint8_t reserved__sl; + uint8_t mtu_selector__mtu; + uint8_t rate_selector__rate; + uint32_t preference__packet_lifetime__packet_lifetime_selector; + uint32_t reserved2[35]; +} __attribute__ (( packed )); + +#define IB_SA_PATH_REC_DGID (1<<2) +#define IB_SA_PATH_REC_SGID (1<<3) + +struct ib_mc_member_record { + struct ib_gid mgid; + struct ib_gid port_gid; + uint32_t qkey; + uint16_t mlid; + uint8_t mtu_selector__mtu; + uint8_t tclass; + uint16_t pkey; + uint8_t rate_selector__rate; + uint8_t packet_lifetime_selector__packet_lifetime; + uint32_t sl__flow_label__hop_limit; + uint8_t scope__join_state; + uint8_t proxy_join__reserved; + uint16_t reserved0; + uint32_t reserved1[37]; +} __attribute__ (( packed )); + +#define IB_SA_MCMEMBER_REC_MGID (1<<0) +#define IB_SA_MCMEMBER_REC_PORT_GID (1<<1) +#define IB_SA_MCMEMBER_REC_QKEY (1<<2) +#define IB_SA_MCMEMBER_REC_MLID (1<<3) +#define IB_SA_MCMEMBER_REC_MTU_SELECTOR (1<<4) +#define IB_SA_MCMEMBER_REC_MTU (1<<5) +#define IB_SA_MCMEMBER_REC_TRAFFIC_CLASS (1<<6) +#define IB_SA_MCMEMBER_REC_PKEY (1<<7) +#define IB_SA_MCMEMBER_REC_RATE_SELECTOR (1<<8) +#define IB_SA_MCMEMBER_REC_RATE (1<<9) +#define IB_SA_MCMEMBER_REC_PACKET_LIFE_TIME_SELECTOR (1<<10) +#define IB_SA_MCMEMBER_REC_PACKET_LIFE_TIME (1<<11) +#define IB_SA_MCMEMBER_REC_SL (1<<12) +#define IB_SA_MCMEMBER_REC_FLOW_LABEL (1<<13) +#define IB_SA_MCMEMBER_REC_HOP_LIMIT (1<<14) +#define IB_SA_MCMEMBER_REC_SCOPE (1<<15) +#define IB_SA_MCMEMBER_REC_JOIN_STATE (1<<16) +#define IB_SA_MCMEMBER_REC_PROXY_JOIN (1<<17) + +union ib_sa_data { + struct ib_path_record path_record; + struct ib_mc_member_record mc_member_record; +} __attribute__ (( packed )); + +/***************************************************************************** + * + * MADs + * + ***************************************************************************** + */ + +/** Management datagram class_specific data */ +union ib_mad_class_specific { + uint16_t raw; + struct ib_smp_class_specific smp; +} __attribute__ (( packed )); + +/** A management datagram common header + * + * Defined in section 13.4.2 of the IBA. + */ +struct ib_mad_hdr { + uint8_t base_version; + uint8_t mgmt_class; + uint8_t class_version; + uint8_t method; + uint16_t status; + union ib_mad_class_specific class_specific; + uint32_t tid[2]; + uint16_t attr_id; + uint8_t reserved[2]; + uint32_t attr_mod; +} __attribute__ (( packed )); + +/* Management base version */ +#define IB_MGMT_BASE_VERSION 1 + +/* Management classes */ +#define IB_MGMT_CLASS_SUBN_LID_ROUTED 0x01 +#define IB_MGMT_CLASS_SUBN_DIRECTED_ROUTE 0x81 +#define IB_MGMT_CLASS_SUBN_ADM 0x03 +#define IB_MGMT_CLASS_PERF_MGMT 0x04 +#define IB_MGMT_CLASS_BM 0x05 +#define IB_MGMT_CLASS_DEVICE_MGMT 0x06 +#define IB_MGMT_CLASS_CM 0x07 +#define IB_MGMT_CLASS_SNMP 0x08 +#define IB_MGMT_CLASS_VENDOR_RANGE2_START 0x30 +#define IB_MGMT_CLASS_VENDOR_RANGE2_END 0x4F + +/* Management methods */ +#define IB_MGMT_METHOD_GET 0x01 +#define IB_MGMT_METHOD_SET 0x02 +#define IB_MGMT_METHOD_GET_RESP 0x81 +#define IB_MGMT_METHOD_SEND 0x03 +#define IB_MGMT_METHOD_TRAP 0x05 +#define IB_MGMT_METHOD_REPORT 0x06 +#define IB_MGMT_METHOD_REPORT_RESP 0x86 +#define IB_MGMT_METHOD_TRAP_REPRESS 0x07 +#define IB_MGMT_METHOD_DELETE 0x15 + +/* Status codes */ +#define IB_MGMT_STATUS_OK 0x0000 +#define IB_MGMT_STATUS_BAD_VERSION 0x0001 +#define IB_MGMT_STATUS_UNSUPPORTED_METHOD 0x0002 +#define IB_MGMT_STATUS_UNSUPPORTED_METHOD_ATTR 0x0003 +#define IB_MGMT_STATUS_INVALID_VALUE 0x0004 + +/** A subnet management MAD */ +struct ib_mad_smp { + struct ib_mad_hdr mad_hdr; + struct ib_smp_hdr smp_hdr; + union ib_smp_data smp_data; + struct ib_smp_dr_path initial_path; + struct ib_smp_dr_path return_path; +} __attribute__ (( packed )); + +/** A subnet administration MAD */ +struct ib_mad_sa { + struct ib_mad_hdr mad_hdr; + struct ib_rmpp_hdr rmpp_hdr; + struct ib_sa_hdr sa_hdr; + union ib_sa_data sa_data; +} __attribute__ (( packed )); + +/** A management datagram */ +union ib_mad { + struct ib_mad_hdr hdr; + struct ib_mad_smp smp; + struct ib_mad_sa sa; + uint8_t bytes[256]; +} __attribute__ (( packed )); + +#endif /* _GPXE_IB_MAD_H */ diff --git a/gpxe/src/include/gpxe/ib_packet.h b/gpxe/src/include/gpxe/ib_packet.h new file mode 100644 index 00000000..5374802c --- /dev/null +++ b/gpxe/src/include/gpxe/ib_packet.h @@ -0,0 +1,147 @@ +#ifndef _GPXE_IB_PACKET_H +#define _GPXE_IB_PACKET_H + +/** @file + * + * Infiniband packet format + * + */ + +struct ib_device; +struct ib_queue_pair; +struct ib_address_vector; +struct io_buffer; + +/** Half of an Infiniband Global Identifier */ +struct ib_gid_half { + uint8_t bytes[8]; +}; + +/** An Infiniband Global Identifier */ +struct ib_gid { + union { + uint8_t bytes[16]; + uint16_t words[8]; + uint32_t dwords[4]; + struct ib_gid_half half[2]; + } u; +}; + +/** An Infiniband Local Route Header */ +struct ib_local_route_header { + /** Virtual lane and link version */ + uint8_t vl__lver; + /** Service level and next link header */ + uint8_t sl__lnh; + /** Destination LID */ + uint16_t dlid; + /** Packet length */ + uint16_t length; + /** Source LID */ + uint16_t slid; +} __attribute__ (( packed )); + +/** Infiniband virtual lanes */ +enum ib_vl { + IB_VL_DEFAULT = 0, + IB_VL_SMP = 15, +}; + +/** An Infiniband Link Next Header value */ +enum ib_lnh { + IB_LNH_RAW = 0, + IB_LNH_IPv6 = 1, + IB_LNH_BTH = 2, + IB_LNH_GRH = 3 +}; + +/** Default Infiniband LID */ +#define IB_LID_NONE 0xffff + +/** Test for multicast LID */ +#define IB_LID_MULTICAST( lid ) ( ( (lid) >= 0xc000 ) && ( (lid) <= 0xfffe ) ) + +/** An Infiniband Global Route Header */ +struct ib_global_route_header { + /** IP version, traffic class, and flow label + * + * 4 bits : Version of the GRH + * 8 bits : Traffic class + * 20 bits : Flow label + */ + uint32_t ipver__tclass__flowlabel; + /** Payload length */ + uint16_t paylen; + /** Next header */ + uint8_t nxthdr; + /** Hop limit */ + uint8_t hoplmt; + /** Source GID */ + struct ib_gid sgid; + /** Destiniation GID */ + struct ib_gid dgid; +} __attribute__ (( packed )); + +#define IB_GRH_IPVER_IPv6 0x06 +#define IB_GRH_NXTHDR_IBA 0x1b + +/** An Infiniband Base Transport Header */ +struct ib_base_transport_header { + /** Opcode */ + uint8_t opcode; + /** Transport header version, pad count, migration and solicitation */ + uint8_t se__m__padcnt__tver; + /** Partition key */ + uint16_t pkey; + /** Destination queue pair */ + uint32_t dest_qp; + /** Packet sequence number and acknowledge request */ + uint32_t ack__psn; +} __attribute__ (( packed )); + +/** An Infiniband BTH opcode */ +enum ib_bth_opcode { + BTH_OPCODE_UD_SEND = 0x64, +}; + +/** Default Infiniband partition key */ +#define IB_PKEY_NONE 0xffff + +/** Subnet management queue pair number */ +#define IB_QPN_SMP 0 + +/** An Infiniband Datagram Extended Transport Header */ +struct ib_datagram_extended_transport_header { + /** Queue key */ + uint32_t qkey; + /** Source queue pair */ + uint32_t src_qp; +} __attribute__ (( packed )); + +/** All known IB header formats */ +union ib_headers { + struct ib_local_route_header lrh; + struct { + struct ib_local_route_header lrh; + struct ib_global_route_header grh; + struct ib_base_transport_header bth; + struct ib_datagram_extended_transport_header deth; + } __attribute__ (( packed )) lrh__grh__bth__deth; + struct { + struct ib_local_route_header lrh; + struct ib_base_transport_header bth; + struct ib_datagram_extended_transport_header deth; + } __attribute__ (( packed )) lrh__bth__deth; +} __attribute__ (( packed )); + +/** Maximum size required for IB headers */ +#define IB_MAX_HEADER_SIZE sizeof ( union ib_headers ) + +extern int ib_push ( struct ib_device *ibdev, struct io_buffer *iobuf, + struct ib_queue_pair *qp, size_t payload_len, + const struct ib_address_vector *av ); +extern int ib_pull ( struct ib_device *ibdev, struct io_buffer *iobuf, + struct ib_queue_pair **qp, size_t *payload_len, + struct ib_address_vector *av ); + +#endif /* _GPXE_IB_PACKET_H */ diff --git a/gpxe/src/include/gpxe/ib_sma.h b/gpxe/src/include/gpxe/ib_sma.h new file mode 100644 index 00000000..835ed4ea --- /dev/null +++ b/gpxe/src/include/gpxe/ib_sma.h @@ -0,0 +1,63 @@ +#ifndef _GPXE_IB_SMA_H +#define _GPXE_IB_SMA_H + +/** @file + * + * Infiniband Subnet Management Agent + * + */ + +#include <gpxe/infiniband.h> +#include <gpxe/process.h> + +/** Infiniband Subnet Management Agent operations */ +struct ib_sma_operations { + /** Set port information + * + * @v ibdev Infiniband device + * @v port_info New port information + */ + int ( * set_port_info ) ( struct ib_device *ibdev, + const struct ib_port_info *port_info ); +}; + +/** An Infiniband Subnet Management Agent */ +struct ib_sma { + /** Infiniband device */ + struct ib_device *ibdev; + /** SMA operations */ + struct ib_sma_operations *op; + /** SMA completion queue */ + struct ib_completion_queue *cq; + /** SMA queue pair */ + struct ib_queue_pair *qp; + /** Poll process */ + struct process poll; +}; + +/** SMA payload size allocated for received packets */ +#define IB_SMA_PAYLOAD_LEN 2048 + +/** SMA number of send WQEs + * + * This is a policy decision. + */ +#define IB_SMA_NUM_SEND_WQES 4 + +/** SMA number of receive WQEs + * + * This is a policy decision. + */ +#define IB_SMA_NUM_RECV_WQES 2 + +/** SMA number of completion queue entries + * + * This is a policy decision + */ +#define IB_SMA_NUM_CQES 8 + +extern int ib_create_sma ( struct ib_sma *sma, struct ib_device *ibdev, + struct ib_sma_operations *op ); +extern void ib_destroy_sma ( struct ib_sma *sma ); + +#endif /* _GPXE_IB_SMA_H */ diff --git a/gpxe/src/include/gpxe/ib_smc.h b/gpxe/src/include/gpxe/ib_smc.h new file mode 100644 index 00000000..bb9020bf --- /dev/null +++ b/gpxe/src/include/gpxe/ib_smc.h @@ -0,0 +1,18 @@ +#ifndef _GPXE_IB_SMC_H +#define _GPXE_IB_SMC_H + +/** @file + * + * Infiniband Subnet Management Client + * + */ + +#include <gpxe/infiniband.h> + +typedef int ( * ib_local_mad_t ) ( struct ib_device *ibdev, + union ib_mad *mad ); + +extern int ib_smc_update ( struct ib_device *ibdev, + ib_local_mad_t local_mad ); + +#endif /* _GPXE_IB_SMC_H */ diff --git a/gpxe/src/include/gpxe/icmp.h b/gpxe/src/include/gpxe/icmp.h new file mode 100644 index 00000000..49ade2f2 --- /dev/null +++ b/gpxe/src/include/gpxe/icmp.h @@ -0,0 +1,23 @@ +#ifndef _GPXE_ICMP_H +#define _GPXE_ICMP_H + +/** @file + * + * ICMP protocol + * + */ + +/** An ICMP header */ +struct icmp_header { + /** Type */ + uint8_t type; + /** Code */ + uint8_t code; + /** Checksum */ + uint16_t chksum; +} __attribute__ (( packed )); + +#define ICMP_ECHO_RESPONSE 0 +#define ICMP_ECHO_REQUEST 8 + +#endif /* _GPXE_ICMP_H */ diff --git a/gpxe/src/include/gpxe/image.h b/gpxe/src/include/gpxe/image.h index 76dc3b8f..f8b1482e 100644 --- a/gpxe/src/include/gpxe/image.h +++ b/gpxe/src/include/gpxe/image.h @@ -46,6 +46,21 @@ struct image { userptr_t user; unsigned long ul; } priv; + + /** Replacement image + * + * An image wishing to replace itself with another image (in a + * style similar to a Unix exec() call) should return from its + * exec() method with the replacement image set to point to + * the new image. The new image must already be in a suitable + * state for execution (i.e. loaded). + * + * If an image unregisters itself as a result of being + * executed, it must make sure that its replacement image (if + * any) is registered, otherwise the replacement is likely to + * be freed before it can be executed. + */ + struct image *replacement; }; /** Image is loaded */ @@ -79,6 +94,10 @@ struct image_type { * * @v image Loaded image * @ret rc Return status code + * + * Note that the image may be invalidated by the act of + * execution, i.e. an image is allowed to choose to unregister + * (and so potentially free) itself. */ int ( * exec ) ( struct image *image ); }; diff --git a/gpxe/src/include/gpxe/in.h b/gpxe/src/include/gpxe/in.h index 40e4d407..831a6110 100644 --- a/gpxe/src/include/gpxe/in.h +++ b/gpxe/src/include/gpxe/in.h @@ -71,7 +71,7 @@ struct sockaddr_in { char pad[ sizeof ( struct sockaddr ) - sizeof ( sa_family_t ) - sizeof ( uint16_t ) - sizeof ( struct in_addr ) ]; -}; +} __attribute__ (( may_alias )); /** * IPv6 socket address @@ -87,7 +87,7 @@ struct sockaddr_in6 { 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 )); extern int inet_aton ( const char *cp, struct in_addr *inp ); extern char * inet_ntoa ( struct in_addr in ); diff --git a/gpxe/src/include/gpxe/infiniband.h b/gpxe/src/include/gpxe/infiniband.h index f9e65348..196b5950 100644 --- a/gpxe/src/include/gpxe/infiniband.h +++ b/gpxe/src/include/gpxe/infiniband.h @@ -10,6 +10,8 @@ #include <stdint.h> #include <gpxe/refcnt.h> #include <gpxe/device.h> +#include <gpxe/ib_packet.h> +#include <gpxe/ib_mad.h> /** Subnet administrator QPN */ #define IB_SA_QPN 1 @@ -20,38 +22,9 @@ /** Subnet administrator queue key */ #define IB_GLOBAL_QKEY 0x80010000UL -/** An Infiniband Global Identifier */ -struct ib_gid { - union { - uint8_t bytes[16]; - uint16_t words[8]; - uint32_t dwords[4]; - } u; -}; - -/** An Infiniband Global Route Header */ -struct ib_global_route_header { - /** IP version, traffic class, and flow label - * - * 4 bits : Version of the GRH - * 8 bits : Traffic class - * 20 bits : Flow label - */ - uint32_t ipver_tclass_flowlabel; - /** Payload length */ - uint16_t paylen; - /** Next header */ - uint8_t nxthdr; - /** Hop limit */ - uint8_t hoplmt; - /** Source GID */ - struct ib_gid sgid; - /** Destiniation GID */ - struct ib_gid dgid; -} __attribute__ (( packed )); - struct ib_device; struct ib_queue_pair; +struct ib_address_vector; struct ib_completion_queue; /** An Infiniband Work Queue */ @@ -66,6 +39,8 @@ struct ib_work_queue { struct list_head list; /** Number of work queue entries */ unsigned int num_wqes; + /** Number of occupied work queue entries */ + unsigned int fill; /** Next work queue entry index * * This is the index of the next entry to be filled (i.e. the @@ -80,8 +55,20 @@ struct ib_work_queue { void *drv_priv; }; +/** An Infiniband multicast GID */ +struct ib_multicast_gid { + /** List of multicast GIDs on this QP */ + struct list_head list; + /** Multicast GID */ + struct ib_gid gid; +}; + /** An Infiniband Queue Pair */ struct ib_queue_pair { + /** Containing Infiniband device */ + struct ib_device *ibdev; + /** List of queue pairs on this Infiniband device */ + struct list_head list; /** Queue Pair Number */ unsigned long qpn; /** Queue key */ @@ -90,6 +77,8 @@ struct ib_queue_pair { struct ib_work_queue send; /** Receive queue */ struct ib_work_queue recv; + /** List of multicast GIDs */ + struct list_head mgids; /** Driver private data */ void *drv_priv; /** Queue owner private data */ @@ -101,6 +90,58 @@ enum ib_queue_pair_mods { IB_MODIFY_QKEY = 0x0001, }; +/** An Infiniband Address Vector */ +struct ib_address_vector { + /** Queue Pair Number */ + unsigned long qpn; + /** Queue key + * + * Not specified for received packets. + */ + unsigned long qkey; + /** Local ID */ + unsigned int lid; + /** Rate + * + * Not specified for received packets. + */ + unsigned int rate; + /** Service level */ + unsigned int sl; + /** GID is present */ + unsigned int gid_present; + /** GID, if present */ + struct ib_gid gid; +}; + +/** Infiniband completion queue operations */ +struct ib_completion_queue_operations { + /** + * Complete Send WQE + * + * @v ibdev Infiniband device + * @v qp Queue pair + * @v iobuf I/O buffer + * @v rc Completion status code + */ + void ( * complete_send ) ( struct ib_device *ibdev, + struct ib_queue_pair *qp, + struct io_buffer *iobuf, int rc ); + /** + * Complete Receive WQE + * + * @v ibdev Infiniband device + * @v qp Queue pair + * @v av Address vector, or NULL + * @v iobuf I/O buffer + * @v rc Completion status code + */ + void ( * complete_recv ) ( struct ib_device *ibdev, + struct ib_queue_pair *qp, + struct ib_address_vector *av, + struct io_buffer *iobuf, int rc ); +}; + /** An Infiniband Completion Queue */ struct ib_completion_queue { /** Completion queue number */ @@ -117,53 +158,12 @@ struct ib_completion_queue { unsigned long next_idx; /** List of work queues completing to this queue */ struct list_head work_queues; + /** Completion queue operations */ + struct ib_completion_queue_operations *op; /** Driver private data */ void *drv_priv; }; -/** An Infiniband completion */ -struct ib_completion { - /** Syndrome - * - * If non-zero, then the completion is in error. - */ - unsigned int syndrome; - /** Length */ - size_t len; -}; - -/** An Infiniband completion handler - * - * @v ibdev Infiniband device - * @v qp Queue pair - * @v completion Completion - * @v iobuf I/O buffer - */ -typedef void ( * ib_completer_t ) ( struct ib_device *ibdev, - struct ib_queue_pair *qp, - struct ib_completion *completion, - struct io_buffer *iobuf ); - -/** An Infiniband Address Vector */ -struct ib_address_vector { - /** Destination Queue Pair */ - unsigned int dest_qp; - /** Queue key */ - unsigned long qkey; - /** Destination Local ID */ - unsigned int dlid; - /** Rate */ - unsigned int rate; - /** Service level */ - unsigned int sl; - /** GID is present */ - unsigned int gid_present; - /** GID */ - struct ib_gid gid; -}; - -struct ib_mad_hdr; - /** * Infiniband device operations * @@ -246,15 +246,12 @@ struct ib_device_operations { * * @v ibdev Infiniband device * @v cq Completion queue - * @v complete_send Send completion handler - * @v complete_recv Receive completion handler * - * The completion handler takes ownership of the I/O buffer. + * The relevant completion handler (specified at completion + * queue creation time) takes ownership of the I/O buffer. */ void ( * poll_cq ) ( struct ib_device *ibdev, - struct ib_completion_queue *cq, - ib_completer_t complete_send, - ib_completer_t complete_recv ); + struct ib_completion_queue *cq ); /** * Poll event queue * @@ -293,16 +290,6 @@ struct ib_device_operations { void ( * mcast_detach ) ( struct ib_device *ibdev, struct ib_queue_pair *qp, struct ib_gid *gid ); - /** - * Issue management datagram - * - * @v ibdev Infiniband device - * @v mad Management datagram - * @v len Length of management datagram - * @ret rc Return status code - */ - int ( * mad ) ( struct ib_device *ibdev, struct ib_mad_hdr *mad, - size_t len ); }; /** An Infiniband device */ @@ -313,26 +300,44 @@ struct ib_device { struct list_head list; /** Underlying device */ struct device *dev; + /** List of queue pairs */ + struct list_head qps; /** Infiniband operations */ struct ib_device_operations *op; /** Port number */ unsigned int port; - /** Link state */ - int link_up; + /** Port open request counter */ + unsigned int open_count; + + /** Port state */ + uint8_t port_state; + /** Link width */ + uint8_t link_width; + /** Link speed */ + uint8_t link_speed; /** Port GID */ - struct ib_gid port_gid; + struct ib_gid gid; + /** Port LID */ + uint16_t lid; /** Subnet manager LID */ - unsigned long sm_lid; + uint16_t sm_lid; + /** Subnet manager SL */ + uint8_t sm_sl; /** Partition key */ - unsigned int pkey; + uint16_t pkey; + + /** Outbound packet sequence number */ + uint32_t psn; + /** Driver private data */ void *drv_priv; /** Owner private data */ void *owner_priv; }; -extern struct ib_completion_queue * ib_create_cq ( struct ib_device *ibdev, - unsigned int num_cqes ); +extern struct ib_completion_queue * +ib_create_cq ( struct ib_device *ibdev, unsigned int num_cqes, + struct ib_completion_queue_operations *op ); extern void ib_destroy_cq ( struct ib_device *ibdev, struct ib_completion_queue *cq ); extern struct ib_queue_pair * @@ -343,115 +348,60 @@ extern int ib_modify_qp ( struct ib_device *ibdev, struct ib_queue_pair *qp, unsigned long mod_list, unsigned long qkey ); extern void ib_destroy_qp ( struct ib_device *ibdev, struct ib_queue_pair *qp ); +extern struct ib_queue_pair * ib_find_qp_qpn ( struct ib_device *ibdev, + unsigned long qpn ); +extern struct ib_queue_pair * ib_find_qp_mgid ( struct ib_device *ibdev, + struct ib_gid *gid ); extern struct ib_work_queue * ib_find_wq ( struct ib_completion_queue *cq, unsigned long qpn, int is_send ); +extern int ib_post_send ( struct ib_device *ibdev, struct ib_queue_pair *qp, + struct ib_address_vector *av, + struct io_buffer *iobuf ); +extern int ib_post_recv ( struct ib_device *ibdev, struct ib_queue_pair *qp, + struct io_buffer *iobuf ); +extern void ib_complete_send ( struct ib_device *ibdev, + struct ib_queue_pair *qp, + struct io_buffer *iobuf, int rc ); +extern void ib_complete_recv ( struct ib_device *ibdev, + struct ib_queue_pair *qp, + struct ib_address_vector *av, + struct io_buffer *iobuf, int rc ); +extern int ib_open ( struct ib_device *ibdev ); +extern void ib_close ( struct ib_device *ibdev ); +extern int ib_mcast_attach ( struct ib_device *ibdev, struct ib_queue_pair *qp, + struct ib_gid *gid ); +extern void ib_mcast_detach ( struct ib_device *ibdev, + struct ib_queue_pair *qp, struct ib_gid *gid ); extern struct ib_device * alloc_ibdev ( size_t priv_size ); extern int register_ibdev ( struct ib_device *ibdev ); extern void unregister_ibdev ( struct ib_device *ibdev ); extern void ib_link_state_changed ( struct ib_device *ibdev ); +extern struct list_head ib_devices; -/** - * Post send work queue entry - * - * @v ibdev Infiniband device - * @v qp Queue pair - * @v av Address vector - * @v iobuf I/O buffer - * @ret rc Return status code - */ -static inline __attribute__ (( always_inline )) int -ib_post_send ( struct ib_device *ibdev, struct ib_queue_pair *qp, - struct ib_address_vector *av, struct io_buffer *iobuf ) { - return ibdev->op->post_send ( ibdev, qp, av, iobuf ); -} - -/** - * Post receive work queue entry - * - * @v ibdev Infiniband device - * @v qp Queue pair - * @v iobuf I/O buffer - * @ret rc Return status code - */ -static inline __attribute__ (( always_inline )) int -ib_post_recv ( struct ib_device *ibdev, struct ib_queue_pair *qp, - struct io_buffer *iobuf ) { - return ibdev->op->post_recv ( ibdev, qp, iobuf ); -} +/** Iterate over all network devices */ +#define for_each_ibdev( ibdev ) \ + list_for_each_entry ( (ibdev), &ib_devices, list ) /** * Poll completion queue * * @v ibdev Infiniband device * @v cq Completion queue - * @v complete_send Send completion handler - * @v complete_recv Receive completion handler - */ -static inline __attribute__ (( always_inline )) void -ib_poll_cq ( struct ib_device *ibdev, struct ib_completion_queue *cq, - ib_completer_t complete_send, ib_completer_t complete_recv ) { - ibdev->op->poll_cq ( ibdev, cq, complete_send, complete_recv ); -} - -/** - * Open port - * - * @v ibdev Infiniband device - * @ret rc Return status code - */ -static inline __attribute__ (( always_inline )) int -ib_open ( struct ib_device *ibdev ) { - return ibdev->op->open ( ibdev ); -} - -/** - * Close port - * - * @v ibdev Infiniband device - */ -static inline __attribute__ (( always_inline )) void -ib_close ( struct ib_device *ibdev ) { - ibdev->op->close ( ibdev ); -} - -/** - * Attach to multicast group - * - * @v ibdev Infiniband device - * @v qp Queue pair - * @v gid Multicast GID - * @ret rc Return status code */ -static inline __attribute__ (( always_inline )) int -ib_mcast_attach ( struct ib_device *ibdev, struct ib_queue_pair *qp, - struct ib_gid *gid ) { - return ibdev->op->mcast_attach ( ibdev, qp, gid ); +static inline __always_inline void +ib_poll_cq ( struct ib_device *ibdev, struct ib_completion_queue *cq ) { + ibdev->op->poll_cq ( ibdev, cq ); } /** - * Detach from multicast group + * Check link state * * @v ibdev Infiniband device - * @v qp Queue pair - * @v gid Multicast GID - */ -static inline __attribute__ (( always_inline )) void -ib_mcast_detach ( struct ib_device *ibdev, struct ib_queue_pair *qp, - struct ib_gid *gid ) { - ibdev->op->mcast_detach ( ibdev, qp, gid ); -} - -/** - * Issue management datagram - * - * @v ibdev Infiniband device - * @v mad Management datagram - * @v len Length of management datagram - * @ret rc Return status code + * @ret link_up Link is up */ -static inline __attribute__ (( always_inline )) int -ib_mad ( struct ib_device *ibdev, struct ib_mad_hdr *mad, size_t len ) { - return ibdev->op->mad ( ibdev, mad, len ); +static inline __always_inline int +ib_link_ok ( struct ib_device *ibdev ) { + return ( ibdev->port_state == IB_PORT_STATE_ACTIVE ); } /** @@ -460,7 +410,7 @@ ib_mad ( struct ib_device *ibdev, struct ib_mad_hdr *mad, size_t len ) { * @v ibdev Infiniband device * @ret ibdev Infiniband device */ -static inline __attribute__ (( always_inline )) struct ib_device * +static inline __always_inline struct ib_device * ibdev_get ( struct ib_device *ibdev ) { ref_get ( &ibdev->refcnt ); return ibdev; @@ -471,7 +421,7 @@ ibdev_get ( struct ib_device *ibdev ) { * * @v ibdev Infiniband device */ -static inline __attribute__ (( always_inline )) void +static inline __always_inline void ibdev_put ( struct ib_device *ibdev ) { ref_put ( &ibdev->refcnt ); } @@ -482,7 +432,7 @@ ibdev_put ( struct ib_device *ibdev ) { * @v wq Work queue * @v priv Private data */ -static inline __attribute__ (( always_inline )) void +static inline __always_inline void ib_wq_set_drvdata ( struct ib_work_queue *wq, void *priv ) { wq->drv_priv = priv; } @@ -493,7 +443,7 @@ ib_wq_set_drvdata ( struct ib_work_queue *wq, void *priv ) { * @v wq Work queue * @ret priv Private data */ -static inline __attribute__ (( always_inline )) void * +static inline __always_inline void * ib_wq_get_drvdata ( struct ib_work_queue *wq ) { return wq->drv_priv; } @@ -504,7 +454,7 @@ ib_wq_get_drvdata ( struct ib_work_queue *wq ) { * @v qp Queue pair * @v priv Private data */ -static inline __attribute__ (( always_inline )) void +static inline __always_inline void ib_qp_set_drvdata ( struct ib_queue_pair *qp, void *priv ) { qp->drv_priv = priv; } @@ -515,7 +465,7 @@ ib_qp_set_drvdata ( struct ib_queue_pair *qp, void *priv ) { * @v qp Queue pair * @ret priv Private data */ -static inline __attribute__ (( always_inline )) void * +static inline __always_inline void * ib_qp_get_drvdata ( struct ib_queue_pair *qp ) { return qp->drv_priv; } @@ -526,7 +476,7 @@ ib_qp_get_drvdata ( struct ib_queue_pair *qp ) { * @v qp Queue pair * @v priv Private data */ -static inline __attribute__ (( always_inline )) void +static inline __always_inline void ib_qp_set_ownerdata ( struct ib_queue_pair *qp, void *priv ) { qp->owner_priv = priv; } @@ -537,7 +487,7 @@ ib_qp_set_ownerdata ( struct ib_queue_pair *qp, void *priv ) { * @v qp Queue pair * @ret priv Private data */ -static inline __attribute__ (( always_inline )) void * +static inline __always_inline void * ib_qp_get_ownerdata ( struct ib_queue_pair *qp ) { return qp->owner_priv; } @@ -548,7 +498,7 @@ ib_qp_get_ownerdata ( struct ib_queue_pair *qp ) { * @v cq Completion queue * @v priv Private data */ -static inline __attribute__ (( always_inline )) void +static inline __always_inline void ib_cq_set_drvdata ( struct ib_completion_queue *cq, void *priv ) { cq->drv_priv = priv; } @@ -559,7 +509,7 @@ ib_cq_set_drvdata ( struct ib_completion_queue *cq, void *priv ) { * @v cq Completion queue * @ret priv Private data */ -static inline __attribute__ (( always_inline )) void * +static inline __always_inline void * ib_cq_get_drvdata ( struct ib_completion_queue *cq ) { return cq->drv_priv; } @@ -570,7 +520,7 @@ ib_cq_get_drvdata ( struct ib_completion_queue *cq ) { * @v ibdev Infiniband device * @v priv Private data */ -static inline __attribute__ (( always_inline )) void +static inline __always_inline void ib_set_drvdata ( struct ib_device *ibdev, void *priv ) { ibdev->drv_priv = priv; } @@ -581,7 +531,7 @@ ib_set_drvdata ( struct ib_device *ibdev, void *priv ) { * @v ibdev Infiniband device * @ret priv Private data */ -static inline __attribute__ (( always_inline )) void * +static inline __always_inline void * ib_get_drvdata ( struct ib_device *ibdev ) { return ibdev->drv_priv; } @@ -592,7 +542,7 @@ ib_get_drvdata ( struct ib_device *ibdev ) { * @v ibdev Infiniband device * @v priv Private data */ -static inline __attribute__ (( always_inline )) void +static inline __always_inline void ib_set_ownerdata ( struct ib_device *ibdev, void *priv ) { ibdev->owner_priv = priv; } @@ -603,201 +553,9 @@ ib_set_ownerdata ( struct ib_device *ibdev, void *priv ) { * @v ibdev Infiniband device * @ret priv Private data */ -static inline __attribute__ (( always_inline )) void * +static inline __always_inline void * ib_get_ownerdata ( struct ib_device *ibdev ) { return ibdev->owner_priv; } -/***************************************************************************** - * - * Management datagrams - * - * Portions Copyright (c) 2004 Mellanox Technologies Ltd. All rights - * reserved. - * - */ - -/* Management base version */ -#define IB_MGMT_BASE_VERSION 1 - -/* Management classes */ -#define IB_MGMT_CLASS_SUBN_LID_ROUTED 0x01 -#define IB_MGMT_CLASS_SUBN_DIRECTED_ROUTE 0x81 -#define IB_MGMT_CLASS_SUBN_ADM 0x03 -#define IB_MGMT_CLASS_PERF_MGMT 0x04 -#define IB_MGMT_CLASS_BM 0x05 -#define IB_MGMT_CLASS_DEVICE_MGMT 0x06 -#define IB_MGMT_CLASS_CM 0x07 -#define IB_MGMT_CLASS_SNMP 0x08 -#define IB_MGMT_CLASS_VENDOR_RANGE2_START 0x30 -#define IB_MGMT_CLASS_VENDOR_RANGE2_END 0x4F - -/* Management methods */ -#define IB_MGMT_METHOD_GET 0x01 -#define IB_MGMT_METHOD_SET 0x02 -#define IB_MGMT_METHOD_GET_RESP 0x81 -#define IB_MGMT_METHOD_SEND 0x03 -#define IB_MGMT_METHOD_TRAP 0x05 -#define IB_MGMT_METHOD_REPORT 0x06 -#define IB_MGMT_METHOD_REPORT_RESP 0x86 -#define IB_MGMT_METHOD_TRAP_REPRESS 0x07 -#define IB_MGMT_METHOD_DELETE 0x15 -#define IB_MGMT_METHOD_RESP 0x80 - -/* Subnet management attributes */ -#define IB_SMP_ATTR_NOTICE 0x0002 -#define IB_SMP_ATTR_NODE_DESC 0x0010 -#define IB_SMP_ATTR_NODE_INFO 0x0011 -#define IB_SMP_ATTR_SWITCH_INFO 0x0012 -#define IB_SMP_ATTR_GUID_INFO 0x0014 -#define IB_SMP_ATTR_PORT_INFO 0x0015 -#define IB_SMP_ATTR_PKEY_TABLE 0x0016 -#define IB_SMP_ATTR_SL_TO_VL_TABLE 0x0017 -#define IB_SMP_ATTR_VL_ARB_TABLE 0x0018 -#define IB_SMP_ATTR_LINEAR_FORWARD_TABLE 0x0019 -#define IB_SMP_ATTR_RANDOM_FORWARD_TABLE 0x001A -#define IB_SMP_ATTR_MCAST_FORWARD_TABLE 0x001B -#define IB_SMP_ATTR_SM_INFO 0x0020 -#define IB_SMP_ATTR_VENDOR_DIAG 0x0030 -#define IB_SMP_ATTR_LED_INFO 0x0031 -#define IB_SMP_ATTR_VENDOR_MASK 0xFF00 - -#define IB_SA_ATTR_MC_MEMBER_REC 0x38 -#define IB_SA_ATTR_PATH_REC 0x35 - -#define IB_SA_MCMEMBER_REC_MGID (1<<0) -#define IB_SA_MCMEMBER_REC_PORT_GID (1<<1) -#define IB_SA_MCMEMBER_REC_QKEY (1<<2) -#define IB_SA_MCMEMBER_REC_MLID (1<<3) -#define IB_SA_MCMEMBER_REC_MTU_SELECTOR (1<<4) -#define IB_SA_MCMEMBER_REC_MTU (1<<5) -#define IB_SA_MCMEMBER_REC_TRAFFIC_CLASS (1<<6) -#define IB_SA_MCMEMBER_REC_PKEY (1<<7) -#define IB_SA_MCMEMBER_REC_RATE_SELECTOR (1<<8) -#define IB_SA_MCMEMBER_REC_RATE (1<<9) -#define IB_SA_MCMEMBER_REC_PACKET_LIFE_TIME_SELECTOR (1<<10) -#define IB_SA_MCMEMBER_REC_PACKET_LIFE_TIME (1<<11) -#define IB_SA_MCMEMBER_REC_SL (1<<12) -#define IB_SA_MCMEMBER_REC_FLOW_LABEL (1<<13) -#define IB_SA_MCMEMBER_REC_HOP_LIMIT (1<<14) -#define IB_SA_MCMEMBER_REC_SCOPE (1<<15) -#define IB_SA_MCMEMBER_REC_JOIN_STATE (1<<16) -#define IB_SA_MCMEMBER_REC_PROXY_JOIN (1<<17) - -#define IB_SA_PATH_REC_DGID (1<<2) -#define IB_SA_PATH_REC_SGID (1<<3) - -struct ib_mad_hdr { - uint8_t base_version; - uint8_t mgmt_class; - uint8_t class_version; - uint8_t method; - uint16_t status; - uint16_t class_specific; - uint32_t tid[2]; - uint16_t attr_id; - uint16_t resv; - uint32_t attr_mod; -} __attribute__ (( packed )); - -struct ib_sa_hdr { - uint32_t sm_key[2]; - uint16_t reserved; - uint16_t attrib_offset; - uint32_t comp_mask[2]; -} __attribute__ (( packed )); - -struct ib_rmpp_hdr { - uint32_t raw[3]; -} __attribute__ (( packed )); - -struct ib_mad_data { - struct ib_mad_hdr mad_hdr; - uint8_t data[232]; -} __attribute__ (( packed )); - -struct ib_mad_guid_info { - struct ib_mad_hdr mad_hdr; - uint32_t mkey[2]; - uint32_t reserved[8]; - uint8_t gid_local[8]; -} __attribute__ (( packed )); - -struct ib_mad_port_info { - struct ib_mad_hdr mad_hdr; - uint32_t mkey[2]; - uint32_t reserved[8]; - uint32_t mkey2[2]; - uint8_t gid_prefix[8]; - uint16_t lid; - uint16_t mastersm_lid; - uint32_t cap_mask; - uint16_t diag_code; - uint16_t mkey_lease_period; - uint8_t local_port_num; - uint8_t link_width_enabled; - uint8_t link_width_supported; - uint8_t link_width_active; - uint8_t port_state__link_speed_supported; - uint8_t link_down_def_state__port_phys_state; - uint8_t lmc__r1__mkey_prot_bits; - uint8_t link_speed_enabled__link_speed_active; -} __attribute__ (( packed )); - -struct ib_mad_pkey_table { - struct ib_mad_hdr mad_hdr; - uint32_t mkey[2]; - uint32_t reserved[8]; - uint16_t pkey[16][2]; -} __attribute__ (( packed )); - -struct ib_mad_path_record { - struct ib_mad_hdr mad_hdr; - struct ib_rmpp_hdr rmpp_hdr; - struct ib_sa_hdr sa_hdr; - uint32_t reserved0[2]; - struct ib_gid dgid; - struct ib_gid sgid; - uint16_t dlid; - uint16_t slid; - uint32_t hop_limit__flow_label__raw_traffic; - uint32_t pkey__numb_path__reversible__tclass; - uint8_t reserved1; - uint8_t reserved__sl; - uint8_t mtu_selector__mtu; - uint8_t rate_selector__rate; - uint32_t preference__packet_lifetime__packet_lifetime_selector; - uint32_t reserved2[35]; -} __attribute__ (( packed )); - -struct ib_mad_mc_member_record { - struct ib_mad_hdr mad_hdr; - struct ib_rmpp_hdr rmpp_hdr; - struct ib_sa_hdr sa_hdr; - struct ib_gid mgid; - struct ib_gid port_gid; - uint32_t qkey; - uint16_t mlid; - uint8_t mtu_selector__mtu; - uint8_t tclass; - uint16_t pkey; - uint8_t rate_selector__rate; - uint8_t packet_lifetime_selector__packet_lifetime; - uint32_t sl__flow_label__hop_limit; - uint8_t scope__join_state; - uint8_t proxy_join__reserved; - uint16_t reserved0; - uint32_t reserved1[37]; -} __attribute__ (( packed )); - -union ib_mad { - struct ib_mad_hdr mad_hdr; - struct ib_mad_data data; - struct ib_mad_guid_info guid_info; - struct ib_mad_port_info port_info; - struct ib_mad_pkey_table pkey_table; - struct ib_mad_path_record path_record; - struct ib_mad_mc_member_record mc_member_record; -} __attribute__ (( packed )); - #endif /* _GPXE_INFINIBAND_H */ diff --git a/gpxe/src/include/gpxe/init.h b/gpxe/src/include/gpxe/init.h index d2b450d7..e0e9f9c8 100644 --- a/gpxe/src/include/gpxe/init.h +++ b/gpxe/src/include/gpxe/init.h @@ -63,6 +63,7 @@ struct startup_fn { #define STARTUP_EARLY 01 /**< Early startup */ #define STARTUP_NORMAL 02 /**< Normal startup */ +#define STARTUP_LATE 03 /**< Late startup */ /** @} */ diff --git a/gpxe/src/include/gpxe/io.h b/gpxe/src/include/gpxe/io.h new file mode 100644 index 00000000..ebb8ba30 --- /dev/null +++ b/gpxe/src/include/gpxe/io.h @@ -0,0 +1,504 @@ +#ifndef _GPXE_IO_H +#define _GPXE_IO_H + +/** @file + * + * gPXE I/O API + * + * The I/O API provides methods for reading from and writing to + * memory-mapped and I/O-mapped devices. + * + * The standard methods (readl()/writel() etc.) do not strictly check + * the type of the address parameter; this is because traditional + * usage does not necessarily provide the correct pointer type. For + * example, code written for ISA devices at fixed I/O addresses (such + * as the keyboard controller) tend to use plain integer constants for + * the address parameter. + */ + +#include <stdint.h> +#include <gpxe/api.h> +#include <config/ioapi.h> +#include <gpxe/uaccess.h> + +/** + * Calculate static inline I/O API function name + * + * @v _prefix Subsystem prefix + * @v _api_func API function + * @ret _subsys_func Subsystem API function + */ +#define IOAPI_INLINE( _subsys, _api_func ) \ + SINGLE_API_INLINE ( IOAPI_PREFIX_ ## _subsys, _api_func ) + +/** + * Provide an I/O API implementation + * + * @v _prefix Subsystem prefix + * @v _api_func API function + * @v _func Implementing function + */ +#define PROVIDE_IOAPI( _subsys, _api_func, _func ) \ + PROVIDE_SINGLE_API ( IOAPI_PREFIX_ ## _subsys, _api_func, _func ) + +/** + * Provide a static inline I/O API implementation + * + * @v _prefix Subsystem prefix + * @v _api_func API function + */ +#define PROVIDE_IOAPI_INLINE( _subsys, _api_func ) \ + PROVIDE_SINGLE_API_INLINE ( IOAPI_PREFIX_ ## _subsys, _api_func ) + +/* Include all architecture-independent I/O API headers */ +#include <gpxe/efi/efi_io.h> + +/* Include all architecture-dependent I/O API headers */ +#include <bits/io.h> + +/** + * Wrap an I/O read + * + * @v _func I/O API function + * @v _type Data type + * @v io_addr I/O address + * @v _prefix Prefix for address in debug message + * @v _ndigits Number of hex digits for this data type + */ +#define IOAPI_READ( _func, _type, io_addr, _prefix, _ndigits ) ( { \ + volatile _type *_io_addr = \ + ( ( volatile _type * ) ( intptr_t ) (io_addr) ); \ + _type _data = _func ( _io_addr ); \ + DBGIO ( "[" _prefix " %08lx] => %0" #_ndigits "llx\n", \ + io_to_bus ( _io_addr ), ( unsigned long long ) _data ); \ + _data; } ) + +/** + * Wrap an I/O write + * + * @v _func I/O API function + * @v _type Data type + * @v data Value to write + * @v io_addr I/O address + * @v _prefix Prefix for address in debug message + * @v _ndigits Number of hex digits for this data type + */ +#define IOAPI_WRITE( _func, _type, data, io_addr, _prefix, _ndigits ) do { \ + volatile _type *_io_addr = \ + ( ( volatile _type * ) ( intptr_t ) (io_addr) ); \ + _type _data = (data); \ + DBGIO ( "[" _prefix " %08lx] <= %0" #_ndigits "llx\n", \ + io_to_bus ( _io_addr ), ( unsigned long long ) _data ); \ + _func ( _data, _io_addr ); \ + } while ( 0 ) + +/** + * Wrap an I/O string read + * + * @v _func I/O API function + * @v _type Data type + * @v io_addr I/O address + * @v data Data buffer + * @v count Number of elements to read + * @v _prefix Prefix for address in debug message + * @v _ndigits Number of hex digits for this data type + */ +#define IOAPI_READS( _func, _type, io_addr, data, count, _prefix, _ndigits ) \ + do { \ + volatile _type *_io_addr = \ + ( ( volatile _type * ) ( intptr_t ) (io_addr) ); \ + void *_data_void = (data); /* Check data is a pointer */ \ + _type * _data = ( ( _type * ) _data_void ); \ + const _type * _dbg_data = _data; \ + unsigned int _count = (count); \ + unsigned int _dbg_count = _count; \ + _func ( _io_addr, _data, _count ); \ + DBGIO ( "[" _prefix " %08lx] =>", io_to_bus ( _io_addr ) ); \ + while ( _dbg_count-- ) { \ + DBGIO ( " %0" #_ndigits "llx", \ + ( ( unsigned long long ) *(_dbg_data++) ) ); \ + } \ + DBGIO ( "\n" ); \ + } while ( 0 ) + +/** + * Wrap an I/O string write + * + * @v _func I/O API function + * @v _type Data type + * @v io_addr I/O address + * @v data Data buffer + * @v count Number of elements to write + * @v _prefix Prefix for address in debug message + * @v _ndigits Number of hex digits for this data type + */ +#define IOAPI_WRITES( _func, _type, io_addr, data, count, _prefix, _ndigits ) \ + do { \ + volatile _type *_io_addr = \ + ( ( volatile _type * ) ( intptr_t ) (io_addr) ); \ + const void *_data_void = (data); /* Check data is a pointer */ \ + const _type * _data = ( ( const _type * ) _data_void ); \ + const _type * _dbg_data = _data; \ + unsigned int _count = (count); \ + unsigned int _dbg_count = _count; \ + DBGIO ( "[" _prefix " %08lx] <=", io_to_bus ( _io_addr ) ); \ + while ( _dbg_count-- ) { \ + DBGIO ( " %0" #_ndigits "llx", \ + ( ( unsigned long long ) *(_dbg_data++) ) ); \ + } \ + DBGIO ( "\n" ); \ + _func ( _io_addr, _data, _count ); \ + } while ( 0 ) + +/** + * Convert physical address to a bus address + * + * @v phys_addr Physical address + * @ret bus_addr Bus address + */ +unsigned long phys_to_bus ( unsigned long phys_addr ); + +/** + * Convert bus address to a physical address + * + * @v bus_addr Bus address + * @ret phys_addr Physical address + */ +unsigned long bus_to_phys ( unsigned long bus_addr ); + +/** + * Convert virtual address to a bus address + * + * @v addr Virtual address + * @ret bus_addr Bus address + */ +static inline __always_inline unsigned long +virt_to_bus ( volatile const void *addr ) { + return phys_to_bus ( virt_to_phys ( addr ) ); +} + +/** + * Convert bus address to a virtual address + * + * @v bus_addr Bus address + * @ret addr Virtual address + * + * This operation is not available under all memory models. + */ +static inline __always_inline void * bus_to_virt ( unsigned long bus_addr ) { + return phys_to_virt ( bus_to_phys ( bus_addr ) ); +} + +/** + * Map bus address as an I/O address + * + * @v bus_addr Bus address + * @v len Length of region + * @ret io_addr I/O address + */ +void * ioremap ( unsigned long bus_addr, size_t len ); + +/** + * Unmap I/O address + * + * @v io_addr I/O address + */ +void iounmap ( volatile const void *io_addr ); + +/** + * Convert I/O address to bus address (for debug only) + * + * @v io_addr I/O address + * @ret bus_addr Bus address + */ +unsigned long io_to_bus ( volatile const void *io_addr ); + +/** + * Read byte from memory-mapped device + * + * @v io_addr I/O address + * @ret data Value read + */ +uint8_t readb ( volatile uint8_t *io_addr ); +#define readb( io_addr ) IOAPI_READ ( readb, uint8_t, io_addr, "MEM", 2 ) + +/** + * Read 16-bit word from memory-mapped device + * + * @v io_addr I/O address + * @ret data Value read + */ +uint16_t readw ( volatile uint16_t *io_addr ); +#define readw( io_addr ) IOAPI_READ ( readw, uint16_t, io_addr, "MEM", 4 ) + +/** + * Read 32-bit dword from memory-mapped device + * + * @v io_addr I/O address + * @ret data Value read + */ +uint32_t readl ( volatile uint32_t *io_addr ); +#define readl( io_addr ) IOAPI_READ ( readl, uint32_t, io_addr, "MEM", 8 ) + +/** + * Read 64-bit qword from memory-mapped device + * + * @v io_addr I/O address + * @ret data Value read + */ +uint64_t readq ( volatile uint64_t *io_addr ); +#define readq( io_addr ) IOAPI_READ ( readq, uint64_t, io_addr, "MEM", 16 ) + +/** + * Write byte to memory-mapped device + * + * @v data Value to write + * @v io_addr I/O address + */ +void writeb ( uint8_t data, volatile uint8_t *io_addr ); +#define writeb( data, io_addr ) \ + IOAPI_WRITE ( writeb, uint8_t, data, io_addr, "MEM", 2 ) + +/** + * Write 16-bit word to memory-mapped device + * + * @v data Value to write + * @v io_addr I/O address + */ +void writew ( uint16_t data, volatile uint16_t *io_addr ); +#define writew( data, io_addr ) \ + IOAPI_WRITE ( writew, uint16_t, data, io_addr, "MEM", 4 ) + +/** + * Write 32-bit dword to memory-mapped device + * + * @v data Value to write + * @v io_addr I/O address + */ +void writel ( uint32_t data, volatile uint32_t *io_addr ); +#define writel( data, io_addr ) \ + IOAPI_WRITE ( writel, uint32_t, data, io_addr, "MEM", 8 ) + +/** + * Write 64-bit qword to memory-mapped device + * + * @v data Value to write + * @v io_addr I/O address + */ +void writeq ( uint64_t data, volatile uint64_t *io_addr ); +#define writeq( data, io_addr ) \ + IOAPI_WRITE ( writeq, uint64_t, data, io_addr, "MEM", 16 ) + +/** + * Read byte from I/O-mapped device + * + * @v io_addr I/O address + * @ret data Value read + */ +uint8_t inb ( volatile uint8_t *io_addr ); +#define inb( io_addr ) IOAPI_READ ( inb, uint8_t, io_addr, "IO", 2 ) + +/** + * Read 16-bit word from I/O-mapped device + * + * @v io_addr I/O address + * @ret data Value read + */ +uint16_t inw ( volatile uint16_t *io_addr ); +#define inw( io_addr ) IOAPI_READ ( inw, uint16_t, io_addr, "IO", 4 ) + +/** + * Read 32-bit dword from I/O-mapped device + * + * @v io_addr I/O address + * @ret data Value read + */ +uint32_t inl ( volatile uint32_t *io_addr ); +#define inl( io_addr ) IOAPI_READ ( inl, uint32_t, io_addr, "IO", 8 ) + +/** + * Write byte to I/O-mapped device + * + * @v data Value to write + * @v io_addr I/O address + */ +void outb ( uint8_t data, volatile uint8_t *io_addr ); +#define outb( data, io_addr ) \ + IOAPI_WRITE ( outb, uint8_t, data, io_addr, "IO", 2 ) + +/** + * Write 16-bit word to I/O-mapped device + * + * @v data Value to write + * @v io_addr I/O address + */ +void outw ( uint16_t data, volatile uint16_t *io_addr ); +#define outw( data, io_addr ) \ + IOAPI_WRITE ( outw, uint16_t, data, io_addr, "IO", 4 ) + +/** + * Write 32-bit dword to I/O-mapped device + * + * @v data Value to write + * @v io_addr I/O address + */ +void outl ( uint32_t data, volatile uint32_t *io_addr ); +#define outl( data, io_addr ) \ + IOAPI_WRITE ( outl, uint32_t, data, io_addr, "IO", 8 ) + +/** + * Read bytes from I/O-mapped device + * + * @v io_addr I/O address + * @v data Data buffer + * @v count Number of bytes to read + */ +void insb ( volatile uint8_t *io_addr, uint8_t *data, unsigned int count ); +#define insb( io_addr, data, count ) \ + IOAPI_READS ( insb, uint8_t, io_addr, data, count, "IO", 2 ) + +/** + * Read 16-bit words from I/O-mapped device + * + * @v io_addr I/O address + * @v data Data buffer + * @v count Number of words to read + */ +void insw ( volatile uint16_t *io_addr, uint16_t *data, unsigned int count ); +#define insw( io_addr, data, count ) \ + IOAPI_READS ( insw, uint16_t, io_addr, data, count, "IO", 4 ) + +/** + * Read 32-bit words from I/O-mapped device + * + * @v io_addr I/O address + * @v data Data buffer + * @v count Number of words to read + */ +void insl ( volatile uint32_t *io_addr, uint32_t *data, unsigned int count ); +#define insl( io_addr, data, count ) \ + IOAPI_READS ( insl, uint32_t, io_addr, data, count, "IO", 8 ) + +/** + * Write bytes to I/O-mapped device + * + * @v io_addr I/O address + * @v data Data buffer + * @v count Number of bytes to write + */ +void outsb ( volatile uint8_t *io_addr, const uint8_t *data, + unsigned int count ); +#define outsb( io_addr, data, count ) \ + IOAPI_WRITES ( outsb, uint8_t, io_addr, data, count, "IO", 2 ) + +/** + * Write 16-bit words to I/O-mapped device + * + * @v io_addr I/O address + * @v data Data buffer + * @v count Number of words to write + */ +void outsw ( volatile uint16_t *io_addr, const uint16_t *data, + unsigned int count ); +#define outsw( io_addr, data, count ) \ + IOAPI_WRITES ( outsw, uint16_t, io_addr, data, count, "IO", 4 ) + +/** + * Write 32-bit words to I/O-mapped device + * + * @v io_addr I/O address + * @v data Data buffer + * @v count Number of words to write + */ +void outsl ( volatile uint32_t *io_addr, const uint32_t *data, + unsigned int count ); +#define outsl( io_addr, data, count ) \ + IOAPI_WRITES ( outsl, uint32_t, io_addr, data, count, "IO", 8 ) + +/** + * Slow down I/O + * + */ +void iodelay ( void ); + +/** + * Read value from I/O-mapped device, slowly + * + * @v _func Function to use to read value + * @v data Value to write + * @v io_addr I/O address + */ +#define INX_P( _func, _type, io_addr ) ( { \ + _type _data = _func ( (io_addr) ); \ + iodelay(); \ + _data; } ) + +/** + * Read byte from I/O-mapped device + * + * @v io_addr I/O address + * @ret data Value read + */ +#define inb_p( io_addr ) INX_P ( inb, uint8_t, io_addr ) + +/** + * Read 16-bit word from I/O-mapped device + * + * @v io_addr I/O address + * @ret data Value read + */ +#define inw_p( io_addr ) INX_P ( inw, uint16_t, io_addr ) + +/** + * Read 32-bit dword from I/O-mapped device + * + * @v io_addr I/O address + * @ret data Value read + */ +#define inl_p( io_addr ) INX_P ( inl, uint32_t, io_addr ) + +/** + * Write value to I/O-mapped device, slowly + * + * @v _func Function to use to write value + * @v data Value to write + * @v io_addr I/O address + */ +#define OUTX_P( _func, data, io_addr ) do { \ + _func ( (data), (io_addr) ); \ + iodelay(); \ + } while ( 0 ) + +/** + * Write byte to I/O-mapped device, slowly + * + * @v data Value to write + * @v io_addr I/O address + */ +#define outb_p( data, io_addr ) OUTX_P ( outb, data, io_addr ) + +/** + * Write 16-bit word to I/O-mapped device, slowly + * + * @v data Value to write + * @v io_addr I/O address + */ +#define outw_p( data, io_addr ) OUTX_P ( outw, data, io_addr ) + +/** + * Write 32-bit dword to I/O-mapped device, slowly + * + * @v data Value to write + * @v io_addr I/O address + */ +#define outl_p( data, io_addr ) OUTX_P ( outl, data, io_addr ) + +/** + * Memory barrier + * + */ +void mb ( void ); +#define rmb() mb() +#define wmb() mb() + +#endif /* _GPXE_IO_H */ diff --git a/gpxe/src/include/gpxe/iobuf.h b/gpxe/src/include/gpxe/iobuf.h index ff787754..6d1a58a4 100644 --- a/gpxe/src/include/gpxe/iobuf.h +++ b/gpxe/src/include/gpxe/iobuf.h @@ -181,6 +181,44 @@ static inline size_t iob_tailroom ( struct io_buffer *iobuf ) { return ( iobuf->end - iobuf->tail ); } +/** + * Create a temporary I/O buffer + * + * @v iobuf I/O buffer + * @v data Data buffer + * @v len Length of data + * @v max_len Length of buffer + * + * It is sometimes useful to use the iob_xxx() methods on temporary + * data buffers. + */ +static inline void iob_populate ( struct io_buffer *iobuf, + void *data, size_t len, size_t max_len ) { + iobuf->head = iobuf->data = data; + iobuf->tail = ( data + len ); + iobuf->end = ( data + max_len ); +} + +/** + * Disown an I/O buffer + * + * @v iobuf I/O buffer + * + * There are many functions that take ownership of the I/O buffer they + * are passed as a parameter. The caller should not retain a pointer + * to the I/O buffer. Use iob_disown() to automatically nullify the + * caller's pointer, e.g.: + * + * xfer_deliver_iob ( xfer, iob_disown ( iobuf ) ); + * + * This will ensure that iobuf is set to NULL for any code after the + * call to xfer_deliver_iob(). + */ +#define iob_disown( iobuf ) ( { \ + struct io_buffer *__iobuf = (iobuf); \ + (iobuf) = NULL; \ + __iobuf; } ) + extern struct io_buffer * __malloc alloc_iob ( size_t len ); extern void free_iob ( struct io_buffer *iobuf ); extern void iob_pad ( struct io_buffer *iobuf, size_t min_len ); diff --git a/gpxe/src/include/gpxe/ipoib.h b/gpxe/src/include/gpxe/ipoib.h index bcbdc4c6..80adee5b 100644 --- a/gpxe/src/include/gpxe/ipoib.h +++ b/gpxe/src/include/gpxe/ipoib.h @@ -8,6 +8,9 @@ #include <gpxe/infiniband.h> +/** IPoIB packet length */ +#define IPOIB_PKT_LEN 2048 + /** IPoIB MAC address length */ #define IPOIB_ALEN 20 @@ -23,33 +26,30 @@ struct ipoib_mac { } __attribute__ (( packed )); /** IPoIB link-layer header length */ -#define IPOIB_HLEN 24 - -/** - * IPoIB link-layer header pseudo portion - * - * This part doesn't actually exist on the wire, but it provides a - * convenient way to fit into the typical network device model. - */ -struct ipoib_pseudo_hdr { - /** Peer address */ - struct ipoib_mac peer; -} __attribute__ (( packed )); +#define IPOIB_HLEN 4 -/** IPoIB link-layer header real portion */ -struct ipoib_real_hdr { +/** IPoIB link-layer header */ +struct ipoib_hdr { /** Network-layer protocol */ uint16_t proto; /** Reserved, must be zero */ - uint16_t reserved; -} __attribute__ (( packed )); - -/** An IPoIB link-layer header */ -struct ipoib_hdr { - /** Pseudo portion */ - struct ipoib_pseudo_hdr pseudo; - /** Real portion */ - struct ipoib_real_hdr real; + union { + /** Reserved, must be zero */ + uint16_t reserved; + /** Peer addresses + * + * We use these fields internally to represent the + * peer addresses using a lookup key. There simply + * isn't enough room in the IPoIB header to store + * literal source or destination MAC addresses. + */ + struct { + /** Destination address key */ + uint8_t dest; + /** Source address key */ + uint8_t src; + } __attribute__ (( packed )) peer; + } __attribute__ (( packed )) u; } __attribute__ (( packed )); extern struct ll_protocol ipoib_protocol; @@ -68,6 +68,7 @@ static inline struct net_device * alloc_ipoibdev ( size_t priv_size ) { netdev = alloc_netdev ( priv_size ); if ( netdev ) { netdev->ll_protocol = &ipoib_protocol; + netdev->max_pkt_len = IPOIB_PKT_LEN; } return netdev; } diff --git a/gpxe/src/include/gpxe/keys.h b/gpxe/src/include/gpxe/keys.h index 7a0b5101..3da8a1ff 100644 --- a/gpxe/src/include/gpxe/keys.h +++ b/gpxe/src/include/gpxe/keys.h @@ -52,26 +52,23 @@ * * The names are chosen to match those used by curses. The values are * chosen to facilitate easy conversion from a received ANSI escape - * sequence to a KEY_XXX constant. The KEY_XXX constant is simply - * 0x100 plus the first byte following CSI in the ANSI escape - * sequence. For example, KEY_LEFT is 0x144, since a left cursor key - * is transmitted as the ANSI sequence "^[[D". + * sequence to a KEY_XXX constant. */ -#define KEY_ANSI( character ) ( 0x100 + (character) ) +#define KEY_ANSI( n, terminator ) ( 0x100 * ( (n) + 1 ) + (terminator) ) #define KEY_MIN 0x101 -#define KEY_UP KEY_ANSI ( 'A' ) /**< Up arrow */ -#define KEY_DOWN KEY_ANSI ( 'B' ) /**< Down arrow */ -#define KEY_RIGHT KEY_ANSI ( 'C' ) /**< Right arrow */ -#define KEY_LEFT KEY_ANSI ( 'D' ) /**< Left arrow */ -#define KEY_END KEY_ANSI ( 'F' ) /**< End */ -#define KEY_HOME KEY_ANSI ( 'H' ) /**< Home */ -#define KEY_IC KEY_ANSI ( '2' ) /**< Insert */ -#define KEY_DC KEY_ANSI ( '3' ) /**< Delete */ -#define KEY_PPAGE KEY_ANSI ( '5' ) /**< Page up */ -#define KEY_NPAGE KEY_ANSI ( '6' ) /**< Page down */ -#define KEY_MAX 0x1ff +#define KEY_UP KEY_ANSI ( 0, 'A' ) /**< Up arrow */ +#define KEY_DOWN KEY_ANSI ( 0, 'B' ) /**< Down arrow */ +#define KEY_RIGHT KEY_ANSI ( 0, 'C' ) /**< Right arrow */ +#define KEY_LEFT KEY_ANSI ( 0, 'D' ) /**< Left arrow */ +#define KEY_END KEY_ANSI ( 0, 'F' ) /**< End */ +#define KEY_HOME KEY_ANSI ( 0, 'H' ) /**< Home */ +#define KEY_IC KEY_ANSI ( 2, '~' ) /**< Insert */ +#define KEY_DC KEY_ANSI ( 3, '~' ) /**< Delete */ +#define KEY_PPAGE KEY_ANSI ( 5, '~' ) /**< Page up */ +#define KEY_NPAGE KEY_ANSI ( 6, '~' ) /**< Page down */ +#define KEY_F8 KEY_ANSI ( 19, '~' ) /**< F8 (for PXE) */ /* Not in the [KEY_MIN,KEY_MAX] range; terminals seem to send these as * normal ASCII values. diff --git a/gpxe/src/include/gpxe/login_ui.h b/gpxe/src/include/gpxe/login_ui.h new file mode 100644 index 00000000..d92ba8f3 --- /dev/null +++ b/gpxe/src/include/gpxe/login_ui.h @@ -0,0 +1,12 @@ +#ifndef _GPXE_LOGIN_UI_H +#define _GPXE_LOGIN_UI_H + +/** @file + * + * Login UI + * + */ + +extern int login_ui ( void ); + +#endif /* _GPXE_LOGIN_UI_H */ diff --git a/gpxe/src/include/gpxe/nap.h b/gpxe/src/include/gpxe/nap.h new file mode 100644 index 00000000..f9ae3cf4 --- /dev/null +++ b/gpxe/src/include/gpxe/nap.h @@ -0,0 +1,54 @@ +#ifndef _GPXE_NAP_H +#define _GPXE_NAP_H + +/** @file + * + * CPU sleeping + * + */ + +#include <gpxe/api.h> +#include <config/nap.h> + +/** + * Calculate static inline CPU sleeping API function name + * + * @v _prefix Subsystem prefix + * @v _api_func API function + * @ret _subsys_func Subsystem API function + */ +#define NAP_INLINE( _subsys, _api_func ) \ + SINGLE_API_INLINE ( NAP_PREFIX_ ## _subsys, _api_func ) + +/** + * Provide an CPU sleeping API implementation + * + * @v _prefix Subsystem prefix + * @v _api_func API function + * @v _func Implementing function + */ +#define PROVIDE_NAP( _subsys, _api_func, _func ) \ + PROVIDE_SINGLE_API ( NAP_PREFIX_ ## _subsys, _api_func, _func ) + +/** + * Provide a static inline CPU sleeping API implementation + * + * @v _prefix Subsystem prefix + * @v _api_func API function + */ +#define PROVIDE_NAP_INLINE( _subsys, _api_func ) \ + PROVIDE_SINGLE_API_INLINE ( NAP_PREFIX_ ## _subsys, _api_func ) + +/* Include all architecture-independent I/O API headers */ +#include <gpxe/null_nap.h> + +/* Include all architecture-dependent I/O API headers */ +#include <bits/nap.h> + +/** + * Sleep until next CPU interrupt + * + */ +void cpu_nap ( void ); + +#endif /* _GPXE_NAP_H */ diff --git a/gpxe/src/include/gpxe/netdevice.h b/gpxe/src/include/gpxe/netdevice.h index cdc8cbad..f1585de0 100644 --- a/gpxe/src/include/gpxe/netdevice.h +++ b/gpxe/src/include/gpxe/netdevice.h @@ -23,7 +23,7 @@ struct device; #define MAX_LL_ADDR_LEN 20 /** Maximum length of a link-layer header */ -#define MAX_LL_HEADER_LEN 32 +#define MAX_LL_HEADER_LEN 6 /** Maximum length of a network-layer address */ #define MAX_NET_ADDR_LEN 4 @@ -79,34 +79,24 @@ struct ll_protocol { * Add link-layer header * * @v iobuf I/O buffer - * @v netdev Network device - * @v net_protocol Network-layer protocol * @v ll_dest Link-layer destination address + * @v ll_source Source link-layer address + * @v net_proto Network-layer protocol, in network-byte order * @ret rc Return status code - * - * This method should prepend in the link-layer header - * (e.g. the Ethernet DIX header). */ - int ( * push ) ( struct io_buffer *iobuf, struct net_device *netdev, - struct net_protocol *net_protocol, - const void *ll_dest ); + int ( * push ) ( struct io_buffer *iobuf, const void *ll_dest, + const void *ll_source, uint16_t net_proto ); /** * Remove link-layer header * - * @v iobuf I/O buffer - * @v netdev Network device - * @v net_proto Network-layer protocol, in network-byte order - * @v ll_source Source link-layer address - * @ret rc Return status code - * - * This method should strip off the link-layer header - * (e.g. the Ethernet DIX header) and return the protocol and - * source link-layer address. The method must not alter the - * packet content, and may return the link-layer address as a - * pointer to data within the packet. + * @v iobuf I/O buffer + * @ret ll_dest Link-layer destination address + * @ret ll_source Source link-layer address + * @ret net_proto Network-layer protocol, in network-byte order + * @ret rc Return status code */ - int ( * pull ) ( struct io_buffer *iobuf, struct net_device *netdev, - uint16_t *net_proto, const void **ll_source ); + int ( * pull ) ( struct io_buffer *iobuf, const void **ll_dest, + const void **ll_source, uint16_t *net_proto ); /** * Transcribe link-layer address * @@ -120,6 +110,16 @@ struct ll_protocol { * allocated. */ const char * ( * ntoa ) ( const void * ll_addr ); + /** + * Hash multicast address + * + * @v af Address family + * @v net_addr Network-layer address + * @v ll_addr Link-layer address to fill in + * @ret rc Return status code + */ + int ( * mc_hash ) ( unsigned int af, const void *net_addr, + void *ll_addr ); /** Link-layer protocol * * This is an ARPHRD_XXX constant, in network byte order. @@ -193,16 +193,25 @@ struct net_device_operations { void ( * irq ) ( struct net_device *netdev, int enable ); }; +/** Network device error */ +struct net_device_error { + /** Error status code */ + int rc; + /** Error count */ + unsigned int count; +}; + +/** Maximum number of unique errors that we will keep track of */ +#define NETDEV_MAX_UNIQUE_ERRORS 4 + /** Network device statistics */ struct net_device_stats { - /** Count of successfully completed transmissions */ - unsigned int tx_ok; - /** Count of transmission errors */ - unsigned int tx_err; - /** Count of successfully received packets */ - unsigned int rx_ok; - /** Count of reception errors */ - unsigned int rx_err; + /** Count of successful completions */ + unsigned int good; + /** Count of error completions */ + unsigned int bad; + /** Error breakdowns */ + struct net_device_error errors[NETDEV_MAX_UNIQUE_ERRORS]; }; /** @@ -220,6 +229,8 @@ struct net_device { struct refcnt refcnt; /** List of network devices */ struct list_head list; + /** List of open network devices */ + struct list_head open_list; /** Name of this network device */ char name[8]; /** Underlying hardware device */ @@ -241,12 +252,19 @@ struct net_device { * This is the bitwise-OR of zero or more NETDEV_XXX constants. */ unsigned int state; + /** Maximum packet length + * + * This length includes any link-layer headers. + */ + size_t max_pkt_len; /** TX packet queue */ struct list_head tx_queue; /** RX packet queue */ struct list_head rx_queue; - /** Device statistics */ - struct net_device_stats stats; + /** TX statistics */ + struct net_device_stats tx_stats; + /** RX statistics */ + struct net_device_stats rx_stats; /** Configuration settings applicable to this device */ struct simple_settings settings; @@ -408,6 +426,7 @@ 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_location ( unsigned int bus_type, unsigned int location ); +extern struct net_device * last_opened_netdev ( void ); extern int net_tx ( struct io_buffer *iobuf, struct net_device *netdev, struct net_protocol *net_protocol, const void *ll_dest ); extern int net_rx ( struct io_buffer *iobuf, struct net_device *netdev, diff --git a/gpxe/src/include/gpxe/null_nap.h b/gpxe/src/include/gpxe/null_nap.h new file mode 100644 index 00000000..6dd0cda3 --- /dev/null +++ b/gpxe/src/include/gpxe/null_nap.h @@ -0,0 +1,21 @@ +#ifndef _GPXE_NULL_NAP_H +#define _GPXE_NULL_NAP_H + +/** @file + * + * Null CPU sleeping + * + */ + +#ifdef NAP_NULL +#define NAP_PREFIX_null +#else +#define NAP_PREFIX_null __null_ +#endif + +static inline __always_inline void +NAP_INLINE ( null, cpu_nap ) ( void ) { + /* Do nothing */ +} + +#endif /* _GPXE_NULL_NAP_H */ diff --git a/gpxe/src/include/gpxe/open.h b/gpxe/src/include/gpxe/open.h index beab0a1f..81d5fc24 100644 --- a/gpxe/src/include/gpxe/open.h +++ b/gpxe/src/include/gpxe/open.h @@ -9,10 +9,10 @@ #include <stdarg.h> #include <gpxe/tables.h> +#include <gpxe/socket.h> struct xfer_interface; struct uri; -struct sockaddr; /** Location types */ enum { diff --git a/gpxe/src/include/gpxe/pci.h b/gpxe/src/include/gpxe/pci.h index 90721574..1ccdb100 100644 --- a/gpxe/src/include/gpxe/pci.h +++ b/gpxe/src/include/gpxe/pci.h @@ -19,7 +19,7 @@ #include <stdint.h> #include <gpxe/device.h> #include <gpxe/tables.h> -#include <pci_io.h> +#include <gpxe/pci_io.h> #include "pci_ids.h" /* diff --git a/gpxe/src/include/gpxe/pci_io.h b/gpxe/src/include/gpxe/pci_io.h new file mode 100644 index 00000000..365166c8 --- /dev/null +++ b/gpxe/src/include/gpxe/pci_io.h @@ -0,0 +1,122 @@ +#ifndef _GPXE_PCI_IO_H +#define _GPXE_PCI_IO_H + +/** @file + * + * PCI I/O API + * + */ + +#include <stdint.h> +#include <gpxe/api.h> +#include <config/ioapi.h> + +/** + * Calculate static inline PCI I/O API function name + * + * @v _prefix Subsystem prefix + * @v _api_func API function + * @ret _subsys_func Subsystem API function + */ +#define PCIAPI_INLINE( _subsys, _api_func ) \ + SINGLE_API_INLINE ( PCIAPI_PREFIX_ ## _subsys, _api_func ) + +/** + * Provide a PCI I/O API implementation + * + * @v _prefix Subsystem prefix + * @v _api_func API function + * @v _func Implementing function + */ +#define PROVIDE_PCIAPI( _subsys, _api_func, _func ) \ + PROVIDE_SINGLE_API ( PCIAPI_PREFIX_ ## _subsys, _api_func, _func ) + +/** + * Provide a static inline PCI I/O API implementation + * + * @v _prefix Subsystem prefix + * @v _api_func API function + */ +#define PROVIDE_PCIAPI_INLINE( _subsys, _api_func ) \ + PROVIDE_SINGLE_API_INLINE ( PCIAPI_PREFIX_ ## _subsys, _api_func ) + +/* Include all architecture-independent I/O API headers */ +#include <gpxe/efi/efi_pci.h> + +/* Include all architecture-dependent I/O API headers */ +#include <bits/pci_io.h> + +/** + * Determine maximum PCI bus number within system + * + * @ret max_bus Maximum bus number + */ +int pci_max_bus ( void ); + +/** + * 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 + */ +int pci_read_config_byte ( struct pci_device *pci, unsigned int where, + uint8_t *value ); + +/** + * Read 16-bit 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 + */ +int pci_read_config_word ( struct pci_device *pci, unsigned int where, + uint16_t *value ); + +/** + * Read 32-bit 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 + */ +int pci_read_config_dword ( struct pci_device *pci, unsigned int where, + uint32_t *value ); + +/** + * 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 + */ +int pci_write_config_byte ( struct pci_device *pci, unsigned int where, + uint8_t value ); + +/** + * Write 16-bit 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 + */ +int pci_write_config_word ( struct pci_device *pci, unsigned int where, + uint16_t value ); + +/** + * Write 32-bit 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 + */ +int pci_write_config_dword ( struct pci_device *pci, unsigned int where, + uint32_t value ); + +#endif /* _GPXE_PCI_IO_H */ diff --git a/gpxe/src/include/gpxe/resolv.h b/gpxe/src/include/gpxe/resolv.h index 7c1ee6e2..e73c8201 100644 --- a/gpxe/src/include/gpxe/resolv.h +++ b/gpxe/src/include/gpxe/resolv.h @@ -10,8 +10,8 @@ #include <gpxe/refcnt.h> #include <gpxe/interface.h> #include <gpxe/tables.h> +#include <gpxe/socket.h> -struct sockaddr; struct resolv_interface; /** Name resolution interface operations */ diff --git a/gpxe/src/include/gpxe/retry.h b/gpxe/src/include/gpxe/retry.h index ec57db9e..1e7fde4c 100644 --- a/gpxe/src/include/gpxe/retry.h +++ b/gpxe/src/include/gpxe/retry.h @@ -19,6 +19,8 @@ struct retry_timer { /** List of active timers */ struct list_head list; + /** Timer is currently running */ + unsigned int running; /** Timeout value (in ticks) */ unsigned long timeout; /** Minimum timeout value (in ticks) @@ -31,10 +33,7 @@ struct retry_timer { * A value of zero means "use default timeout." */ unsigned long max_timeout; - /** Start time (in ticks) - * - * A start time of zero indicates a stopped timer. - */ + /** Start time (in ticks) */ unsigned long start; /** Retry count */ unsigned int count; @@ -74,7 +73,7 @@ static inline void start_timer_nodelay ( struct retry_timer *timer ) { */ static inline __attribute__ (( always_inline )) unsigned long timer_running ( struct retry_timer *timer ) { - return ( timer->start ); + return ( timer->running ); } #endif /* _GPXE_RETRY_H */ diff --git a/gpxe/src/include/gpxe/rotate.h b/gpxe/src/include/gpxe/rotate.h new file mode 100644 index 00000000..42ec7196 --- /dev/null +++ b/gpxe/src/include/gpxe/rotate.h @@ -0,0 +1,27 @@ +#ifndef _GPXE_ROTATE_H +#define _GPXE_ROTATE_H + +/** @file + * + * Bit operations + */ + +#include <stdint.h> + +static inline uint32_t rol32 ( uint32_t data, unsigned int rotation ) { + return ( ( data << rotation ) | ( data >> ( 32 - rotation ) ) ); +} + +static inline uint32_t ror32 ( uint32_t data, unsigned int rotation ) { + return ( ( data >> rotation ) | ( data << ( 32 - rotation ) ) ); +} + +static inline uint64_t rol64 ( uint64_t data, unsigned int rotation ) { + return ( ( data << rotation ) | ( data >> ( 64 - rotation ) ) ); +} + +static inline uint64_t ror64 ( uint64_t data, unsigned int rotation ) { + return ( ( data >> rotation ) | ( data << ( 64 - rotation ) ) ); +} + +#endif /* _GPXE_ROTATE_H */ diff --git a/gpxe/src/include/gpxe/sanboot.h b/gpxe/src/include/gpxe/sanboot.h new file mode 100644 index 00000000..ea26a356 --- /dev/null +++ b/gpxe/src/include/gpxe/sanboot.h @@ -0,0 +1,14 @@ +#ifndef _GPXE_SANBOOT_H +#define _GPXE_SANBOOT_H + +#include <gpxe/tables.h> + +struct sanboot_protocol { + const char *prefix; + int ( * boot ) ( const char *root_path ); +}; + +#define __sanboot_protocol \ + __table ( struct sanboot_protocol, sanboot_protocols, 01 ) + +#endif /* _GPXE_SANBOOT_H */ diff --git a/gpxe/src/include/gpxe/settings.h b/gpxe/src/include/gpxe/settings.h index ee7dacee..9e62cdea 100644 --- a/gpxe/src/include/gpxe/settings.h +++ b/gpxe/src/include/gpxe/settings.h @@ -72,6 +72,14 @@ 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(), and can be used to + * avoid e.g. attempting to retrieve the subnet mask from + * SMBIOS, or the system UUID from DHCP. + */ + unsigned int tag_magic; /** Parent settings block */ struct settings *parent; /** Sibling settings blocks */ @@ -167,6 +175,9 @@ extern int fetch_setting_len ( struct settings *settings, extern int fetch_string_setting ( struct settings *settings, struct setting *setting, char *data, size_t len ); +extern int fetch_string_setting_copy ( struct settings *settings, + struct setting *setting, + char **data ); extern int fetch_ipv4_setting ( struct settings *settings, struct setting *setting, struct in_addr *inp ); extern int fetch_int_setting ( struct settings *settings, @@ -207,16 +218,17 @@ extern struct setting ip_setting __setting; extern struct setting netmask_setting __setting; extern struct setting gateway_setting __setting; extern struct setting dns_setting __setting; +extern struct setting domain_setting __setting; extern struct setting hostname_setting __setting; extern struct setting filename_setting __setting; extern struct setting root_path_setting __setting; extern struct setting username_setting __setting; extern struct setting password_setting __setting; extern struct setting priority_setting __setting; -extern struct setting bios_drive_setting __setting; extern struct setting uuid_setting __setting; extern struct setting next_server_setting __setting; extern struct setting mac_setting __setting; +extern struct setting user_class_setting __setting; /** * Initialise a settings block @@ -225,16 +237,19 @@ extern struct setting mac_setting __setting; * @v op Settings block operations * @v refcnt Containing object reference counter, or NULL * @v name Settings block name + * @v tag_magic Tag magic */ static inline void settings_init ( struct settings *settings, struct settings_operations *op, struct refcnt *refcnt, - const char *name ) { + const char *name, + unsigned int tag_magic ) { INIT_LIST_HEAD ( &settings->siblings ); INIT_LIST_HEAD ( &settings->children ); settings->op = op; settings->refcnt = refcnt; settings->name = name; + settings->tag_magic = tag_magic; } /** @@ -248,7 +263,7 @@ static inline void simple_settings_init ( struct simple_settings *simple, struct refcnt *refcnt, const char *name ) { settings_init ( &simple->settings, &simple_settings_operations, - refcnt, name ); + refcnt, name, 0 ); } /** @@ -289,4 +304,16 @@ static inline int delete_named_setting ( const char *name ) { return storef_named_setting ( name, NULL ); } +/** + * Check existence of 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 ); +} + #endif /* _GPXE_SETTINGS_H */ diff --git a/gpxe/src/include/gpxe/smbios.h b/gpxe/src/include/gpxe/smbios.h new file mode 100644 index 00000000..2b0fcbd1 --- /dev/null +++ b/gpxe/src/include/gpxe/smbios.h @@ -0,0 +1,140 @@ +#ifndef _GPXE_SMBIOS_H +#define _GPXE_SMBIOS_H + +/** @file + * + * System Management BIOS + * + */ + +#include <stdint.h> +#include <gpxe/api.h> +#include <config/general.h> +#include <gpxe/uaccess.h> + +/** + * Provide an SMBIOS API implementation + * + * @v _prefix Subsystem prefix + * @v _api_func API function + * @v _func Implementing function + */ +#define PROVIDE_SMBIOS( _subsys, _api_func, _func ) \ + PROVIDE_SINGLE_API ( SMBIOS_PREFIX_ ## _subsys, _api_func, _func ) + +/* Include all architecture-independent SMBIOS API headers */ +#include <gpxe/efi/efi_smbios.h> + +/* Include all architecture-dependent SMBIOS API headers */ +#include <bits/smbios.h> + +/** Signature for SMBIOS entry point */ +#define SMBIOS_SIGNATURE \ + ( ( '_' << 0 ) + ( 'S' << 8 ) + ( 'M' << 16 ) + ( '_' << 24 ) ) + +/** + * SMBIOS entry point + * + * This is the single table which describes the list of SMBIOS + * structures. It is located by scanning through the BIOS segment. + */ +struct smbios_entry { + /** Signature + * + * Must be equal to SMBIOS_SIGNATURE + */ + uint32_t signature; + /** Checksum */ + uint8_t checksum; + /** Length */ + uint8_t len; + /** Major version */ + uint8_t major; + /** Minor version */ + uint8_t minor; + /** Maximum structure size */ + uint16_t max; + /** Entry point revision */ + uint8_t revision; + /** Formatted area */ + uint8_t formatted[5]; + /** DMI Signature */ + uint8_t dmi_signature[5]; + /** DMI checksum */ + uint8_t dmi_checksum; + /** Structure table length */ + uint16_t smbios_len; + /** Structure table address */ + uint32_t smbios_address; + /** Number of SMBIOS structures */ + uint16_t smbios_count; + /** BCD revision */ + uint8_t bcd_revision; +} __attribute__ (( packed )); + +/** An SMBIOS structure header */ +struct smbios_header { + /** Type */ + uint8_t type; + /** Length */ + uint8_t len; + /** Handle */ + uint16_t handle; +} __attribute__ (( packed )); + +/** SMBIOS structure descriptor */ +struct smbios_structure { + /** Copy of SMBIOS structure header */ + struct smbios_header header; + /** Offset of structure within SMBIOS */ + size_t offset; + /** Length of strings section */ + size_t strings_len; +}; + +/** SMBIOS system information structure */ +struct smbios_system_information { + /** SMBIOS structure header */ + struct smbios_header header; + /** Manufacturer string */ + uint8_t manufacturer; + /** Product string */ + uint8_t product; + /** Version string */ + uint8_t version; + /** Serial number string */ + uint8_t serial; + /** UUID */ + uint8_t uuid[16]; + /** Wake-up type */ + uint8_t wakeup; +} __attribute__ (( packed )); + +/** SMBIOS system information structure type */ +#define SMBIOS_TYPE_SYSTEM_INFORMATION 1 + +/** + * SMBIOS entry point descriptor + * + * This contains the information from the SMBIOS entry point that we + * care about. + */ +struct smbios { + /** Start of SMBIOS structures */ + userptr_t address; + /** Length of SMBIOS structures */ + size_t len; + /** Number of SMBIOS structures */ + unsigned int count; +}; + +extern int find_smbios ( struct smbios *smbios ); +extern int find_smbios_structure ( unsigned int type, + 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 ); + +#endif /* _GPXE_SMBIOS_H */ diff --git a/gpxe/src/include/gpxe/socket.h b/gpxe/src/include/gpxe/socket.h index 9c7afb87..b683bed6 100644 --- a/gpxe/src/include/gpxe/socket.h +++ b/gpxe/src/include/gpxe/socket.h @@ -7,6 +7,8 @@ * */ +#include <stdint.h> + /** * @defgroup commtypes Communication semantics * @@ -14,12 +16,14 @@ */ /** Connection-based, reliable streams */ -#define SOCK_STREAM ( ( int ) TCP_SOCK_STREAM ) -extern char TCP_SOCK_STREAM[]; +extern int tcp_sock_stream; +#define TCP_SOCK_STREAM 0x1 +#define SOCK_STREAM tcp_sock_stream /** Connectionless, unreliable streams */ -#define SOCK_DGRAM ( ( int ) UDP_SOCK_DGRAM ) -extern char UDP_SOCK_DGRAM[]; +extern int udp_sock_dgram; +#define UDP_SOCK_DGRAM 0x2 +#define SOCK_DGRAM udp_sock_dgram /** @} */ @@ -90,6 +94,6 @@ struct sockaddr { * family. */ char pad[ SA_LEN - sizeof ( sa_family_t ) ]; -}; +} __attribute__ (( may_alias )); #endif /* _GPXE_SOCKET_H */ diff --git a/gpxe/src/include/gpxe/tcpip.h b/gpxe/src/include/gpxe/tcpip.h index c0fadd23..da89530e 100644 --- a/gpxe/src/include/gpxe/tcpip.h +++ b/gpxe/src/include/gpxe/tcpip.h @@ -40,7 +40,7 @@ struct sockaddr_tcpip { */ char pad[ sizeof ( struct sockaddr ) - ( sizeof ( sa_family_t ) + sizeof ( uint16_t ) ) ]; -}; +} __attribute__ (( may_alias )); /** * A transport-layer protocol of the TCP/IP stack (eg. UDP, TCP, etc) @@ -82,6 +82,7 @@ struct tcpip_net_protocol { * * @v iobuf I/O buffer * @v tcpip_protocol Transport-layer protocol + * @v st_src Source address, or NULL to use default * @v st_dest Destination address * @v netdev Network device (or NULL to route automatically) * @v trans_csum Transport-layer checksum to complete, or NULL @@ -91,6 +92,7 @@ struct tcpip_net_protocol { */ int ( * tx ) ( struct io_buffer *iobuf, struct tcpip_protocol *tcpip_protocol, + struct sockaddr_tcpip *st_src, struct sockaddr_tcpip *st_dest, struct net_device *netdev, uint16_t *trans_csum ); @@ -107,7 +109,8 @@ struct tcpip_net_protocol { 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_tx ( struct io_buffer *iobuf, struct tcpip_protocol *tcpip, +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 ); diff --git a/gpxe/src/include/gpxe/timer.h b/gpxe/src/include/gpxe/timer.h index b7057225..862d87b3 100644 --- a/gpxe/src/include/gpxe/timer.h +++ b/gpxe/src/include/gpxe/timer.h @@ -1,41 +1,74 @@ -#ifndef GPXE_TIMER_H -#define GPXE_TIMER_H +#ifndef _GPXE_TIMER_H +#define _GPXE_TIMER_H -#include <stddef.h> -#include <gpxe/tables.h> +/** @file + * + * gPXE timer API + * + * The timer API provides udelay() for fixed delays, and currticks() + * for a monotonically increasing tick counter. + */ -typedef unsigned long tick_t; +#include <gpxe/api.h> +#include <config/timer.h> -#define MSECS_IN_SEC (1000) -#define USECS_IN_SEC (1000*1000) -#define USECS_IN_MSEC (1000) +/** + * Calculate static inline timer API function name + * + * @v _prefix Subsystem prefix + * @v _api_func API function + * @ret _subsys_func Subsystem API function + */ +#define TIMER_INLINE( _subsys, _api_func ) \ + SINGLE_API_INLINE ( TIMER_PREFIX_ ## _subsys, _api_func ) -#define TICKS_PER_SEC USECS_IN_SEC +/** + * Provide a timer API implementation + * + * @v _prefix Subsystem prefix + * @v _api_func API function + * @v _func Implementing function + */ +#define PROVIDE_TIMER( _subsys, _api_func, _func ) \ + PROVIDE_SINGLE_API ( TIMER_PREFIX_ ## _subsys, _api_func, _func ) -extern tick_t currticks ( void ); +/** + * Provide a static inline timer API implementation + * + * @v _prefix Subsystem prefix + * @v _api_func API function + */ +#define PROVIDE_TIMER_INLINE( _subsys, _api_func ) \ + PROVIDE_SINGLE_API_INLINE ( TIMER_PREFIX_ ## _subsys, _api_func ) -extern void generic_currticks_udelay ( unsigned int usecs ); +/* Include all architecture-independent I/O API headers */ +#include <gpxe/efi/efi_timer.h> -/** A timer */ -struct timer { - /** Initialise timer - * - * @ret rc Return status code - */ - int ( * init ) ( void ); - /** Read current time - * - * @ret ticks Current time, in ticks - */ - tick_t ( * currticks ) ( void ); - /** Delay - * - * @v usecs Time to delay, in microseconds - */ - void ( * udelay ) ( unsigned int usecs ); -}; +/* Include all architecture-dependent I/O API headers */ +#include <bits/timer.h> -#define __timer( order ) __table ( struct timer, timers, order ) +/** + * Delay for a fixed number of microseconds + * + * @v usecs Number of microseconds for which to delay + */ +void udelay ( unsigned long usecs ); -#endif /* GPXE_TIMER_H */ +/** + * Get current system time in ticks + * + * @ret ticks Current time, in ticks + */ +unsigned long currticks ( void ); +/** + * Get number of ticks per second + * + * @ret ticks_per_sec Number of ticks per second + */ +unsigned long ticks_per_sec ( void ); + +/** Number of ticks per second */ +#define TICKS_PER_SEC ( ticks_per_sec() ) + +#endif /* _GPXE_TIMER_H */ diff --git a/gpxe/src/include/gpxe/tls.h b/gpxe/src/include/gpxe/tls.h index a8cf16ef..182bc49d 100644 --- a/gpxe/src/include/gpxe/tls.h +++ b/gpxe/src/include/gpxe/tls.h @@ -14,6 +14,7 @@ #include <gpxe/crypto.h> #include <gpxe/md5.h> #include <gpxe/sha1.h> +#include <gpxe/x509.h> /** A TLS header */ struct tls_header { @@ -109,6 +110,22 @@ struct tls_cipherspec { void *mac_secret; }; +/** TLS pre-master secret */ +struct tls_pre_master_secret { + /** TLS version */ + uint16_t version; + /** Random data */ + uint8_t random[46]; +} __attribute__ (( packed )); + +/** TLS client random data */ +struct tls_client_random { + /** GMT Unix time */ + uint32_t gmt_unix_time; + /** Random data */ + uint8_t random[28]; +} __attribute__ (( packed )); + /** A TLS session */ struct tls_session { /** Reference counter */ @@ -128,23 +145,20 @@ struct tls_session { /** Next RX cipher specification */ struct tls_cipherspec rx_cipherspec_pending; /** Premaster secret */ - uint8_t pre_master_secret[48]; + struct tls_pre_master_secret pre_master_secret; /** Master secret */ uint8_t master_secret[48]; /** Server random bytes */ uint8_t server_random[32]; /** Client random bytes */ - uint8_t client_random[32]; + struct tls_client_random client_random; /** MD5 context for handshake verification */ uint8_t handshake_md5_ctx[MD5_CTX_SIZE]; /** SHA1 context for handshake verification */ uint8_t handshake_sha1_ctx[SHA1_CTX_SIZE]; /** Hack: server RSA public key */ - uint8_t *rsa_mod; - size_t rsa_mod_len; - uint8_t *rsa_pub_exp; - size_t rsa_pub_exp_len; + struct x509_rsa_public_key rsa; /** TX sequence number */ uint64_t tx_seq; diff --git a/gpxe/src/include/gpxe/uaccess.h b/gpxe/src/include/gpxe/uaccess.h index 05f89e03..33aaed18 100644 --- a/gpxe/src/include/gpxe/uaccess.h +++ b/gpxe/src/include/gpxe/uaccess.h @@ -19,9 +19,324 @@ * */ -#include <bits/uaccess.h> +#include <stdint.h> +#include <string.h> +#include <gpxe/api.h> +#include <config/ioapi.h> + +/** + * A pointer to a user buffer + * + */ +typedef unsigned long userptr_t; /** Equivalent of NULL for user pointers */ #define UNULL ( ( userptr_t ) 0 ) +/** + * @defgroup uaccess_trivial Trivial user access API implementations + * + * User access API implementations that can be used by environments in + * which virtual addresses allow access to all of memory. + * + * @{ + * + */ + +/** + * Convert virtual address to user pointer + * + * @v addr Virtual address + * @ret userptr User pointer + */ +static inline __always_inline userptr_t +trivial_virt_to_user ( volatile const void *addr ) { + return ( ( userptr_t ) addr ); +} + +/** + * Convert user pointer to virtual address + * + * @v userptr User pointer + * @v offset Offset from user pointer + * @ret addr Virtual address + * + * This operation is not available under all memory models. + */ +static inline __always_inline void * +trivial_user_to_virt ( userptr_t userptr, off_t offset ) { + return ( ( void * ) userptr + offset ); +} + +/** + * Add offset to user pointer + * + * @v userptr User pointer + * @v offset Offset + * @ret userptr New pointer value + */ +static inline __always_inline userptr_t +trivial_userptr_add ( userptr_t userptr, off_t offset ) { + return ( userptr + offset ); +} + +/** + * Copy data between user buffers + * + * @v dest Destination + * @v dest_off Destination offset + * @v src Source + * @v src_off Source offset + * @v len Length + */ +static inline __always_inline void +trivial_memcpy_user ( userptr_t dest, off_t dest_off, + userptr_t src, off_t src_off, size_t len ) { + memcpy ( ( ( void * ) dest + dest_off ), + ( ( void * ) src + src_off ), len ); +} + +/** + * Copy data between user buffers, allowing for overlap + * + * @v dest Destination + * @v dest_off Destination offset + * @v src Source + * @v src_off Source offset + * @v len Length + */ +static inline __always_inline void +trivial_memmove_user ( userptr_t dest, off_t dest_off, + userptr_t src, off_t src_off, size_t len ) { + memmove ( ( ( void * ) dest + dest_off ), + ( ( void * ) src + src_off ), len ); +} + +/** + * Fill user buffer with a constant byte + * + * @v buffer User buffer + * @v offset Offset within buffer + * @v c Constant byte with which to fill + * @v len Length + */ +static inline __always_inline void +trivial_memset_user ( userptr_t buffer, off_t offset, int c, size_t len ) { + memset ( ( ( void * ) buffer + offset ), c, len ); +} + +/** + * Find length of NUL-terminated string in user buffer + * + * @v buffer User buffer + * @v offset Offset within buffer + * @ret len Length of string (excluding NUL) + */ +static inline __always_inline size_t +trivial_strlen_user ( userptr_t buffer, off_t offset ) { + return strlen ( ( void * ) buffer + offset ); +} + +/** + * Find character in user buffer + * + * @v buffer User buffer + * @v offset Starting offset within buffer + * @v c Character to search for + * @v len Length of user buffer + * @ret offset Offset of character, or <0 if not found + */ +static inline __always_inline off_t +trivial_memchr_user ( userptr_t buffer, off_t offset, int c, size_t len ) { + void *found; + + found = memchr ( ( ( void * ) buffer + offset ), c, len ); + return ( found ? ( found - ( void * ) buffer ) : -1 ); +} + +/** @} */ + +/** + * Calculate static inline user access API function name + * + * @v _prefix Subsystem prefix + * @v _api_func API function + * @ret _subsys_func Subsystem API function + */ +#define UACCESS_INLINE( _subsys, _api_func ) \ + SINGLE_API_INLINE ( UACCESS_PREFIX_ ## _subsys, _api_func ) + +/** + * Provide an user access API implementation + * + * @v _prefix Subsystem prefix + * @v _api_func API function + * @v _func Implementing function + */ +#define PROVIDE_UACCESS( _subsys, _api_func, _func ) \ + PROVIDE_SINGLE_API ( UACCESS_PREFIX_ ## _subsys, _api_func, _func ) + +/** + * Provide a static inline user access API implementation + * + * @v _prefix Subsystem prefix + * @v _api_func API function + */ +#define PROVIDE_UACCESS_INLINE( _subsys, _api_func ) \ + PROVIDE_SINGLE_API_INLINE ( UACCESS_PREFIX_ ## _subsys, _api_func ) + +/* Include all architecture-independent user access API headers */ +#include <gpxe/efi/efi_uaccess.h> + +/* Include all architecture-dependent user access API headers */ +#include <bits/uaccess.h> + +/** + * Convert physical address to user pointer + * + * @v phys_addr Physical address + * @ret userptr User pointer + */ +userptr_t phys_to_user ( unsigned long phys_addr ); + +/** + * Convert user pointer to physical address + * + * @v userptr User pointer + * @v offset Offset from user pointer + * @ret phys_addr Physical address + */ +unsigned long user_to_phys ( userptr_t userptr, off_t offset ); + +/** + * Convert virtual address to user pointer + * + * @v addr Virtual address + * @ret userptr User pointer + */ +userptr_t virt_to_user ( volatile const void *addr ); + +/** + * Convert user pointer to virtual address + * + * @v userptr User pointer + * @v offset Offset from user pointer + * @ret addr Virtual address + * + * This operation is not available under all memory models. + */ +void * user_to_virt ( userptr_t userptr, off_t offset ); + +/** + * Add offset to user pointer + * + * @v userptr User pointer + * @v offset Offset + * @ret userptr New pointer value + */ +userptr_t userptr_add ( userptr_t userptr, off_t offset ); + +/** + * Convert virtual address to a physical address + * + * @v addr Virtual address + * @ret phys_addr Physical address + */ +static inline __always_inline unsigned long +virt_to_phys ( volatile const void *addr ) { + return user_to_phys ( virt_to_user ( addr ), 0 ); +} + +/** + * Convert physical address to a virtual address + * + * @v addr Virtual address + * @ret phys_addr Physical address + * + * This operation is not available under all memory models. + */ +static inline __always_inline void * phys_to_virt ( unsigned long phys_addr ) { + return user_to_virt ( phys_to_user ( phys_addr ), 0 ); +} + +/** + * Copy data between user buffers + * + * @v dest Destination + * @v dest_off Destination offset + * @v src Source + * @v src_off Source offset + * @v len Length + */ +void memcpy_user ( userptr_t dest, off_t dest_off, + userptr_t src, off_t src_off, size_t len ); + +/** + * Copy data to user buffer + * + * @v dest Destination + * @v dest_off Destination offset + * @v src Source + * @v len Length + */ +static inline __always_inline void +copy_to_user ( userptr_t dest, off_t dest_off, const void *src, size_t len ) { + memcpy_user ( dest, dest_off, virt_to_user ( src ), 0, len ); +} + +/** + * Copy data from user buffer + * + * @v dest Destination + * @v src Source + * @v src_off Source offset + * @v len Length + */ +static inline __always_inline void +copy_from_user ( void *dest, userptr_t src, off_t src_off, size_t len ) { + memcpy_user ( virt_to_user ( dest ), 0, src, src_off, len ); +} + +/** + * Copy data between user buffers, allowing for overlap + * + * @v dest Destination + * @v dest_off Destination offset + * @v src Source + * @v src_off Source offset + * @v len Length + */ +void memmove_user ( userptr_t dest, off_t dest_off, + userptr_t src, off_t src_off, size_t len ); + +/** + * Fill user buffer with a constant byte + * + * @v userptr User buffer + * @v offset Offset within buffer + * @v c Constant byte with which to fill + * @v len Length + */ +void memset_user ( userptr_t userptr, off_t offset, int c, size_t len ); + +/** + * Find length of NUL-terminated string in user buffer + * + * @v userptr User buffer + * @v offset Offset within buffer + * @ret len Length of string (excluding NUL) + */ +size_t strlen_user ( userptr_t userptr, off_t offset ); + +/** + * Find character in user buffer + * + * @v userptr User buffer + * @v offset Starting offset within buffer + * @v c Character to search for + * @v len Length of user buffer + * @ret offset Offset of character, or <0 if not found + */ +off_t memchr_user ( userptr_t userptr, off_t offset, int c, size_t len ); + #endif /* _GPXE_UACCESS_H */ diff --git a/gpxe/src/include/gpxe/udp.h b/gpxe/src/include/gpxe/udp.h index cb0e44eb..e515f650 100644 --- a/gpxe/src/include/gpxe/udp.h +++ b/gpxe/src/include/gpxe/udp.h @@ -15,7 +15,6 @@ #include <gpxe/if_ether.h> struct xfer_interface; -struct sockaddr; /** * UDP constants diff --git a/gpxe/src/include/gpxe/umalloc.h b/gpxe/src/include/gpxe/umalloc.h index 49ec22b4..e6fc7bf0 100644 --- a/gpxe/src/include/gpxe/umalloc.h +++ b/gpxe/src/include/gpxe/umalloc.h @@ -8,10 +8,59 @@ * */ +#include <gpxe/api.h> +#include <config/umalloc.h> #include <gpxe/uaccess.h> -extern userptr_t umalloc ( size_t size ); -extern userptr_t urealloc ( userptr_t ptr, size_t new_size ); -extern void ufree ( userptr_t ptr ); +/** + * Provide a user memory allocation API implementation + * + * @v _prefix Subsystem prefix + * @v _api_func API function + * @v _func Implementing function + */ +#define PROVIDE_UMALLOC( _subsys, _api_func, _func ) \ + PROVIDE_SINGLE_API ( UMALLOC_PREFIX_ ## _subsys, _api_func, _func ) + +/* Include all architecture-independent I/O API headers */ +#include <gpxe/efi/efi_umalloc.h> + +/* Include all architecture-dependent I/O API headers */ +#include <bits/umalloc.h> + +/** + * Reallocate external memory + * + * @v userptr Memory previously allocated by umalloc(), or UNULL + * @v new_size Requested size + * @ret userptr Allocated memory, or UNULL + * + * Calling realloc() with a new size of zero is a valid way to free a + * memory block. + */ +userptr_t urealloc ( userptr_t userptr, size_t new_size ); + +/** + * Allocate external memory + * + * @v size Requested size + * @ret userptr Memory, or UNULL + * + * Memory is guaranteed to be aligned to a page boundary. + */ +static inline __always_inline userptr_t umalloc ( size_t size ) { + return urealloc ( UNULL, size ); +} + +/** + * Free external memory + * + * @v userptr Memory allocated by umalloc(), or UNULL + * + * If @c ptr is UNULL, no action is taken. + */ +static inline __always_inline void ufree ( userptr_t userptr ) { + urealloc ( userptr, 0 ); +} #endif /* _GPXE_UMALLOC_H */ diff --git a/gpxe/src/include/gpxe/uri.h b/gpxe/src/include/gpxe/uri.h index 37f3aac9..3803868d 100644 --- a/gpxe/src/include/gpxe/uri.h +++ b/gpxe/src/include/gpxe/uri.h @@ -7,6 +7,7 @@ * */ +#include <stddef.h> #include <stdlib.h> #include <gpxe/refcnt.h> diff --git a/gpxe/src/drivers/net/virtio-pci.h b/gpxe/src/include/gpxe/virtio-pci.h index ba0604d5..f0c17e8d 100644 --- a/gpxe/src/drivers/net/virtio-pci.h +++ b/gpxe/src/include/gpxe/virtio-pci.h @@ -37,58 +37,61 @@ /* Virtio ABI version, this must match exactly */ #define VIRTIO_PCI_ABI_VERSION 0 -static inline u32 vp_get_features(struct nic *nic) +static inline u32 vp_get_features(unsigned int ioaddr) { - return inl(nic->ioaddr + VIRTIO_PCI_HOST_FEATURES); + return inl(ioaddr + VIRTIO_PCI_HOST_FEATURES); } -static inline void vp_set_features(struct nic *nic, u32 features) +static inline void vp_set_features(unsigned int ioaddr, u32 features) { - outl(features, nic->ioaddr + VIRTIO_PCI_GUEST_FEATURES); + outl(features, ioaddr + VIRTIO_PCI_GUEST_FEATURES); } -static inline void vp_get(struct nic *nic, unsigned offset, +static inline void vp_get(unsigned int ioaddr, unsigned offset, void *buf, unsigned len) { u8 *ptr = buf; unsigned i; for (i = 0; i < len; i++) - ptr[i] = inb(nic->ioaddr + VIRTIO_PCI_CONFIG + offset + i); + ptr[i] = inb(ioaddr + VIRTIO_PCI_CONFIG + offset + i); } -static inline u8 vp_get_status(struct nic *nic) +static inline u8 vp_get_status(unsigned int ioaddr) { - return inb(nic->ioaddr + VIRTIO_PCI_STATUS); + return inb(ioaddr + VIRTIO_PCI_STATUS); } -static inline void vp_set_status(struct nic *nic, u8 status) +static inline void vp_set_status(unsigned int ioaddr, u8 status) { if (status == 0) /* reset */ return; - outb(status, nic->ioaddr + VIRTIO_PCI_STATUS); + outb(status, ioaddr + VIRTIO_PCI_STATUS); } -static inline void vp_reset(struct nic *nic) +static inline void vp_reset(unsigned int ioaddr) { - outb(0, nic->ioaddr + VIRTIO_PCI_STATUS); - (void)inb(nic->ioaddr + VIRTIO_PCI_ISR); + outb(0, ioaddr + VIRTIO_PCI_STATUS); + (void)inb(ioaddr + VIRTIO_PCI_ISR); } -static inline void vp_notify(struct nic *nic, int queue_index) +static inline void vp_notify(unsigned int ioaddr, int queue_index) { - outw(queue_index, nic->ioaddr + VIRTIO_PCI_QUEUE_NOTIFY); + outw(queue_index, ioaddr + VIRTIO_PCI_QUEUE_NOTIFY); } -static inline void vp_del_vq(struct nic *nic, int queue_index) +static inline void vp_del_vq(unsigned int ioaddr, int queue_index) { /* select the queue */ - outw(queue_index, nic->ioaddr + VIRTIO_PCI_QUEUE_SEL); + outw(queue_index, ioaddr + VIRTIO_PCI_QUEUE_SEL); /* deactivate the queue */ - outl(0, nic->ioaddr + VIRTIO_PCI_QUEUE_PFN); + outl(0, ioaddr + VIRTIO_PCI_QUEUE_PFN); } + +int vp_find_vq(unsigned int ioaddr, int queue_index, + struct vring_virtqueue *vq); #endif /* _VIRTIO_PCI_H_ */ diff --git a/gpxe/src/drivers/net/virtio-ring.h b/gpxe/src/include/gpxe/virtio-ring.h index 33060b11..e96dd371 100644 --- a/gpxe/src/drivers/net/virtio-ring.h +++ b/gpxe/src/include/gpxe/virtio-ring.h @@ -58,6 +58,29 @@ struct vring { struct vring_used *used; }; +#define vring_size(num) \ + (((((sizeof(struct vring_desc) * num) + \ + (sizeof(struct vring_avail) + sizeof(u16) * num)) \ + + PAGE_MASK) & ~PAGE_MASK) + \ + (sizeof(struct vring_used) + sizeof(struct vring_used_elem) * num)) + +typedef unsigned char virtio_queue_t[PAGE_MASK + vring_size(MAX_QUEUE_NUM)]; + +struct vring_virtqueue { + virtio_queue_t queue; + struct vring vring; + u16 free_head; + u16 last_used_idx; + u16 vdata[MAX_QUEUE_NUM]; + /* PCI */ + int queue_index; +}; + +struct vring_list { + char *addr; + unsigned int length; +}; + static inline void vring_init(struct vring *vr, unsigned int num, unsigned char *queue) { @@ -85,9 +108,35 @@ static inline void vring_init(struct vring *vr, vr->desc[i].next = 0; } -#define vring_size(num) \ - (((((sizeof(struct vring_desc) * num) + \ - (sizeof(struct vring_avail) + sizeof(u16) * num)) \ - + PAGE_MASK) & ~PAGE_MASK) + \ - (sizeof(struct vring_used) + sizeof(struct vring_used_elem) * num)) +static inline void vring_enable_cb(struct vring_virtqueue *vq) +{ + vq->vring.avail->flags &= ~VRING_AVAIL_F_NO_INTERRUPT; +} + +static inline void vring_disable_cb(struct vring_virtqueue *vq) +{ + vq->vring.avail->flags |= VRING_AVAIL_F_NO_INTERRUPT; +} + + +/* + * vring_more_used + * + * is there some used buffers ? + * + */ + +static inline int vring_more_used(struct vring_virtqueue *vq) +{ + wmb(); + return vq->last_used_idx != vq->vring.used->idx; +} + +void vring_detach(struct vring_virtqueue *vq, unsigned int head); +int vring_get_buf(struct vring_virtqueue *vq, unsigned int *len); +void vring_add_buf(struct vring_virtqueue *vq, struct vring_list list[], + unsigned int out, unsigned int in, + int index, int num_added); +void vring_kick(unsigned int ioaddr, struct vring_virtqueue *vq, int num_added); + #endif /* _VIRTIO_RING_H_ */ diff --git a/gpxe/src/include/gpxe/x509.h b/gpxe/src/include/gpxe/x509.h new file mode 100644 index 00000000..071e1de5 --- /dev/null +++ b/gpxe/src/include/gpxe/x509.h @@ -0,0 +1,39 @@ +#ifndef _GPXE_X509_H +#define _GPXE_X509_H + +/** @file + * + * X.509 certificates + * + */ + +#include <stdint.h> + +struct asn1_cursor; + +/** An X.509 RSA public key */ +struct x509_rsa_public_key { + /** Modulus */ + uint8_t *modulus; + /** Modulus length */ + size_t modulus_len; + /** Exponent */ + uint8_t *exponent; + /** Exponent length */ + size_t exponent_len; +}; + +/** + * Free X.509 RSA public key + * + * @v rsa_pubkey RSA public key + */ +static inline void +x509_free_rsa_public_key ( struct x509_rsa_public_key *rsa_pubkey ) { + free ( rsa_pubkey->modulus ); +} + +extern int x509_rsa_public_key ( const struct asn1_cursor *certificate, + struct x509_rsa_public_key *rsa_pubkey ); + +#endif /* _GPXE_X509_H */ diff --git a/gpxe/src/include/gpxe/xfer.h b/gpxe/src/include/gpxe/xfer.h index 9575bf69..e592fa38 100644 --- a/gpxe/src/include/gpxe/xfer.h +++ b/gpxe/src/include/gpxe/xfer.h @@ -149,8 +149,8 @@ extern int xfer_deliver_raw ( struct xfer_interface *xfer, const void *data, size_t len ); extern int xfer_vprintf ( struct xfer_interface *xfer, const char *format, va_list args ); -extern int xfer_printf ( struct xfer_interface *xfer, - const char *format, ... ); +extern int __attribute__ (( format ( printf, 2, 3 ) )) +xfer_printf ( struct xfer_interface *xfer, const char *format, ... ); extern int xfer_seek ( struct xfer_interface *xfer, off_t offset, int whence ); extern void ignore_xfer_close ( struct xfer_interface *xfer, int rc ); diff --git a/gpxe/src/include/nic.h b/gpxe/src/include/nic.h index 65e4be71..186b2ea4 100644 --- a/gpxe/src/include/nic.h +++ b/gpxe/src/include/nic.h @@ -17,6 +17,7 @@ #include <gpxe/isa.h> #include <gpxe/eisa.h> #include <gpxe/mca.h> +#include <gpxe/io.h> #include "dhcp.h" typedef enum { diff --git a/gpxe/src/include/stddef.h b/gpxe/src/include/stddef.h index 6f91d219..11ea9345 100644 --- a/gpxe/src/include/stddef.h +++ b/gpxe/src/include/stddef.h @@ -15,4 +15,10 @@ const typeof( ((type *)0)->member ) *__mptr = (ptr); \ (type *)( (char *)__mptr - offsetof(type,member) );}) +/* __WCHAR_TYPE__ is defined by gcc and will change if -fshort-wchar is used */ +#ifndef __WCHAR_TYPE__ +#define __WCHAR_TYPE__ long int +#endif +typedef __WCHAR_TYPE__ wchar_t; + #endif /* STDDEF_H */ diff --git a/gpxe/src/include/stdlib.h b/gpxe/src/include/stdlib.h index ae996962..838a22ac 100644 --- a/gpxe/src/include/stdlib.h +++ b/gpxe/src/include/stdlib.h @@ -68,5 +68,6 @@ static inline void srand ( unsigned int seed ) { */ extern int system ( const char *command ); +extern __asmcall int main ( void ); #endif /* STDLIB_H */ diff --git a/gpxe/src/include/unistd.h b/gpxe/src/include/unistd.h index 7c44a0ce..dc1f67f6 100644 --- a/gpxe/src/include/unistd.h +++ b/gpxe/src/include/unistd.h @@ -4,7 +4,6 @@ #include <stddef.h> #include <stdarg.h> -unsigned int sleep ( unsigned int seconds ); extern int execv ( const char *command, char * const argv[] ); /** @@ -22,10 +21,21 @@ extern int execv ( const char *command, char * const argv[] ); rc; \ } ) -void udelay(unsigned int usecs); -void mdelay(unsigned int msecs); +/* Pick up udelay() */ +#include <gpxe/timer.h> -#define usleep(x) udelay(x) +/* + * sleep() prototype is defined by POSIX.1. usleep() prototype is + * defined by 4.3BSD. udelay() and mdelay() prototypes are chosen to + * be reasonably sensible. + * + */ + +extern unsigned int sleep ( unsigned int seconds ); +extern void mdelay ( unsigned long msecs ); +static inline __always_inline void usleep ( unsigned long usecs ) { + udelay ( usecs ); +} #endif /* _UNISTD_H */ diff --git a/gpxe/src/include/usr/aoeboot.h b/gpxe/src/include/usr/aoeboot.h deleted file mode 100644 index 0421ebcc..00000000 --- a/gpxe/src/include/usr/aoeboot.h +++ /dev/null @@ -1,6 +0,0 @@ -#ifndef _USR_AOEBOOT_H -#define _USR_AOEBOOT_H - -extern int aoeboot ( const char *root_path ); - -#endif /* _USR_AOEBOOT_H */ diff --git a/gpxe/src/include/usr/autoboot.h b/gpxe/src/include/usr/autoboot.h index b64cbb8e..1e9647c3 100644 --- a/gpxe/src/include/usr/autoboot.h +++ b/gpxe/src/include/usr/autoboot.h @@ -7,9 +7,15 @@ * */ +#include <gpxe/in.h> +struct net_device; + extern int shutdown_exit_flags; extern void autoboot ( void ); +extern int boot_next_server_and_filename ( struct in_addr next_server, + const char *filename ); extern int boot_root_path ( const char *root_path ); +extern int pxe_menu_boot ( struct net_device *netdev ); #endif /* _USR_AUTOBOOT_H */ diff --git a/gpxe/src/include/usr/dhcpmgmt.h b/gpxe/src/include/usr/dhcpmgmt.h index 2757a1c1..0f275600 100644 --- a/gpxe/src/include/usr/dhcpmgmt.h +++ b/gpxe/src/include/usr/dhcpmgmt.h @@ -9,6 +9,7 @@ struct net_device; -int dhcp ( struct net_device *netdev ); +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/gpxe/src/include/usr/iscsiboot.h b/gpxe/src/include/usr/iscsiboot.h deleted file mode 100644 index b17951d5..00000000 --- a/gpxe/src/include/usr/iscsiboot.h +++ /dev/null @@ -1,6 +0,0 @@ -#ifndef _USR_ISCSIBOOT_H -#define _USR_ISCSIBOOT_H - -extern int iscsiboot ( const char *root_path ); - -#endif /* _USR_ISCSIBOOT_H */ diff --git a/gpxe/src/interface/efi/efi_console.c b/gpxe/src/interface/efi/efi_console.c new file mode 100644 index 00000000..b78de618 --- /dev/null +++ b/gpxe/src/interface/efi/efi_console.c @@ -0,0 +1,274 @@ +/* + * 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., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +#include <stddef.h> +#include <assert.h> +#include <gpxe/efi/efi.h> +#include <gpxe/ansiesc.h> +#include <console.h> + +#define ATTR_BOLD 0x08 + +#define ATTR_FCOL_MASK 0x07 +#define ATTR_FCOL_BLACK 0x00 +#define ATTR_FCOL_BLUE 0x01 +#define ATTR_FCOL_GREEN 0x02 +#define ATTR_FCOL_CYAN 0x03 +#define ATTR_FCOL_RED 0x04 +#define ATTR_FCOL_MAGENTA 0x05 +#define ATTR_FCOL_YELLOW 0x06 +#define ATTR_FCOL_WHITE 0x07 + +#define ATTR_BCOL_MASK 0x70 +#define ATTR_BCOL_BLACK 0x00 +#define ATTR_BCOL_BLUE 0x10 +#define ATTR_BCOL_GREEN 0x20 +#define ATTR_BCOL_CYAN 0x30 +#define ATTR_BCOL_RED 0x40 +#define ATTR_BCOL_MAGENTA 0x50 +#define ATTR_BCOL_YELLOW 0x60 +#define ATTR_BCOL_WHITE 0x70 + +#define ATTR_DEFAULT ATTR_FCOL_WHITE + +/** Current character attribute */ +static unsigned int efi_attr = ATTR_DEFAULT; + +/** + * Handle ANSI CUP (cursor position) + * + * @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[] ) { + EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL *conout = efi_systab->ConOut; + int cx = ( params[1] - 1 ); + int cy = ( params[0] - 1 ); + + if ( cx < 0 ) + cx = 0; + if ( cy < 0 ) + cy = 0; + + conout->SetCursorPosition ( conout, cx, cy ); +} + +/** + * Handle ANSI ED (erase in page) + * + * @v count Parameter count + * @v params[0] Region to erase + */ +static void efi_handle_ed ( 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 */ + assert ( params[0] == ANSIESC_ED_ALL ); + + conout->ClearScreen ( conout ); +} + +/** + * Handle ANSI SGR (set graphics rendition) + * + * @v count Parameter count + * @v params List of graphic rendition aspects + */ +static void efi_handle_sgr ( 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, + ATTR_FCOL_YELLOW, ATTR_FCOL_BLUE, ATTR_FCOL_MAGENTA, + ATTR_FCOL_CYAN, ATTR_FCOL_WHITE, + ATTR_FCOL_WHITE, ATTR_FCOL_WHITE /* defaults */ + }; + static const uint8_t efi_attr_bcols[10] = { + ATTR_BCOL_BLACK, ATTR_BCOL_RED, ATTR_BCOL_GREEN, + ATTR_BCOL_YELLOW, ATTR_BCOL_BLUE, ATTR_BCOL_MAGENTA, + ATTR_BCOL_CYAN, ATTR_BCOL_WHITE, + ATTR_BCOL_BLACK, ATTR_BCOL_BLACK /* defaults */ + }; + unsigned int i; + int aspect; + + for ( i = 0 ; i < count ; i++ ) { + aspect = params[i]; + if ( aspect == 0 ) { + efi_attr = ATTR_DEFAULT; + } else if ( aspect == 1 ) { + efi_attr |= ATTR_BOLD; + } else if ( aspect == 22 ) { + efi_attr &= ~ATTR_BOLD; + } else if ( ( aspect >= 30 ) && ( aspect <= 39 ) ) { + efi_attr &= ~ATTR_FCOL_MASK; + efi_attr |= efi_attr_fcols[ aspect - 30 ]; + } else if ( ( aspect >= 40 ) && ( aspect <= 49 ) ) { + efi_attr &= ~ATTR_BCOL_MASK; + efi_attr |= efi_attr_bcols[ aspect - 40 ]; + } + } + + conout->SetAttribute ( conout, efi_attr ); +} + +/** EFI console ANSI escape sequence handlers */ +static struct ansiesc_handler efi_ansiesc_handlers[] = { + { ANSIESC_CUP, efi_handle_cup }, + { ANSIESC_ED, efi_handle_ed }, + { ANSIESC_SGR, efi_handle_sgr }, + { 0, NULL } +}; + +/** EFI console ANSI escape sequence context */ +static struct ansiesc_context efi_ansiesc_ctx = { + .handlers = efi_ansiesc_handlers, +}; + +/** + * Print a character to EFI console + * + * @v character Character to be printed + */ +static void efi_putchar ( int character ) { + EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL *conout = efi_systab->ConOut; + wchar_t wstr[] = { character, 0 }; + + /* Intercept ANSI escape sequences */ + character = ansiesc_process ( &efi_ansiesc_ctx, character ); + if ( character < 0 ) + return; + + conout->OutputString ( conout, wstr ); +} + +/** + * Pointer to current ANSI output sequence + * + * While we are in the middle of returning an ANSI sequence for a + * special key, this will point to the next character to return. When + * not in the middle of such a sequence, this will point to a NUL + * (note: not "will be NULL"). + */ +static const char *ansi_input = ""; + +/** Mapping from EFI scan codes to ANSI escape sequences */ +static const char *ansi_sequences[] = { + [SCAN_UP] = "[A", + [SCAN_DOWN] = "[B", + [SCAN_RIGHT] = "[C", + [SCAN_LEFT] = "[D", + [SCAN_HOME] = "[H", + [SCAN_END] = "[F", + [SCAN_INSERT] = "[2~", + /* EFI translates an incoming backspace via the serial console + * into a SCAN_DELETE. There's not much we can do about this. + */ + [SCAN_DELETE] = "[3~", + [SCAN_PAGE_UP] = "[5~", + [SCAN_PAGE_DOWN] = "[6~", + /* EFI translates some (but not all) incoming escape sequences + * via the serial console into equivalent scancodes. When it + * doesn't recognise a sequence, it helpfully(!) translates + * the initial ESC and passes the remainder through verbatim. + * Treating SCAN_ESC as equivalent to an empty escape sequence + * works around this bug. + */ + [SCAN_ESC] = "", +}; + +/** + * Get ANSI escape sequence corresponding to EFI scancode + * + * @v scancode EFI scancode + * @ret ansi_seq ANSI escape sequence, if any, otherwise NULL + */ +static const char * scancode_to_ansi_seq ( unsigned int scancode ) { + if ( scancode < ( sizeof ( ansi_sequences ) / + sizeof ( ansi_sequences[0] ) ) ) { + return ansi_sequences[scancode]; + } + return NULL; +} + +/** + * Get character from EFI console + * + * @ret character Character read from console + */ +static int efi_getchar ( void ) { + EFI_SIMPLE_TEXT_INPUT_PROTOCOL *conin = efi_systab->ConIn; + const char *ansi_seq; + EFI_INPUT_KEY key; + EFI_STATUS efirc; + + /* If we are mid-sequence, pass out the next byte */ + if ( *ansi_input ) + return *(ansi_input++); + + /* Read key from real EFI console */ + if ( ( efirc = conin->ReadKeyStroke ( conin, &key ) ) != 0 ) { + DBG ( "EFI could not read keystroke: %s\n", + efi_strerror ( efirc ) ); + return 0; + } + DBG2 ( "EFI read key stroke with unicode %04x scancode %04x\n", + key.UnicodeChar, key.ScanCode ); + + /* If key has a Unicode representation, return it */ + if ( key.UnicodeChar ) + return key.UnicodeChar; + + /* Otherwise, check for a special key that we know about */ + if ( ( ansi_seq = scancode_to_ansi_seq ( key.ScanCode ) ) ) { + /* Start of escape sequence: return ESC (0x1b) */ + ansi_input = ansi_seq; + return 0x1b; + } + + return 0; +} + +/** + * Check for character ready to read from EFI console + * + * @ret True Character available to read + * @ret False No character available to read + */ +static int efi_iskey ( void ) { + EFI_BOOT_SERVICES *bs = efi_systab->BootServices; + EFI_SIMPLE_TEXT_INPUT_PROTOCOL *conin = efi_systab->ConIn; + EFI_STATUS efirc; + + /* If we are mid-sequence, we are always ready */ + if ( *ansi_input ) + return 1; + + /* Check to see if the WaitForKey event has fired */ + if ( ( efirc = bs->CheckEvent ( conin->WaitForKey ) ) == 0 ) + return 1; + + return 0; +} + +struct console_driver efi_console __console_driver = { + .putchar = efi_putchar, + .getchar = efi_getchar, + .iskey = efi_iskey, +}; diff --git a/gpxe/src/interface/efi/efi_init.c b/gpxe/src/interface/efi/efi_init.c new file mode 100644 index 00000000..6e54cf7e --- /dev/null +++ b/gpxe/src/interface/efi/efi_init.c @@ -0,0 +1,122 @@ +/* + * 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., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +#include <string.h> +#include <gpxe/efi/efi.h> +#include <gpxe/uuid.h> + +/** Image handle passed to entry point */ +EFI_HANDLE efi_image_handle; + +/** System table passed to entry point */ +EFI_SYSTEM_TABLE *efi_systab; + +/** Declared used EFI protocols */ +static struct efi_protocol efi_protocols[0] \ + __table_start ( struct efi_protocol, efi_protocols ); +static struct efi_protocol efi_protocols_end[0] \ + __table_end ( struct efi_protocol, efi_protocols ); + +/** Declared used EFI configuration tables */ +static struct efi_config_table efi_config_tables[0] \ + __table_start ( struct efi_config_table, efi_config_tables ); +static struct efi_config_table efi_config_tables_end[0] \ + __table_end ( struct efi_config_table, efi_config_tables ); + +/** + * Look up EFI configuration table + * + * @v guid Configuration table GUID + * @ret table Configuration table, or NULL + */ +static void * efi_find_table ( EFI_GUID *guid ) { + unsigned int i; + + for ( i = 0 ; i < efi_systab->NumberOfTableEntries ; i++ ) { + if ( memcmp ( &efi_systab->ConfigurationTable[i].VendorGuid, + guid, sizeof ( *guid ) ) == 0 ) + return efi_systab->ConfigurationTable[i].VendorTable; + } + + return NULL; +} + +/** + * Initialise EFI environment + * + * @v image_handle Image handle + * @v systab System table + * @ret efirc EFI return status code + */ +EFI_STATUS efi_init ( EFI_HANDLE image_handle, + EFI_SYSTEM_TABLE *systab ) { + EFI_BOOT_SERVICES *bs; + struct efi_protocol *prot; + struct efi_config_table *tab; + EFI_STATUS efirc; + + /* Store image handle and system table pointer for future use */ + efi_image_handle = image_handle; + efi_systab = systab; + + /* Sanity checks */ + if ( ! systab ) + return EFI_NOT_AVAILABLE_YET; + if ( ! systab->ConOut ) + return EFI_NOT_AVAILABLE_YET; + if ( ! systab->BootServices ) { + DBGC ( systab, "EFI provided no BootServices entry point\n" ); + return EFI_NOT_AVAILABLE_YET; + } + if ( ! systab->RuntimeServices ) { + DBGC ( systab, "EFI provided no RuntimeServices entry " + "point\n" ); + return EFI_NOT_AVAILABLE_YET; + } + DBGC ( systab, "EFI handle %p systab %p\n", image_handle, systab ); + + /* Look up used protocols */ + bs = systab->BootServices; + for ( prot = efi_protocols ; prot < efi_protocols_end ; prot++ ) { + if ( ( efirc = bs->LocateProtocol ( &prot->u.guid, NULL, + prot->protocol ) ) == 0 ) { + DBGC ( systab, "EFI protocol %s is at %p\n", + uuid_ntoa ( &prot->u.uuid ), *(prot->protocol)); + } else { + DBGC ( systab, "EFI does not provide protocol %s\n", + uuid_ntoa ( &prot->u.uuid ) ); + /* All protocols are required */ + return efirc; + } + } + + /* Look up used configuration tables */ + for ( tab = efi_config_tables ; tab < efi_config_tables_end ; tab++ ) { + if ( ( *(tab->table) = efi_find_table ( &tab->u.guid ) ) ) { + DBGC ( systab, "EFI configuration table %s is at %p\n", + uuid_ntoa ( &tab->u.uuid ), *(tab->table) ); + } else { + DBGC ( systab, "EFI does not provide configuration " + "table %s\n", uuid_ntoa ( &tab->u.uuid ) ); + if ( tab->required ) + return EFI_NOT_AVAILABLE_YET; + } + } + + return 0; +} diff --git a/gpxe/src/interface/efi/efi_io.c b/gpxe/src/interface/efi/efi_io.c new file mode 100644 index 00000000..e11f9bfd --- /dev/null +++ b/gpxe/src/interface/efi/efi_io.c @@ -0,0 +1,203 @@ +/* + * 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., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +#include <assert.h> +#include <gpxe/io.h> +#include <gpxe/efi/efi.h> +#include <gpxe/efi/Protocol/CpuIo.h> +#include <gpxe/efi/efi_io.h> + +/** @file + * + * gPXE 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 ); +} + +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 ); diff --git a/gpxe/src/interface/efi/efi_pci.c b/gpxe/src/interface/efi/efi_pci.c new file mode 100644 index 00000000..f87b5407 --- /dev/null +++ b/gpxe/src/interface/efi/efi_pci.c @@ -0,0 +1,81 @@ +/* + * 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., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +#include <errno.h> +#include <gpxe/pci.h> +#include <gpxe/efi/efi.h> +#include <gpxe/efi/Protocol/PciRootBridgeIo.h> + +/** @file + * + * gPXE PCI I/O API for EFI + * + */ + +/** PCI root bridge I/O protocol */ +static EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL *efipci; +EFI_REQUIRE_PROTOCOL ( EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL, &efipci ); + +static unsigned long efipci_address ( struct pci_device *pci, + unsigned long location ) { + return EFI_PCI_ADDRESS ( pci->bus, PCI_SLOT ( pci->devfn ), + PCI_FUNC ( pci->devfn ), + EFIPCI_OFFSET ( location ) ); +} + +int efipci_read ( struct pci_device *pci, unsigned long location, + void *value ) { + EFI_STATUS efirc; + + if ( ( efirc = efipci->Pci.Read ( efipci, EFIPCI_WIDTH ( location ), + efipci_address ( pci, location ), 1, + value ) ) != 0 ) { + DBG ( "EFIPCI config read from %02x:%02x.%x offset %02lx " + "failed: %s\n", pci->bus, PCI_SLOT ( pci->devfn ), + PCI_FUNC ( pci->devfn ), EFIPCI_OFFSET ( location ), + efi_strerror ( efirc ) ); + return -EIO; + } + + return 0; +} + +int efipci_write ( struct pci_device *pci, unsigned long location, + unsigned long value ) { + EFI_STATUS efirc; + + if ( ( efirc = efipci->Pci.Write ( efipci, EFIPCI_WIDTH ( location ), + efipci_address ( pci, location ), 1, + &value ) ) != 0 ) { + DBG ( "EFIPCI config write to %02x:%02x.%x offset %02lx " + "failed: %s\n", pci->bus, PCI_SLOT ( pci->devfn ), + PCI_FUNC ( pci->devfn ), EFIPCI_OFFSET ( location ), + efi_strerror ( efirc ) ); + return -EIO; + } + + return 0; +} + +PROVIDE_PCIAPI_INLINE ( efi, pci_max_bus ); +PROVIDE_PCIAPI_INLINE ( efi, pci_read_config_byte ); +PROVIDE_PCIAPI_INLINE ( efi, pci_read_config_word ); +PROVIDE_PCIAPI_INLINE ( efi, pci_read_config_dword ); +PROVIDE_PCIAPI_INLINE ( efi, pci_write_config_byte ); +PROVIDE_PCIAPI_INLINE ( efi, pci_write_config_word ); +PROVIDE_PCIAPI_INLINE ( efi, pci_write_config_dword ); diff --git a/gpxe/src/interface/efi/efi_smbios.c b/gpxe/src/interface/efi/efi_smbios.c new file mode 100644 index 00000000..5888f2f9 --- /dev/null +++ b/gpxe/src/interface/efi/efi_smbios.c @@ -0,0 +1,62 @@ +/* + * 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., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +#include <errno.h> +#include <gpxe/smbios.h> +#include <gpxe/efi/efi.h> +#include <gpxe/efi/Guid/SmBios.h> + +/** @file + * + * gPXE SMBIOS API for EFI + * + */ + +/** SMBIOS configuration table */ +static struct smbios_entry *smbios_entry; +EFI_USE_TABLE ( EFI_SMBIOS_TABLE, &smbios_entry, 0 ); + +/** + * Find SMBIOS + * + * @v smbios SMBIOS entry point descriptor structure to fill in + * @ret rc Return status code + */ +static int efi_find_smbios ( struct smbios *smbios ) { + + if ( ! smbios_entry ) { + DBG ( "No SMBIOS table provided\n" ); + return -ENODEV; + } + + if ( smbios_entry->signature != SMBIOS_SIGNATURE ) { + DBG ( "Invalid SMBIOS signature\n" ); + return -ENODEV; + } + + smbios->address = phys_to_user ( smbios_entry->smbios_address ); + smbios->len = smbios_entry->smbios_len; + smbios->count = smbios_entry->smbios_count; + 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 ); + + return 0; +} + +PROVIDE_SMBIOS ( efi, find_smbios, efi_find_smbios ); diff --git a/gpxe/src/interface/efi/efi_snp.c b/gpxe/src/interface/efi/efi_snp.c new file mode 100644 index 00000000..771b9174 --- /dev/null +++ b/gpxe/src/interface/efi/efi_snp.c @@ -0,0 +1,1145 @@ +/* + * 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., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +#include <stdlib.h> +#include <string.h> +#include <errno.h> +#include <assert.h> +#include <byteswap.h> +#include <gpxe/netdevice.h> +#include <gpxe/iobuf.h> +#include <gpxe/in.h> +#include <gpxe/pci.h> +#include <gpxe/efi/efi.h> +#include <gpxe/efi/Protocol/DriverBinding.h> +#include <gpxe/efi/Protocol/PciIo.h> +#include <gpxe/efi/Protocol/SimpleNetwork.h> +#include <gpxe/efi/Protocol/ComponentName2.h> +#include <gpxe/efi/Protocol/NetworkInterfaceIdentifier.h> +#include <config/general.h> + +/** @file + * + * gPXE EFI SNP interface + * + */ + +/** An SNP device */ +struct efi_snp_device { + /** The underlying gPXE network device */ + struct net_device *netdev; + /** EFI device handle */ + EFI_HANDLE handle; + /** The SNP structure itself */ + EFI_SIMPLE_NETWORK_PROTOCOL snp; + /** The SNP "mode" (parameters) */ + EFI_SIMPLE_NETWORK_MODE mode; + /** Outstanding TX packet count (via "interrupt status") + * + * Used in order to generate TX completions. + */ + unsigned int tx_count_interrupts; + /** Outstanding TX packet count (via "recycled tx buffers") + * + * Used in order to generate TX completions. + */ + unsigned int tx_count_txbufs; + /** Outstanding RX packet count (via "interrupt status") */ + unsigned int rx_count_interrupts; + /** Outstanding RX packet count (via WaitForPacket event) */ + unsigned int rx_count_events; + /** The network interface identifier */ + EFI_NETWORK_INTERFACE_IDENTIFIER_PROTOCOL nii; + /** Device name */ + wchar_t name[ sizeof ( ( ( struct net_device * ) NULL )->name ) ]; + /** The device path + * + * This field is variable in size and must appear at the end + * of the structure. + */ + EFI_DEVICE_PATH_PROTOCOL path; +}; + +/** EFI simple network protocol GUID */ +static EFI_GUID efi_simple_network_protocol_guid + = EFI_SIMPLE_NETWORK_PROTOCOL_GUID; + +/** EFI driver binding protocol GUID */ +static EFI_GUID efi_driver_binding_protocol_guid + = EFI_DRIVER_BINDING_PROTOCOL_GUID; + +/** EFI component name protocol GUID */ +static EFI_GUID efi_component_name2_protocol_guid + = EFI_COMPONENT_NAME2_PROTOCOL_GUID; + +/** EFI device path protocol GUID */ +static EFI_GUID efi_device_path_protocol_guid + = EFI_DEVICE_PATH_PROTOCOL_GUID; + +/** EFI network interface identifier GUID */ +static EFI_GUID efi_nii_protocol_guid + = EFI_NETWORK_INTERFACE_IDENTIFIER_PROTOCOL_GUID; + +/** EFI network interface identifier GUID (extra special version) */ +static EFI_GUID efi_nii31_protocol_guid = { + /* At some point, it seems that someone decided to change the + * GUID. Current EFI builds ignore the older GUID, older EFI + * builds ignore the newer GUID, so we have to expose both. + */ + 0x1ACED566, 0x76ED, 0x4218, + { 0xBC, 0x81, 0x76, 0x7F, 0x1F, 0x97, 0x7A, 0x89 } +}; + +/** EFI PCI I/O protocol GUID */ +static EFI_GUID efi_pci_io_protocol_guid + = EFI_PCI_IO_PROTOCOL_GUID; + +/** + * Set EFI SNP mode based on gPXE net device parameters + * + * @v snp SNP interface + */ +static void efi_snp_set_mode ( struct efi_snp_device *snpdev ) { + struct net_device *netdev = snpdev->netdev; + EFI_SIMPLE_NETWORK_MODE *mode = &snpdev->mode; + unsigned int ll_addr_len = netdev->ll_protocol->ll_addr_len; + + mode->HwAddressSize = ll_addr_len; + mode->MediaHeaderSize = netdev->ll_protocol->ll_header_len; + mode->MaxPacketSize = netdev->max_pkt_len; + mode->ReceiveFilterMask = ( EFI_SIMPLE_NETWORK_RECEIVE_UNICAST | + EFI_SIMPLE_NETWORK_RECEIVE_MULTICAST | + EFI_SIMPLE_NETWORK_RECEIVE_BROADCAST ); + assert ( ll_addr_len <= sizeof ( mode->CurrentAddress ) ); + memcpy ( &mode->CurrentAddress, netdev->ll_addr, ll_addr_len ); + memcpy ( &mode->BroadcastAddress, netdev->ll_protocol->ll_broadcast, + ll_addr_len ); + memcpy ( &mode->PermanentAddress, netdev->ll_addr, ll_addr_len ); + mode->IfType = ntohs ( netdev->ll_protocol->ll_proto ); + mode->MacAddressChangeable = TRUE; + mode->MediaPresentSupported = TRUE; + mode->MediaPresent = ( netdev_link_ok ( netdev ) ? TRUE : FALSE ); +} + +/** + * Poll net device and count received packets + * + * @v snpdev SNP device + */ +static void efi_snp_poll ( struct efi_snp_device *snpdev ) { + struct io_buffer *iobuf; + unsigned int before = 0; + unsigned int after = 0; + unsigned int arrived; + + /* We have to report packet arrivals, and this is the easiest + * way to fake it. + */ + list_for_each_entry ( iobuf, &snpdev->netdev->rx_queue, list ) + before++; + netdev_poll ( snpdev->netdev ); + list_for_each_entry ( iobuf, &snpdev->netdev->rx_queue, list ) + after++; + arrived = ( after - before ); + + snpdev->rx_count_interrupts += arrived; + snpdev->rx_count_events += arrived; +} + +/** + * Change SNP state from "stopped" to "started" + * + * @v snp SNP interface + * @ret efirc EFI status code + */ +static EFI_STATUS EFIAPI +efi_snp_start ( EFI_SIMPLE_NETWORK_PROTOCOL *snp ) { + struct efi_snp_device *snpdev = + container_of ( snp, struct efi_snp_device, snp ); + + DBGC2 ( snpdev, "SNPDEV %p START\n", snpdev ); + + snpdev->mode.State = EfiSimpleNetworkStarted; + return 0; +} + +/** + * Change SNP state from "started" to "stopped" + * + * @v snp SNP interface + * @ret efirc EFI status code + */ +static EFI_STATUS EFIAPI +efi_snp_stop ( EFI_SIMPLE_NETWORK_PROTOCOL *snp ) { + struct efi_snp_device *snpdev = + container_of ( snp, struct efi_snp_device, snp ); + + DBGC2 ( snpdev, "SNPDEV %p STOP\n", snpdev ); + + snpdev->mode.State = EfiSimpleNetworkStopped; + return 0; +} + +/** + * Open the network device + * + * @v snp SNP interface + * @v extra_rx_bufsize Extra RX buffer size, in bytes + * @v extra_tx_bufsize Extra TX buffer size, in bytes + * @ret efirc EFI status code + */ +static EFI_STATUS EFIAPI +efi_snp_initialize ( EFI_SIMPLE_NETWORK_PROTOCOL *snp, + UINTN extra_rx_bufsize, UINTN extra_tx_bufsize ) { + struct efi_snp_device *snpdev = + container_of ( snp, struct efi_snp_device, snp ); + int rc; + + DBGC2 ( snpdev, "SNPDEV %p INITIALIZE (%ld extra RX, %ld extra TX)\n", + snpdev, ( ( unsigned long ) extra_rx_bufsize ), + ( ( unsigned long ) extra_tx_bufsize ) ); + + 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 ); + } + + snpdev->mode.State = EfiSimpleNetworkInitialized; + return 0; +} + +/** + * Reset the network device + * + * @v snp SNP interface + * @v ext_verify Extended verification required + * @ret efirc EFI status code + */ +static EFI_STATUS EFIAPI +efi_snp_reset ( EFI_SIMPLE_NETWORK_PROTOCOL *snp, BOOLEAN ext_verify ) { + struct efi_snp_device *snpdev = + container_of ( snp, struct efi_snp_device, snp ); + int rc; + + DBGC2 ( snpdev, "SNPDEV %p RESET (%s extended verification)\n", + snpdev, ( ext_verify ? "with" : "without" ) ); + + netdev_close ( snpdev->netdev ); + snpdev->mode.State = EfiSimpleNetworkStarted; + + 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 ); + } + + snpdev->mode.State = EfiSimpleNetworkInitialized; + return 0; +} + +/** + * Shut down the network device + * + * @v snp SNP interface + * @ret efirc EFI status code + */ +static EFI_STATUS EFIAPI +efi_snp_shutdown ( EFI_SIMPLE_NETWORK_PROTOCOL *snp ) { + struct efi_snp_device *snpdev = + container_of ( snp, struct efi_snp_device, snp ); + + DBGC2 ( snpdev, "SNPDEV %p SHUTDOWN\n", snpdev ); + + netdev_close ( snpdev->netdev ); + snpdev->mode.State = EfiSimpleNetworkStarted; + return 0; +} + +/** + * Manage receive filters + * + * @v snp SNP interface + * @v enable Receive filters to enable + * @v disable Receive filters to disable + * @v mcast_reset Reset multicast filters + * @v mcast_count Number of multicast filters + * @v mcast Multicast filters + * @ret efirc EFI status code + */ +static EFI_STATUS EFIAPI +efi_snp_receive_filters ( EFI_SIMPLE_NETWORK_PROTOCOL *snp, UINT32 enable, + UINT32 disable, BOOLEAN mcast_reset, + UINTN mcast_count, EFI_MAC_ADDRESS *mcast ) { + struct efi_snp_device *snpdev = + container_of ( snp, struct efi_snp_device, snp ); + unsigned int i; + + DBGC2 ( snpdev, "SNPDEV %p RECEIVE_FILTERS %08x&~%08x%s %ld mcast\n", + snpdev, enable, disable, ( mcast_reset ? " reset" : "" ), + ( ( unsigned long ) mcast_count ) ); + for ( i = 0 ; i < mcast_count ; i++ ) { + DBGC2_HDA ( snpdev, i, &mcast[i], + snpdev->netdev->ll_protocol->ll_addr_len ); + } + + /* Lie through our teeth, otherwise MNP refuses to accept us */ + return 0; +} + +/** + * Set station address + * + * @v snp SNP interface + * @v reset Reset to permanent address + * @v new New station address + * @ret efirc EFI status code + */ +static EFI_STATUS EFIAPI +efi_snp_station_address ( EFI_SIMPLE_NETWORK_PROTOCOL *snp, BOOLEAN reset, + EFI_MAC_ADDRESS *new ) { + struct efi_snp_device *snpdev = + container_of ( snp, struct efi_snp_device, snp ); + struct ll_protocol *ll_protocol = snpdev->netdev->ll_protocol; + + DBGC2 ( snpdev, "SNPDEV %p STATION_ADDRESS %s\n", snpdev, + ( reset ? "reset" : ll_protocol->ntoa ( new ) ) ); + + /* Set the MAC address */ + if ( reset ) + new = &snpdev->mode.PermanentAddress; + memcpy ( snpdev->netdev->ll_addr, new, ll_protocol->ll_addr_len ); + + /* MAC address changes take effect only on netdev_open() */ + if ( snpdev->netdev->state & NETDEV_OPEN ) { + DBGC ( snpdev, "SNPDEV %p MAC address changed while net " + "devive open\n", snpdev ); + } + + return 0; +} + +/** + * Get (or reset) statistics + * + * @v snp SNP interface + * @v reset Reset statistics + * @v stats_len Size of statistics table + * @v stats Statistics table + * @ret efirc EFI status code + */ +static EFI_STATUS EFIAPI +efi_snp_statistics ( EFI_SIMPLE_NETWORK_PROTOCOL *snp, BOOLEAN reset, + UINTN *stats_len, EFI_NETWORK_STATISTICS *stats ) { + struct efi_snp_device *snpdev = + container_of ( snp, struct efi_snp_device, snp ); + EFI_NETWORK_STATISTICS stats_buf; + + DBGC2 ( snpdev, "SNPDEV %p STATISTICS%s", snpdev, + ( reset ? " reset" : "" ) ); + + /* Gather statistics */ + memset ( &stats_buf, 0, sizeof ( stats_buf ) ); + stats_buf.TxGoodFrames = snpdev->netdev->tx_stats.good; + stats_buf.TxDroppedFrames = snpdev->netdev->tx_stats.bad; + stats_buf.TxTotalFrames = ( snpdev->netdev->tx_stats.good + + snpdev->netdev->tx_stats.bad ); + stats_buf.RxGoodFrames = snpdev->netdev->rx_stats.good; + stats_buf.RxDroppedFrames = snpdev->netdev->rx_stats.bad; + stats_buf.RxTotalFrames = ( snpdev->netdev->rx_stats.good + + snpdev->netdev->rx_stats.bad ); + if ( *stats_len > sizeof ( stats_buf ) ) + *stats_len = sizeof ( stats_buf ); + if ( stats ) + memcpy ( stats, &stats_buf, *stats_len ); + + /* Reset statistics if requested to do so */ + if ( reset ) { + memset ( &snpdev->netdev->tx_stats, 0, + sizeof ( snpdev->netdev->tx_stats ) ); + memset ( &snpdev->netdev->rx_stats, 0, + sizeof ( snpdev->netdev->rx_stats ) ); + } + + return 0; +} + +/** + * Convert multicast IP address to MAC address + * + * @v snp SNP interface + * @v ipv6 Address is IPv6 + * @v ip IP address + * @v mac MAC address + * @ret efirc EFI status code + */ +static EFI_STATUS EFIAPI +efi_snp_mcast_ip_to_mac ( EFI_SIMPLE_NETWORK_PROTOCOL *snp, BOOLEAN ipv6, + EFI_IP_ADDRESS *ip, EFI_MAC_ADDRESS *mac ) { + struct efi_snp_device *snpdev = + container_of ( snp, struct efi_snp_device, snp ); + struct ll_protocol *ll_protocol = snpdev->netdev->ll_protocol; + const char *ip_str; + int rc; + + ip_str = ( ipv6 ? "(IPv6)" /* FIXME when we have inet6_ntoa() */ : + inet_ntoa ( *( ( struct in_addr * ) ip ) ) ); + DBGC2 ( snpdev, "SNPDEV %p MCAST_IP_TO_MAC %s\n", snpdev, ip_str ); + + /* 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 0; +} + +/** + * Read or write non-volatile storage + * + * @v snp SNP interface + * @v read Operation is a read + * @v offset Starting offset within NVRAM + * @v len Length of data buffer + * @v data Data buffer + * @ret efirc EFI status code + */ +static EFI_STATUS EFIAPI +efi_snp_nvdata ( EFI_SIMPLE_NETWORK_PROTOCOL *snp, BOOLEAN read, + UINTN offset, UINTN len, VOID *data ) { + struct efi_snp_device *snpdev = + container_of ( snp, struct efi_snp_device, snp ); + + DBGC2 ( snpdev, "SNPDEV %p NVDATA %s %lx+%lx\n", snpdev, + ( read ? "read" : "write" ), ( ( unsigned long ) offset ), + ( ( unsigned long ) len ) ); + if ( ! read ) + DBGC2_HDA ( snpdev, offset, data, len ); + + return EFI_UNSUPPORTED; +} + +/** + * Read interrupt status and TX recycled buffer status + * + * @v snp SNP interface + * @v interrupts Interrupt status, or NULL + * @v txbufs Recycled transmit buffer address, or NULL + * @ret efirc EFI status code + */ +static EFI_STATUS EFIAPI +efi_snp_get_status ( EFI_SIMPLE_NETWORK_PROTOCOL *snp, + UINT32 *interrupts, VOID **txbufs ) { + struct efi_snp_device *snpdev = + container_of ( snp, struct efi_snp_device, snp ); + + DBGC2 ( snpdev, "SNPDEV %p GET_STATUS", snpdev ); + + /* Poll the network device */ + efi_snp_poll ( snpdev ); + + /* Interrupt status. In practice, this seems to be used only + * to detect TX completions. + */ + if ( interrupts ) { + *interrupts = 0; + /* Report TX completions once queue is empty; this + * avoids having to add hooks in the net device layer. + */ + if ( snpdev->tx_count_interrupts && + list_empty ( &snpdev->netdev->tx_queue ) ) { + *interrupts |= EFI_SIMPLE_NETWORK_TRANSMIT_INTERRUPT; + snpdev->tx_count_interrupts--; + } + /* Report RX */ + if ( snpdev->rx_count_interrupts ) { + *interrupts |= EFI_SIMPLE_NETWORK_RECEIVE_INTERRUPT; + snpdev->rx_count_interrupts--; + } + DBGC2 ( snpdev, " INTS:%02x", *interrupts ); + } + + /* TX completions. It would be possible to design a more + * idiotic scheme for this, but it would be a challenge. + * According to the UEFI header file, txbufs will be filled in + * with a list of "recycled transmit buffers" (i.e. completed + * TX buffers). Observant readers may care to note that + * *txbufs is a void pointer. Precisely how a list of + * completed transmit buffers is meant to be represented as an + * array of voids is left as an exercise for the reader. + * + * The only users of this interface (MnpDxe/MnpIo.c and + * PxeBcDxe/Bc.c within the EFI dev kit) both just poll until + * seeing a non-NULL result return in txbufs. This is valid + * provided that they do not ever attempt to transmit more + * than one packet concurrently (and that TX never times out). + */ + if ( txbufs ) { + if ( snpdev->tx_count_txbufs && + list_empty ( &snpdev->netdev->tx_queue ) ) { + *txbufs = "Which idiot designed this API?"; + snpdev->tx_count_txbufs--; + } else { + *txbufs = NULL; + } + DBGC2 ( snpdev, " TX:%s", ( *txbufs ? "some" : "none" ) ); + } + + DBGC2 ( snpdev, "\n" ); + return 0; +} + +/** + * Start packet transmission + * + * @v snp SNP interface + * @v ll_header_len Link-layer header length, if to be filled in + * @v len Length of data buffer + * @v data Data buffer + * @v ll_src Link-layer source address, if specified + * @v ll_dest Link-layer destination address, if specified + * @v net_proto Network-layer protocol (in host order) + * @ret efirc EFI status code + */ +static EFI_STATUS EFIAPI +efi_snp_transmit ( EFI_SIMPLE_NETWORK_PROTOCOL *snp, + UINTN ll_header_len, UINTN len, VOID *data, + EFI_MAC_ADDRESS *ll_src, EFI_MAC_ADDRESS *ll_dest, + UINT16 *net_proto ) { + struct efi_snp_device *snpdev = + container_of ( snp, struct efi_snp_device, snp ); + struct ll_protocol *ll_protocol = snpdev->netdev->ll_protocol; + struct io_buffer *iobuf; + int rc; + EFI_STATUS efirc; + + DBGC2 ( snpdev, "SNPDEV %p TRANSMIT %p+%lx", snpdev, data, + ( ( unsigned long ) len ) ); + if ( ll_header_len ) { + if ( ll_src ) { + DBGC2 ( snpdev, " src %s", + ll_protocol->ntoa ( ll_src ) ); + } + if ( ll_dest ) { + DBGC2 ( snpdev, " dest %s", + ll_protocol->ntoa ( ll_dest ) ); + } + if ( net_proto ) { + DBGC2 ( snpdev, " proto %04x", *net_proto ); + } + } + DBGC2 ( snpdev, "\n" ); + + /* 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; + 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; + goto err_sanity; + } + if ( ! ll_dest ) { + DBGC ( snpdev, "SNPDEV %p TX missing destination " + "address\n", snpdev ); + efirc = EFI_INVALID_PARAMETER; + goto err_sanity; + } + if ( ! net_proto ) { + DBGC ( snpdev, "SNPDEV %p TX missing network " + "protocol\n", snpdev ); + efirc = EFI_INVALID_PARAMETER; + goto err_sanity; + } + if ( ! ll_src ) + ll_src = &snpdev->mode.CurrentAddress; + } + + /* Allocate buffer */ + iobuf = alloc_iob ( len ); + if ( ! iobuf ) { + DBGC ( snpdev, "SNPDEV %p TX could not allocate %ld-byte " + "buffer\n", snpdev, ( ( unsigned long ) len ) ); + efirc = EFI_DEVICE_ERROR; + goto err_alloc_iob; + } + memcpy ( iob_put ( iobuf, len ), data, len ); + + /* Create link-layer header, if specified */ + if ( ll_header_len ) { + iob_pull ( iobuf, ll_header_len ); + if ( ( rc = ll_protocol->push ( iobuf, ll_dest, ll_src, + 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; + } + } + + /* Transmit packet */ + 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; + } + + /* Record transmission as outstanding */ + snpdev->tx_count_interrupts++; + snpdev->tx_count_txbufs++; + + return 0; + + err_tx: + err_ll_push: + free_iob ( iobuf ); + err_alloc_iob: + err_sanity: + return efirc; +} + +/** + * Receive packet + * + * @v snp SNP interface + * @v ll_header_len Link-layer header length, if to be filled in + * @v len Length of data buffer + * @v data Data buffer + * @v ll_src Link-layer source address, if specified + * @v ll_dest Link-layer destination address, if specified + * @v net_proto Network-layer protocol (in host order) + * @ret efirc EFI status code + */ +static EFI_STATUS EFIAPI +efi_snp_receive ( EFI_SIMPLE_NETWORK_PROTOCOL *snp, + UINTN *ll_header_len, UINTN *len, VOID *data, + EFI_MAC_ADDRESS *ll_src, EFI_MAC_ADDRESS *ll_dest, + UINT16 *net_proto ) { + struct efi_snp_device *snpdev = + container_of ( snp, struct efi_snp_device, snp ); + struct ll_protocol *ll_protocol = snpdev->netdev->ll_protocol; + struct io_buffer *iobuf; + const void *iob_ll_dest; + const void *iob_ll_src; + uint16_t iob_net_proto; + int rc; + EFI_STATUS efirc; + + DBGC2 ( snpdev, "SNPDEV %p RECEIVE %p(+%lx)", snpdev, data, + ( ( unsigned long ) *len ) ); + + /* Poll the network device */ + efi_snp_poll ( snpdev ); + + /* Dequeue a packet, if one is available */ + iobuf = netdev_rx_dequeue ( snpdev->netdev ); + if ( ! iobuf ) { + DBGC2 ( snpdev, "\n" ); + efirc = EFI_NOT_READY; + goto out_no_packet; + } + DBGC2 ( snpdev, "+%zx\n", iob_len ( iobuf ) ); + + /* Return packet to caller */ + memcpy ( data, iobuf->data, iob_len ( iobuf ) ); + *len = iob_len ( iobuf ); + + /* Attempt to decode link-layer header */ + if ( ( rc = ll_protocol->pull ( iobuf, &iob_ll_dest, &iob_ll_src, + &iob_net_proto ) ) != 0 ) { + DBGC ( snpdev, "SNPDEV %p could not parse header: %s\n", + snpdev, strerror ( rc ) ); + efirc = RC_TO_EFIRC ( rc ); + goto out_bad_ll_header; + } + + /* Return link-layer header parameters to caller, if required */ + if ( ll_header_len ) + *ll_header_len = ll_protocol->ll_header_len; + if ( ll_src ) + memcpy ( ll_src, iob_ll_src, ll_protocol->ll_addr_len ); + if ( ll_dest ) + memcpy ( ll_dest, iob_ll_dest, ll_protocol->ll_addr_len ); + if ( net_proto ) + *net_proto = ntohs ( iob_net_proto ); + + efirc = 0; + + out_bad_ll_header: + free_iob ( iobuf ); +out_no_packet: + return efirc; +} + +/** + * Poll event + * + * @v event Event + * @v context Event context + */ +static VOID EFIAPI efi_snp_wait_for_packet ( EFI_EVENT event, + VOID *context ) { + EFI_BOOT_SERVICES *bs = efi_systab->BootServices; + struct efi_snp_device *snpdev = context; + + DBGCP ( snpdev, "SNPDEV %p WAIT_FOR_PACKET\n", snpdev ); + + /* Do nothing unless the net device is open */ + if ( ! ( snpdev->netdev->state & NETDEV_OPEN ) ) + return; + + /* Poll the network device */ + efi_snp_poll ( snpdev ); + + /* Fire event if packets have been received */ + if ( snpdev->rx_count_events != 0 ) { + DBGC2 ( snpdev, "SNPDEV %p firing WaitForPacket event\n", + snpdev ); + bs->SignalEvent ( event ); + snpdev->rx_count_events--; + } +} + +/** SNP interface */ +static EFI_SIMPLE_NETWORK_PROTOCOL efi_snp_device_snp = { + .Revision = EFI_SIMPLE_NETWORK_PROTOCOL_REVISION, + .Start = efi_snp_start, + .Stop = efi_snp_stop, + .Initialize = efi_snp_initialize, + .Reset = efi_snp_reset, + .Shutdown = efi_snp_shutdown, + .ReceiveFilters = efi_snp_receive_filters, + .StationAddress = efi_snp_station_address, + .Statistics = efi_snp_statistics, + .MCastIpToMac = efi_snp_mcast_ip_to_mac, + .NvData = efi_snp_nvdata, + .GetStatus = efi_snp_get_status, + .Transmit = efi_snp_transmit, + .Receive = efi_snp_receive, +}; + +/** + * Locate net device corresponding to EFI device + * + * @v driver EFI driver + * @v device EFI device + * @ret netdev Net device, or NULL if not found + */ +static struct net_device * +efi_snp_netdev ( EFI_DRIVER_BINDING_PROTOCOL *driver, EFI_HANDLE device ) { + EFI_BOOT_SERVICES *bs = efi_systab->BootServices; + union { + EFI_PCI_IO_PROTOCOL *pci; + void *interface; + } u; + UINTN pci_segment, pci_bus, pci_dev, pci_fn; + unsigned int pci_busdevfn; + struct net_device *netdev = NULL; + EFI_STATUS efirc; + + /* See if device is a PCI device */ + if ( ( efirc = bs->OpenProtocol ( device, + &efi_pci_io_protocol_guid, + &u.interface, + driver->DriverBindingHandle, + device, + EFI_OPEN_PROTOCOL_BY_DRIVER )) !=0 ){ + DBGCP ( driver, "SNPDRV %p device %p is not a PCI device\n", + driver, device ); + goto out_no_pci_io; + } + + /* Get PCI bus:dev.fn address */ + if ( ( efirc = u.pci->GetLocation ( u.pci, &pci_segment, &pci_bus, + &pci_dev, &pci_fn ) ) != 0 ) { + DBGC ( driver, "SNPDRV %p device %p could not get PCI " + "location: %s\n", + driver, device, efi_strerror ( efirc ) ); + goto out_no_pci_location; + } + DBGCP ( driver, "SNPDRV %p device %p is PCI %04lx:%02lx:%02lx.%lx\n", + driver, device, ( ( unsigned long ) pci_segment ), + ( ( unsigned long ) pci_bus ), ( ( unsigned long ) pci_dev ), + ( ( unsigned long ) pci_fn ) ); + + /* Look up corresponding network device */ + pci_busdevfn = PCI_BUSDEVFN ( pci_bus, PCI_DEVFN ( pci_dev, pci_fn ) ); + if ( ( netdev = find_netdev_by_location ( BUS_TYPE_PCI, + pci_busdevfn ) ) == NULL ) { + DBGCP ( driver, "SNPDRV %p device %p is not a gPXE network " + "device\n", driver, device ); + goto out_no_netdev; + } + DBGC ( driver, "SNPDRV %p device %p is %s\n", + driver, device, netdev->name ); + + out_no_netdev: + out_no_pci_location: + bs->CloseProtocol ( device, &efi_pci_io_protocol_guid, + driver->DriverBindingHandle, device ); + out_no_pci_io: + return netdev; +} + +/** + * Locate SNP corresponding to EFI device + * + * @v driver EFI driver + * @v device EFI device + * @ret snp EFI SNP, or NULL if not found + */ +static struct efi_snp_device * +efi_snp_snpdev ( EFI_DRIVER_BINDING_PROTOCOL *driver, EFI_HANDLE device ) { + EFI_BOOT_SERVICES *bs = efi_systab->BootServices; + union { + EFI_SIMPLE_NETWORK_PROTOCOL *snp; + void *interface; + } u; + struct efi_snp_device *snpdev = NULL; + EFI_STATUS efirc; + + if ( ( efirc = bs->OpenProtocol ( device, + &efi_simple_network_protocol_guid, + &u.interface, + driver->DriverBindingHandle, + device, + EFI_OPEN_PROTOCOL_GET_PROTOCOL))!=0){ + DBGC ( driver, "SNPDRV %p device %p could not locate SNP: " + "%s\n", driver, device, efi_strerror ( efirc ) ); + goto err_no_snp; + } + + snpdev = container_of ( u.snp, struct efi_snp_device, snp ); + DBGCP ( driver, "SNPDRV %p device %p is SNPDEV %p\n", + driver, device, snpdev ); + + bs->CloseProtocol ( device, &efi_simple_network_protocol_guid, + driver->DriverBindingHandle, device ); + err_no_snp: + return snpdev; +} + +/** + * 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_snp_driver_supported ( EFI_DRIVER_BINDING_PROTOCOL *driver, + EFI_HANDLE device, + EFI_DEVICE_PATH_PROTOCOL *child ) { + struct net_device *netdev; + + DBGCP ( driver, "SNPDRV %p DRIVER_SUPPORTED %p (%p)\n", + driver, device, child ); + + netdev = efi_snp_netdev ( driver, device ); + return ( netdev ? 0 : 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_snp_driver_start ( EFI_DRIVER_BINDING_PROTOCOL *driver, + EFI_HANDLE device, + EFI_DEVICE_PATH_PROTOCOL *child ) { + EFI_BOOT_SERVICES *bs = efi_systab->BootServices; + EFI_DEVICE_PATH_PROTOCOL *path; + EFI_DEVICE_PATH_PROTOCOL *subpath; + MAC_ADDR_DEVICE_PATH *macpath; + struct efi_snp_device *snpdev; + struct net_device *netdev; + size_t subpath_len; + size_t path_prefix_len = 0; + unsigned int i; + EFI_STATUS efirc; + + DBGCP ( driver, "SNPDRV %p DRIVER_START %p (%p)\n", + driver, device, child ); + + /* Determine device path prefix length */ + if ( ( efirc = bs->OpenProtocol ( device, + &efi_device_path_protocol_guid, + ( void * ) &path, + driver->DriverBindingHandle, + device, + EFI_OPEN_PROTOCOL_BY_DRIVER )) !=0 ){ + DBGCP ( driver, "SNPDRV %p device %p has no device path\n", + driver, device ); + goto err_no_device_path; + } + subpath = path; + while ( subpath->Type != END_DEVICE_PATH_TYPE ) { + subpath_len = ( ( subpath->Length[1] << 8 ) | + subpath->Length[0] ); + path_prefix_len += subpath_len; + subpath = ( ( ( void * ) subpath ) + subpath_len ); + } + + /* Allocate the SNP device */ + snpdev = zalloc ( sizeof ( *snpdev ) + path_prefix_len + + sizeof ( *macpath ) ); + if ( ! snpdev ) { + efirc = EFI_OUT_OF_RESOURCES; + goto err_alloc_snp; + } + + /* Identify the net device */ + netdev = efi_snp_netdev ( driver, device ); + if ( ! netdev ) { + DBGC ( snpdev, "SNPDEV %p cannot find netdev for device %p\n", + snpdev, device ); + efirc = EFI_UNSUPPORTED; + goto err_no_netdev; + } + snpdev->netdev = netdev_get ( netdev ); + + /* Sanity check */ + if ( netdev->ll_protocol->ll_addr_len > sizeof ( EFI_MAC_ADDRESS ) ) { + DBGC ( snpdev, "SNPDEV %p cannot support link-layer address " + "length %d for %s\n", snpdev, + netdev->ll_protocol->ll_addr_len, netdev->name ); + efirc = EFI_INVALID_PARAMETER; + goto err_ll_addr_len; + } + + /* Populate the SNP structure */ + memcpy ( &snpdev->snp, &efi_snp_device_snp, sizeof ( snpdev->snp ) ); + snpdev->snp.Mode = &snpdev->mode; + if ( ( efirc = bs->CreateEvent ( EVT_NOTIFY_WAIT, TPL_NOTIFY, + efi_snp_wait_for_packet, snpdev, + &snpdev->snp.WaitForPacket ) ) != 0 ){ + DBGC ( snpdev, "SNPDEV %p could not create event: %s\n", + snpdev, efi_strerror ( efirc ) ); + goto err_create_event; + } + + /* Populate the SNP mode structure */ + snpdev->mode.State = EfiSimpleNetworkStopped; + efi_snp_set_mode ( snpdev ); + + /* Populate the NII structure */ + snpdev->nii.Revision = + EFI_NETWORK_INTERFACE_IDENTIFIER_PROTOCOL_REVISION; + strncpy ( snpdev->nii.StringId, "gPXE", + sizeof ( snpdev->nii.StringId ) ); + + /* Populate the device name */ + for ( i = 0 ; i < sizeof ( netdev->name ) ; i++ ) { + /* Damn Unicode names */ + assert ( i < ( sizeof ( snpdev->name ) / + sizeof ( snpdev->name[0] ) ) ); + snpdev->name[i] = netdev->name[i]; + } + + /* Populate the device path */ + memcpy ( &snpdev->path, path, path_prefix_len ); + macpath = ( ( ( void * ) &snpdev->path ) + path_prefix_len ); + subpath = ( ( void * ) ( macpath + 1 ) ); + memset ( macpath, 0, sizeof ( *macpath ) ); + macpath->Header.Type = MESSAGING_DEVICE_PATH; + macpath->Header.SubType = MSG_MAC_ADDR_DP; + macpath->Header.Length[0] = sizeof ( *macpath ); + memcpy ( &macpath->MacAddress, netdev->ll_addr, + sizeof ( macpath->MacAddress ) ); + macpath->IfType = ntohs ( netdev->ll_protocol->ll_proto ); + memset ( subpath, 0, sizeof ( *subpath ) ); + subpath->Type = END_DEVICE_PATH_TYPE; + subpath->SubType = END_ENTIRE_DEVICE_PATH_SUBTYPE; + subpath->Length[0] = sizeof ( *subpath ); + + /* Install the SNP */ + if ( ( efirc = bs->InstallMultipleProtocolInterfaces ( + &snpdev->handle, + &efi_simple_network_protocol_guid, &snpdev->snp, + &efi_device_path_protocol_guid, &snpdev->path, + &efi_nii_protocol_guid, &snpdev->nii, + &efi_nii31_protocol_guid, &snpdev->nii, + NULL ) ) != 0 ) { + DBGC ( snpdev, "SNPDEV %p could not install protocols: " + "%s\n", snpdev, efi_strerror ( efirc ) ); + goto err_install_protocol_interface; + } + + DBGC ( snpdev, "SNPDEV %p installed for %s as device %p\n", + snpdev, netdev->name, snpdev->handle ); + return 0; + + bs->UninstallMultipleProtocolInterfaces ( + snpdev->handle, + &efi_simple_network_protocol_guid, &snpdev->snp, + &efi_device_path_protocol_guid, &snpdev->path, + &efi_nii_protocol_guid, &snpdev->nii, + &efi_nii31_protocol_guid, &snpdev->nii, + NULL ); + err_install_protocol_interface: + bs->CloseEvent ( snpdev->snp.WaitForPacket ); + err_create_event: + err_ll_addr_len: + netdev_put ( netdev ); + err_no_netdev: + free ( snpdev ); + err_alloc_snp: + bs->CloseProtocol ( device, &efi_device_path_protocol_guid, + driver->DriverBindingHandle, device ); + err_no_device_path: + return efirc; +} + +/** + * Detach driver from device + * + * @v driver EFI driver + * @v device EFI device + * @v num_children Number of child devices + * @v children List of child devices + * @ret efirc EFI status code + */ +static EFI_STATUS EFIAPI +efi_snp_driver_stop ( EFI_DRIVER_BINDING_PROTOCOL *driver, + EFI_HANDLE device, + UINTN num_children, + EFI_HANDLE *children ) { + EFI_BOOT_SERVICES *bs = efi_systab->BootServices; + struct efi_snp_device *snpdev; + + DBGCP ( driver, "SNPDRV %p DRIVER_STOP %p (%ld %p)\n", + driver, device, ( ( unsigned long ) num_children ), children ); + + /* Locate SNP device */ + snpdev = efi_snp_snpdev ( driver, device ); + if ( ! snpdev ) { + DBGC ( driver, "SNPDRV %p device %p could not find SNPDEV\n", + driver, device ); + return EFI_DEVICE_ERROR; + } + + /* Uninstall the SNP */ + bs->UninstallMultipleProtocolInterfaces ( + snpdev->handle, + &efi_simple_network_protocol_guid, &snpdev->snp, + &efi_device_path_protocol_guid, &snpdev->path, + &efi_nii_protocol_guid, &snpdev->nii, + &efi_nii31_protocol_guid, &snpdev->nii, + NULL ); + bs->CloseEvent ( snpdev->snp.WaitForPacket ); + netdev_put ( snpdev->netdev ); + free ( snpdev ); + bs->CloseProtocol ( device, &efi_device_path_protocol_guid, + driver->DriverBindingHandle, device ); + return 0; +} + +/** EFI SNP driver binding */ +static EFI_DRIVER_BINDING_PROTOCOL efi_snp_binding = { + efi_snp_driver_supported, + efi_snp_driver_start, + efi_snp_driver_stop, + 0x10, + NULL, + NULL +}; + +/** + * Look up driver name + * + * @v wtf Component name protocol + * @v language Language to use + * @v driver_name Driver name to fill in + * @ret efirc EFI status code + */ +static EFI_STATUS EFIAPI +efi_snp_get_driver_name ( EFI_COMPONENT_NAME2_PROTOCOL *wtf __unused, + CHAR8 *language __unused, CHAR16 **driver_name ) { + + *driver_name = L"" PRODUCT_SHORT_NAME " Driver"; + return 0; +} + +/** + * Look up controller name + * + * @v wtf Component name protocol + * @v device Device + * @v child Child device, or NULL + * @v language Language to use + * @v driver_name Device name to fill in + * @ret efirc EFI status code + */ +static EFI_STATUS EFIAPI +efi_snp_get_controller_name ( EFI_COMPONENT_NAME2_PROTOCOL *wtf __unused, + EFI_HANDLE device __unused, + EFI_HANDLE child __unused, + CHAR8 *language __unused, + CHAR16 **controller_name __unused ) { + + /* Just let EFI use the default Device Path Name */ + return EFI_UNSUPPORTED; +} + +/** EFI SNP component name protocol */ +static EFI_COMPONENT_NAME2_PROTOCOL efi_snp_name = { + efi_snp_get_driver_name, + efi_snp_get_controller_name, + "en" +}; + +/** + * Install EFI SNP driver + * + * @ret rc Return status code + */ +int efi_snp_install ( void ) { + EFI_BOOT_SERVICES *bs = efi_systab->BootServices; + EFI_DRIVER_BINDING_PROTOCOL *driver = &efi_snp_binding; + EFI_STATUS efirc; + + driver->ImageHandle = efi_image_handle; + if ( ( efirc = bs->InstallMultipleProtocolInterfaces ( + &driver->DriverBindingHandle, + &efi_driver_binding_protocol_guid, driver, + &efi_component_name2_protocol_guid, &efi_snp_name, + NULL ) ) != 0 ) { + DBGC ( driver, "SNPDRV %p could not install protocols: " + "%s\n", driver, efi_strerror ( efirc ) ); + return EFIRC_TO_RC ( efirc ); + } + + DBGC ( driver, "SNPDRV %p driver binding installed as %p\n", + driver, driver->DriverBindingHandle ); + return 0; +} diff --git a/gpxe/src/interface/efi/efi_strerror.c b/gpxe/src/interface/efi/efi_strerror.c new file mode 100644 index 00000000..adfeaed5 --- /dev/null +++ b/gpxe/src/interface/efi/efi_strerror.c @@ -0,0 +1,43 @@ +/* + * 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., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +#include <stdio.h> +#include <gpxe/efi/efi.h> + +/** @file + * + * gPXE error message formatting for EFI + * + */ + +/** + * Format EFI status code + * + * @v efirc EFI status code + * @v efi_strerror EFI status code string + */ +const char * efi_strerror ( EFI_STATUS efirc ) { + static char errbuf[32]; + + if ( ! efirc ) + return "No error"; + + snprintf ( errbuf, sizeof ( errbuf ), "Error %lld", + ( unsigned long long ) ( efirc ^ MAX_BIT ) ); + return errbuf; +} diff --git a/gpxe/src/interface/efi/efi_timer.c b/gpxe/src/interface/efi/efi_timer.c new file mode 100644 index 00000000..d1ba43af --- /dev/null +++ b/gpxe/src/interface/efi/efi_timer.c @@ -0,0 +1,116 @@ +/* + * 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., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +#include <limits.h> +#include <assert.h> +#include <unistd.h> +#include <gpxe/timer.h> +#include <gpxe/efi/efi.h> +#include <gpxe/efi/Protocol/Cpu.h> + +/** @file + * + * gPXE timer API for EFI + * + */ + +/** Scale factor to apply to CPU timer 0 + * + * The timer is scaled down in order to ensure that reasonable values + * for "number of ticks" don't exceed the size of an unsigned long. + */ +#define EFI_TIMER0_SHIFT 12 + +/** Calibration time */ +#define EFI_CALIBRATE_DELAY_MS 1 + +/** CPU protocol */ +static EFI_CPU_ARCH_PROTOCOL *cpu_arch; +EFI_REQUIRE_PROTOCOL ( EFI_CPU_ARCH_PROTOCOL, &cpu_arch ); + +/** + * Delay for a fixed number of microseconds + * + * @v usecs Number of microseconds for which to delay + */ +static void efi_udelay ( unsigned long usecs ) { + EFI_BOOT_SERVICES *bs = efi_systab->BootServices; + EFI_STATUS efirc; + + if ( ( efirc = bs->Stall ( usecs ) ) != 0 ) { + DBG ( "EFI could not delay for %ldus: %s\n", + usecs, efi_strerror ( efirc ) ); + /* Probably screwed */ + } +} + +/** + * Get current system time in ticks + * + * @ret ticks Current time, in ticks + */ +static unsigned long efi_currticks ( void ) { + UINT64 time; + EFI_STATUS efirc; + + /* 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 ) ); + /* Probably screwed */ + return -1UL; + } + + return ( time >> EFI_TIMER0_SHIFT ); +} + +/** + * Get number of ticks per second + * + * @ret ticks_per_sec Number of ticks per second + */ +static unsigned long efi_ticks_per_sec ( void ) { + static unsigned long ticks_per_sec = 0; + + /* Calibrate timer, if necessary. EFI does nominally provide + * the timer speed via the (optional) TimerPeriod parameter to + * the GetTimerValue() call, but it gets the speed slightly + * wrong. By up to three orders of magnitude. Not helpful. + */ + if ( ! ticks_per_sec ) { + unsigned long start; + unsigned long elapsed; + + DBG ( "Calibrating EFI timer with a %d ms delay\n", + EFI_CALIBRATE_DELAY_MS ); + start = currticks(); + mdelay ( EFI_CALIBRATE_DELAY_MS ); + elapsed = ( currticks() - start ); + ticks_per_sec = ( elapsed * ( 1000 / EFI_CALIBRATE_DELAY_MS )); + DBG ( "EFI CPU timer calibrated at %ld ticks in %d ms (%ld " + "ticks/sec)\n", elapsed, EFI_CALIBRATE_DELAY_MS, + ticks_per_sec ); + } + + return ticks_per_sec; +} + +PROVIDE_TIMER ( efi, udelay, efi_udelay ); +PROVIDE_TIMER ( efi, currticks, efi_currticks ); +PROVIDE_TIMER ( efi, ticks_per_sec, efi_ticks_per_sec ); diff --git a/gpxe/src/interface/efi/efi_uaccess.c b/gpxe/src/interface/efi/efi_uaccess.c new file mode 100644 index 00000000..1c54c031 --- /dev/null +++ b/gpxe/src/interface/efi/efi_uaccess.c @@ -0,0 +1,37 @@ +/* + * 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., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +#include <gpxe/uaccess.h> +#include <gpxe/efi/efi.h> + +/** @file + * + * gPXE user access API for EFI + * + */ + +PROVIDE_UACCESS_INLINE ( efi, phys_to_user ); +PROVIDE_UACCESS_INLINE ( efi, user_to_phys ); +PROVIDE_UACCESS_INLINE ( efi, virt_to_user ); +PROVIDE_UACCESS_INLINE ( efi, user_to_virt ); +PROVIDE_UACCESS_INLINE ( efi, userptr_add ); +PROVIDE_UACCESS_INLINE ( efi, memcpy_user ); +PROVIDE_UACCESS_INLINE ( efi, memmove_user ); +PROVIDE_UACCESS_INLINE ( efi, memset_user ); +PROVIDE_UACCESS_INLINE ( efi, strlen_user ); +PROVIDE_UACCESS_INLINE ( efi, memchr_user ); diff --git a/gpxe/src/interface/efi/efi_umalloc.c b/gpxe/src/interface/efi/efi_umalloc.c new file mode 100644 index 00000000..4de3789d --- /dev/null +++ b/gpxe/src/interface/efi/efi_umalloc.c @@ -0,0 +1,96 @@ +/* + * 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., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +#include <assert.h> +#include <gpxe/umalloc.h> +#include <gpxe/efi/efi.h> + +/** @file + * + * gPXE user memory allocation API for EFI + * + */ + +/** Equivalent of NOWHERE for user pointers */ +#define UNOWHERE ( ~UNULL ) + +/** + * Reallocate external memory + * + * @v old_ptr Memory previously allocated by umalloc(), or UNULL + * @v new_size Requested size + * @ret new_ptr Allocated memory, or UNULL + * + * Calling realloc() with a new size of zero is a valid way to free a + * memory block. + */ +static userptr_t efi_urealloc ( userptr_t old_ptr, size_t new_size ) { + EFI_BOOT_SERVICES *bs = efi_systab->BootServices; + EFI_PHYSICAL_ADDRESS phys_addr; + unsigned int new_pages, old_pages; + userptr_t new_ptr = UNOWHERE; + size_t old_size; + EFI_STATUS efirc; + + /* Allocate new memory if necessary. If allocation fails, + * return without touching the old block. + */ + if ( new_size ) { + new_pages = ( EFI_SIZE_TO_PAGES ( new_size ) + 1 ); + if ( ( efirc = bs->AllocatePages ( AllocateAnyPages, + EfiBootServicesData, + new_pages, + &phys_addr ) ) != 0 ) { + DBG ( "EFI could not allocate %d pages: %s\n", + new_pages, efi_strerror ( efirc ) ); + return UNULL; + } + assert ( phys_addr != 0 ); + new_ptr = phys_to_user ( phys_addr + EFI_PAGE_SIZE ); + copy_to_user ( new_ptr, -EFI_PAGE_SIZE, + &new_size, sizeof ( new_size ) ); + DBG ( "EFI allocated %d pages at %llx\n", + new_pages, phys_addr ); + } + + /* Copy across relevant part of the old data region (if any), + * then free it. Note that at this point either (a) new_ptr + * is valid, or (b) new_size is 0; either way, the memcpy() is + * valid. + */ + if ( old_ptr && ( old_ptr != UNOWHERE ) ) { + copy_from_user ( &old_size, old_ptr, -EFI_PAGE_SIZE, + sizeof ( old_size ) ); + memcpy_user ( new_ptr, 0, old_ptr, 0, + ( (old_size < new_size) ? old_size : 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 ){ + DBG ( "EFI could not free %d pages at %llx: %s\n", + old_pages, phys_addr, efi_strerror ( efirc ) ); + /* Not fatal; we have leaked memory but successfully + * allocated (if asked to do so). + */ + } + DBG ( "EFI freed %d pages at %llx\n", old_pages, phys_addr ); + } + + return new_ptr; +} + +PROVIDE_UMALLOC ( efi, urealloc, efi_urealloc ); diff --git a/gpxe/src/arch/i386/firmware/pcbios/smbios.c b/gpxe/src/interface/smbios/smbios.c index a2cb3b88..8207c1fa 100644 --- a/gpxe/src/arch/i386/firmware/pcbios/smbios.c +++ b/gpxe/src/interface/smbios/smbios.c @@ -21,9 +21,7 @@ #include <errno.h> #include <assert.h> #include <gpxe/uaccess.h> -#include <realmode.h> -#include <pnpbios.h> -#include <smbios.h> +#include <gpxe/smbios.h> /** @file * @@ -31,124 +29,12 @@ * */ -/** Signature for SMBIOS entry point */ -#define SMBIOS_SIGNATURE \ - ( ( '_' << 0 ) + ( 'S' << 8 ) + ( 'M' << 16 ) + ( '_' << 24 ) ) - -/** - * SMBIOS entry point - * - * This is the single table which describes the list of SMBIOS - * structures. It is located by scanning through the BIOS segment. - */ -struct smbios_entry { - /** Signature - * - * Must be equal to SMBIOS_SIGNATURE - */ - uint32_t signature; - /** Checksum */ - uint8_t checksum; - /** Length */ - uint8_t len; - /** Major version */ - uint8_t major; - /** Minor version */ - uint8_t minor; - /** Maximum structure size */ - uint16_t max; - /** Entry point revision */ - uint8_t revision; - /** Formatted area */ - uint8_t formatted[5]; - /** DMI Signature */ - uint8_t dmi_signature[5]; - /** DMI checksum */ - uint8_t dmi_checksum; - /** Structure table length */ - uint16_t smbios_len; - /** Structure table address */ - physaddr_t smbios_address; - /** Number of SMBIOS structures */ - uint16_t smbios_count; - /** BCD revision */ - uint8_t bcd_revision; -} __attribute__ (( packed )); - -/** - * SMBIOS entry point descriptor - * - * This contains the information from the SMBIOS entry point that we - * care about. - */ -struct smbios { - /** Start of SMBIOS structures */ - userptr_t address; - /** Length of SMBIOS structures */ - size_t len; - /** Number of SMBIOS structures */ - unsigned int count; -}; - /** SMBIOS entry point descriptor */ static struct smbios smbios = { .address = UNULL, }; /** - * Find SMBIOS - * - * @ret rc Return status code - */ -static int find_smbios ( void ) { - 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; - - /* Return cached result if avaiable */ - if ( smbios.address != UNULL ) - return 0; - - /* Try to find SMBIOS */ - for ( ; offset < 0x10000 ; offset += 0x10 ) { - - /* 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; - - /* 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; -} - -/** * Find SMBIOS strings terminator * * @v offset Offset to start of strings @@ -182,8 +68,10 @@ int find_smbios_structure ( unsigned int type, int rc; /* Find SMBIOS */ - if ( ( rc = find_smbios() ) != 0 ) + if ( ( smbios.address == UNULL ) && + ( ( rc = find_smbios ( &smbios ) ) != 0 ) ) return rc; + assert ( smbios.address != UNULL ); /* Scan through list of structures */ while ( ( ( offset + sizeof ( structure->header ) ) < smbios.len ) diff --git a/gpxe/src/arch/i386/firmware/pcbios/smbios_settings.c b/gpxe/src/interface/smbios/smbios_settings.c index b088e51d..61c2d919 100644 --- a/gpxe/src/arch/i386/firmware/pcbios/smbios_settings.c +++ b/gpxe/src/interface/smbios/smbios_settings.c @@ -22,7 +22,17 @@ #include <gpxe/settings.h> #include <gpxe/init.h> #include <gpxe/uuid.h> -#include <smbios.h> +#include <gpxe/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 ) /** * Construct SMBIOS raw-data tag @@ -33,7 +43,8 @@ * @ret tag SMBIOS setting tag */ #define SMBIOS_RAW_TAG( _type, _structure, _field ) \ - ( ( (_type) << 16 ) | \ + ( ( SMBIOS_TAG_MAGIC << 24 ) | \ + ( (_type) << 16 ) | \ ( offsetof ( _structure, _field ) << 8 ) | \ ( sizeof ( ( ( _structure * ) 0 )->_field ) ) ) @@ -46,7 +57,8 @@ * @ret tag SMBIOS setting tag */ #define SMBIOS_STRING_TAG( _type, _structure, _field ) \ - ( ( (_type) << 16 ) | \ + ( ( SMBIOS_TAG_MAGIC << 24 ) | \ + ( (_type) << 16 ) | \ ( offsetof ( _structure, _field ) << 8 ) ) /** @@ -78,16 +90,18 @@ 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_type; unsigned int tag_offset; unsigned int tag_len; int rc; /* Split tag into type, offset and length */ - tag_type = ( setting->tag >> 16 ); + tag_magic = ( setting->tag >> 24 ); + tag_type = ( ( setting->tag >> 16 ) & 0xff ); tag_offset = ( ( setting->tag >> 8 ) & 0xff ); tag_len = ( setting->tag & 0xff ); - if ( ! tag_type ) + if ( tag_magic != SMBIOS_TAG_MAGIC ) return -ENOENT; /* Find SMBIOS structure */ @@ -127,6 +141,7 @@ static struct settings_operations smbios_settings_operations = { static struct settings smbios_settings = { .refcnt = NULL, .name = "smbios", + .tag_magic = SMBIOS_EMPTY_TAG, .siblings = LIST_HEAD_INIT ( smbios_settings.siblings ), .children = LIST_HEAD_INIT ( smbios_settings.children ), .op = &smbios_settings_operations, diff --git a/gpxe/src/libgcc/__divdi3.c b/gpxe/src/libgcc/__divdi3.c index 36f0b37f..7097b11e 100644 --- a/gpxe/src/libgcc/__divdi3.c +++ b/gpxe/src/libgcc/__divdi3.c @@ -4,7 +4,7 @@ #include "libgcc.h" -LIBGCC int64_t __divdi3(int64_t num, int64_t den) +__libgcc int64_t __divdi3(int64_t num, int64_t den) { int minus = 0; int64_t v; diff --git a/gpxe/src/libgcc/__moddi3.c b/gpxe/src/libgcc/__moddi3.c index eb7784b7..d671bbc4 100644 --- a/gpxe/src/libgcc/__moddi3.c +++ b/gpxe/src/libgcc/__moddi3.c @@ -4,7 +4,7 @@ #include "libgcc.h" -LIBGCC int64_t __moddi3(int64_t num, int64_t den) +__libgcc int64_t __moddi3(int64_t num, int64_t den) { int minus = 0; int64_t v; diff --git a/gpxe/src/libgcc/__udivdi3.c b/gpxe/src/libgcc/__udivdi3.c index 9ae0c3dc..f5a14de2 100644 --- a/gpxe/src/libgcc/__udivdi3.c +++ b/gpxe/src/libgcc/__udivdi3.c @@ -4,7 +4,7 @@ #include "libgcc.h" -LIBGCC uint64_t __udivdi3(uint64_t num, uint64_t den) +__libgcc uint64_t __udivdi3(uint64_t num, uint64_t den) { return __udivmoddi4(num, den, NULL); } diff --git a/gpxe/src/libgcc/__udivmoddi4.c b/gpxe/src/libgcc/__udivmoddi4.c index 59966edb..21e0d51f 100644 --- a/gpxe/src/libgcc/__udivmoddi4.c +++ b/gpxe/src/libgcc/__udivmoddi4.c @@ -1,6 +1,6 @@ #include "libgcc.h" -LIBGCC uint64_t __udivmoddi4(uint64_t num, uint64_t den, uint64_t *rem_p) +__libgcc uint64_t __udivmoddi4(uint64_t num, uint64_t den, uint64_t *rem_p) { uint64_t quot = 0, qbit = 1; diff --git a/gpxe/src/libgcc/__umoddi3.c b/gpxe/src/libgcc/__umoddi3.c index f6c76cb6..fb4da991 100644 --- a/gpxe/src/libgcc/__umoddi3.c +++ b/gpxe/src/libgcc/__umoddi3.c @@ -4,7 +4,7 @@ #include "libgcc.h" -LIBGCC uint64_t __umoddi3(uint64_t num, uint64_t den) +__libgcc uint64_t __umoddi3(uint64_t num, uint64_t den) { uint64_t v; diff --git a/gpxe/src/libgcc/libgcc.h b/gpxe/src/libgcc/libgcc.h index 5b4a6244..d3e9bdd7 100644 --- a/gpxe/src/libgcc/libgcc.h +++ b/gpxe/src/libgcc/libgcc.h @@ -4,23 +4,11 @@ #include <stdint.h> #include <stddef.h> -/* - * It seems as though gcc expects its implicit arithmetic functions to - * be cdecl, even if -mrtd is specified. This is somewhat - * inconsistent; for example, if -mregparm=3 is used then the implicit - * functions do become regparm(3). - * - * 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. - * - */ -#define LIBGCC __attribute__ (( cdecl )) - -extern LIBGCC uint64_t __udivmoddi4(uint64_t num, uint64_t den, uint64_t *rem); -extern LIBGCC uint64_t __udivdi3(uint64_t num, uint64_t den); -extern LIBGCC uint64_t __umoddi3(uint64_t num, uint64_t den); -extern LIBGCC int64_t __divdi3(int64_t num, int64_t den); -extern LIBGCC int64_t __moddi3(int64_t num, int64_t den); +extern __libgcc uint64_t __udivmoddi4 ( uint64_t num, uint64_t den, + uint64_t *rem ); +extern __libgcc uint64_t __udivdi3 (uint64_t num, uint64_t den ); +extern __libgcc uint64_t __umoddi3 ( uint64_t num, uint64_t den ); +extern __libgcc int64_t __divdi3 ( int64_t num, int64_t den ); +extern __libgcc int64_t __moddi3 ( int64_t num, int64_t den ); #endif /* _LIBGCC_H */ diff --git a/gpxe/src/net/aoe.c b/gpxe/src/net/aoe.c index e3f84e5a..08887fe0 100644 --- a/gpxe/src/net/aoe.c +++ b/gpxe/src/net/aoe.c @@ -64,8 +64,13 @@ static void aoe_free ( struct refcnt *refcnt ) { static void aoe_done ( struct aoe_session *aoe, int rc ) { /* Record overall command status */ - aoe->command->cb.cmd_stat = aoe->status; - aoe->command = NULL; + if ( aoe->command ) { + aoe->command->cb.cmd_stat = aoe->status; + aoe->command = NULL; + } + + /* Stop retransmission timer */ + stop_timer ( &aoe->timer ); /* Mark operation as complete */ aoe->rc = rc; @@ -84,9 +89,11 @@ static int aoe_send_command ( struct aoe_session *aoe ) { struct ata_command *command = aoe->command; struct io_buffer *iobuf; struct aoehdr *aoehdr; - struct aoecmd *aoecmd; + union aoecmd *aoecmd; + struct aoeata *aoeata; unsigned int count; unsigned int data_out_len; + unsigned int aoecmdlen; /* Fail immediately if we have no netdev to send on */ if ( ! aoe->netdev ) { @@ -94,46 +101,81 @@ static int aoe_send_command ( struct aoe_session *aoe ) { return -ENETUNREACH; } + /* If we are transmitting anything that requires a response, + * start the retransmission timer. Do this before attempting + * to allocate the I/O buffer, in case allocation itself + * fails. + */ + start_timer ( &aoe->timer ); + /* Calculate count and data_out_len for this subcommand */ - count = command->cb.count.native; - if ( count > AOE_MAX_COUNT ) - count = AOE_MAX_COUNT; - data_out_len = ( command->data_out ? ( count * ATA_SECTOR_SIZE ) : 0 ); + switch ( aoe->aoe_cmd_type ) { + case AOE_CMD_ATA: + count = command->cb.count.native; + if ( count > AOE_MAX_COUNT ) + count = AOE_MAX_COUNT; + data_out_len = ( command->data_out ? + ( count * ATA_SECTOR_SIZE ) : 0 ); + aoecmdlen = sizeof ( aoecmd->ata ); + break; + case AOE_CMD_CONFIG: + count = 0; + data_out_len = 0; + aoecmdlen = sizeof ( aoecmd->cfg ); + break; + default: + return -ENOTSUP; + } /* Create outgoing I/O buffer */ - iobuf = alloc_iob ( ETH_HLEN + sizeof ( *aoehdr ) + sizeof ( *aoecmd ) + - data_out_len ); + iobuf = alloc_iob ( ETH_HLEN + sizeof ( *aoehdr ) + + aoecmdlen + data_out_len ); + if ( ! iobuf ) return -ENOMEM; iob_reserve ( iobuf, ETH_HLEN ); aoehdr = iob_put ( iobuf, sizeof ( *aoehdr ) ); - aoecmd = iob_put ( iobuf, sizeof ( *aoecmd ) ); - memset ( aoehdr, 0, ( sizeof ( *aoehdr ) + sizeof ( *aoecmd ) ) ); + aoecmd = iob_put ( iobuf, aoecmdlen ); + memset ( aoehdr, 0, ( sizeof ( *aoehdr ) + aoecmdlen ) ); /* Fill AoE header */ aoehdr->ver_flags = AOE_VERSION; aoehdr->major = htons ( aoe->major ); aoehdr->minor = aoe->minor; + aoehdr->command = aoe->aoe_cmd_type; aoehdr->tag = htonl ( ++aoe->tag ); - /* Fill AoE command */ - linker_assert ( AOE_FL_DEV_HEAD == ATA_DEV_SLAVE, __fix_ata_h__ ); - aoecmd->aflags = ( ( command->cb.lba48 ? AOE_FL_EXTENDED : 0 ) | - ( command->cb.device & ATA_DEV_SLAVE ) | - ( data_out_len ? AOE_FL_WRITE : 0 ) ); - aoecmd->err_feat = command->cb.err_feat.bytes.cur; - aoecmd->count = count; - aoecmd->cmd_stat = command->cb.cmd_stat; - aoecmd->lba.u64 = cpu_to_le64 ( command->cb.lba.native ); - if ( ! command->cb.lba48 ) - aoecmd->lba.bytes[3] |= ( command->cb.device & ATA_DEV_MASK ); - - /* Fill data payload */ - copy_from_user ( iob_put ( iobuf, data_out_len ), command->data_out, - aoe->command_offset, data_out_len ); + /* Fill AoE payload */ + switch ( aoe->aoe_cmd_type ) { + case AOE_CMD_ATA: + /* Fill AoE command */ + aoeata = &aoecmd->ata; + linker_assert ( AOE_FL_DEV_HEAD == ATA_DEV_SLAVE, + __fix_ata_h__ ); + aoeata->aflags = ( ( command->cb.lba48 ? AOE_FL_EXTENDED : 0 )| + ( command->cb.device & ATA_DEV_SLAVE ) | + ( data_out_len ? AOE_FL_WRITE : 0 ) ); + aoeata->err_feat = command->cb.err_feat.bytes.cur; + aoeata->count = count; + aoeata->cmd_stat = command->cb.cmd_stat; + aoeata->lba.u64 = cpu_to_le64 ( command->cb.lba.native ); + if ( ! command->cb.lba48 ) + aoeata->lba.bytes[3] |= + ( command->cb.device & ATA_DEV_MASK ); + + /* Fill data payload */ + copy_from_user ( iob_put ( iobuf, data_out_len ), + command->data_out, aoe->command_offset, + data_out_len ); + break; + case AOE_CMD_CONFIG: + /* Nothing to do */ + break; + default: + assert ( 0 ); + } /* Send packet */ - start_timer ( &aoe->timer ); return net_tx ( iobuf, aoe->netdev, &aoe_protocol, aoe->target ); } @@ -155,38 +197,46 @@ static void aoe_timer_expired ( struct retry_timer *timer, int fail ) { } /** - * Handle AoE response + * Handle AoE configuration command response * * @v aoe AoE session - * @v aoehdr AoE header + * @v ll_source Link-layer source address * @ret rc Return status code */ -static int aoe_rx_response ( struct aoe_session *aoe, struct aoehdr *aoehdr, - unsigned int len ) { - struct aoecmd *aoecmd = aoehdr->arg.command; +static int aoe_rx_cfg ( struct aoe_session *aoe, const void *ll_source ) { + + /* Record target MAC address */ + memcpy ( aoe->target, ll_source, sizeof ( aoe->target ) ); + DBGC ( aoe, "AoE %p target MAC address %s\n", + aoe, eth_ntoa ( aoe->target ) ); + + /* Mark config request as complete */ + aoe_done ( aoe, 0 ); + + return 0; +} + +/** + * Handle AoE ATA command response + * + * @v aoe AoE session + * @v aoeata AoE ATA command + * @v len Length of AoE ATA command + * @ret rc Return status code + */ +static int aoe_rx_ata ( struct aoe_session *aoe, struct aoeata *aoeata, + size_t len ) { struct ata_command *command = aoe->command; unsigned int rx_data_len; unsigned int count; unsigned int data_len; - + /* Sanity check */ - if ( len < ( sizeof ( *aoehdr ) + sizeof ( *aoecmd ) ) ) { + if ( len < sizeof ( *aoeata ) ) { /* Ignore packet; allow timer to trigger retransmit */ return -EINVAL; } - rx_data_len = ( len - sizeof ( *aoehdr ) - sizeof ( *aoecmd ) ); - - /* Stop retry timer. After this point, every code path must - * either terminate the AoE operation via aoe_done(), or - * transmit a new packet. - */ - stop_timer ( &aoe->timer ); - - /* Check for fatal errors */ - if ( aoehdr->ver_flags & AOE_FL_ERROR ) { - aoe_done ( aoe, -EIO ); - return 0; - } + rx_data_len = ( len - sizeof ( *aoeata ) ); /* Calculate count and data_len for this subcommand */ count = command->cb.count.native; @@ -195,14 +245,14 @@ static int aoe_rx_response ( struct aoe_session *aoe, struct aoehdr *aoehdr, data_len = count * ATA_SECTOR_SIZE; /* Merge into overall ATA status */ - aoe->status |= aoecmd->cmd_stat; + aoe->status |= aoeata->cmd_stat; /* Copy data payload */ if ( command->data_in ) { if ( rx_data_len > data_len ) rx_data_len = data_len; copy_to_user ( command->data_in, aoe->command_offset, - aoecmd->data, rx_data_len ); + aoeata->data, rx_data_len ); } /* Update ATA command and offset */ @@ -217,6 +267,7 @@ static int aoe_rx_response ( struct aoe_session *aoe, struct aoehdr *aoehdr, } /* Transmit next portion of request */ + stop_timer ( &aoe->timer ); aoe_send_command ( aoe ); return 0; @@ -231,15 +282,15 @@ static int aoe_rx_response ( struct aoe_session *aoe, struct aoehdr *aoehdr, * @ret rc Return status code * */ -static int aoe_rx ( struct io_buffer *iobuf, struct net_device *netdev __unused, +static int aoe_rx ( struct io_buffer *iobuf, + struct net_device *netdev __unused, const void *ll_source ) { struct aoehdr *aoehdr = iobuf->data; - unsigned int len = iob_len ( iobuf ); struct aoe_session *aoe; int rc = 0; /* Sanity checks */ - if ( len < sizeof ( *aoehdr ) ) { + if ( iob_len ( iobuf ) < sizeof ( *aoehdr ) ) { rc = -EINVAL; goto done; } @@ -251,6 +302,7 @@ static int aoe_rx ( struct io_buffer *iobuf, struct net_device *netdev __unused, /* Ignore AoE requests that we happen to see */ goto done; } + iob_pull ( iobuf, sizeof ( *aoehdr ) ); /* Demultiplex amongst active AoE sessions */ list_for_each_entry ( aoe, &aoe_sessions, list ) { @@ -260,8 +312,22 @@ static int aoe_rx ( struct io_buffer *iobuf, struct net_device *netdev __unused, continue; if ( ntohl ( aoehdr->tag ) != aoe->tag ) continue; - memcpy ( aoe->target, ll_source, sizeof ( aoe->target ) ); - rc = aoe_rx_response ( aoe, aoehdr, len ); + if ( aoehdr->ver_flags & AOE_FL_ERROR ) { + aoe_done ( aoe, -EIO ); + break; + } + switch ( aoehdr->command ) { + case AOE_CMD_ATA: + rc = aoe_rx_ata ( aoe, iobuf->data, iob_len ( iobuf )); + break; + case AOE_CMD_CONFIG: + rc = aoe_rx_cfg ( aoe, ll_source ); + break; + default: + DBGC ( aoe, "AoE %p ignoring command %02x\n", + aoe, aoehdr->command ); + break; + } break; } @@ -293,6 +359,32 @@ static int aoe_command ( struct ata_device *ata, aoe->command = command; aoe->status = 0; aoe->command_offset = 0; + aoe->aoe_cmd_type = AOE_CMD_ATA; + + aoe_send_command ( aoe ); + + aoe->rc = -EINPROGRESS; + while ( aoe->rc == -EINPROGRESS ) + step(); + rc = aoe->rc; + + return rc; +} + + +/** + * Issue AoE config query for AoE target discovery + * + * @v aoe AoE session + * @ret rc Return status code + */ +static int aoe_discover ( struct aoe_session *aoe ) { + int rc; + + aoe->status = 0; + aoe->aoe_cmd_type = AOE_CMD_CONFIG; + aoe->command = NULL; + aoe_send_command ( aoe ); aoe->rc = -EINPROGRESS; @@ -367,6 +459,15 @@ int aoe_attach ( struct ata_device *ata, struct net_device *netdev, ata->backend = ref_get ( &aoe->refcnt ); ata->command = aoe_command; list_add ( &aoe->list, &aoe_sessions ); + + /* Send discovery packet to find the target MAC address. + * Ideally, this ought to be done asynchronously, but the + * block device interface does not yet support asynchronous + * operation. + */ + if ( ( rc = aoe_discover( aoe ) ) != 0 ) + goto err; + return 0; err: diff --git a/gpxe/src/net/arp.c b/gpxe/src/net/arp.c index 011d4fef..ba9ebf48 100644 --- a/gpxe/src/net/arp.c +++ b/gpxe/src/net/arp.c @@ -265,8 +265,8 @@ static int arp_rx ( struct io_buffer *iobuf, struct net_device *netdev, memcpy ( arp_sender_ha ( arphdr ), netdev->ll_addr, arphdr->ar_hln ); /* Send reply */ - net_tx ( iobuf, netdev, &arp_protocol, arp_target_ha (arphdr ) ); - iobuf = NULL; + net_tx ( iob_disown ( iobuf ), netdev, &arp_protocol, + arp_target_ha ( arphdr ) ); done: free_iob ( iobuf ); diff --git a/gpxe/src/net/dhcppkt.c b/gpxe/src/net/dhcppkt.c index c8bf215b..1f2d373c 100644 --- a/gpxe/src/net/dhcppkt.c +++ b/gpxe/src/net/dhcppkt.c @@ -32,6 +32,12 @@ * */ +/**************************************************************************** + * + * DHCP packet raw interface + * + */ + /** * Calculate used length of an IPv4 field within a DHCP packet * @@ -193,21 +199,79 @@ int dhcppkt_fetch ( struct dhcp_packet *dhcppkt, unsigned int tag, return dhcpopt_fetch ( &dhcppkt->options, tag, data, len ); } +/**************************************************************************** + * + * DHCP packet settings interface + * + */ + +/** + * Store value of DHCP setting + * + * @v settings Settings block + * @v setting Setting to store + * @v data Setting data, or NULL to clear setting + * @v len Length of setting data + * @ret rc Return status code + */ +static int dhcppkt_settings_store ( struct settings *settings, + struct setting *setting, + const void *data, size_t len ) { + struct dhcp_packet *dhcppkt = + container_of ( settings, struct dhcp_packet, settings ); + + return dhcppkt_store ( dhcppkt, setting->tag, data, len ); +} + +/** + * Fetch value of DHCP 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 + */ +static int dhcppkt_settings_fetch ( struct settings *settings, + struct setting *setting, + void *data, size_t len ) { + struct dhcp_packet *dhcppkt = + container_of ( settings, struct dhcp_packet, settings ); + + return dhcppkt_fetch ( dhcppkt, setting->tag, data, len ); +} + +/** DHCP settings operations */ +static struct settings_operations dhcppkt_settings_operations = { + .store = dhcppkt_settings_store, + .fetch = dhcppkt_settings_fetch, +}; + +/**************************************************************************** + * + * Constructor + * + */ + /** - * Initialise prepopulated DHCP packet + * Initialise DHCP packet * - * @v dhcppkt Uninitialised DHCP packet - * @v data Memory for DHCP packet data - * @v max_len Length of memory for DHCP packet data + * @v dhcppkt DHCP packet structure to fill in + * @v data DHCP packet raw data + * @v max_len Length of raw data buffer * - * The memory content must already be filled with valid DHCP options. - * A zeroed block counts as a block of valid DHCP options. + * Initialise a DHCP packet structure from a data buffer containing a + * DHCP packet. */ -void dhcppkt_init ( struct dhcp_packet *dhcppkt, void *data, size_t len ) { +void dhcppkt_init ( struct dhcp_packet *dhcppkt, struct dhcphdr *data, + size_t len ) { dhcppkt->dhcphdr = data; dhcppkt->max_len = len; dhcpopt_init ( &dhcppkt->options, &dhcppkt->dhcphdr->options, ( len - offsetof ( struct dhcphdr, options ) ) ); dhcppkt->len = ( offsetof ( struct dhcphdr, options ) + dhcppkt->options.len ); + settings_init ( &dhcppkt->settings, + &dhcppkt_settings_operations, &dhcppkt->refcnt, + DHCP_SETTINGS_NAME, 0 ); } diff --git a/gpxe/src/net/ethernet.c b/gpxe/src/net/ethernet.c index 7b1c496f..b16135a9 100644 --- a/gpxe/src/net/ethernet.c +++ b/gpxe/src/net/ethernet.c @@ -24,6 +24,7 @@ #include <assert.h> #include <gpxe/if_arp.h> #include <gpxe/if_ether.h> +#include <gpxe/in.h> #include <gpxe/netdevice.h> #include <gpxe/iobuf.h> #include <gpxe/ethernet.h> @@ -41,19 +42,19 @@ static uint8_t eth_broadcast[ETH_ALEN] = { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff}; * Add Ethernet link-layer header * * @v iobuf I/O buffer - * @v netdev Network device - * @v net_protocol Network-layer protocol * @v ll_dest Link-layer destination address + * @v ll_source Source link-layer address + * @v net_proto Network-layer protocol, in network-byte order + * @ret rc Return status code */ -static int eth_push ( struct io_buffer *iobuf, struct net_device *netdev, - struct net_protocol *net_protocol, - const void *ll_dest ) { +static int eth_push ( struct io_buffer *iobuf, const void *ll_dest, + const void *ll_source, uint16_t net_proto ) { struct ethhdr *ethhdr = iob_push ( iobuf, sizeof ( *ethhdr ) ); /* Build Ethernet header */ memcpy ( ethhdr->h_dest, ll_dest, ETH_ALEN ); - memcpy ( ethhdr->h_source, netdev->ll_addr, ETH_ALEN ); - ethhdr->h_protocol = net_protocol->net_proto; + memcpy ( ethhdr->h_source, ll_source, ETH_ALEN ); + ethhdr->h_protocol = net_proto; return 0; } @@ -62,14 +63,13 @@ static int eth_push ( struct io_buffer *iobuf, struct net_device *netdev, * Remove Ethernet link-layer header * * @v iobuf I/O buffer - * @v netdev Network device - * @v net_proto Network-layer protocol, in network-byte order - * @v ll_source Source link-layer address + * @ret ll_dest Link-layer destination address + * @ret ll_source Source link-layer address + * @ret net_proto Network-layer protocol, in network-byte order * @ret rc Return status code */ -static int eth_pull ( struct io_buffer *iobuf, - struct net_device *netdev __unused, - uint16_t *net_proto, const void **ll_source ) { +static int eth_pull ( struct io_buffer *iobuf, const void **ll_dest, + const void **ll_source, uint16_t *net_proto ) { struct ethhdr *ethhdr = iobuf->data; /* Sanity check */ @@ -83,8 +83,9 @@ static int eth_pull ( struct io_buffer *iobuf, iob_pull ( iobuf, sizeof ( *ethhdr ) ); /* Fill in required fields */ - *net_proto = ethhdr->h_protocol; + *ll_dest = ethhdr->h_dest; *ll_source = ethhdr->h_source; + *net_proto = ethhdr->h_protocol; return 0; } @@ -92,8 +93,8 @@ static int eth_pull ( struct io_buffer *iobuf, /** * Transcribe Ethernet address * - * @v ll_addr Link-layer address - * @ret string Link-layer address in human-readable format + * @v ll_addr Link-layer address + * @ret string Link-layer address in human-readable format */ const char * eth_ntoa ( const void *ll_addr ) { static char buf[18]; /* "00:00:00:00:00:00" */ @@ -105,6 +106,33 @@ const char * eth_ntoa ( const void *ll_addr ) { return buf; } +/** + * Hash multicast address + * + * @v af Address family + * @v net_addr Network-layer address + * @v ll_addr Link-layer address to fill in + * @ret rc Return status code + */ +static int eth_mc_hash ( unsigned int af, const void *net_addr, + void *ll_addr ) { + const uint8_t *net_addr_bytes = net_addr; + uint8_t *ll_addr_bytes = ll_addr; + + switch ( af ) { + case AF_INET: + ll_addr_bytes[0] = 0x01; + ll_addr_bytes[1] = 0x00; + ll_addr_bytes[2] = 0x5e; + ll_addr_bytes[3] = net_addr_bytes[1] & 0x7f; + ll_addr_bytes[4] = net_addr_bytes[2]; + ll_addr_bytes[5] = net_addr_bytes[3]; + return 0; + default: + return -ENOTSUP; + } +} + /** Ethernet protocol */ struct ll_protocol ethernet_protocol __ll_protocol = { .name = "Ethernet", @@ -115,4 +143,5 @@ struct ll_protocol ethernet_protocol __ll_protocol = { .push = eth_push, .pull = eth_pull, .ntoa = eth_ntoa, + .mc_hash = eth_mc_hash, }; diff --git a/gpxe/src/net/fakedhcp.c b/gpxe/src/net/fakedhcp.c index 60264756..0518789c 100644 --- a/gpxe/src/net/fakedhcp.c +++ b/gpxe/src/net/fakedhcp.c @@ -111,8 +111,8 @@ int create_fakedhcpdiscover ( struct net_device *netdev, struct in_addr ciaddr = { 0 }; int rc; - if ( ( rc = dhcp_create_request ( &dhcppkt, netdev, ciaddr, NULL, data, - max_len ) ) != 0 ) { + if ( ( rc = dhcp_create_request ( &dhcppkt, netdev, DHCPDISCOVER, + ciaddr, data, max_len ) ) != 0 ) { DBG ( "Could not create DHCPDISCOVER: %s\n", strerror ( rc ) ); return rc; @@ -137,7 +137,7 @@ int create_fakedhcpack ( struct net_device *netdev, int rc; /* Create base DHCPACK packet */ - if ( ( rc = dhcp_create_packet ( &dhcppkt, netdev, DHCPACK, NULL, + if ( ( rc = dhcp_create_packet ( &dhcppkt, netdev, DHCPACK, NULL, 0, data, max_len ) ) != 0 ) { DBG ( "Could not create DHCPACK: %s\n", strerror ( rc ) ); return rc; @@ -163,7 +163,7 @@ int create_fakedhcpack ( struct net_device *netdev, } /** - * Create ProxyDHCPACK packet + * Create fake PXE Boot Server ACK packet * * @v netdev Network device * @v data Buffer for DHCP packet @@ -172,30 +172,41 @@ int create_fakedhcpack ( struct net_device *netdev, * * Used by external code. */ -int create_fakeproxydhcpack ( struct net_device *netdev, - void *data, size_t max_len ) { +int create_fakepxebsack ( struct net_device *netdev, + void *data, size_t max_len ) { struct dhcp_packet dhcppkt; - struct settings *settings; + struct settings *proxy_settings; + struct settings *pxebs_settings; int rc; - /* Identify ProxyDHCP settings */ - settings = find_settings ( PROXYDHCP_SETTINGS_NAME ); - - /* No ProxyDHCP settings => use normal DHCPACK */ - if ( ! settings ) + /* Identify available settings */ + proxy_settings = find_settings ( PROXYDHCP_SETTINGS_NAME ); + pxebs_settings = find_settings ( PXEBS_SETTINGS_NAME ); + if ( ( ! proxy_settings ) && ( ! pxebs_settings ) ) { + /* No PXE boot server; return the regular DHCPACK */ return create_fakedhcpack ( netdev, data, max_len ); + } /* Create base DHCPACK packet */ - if ( ( rc = dhcp_create_packet ( &dhcppkt, netdev, DHCPACK, NULL, + if ( ( rc = dhcp_create_packet ( &dhcppkt, netdev, DHCPACK, NULL, 0, data, max_len ) ) != 0 ) { - DBG ( "Could not create ProxyDHCPACK: %s\n", + DBG ( "Could not create PXE BS ACK: %s\n", strerror ( rc ) ); return rc; } /* Merge in ProxyDHCP options */ - if ( ( rc = copy_settings ( &dhcppkt, settings ) ) != 0 ) { - DBG ( "Could not set ProxyDHCPACK settings: %s\n", + if ( proxy_settings && + ( ( rc = copy_settings ( &dhcppkt, proxy_settings ) ) != 0 ) ) { + DBG ( "Could not copy ProxyDHCP settings: %s\n", + strerror ( rc ) ); + return rc; + } + + /* Merge in BootServerDHCP options, if present */ + if ( pxebs_settings && + ( ( rc = copy_settings ( &dhcppkt, pxebs_settings ) ) != 0 ) ) { + DBG ( "Could not copy PXE BS settings: %s\n", strerror ( rc ) ); return rc; } diff --git a/gpxe/src/net/icmp.c b/gpxe/src/net/icmp.c new file mode 100644 index 00000000..3e45c1f6 --- /dev/null +++ b/gpxe/src/net/icmp.c @@ -0,0 +1,101 @@ +/* + * Copyright (C) 2009 Michael Brown <mbrown@fensystems.co.uk>. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of the + * License, or any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +#include <string.h> +#include <errno.h> +#include <gpxe/iobuf.h> +#include <gpxe/in.h> +#include <gpxe/tcpip.h> +#include <gpxe/icmp.h> + +/** @file + * + * ICMP protocol + * + */ + +struct tcpip_protocol icmp_protocol __tcpip_protocol; + +/** + * Process a received 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 + * @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; + 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; + } + + /* 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; + } + + /* We respond only to pings */ + if ( icmp->type != ICMP_ECHO_REQUEST ) { + DBG ( "ICMP ignoring type %d\n", icmp->type ); + rc = 0; + goto done; + } + + DBG ( "ICMP responding to ping\n" ); + + /* Change type to response and recalculate checksum */ + icmp->type = ICMP_ECHO_RESPONSE; + icmp->chksum = 0; + icmp->chksum = tcpip_chksum ( icmp, len ); + + /* 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; + } + + done: + free_iob ( iobuf ); + return rc; +} + +/** ICMP TCP/IP protocol */ +struct tcpip_protocol icmp_protocol __tcpip_protocol = { + .name = "ICMP", + .rx = icmp_rx, + .tcpip_proto = IP_ICMP, +}; diff --git a/gpxe/src/net/icmpv6.c b/gpxe/src/net/icmpv6.c index 7b7146c2..237fc4a6 100644 --- a/gpxe/src/net/icmpv6.c +++ b/gpxe/src/net/icmpv6.c @@ -60,7 +60,7 @@ int icmp6_send_solicit ( struct net_device *netdev, struct in6_addr *src __unuse st_dest.sin6.sin6_addr.in6_u.u6_addr8[13] = 0xff; /* Send packet over IP6 */ - return tcpip_tx ( iobuf, &icmp6_protocol, &st_dest.st, + return tcpip_tx ( iobuf, &icmp6_protocol, NULL, &st_dest.st, NULL, &nsolicit->csum ); } diff --git a/gpxe/src/net/infiniband.c b/gpxe/src/net/infiniband.c index ab76742e..d79bdc2c 100644 --- a/gpxe/src/net/infiniband.c +++ b/gpxe/src/net/infiniband.c @@ -46,10 +46,12 @@ struct list_head ib_devices = LIST_HEAD_INIT ( ib_devices ); * * @v ibdev Infiniband device * @v num_cqes Number of completion queue entries + * @v op Completion queue operations * @ret cq New completion queue */ -struct ib_completion_queue * ib_create_cq ( struct ib_device *ibdev, - unsigned int num_cqes ) { +struct ib_completion_queue * +ib_create_cq ( struct ib_device *ibdev, unsigned int num_cqes, + struct ib_completion_queue_operations *op ) { struct ib_completion_queue *cq; int rc; @@ -58,22 +60,28 @@ struct ib_completion_queue * ib_create_cq ( struct ib_device *ibdev, /* Allocate and initialise data structure */ cq = zalloc ( sizeof ( *cq ) ); if ( ! cq ) - return NULL; + goto err_alloc_cq; cq->num_cqes = num_cqes; INIT_LIST_HEAD ( &cq->work_queues ); + cq->op = op; /* Perform device-specific initialisation and get CQN */ if ( ( rc = ibdev->op->create_cq ( ibdev, cq ) ) != 0 ) { DBGC ( ibdev, "IBDEV %p could not initialise completion " "queue: %s\n", ibdev, strerror ( rc ) ); - free ( cq ); - return NULL; + goto err_dev_create_cq; } DBGC ( ibdev, "IBDEV %p created %d-entry completion queue %p (%p) " "with CQN %#lx\n", ibdev, num_cqes, cq, ib_cq_get_drvdata ( cq ), cq->cqn ); return cq; + + ibdev->op->destroy_cq ( ibdev, cq ); + err_dev_create_cq: + free ( cq ); + err_alloc_cq: + return NULL; } /** @@ -120,7 +128,9 @@ struct ib_queue_pair * ib_create_qp ( struct ib_device *ibdev, ( num_recv_wqes * sizeof ( qp->recv.iobufs[0] ) ) ); qp = zalloc ( total_size ); if ( ! qp ) - return NULL; + goto err_alloc_qp; + qp->ibdev = ibdev; + list_add ( &qp->list, &ibdev->qps ); qp->qkey = qkey; qp->send.qp = qp; qp->send.is_send = 1; @@ -134,15 +144,13 @@ struct ib_queue_pair * ib_create_qp ( struct ib_device *ibdev, qp->recv.num_wqes = num_recv_wqes; qp->recv.iobufs = ( ( ( void * ) qp ) + sizeof ( *qp ) + ( num_send_wqes * sizeof ( qp->send.iobufs[0] ) )); + INIT_LIST_HEAD ( &qp->mgids ); /* Perform device-specific initialisation and get QPN */ if ( ( rc = ibdev->op->create_qp ( ibdev, qp ) ) != 0 ) { DBGC ( ibdev, "IBDEV %p could not initialise queue pair: " "%s\n", ibdev, strerror ( rc ) ); - list_del ( &qp->send.list ); - list_del ( &qp->recv.list ); - free ( qp ); - return NULL; + goto err_dev_create_qp; } DBGC ( ibdev, "IBDEV %p created queue pair %p (%p) with QPN %#lx\n", @@ -154,6 +162,15 @@ struct ib_queue_pair * ib_create_qp ( struct ib_device *ibdev, ibdev, qp->qpn, num_recv_wqes, qp->recv.iobufs, ( ( ( void * ) qp ) + total_size ) ); return qp; + + ibdev->op->destroy_qp ( ibdev, qp ); + err_dev_create_qp: + list_del ( &qp->send.list ); + list_del ( &qp->recv.list ); + list_del ( &qp->list ); + free ( qp ); + err_alloc_qp: + return NULL; } /** @@ -190,15 +207,80 @@ int ib_modify_qp ( struct ib_device *ibdev, struct ib_queue_pair *qp, * @v qp Queue pair */ void ib_destroy_qp ( struct ib_device *ibdev, struct ib_queue_pair *qp ) { + struct io_buffer *iobuf; + unsigned int i; + DBGC ( ibdev, "IBDEV %p destroying QPN %#lx\n", ibdev, qp->qpn ); + + assert ( list_empty ( &qp->mgids ) ); + + /* Perform device-specific destruction */ ibdev->op->destroy_qp ( ibdev, qp ); + + /* Complete any remaining I/O buffers with errors */ + for ( i = 0 ; i < qp->send.num_wqes ; i++ ) { + if ( ( iobuf = qp->send.iobufs[i] ) != NULL ) + ib_complete_send ( ibdev, qp, iobuf, -ECANCELED ); + } + for ( i = 0 ; i < qp->recv.num_wqes ; i++ ) { + if ( ( iobuf = qp->recv.iobufs[i] ) != NULL ) { + ib_complete_recv ( ibdev, qp, NULL, iobuf, + -ECANCELED ); + } + } + + /* Remove work queues from completion queue */ list_del ( &qp->send.list ); list_del ( &qp->recv.list ); + + /* Free QP */ + list_del ( &qp->list ); free ( qp ); } /** + * Find queue pair by QPN + * + * @v ibdev Infiniband device + * @v qpn Queue pair number + * @ret qp Queue pair, or NULL + */ +struct ib_queue_pair * ib_find_qp_qpn ( struct ib_device *ibdev, + unsigned long qpn ) { + struct ib_queue_pair *qp; + + list_for_each_entry ( qp, &ibdev->qps, list ) { + if ( qp->qpn == qpn ) + return qp; + } + return NULL; +} + +/** + * Find queue pair by multicast GID + * + * @v ibdev Infiniband device + * @v gid Multicast GID + * @ret qp Queue pair, or NULL + */ +struct ib_queue_pair * ib_find_qp_mgid ( struct ib_device *ibdev, + struct ib_gid *gid ) { + struct ib_queue_pair *qp; + struct ib_multicast_gid *mgid; + + list_for_each_entry ( qp, &ibdev->qps, list ) { + list_for_each_entry ( mgid, &qp->mgids, list ) { + if ( memcmp ( &mgid->gid, gid, + sizeof ( mgid->gid ) ) == 0 ) { + return qp; + } + } + } + return NULL; +} + +/** * Find work queue belonging to completion queue * * @v cq Completion queue @@ -217,142 +299,194 @@ struct ib_work_queue * ib_find_wq ( struct ib_completion_queue *cq, return NULL; } -/*************************************************************************** - * - * Management datagram operations - * - *************************************************************************** - */ - /** - * Get port information + * Post send work queue entry * * @v ibdev Infiniband device - * @v port_info Port information datagram to fill in + * @v qp Queue pair + * @v av Address vector + * @v iobuf I/O buffer * @ret rc Return status code */ -static int ib_get_port_info ( struct ib_device *ibdev, - struct ib_mad_port_info *port_info ) { - struct ib_mad_hdr *hdr = &port_info->mad_hdr; +int ib_post_send ( struct ib_device *ibdev, struct ib_queue_pair *qp, + struct ib_address_vector *av, + struct io_buffer *iobuf ) { int rc; - /* Construct MAD */ - memset ( port_info, 0, sizeof ( *port_info ) ); - hdr->base_version = IB_MGMT_BASE_VERSION; - hdr->mgmt_class = IB_MGMT_CLASS_SUBN_LID_ROUTED; - hdr->class_version = 1; - hdr->method = IB_MGMT_METHOD_GET; - hdr->attr_id = htons ( IB_SMP_ATTR_PORT_INFO ); - hdr->attr_mod = htonl ( ibdev->port ); - - if ( ( rc = ib_mad ( ibdev, hdr, sizeof ( *port_info ) ) ) != 0 ) { - DBGC ( ibdev, "IBDEV %p could not get port info: %s\n", - ibdev, strerror ( rc ) ); + /* Check queue fill level */ + if ( qp->send.fill >= qp->send.num_wqes ) { + DBGC ( ibdev, "IBDEV %p QPN %#lx send queue full\n", + ibdev, qp->qpn ); + return -ENOBUFS; + } + + /* Post to hardware */ + if ( ( rc = ibdev->op->post_send ( ibdev, qp, av, iobuf ) ) != 0 ) { + DBGC ( ibdev, "IBDEV %p QPN %#lx could not post send WQE: " + "%s\n", ibdev, qp->qpn, strerror ( rc ) ); return rc; } + + qp->send.fill++; return 0; } /** - * Get GUID information + * Post receive work queue entry * * @v ibdev Infiniband device - * @v guid_info GUID information datagram to fill in + * @v qp Queue pair + * @v iobuf I/O buffer * @ret rc Return status code */ -static int ib_get_guid_info ( struct ib_device *ibdev, - struct ib_mad_guid_info *guid_info ) { - struct ib_mad_hdr *hdr = &guid_info->mad_hdr; +int ib_post_recv ( struct ib_device *ibdev, struct ib_queue_pair *qp, + struct io_buffer *iobuf ) { int rc; - /* Construct MAD */ - memset ( guid_info, 0, sizeof ( *guid_info ) ); - hdr->base_version = IB_MGMT_BASE_VERSION; - hdr->mgmt_class = IB_MGMT_CLASS_SUBN_LID_ROUTED; - hdr->class_version = 1; - hdr->method = IB_MGMT_METHOD_GET; - hdr->attr_id = htons ( IB_SMP_ATTR_GUID_INFO ); + /* Check queue fill level */ + if ( qp->recv.fill >= qp->recv.num_wqes ) { + DBGC ( ibdev, "IBDEV %p QPN %#lx receive queue full\n", + ibdev, qp->qpn ); + return -ENOBUFS; + } - if ( ( rc = ib_mad ( ibdev, hdr, sizeof ( *guid_info ) ) ) != 0 ) { - DBGC ( ibdev, "IBDEV %p could not get GUID info: %s\n", - ibdev, strerror ( rc ) ); + /* Post to hardware */ + if ( ( rc = ibdev->op->post_recv ( ibdev, qp, iobuf ) ) != 0 ) { + DBGC ( ibdev, "IBDEV %p QPN %#lx could not post receive WQE: " + "%s\n", ibdev, qp->qpn, strerror ( rc ) ); return rc; } + + qp->recv.fill++; return 0; } /** - * Get partition key table + * Complete send work queue entry + * + * @v ibdev Infiniband device + * @v qp Queue pair + * @v iobuf I/O buffer + * @v rc Completion status code + */ +void ib_complete_send ( struct ib_device *ibdev, struct ib_queue_pair *qp, + struct io_buffer *iobuf, int rc ) { + qp->send.cq->op->complete_send ( ibdev, qp, iobuf, rc ); + qp->send.fill--; +} + +/** + * Complete receive work queue entry + * + * @v ibdev Infiniband device + * @v qp Queue pair + * @v av Address vector + * @v iobuf I/O buffer + * @v rc Completion status code + */ +void ib_complete_recv ( struct ib_device *ibdev, struct ib_queue_pair *qp, + struct ib_address_vector *av, + struct io_buffer *iobuf, int rc ) { + qp->recv.cq->op->complete_recv ( ibdev, qp, av, iobuf, rc ); + qp->recv.fill--; +} + +/** + * Open port * * @v ibdev Infiniband device - * @v guid_info Partition key table datagram to fill in * @ret rc Return status code */ -static int ib_get_pkey_table ( struct ib_device *ibdev, - struct ib_mad_pkey_table *pkey_table ) { - struct ib_mad_hdr *hdr = &pkey_table->mad_hdr; +int ib_open ( struct ib_device *ibdev ) { int rc; - /* Construct MAD */ - memset ( pkey_table, 0, sizeof ( *pkey_table ) ); - hdr->base_version = IB_MGMT_BASE_VERSION; - hdr->mgmt_class = IB_MGMT_CLASS_SUBN_LID_ROUTED; - hdr->class_version = 1; - hdr->method = IB_MGMT_METHOD_GET; - hdr->attr_id = htons ( IB_SMP_ATTR_PKEY_TABLE ); - - if ( ( rc = ib_mad ( ibdev, hdr, sizeof ( *pkey_table ) ) ) != 0 ) { - DBGC ( ibdev, "IBDEV %p could not get pkey table: %s\n", - ibdev, strerror ( rc ) ); - return rc; + /* Open device if this is the first requested opening */ + if ( ibdev->open_count == 0 ) { + if ( ( rc = ibdev->op->open ( ibdev ) ) != 0 ) + return rc; } + + /* Increment device open request counter */ + ibdev->open_count++; + return 0; } /** - * Get MAD parameters + * Close port * * @v ibdev Infiniband device + */ +void ib_close ( struct ib_device *ibdev ) { + + /* Decrement device open request counter */ + ibdev->open_count--; + + /* Close device if this was the last remaining requested opening */ + if ( ibdev->open_count == 0 ) + ibdev->op->close ( ibdev ); +} + +/** + * Attach to multicast group + * + * @v ibdev Infiniband device + * @v qp Queue pair + * @v gid Multicast GID * @ret rc Return status code */ -static int ib_get_mad_params ( struct ib_device *ibdev ) { - union { - /* This union exists just to save stack space */ - struct ib_mad_port_info port_info; - struct ib_mad_guid_info guid_info; - struct ib_mad_pkey_table pkey_table; - } u; +int ib_mcast_attach ( struct ib_device *ibdev, struct ib_queue_pair *qp, + struct ib_gid *gid ) { + struct ib_multicast_gid *mgid; int rc; - /* Port info gives us the link state, the first half of the - * port GID and the SM LID. - */ - if ( ( rc = ib_get_port_info ( ibdev, &u.port_info ) ) != 0 ) - return rc; - ibdev->link_up = ( ( u.port_info.port_state__link_speed_supported - & 0xf ) == 4 ); - memcpy ( &ibdev->port_gid.u.bytes[0], u.port_info.gid_prefix, 8 ); - ibdev->sm_lid = ntohs ( u.port_info.mastersm_lid ); + /* Add to software multicast GID list */ + mgid = zalloc ( sizeof ( *mgid ) ); + if ( ! mgid ) { + rc = -ENOMEM; + goto err_alloc_mgid; + } + memcpy ( &mgid->gid, gid, sizeof ( mgid->gid ) ); + list_add ( &mgid->list, &qp->mgids ); - /* GUID info gives us the second half of the port GID */ - if ( ( rc = ib_get_guid_info ( ibdev, &u.guid_info ) ) != 0 ) - return rc; - memcpy ( &ibdev->port_gid.u.bytes[8], u.guid_info.gid_local, 8 ); + /* Add to hardware multicast GID list */ + if ( ( rc = ibdev->op->mcast_attach ( ibdev, qp, gid ) ) != 0 ) + goto err_dev_mcast_attach; - /* Get partition key */ - if ( ( rc = ib_get_pkey_table ( ibdev, &u.pkey_table ) ) != 0 ) - return rc; - ibdev->pkey = ntohs ( u.pkey_table.pkey[0][0] ); + return 0; - DBGC ( ibdev, "IBDEV %p port GID is %08lx:%08lx:%08lx:%08lx\n", - ibdev, htonl ( ibdev->port_gid.u.dwords[0] ), - htonl ( ibdev->port_gid.u.dwords[1] ), - htonl ( ibdev->port_gid.u.dwords[2] ), - htonl ( ibdev->port_gid.u.dwords[3] ) ); + err_dev_mcast_attach: + list_del ( &mgid->list ); + free ( mgid ); + err_alloc_mgid: + return rc; +} - return 0; +/** + * Detach from multicast group + * + * @v ibdev Infiniband device + * @v qp Queue pair + * @v gid Multicast GID + */ +void ib_mcast_detach ( struct ib_device *ibdev, struct ib_queue_pair *qp, + struct ib_gid *gid ) { + struct ib_multicast_gid *mgid; + + /* Remove from hardware multicast GID list */ + ibdev->op->mcast_detach ( ibdev, qp, gid ); + + /* Remove from software multicast GID list */ + list_for_each_entry ( mgid, &qp->mgids, list ) { + if ( memcmp ( &mgid->gid, gid, sizeof ( mgid->gid ) ) == 0 ) { + list_del ( &mgid->list ); + free ( mgid ); + break; + } + } } + /*************************************************************************** * * Event queues @@ -366,14 +500,6 @@ static int ib_get_mad_params ( struct ib_device *ibdev ) { * @v ibdev Infiniband device */ void ib_link_state_changed ( struct ib_device *ibdev ) { - int rc; - - /* Update MAD parameters */ - if ( ( rc = ib_get_mad_params ( ibdev ) ) != 0 ) { - DBGC ( ibdev, "IBDEV %p could not update MAD parameters: %s\n", - ibdev, strerror ( rc ) ); - return; - } /* Notify IPoIB of link state change */ ipoib_link_state_changed ( ibdev ); @@ -420,6 +546,9 @@ struct ib_device * alloc_ibdev ( size_t priv_size ) { if ( ibdev ) { drv_priv = ( ( ( void * ) ibdev ) + sizeof ( *ibdev ) ); ib_set_drvdata ( ibdev, drv_priv ); + INIT_LIST_HEAD ( &ibdev->qps ); + ibdev->lid = IB_LID_NONE; + ibdev->pkey = IB_PKEY_NONE; } return ibdev; } @@ -437,14 +566,6 @@ int register_ibdev ( struct ib_device *ibdev ) { ibdev_get ( ibdev ); list_add_tail ( &ibdev->list, &ib_devices ); - /* Open link */ - if ( ( rc = ib_open ( ibdev ) ) != 0 ) - goto err_open; - - /* Get MAD parameters */ - if ( ( rc = ib_get_mad_params ( ibdev ) ) != 0 ) - goto err_get_mad_params; - /* Add IPoIB device */ if ( ( rc = ipoib_probe ( ibdev ) ) != 0 ) { DBGC ( ibdev, "IBDEV %p could not add IPoIB device: %s\n", @@ -457,9 +578,6 @@ int register_ibdev ( struct ib_device *ibdev ) { return 0; err_ipoib_probe: - err_get_mad_params: - ib_close ( ibdev ); - err_open: list_del ( &ibdev->list ); ibdev_put ( ibdev ); return rc; @@ -474,7 +592,6 @@ void unregister_ibdev ( struct ib_device *ibdev ) { /* Close device */ ipoib_remove ( ibdev ); - ib_close ( ibdev ); /* Remove from device list */ list_del ( &ibdev->list ); diff --git a/gpxe/src/net/ipv4.c b/gpxe/src/net/ipv4.c index 82a13c33..8668d44b 100644 --- a/gpxe/src/net/ipv4.c +++ b/gpxe/src/net/ipv4.c @@ -188,7 +188,7 @@ static struct io_buffer * ipv4_reassemble ( struct io_buffer * iobuf ) { free_iob ( iobuf ); /** Check if the fragment series is over */ - if ( !iphdr->frags & IP_MASK_MOREFRAGS ) { + if ( ! ( iphdr->frags & IP_MASK_MOREFRAGS ) ) { iobuf = fragbuf->frag_iob; free_fragbuf ( fragbuf ); return iobuf; @@ -266,7 +266,6 @@ static uint16_t ipv4_pshdr_chksum ( struct io_buffer *iobuf, uint16_t csum ) { static int ipv4_ll_addr ( struct in_addr dest, struct in_addr src, struct net_device *netdev, uint8_t *ll_dest ) { struct ll_protocol *ll_protocol = netdev->ll_protocol; - uint8_t *dest_bytes = ( ( uint8_t * ) &dest ); if ( dest.s_addr == INADDR_BROADCAST ) { /* Broadcast address */ @@ -274,17 +273,7 @@ static int ipv4_ll_addr ( struct in_addr dest, struct in_addr src, ll_protocol->ll_addr_len ); return 0; } else if ( IN_MULTICAST ( ntohl ( dest.s_addr ) ) ) { - /* Special case: IPv4 multicast over Ethernet. This - * code may need to be generalised once we find out - * what happens for other link layers. - */ - ll_dest[0] = 0x01; - ll_dest[1] = 0x00; - ll_dest[2] = 0x5e; - ll_dest[3] = dest_bytes[1] & 0x7f; - ll_dest[4] = dest_bytes[2]; - ll_dest[5] = dest_bytes[3]; - return 0; + return ll_protocol->mc_hash ( AF_INET, &dest, ll_dest ); } else { /* Unicast address: resolve via ARP */ return arp_resolve ( netdev, &ipv4_protocol, &dest, @@ -297,6 +286,7 @@ static int ipv4_ll_addr ( struct in_addr dest, struct in_addr src, * * @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 @@ -306,10 +296,12 @@ static int ipv4_ll_addr ( struct in_addr dest, struct in_addr src, */ static int ipv4_tx ( struct io_buffer *iobuf, struct tcpip_protocol *tcpip_protocol, + struct sockaddr_tcpip *st_src, struct sockaddr_tcpip *st_dest, struct net_device *netdev, uint16_t *trans_csum ) { struct iphdr *iphdr = iob_push ( iobuf, sizeof ( *iphdr ) ); + struct sockaddr_in *sin_src = ( ( struct sockaddr_in * ) st_src ); struct sockaddr_in *sin_dest = ( ( struct sockaddr_in * ) st_dest ); struct ipv4_miniroute *miniroute; struct in_addr next_hop; @@ -328,7 +320,11 @@ static int ipv4_tx ( struct io_buffer *iobuf, /* Use routing table to identify next hop and transmitting netdev */ next_hop = iphdr->dest; - if ( ( miniroute = ipv4_route ( &next_hop ) ) ) { + if ( sin_src ) + iphdr->src = sin_src->sin_addr; + if ( ( next_hop.s_addr != INADDR_BROADCAST ) && + ( ! IN_MULTICAST ( ntohl ( next_hop.s_addr ) ) ) && + ( ( miniroute = ipv4_route ( &next_hop ) ) != NULL ) ) { iphdr->src = miniroute->address; netdev = miniroute->netdev; } @@ -631,3 +627,6 @@ static int ipv4_create_routes ( void ) { struct settings_applicator ipv4_settings_applicator __settings_applicator = { .apply = ipv4_create_routes, }; + +/* Drag in ICMP */ +REQUIRE_OBJECT ( icmp ); diff --git a/gpxe/src/net/ipv6.c b/gpxe/src/net/ipv6.c index 3407d538..f7308bb4 100644 --- a/gpxe/src/net/ipv6.c +++ b/gpxe/src/net/ipv6.c @@ -176,6 +176,7 @@ void ipv6_dump ( struct ip6_header *ip6hdr ) { */ static int ipv6_tx ( struct io_buffer *iobuf, struct tcpip_protocol *tcpip, + struct sockaddr_tcpip *st_src __unused, struct sockaddr_tcpip *st_dest, struct net_device *netdev, uint16_t *trans_csum ) { diff --git a/gpxe/src/net/netdevice.c b/gpxe/src/net/netdevice.c index 3721b334..9e142d27 100644 --- a/gpxe/src/net/netdevice.c +++ b/gpxe/src/net/netdevice.c @@ -45,6 +45,48 @@ static struct net_protocol net_protocols_end[0] /** List of network devices */ struct list_head net_devices = LIST_HEAD_INIT ( net_devices ); +/** List of open network devices, in reverse order of opening */ +struct list_head open_net_devices = LIST_HEAD_INIT ( open_net_devices ); + +/** + * Record network device statistic + * + * @v stats Network device statistics + * @v rc Status code + */ +static void netdev_record_stat ( struct net_device_stats *stats, int rc ) { + struct net_device_error *error; + struct net_device_error *least_common_error; + unsigned int i; + + /* If this is not an error, just update the good counter */ + if ( rc == 0 ) { + stats->good++; + return; + } + + /* Update the bad counter */ + stats->bad++; + + /* Locate the appropriate error record */ + least_common_error = &stats->errors[0]; + for ( i = 0 ; i < ( sizeof ( stats->errors ) / + sizeof ( stats->errors[0] ) ) ; i++ ) { + error = &stats->errors[i]; + /* Update matching record, if found */ + if ( error->rc == rc ) { + error->count++; + return; + } + if ( error->count < least_common_error->count ) + least_common_error = error; + } + + /* Overwrite the least common error record */ + least_common_error->rc = rc; + least_common_error->count = 1; +} + /** * Transmit raw packet via network device * @@ -91,12 +133,11 @@ void netdev_tx_complete_err ( struct net_device *netdev, struct io_buffer *iobuf, int rc ) { /* Update statistics counter */ + netdev_record_stat ( &netdev->tx_stats, rc ); if ( rc == 0 ) { - netdev->stats.tx_ok++; DBGC ( netdev, "NETDEV %p transmission %p complete\n", netdev, iobuf ); } else { - netdev->stats.tx_err++; DBGC ( netdev, "NETDEV %p transmission %p failed: %s\n", netdev, iobuf, strerror ( rc ) ); } @@ -158,7 +199,7 @@ void netdev_rx ( struct net_device *netdev, struct io_buffer *iobuf ) { list_add_tail ( &iobuf->list, &netdev->rx_queue ); /* Update statistics counter */ - netdev->stats.rx_ok++; + netdev_record_stat ( &netdev->rx_stats, 0 ); } /** @@ -183,7 +224,7 @@ void netdev_rx_err ( struct net_device *netdev, free_iob ( iobuf ); /* Update statistics counter */ - netdev->stats.rx_err++; + netdev_record_stat ( &netdev->rx_stats, rc ); } /** @@ -268,7 +309,7 @@ struct net_device * alloc_netdev ( size_t priv_size ) { INIT_LIST_HEAD ( &netdev->rx_queue ); settings_init ( netdev_settings ( netdev ), &netdev_settings_operations, &netdev->refcnt, - netdev->name ); + netdev->name, 0 ); netdev->priv = ( ( ( void * ) netdev ) + sizeof ( *netdev ) ); } return netdev; @@ -330,6 +371,10 @@ int netdev_open ( struct net_device *netdev ) { /* Mark as opened */ netdev->state |= NETDEV_OPEN; + + /* Add to head of open devices list */ + list_add ( &netdev->open_list, &open_net_devices ); + return 0; } @@ -355,6 +400,9 @@ void netdev_close ( struct net_device *netdev ) { /* Mark as closed */ netdev->state &= ~NETDEV_OPEN; + + /* Remove from open devices list */ + list_del ( &netdev->open_list ); } /** @@ -425,6 +473,22 @@ struct net_device * find_netdev_by_location ( unsigned int bus_type, } /** + * Get most recently opened network device + * + * @ret netdev Most recently opened network device, or NULL + */ +struct net_device * last_opened_netdev ( void ) { + struct net_device *netdev; + + list_for_each_entry ( netdev, &open_net_devices, open_list ) { + assert ( netdev->state & NETDEV_OPEN ); + return netdev; + } + + return NULL; +} + +/** * Transmit network-layer packet * * @v iobuf I/O buffer @@ -439,6 +503,7 @@ struct net_device * find_netdev_by_location ( unsigned int bus_type, */ int net_tx ( struct io_buffer *iobuf, struct net_device *netdev, struct net_protocol *net_protocol, const void *ll_dest ) { + struct ll_protocol *ll_protocol = netdev->ll_protocol; int rc; /* Force a poll on the netdevice to (potentially) clear any @@ -449,8 +514,8 @@ int net_tx ( struct io_buffer *iobuf, struct net_device *netdev, netdev_poll ( netdev ); /* Add link-layer header */ - if ( ( rc = netdev->ll_protocol->push ( iobuf, netdev, net_protocol, - ll_dest ) ) != 0 ) { + if ( ( rc = ll_protocol->push ( iobuf, ll_dest, netdev->ll_addr, + net_protocol->net_proto ) ) != 0 ) { free_iob ( iobuf ); return rc; } @@ -495,8 +560,9 @@ static void net_step ( struct process *process __unused ) { struct net_device *netdev; struct io_buffer *iobuf; struct ll_protocol *ll_protocol; - uint16_t net_proto; + const void *ll_dest; const void *ll_source; + uint16_t net_proto; int rc; /* Poll and process each network device */ @@ -519,9 +585,9 @@ static void net_step ( struct process *process __unused ) { /* Remove link-layer header */ ll_protocol = netdev->ll_protocol; - if ( ( rc = ll_protocol->pull ( iobuf, netdev, - &net_proto, - &ll_source ) ) != 0 ) { + if ( ( rc = ll_protocol->pull ( iobuf, &ll_dest, + &ll_source, + &net_proto ) ) != 0 ) { free_iob ( iobuf ); continue; } diff --git a/gpxe/src/net/retry.c b/gpxe/src/net/retry.c index 2a645c97..cd793a7f 100644 --- a/gpxe/src/net/retry.c +++ b/gpxe/src/net/retry.c @@ -55,9 +55,10 @@ static LIST_HEAD ( timers ); * be stopped and the timer's callback function will be called. */ void start_timer ( struct retry_timer *timer ) { - if ( ! timer_running ( timer ) ) + if ( ! timer->running ) list_add ( &timer->list, &timers ); timer->start = currticks(); + timer->running = 1; /* 0 means "use default timeout" */ if ( timer->min_timeout == 0 ) @@ -82,6 +83,8 @@ void start_timer ( struct retry_timer *timer ) { void start_timer_fixed ( struct retry_timer *timer, unsigned long timeout ) { start_timer ( timer ); timer->timeout = timeout; + DBG2 ( "Timer %p expiry time changed to %ld\n", + timer, ( timer->start + timer->timeout ) ); } /** @@ -97,12 +100,12 @@ void stop_timer ( struct retry_timer *timer ) { unsigned long runtime; /* If timer was already stopped, do nothing */ - if ( ! timer_running ( timer ) ) + if ( ! timer->running ) return; list_del ( &timer->list ); runtime = ( now - timer->start ); - timer->start = 0; + timer->running = 0; DBG2 ( "Timer %p stopped at time %ld (ran for %ld)\n", timer, now, runtime ); @@ -144,8 +147,9 @@ static void timer_expired ( struct retry_timer *timer ) { /* Stop timer without performing RTT calculations */ DBG2 ( "Timer %p stopped at time %ld on expiry\n", timer, currticks() ); + assert ( timer->running ); list_del ( &timer->list ); - timer->start = 0; + timer->running = 0; timer->count++; /* Back off the timeout value */ diff --git a/gpxe/src/net/tcp.c b/gpxe/src/net/tcp.c index df87fc14..6bcd193c 100644 --- a/gpxe/src/net/tcp.c +++ b/gpxe/src/net/tcp.c @@ -478,12 +478,12 @@ static int tcp_xmit ( struct tcp_connection *tcp, int force_send ) { tcphdr->seq = htonl ( tcp->snd_seq ); tcphdr->ack = htonl ( tcp->rcv_ack ); tcphdr->hlen = ( ( payload - iobuf->data ) << 2 ); - tcphdr->flags = flags; + tcphdr->flags = ( flags | TCP_PSH ); tcphdr->win = htons ( tcp->rcv_win ); tcphdr->csum = tcpip_chksum ( iobuf->data, iob_len ( iobuf ) ); /* Dump header */ - DBGC ( tcp, "TCP %p TX %d->%d %08lx..%08lx %08lx %4zd", + DBGC ( tcp, "TCP %p TX %d->%d %08x..%08zx %08x %4zd", tcp, ntohs ( tcphdr->src ), ntohs ( tcphdr->dest ), ntohl ( tcphdr->seq ), ( ntohl ( tcphdr->seq ) + seq_len ), ntohl ( tcphdr->ack ), len ); @@ -491,7 +491,7 @@ static int tcp_xmit ( struct tcp_connection *tcp, int force_send ) { DBGC ( tcp, "\n" ); /* Transmit packet */ - return tcpip_tx ( iobuf, &tcp_protocol, &tcp->peer, NULL, + return tcpip_tx ( iobuf, &tcp_protocol, NULL, &tcp->peer, NULL, &tcphdr->csum ); } @@ -564,7 +564,7 @@ static int tcp_xmit_reset ( struct tcp_connection *tcp, tcphdr->csum = tcpip_chksum ( iobuf->data, iob_len ( iobuf ) ); /* Dump header */ - DBGC ( tcp, "TCP %p TX %d->%d %08lx..%08lx %08lx %4d", + DBGC ( tcp, "TCP %p TX %d->%d %08x..%08x %08x %4d", tcp, ntohs ( tcphdr->src ), ntohs ( tcphdr->dest ), ntohl ( tcphdr->seq ), ( ntohl ( tcphdr->seq ) ), ntohl ( tcphdr->ack ), 0 ); @@ -572,7 +572,7 @@ static int tcp_xmit_reset ( struct tcp_connection *tcp, DBGC ( tcp, "\n" ); /* Transmit packet */ - return tcpip_tx ( iobuf, &tcp_protocol, st_dest, + return tcpip_tx ( iobuf, &tcp_protocol, NULL, st_dest, NULL, &tcphdr->csum ); } @@ -702,8 +702,8 @@ static int tcp_rx_ack ( struct tcp_connection *tcp, uint32_t ack, /* Ignore duplicate or out-of-range ACK */ if ( ack_len > tcp->snd_sent ) { - DBGC ( tcp, "TCP %p received ACK for [%08lx,%08lx), " - "sent only [%08lx,%08lx)\n", tcp, tcp->snd_seq, + DBGC ( tcp, "TCP %p received ACK for [%08x,%08zx), " + "sent only [%08x,%08x)\n", tcp, tcp->snd_seq, ( tcp->snd_seq + ack_len ), tcp->snd_seq, ( tcp->snd_seq + tcp->snd_sent ) ); return -EINVAL; @@ -894,7 +894,7 @@ static int tcp_rx ( struct io_buffer *iobuf, len = iob_len ( iobuf ); /* Dump header */ - DBGC ( tcp, "TCP %p RX %d<-%d %08lx %08lx..%08lx %4zd", + DBGC ( tcp, "TCP %p RX %d<-%d %08x %08x..%08zx %4zd", tcp, ntohs ( tcphdr->dest ), ntohs ( tcphdr->src ), ntohl ( tcphdr->ack ), ntohl ( tcphdr->seq ), ( ntohl ( tcphdr->seq ) + len + @@ -1033,7 +1033,7 @@ static size_t tcp_xfer_window ( struct xfer_interface *xfer ) { * * @v xfer Data transfer interface * @v iobuf Datagram I/O buffer - * @v meta Data transfer metadata, or NULL + * @v meta Data transfer metadata * @ret rc Return status code */ static int tcp_xfer_deliver_iob ( struct xfer_interface *xfer, @@ -1070,12 +1070,13 @@ static struct xfer_interface_operations tcp_xfer_operations = { /** TCP socket opener */ struct socket_opener tcp_socket_opener __socket_opener = { - .semantics = SOCK_STREAM, + .semantics = TCP_SOCK_STREAM, .family = AF_INET, .open = tcp_open, }; -char TCP_SOCK_STREAM[1]; +/** Linkage hack */ +int tcp_sock_stream = TCP_SOCK_STREAM; /** * Open TCP URI diff --git a/gpxe/src/net/tcp/ftp.c b/gpxe/src/net/tcp/ftp.c index 3b88f7b6..445e32bb 100644 --- a/gpxe/src/net/tcp/ftp.c +++ b/gpxe/src/net/tcp/ftp.c @@ -109,23 +109,39 @@ static void ftp_done ( struct ftp_request *ftp, int rc ) { * */ +/** An FTP control channel string */ +struct ftp_control_string { + /** Literal portion */ + const char *literal; + /** Variable portion + * + * @v ftp FTP request + * @ret string Variable portion of string + */ + const char * ( *variable ) ( struct ftp_request *ftp ); +}; + /** - * FTP control channel strings + * Retrieve FTP pathname * - * These are used as printf() format strings. Since only one of them - * (RETR) takes an argument, we always supply that argument to the - * snprintf() call. + * @v ftp FTP request + * @ret path FTP pathname */ -static const char * ftp_strings[] = { - [FTP_CONNECT] = NULL, - [FTP_USER] = "USER anonymous\r\n", - [FTP_PASS] = "PASS etherboot@etherboot.org\r\n", - [FTP_TYPE] = "TYPE I\r\n", - [FTP_PASV] = "PASV\r\n", - [FTP_RETR] = "RETR %s\r\n", - [FTP_WAIT] = NULL, - [FTP_QUIT] = "QUIT\r\n", - [FTP_DONE] = NULL, +static const char * ftp_uri_path ( struct ftp_request *ftp ) { + return ftp->uri->path; +} + +/** FTP control channel strings */ +static struct ftp_control_string ftp_strings[] = { + [FTP_CONNECT] = { NULL, NULL }, + [FTP_USER] = { "USER anonymous", NULL }, + [FTP_PASS] = { "PASS etherboot@etherboot.org", NULL }, + [FTP_TYPE] = { "TYPE I", NULL }, + [FTP_PASV] = { "PASV", NULL }, + [FTP_RETR] = { "RETR ", ftp_uri_path }, + [FTP_WAIT] = { NULL, NULL }, + [FTP_QUIT] = { "QUIT", NULL }, + [FTP_DONE] = { NULL, NULL }, }; /** @@ -178,18 +194,23 @@ static void ftp_parse_value ( char **text, uint8_t *value, size_t len ) { * */ static void ftp_next_state ( struct ftp_request *ftp ) { + struct ftp_control_string *ftp_string; + const char *literal; + const char *variable; /* Move to next state */ if ( ftp->state < FTP_DONE ) ftp->state++; /* Send control string if needed */ - if ( ftp_strings[ftp->state] != NULL ) { - DBGC ( ftp, "FTP %p sending ", ftp ); - DBGC ( ftp, ftp_strings[ftp->state], ftp->uri->path ); - xfer_printf ( &ftp->control, ftp_strings[ftp->state], - ftp->uri->path ); - } + ftp_string = &ftp_strings[ftp->state]; + literal = ftp_string->literal; + variable = ( ftp_string->variable ? + ftp_string->variable ( ftp ) : "" ); + if ( literal ) { + DBGC ( ftp, "FTP %p sending %s%s\n", ftp, literal, variable ); + xfer_printf ( &ftp->control, "%s%s\r\n", literal, variable ); + } } /** @@ -359,7 +380,7 @@ static void ftp_data_closed ( struct xfer_interface *data, int rc ) { * * @v xfer FTP data channel interface * @v iobuf I/O buffer - * @v meta Data transfer metadata, or NULL + * @v meta Data transfer metadata * @ret rc Return status code */ static int ftp_data_deliver_iob ( struct xfer_interface *data, diff --git a/gpxe/src/net/tcp/http.c b/gpxe/src/net/tcp/http.c index 4dc1ab73..93ccfd3b 100644 --- a/gpxe/src/net/tcp/http.c +++ b/gpxe/src/net/tcp/http.c @@ -41,6 +41,7 @@ #include <gpxe/process.h> #include <gpxe/linebuf.h> #include <gpxe/features.h> +#include <gpxe/base64.h> #include <gpxe/http.h> FEATURE ( FEATURE_PROTOCOL, "HTTP", DHCP_EB_FEATURE_HTTP, 1 ); @@ -142,6 +143,8 @@ static int http_response_to_rc ( unsigned int response ) { return -ENOENT; case 403: return -EPERM; + case 401: + return -EACCES; default: return -EIO; } @@ -318,7 +321,7 @@ static int http_rx_data ( struct http_request *http, * * @v socket Transport layer interface * @v iobuf I/O buffer - * @v meta Data transfer metadata, or NULL + * @v meta Data transfer metadata * @ret rc Return status code */ static int http_socket_deliver_iob ( struct xfer_interface *socket, @@ -340,8 +343,7 @@ static int http_socket_deliver_iob ( struct xfer_interface *socket, /* Once we're into the data phase, just fill * the data buffer */ - rc = http_rx_data ( http, iobuf ); - iobuf = NULL; + rc = http_rx_data ( http, iob_disown ( iobuf ) ); goto done; case HTTP_RX_RESPONSE: case HTTP_RX_HEADER: @@ -388,18 +390,55 @@ static void http_step ( struct process *process ) { const char *path = http->uri->path; const char *host = http->uri->host; const char *query = http->uri->query; + const char *user = http->uri->user; + const char *password = + ( http->uri->password ? http->uri->password : "" ); + size_t user_pw_len = ( user ? ( strlen ( user ) + 1 /* ":" */ + + strlen ( password ) ) : 0 ); + size_t user_pw_base64_len = base64_encoded_len ( user_pw_len ); + char user_pw[ user_pw_len + 1 /* NUL */ ]; + char user_pw_base64[ user_pw_base64_len + 1 /* NUL */ ]; int rc; if ( xfer_window ( &http->socket ) ) { + + /* We want to execute only once */ process_del ( &http->process ); + + /* Construct authorisation, if applicable */ + if ( user ) { + char *buf = user_pw; + ssize_t remaining = sizeof ( user_pw ); + size_t len; + + /* URI-decode the username and password */ + len = uri_decode ( user, buf, remaining ); + buf += len; + remaining -= len; + *(remaining--, buf++) = ':'; + len = uri_decode ( password, buf, remaining ); + buf += len; + remaining -= len; + assert ( remaining >= 0 ); + + /* Base64-encode the "user:password" string */ + base64_encode ( user_pw, user_pw_base64 ); + } + + /* Send GET request */ if ( ( rc = xfer_printf ( &http->socket, "GET %s%s%s HTTP/1.0\r\n" "User-Agent: gPXE/" VERSION "\r\n" + "%s%s%s" "Host: %s\r\n" "\r\n", ( path ? path : "/" ), ( query ? "?" : "" ), ( query ? query : "" ), + ( user ? + "Authorization: Basic " : "" ), + ( user ? user_pw_base64 : "" ), + ( user ? "\r\n" : "" ), host ) ) != 0 ) { http_done ( http, rc ); } diff --git a/gpxe/src/net/tcp/iscsi.c b/gpxe/src/net/tcp/iscsi.c index e9e36449..aa99db71 100644 --- a/gpxe/src/net/tcp/iscsi.c +++ b/gpxe/src/net/tcp/iscsi.c @@ -1305,7 +1305,7 @@ static int iscsi_rx_bhs ( struct iscsi_session *iscsi, const void *data, size_t len, size_t remaining __unused ) { memcpy ( &iscsi->rx_bhs.bytes[iscsi->rx_offset], data, len ); if ( ( iscsi->rx_offset + len ) >= sizeof ( iscsi->rx_bhs ) ) { - DBGC2 ( iscsi, "iSCSI %p received PDU opcode %#x len %#lx\n", + DBGC2 ( iscsi, "iSCSI %p received PDU opcode %#x len %#x\n", iscsi, iscsi->rx_bhs.common.opcode, ISCSI_DATA_LEN ( iscsi->rx_bhs.common.lengths ) ); } diff --git a/gpxe/src/net/tcpip.c b/gpxe/src/net/tcpip.c index 1bc8d1a3..d4542b05 100644 --- a/gpxe/src/net/tcpip.c +++ b/gpxe/src/net/tcpip.c @@ -64,14 +64,15 @@ int tcpip_rx ( struct io_buffer *iobuf, uint8_t tcpip_proto, * * @v iobuf I/O buffer * @v tcpip_protocol Transport-layer protocol + * @v st_src Source address, or NULL to use route default * @v st_dest Destination 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 Return status code */ int tcpip_tx ( struct io_buffer *iobuf, struct tcpip_protocol *tcpip_protocol, - struct sockaddr_tcpip *st_dest, struct net_device *netdev, - uint16_t *trans_csum ) { + struct sockaddr_tcpip *st_src, struct sockaddr_tcpip *st_dest, + struct net_device *netdev, uint16_t *trans_csum ) { struct tcpip_net_protocol *tcpip_net; /* Hand off packet to the appropriate network-layer protocol */ @@ -79,8 +80,8 @@ int tcpip_tx ( struct io_buffer *iobuf, struct tcpip_protocol *tcpip_protocol, tcpip_net < tcpip_net_protocols_end ; tcpip_net++ ) { 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_dest, - netdev, trans_csum ); + return tcpip_net->tx ( iobuf, tcpip_protocol, st_src, + st_dest, netdev, trans_csum ); } } diff --git a/gpxe/src/net/tls.c b/gpxe/src/net/tls.c index 834686fb..f5bff7a4 100644 --- a/gpxe/src/net/tls.c +++ b/gpxe/src/net/tls.c @@ -36,6 +36,8 @@ #include <gpxe/xfer.h> #include <gpxe/open.h> #include <gpxe/filter.h> +#include <gpxe/asn1.h> +#include <gpxe/x509.h> #include <gpxe/tls.h> static int tls_send_plaintext ( struct tls_session *tls, unsigned int type, @@ -43,6 +45,33 @@ static int tls_send_plaintext ( struct tls_session *tls, unsigned int type, static void tls_clear_cipher ( struct tls_session *tls, struct tls_cipherspec *cipherspec ); +/****************************************************************************** + * + * Utility functions + * + ****************************************************************************** + */ + +/** + * Extract 24-bit field value + * + * @v field24 24-bit field + * @ret value Field value + * + * TLS uses 24-bit integers in several places, which are awkward to + * parse in C. + */ +static unsigned long tls_uint24 ( uint8_t field24[3] ) { + return ( ( field24[0] << 16 ) + ( field24[1] << 8 ) + field24[2] ); +} + +/****************************************************************************** + * + * Cleanup functions + * + ****************************************************************************** + */ + /** * Free TLS session * @@ -57,8 +86,7 @@ static void free_tls ( struct refcnt *refcnt ) { tls_clear_cipher ( tls, &tls->tx_cipherspec_pending ); tls_clear_cipher ( tls, &tls->rx_cipherspec ); tls_clear_cipher ( tls, &tls->rx_cipherspec_pending ); - free ( tls->rsa_mod ); - free ( tls->rsa_pub_exp ); + x509_free_rsa_public_key ( &tls->rsa ); free ( tls->rx_data ); /* Free TLS structure itself */ @@ -270,16 +298,16 @@ static void tls_generate_master_secret ( struct tls_session *tls ) { DBGC_HD ( tls, &tls->pre_master_secret, sizeof ( tls->pre_master_secret ) ); DBGC ( tls, "TLS %p client random bytes:\n", tls ); - DBGC_HD ( tls, &tls->client_random, sizeof ( tls->server_random ) ); + DBGC_HD ( tls, &tls->client_random, sizeof ( tls->client_random ) ); DBGC ( tls, "TLS %p server random bytes:\n", tls ); DBGC_HD ( tls, &tls->server_random, sizeof ( tls->server_random ) ); - tls_prf_label ( tls, tls->pre_master_secret, + tls_prf_label ( tls, &tls->pre_master_secret, sizeof ( tls->pre_master_secret ), - tls->master_secret, sizeof ( tls->master_secret ), + &tls->master_secret, sizeof ( tls->master_secret ), "master secret", - tls->client_random, sizeof ( tls->client_random ), - tls->server_random, sizeof ( tls->server_random ) ); + &tls->client_random, sizeof ( tls->client_random ), + &tls->server_random, sizeof ( tls->server_random ) ); DBGC ( tls, "TLS %p generated master secret:\n", tls ); DBGC_HD ( tls, &tls->master_secret, sizeof ( tls->master_secret ) ); @@ -304,10 +332,10 @@ static int tls_generate_keys ( struct tls_session *tls ) { int rc; /* Generate key block */ - tls_prf_label ( tls, tls->master_secret, sizeof ( tls->master_secret ), + tls_prf_label ( tls, &tls->master_secret, sizeof ( tls->master_secret ), key_block, sizeof ( key_block ), "key expansion", - tls->server_random, sizeof ( tls->server_random ), - tls->client_random, sizeof ( tls->client_random ) ); + &tls->server_random, sizeof ( tls->server_random ), + &tls->client_random, sizeof ( tls->client_random ) ); /* Split key block into portions */ key = key_block; @@ -604,7 +632,7 @@ static int tls_send_client_hello ( struct tls_session *tls ) { htonl ( sizeof ( hello ) - sizeof ( hello.type_length ) ) ); hello.version = htons ( TLS_VERSION_TLS_1_0 ); - memcpy ( &hello.random, tls->client_random, sizeof ( hello.random ) ); + memcpy ( &hello.random, &tls->client_random, sizeof ( hello.random ) ); hello.cipher_suite_len = htons ( sizeof ( hello.cipher_suites ) ); hello.cipher_suites[0] = htons ( TLS_RSA_WITH_AES_128_CBC_SHA ); hello.cipher_suites[1] = htons ( TLS_RSA_WITH_AES_256_CBC_SHA ); @@ -622,8 +650,8 @@ static int tls_send_client_hello ( struct tls_session *tls ) { static int tls_send_client_key_exchange ( struct tls_session *tls ) { /* FIXME: Hack alert */ RSA_CTX *rsa_ctx; - RSA_pub_key_new ( &rsa_ctx, tls->rsa_mod, tls->rsa_mod_len, - tls->rsa_pub_exp, tls->rsa_pub_exp_len ); + RSA_pub_key_new ( &rsa_ctx, tls->rsa.modulus, tls->rsa.modulus_len, + tls->rsa.exponent, tls->rsa.exponent_len ); struct { uint32_t type_length; uint16_t encrypted_pre_master_secret_len; @@ -641,9 +669,9 @@ static int tls_send_client_key_exchange ( struct tls_session *tls ) { DBGC ( tls, "RSA encrypting plaintext, modulus, exponent:\n" ); DBGC_HD ( tls, &tls->pre_master_secret, sizeof ( tls->pre_master_secret ) ); - DBGC_HD ( tls, tls->rsa_mod, tls->rsa_mod_len ); - DBGC_HD ( tls, tls->rsa_pub_exp, tls->rsa_pub_exp_len ); - RSA_encrypt ( rsa_ctx, tls->pre_master_secret, + DBGC_HD ( tls, tls->rsa.modulus, tls->rsa.modulus_len ); + DBGC_HD ( tls, tls->rsa.exponent, tls->rsa.exponent_len ); + RSA_encrypt ( rsa_ctx, ( const uint8_t * ) &tls->pre_master_secret, sizeof ( tls->pre_master_secret ), key_xchg.encrypted_pre_master_secret, 0 ); DBGC ( tls, "RSA encrypt done. Ciphertext:\n" ); @@ -685,7 +713,7 @@ static int tls_send_finished ( struct tls_session *tls ) { htonl ( sizeof ( finished ) - sizeof ( finished.type_length ) ) ); tls_verify_handshake ( tls, digest ); - tls_prf_label ( tls, tls->master_secret, sizeof ( tls->master_secret ), + tls_prf_label ( tls, &tls->master_secret, sizeof ( tls->master_secret ), finished.verify_data, sizeof ( finished.verify_data ), "client finished", digest, sizeof ( digest ) ); @@ -761,17 +789,16 @@ static int tls_new_alert ( struct tls_session *tls, void *data, size_t len ) { } /** - * Receive new Server Hello record + * Receive new Server Hello handshake record * * @v tls TLS session - * @v data Plaintext record - * @v len Length of plaintext record + * @v data Plaintext handshake record + * @v len Length of plaintext handshake record * @ret rc Return status code */ static int tls_new_server_hello ( struct tls_session *tls, void *data, size_t len ) { struct { - uint32_t type_length; uint16_t version; uint8_t random[32]; uint8_t session_id_len; @@ -802,7 +829,7 @@ static int tls_new_server_hello ( struct tls_session *tls, } /* Copy out server random bytes */ - memcpy ( tls->server_random, hello_a->random, + memcpy ( &tls->server_random, &hello_a->random, sizeof ( tls->server_random ) ); /* Select cipher suite */ @@ -818,72 +845,74 @@ static int tls_new_server_hello ( struct tls_session *tls, } /** - * Receive new Certificate record + * Receive new Certificate handshake record * * @v tls TLS session - * @v data Plaintext record - * @v len Length of plaintext record + * @v data Plaintext handshake record + * @v len Length of plaintext handshake record * @ret rc Return status code */ static int tls_new_certificate ( struct tls_session *tls, void *data, size_t len ) { struct { - uint32_t type_length; uint8_t length[3]; - uint8_t first_cert_length[3]; - uint8_t asn1_start[0]; + uint8_t certificates[0]; } __attribute__ (( packed )) *certificate = data; - uint8_t *cert = certificate->asn1_start; - int offset = 0; - - /* FIXME */ - (void) len; - - if (asn1_next_obj(cert, &offset, ASN1_SEQUENCE) < 0 || - asn1_next_obj(cert, &offset, ASN1_SEQUENCE) < 0 || - asn1_skip_obj(cert, &offset, ASN1_EXPLICIT_TAG) || - asn1_skip_obj(cert, &offset, ASN1_INTEGER) || - asn1_skip_obj(cert, &offset, ASN1_SEQUENCE) || - asn1_skip_obj(cert, &offset, ASN1_SEQUENCE) || - asn1_skip_obj(cert, &offset, ASN1_SEQUENCE) || - asn1_skip_obj(cert, &offset, ASN1_SEQUENCE) || - asn1_next_obj(cert, &offset, ASN1_SEQUENCE) < 0 || - asn1_skip_obj(cert, &offset, ASN1_SEQUENCE) || - asn1_next_obj(cert, &offset, ASN1_BIT_STRING) < 0) { - DBGC ( tls, "TLS %p invalid certificate\n", tls ); - DBGC_HD ( tls, cert + offset, 64 ); - return -EPERM; - } - - offset++; - - if (asn1_next_obj(cert, &offset, ASN1_SEQUENCE) < 0) { - DBGC ( tls, "TLS %p invalid certificate\n", tls ); - DBGC_HD ( tls, cert + offset, 64 ); - return -EPERM; + struct { + uint8_t length[3]; + uint8_t certificate[0]; + } __attribute__ (( packed )) *element = + ( ( void * ) certificate->certificates ); + size_t elements_len = tls_uint24 ( certificate->length ); + void *end = ( certificate->certificates + elements_len ); + struct asn1_cursor cursor; + int rc; + + /* Sanity check */ + if ( end != ( data + len ) ) { + DBGC ( tls, "TLS %p received overlength Server Certificate\n", + tls ); + DBGC_HD ( tls, data, len ); + return -EINVAL; } - - tls->rsa_mod_len = asn1_get_int(cert, &offset, &tls->rsa_mod); - tls->rsa_pub_exp_len = asn1_get_int(cert, &offset, &tls->rsa_pub_exp); - - DBGC_HD ( tls, tls->rsa_mod, tls->rsa_mod_len ); - DBGC_HD ( tls, tls->rsa_pub_exp, tls->rsa_pub_exp_len ); - return 0; + /* Traverse certificate chain */ + do { + cursor.data = element->certificate; + cursor.len = tls_uint24 ( element->length ); + if ( ( cursor.data + cursor.len ) > end ) { + DBGC ( tls, "TLS %p received corrupt Server " + "Certificate\n", tls ); + DBGC_HD ( tls, data, len ); + return -EINVAL; + } + + // HACK + if ( ( rc = x509_rsa_public_key ( &cursor, + &tls->rsa ) ) != 0 ) { + DBGC ( tls, "TLS %p cannot determine RSA public key: " + "%s\n", tls, strerror ( rc ) ); + return rc; + } + return 0; + + element = ( cursor.data + cursor.len ); + } while ( element != end ); + + return -EINVAL; } /** - * Receive new Server Hello Done record + * Receive new Server Hello Done handshake record * * @v tls TLS session - * @v data Plaintext record - * @v len Length of plaintext record + * @v data Plaintext handshake record + * @v len Length of plaintext handshake record * @ret rc Return status code */ static int tls_new_server_hello_done ( struct tls_session *tls, void *data, size_t len ) { struct { - uint32_t type_length; char next[0]; } __attribute__ (( packed )) *hello_done = data; void *end = hello_done->next; @@ -910,11 +939,11 @@ static int tls_new_server_hello_done ( struct tls_session *tls, } /** - * Receive new Finished record + * Receive new Finished handshake record * * @v tls TLS session - * @v data Plaintext record - * @v len Length of plaintext record + * @v data Plaintext handshake record + * @v len Length of plaintext handshake record * @ret rc Return status code */ static int tls_new_finished ( struct tls_session *tls, @@ -937,33 +966,47 @@ static int tls_new_finished ( struct tls_session *tls, */ static int tls_new_handshake ( struct tls_session *tls, void *data, size_t len ) { - uint8_t *type = data; + struct { + uint8_t type; + uint8_t length[3]; + uint8_t payload[0]; + } __attribute__ (( packed )) *handshake = data; + void *payload = &handshake->payload; + size_t payload_len = tls_uint24 ( handshake->length ); + void *end = ( payload + payload_len ); int rc; - switch ( *type ) { + /* Sanity check */ + if ( end != ( data + len ) ) { + DBGC ( tls, "TLS %p received overlength Handshake\n", tls ); + DBGC_HD ( tls, data, len ); + return -EINVAL; + } + + switch ( handshake->type ) { case TLS_SERVER_HELLO: - rc = tls_new_server_hello ( tls, data, len ); + rc = tls_new_server_hello ( tls, payload, payload_len ); break; case TLS_CERTIFICATE: - rc = tls_new_certificate ( tls, data, len ); + rc = tls_new_certificate ( tls, payload, payload_len ); break; case TLS_SERVER_HELLO_DONE: - rc = tls_new_server_hello_done ( tls, data, len ); + rc = tls_new_server_hello_done ( tls, payload, payload_len ); break; case TLS_FINISHED: - rc = tls_new_finished ( tls, data, len ); + rc = tls_new_finished ( tls, payload, payload_len ); break; default: DBGC ( tls, "TLS %p ignoring handshake type %d\n", - tls, *type ); + tls, handshake->type ); rc = 0; break; } /* Add to handshake digest (except for Hello Requests, which - * are explicitly excludede). + * are explicitly excluded). */ - if ( *type != TLS_HELLO_REQUEST ) + if ( handshake->type != TLS_HELLO_REQUEST ) tls_add_handshake ( tls, data, len ); return rc; @@ -1710,13 +1753,12 @@ int add_tls ( struct xfer_interface *xfer, struct xfer_interface **next ) { tls_clear_cipher ( tls, &tls->tx_cipherspec_pending ); tls_clear_cipher ( tls, &tls->rx_cipherspec ); tls_clear_cipher ( tls, &tls->rx_cipherspec_pending ); - *( ( uint32_t * ) tls->client_random ) = 0; /* GMT Unix time */ - tls_generate_random ( ( tls->client_random + 4 ), - ( sizeof ( tls->client_random ) - 4 ) ); - *( ( uint16_t * ) tls->pre_master_secret ) - = htons ( TLS_VERSION_TLS_1_0 ); - tls_generate_random ( ( tls->pre_master_secret + 2 ), - ( sizeof ( tls->pre_master_secret ) - 2 ) ); + tls->client_random.gmt_unix_time = 0; + tls_generate_random ( &tls->client_random.random, + ( sizeof ( tls->client_random.random ) ) ); + tls->pre_master_secret.version = htons ( TLS_VERSION_TLS_1_0 ); + tls_generate_random ( &tls->pre_master_secret.random, + ( sizeof ( tls->pre_master_secret.random ) ) ); digest_init ( &md5_algorithm, tls->handshake_md5_ctx ); digest_init ( &sha1_algorithm, tls->handshake_sha1_ctx ); tls->tx_state = TLS_TX_CLIENT_HELLO; diff --git a/gpxe/src/net/udp.c b/gpxe/src/net/udp.c index 407ea14d..c3a1eba3 100644 --- a/gpxe/src/net/udp.c +++ b/gpxe/src/net/udp.c @@ -182,13 +182,13 @@ static void udp_close ( struct udp_connection *udp, int rc ) { * * @v udp UDP connection * @v iobuf I/O buffer - * @v src_port Source port, or 0 to use default + * @v src Source address, or NULL to use default * @v dest Destination address, or NULL to use default * @v netdev Network device, or NULL to use default * @ret rc Return status code */ static int udp_tx ( struct udp_connection *udp, struct io_buffer *iobuf, - unsigned int src_port, struct sockaddr_tcpip *dest, + struct sockaddr_tcpip *src, struct sockaddr_tcpip *dest, struct net_device *netdev ) { struct udp_header *udphdr; size_t len; @@ -201,8 +201,8 @@ static int udp_tx ( struct udp_connection *udp, struct io_buffer *iobuf, } /* Fill in default values if not explicitly provided */ - if ( ! src_port ) - src_port = udp->local.st_port; + if ( ! src ) + src = &udp->local; if ( ! dest ) dest = &udp->peer; @@ -210,7 +210,7 @@ static int udp_tx ( struct udp_connection *udp, struct io_buffer *iobuf, udphdr = iob_push ( iobuf, sizeof ( *udphdr ) ); len = iob_len ( iobuf ); udphdr->dest = dest->st_port; - udphdr->src = src_port; + udphdr->src = src->st_port; udphdr->len = htons ( len ); udphdr->chksum = 0; udphdr->chksum = tcpip_chksum ( udphdr, len ); @@ -221,7 +221,7 @@ static int udp_tx ( struct udp_connection *udp, struct io_buffer *iobuf, ntohs ( udphdr->len ) ); /* Send it to the next layer for processing */ - if ( ( rc = tcpip_tx ( iobuf, &udp_protocol, dest, netdev, + if ( ( rc = tcpip_tx ( iobuf, &udp_protocol, src, dest, netdev, &udphdr->chksum ) ) != 0 ) { DBGC ( udp, "UDP %p could not transmit packet: %s\n", udp, strerror ( rc ) ); @@ -328,8 +328,7 @@ static int udp_rx ( struct io_buffer *iobuf, struct sockaddr_tcpip *st_src, memset ( &meta, 0, sizeof ( meta ) ); meta.src = ( struct sockaddr * ) st_src; meta.dest = ( struct sockaddr * ) st_dest; - rc = xfer_deliver_iob_meta ( &udp->xfer, iobuf, &meta ); - iobuf = NULL; + rc = xfer_deliver_iob_meta ( &udp->xfer, iob_disown ( iobuf ), &meta ); done: free_iob ( iobuf ); @@ -391,7 +390,7 @@ static struct io_buffer * udp_alloc_iob ( struct xfer_interface *xfer, * * @v xfer Data transfer interface * @v iobuf Datagram I/O buffer - * @v meta Data transfer metadata, or NULL + * @v meta Data transfer metadata * @ret rc Return status code */ static int udp_xfer_deliver_iob ( struct xfer_interface *xfer, @@ -399,22 +398,10 @@ static int udp_xfer_deliver_iob ( struct xfer_interface *xfer, struct xfer_metadata *meta ) { struct udp_connection *udp = container_of ( xfer, struct udp_connection, xfer ); - struct sockaddr_tcpip *src; - struct sockaddr_tcpip *dest = NULL; - struct net_device *netdev = NULL; - unsigned int src_port = 0; - - /* Apply xfer metadata */ - if ( meta ) { - src = ( struct sockaddr_tcpip * ) meta->src; - if ( src ) - src_port = src->st_port; - dest = ( struct sockaddr_tcpip * ) meta->dest; - netdev = meta->netdev; - } /* Transmit data, if possible */ - udp_tx ( udp, iobuf, src_port, dest, netdev ); + udp_tx ( udp, iobuf, ( ( struct sockaddr_tcpip * ) meta->src ), + ( ( struct sockaddr_tcpip * ) meta->dest ), meta->netdev ); return 0; } @@ -438,12 +425,13 @@ static struct xfer_interface_operations udp_xfer_operations = { /** UDP socket opener */ struct socket_opener udp_socket_opener __socket_opener = { - .semantics = SOCK_DGRAM, + .semantics = UDP_SOCK_DGRAM, .family = AF_INET, .open = udp_open, }; -char UDP_SOCK_DGRAM[1]; +/** Linkage hack */ +int udp_sock_dgram = UDP_SOCK_DGRAM; /** * Open UDP URI diff --git a/gpxe/src/net/udp/dhcp.c b/gpxe/src/net/udp/dhcp.c index ab751cd5..ab843ce1 100644 --- a/gpxe/src/net/udp/dhcp.c +++ b/gpxe/src/net/udp/dhcp.c @@ -19,6 +19,7 @@ #include <string.h> #include <stdlib.h> #include <stdio.h> +#include <ctype.h> #include <errno.h> #include <assert.h> #include <byteswap.h> @@ -32,12 +33,12 @@ #include <gpxe/tcpip.h> #include <gpxe/ip.h> #include <gpxe/uuid.h> -#include <gpxe/dhcp.h> #include <gpxe/timer.h> #include <gpxe/settings.h> #include <gpxe/dhcp.h> #include <gpxe/dhcpopts.h> #include <gpxe/dhcppkt.h> +#include <gpxe/features.h> /** @file * @@ -45,6 +46,9 @@ * */ +struct dhcp_session; +static int dhcp_tx ( struct dhcp_session *dhcp ); + /** * DHCP operation types * @@ -73,6 +77,8 @@ static uint8_t dhcp_request_options_data[] = { DHCP_STRING ( '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' ), + DHCP_USER_CLASS_ID, + DHCP_STRING ( 'g', 'P', 'X', 'E' ), DHCP_PARAMETER_REQUEST_LIST, DHCP_OPTION ( DHCP_SUBNET_MASK, DHCP_ROUTERS, DHCP_DNS_SERVERS, DHCP_LOG_SERVERS, DHCP_HOST_NAME, DHCP_DOMAIN_NAME, @@ -82,44 +88,28 @@ static uint8_t dhcp_request_options_data[] = { DHCP_END }; -/** Options common to all DHCP requests */ -static struct dhcp_options dhcp_request_options = { - .data = dhcp_request_options_data, - .max_len = sizeof ( dhcp_request_options_data ), - .len = sizeof ( dhcp_request_options_data ), -}; - /** DHCP feature codes */ static uint8_t dhcp_features[0] __table_start ( uint8_t, dhcp_features ); static uint8_t dhcp_features_end[0] __table_end ( uint8_t, dhcp_features ); -/** DHCP network device descriptor */ -struct dhcp_netdev_desc { - /** Bus type ID */ - uint8_t type; - /** Vendor ID */ - uint16_t vendor; - /** Device ID */ - uint16_t device; -} __attribute__ (( packed )); - -/** DHCP client identifier */ -struct dhcp_client_id { - /** Link-layer protocol */ - uint8_t ll_proto; - /** Link-layer address */ - uint8_t ll_addr[MAX_LL_ADDR_LEN]; -} __attribute__ (( packed )); - -/** DHCP client UUID */ -struct dhcp_client_uuid { - /** Identifier type */ - uint8_t type; - /** UUID */ - union uuid uuid; -} __attribute__ (( packed )); - -#define DHCP_CLIENT_UUID_TYPE 0 +/** Version number feature */ +FEATURE_VERSION ( VERSION_MAJOR, VERSION_MINOR, VERSION_PATCH ); + +/** DHCP server address setting */ +struct setting dhcp_server_setting __setting = { + .name = "dhcp-server", + .description = "DHCP server address", + .tag = DHCP_SERVER_IDENTIFIER, + .type = &setting_type_ipv4, +}; + +/** DHCP user class setting */ +struct setting user_class_setting __setting = { + .name = "user-class", + .description = "User class identifier", + .tag = DHCP_USER_CLASS_ID, + .type = &setting_type_string, +}; /** * Name a DHCP packet type @@ -161,211 +151,658 @@ static uint32_t dhcp_xid ( struct net_device *netdev ) { /**************************************************************************** * - * DHCP settings + * DHCP session * */ -/** A DHCP settings block */ -struct dhcp_settings { +struct dhcp_session; + +/** DHCP session state operations */ +struct dhcp_session_state { + /** State name */ + const char *name; + /** + * Construct transmitted packet + * + * @v dhcp DHCP session + * @v dhcppkt DHCP packet + * @v peer Destination address + */ + int ( * tx ) ( struct dhcp_session *dhcp, + struct dhcp_packet *dhcppkt, + struct sockaddr_in *peer ); + /** Handle received packet + * + * @v dhcp DHCP session + * @v dhcppkt DHCP packet + * @v peer DHCP server address + * @v msgtype DHCP message type + * @v server_id DHCP server ID + */ + void ( * rx ) ( struct dhcp_session *dhcp, + struct dhcp_packet *dhcppkt, + struct sockaddr_in *peer, + uint8_t msgtype, struct in_addr server_id ); + /** Handle timer expiry + * + * @v dhcp DHCP session + */ + void ( * expired ) ( struct dhcp_session *dhcp ); + /** Transmitted message type */ + uint8_t tx_msgtype; + /** Apply minimum timeout */ + uint8_t apply_min_timeout; +}; + +static struct dhcp_session_state dhcp_state_discover; +static struct dhcp_session_state dhcp_state_request; +static struct dhcp_session_state dhcp_state_proxy; +static struct dhcp_session_state dhcp_state_pxebs; + +/** A DHCP session */ +struct dhcp_session { /** Reference counter */ struct refcnt refcnt; - /** DHCP packet */ - struct dhcp_packet dhcppkt; - /** Setting interface */ - struct settings settings; + /** Job control interface */ + struct job_interface job; + /** Data transfer interface */ + struct xfer_interface xfer; + + /** Network device being configured */ + struct net_device *netdev; + /** Local socket address */ + struct sockaddr_in local; + /** State of the session */ + struct dhcp_session_state *state; + + /** Offered IP address */ + struct in_addr offer; + /** DHCP server */ + struct in_addr server; + /** DHCP offer priority */ + int priority; + + /** ProxyDHCP protocol extensions should be ignored */ + int no_pxedhcp; + /** ProxyDHCP server */ + struct in_addr proxy_server; + /** ProxyDHCP server priority */ + int proxy_priority; + + /** PXE Boot Server type */ + uint16_t pxe_type; + /** List of PXE Boot Servers to attempt */ + struct in_addr *pxe_attempt; + /** List of PXE Boot Servers to accept */ + struct in_addr *pxe_accept; + + /** Retransmission timer */ + struct retry_timer timer; + /** Start time of the current state (in ticks) */ + unsigned long start; }; /** - * Increment reference count on DHCP settings block + * Free DHCP session * - * @v dhcpset DHCP settings block - * @ret dhcpset DHCP settings block + * @v refcnt Reference counter */ -static inline __attribute__ (( always_inline )) struct dhcp_settings * -dhcpset_get ( struct dhcp_settings *dhcpset ) { - ref_get ( &dhcpset->refcnt ); - return dhcpset; +static void dhcp_free ( struct refcnt *refcnt ) { + struct dhcp_session *dhcp = + container_of ( refcnt, struct dhcp_session, refcnt ); + + netdev_put ( dhcp->netdev ); + free ( dhcp ); } /** - * Decrement reference count on DHCP settings block + * Mark DHCP session as complete * - * @v dhcpset DHCP settings block + * @v dhcp DHCP session + * @v rc Return status code */ -static inline __attribute__ (( always_inline )) void -dhcpset_put ( struct dhcp_settings *dhcpset ) { - ref_put ( &dhcpset->refcnt ); +static void dhcp_finished ( struct dhcp_session *dhcp, int rc ) { + + /* Block futher incoming messages */ + job_nullify ( &dhcp->job ); + xfer_nullify ( &dhcp->xfer ); + + /* Stop retry timer */ + stop_timer ( &dhcp->timer ); + + /* Free resources and close interfaces */ + xfer_close ( &dhcp->xfer, rc ); + job_done ( &dhcp->job, rc ); } /** - * Store value of DHCP setting + * Transition to new DHCP session state * - * @v settings Settings block - * @v setting Setting to store - * @v data Setting data, or NULL to clear setting - * @v len Length of setting data - * @ret rc Return status code + * @v dhcp DHCP session + * @v state New session state */ -static int dhcpset_store ( struct settings *settings, struct setting *setting, - const void *data, size_t len ) { - struct dhcp_settings *dhcpset = - container_of ( settings, struct dhcp_settings, settings ); +static void dhcp_set_state ( struct dhcp_session *dhcp, + struct dhcp_session_state *state ) { - return dhcppkt_store ( &dhcpset->dhcppkt, setting->tag, data, len ); + DBGC ( dhcp, "DHCP %p entering %s state\n", dhcp, state->name ); + dhcp->state = state; + dhcp->start = currticks(); + stop_timer ( &dhcp->timer ); + dhcp->timer.min_timeout = + ( state->apply_min_timeout ? DHCP_MIN_TIMEOUT : 0 ); + dhcp->timer.max_timeout = DHCP_MAX_TIMEOUT; + start_timer_nodelay ( &dhcp->timer ); } +/**************************************************************************** + * + * DHCP state machine + * + */ + /** - * Fetch value of DHCP setting + * Construct transmitted packet for DHCP discovery * - * @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 dhcp DHCP session + * @v dhcppkt DHCP packet + * @v peer Destination address */ -static int dhcpset_fetch ( struct settings *settings, struct setting *setting, - void *data, size_t len ) { - struct dhcp_settings *dhcpset = - container_of ( settings, struct dhcp_settings, settings ); +static int dhcp_discovery_tx ( struct dhcp_session *dhcp, + struct dhcp_packet *dhcppkt __unused, + struct sockaddr_in *peer ) { + + DBGC ( dhcp, "DHCP %p DHCPDISCOVER\n", dhcp ); + + /* Set server address */ + peer->sin_addr.s_addr = INADDR_BROADCAST; + peer->sin_port = htons ( BOOTPS_PORT ); - return dhcppkt_fetch ( &dhcpset->dhcppkt, setting->tag, data, len ); + return 0; } -/** DHCP settings operations */ -static struct settings_operations dhcpset_settings_operations = { - .store = dhcpset_store, - .fetch = dhcpset_fetch, -}; +/** + * Handle received packet during DHCP discovery + * + * @v dhcp DHCP session + * @v dhcppkt DHCP packet + * @v peer DHCP server address + * @v msgtype DHCP message type + * @v server_id DHCP server ID + */ +static void dhcp_discovery_rx ( struct dhcp_session *dhcp, + struct dhcp_packet *dhcppkt, + struct sockaddr_in *peer, uint8_t msgtype, + struct in_addr server_id ) { + struct in_addr ip; + char vci[9]; /* "PXEClient" */ + int vci_len; + int has_pxeclient; + int8_t priority = 0; + uint8_t no_pxedhcp = 0; + unsigned long elapsed; + + DBGC ( dhcp, "DHCP %p %s from %s:%d", dhcp, + dhcp_msgtype_name ( msgtype ), inet_ntoa ( peer->sin_addr ), + ntohs ( peer->sin_port ) ); + if ( server_id.s_addr != peer->sin_addr.s_addr ) + DBGC ( dhcp, " (%s)", inet_ntoa ( server_id ) ); + + /* Identify offered IP address */ + ip = dhcppkt->dhcphdr->yiaddr; + if ( ip.s_addr ) + DBGC ( dhcp, " for %s", inet_ntoa ( ip ) ); + + /* Identify "PXEClient" vendor class */ + vci_len = dhcppkt_fetch ( dhcppkt, DHCP_VENDOR_CLASS_ID, + vci, sizeof ( vci ) ); + has_pxeclient = ( ( vci_len >= ( int ) sizeof ( vci ) ) && + ( strncmp ( "PXEClient", vci, sizeof (vci) ) == 0 )); + if ( has_pxeclient ) + DBGC ( dhcp, " pxe" ); + + /* Identify priority */ + dhcppkt_fetch ( dhcppkt, DHCP_EB_PRIORITY, &priority, + sizeof ( priority ) ); + if ( priority ) + DBGC ( dhcp, " pri %d", priority ); + + /* Identify ignore-PXE flag */ + dhcppkt_fetch ( dhcppkt, DHCP_EB_NO_PXEDHCP, &no_pxedhcp, + sizeof ( no_pxedhcp ) ); + if ( no_pxedhcp ) + DBGC ( dhcp, " nopxe" ); + DBGC ( dhcp, "\n" ); + + /* Select as DHCP offer, if applicable */ + if ( ip.s_addr && ( peer->sin_port == htons ( BOOTPS_PORT ) ) && + ( ( msgtype == DHCPOFFER ) || ( ! msgtype /* BOOTP */ ) ) && + ( priority >= dhcp->priority ) ) { + dhcp->offer = ip; + dhcp->server = server_id; + dhcp->priority = priority; + dhcp->no_pxedhcp = no_pxedhcp; + } + + /* Select as ProxyDHCP offer, if applicable */ + if ( has_pxeclient && ( msgtype == DHCPOFFER ) && + ( priority >= dhcp->proxy_priority ) ) { + dhcp->proxy_server = server_id; + dhcp->proxy_priority = priority; + } + + /* We can exit the discovery state when we have a valid + * DHCPOFFER, and either: + * + * o The DHCPOFFER instructs us to ignore ProxyDHCPOFFERs, or + * o We have a valid ProxyDHCPOFFER, or + * o We have allowed sufficient time for ProxyDHCPOFFERs. + */ + + /* If we don't yet have a DHCPOFFER, do nothing */ + if ( ! dhcp->offer.s_addr ) + return; + + /* If we can't yet transition to DHCPREQUEST, do nothing */ + elapsed = ( currticks() - dhcp->start ); + if ( ! ( dhcp->no_pxedhcp || dhcp->proxy_server.s_addr || + ( elapsed > PROXYDHCP_MAX_TIMEOUT ) ) ) + return; + + /* Transition to DHCPREQUEST */ + dhcp_set_state ( dhcp, &dhcp_state_request ); +} /** - * Create DHCP setting block + * Handle timer expiry during DHCP discovery * - * @v dhcphdr DHCP packet - * @v len Length of DHCP packet - * @ret dhcpset DHCP settings block + * @v dhcp DHCP session */ -static struct dhcp_settings * dhcpset_create ( const struct dhcphdr *dhcphdr, - size_t len ) { - struct dhcp_settings *dhcpset; - void *data; - - dhcpset = zalloc ( sizeof ( *dhcpset ) + len ); - if ( dhcpset ) { - data = ( ( ( void * ) dhcpset ) + sizeof ( *dhcpset ) ); - memcpy ( data, dhcphdr, len ); - dhcppkt_init ( &dhcpset->dhcppkt, data, len ); - settings_init ( &dhcpset->settings, - &dhcpset_settings_operations, &dhcpset->refcnt, - DHCP_SETTINGS_NAME ); +static void dhcp_discovery_expired ( struct dhcp_session *dhcp ) { + unsigned long elapsed = ( currticks() - dhcp->start ); + + /* Give up waiting for ProxyDHCP before we reach the failure point */ + if ( dhcp->offer.s_addr && ( elapsed > PROXYDHCP_MAX_TIMEOUT ) ) { + dhcp_set_state ( dhcp, &dhcp_state_request ); + return; } - return dhcpset; + + /* Otherwise, retransmit current packet */ + dhcp_tx ( dhcp ); } -/** DHCP server address setting */ -struct setting dhcp_server_setting __setting = { - .name = "dhcp-server", - .description = "DHCP server address", - .tag = DHCP_SERVER_IDENTIFIER, - .type = &setting_type_ipv4, +/** DHCP discovery state operations */ +static struct dhcp_session_state dhcp_state_discover = { + .name = "discovery", + .tx = dhcp_discovery_tx, + .rx = dhcp_discovery_rx, + .expired = dhcp_discovery_expired, + .tx_msgtype = DHCPDISCOVER, + .apply_min_timeout = 1, }; -/**************************************************************************** +/** + * Construct transmitted packet for DHCP request * - * DHCP session + * @v dhcp DHCP session + * @v dhcppkt DHCP packet + * @v peer Destination address + */ +static int dhcp_request_tx ( struct dhcp_session *dhcp, + struct dhcp_packet *dhcppkt, + struct sockaddr_in *peer ) { + int rc; + + DBGC ( dhcp, "DHCP %p DHCPREQUEST to %s:%d", + dhcp, inet_ntoa ( dhcp->server ), BOOTPS_PORT ); + DBGC ( dhcp, " for %s\n", inet_ntoa ( dhcp->offer ) ); + + /* Set server ID */ + if ( ( rc = dhcppkt_store ( dhcppkt, DHCP_SERVER_IDENTIFIER, + &dhcp->server, + sizeof ( dhcp->server ) ) ) != 0 ) + return rc; + + /* Set requested IP address */ + if ( ( rc = dhcppkt_store ( dhcppkt, DHCP_REQUESTED_ADDRESS, + &dhcp->offer, + sizeof ( dhcp->offer ) ) ) != 0 ) + return rc; + + /* Set server address */ + peer->sin_addr.s_addr = INADDR_BROADCAST; + peer->sin_port = htons ( BOOTPS_PORT ); + + return 0; +} + +/** + * Handle received packet during DHCP request + * + * @v dhcp DHCP session + * @v dhcppkt DHCP packet + * @v peer DHCP server address + * @v msgtype DHCP message type + * @v server_id DHCP server ID + */ +static void dhcp_request_rx ( struct dhcp_session *dhcp, + struct dhcp_packet *dhcppkt, + struct sockaddr_in *peer, uint8_t msgtype, + struct in_addr server_id ) { + struct in_addr ip; + struct settings *parent; + int rc; + + DBGC ( dhcp, "DHCP %p %s from %s:%d", dhcp, + dhcp_msgtype_name ( msgtype ), inet_ntoa ( peer->sin_addr ), + ntohs ( peer->sin_port ) ); + if ( server_id.s_addr != peer->sin_addr.s_addr ) + DBGC ( dhcp, " (%s)", inet_ntoa ( server_id ) ); + + /* Identify leased IP address */ + ip = dhcppkt->dhcphdr->yiaddr; + if ( ip.s_addr ) + DBGC ( dhcp, " for %s", inet_ntoa ( ip ) ); + DBGC ( dhcp, "\n" ); + + /* Filter out unacceptable responses */ + if ( peer->sin_port != htons ( BOOTPS_PORT ) ) + return; + if ( msgtype /* BOOTP */ && ( msgtype != DHCPACK ) ) + return; + if ( server_id.s_addr != dhcp->server.s_addr ) + return; + + /* Record assigned address */ + dhcp->local.sin_addr = ip; + + /* Register settings */ + parent = netdev_settings ( dhcp->netdev ); + if ( ( rc = register_settings ( &dhcppkt->settings, parent ) ) != 0 ){ + DBGC ( dhcp, "DHCP %p could not register settings: %s\n", + dhcp, strerror ( rc ) ); + dhcp_finished ( dhcp, rc ); + return; + } + + /* Start ProxyDHCPREQUEST if applicable */ + if ( dhcp->proxy_server.s_addr && ( ! dhcp->no_pxedhcp ) ) { + dhcp_set_state ( dhcp, &dhcp_state_proxy ); + return; + } + + /* Terminate DHCP */ + dhcp_finished ( dhcp, 0 ); +} + +/** + * Handle timer expiry during DHCP discovery * + * @v dhcp DHCP session */ +static void dhcp_request_expired ( struct dhcp_session *dhcp ) { + + /* Retransmit current packet */ + dhcp_tx ( dhcp ); +} -/** DHCP session states */ -enum dhcp_session_state { - /** Sending DHCPDISCOVERs, collecting DHCPOFFERs and ProxyDHCPOFFERs */ - DHCP_STATE_DISCOVER = 0, - /** Sending DHCPREQUESTs, waiting for DHCPACK */ - DHCP_STATE_REQUEST, - /** Sending ProxyDHCPREQUESTs, waiting for ProxyDHCPACK */ - DHCP_STATE_PROXYREQUEST, +/** DHCP request state operations */ +static struct dhcp_session_state dhcp_state_request = { + .name = "request", + .tx = dhcp_request_tx, + .rx = dhcp_request_rx, + .expired = dhcp_request_expired, + .tx_msgtype = DHCPREQUEST, + .apply_min_timeout = 0, }; /** - * Name a DHCP session state + * Construct transmitted packet for ProxyDHCP request + * + * @v dhcp DHCP session + * @v dhcppkt DHCP packet + * @v peer Destination address + */ +static int dhcp_proxy_tx ( struct dhcp_session *dhcp, + struct dhcp_packet *dhcppkt, + struct sockaddr_in *peer ) { + int rc; + + DBGC ( dhcp, "DHCP %p ProxyDHCP REQUEST to %s:%d\n", + dhcp, inet_ntoa ( dhcp->proxy_server ), PXE_PORT ); + + /* Set server ID */ + if ( ( rc = dhcppkt_store ( dhcppkt, DHCP_SERVER_IDENTIFIER, + &dhcp->proxy_server, + sizeof ( dhcp->proxy_server ) ) ) != 0 ) + return rc; + + /* Set server address */ + peer->sin_addr = dhcp->proxy_server; + peer->sin_port = htons ( PXE_PORT ); + + return 0; +} + +/** + * Handle received packet during ProxyDHCP request * - * @v state DHCP session state - * @ret string DHCP session state name + * @v dhcp DHCP session + * @v dhcppkt DHCP packet + * @v peer DHCP server address + * @v msgtype DHCP message type + * @v server_id DHCP server ID */ -static inline const char * dhcp_state_name ( enum dhcp_session_state state ) { - switch ( state ) { - case DHCP_STATE_DISCOVER: return "DHCPDISCOVER"; - case DHCP_STATE_REQUEST: return "DHCPREQUEST"; - case DHCP_STATE_PROXYREQUEST: return "ProxyDHCPREQUEST"; - default: return "<invalid>"; +static void dhcp_proxy_rx ( struct dhcp_session *dhcp, + struct dhcp_packet *dhcppkt, + struct sockaddr_in *peer, uint8_t msgtype, + struct in_addr server_id ) { + int rc; + + DBGC ( dhcp, "DHCP %p %s from %s:%d", dhcp, + dhcp_msgtype_name ( msgtype ), inet_ntoa ( peer->sin_addr ), + ntohs ( peer->sin_port ) ); + if ( server_id.s_addr != peer->sin_addr.s_addr ) + DBGC ( dhcp, " (%s)", inet_ntoa ( server_id ) ); + DBGC ( dhcp, "\n" ); + + /* Filter out unacceptable responses */ + if ( peer->sin_port != htons ( PXE_PORT ) ) + return; + if ( msgtype != DHCPACK ) + return; + if ( server_id.s_addr /* Linux PXE server omits server ID */ && + ( server_id.s_addr != dhcp->proxy_server.s_addr ) ) + return; + + /* Register settings */ + dhcppkt->settings.name = PROXYDHCP_SETTINGS_NAME; + if ( ( rc = register_settings ( &dhcppkt->settings, NULL ) ) != 0 ) { + DBGC ( dhcp, "DHCP %p could not register settings: %s\n", + dhcp, strerror ( rc ) ); + dhcp_finished ( dhcp, rc ); + return; } + + /* Terminate DHCP */ + dhcp_finished ( dhcp, 0 ); } -/** A DHCP session */ -struct dhcp_session { - /** Reference counter */ - struct refcnt refcnt; - /** Job control interface */ - struct job_interface job; - /** Data transfer interface */ - struct xfer_interface xfer; +/** + * Handle timer expiry during ProxyDHCP request + * + * @v dhcp DHCP session + */ +static void dhcp_proxy_expired ( struct dhcp_session *dhcp ) { + unsigned long elapsed = ( currticks() - dhcp->start ); - /** Network device being configured */ - struct net_device *netdev; + /* Give up waiting for ProxyDHCP before we reach the failure point */ + if ( elapsed > PROXYDHCP_MAX_TIMEOUT ) { + dhcp_finished ( dhcp, 0 ); + return; + } - /** State of the session - * - * This is a value for the @c DHCP_MESSAGE_TYPE option - * (e.g. @c DHCPDISCOVER). - */ - enum dhcp_session_state state; - /** DHCPOFFER obtained during DHCPDISCOVER */ - struct dhcp_settings *dhcpoffer; - /** ProxyDHCPOFFER obtained during DHCPDISCOVER */ - struct dhcp_settings *proxydhcpoffer; - /** Retransmission timer */ - struct retry_timer timer; - /** Start time of the current state (in ticks) */ - unsigned long start; + /* Retransmit current packet */ + dhcp_tx ( dhcp ); +} + +/** ProxyDHCP request state operations */ +static struct dhcp_session_state dhcp_state_proxy = { + .name = "ProxyDHCP", + .tx = dhcp_proxy_tx, + .rx = dhcp_proxy_rx, + .expired = dhcp_proxy_expired, + .tx_msgtype = DHCPREQUEST, + .apply_min_timeout = 0, }; /** - * Free DHCP session + * Construct transmitted packet for PXE Boot Server Discovery * - * @v refcnt Reference counter + * @v dhcp DHCP session + * @v dhcppkt DHCP packet + * @v peer Destination address */ -static void dhcp_free ( struct refcnt *refcnt ) { - struct dhcp_session *dhcp = - container_of ( refcnt, struct dhcp_session, refcnt ); +static int dhcp_pxebs_tx ( struct dhcp_session *dhcp, + struct dhcp_packet *dhcppkt, + struct sockaddr_in *peer ) { + struct dhcp_pxe_boot_menu_item menu_item = { 0, 0 }; + int rc; - netdev_put ( dhcp->netdev ); - dhcpset_put ( dhcp->dhcpoffer ); - dhcpset_put ( dhcp->proxydhcpoffer ); - free ( dhcp ); + DBGC ( dhcp, "DHCP %p PXEBS REQUEST to %s:%d for type %d\n", + dhcp, inet_ntoa ( *(dhcp->pxe_attempt) ), PXE_PORT, + ntohs ( dhcp->pxe_type ) ); + + /* Set boot menu item */ + menu_item.type = dhcp->pxe_type; + if ( ( rc = dhcppkt_store ( dhcppkt, DHCP_PXE_BOOT_MENU_ITEM, + &menu_item, sizeof ( menu_item ) ) ) != 0 ) + return rc; + + /* Set server address */ + peer->sin_addr = *(dhcp->pxe_attempt); + peer->sin_port = htons ( PXE_PORT ); + + return 0; } /** - * Mark DHCP session as complete + * Check to see if PXE Boot Server address is acceptable * * @v dhcp DHCP session - * @v rc Return status code + * @v bs Boot Server address + * @ret accept Boot Server is acceptable */ -static void dhcp_finished ( struct dhcp_session *dhcp, int rc ) { +static int dhcp_pxebs_accept ( struct dhcp_session *dhcp, + struct in_addr bs ) { + struct in_addr *accept; + + /* Accept if we have no acceptance filter */ + if ( ! dhcp->pxe_accept ) + return 1; + + /* Scan through acceptance list */ + for ( accept = dhcp->pxe_accept ; accept->s_addr ; accept++ ) { + if ( accept->s_addr == bs.s_addr ) + return 1; + } - /* Block futher incoming messages */ - job_nullify ( &dhcp->job ); - xfer_nullify ( &dhcp->xfer ); + DBGC ( dhcp, "DHCP %p rejecting server %s\n", + dhcp, inet_ntoa ( bs ) ); + return 0; +} - /* Stop retry timer */ - stop_timer ( &dhcp->timer ); +/** + * Handle received packet during PXE Boot Server Discovery + * + * @v dhcp DHCP session + * @v dhcppkt DHCP packet + * @v peer DHCP server address + * @v msgtype DHCP message type + * @v server_id DHCP server ID + */ +static void dhcp_pxebs_rx ( struct dhcp_session *dhcp, + struct dhcp_packet *dhcppkt, + struct sockaddr_in *peer, uint8_t msgtype, + struct in_addr server_id ) { + struct dhcp_pxe_boot_menu_item menu_item = { 0, 0 }; + int rc; - /* Free resources and close interfaces */ - xfer_close ( &dhcp->xfer, rc ); - job_done ( &dhcp->job, rc ); + DBGC ( dhcp, "DHCP %p %s from %s:%d", dhcp, + dhcp_msgtype_name ( msgtype ), inet_ntoa ( peer->sin_addr ), + ntohs ( peer->sin_port ) ); + if ( server_id.s_addr != peer->sin_addr.s_addr ) + DBGC ( dhcp, " (%s)", inet_ntoa ( server_id ) ); + + /* Identify boot menu item */ + dhcppkt_fetch ( dhcppkt, DHCP_PXE_BOOT_MENU_ITEM, + &menu_item, sizeof ( menu_item ) ); + if ( menu_item.type ) + DBGC ( dhcp, " for type %d", ntohs ( menu_item.type ) ); + DBGC ( dhcp, "\n" ); + + /* Filter out unacceptable responses */ + if ( peer->sin_port != htons ( PXE_PORT ) ) + return; + if ( msgtype != DHCPACK ) + return; + if ( menu_item.type != dhcp->pxe_type ) + return; + if ( ! dhcp_pxebs_accept ( dhcp, ( server_id.s_addr ? + server_id : peer->sin_addr ) ) ) + return; + + /* Register settings */ + dhcppkt->settings.name = PXEBS_SETTINGS_NAME; + if ( ( rc = register_settings ( &dhcppkt->settings, NULL ) ) != 0 ) { + DBGC ( dhcp, "DHCP %p could not register settings: %s\n", + dhcp, strerror ( rc ) ); + dhcp_finished ( dhcp, rc ); + return; + } + + /* Terminate DHCP */ + dhcp_finished ( dhcp, 0 ); } +/** + * Handle timer expiry during PXE Boot Server Discovery + * + * @v dhcp DHCP session + */ +static void dhcp_pxebs_expired ( struct dhcp_session *dhcp ) { + unsigned long elapsed = ( currticks() - dhcp->start ); + + /* Give up waiting before we reach the failure point, and fail + * over to the next server in the attempt list + */ + if ( elapsed > PXEBS_MAX_TIMEOUT ) { + dhcp->pxe_attempt++; + if ( dhcp->pxe_attempt->s_addr ) { + dhcp_set_state ( dhcp, &dhcp_state_pxebs ); + return; + } else { + dhcp_finished ( dhcp, -ETIMEDOUT ); + return; + } + } + + /* Retransmit current packet */ + dhcp_tx ( dhcp ); +} + +/** PXE Boot Server Discovery state operations */ +static struct dhcp_session_state dhcp_state_pxebs = { + .name = "PXEBS", + .tx = dhcp_pxebs_tx, + .rx = dhcp_pxebs_rx, + .expired = dhcp_pxebs_expired, + .tx_msgtype = DHCPREQUEST, + .apply_min_timeout = 1, +}; + /**************************************************************************** * - * Data transfer interface + * Packet construction * */ @@ -376,24 +813,23 @@ static void dhcp_finished ( struct dhcp_session *dhcp, int rc ) { * @v netdev Network device * @v msgtype DHCP message type * @v options Initial options to include (or NULL) + * @v options_len Length of initial options * @v data Buffer for DHCP packet * @v max_len Size of DHCP packet buffer * @ret rc Return status code * - * Creates a DHCP packet in the specified buffer, and fills out a @c - * dhcp_packet structure. + * Creates a DHCP packet in the specified buffer, and initialise a + * DHCP packet structure. */ int dhcp_create_packet ( struct dhcp_packet *dhcppkt, struct net_device *netdev, uint8_t msgtype, - struct dhcp_options *options, + const void *options, size_t options_len, void *data, size_t max_len ) { struct dhcphdr *dhcphdr = data; - size_t options_len; unsigned int hlen; int rc; /* Sanity check */ - options_len = ( options ? options->len : 0 ); if ( max_len < ( sizeof ( *dhcphdr ) + options_len ) ) return -ENOSPC; @@ -413,7 +849,7 @@ int dhcp_create_packet ( struct dhcp_packet *dhcppkt, } dhcphdr->hlen = hlen; memcpy ( dhcphdr->chaddr, netdev->ll_addr, hlen ); - memcpy ( dhcphdr->options, options->data, options_len ); + memcpy ( dhcphdr->options, options, options_len ); /* Initialise DHCP packet structure */ memset ( dhcppkt, 0, sizeof ( *dhcppkt ) ); @@ -432,30 +868,32 @@ int dhcp_create_packet ( struct dhcp_packet *dhcppkt, * * @v dhcppkt DHCP packet structure to fill in * @v netdev Network device + * @v msgtype DHCP message type * @v ciaddr Client IP address - * @v offer DHCP offer, if applicable * @v data Buffer for DHCP packet * @v max_len Size of DHCP packet buffer * @ret rc Return status code + * + * Creates a DHCP request packet in the specified buffer, and + * initialise a DHCP packet structure. */ int dhcp_create_request ( struct dhcp_packet *dhcppkt, - struct net_device *netdev, struct in_addr ciaddr, - struct dhcp_packet *offer, - void *data, size_t max_len ) { + struct net_device *netdev, unsigned int msgtype, + struct in_addr ciaddr, void *data, size_t max_len ) { struct device_description *desc = &netdev->dev->desc; struct dhcp_netdev_desc dhcp_desc; struct dhcp_client_id client_id; struct dhcp_client_uuid client_uuid; - unsigned int msgtype; size_t dhcp_features_len; size_t ll_addr_len; + ssize_t len; int rc; /* Create DHCP packet */ - msgtype = ( offer ? DHCPREQUEST : DHCPDISCOVER ); if ( ( rc = dhcp_create_packet ( dhcppkt, netdev, msgtype, - &dhcp_request_options, data, - max_len ) ) != 0 ) { + dhcp_request_options_data, + sizeof ( dhcp_request_options_data ), + data, max_len ) ) != 0 ) { DBG ( "DHCP could not create DHCP packet: %s\n", strerror ( rc ) ); return rc; @@ -464,32 +902,6 @@ int dhcp_create_request ( struct dhcp_packet *dhcppkt, /* Set client IP address */ dhcppkt->dhcphdr->ciaddr = ciaddr; - /* Copy any required options from previous server repsonse */ - if ( offer ) { - struct in_addr server = { 0 }; - struct in_addr *ip = &offer->dhcphdr->yiaddr; - - /* Copy server identifier, if present */ - if ( ( dhcppkt_fetch ( offer, DHCP_SERVER_IDENTIFIER, &server, - sizeof ( server ) ) >= 0 ) && - ( ( rc = dhcppkt_store ( dhcppkt, DHCP_SERVER_IDENTIFIER, - &server, - sizeof ( server ) ) ) != 0 ) ) { - DBG ( "DHCP could not set server ID: %s\n", - strerror ( rc ) ); - return rc; - } - - /* Copy requested IP address, if present */ - if ( ( ip->s_addr != 0 ) && - ( ( rc = dhcppkt_store ( dhcppkt, DHCP_REQUESTED_ADDRESS, - ip, sizeof ( *ip ) ) ) != 0 ) ) { - DBG ( "DHCP could not set requested address: %s\n", - strerror ( rc ) ); - return rc; - } - } - /* Add options to identify the feature list */ dhcp_features_len = ( dhcp_features_end - dhcp_features ); if ( ( rc = dhcppkt_store ( dhcppkt, DHCP_EB_ENCAP, dhcp_features, @@ -526,8 +938,8 @@ int dhcp_create_request ( struct dhcp_packet *dhcppkt, /* Add client UUID, if we have one. Required for PXE. */ client_uuid.type = DHCP_CLIENT_UUID_TYPE; - if ( ( rc = fetch_uuid_setting ( NULL, &uuid_setting, - &client_uuid.uuid ) ) >= 0 ) { + if ( ( len = fetch_uuid_setting ( NULL, &uuid_setting, + &client_uuid.uuid ) ) >= 0 ) { if ( ( rc = dhcppkt_store ( dhcppkt, DHCP_CLIENT_UUID, &client_uuid, sizeof ( client_uuid ) ) ) != 0 ) { @@ -537,9 +949,29 @@ int dhcp_create_request ( struct dhcp_packet *dhcppkt, } } + /* 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 ( ( rc = dhcppkt_store ( dhcppkt, DHCP_USER_CLASS_ID, + &user_class, + sizeof ( user_class ) ) ) != 0 ) { + DBG ( "DHCP could not set user class: %s\n", + strerror ( rc ) ); + return rc; + } + } + return 0; } +/**************************************************************************** + * + * Data transfer interface + * + */ + /** * Transmit DHCP request * @@ -547,18 +979,17 @@ int dhcp_create_request ( struct dhcp_packet *dhcppkt, * @ret rc Return status code */ static int dhcp_tx ( struct dhcp_session *dhcp ) { - static struct sockaddr_in proxydhcp_server = { + static struct sockaddr_in peer = { .sin_family = AF_INET, - .sin_port = htons ( PROXYDHCP_PORT ), }; struct xfer_metadata meta = { .netdev = dhcp->netdev, + .src = ( struct sockaddr * ) &dhcp->local, + .dest = ( struct sockaddr * ) &peer, }; struct io_buffer *iobuf; + uint8_t msgtype = dhcp->state->tx_msgtype; struct dhcp_packet dhcppkt; - struct dhcp_packet *offer = NULL; - struct in_addr ciaddr = { 0 }; - int check_len; int rc; /* Start retry timer. Do this first so that failures to @@ -566,54 +997,31 @@ static int dhcp_tx ( struct dhcp_session *dhcp ) { */ start_timer ( &dhcp->timer ); - /* Determine packet contents based on current state */ - switch ( dhcp->state ) { - case DHCP_STATE_DISCOVER: - DBGC ( dhcp, "DHCP %p transmitting DHCPDISCOVER\n", dhcp ); - break; - case DHCP_STATE_REQUEST: - DBGC ( dhcp, "DHCP %p transmitting DHCPREQUEST\n", dhcp ); - assert ( dhcp->dhcpoffer ); - offer = &dhcp->dhcpoffer->dhcppkt; - break; - case DHCP_STATE_PROXYREQUEST: - DBGC ( dhcp, "DHCP %p transmitting ProxyDHCPREQUEST\n", dhcp ); - assert ( dhcp->dhcpoffer ); - assert ( dhcp->proxydhcpoffer ); - offer = &dhcp->proxydhcpoffer->dhcppkt; - ciaddr = dhcp->dhcpoffer->dhcppkt.dhcphdr->yiaddr; - check_len = dhcppkt_fetch ( offer, DHCP_SERVER_IDENTIFIER, - &proxydhcp_server.sin_addr, - sizeof(proxydhcp_server.sin_addr)); - meta.dest = ( struct sockaddr * ) &proxydhcp_server; - assert ( ciaddr.s_addr != 0 ); - assert ( proxydhcp_server.sin_addr.s_addr != 0 ); - assert ( check_len == sizeof ( proxydhcp_server.sin_addr ) ); - break; - default: - assert ( 0 ); - break; - } - /* Allocate buffer for packet */ iobuf = xfer_alloc_iob ( &dhcp->xfer, DHCP_MIN_LEN ); if ( ! iobuf ) return -ENOMEM; - /* Create DHCP packet in temporary buffer */ - if ( ( rc = dhcp_create_request ( &dhcppkt, dhcp->netdev, - ciaddr, offer, iobuf->data, + /* Create basic DHCP packet in temporary buffer */ + if ( ( rc = dhcp_create_request ( &dhcppkt, dhcp->netdev, msgtype, + dhcp->local.sin_addr, iobuf->data, iob_tailroom ( iobuf ) ) ) != 0 ) { DBGC ( dhcp, "DHCP %p could not construct DHCP request: %s\n", dhcp, strerror ( rc ) ); goto done; } + /* Fill in packet based on current state */ + if ( ( rc = dhcp->state->tx ( dhcp, &dhcppkt, &peer ) ) != 0 ) { + DBGC ( dhcp, "DHCP %p could not fill DHCP request: %s\n", + dhcp, strerror ( rc ) ); + goto done; + } + /* Transmit the packet */ iob_put ( iobuf, dhcppkt.len ); - rc = xfer_deliver_iob_meta ( &dhcp->xfer, iobuf, &meta ); - iobuf = NULL; - if ( rc != 0 ) { + if ( ( rc = xfer_deliver_iob_meta ( &dhcp->xfer, iob_disown ( iobuf ), + &meta ) ) != 0 ) { DBGC ( dhcp, "DHCP %p could not transmit UDP packet: %s\n", dhcp, strerror ( rc ) ); goto done; @@ -625,246 +1033,6 @@ static int dhcp_tx ( struct dhcp_session *dhcp ) { } /** - * Transition to new DHCP session state - * - * @v dhcp DHCP session - * @v state New session state - */ -static void dhcp_set_state ( struct dhcp_session *dhcp, - enum dhcp_session_state state ) { - DBGC ( dhcp, "DHCP %p entering %s state\n", - dhcp, dhcp_state_name ( state ) ); - dhcp->state = state; - dhcp->start = currticks(); - start_timer_nodelay ( &dhcp->timer ); -} - -/** - * Store received DHCPOFFER - * - * @v dhcp DHCP session - * @v dhcpoffer Received DHCPOFFER - * @v stored_dhcpoffer Location to store DHCPOFFER - * - * The DHCPOFFER will be stored in place of the existing stored - * DHCPOFFER if its priority is equal to or greater than the stored - * DHCPOFFER. - */ -static void dhcp_store_dhcpoffer ( struct dhcp_session *dhcp, - struct dhcp_settings *dhcpoffer, - struct dhcp_settings **stored_dhcpoffer ) { - uint8_t stored_priority = 0; - uint8_t priority = 0; - - /* Get priorities of the two DHCPOFFERs */ - if ( *stored_dhcpoffer ) { - dhcppkt_fetch ( &(*stored_dhcpoffer)->dhcppkt, - DHCP_EB_PRIORITY, &stored_priority, - sizeof ( stored_priority ) ); - } - dhcppkt_fetch ( &dhcpoffer->dhcppkt, DHCP_EB_PRIORITY, &priority, - sizeof ( priority ) ); - - /* Replace stored offer only if priority is equal or greater */ - if ( priority >= stored_priority ) { - if ( *stored_dhcpoffer ) { - DBGC ( dhcp, "DHCP %p stored DHCPOFFER %p discarded\n", - dhcp, *stored_dhcpoffer ); - } - DBGC ( dhcp, "DHCP %p received DHCPOFFER %p stored\n", - dhcp, dhcpoffer ); - dhcpset_put ( *stored_dhcpoffer ); - *stored_dhcpoffer = dhcpset_get ( dhcpoffer ); - } -} - -/** - * Handle received DHCPOFFER - * - * @v dhcp DHCP session - * @v dhcpoffer Received DHCPOFFER - */ -static void dhcp_rx_dhcpoffer ( struct dhcp_session *dhcp, - struct dhcp_settings *dhcpoffer ) { - struct in_addr server_id = { 0 }; - char vci[9]; /* "PXEClient" */ - int len; - uint8_t ignore_proxy = 0; - unsigned long elapsed; - - /* Check for presence of DHCP server ID */ - if ( dhcppkt_fetch ( &dhcpoffer->dhcppkt, DHCP_SERVER_IDENTIFIER, - &server_id, sizeof ( server_id ) ) - != sizeof ( server_id ) ) { - DBGC ( dhcp, "DHCP %p received DHCPOFFER %p missing server " - "identifier\n", dhcp, dhcpoffer ); - /* Could be a valid BOOTP offer; do not abort processing */ - } - - /* If there is an IP address, it's a normal DHCPOFFER */ - if ( dhcpoffer->dhcppkt.dhcphdr->yiaddr.s_addr != 0 ) { - DBGC ( dhcp, "DHCP %p received DHCPOFFER %p from %s has IP " - "address\n", - dhcp, dhcpoffer, inet_ntoa ( server_id ) ); - dhcp_store_dhcpoffer ( dhcp, dhcpoffer, &dhcp->dhcpoffer ); - } - - /* If there is a "PXEClient" vendor class ID, it's a - * ProxyDHCPOFFER. Note that it could be both a normal - * DHCPOFFER and a ProxyDHCPOFFER. - */ - len = dhcppkt_fetch ( &dhcpoffer->dhcppkt, DHCP_VENDOR_CLASS_ID, - vci, sizeof ( vci ) ); - if ( ( server_id.s_addr != 0 ) && - ( len >= ( int ) sizeof ( vci ) ) && - ( strncmp ( "PXEClient", vci, sizeof ( vci ) ) == 0 ) ) { - DBGC ( dhcp, "DHCP %p received DHCPOFFER %p from %s is a " - "ProxyDHCPOFFER\n", - dhcp, dhcpoffer, inet_ntoa ( server_id ) ); - dhcp_store_dhcpoffer ( dhcp, dhcpoffer, - &dhcp->proxydhcpoffer ); - } - - /* We can transition to making the DHCPREQUEST when we have a - * valid DHCPOFFER, and either: - * - * o The DHCPOFFER instructs us to not wait for ProxyDHCP, or - * o We have a valid ProxyDHCPOFFER, or - * o We have allowed sufficient time for ProxyDHCPOFFERs. - */ - - /* If we don't yet have a DHCPOFFER, do nothing */ - if ( ! dhcp->dhcpoffer ) - return; - - /* If the DHCPOFFER instructs us to ignore ProxyDHCP, discard - * any ProxyDHCPOFFER - */ - dhcppkt_fetch ( &dhcp->dhcpoffer->dhcppkt, DHCP_EB_NO_PROXYDHCP, - &ignore_proxy, sizeof ( ignore_proxy ) ); - if ( ignore_proxy && dhcp->proxydhcpoffer ) { - DBGC ( dhcp, "DHCP %p discarding ProxyDHCPOFFER\n", dhcp ); - dhcpset_put ( dhcp->proxydhcpoffer ); - dhcp->proxydhcpoffer = NULL; - } - - /* If we can't yet transition to DHCPREQUEST, do nothing */ - elapsed = ( currticks() - dhcp->start ); - if ( ! ( ignore_proxy || dhcp->proxydhcpoffer || - ( elapsed > PROXYDHCP_WAIT_TIME ) ) ) - return; - - /* Transition to DHCPREQUEST */ - dhcp_set_state ( dhcp, DHCP_STATE_REQUEST ); -} - -/** - * Store received DHCPACK - * - * @v dhcp DHCP session - * @v dhcpack Received DHCPACK - * - * The DHCPACK will be registered as a settings block. - */ -static int dhcp_store_dhcpack ( struct dhcp_session *dhcp, - struct dhcp_settings *dhcpack, - struct settings *parent ) { - struct settings *settings = &dhcpack->settings; - struct settings *old_settings; - int rc; - - /* Unregister any old settings obtained via DHCP */ - if ( ( old_settings = find_child_settings ( parent, settings->name ) )) - unregister_settings ( old_settings ); - - /* Register new settings */ - if ( ( rc = register_settings ( settings, parent ) ) != 0 ) { - DBGC ( dhcp, "DHCP %p could not register settings: %s\n", - dhcp, strerror ( rc ) ); - dhcp_finished ( dhcp, rc ); /* This is a fatal error */ - return rc; - } - - return 0; -} - -/** - * Handle received DHCPACK - * - * @v dhcp DHCP session - * @v dhcpack Received DHCPACK - */ -static void dhcp_rx_dhcpack ( struct dhcp_session *dhcp, - struct dhcp_settings *dhcpack ) { - struct settings *parent; - struct in_addr offer_server_id = { 0 }; - struct in_addr ack_server_id = { 0 }; - int rc; - - /* Verify server ID matches */ - assert ( dhcp->dhcpoffer != NULL ); - dhcppkt_fetch ( &dhcp->dhcpoffer->dhcppkt, DHCP_SERVER_IDENTIFIER, - &offer_server_id, sizeof ( offer_server_id ) ); - dhcppkt_fetch ( &dhcpack->dhcppkt, DHCP_SERVER_IDENTIFIER, - &ack_server_id, sizeof ( ack_server_id ) ); - if ( offer_server_id.s_addr != ack_server_id.s_addr ) { - DBGC ( dhcp, "DHCP %p ignoring DHCPACK with wrong server ID " - "%s\n", dhcp, inet_ntoa ( ack_server_id ) ); - return; - } - - /* Register settings */ - parent = netdev_settings ( dhcp->netdev ); - if ( ( rc = dhcp_store_dhcpack ( dhcp, dhcpack, parent ) ) !=0 ) - return; - - /* If we have a ProxyDHCPOFFER, transition to PROXYDHCPREQUEST */ - if ( dhcp->proxydhcpoffer ) { - dhcp->timer.min_timeout = 0; - dhcp_set_state ( dhcp, DHCP_STATE_PROXYREQUEST ); - return; - } - - /* Terminate DHCP */ - dhcp_finished ( dhcp, 0 ); -} - -/** - * Handle received ProxyDHCPACK - * - * @v dhcp DHCP session - * @v proxydhcpack Received ProxyDHCPACK - */ -static void dhcp_rx_proxydhcpack ( struct dhcp_session *dhcp, - struct dhcp_settings *proxydhcpack ) { - struct in_addr offer_server_id = { 0 }; - struct in_addr ack_server_id = { 0 }; - int rc; - - /* Verify server ID matches */ - assert ( dhcp->proxydhcpoffer != NULL ); - dhcppkt_fetch ( &dhcp->proxydhcpoffer->dhcppkt, DHCP_SERVER_IDENTIFIER, - &offer_server_id, sizeof ( offer_server_id ) ); - dhcppkt_fetch ( &proxydhcpack->dhcppkt, DHCP_SERVER_IDENTIFIER, - &ack_server_id, sizeof ( ack_server_id ) ); - if ( offer_server_id.s_addr != ack_server_id.s_addr ) { - DBGC ( dhcp, "DHCP %p ignoring ProxyDHCPACK with wrong server " - "ID %s\n", dhcp, inet_ntoa ( ack_server_id ) ); - return; - } - - /* Rename settings */ - proxydhcpack->settings.name = PROXYDHCP_SETTINGS_NAME; - - /* Register settings */ - if ( ( rc = dhcp_store_dhcpack ( dhcp, proxydhcpack, NULL ) ) != 0 ) - return; - - /* Terminate DHCP */ - dhcp_finished ( dhcp, 0 ); -} - -/** * Receive new data * * @v xfer Data transfer interface @@ -877,79 +1045,63 @@ static int dhcp_deliver_iob ( struct xfer_interface *xfer, struct xfer_metadata *meta ) { struct dhcp_session *dhcp = container_of ( xfer, struct dhcp_session, xfer ); - struct sockaddr_tcpip *st_src; - unsigned int src_port; - struct dhcp_settings *dhcpset; + struct sockaddr_in *peer; + size_t data_len; + struct dhcp_packet *dhcppkt; struct dhcphdr *dhcphdr; uint8_t msgtype = 0; + struct in_addr server_id = { 0 }; int rc = 0; /* Sanity checks */ - if ( ! meta ) { - DBGC ( dhcp, "DHCP %p received packet without metadata\n", - dhcp ); - rc = -EINVAL; - goto err_no_meta; - } if ( ! meta->src ) { DBGC ( dhcp, "DHCP %p received packet without source port\n", dhcp ); rc = -EINVAL; goto err_no_src; } - st_src = ( struct sockaddr_tcpip * ) meta->src; - src_port = st_src->st_port; + peer = ( struct sockaddr_in * ) meta->src; - /* Convert packet into a DHCP settings block */ - dhcpset = dhcpset_create ( iobuf->data, iob_len ( iobuf ) ); - if ( ! dhcpset ) { - DBGC ( dhcp, "DHCP %p could not store DHCP packet\n", dhcp ); + /* Create a DHCP packet containing the I/O buffer contents. + * Whilst we could just use the original buffer in situ, that + * would waste the unused space in the packet buffer, and also + * waste a relatively scarce fully-aligned I/O buffer. + */ + data_len = iob_len ( iobuf ); + dhcppkt = zalloc ( sizeof ( *dhcppkt ) + data_len ); + if ( ! dhcppkt ) { rc = -ENOMEM; - goto err_dhcpset_create; + goto err_alloc_dhcppkt; } - dhcphdr = dhcpset->dhcppkt.dhcphdr; + dhcphdr = ( ( ( void * ) dhcppkt ) + sizeof ( *dhcppkt ) ); + memcpy ( dhcphdr, iobuf->data, data_len ); + dhcppkt_init ( dhcppkt, dhcphdr, data_len ); /* Identify message type */ - dhcppkt_fetch ( &dhcpset->dhcppkt, DHCP_MESSAGE_TYPE, &msgtype, + dhcppkt_fetch ( dhcppkt, DHCP_MESSAGE_TYPE, &msgtype, sizeof ( msgtype ) ); - DBGC ( dhcp, "DHCP %p received %s %p from port %d\n", dhcp, - dhcp_msgtype_name ( msgtype ), dhcpset, ntohs ( src_port ) ); + + /* Identify server ID */ + dhcppkt_fetch ( dhcppkt, DHCP_SERVER_IDENTIFIER, + &server_id, sizeof ( server_id ) ); /* Check for matching transaction ID */ if ( dhcphdr->xid != dhcp_xid ( dhcp->netdev ) ) { - DBGC ( dhcp, "DHCP %p received %s %p has bad transaction ID\n", - dhcp, dhcp_msgtype_name ( msgtype ), dhcpset ); + DBGC ( dhcp, "DHCP %p %s from %s:%d has bad transaction " + "ID\n", dhcp, dhcp_msgtype_name ( msgtype ), + inet_ntoa ( peer->sin_addr ), + ntohs ( peer->sin_port ) ); rc = -EINVAL; goto err_xid; }; /* Handle packet based on current state */ - switch ( dhcp->state ) { - case DHCP_STATE_DISCOVER: - if ( ( ( msgtype == DHCPOFFER ) || ( msgtype == DHCPNONE ) ) && - ( src_port == htons ( BOOTPS_PORT ) ) ) - dhcp_rx_dhcpoffer ( dhcp, dhcpset ); - break; - case DHCP_STATE_REQUEST: - if ( ( ( msgtype == DHCPACK ) || ( msgtype == DHCPNONE ) ) && - ( src_port == htons ( BOOTPS_PORT ) ) ) - dhcp_rx_dhcpack ( dhcp, dhcpset ); - break; - case DHCP_STATE_PROXYREQUEST: - if ( ( msgtype == DHCPACK ) && - ( src_port == htons ( PROXYDHCP_PORT ) ) ) - dhcp_rx_proxydhcpack ( dhcp, dhcpset ); - break; - default: - assert ( 0 ); - break; - } + dhcp->state->rx ( dhcp, dhcppkt, peer, msgtype, server_id ); err_xid: - dhcpset_put ( dhcpset ); - err_dhcpset_create: + dhcppkt_put ( dhcppkt ); + err_alloc_dhcppkt: err_no_src: - err_no_meta: free_iob ( iobuf ); return rc; } @@ -973,7 +1125,6 @@ static struct xfer_interface_operations dhcp_xfer_operations = { static void dhcp_timer_expired ( struct retry_timer *timer, int fail ) { struct dhcp_session *dhcp = container_of ( timer, struct dhcp_session, timer ); - unsigned long elapsed = ( currticks() - dhcp->start ); /* If we have failed, terminate DHCP */ if ( fail ) { @@ -981,19 +1132,8 @@ static void dhcp_timer_expired ( struct retry_timer *timer, int fail ) { return; } - /* Give up waiting for ProxyDHCP before we reach the failure point */ - if ( dhcp->dhcpoffer && ( elapsed > PROXYDHCP_WAIT_TIME ) ) { - if ( dhcp->state == DHCP_STATE_DISCOVER ) { - dhcp_set_state ( dhcp, DHCP_STATE_REQUEST ); - return; - } else if ( dhcp->state == DHCP_STATE_PROXYREQUEST ) { - dhcp_finished ( dhcp, 0 ); - return; - } - } - - /* Otherwise, retransmit current packet */ - dhcp_tx ( dhcp ); + /* Handle timer expiry based on current state */ + dhcp->state->expired ( dhcp ); } /**************************************************************************** @@ -1024,32 +1164,33 @@ static struct job_interface_operations dhcp_job_operations = { /**************************************************************************** * - * Instantiator + * Instantiators + * + */ + +/** + * DHCP peer address for socket opening * + * This is a dummy address; the only useful portion is the socket + * family (so that we get a UDP connection). The DHCP client will set + * the IP address and source port explicitly on each transmission. */ +static struct sockaddr dhcp_peer = { + .sa_family = AF_INET, +}; /** - * Start DHCP on a network device + * Start DHCP state machine on a network device * * @v job Job control interface * @v netdev Network device - * @v register_options DHCP option block registration routine * @ret rc Return status code * - * Starts DHCP on the specified network device. If successful, the @c - * register_options() routine will be called with the acquired - * options. + * Starts DHCP on the specified network device. If successful, the + * DHCPACK (and ProxyDHCPACK, if applicable) will be registered as + * option sources. */ int start_dhcp ( struct job_interface *job, struct net_device *netdev ) { - static struct sockaddr_in server = { - .sin_family = AF_INET, - .sin_addr.s_addr = INADDR_BROADCAST, - .sin_port = htons ( BOOTPS_PORT ), - }; - static struct sockaddr_in client = { - .sin_family = AF_INET, - .sin_port = htons ( BOOTPC_PORT ), - }; struct dhcp_session *dhcp; int rc; @@ -1061,19 +1202,163 @@ int start_dhcp ( struct job_interface *job, struct net_device *netdev ) { job_init ( &dhcp->job, &dhcp_job_operations, &dhcp->refcnt ); xfer_init ( &dhcp->xfer, &dhcp_xfer_operations, &dhcp->refcnt ); dhcp->netdev = netdev_get ( netdev ); + dhcp->local.sin_family = AF_INET; + dhcp->local.sin_port = htons ( BOOTPC_PORT ); dhcp->timer.expired = dhcp_timer_expired; - dhcp->timer.min_timeout = DHCP_MIN_TIMEOUT; - dhcp->timer.max_timeout = DHCP_MAX_TIMEOUT; - dhcp->start = currticks(); /* Instantiate child objects and attach to our interfaces */ - if ( ( rc = xfer_open_socket ( &dhcp->xfer, SOCK_DGRAM, - ( struct sockaddr * ) &server, - ( struct sockaddr * ) &client ) ) != 0 ) + if ( ( rc = xfer_open_socket ( &dhcp->xfer, SOCK_DGRAM, &dhcp_peer, + ( struct sockaddr * ) &dhcp->local ) ) != 0 ) goto err; - /* Start timer to initiate initial DHCPREQUEST */ - start_timer_nodelay ( &dhcp->timer ); + /* Enter DHCPDISCOVER state */ + dhcp_set_state ( dhcp, &dhcp_state_discover ); + + /* Attach parent interface, mortalise self, and return */ + job_plug_plug ( &dhcp->job, job ); + ref_put ( &dhcp->refcnt ); + return 0; + + err: + dhcp_finished ( dhcp, rc ); + ref_put ( &dhcp->refcnt ); + return rc; +} + +/** + * Retrieve list of PXE boot servers for a given server type + * + * @v dhcp DHCP session + * @v raw DHCP PXE boot server list + * @v raw_len Length of DHCP PXE boot server list + * @v ip IP address list to fill in + * + * The caller must ensure that the IP address list has sufficient + * space. + */ +static void pxebs_list ( struct dhcp_session *dhcp, void *raw, + size_t raw_len, struct in_addr *ip ) { + struct dhcp_pxe_boot_server *server = raw; + size_t server_len; + unsigned int i; + + while ( raw_len ) { + if ( raw_len < sizeof ( *server ) ) { + DBGC ( dhcp, "DHCP %p malformed PXE server list\n", + dhcp ); + break; + } + server_len = offsetof ( typeof ( *server ), + ip[ server->num_ip ] ); + if ( raw_len < server_len ) { + DBGC ( dhcp, "DHCP %p malformed PXE server list\n", + dhcp ); + break; + } + if ( server->type == dhcp->pxe_type ) { + for ( i = 0 ; i < server->num_ip ; i++ ) + *(ip++) = server->ip[i]; + } + server = ( ( ( void * ) server ) + server_len ); + raw_len -= server_len; + } +} + +/** + * Start PXE Boot Server Discovery on a network device + * + * @v job Job control interface + * @v netdev Network device + * @v pxe_type PXE server type + * @ret rc Return status code + * + * Starts PXE Boot Server Discovery on the specified network device. + * If successful, the Boot Server ACK will be registered as an option + * source. + */ +int start_pxebs ( struct job_interface *job, struct net_device *netdev, + unsigned int pxe_type ) { + struct setting pxe_discovery_control_setting = + { .tag = DHCP_PXE_DISCOVERY_CONTROL }; + struct setting pxe_boot_servers_setting = + { .tag = DHCP_PXE_BOOT_SERVERS }; + struct setting pxe_boot_server_mcast_setting = + { .tag = DHCP_PXE_BOOT_SERVER_MCAST }; + ssize_t pxebs_list_len; + struct dhcp_session *dhcp; + struct in_addr *ip; + unsigned int pxe_discovery_control; + int rc; + + /* Get upper bound for PXE boot server IP address list */ + pxebs_list_len = fetch_setting_len ( NULL, &pxe_boot_servers_setting ); + if ( pxebs_list_len < 0 ) + pxebs_list_len = 0; + + /* Allocate and initialise structure */ + dhcp = zalloc ( sizeof ( *dhcp ) + sizeof ( *ip ) /* mcast */ + + sizeof ( *ip ) /* bcast */ + pxebs_list_len + + sizeof ( *ip ) /* terminator */ ); + if ( ! dhcp ) + return -ENOMEM; + dhcp->refcnt.free = dhcp_free; + job_init ( &dhcp->job, &dhcp_job_operations, &dhcp->refcnt ); + xfer_init ( &dhcp->xfer, &dhcp_xfer_operations, &dhcp->refcnt ); + dhcp->netdev = netdev_get ( netdev ); + dhcp->local.sin_family = AF_INET; + fetch_ipv4_setting ( netdev_settings ( netdev ), &ip_setting, + &dhcp->local.sin_addr ); + dhcp->local.sin_port = htons ( BOOTPC_PORT ); + dhcp->pxe_type = htons ( pxe_type ); + dhcp->timer.expired = dhcp_timer_expired; + + /* Construct PXE boot server IP address lists */ + pxe_discovery_control = + fetch_uintz_setting ( NULL, &pxe_discovery_control_setting ); + ip = ( ( ( void * ) dhcp ) + sizeof ( *dhcp ) ); + dhcp->pxe_attempt = ip; + if ( ! ( pxe_discovery_control & PXEBS_NO_MULTICAST ) ) { + fetch_ipv4_setting ( NULL, &pxe_boot_server_mcast_setting, ip); + if ( ip->s_addr ) + ip++; + } + if ( ! ( pxe_discovery_control & PXEBS_NO_BROADCAST ) ) + (ip++)->s_addr = INADDR_BROADCAST; + if ( pxe_discovery_control & PXEBS_NO_UNKNOWN_SERVERS ) + dhcp->pxe_accept = ip; + if ( pxebs_list_len ) { + uint8_t buf[pxebs_list_len]; + + fetch_setting ( NULL, &pxe_boot_servers_setting, + buf, sizeof ( buf ) ); + pxebs_list ( dhcp, buf, sizeof ( buf ), ip ); + } + if ( ! dhcp->pxe_attempt->s_addr ) { + DBGC ( dhcp, "DHCP %p has no PXE boot servers for type %04x\n", + dhcp, pxe_type ); + rc = -EINVAL; + goto err; + } + + /* Dump out PXE server lists */ + DBGC ( dhcp, "DHCP %p attempting", dhcp ); + for ( ip = dhcp->pxe_attempt ; ip->s_addr ; ip++ ) + DBGC ( dhcp, " %s", inet_ntoa ( *ip ) ); + DBGC ( dhcp, "\n" ); + if ( dhcp->pxe_accept ) { + DBGC ( dhcp, "DHCP %p accepting", dhcp ); + for ( ip = dhcp->pxe_accept ; ip->s_addr ; ip++ ) + DBGC ( dhcp, " %s", inet_ntoa ( *ip ) ); + DBGC ( dhcp, "\n" ); + } + + /* Instantiate child objects and attach to our interfaces */ + if ( ( rc = xfer_open_socket ( &dhcp->xfer, SOCK_DGRAM, &dhcp_peer, + ( struct sockaddr * ) &dhcp->local ) ) != 0 ) + goto err; + + /* Enter PXEBS state */ + dhcp_set_state ( dhcp, &dhcp_state_pxebs ); /* Attach parent interface, mortalise self, and return */ job_plug_plug ( &dhcp->job, job ); diff --git a/gpxe/src/net/udp/dns.c b/gpxe/src/net/udp/dns.c index 1bcdbc7e..a498aefc 100644 --- a/gpxe/src/net/udp/dns.c +++ b/gpxe/src/net/udp/dns.c @@ -22,6 +22,7 @@ #include <stdint.h> #include <stdlib.h> #include <string.h> +#include <stdio.h> #include <errno.h> #include <byteswap.h> #include <gpxe/refcnt.h> @@ -47,6 +48,9 @@ static struct sockaddr_tcpip nameserver = { .st_port = htons ( DNS_PORT ), }; +/** The local domain */ +static char *localdomain; + /** A DNS request */ struct dns_request { /** Reference counter */ @@ -180,6 +184,27 @@ static union dns_rr_info * dns_find_rr ( struct dns_request *dns, } /** + * Append DHCP domain name if available and name is not fully qualified + * + * @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. + */ +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 ); + + /* Append local domain to name */ + asprintf ( &fqdn, "%s.%s", string, localdomain ); + return fqdn; +} + +/** * Convert a standard NUL-terminated string to a DNS name * * @v string Name as a NUL-terminated string @@ -452,19 +477,30 @@ static struct xfer_interface_operations dns_socket_operations = { static int dns_resolv ( struct resolv_interface *resolv, const char *name, struct sockaddr *sa ) { struct dns_request *dns; + char *fqdn; int rc; /* Fail immediately if no DNS servers */ if ( ! nameserver.st_family ) { DBG ( "DNS not attempting to resolve \"%s\": " "no DNS servers\n", name ); - return -ENXIO; + rc = -ENXIO; + 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; } /* Allocate DNS structure */ dns = zalloc ( sizeof ( *dns ) ); - if ( ! dns ) - return -ENOMEM; + if ( ! dns ) { + rc = -ENOMEM; + goto err_alloc_dns; + } resolv_init ( &dns->resolv, &null_resolv_ops, &dns->refcnt ); xfer_init ( &dns->socket, &dns_socket_operations, &dns->refcnt ); dns->timer.expired = dns_timer_expired; @@ -474,7 +510,7 @@ static int dns_resolv ( struct resolv_interface *resolv, 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 ( name, dns->query.payload ); + dns->qinfo = ( void * ) dns_make_name ( fqdn, dns->query.payload ); dns->qinfo->qtype = htons ( DNS_TYPE_A ); dns->qinfo->qclass = htons ( DNS_CLASS_IN ); @@ -484,7 +520,7 @@ static int dns_resolv ( struct resolv_interface *resolv, NULL ) ) != 0 ) { DBGC ( dns, "DNS %p could not open socket: %s\n", dns, strerror ( rc ) ); - goto err; + goto err_open_socket; } /* Send first DNS packet */ @@ -493,10 +529,15 @@ static int dns_resolv ( struct resolv_interface *resolv, /* Attach parent interface, mortalise self, and return */ resolv_plug_plug ( &dns->resolv, resolv ); ref_put ( &dns->refcnt ); + free ( fqdn ); return 0; - err: + err_open_socket: + err_alloc_dns: ref_put ( &dns->refcnt ); + err_qualify_name: + free ( fqdn ); + err_no_nameserver: return rc; } @@ -521,12 +562,20 @@ struct setting dns_setting __setting = { .type = &setting_type_ipv4, }; +/** Domain name setting */ +struct setting domain_setting __setting = { + .name = "domain", + .description = "Local domain", + .tag = DHCP_DOMAIN_NAME, + .type = &setting_type_string, +}; + /** - * Apply nameserver setting + * Apply DNS settings * * @ret rc Return status code */ -static int apply_nameserver_setting ( void ) { +static int apply_dns_settings ( void ) { struct sockaddr_in *sin_nameserver = ( struct sockaddr_in * ) &nameserver; int len; @@ -538,10 +587,15 @@ static int apply_nameserver_setting ( void ) { inet_ntoa ( sin_nameserver->sin_addr ) ); } + /* Get local domain DHCP option */ + if ( ( len = fetch_string_setting_copy ( NULL, &domain_setting, + &localdomain ) ) >= 0 ) + DBG ( "DNS local domain %s\n", localdomain ); + return 0; } -/** Nameserver setting applicator */ -struct settings_applicator nameserver_applicator __settings_applicator = { - .apply = apply_nameserver_setting, +/** DNS settings applicator */ +struct settings_applicator dns_applicator __settings_applicator = { + .apply = apply_dns_settings, }; diff --git a/gpxe/src/net/udp/slam.c b/gpxe/src/net/udp/slam.c index cb0dfa5c..6add99bc 100644 --- a/gpxe/src/net/udp/slam.c +++ b/gpxe/src/net/udp/slam.c @@ -219,7 +219,7 @@ static int slam_put_value ( struct slam_request *slam, */ len = ( ( flsl ( value ) + 10 ) / 8 ); if ( len >= iob_tailroom ( iobuf ) ) { - DBGC2 ( slam, "SLAM %p cannot add %d-byte value\n", + DBGC2 ( slam, "SLAM %p cannot add %zd-byte value\n", slam, len ); return -ENOBUFS; } @@ -380,7 +380,7 @@ static int slam_pull_value ( struct slam_request *slam, len = ( *data >> 5 ); if ( ( len == 0 ) || ( value && ( len > sizeof ( *value ) ) ) ) { - DBGC ( slam, "SLAM %p invalid value length %d bytes\n", + DBGC ( slam, "SLAM %p invalid value length %zd bytes\n", slam, len ); return -EINVAL; } diff --git a/gpxe/src/net/udp/tftp.c b/gpxe/src/net/udp/tftp.c index 8fdb3714..19525f79 100644 --- a/gpxe/src/net/udp/tftp.c +++ b/gpxe/src/net/udp/tftp.c @@ -45,6 +45,15 @@ FEATURE ( FEATURE_PROTOCOL, "TFTP", DHCP_EB_FEATURE_TFTP, 1 ); +/* TFTP-specific error codes */ +#define ETFTP_INVALID_BLKSIZE EUNIQ_01 +#define ETFTP_INVALID_TSIZE EUNIQ_02 +#define ETFTP_MC_NO_PORT EUNIQ_03 +#define ETFTP_MC_NO_MC EUNIQ_04 +#define ETFTP_MC_INVALID_MC EUNIQ_05 +#define ETFTP_MC_INVALID_IP EUNIQ_06 +#define ETFTP_MC_INVALID_PORT EUNIQ_07 + /** * A TFTP request * @@ -504,7 +513,7 @@ static int tftp_process_blksize ( struct tftp_request *tftp, if ( *end ) { DBGC ( tftp, "TFTP %p got invalid blksize \"%s\"\n", tftp, value ); - return -EINVAL; + return -( EINVAL | ETFTP_INVALID_BLKSIZE ); } DBGC ( tftp, "TFTP %p blksize=%d\n", tftp, tftp->blksize ); @@ -526,7 +535,7 @@ static int tftp_process_tsize ( struct tftp_request *tftp, if ( *end ) { DBGC ( tftp, "TFTP %p got invalid tsize \"%s\"\n", tftp, value ); - return -EINVAL; + return -( EINVAL | ETFTP_INVALID_TSIZE ); } DBGC ( tftp, "TFTP %p tsize=%ld\n", tftp, tftp->tsize ); @@ -560,13 +569,13 @@ static int tftp_process_multicast ( struct tftp_request *tftp, port = strchr ( addr, ',' ); if ( ! port ) { DBGC ( tftp, "TFTP %p multicast missing port,mc\n", tftp ); - return -EINVAL; + return -( EINVAL | ETFTP_MC_NO_PORT ); } *(port++) = '\0'; mc = strchr ( port, ',' ); if ( ! mc ) { DBGC ( tftp, "TFTP %p multicast missing mc\n", tftp ); - return -EINVAL; + return -( EINVAL | ETFTP_MC_NO_MC ); } *(mc++) = '\0'; @@ -575,7 +584,7 @@ static int tftp_process_multicast ( struct tftp_request *tftp, tftp->flags &= ~TFTP_FL_SEND_ACK; if ( *mc_end ) { DBGC ( tftp, "TFTP %p multicast invalid mc %s\n", tftp, mc ); - return -EINVAL; + return -( EINVAL | ETFTP_MC_INVALID_MC ); } DBGC ( tftp, "TFTP %p is%s the master client\n", tftp, ( ( tftp->flags & TFTP_FL_SEND_ACK ) ? "" : " not" ) ); @@ -584,7 +593,7 @@ static int tftp_process_multicast ( struct tftp_request *tftp, if ( inet_aton ( addr, &socket.sin.sin_addr ) == 0 ) { DBGC ( tftp, "TFTP %p multicast invalid IP address " "%s\n", tftp, addr ); - return -EINVAL; + return -( EINVAL | ETFTP_MC_INVALID_IP ); } DBGC ( tftp, "TFTP %p multicast IP address %s\n", tftp, inet_ntoa ( socket.sin.sin_addr ) ); @@ -592,7 +601,7 @@ static int tftp_process_multicast ( struct tftp_request *tftp, if ( *port_end ) { DBGC ( tftp, "TFTP %p multicast invalid port %s\n", tftp, port ); - return -EINVAL; + return -( EINVAL | ETFTP_MC_INVALID_PORT ); } DBGC ( tftp, "TFTP %p multicast port %d\n", tftp, ntohs ( socket.sin.sin_port ) ); @@ -732,6 +741,11 @@ static int tftp_rx_data ( struct tftp_request *tftp, rc = -EINVAL; goto done; } + if ( data->block == 0 ) { + DBGC ( tftp, "TFTP %p received data block 0\n", tftp ); + rc = -EINVAL; + goto done; + } /* Extract data */ block = ( ntohs ( data->block ) - 1 ); @@ -749,9 +763,8 @@ static int tftp_rx_data ( struct tftp_request *tftp, memset ( &meta, 0, sizeof ( meta ) ); meta.whence = SEEK_SET; meta.offset = offset; - rc = xfer_deliver_iob_meta ( &tftp->xfer, iobuf, &meta ); - iobuf = NULL; - if ( rc != 0 ) { + if ( ( rc = xfer_deliver_iob_meta ( &tftp->xfer, iob_disown ( iobuf ), + &meta ) ) != 0 ) { DBGC ( tftp, "TFTP %p could not deliver data: %s\n", tftp, strerror ( rc ) ); goto done; @@ -826,7 +839,7 @@ static int tftp_rx_error ( struct tftp_request *tftp, void *buf, size_t len ) { * * @v tftp TFTP connection * @v iobuf I/O buffer - * @v meta Transfer metadata, or NULL + * @v meta Transfer metadata * @ret rc Return status code */ static int tftp_rx ( struct tftp_request *tftp, @@ -843,11 +856,6 @@ static int tftp_rx ( struct tftp_request *tftp, "%zd\n", tftp, len ); goto done; } - if ( ! meta ) { - DBGC ( tftp, "TFTP %p received packet without metadata\n", - tftp ); - goto done; - } if ( ! meta->src ) { DBGC ( tftp, "TFTP %p received packet without source port\n", tftp ); @@ -873,8 +881,7 @@ static int tftp_rx ( struct tftp_request *tftp, rc = tftp_rx_oack ( tftp, iobuf->data, len ); break; case htons ( TFTP_DATA ): - rc = tftp_rx_data ( tftp, iobuf ); - iobuf = NULL; + rc = tftp_rx_data ( tftp, iob_disown ( iobuf ) ); break; case htons ( TFTP_ERROR ): rc = tftp_rx_error ( tftp, iobuf->data, len ); @@ -895,7 +902,7 @@ static int tftp_rx ( struct tftp_request *tftp, * * @v socket Transport layer interface * @v iobuf I/O buffer - * @v meta Transfer metadata, or NULL + * @v meta Transfer metadata * @ret rc Return status code */ static int tftp_socket_deliver_iob ( struct xfer_interface *socket, @@ -939,7 +946,7 @@ static struct xfer_interface_operations tftp_socket_operations = { * * @v mc_socket Multicast transport layer interface * @v iobuf I/O buffer - * @v meta Transfer metadata, or NULL + * @v meta Transfer metadata * @ret rc Return status code */ static int tftp_mc_socket_deliver_iob ( struct xfer_interface *mc_socket, @@ -977,11 +984,29 @@ static void tftp_xfer_close ( struct xfer_interface *xfer, int rc ) { tftp_done ( tftp, rc ); } +/** + * Check flow control window + * + * @v xfer Data transfer interface + * @ret len Length of window + */ +static size_t tftp_xfer_window ( struct xfer_interface *xfer ) { + struct tftp_request *tftp = + container_of ( xfer, struct tftp_request, xfer ); + + /* We abuse this data-xfer method to convey the blocksize to + * the caller. This really should be done using some kind of + * stat() method, but we don't yet have the facility to do + * that. + */ + return tftp->blksize; +} + /** TFTP data transfer interface operations */ static struct xfer_interface_operations tftp_xfer_operations = { .close = tftp_xfer_close, .vredirect = ignore_xfer_vredirect, - .window = unlimited_xfer_window, + .window = tftp_xfer_window, .alloc_iob = default_xfer_alloc_iob, .deliver_iob = xfer_deliver_as_raw, .deliver_raw = ignore_xfer_deliver_raw, diff --git a/gpxe/src/netboot.gpxe b/gpxe/src/netboot.gpxe new file mode 100644 index 00000000..dd3f01a3 --- /dev/null +++ b/gpxe/src/netboot.gpxe @@ -0,0 +1,4 @@ +#!gpxe +kernel http://www.zytor.com/netboot/pxelinux.0 +set filename http://www.zytor.com/netboot/pxelinux.0 +boot diff --git a/gpxe/src/tests/gdbstub_test.S b/gpxe/src/tests/gdbstub_test.S index bd293836..739b0527 100644 --- a/gpxe/src/tests/gdbstub_test.S +++ b/gpxe/src/tests/gdbstub_test.S @@ -1,10 +1,10 @@ .arch i386 - .section ".data" + .section ".data", "aw", @progbits watch_me: .long 0xfeedbeef - .section ".text" + .section ".text", "ax", @progbits .code32 gdbstub_test: /* 1. Read registers test */ diff --git a/gpxe/src/tests/gdbstub_test.gdb b/gpxe/src/tests/gdbstub_test.gdb index 52aa693f..52aa693f 100644..100755 --- a/gpxe/src/tests/gdbstub_test.gdb +++ b/gpxe/src/tests/gdbstub_test.gdb diff --git a/gpxe/src/usr/autoboot.c b/gpxe/src/usr/autoboot.c index 326292b4..98e79a7f 100644 --- a/gpxe/src/usr/autoboot.c +++ b/gpxe/src/usr/autoboot.c @@ -23,14 +23,12 @@ #include <gpxe/dhcp.h> #include <gpxe/settings.h> #include <gpxe/image.h> -#include <gpxe/embedded.h> +#include <gpxe/sanboot.h> #include <gpxe/uri.h> #include <usr/ifmgmt.h> #include <usr/route.h> #include <usr/dhcpmgmt.h> #include <usr/imgmgmt.h> -#include <usr/iscsiboot.h> -#include <usr/aoeboot.h> #include <usr/autoboot.h> /** @file @@ -45,6 +43,12 @@ /** Shutdown flags for exit */ int shutdown_exit_flags = 0; +/* SAN boot protocols */ +static struct sanboot_protocol sanboot_protocols[0] \ + __table_start ( struct sanboot_protocol, sanboot_protocols ); +static struct sanboot_protocol sanboot_protocols_end[0] \ + __table_end ( struct sanboot_protocol, sanboot_protocols ); + /** * Identify the boot network device * @@ -55,37 +59,13 @@ static struct net_device * find_boot_netdev ( void ) { } /** - * Boot embedded image - * - * @ret rc Return status code - */ -static int boot_embedded_image ( void ) { - struct image *image; - int rc; - - image = embedded_image(); - if ( !image ) - return ENOENT; - - if ( ( rc = imgload ( image ) ) != 0 ) { - printf ( "Could not load embedded image: %s\n", - strerror ( rc ) ); - } else if ( ( rc = imgexec ( image ) ) != 0 ) { - printf ( "Could not boot embedded image: %s\n", - strerror ( rc ) ); - } - image_put ( image ); - return rc; -} - -/** * Boot using next-server and filename * * @v filename Boot filename * @ret rc Return status code */ -static int boot_next_server_and_filename ( struct in_addr next_server, - const char *filename ) { +int boot_next_server_and_filename ( struct in_addr next_server, + const char *filename ) { struct uri *uri; struct image *image; char buf[ 23 /* tftp://xxx.xxx.xxx.xxx/ */ + strlen(filename) + 1 ]; @@ -141,12 +121,15 @@ static int boot_next_server_and_filename ( struct in_addr next_server, * @ret rc Return status code */ int boot_root_path ( const char *root_path ) { + struct sanboot_protocol *sanboot; /* Quick hack */ - if ( strncmp ( root_path, "iscsi:", 6 ) == 0 ) { - return iscsiboot ( root_path ); - } else if ( strncmp ( root_path, "aoe:", 4 ) == 0 ) { - return aoeboot ( root_path ); + for ( sanboot = sanboot_protocols ; + sanboot < sanboot_protocols_end ; sanboot++ ) { + if ( strncmp ( root_path, sanboot->prefix, + strlen ( sanboot->prefix ) ) == 0 ) { + return sanboot->boot ( root_path ); + } } return -ENOTSUP; @@ -159,8 +142,15 @@ int boot_root_path ( const char *root_path ) { * @ret rc Return status code */ static int netboot ( struct net_device *netdev ) { + struct setting vendor_class_id_setting + = { .tag = DHCP_VENDOR_CLASS_ID }; + struct setting pxe_discovery_control_setting + = { .tag = DHCP_PXE_DISCOVERY_CONTROL }; + struct setting pxe_boot_menu_setting + = { .tag = DHCP_PXE_BOOT_MENU }; char buf[256]; struct in_addr next_server; + unsigned int pxe_discovery_control; int rc; /* Open device and display device status */ @@ -181,10 +171,18 @@ static int netboot ( struct net_device *netdev ) { return rc; route(); - /* Try to boot an embedded image if we have one */ - rc = boot_embedded_image (); - if ( rc != ENOENT ) - return rc; + /* Try PXE menu boot, if applicable */ + fetch_string_setting ( NULL, &vendor_class_id_setting, + buf, sizeof ( buf ) ); + pxe_discovery_control = + fetch_uintz_setting ( NULL, &pxe_discovery_control_setting ); + if ( ( strcmp ( buf, "PXEClient" ) == 0 ) && + setting_exists ( NULL, &pxe_boot_menu_setting ) && + ( ! ( ( pxe_discovery_control & PXEBS_SKIP ) && + setting_exists ( NULL, &filename_setting ) ) ) ) { + printf ( "Booting from PXE menu\n" ); + return pxe_menu_boot ( netdev ); + } /* Try to download and boot whatever we are given as a filename */ fetch_ipv4_setting ( NULL, &next_server_setting, &next_server ); diff --git a/gpxe/src/usr/dhcpmgmt.c b/gpxe/src/usr/dhcpmgmt.c index 2e429cd6..6acf7f6d 100644 --- a/gpxe/src/usr/dhcpmgmt.c +++ b/gpxe/src/usr/dhcpmgmt.c @@ -46,3 +46,14 @@ int dhcp ( struct net_device *netdev ) { 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 ( "" ); + + return rc; +} diff --git a/gpxe/src/usr/ifmgmt.c b/gpxe/src/usr/ifmgmt.c index 9c88ab53..0ebf5615 100644 --- a/gpxe/src/usr/ifmgmt.c +++ b/gpxe/src/usr/ifmgmt.c @@ -20,9 +20,11 @@ #include <stdio.h> #include <unistd.h> #include <errno.h> +#include <console.h> #include <gpxe/netdevice.h> #include <gpxe/device.h> #include <gpxe/process.h> +#include <gpxe/keys.h> #include <usr/ifmgmt.h> /** @file @@ -59,6 +61,25 @@ void ifclose ( struct net_device *netdev ) { } /** + * Print network device error breakdown + * + * @v stats Network device statistics + * @v prefix Message prefix + */ +static void ifstat_errors ( struct net_device_stats *stats, + const char *prefix ) { + unsigned int i; + + for ( i = 0 ; i < ( sizeof ( stats->errors ) / + sizeof ( stats->errors[0] ) ) ; i++ ) { + if ( stats->errors[i].count ) + printf ( " [%s: %d x \"%s\"]\n", prefix, + stats->errors[i].count, + strerror ( stats->errors[i].rc ) ); + } +} + +/** * Print status of network device * * @v netdev Network device @@ -69,8 +90,10 @@ void ifstat ( struct net_device *netdev ) { netdev->name, netdev_hwaddr ( netdev ), netdev->dev->name, ( ( netdev->state & NETDEV_OPEN ) ? "open" : "closed" ), ( netdev_link_ok ( netdev ) ? "up" : "down" ), - netdev->stats.tx_ok, netdev->stats.tx_err, - netdev->stats.rx_ok, netdev->stats.rx_err ); + netdev->tx_stats.good, netdev->tx_stats.bad, + netdev->rx_stats.good, netdev->rx_stats.bad ); + ifstat_errors ( &netdev->tx_stats, "TXE" ); + ifstat_errors ( &netdev->rx_stats, "RXE" ); } /** @@ -80,12 +103,19 @@ void ifstat ( struct net_device *netdev ) { * @v max_wait_ms Maximum time to wait, in ms */ int iflinkwait ( struct net_device *netdev, unsigned int max_wait_ms ) { + int key; + while ( 1 ) { if ( netdev_link_ok ( netdev ) ) return 0; if ( max_wait_ms-- == 0 ) return -ETIMEDOUT; step(); + if ( iskey() ) { + key = getchar(); + if ( key == CTRL_C ) + return -ECANCELED; + } mdelay ( 1 ); } } diff --git a/gpxe/src/usr/imgmgmt.c b/gpxe/src/usr/imgmgmt.c index be153f87..bd53d824 100644 --- a/gpxe/src/usr/imgmgmt.c +++ b/gpxe/src/usr/imgmgmt.c @@ -43,7 +43,10 @@ */ int imgfetch ( struct image *image, const char *uri_string, int ( * image_register ) ( struct image *image ) ) { + char uri_string_redacted[ strlen ( uri_string ) + 3 /* "***" */ + + 1 /* NUL */ ]; struct uri *uri; + const char *password; int rc; if ( ! ( uri = parse_uri ( uri_string ) ) ) @@ -51,9 +54,17 @@ int imgfetch ( struct image *image, const char *uri_string, image_set_uri ( image, uri ); + /* 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->password = password; + if ( ( rc = create_downloader ( &monojob, image, image_register, LOCATION_URI, uri ) ) == 0 ) - rc = monojob_wait ( uri_string ); + rc = monojob_wait ( uri_string_redacted ); uri_put ( uri ); return rc; diff --git a/gpxe/src/usr/pxemenu.c b/gpxe/src/usr/pxemenu.c new file mode 100644 index 00000000..793cb624 --- /dev/null +++ b/gpxe/src/usr/pxemenu.c @@ -0,0 +1,381 @@ +/* + * Copyright (C) 2009 Michael Brown <mbrown@fensystems.co.uk>. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of the + * License, or any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +#include <stdint.h> +#include <stdlib.h> +#include <stdio.h> +#include <string.h> +#include <errno.h> +#include <ctype.h> +#include <byteswap.h> +#include <curses.h> +#include <console.h> +#include <gpxe/dhcp.h> +#include <gpxe/keys.h> +#include <gpxe/timer.h> +#include <gpxe/process.h> +#include <usr/dhcpmgmt.h> +#include <usr/autoboot.h> + +/** @file + * + * PXE Boot Menus + * + */ + +/* Colour pairs */ +#define CPAIR_NORMAL 1 +#define CPAIR_SELECT 2 + +/** A PXE boot menu item */ +struct pxe_menu_item { + /** Boot Server type */ + unsigned int type; + /** Description */ + char *desc; +}; + +/** + * A PXE boot menu + * + * This structure encapsulates the menu information provided via DHCP + * options. + */ +struct pxe_menu { + /** Prompt string (optional) */ + const char *prompt; + /** Timeout (in seconds) + * + * Negative indicates no timeout (i.e. wait indefinitely) + */ + int timeout; + /** Number of menu items */ + unsigned int num_items; + /** Selected menu item */ + unsigned int selection; + /** Menu items */ + struct pxe_menu_item items[0]; +}; + +/** + * Parse and allocate PXE boot menu + * + * @v menu PXE boot menu to fill in + * @ret rc Return status code + * + * It is the callers responsibility to eventually free the allocated + * boot menu. + */ +static int pxe_menu_parse ( struct pxe_menu **menu ) { + struct setting pxe_boot_menu_prompt_setting = + { .tag = DHCP_PXE_BOOT_MENU_PROMPT }; + struct setting pxe_boot_menu_setting = + { .tag = DHCP_PXE_BOOT_MENU }; + uint8_t raw_menu[256]; + int raw_prompt_len; + int raw_menu_len; + struct dhcp_pxe_boot_menu *raw_menu_item; + struct dhcp_pxe_boot_menu_prompt *raw_menu_prompt; + void *raw_menu_end; + unsigned int num_menu_items; + unsigned int i; + int rc; + + /* 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 ) { + rc = raw_menu_len; + DBG ( "Could not retrieve raw PXE boot menu: %s\n", + strerror ( rc ) ); + return rc; + } + if ( raw_menu_len >= ( int ) sizeof ( raw_menu ) ) { + DBG ( "Raw PXE boot menu too large for buffer\n" ); + return -ENOSPC; + } + raw_menu_end = ( raw_menu + raw_menu_len ); + + /* Fetch raw prompt length */ + raw_prompt_len = fetch_setting_len ( NULL, + &pxe_boot_menu_prompt_setting ); + if ( raw_prompt_len < 0 ) + raw_prompt_len = 0; + + /* Count menu items */ + num_menu_items = 0; + raw_menu_item = ( ( void * ) raw_menu ); + while ( 1 ) { + if ( ( ( ( void * ) raw_menu_item ) + + sizeof ( *raw_menu_item ) ) > raw_menu_end ) + break; + if ( ( ( ( void * ) raw_menu_item ) + + sizeof ( *raw_menu_item ) + + raw_menu_item->desc_len ) > raw_menu_end ) + break; + num_menu_items++; + raw_menu_item = ( ( ( void * ) raw_menu_item ) + + sizeof ( *raw_menu_item ) + + raw_menu_item->desc_len ); + } + + /* Allocate space for parsed menu */ + *menu = zalloc ( sizeof ( **menu ) + + ( num_menu_items * sizeof ( (*menu)->items[0] ) ) + + raw_menu_len + 1 /* NUL */ + + raw_prompt_len + 1 /* NUL */ ); + if ( ! *menu ) { + DBG ( "Could not allocate PXE boot menu\n" ); + return -ENOMEM; + } + + /* Fill in parsed menu */ + (*menu)->num_items = num_menu_items; + raw_menu_item = ( ( ( void * ) (*menu) ) + sizeof ( **menu ) + + ( num_menu_items * sizeof ( (*menu)->items[0] ) ) ); + memcpy ( raw_menu_item, raw_menu, raw_menu_len ); + for ( i = 0 ; i < num_menu_items ; i++ ) { + (*menu)->items[i].type = ntohs ( raw_menu_item->type ); + (*menu)->items[i].desc = raw_menu_item->desc; + /* Set type to 0; this ensures that the description + * for the previous menu item is NUL-terminated. + * (Final item is NUL-terminated anyway.) + */ + raw_menu_item->type = 0; + raw_menu_item = ( ( ( void * ) raw_menu_item ) + + sizeof ( *raw_menu_item ) + + raw_menu_item->desc_len ); + } + 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 ); + (*menu)->timeout = + ( ( raw_menu_prompt->timeout == 0xff ) ? + -1 : raw_menu_prompt->timeout ); + (*menu)->prompt = raw_menu_prompt->prompt; + } else { + (*menu)->timeout = -1; + } + + return 0; +} + +/** + * Draw PXE boot menu item + * + * @v menu PXE boot menu + * @v index Index of item to draw + * @v selected Item is selected + */ +static void pxe_menu_draw_item ( struct pxe_menu *menu, + unsigned int index, int selected ) { + char buf[COLS+1]; + size_t len; + unsigned int row; + + /* Prepare space-padded row content */ + len = snprintf ( buf, sizeof ( buf ), " %c. %s", + ( 'A' + index ), menu->items[index].desc ); + while ( len < ( sizeof ( buf ) - 1 ) ) + buf[len++] = ' '; + buf[ sizeof ( buf ) - 1 ] = '\0'; + + /* Draw row */ + row = ( LINES - menu->num_items + index ); + color_set ( ( selected ? CPAIR_SELECT : CPAIR_NORMAL ), NULL ); + mvprintw ( row, 0, "%s", buf ); + move ( row, 1 ); +} + +/** + * Make selection from PXE boot menu + * + * @v menu PXE boot menu + * @ret rc Return status code + */ +static int pxe_menu_select ( struct pxe_menu *menu ) { + int key; + unsigned int key_selection; + unsigned int i; + int rc = 0; + + /* 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 ); + + /* Draw initial menu */ + for ( i = 0 ; i < menu->num_items ; i++ ) + printf ( "\n" ); + for ( i = 0 ; i < menu->num_items ; i++ ) + pxe_menu_draw_item ( menu, ( menu->num_items - i - 1 ), 0 ); + + while ( 1 ) { + + /* Highlight currently selected item */ + pxe_menu_draw_item ( menu, menu->selection, 1 ); + + /* Wait for keyboard input */ + while ( ! iskey() ) + step(); + key = getkey(); + + /* Unhighlight currently selected item */ + pxe_menu_draw_item ( menu, menu->selection, 0 ); + + /* Act upon key */ + if ( ( key == CR ) || ( key == LF ) ) { + pxe_menu_draw_item ( menu, menu->selection, 1 ); + break; + } else if ( ( key == CTRL_C ) || ( key == ESC ) ) { + rc = -ECANCELED; + break; + } else if ( key == KEY_UP ) { + if ( menu->selection > 0 ) + menu->selection--; + } else if ( key == KEY_DOWN ) { + if ( menu->selection < ( menu->num_items - 1 ) ) + menu->selection++; + } else if ( ( key < KEY_MIN ) && + ( ( key_selection = ( toupper ( key ) - 'A' ) ) + < menu->num_items ) ) { + menu->selection = key_selection; + pxe_menu_draw_item ( menu, menu->selection, 1 ); + break; + } + } + + /* Shut down UI */ + endwin(); + + return rc; +} + +/** + * Prompt for (and make selection from) PXE boot menu + * + * @v menu PXE boot menu + * @ret rc Return status code + */ +static int pxe_menu_prompt_and_select ( struct pxe_menu *menu ) { + unsigned long start = currticks(); + unsigned long now; + unsigned long elapsed; + size_t len = 0; + int key; + int rc = 0; + + /* Display menu immediately, if specified to do so */ + if ( menu->timeout < 0 ) { + if ( menu->prompt ) + printf ( "%s\n", menu->prompt ); + return pxe_menu_select ( menu ); + } + + /* Display prompt, if specified */ + if ( menu->prompt ) + printf ( "%s", menu->prompt ); + + /* Wait for timeout, if specified */ + while ( menu->timeout > 0 ) { + if ( ! len ) + len = printf ( " (%d)", menu->timeout ); + if ( iskey() ) { + key = getkey(); + if ( key == KEY_F8 ) { + /* Display menu */ + printf ( "\n" ); + return pxe_menu_select ( menu ); + } else if ( ( key == CTRL_C ) || ( key == ESC ) ) { + /* Abort */ + rc = -ECANCELED; + break; + } else { + /* Stop waiting */ + break; + } + } + now = currticks(); + elapsed = ( now - start ); + if ( elapsed >= TICKS_PER_SEC ) { + menu->timeout -= 1; + do { + printf ( "\b \b" ); + } while ( --len ); + start = now; + } + } + + /* Return with default option selected */ + printf ( "\n" ); + return rc; +} + +/** + * Boot using PXE boot menu + * + * @ret rc Return status code + * + * Note that a success return status indicates that a PXE boot menu + * item has been selected, and that the DHCP session should perform a + * boot server request/ack. + */ +int pxe_menu_boot ( struct net_device *netdev ) { + struct pxe_menu *menu; + unsigned int pxe_type; + struct settings *pxebs_settings; + struct in_addr next_server; + char filename[256]; + int rc; + + /* Parse and allocate boot menu */ + if ( ( rc = pxe_menu_parse ( &menu ) ) != 0 ) + return rc; + + /* Make selection from boot menu */ + if ( ( rc = pxe_menu_prompt_and_select ( menu ) ) != 0 ) { + free ( menu ); + return rc; + } + pxe_type = menu->items[menu->selection].type; + + /* Free boot menu */ + free ( menu ); + + /* Return immediately if local boot selected */ + if ( ! pxe_type ) + return 0; + + /* Attempt PXE Boot Server Discovery */ + if ( ( rc = pxebs ( netdev, pxe_type ) ) != 0 ) + return rc; + + /* Attempt boot */ + pxebs_settings = find_settings ( PXEBS_SETTINGS_NAME ); + assert ( pxebs_settings ); + fetch_ipv4_setting ( pxebs_settings, &next_server_setting, + &next_server ); + fetch_string_setting ( pxebs_settings, &filename_setting, + filename, sizeof ( filename ) ); + return boot_next_server_and_filename ( next_server, filename ); +} diff --git a/gpxe/src/util/.gitignore b/gpxe/src/util/.gitignore index 98adc2df..c2567012 100644 --- a/gpxe/src/util/.gitignore +++ b/gpxe/src/util/.gitignore @@ -2,3 +2,6 @@ nrv2b zbin hijack prototester +elf2efi32 +elf2efi64 +efirom diff --git a/gpxe/src/util/disrom.pl b/gpxe/src/util/disrom.pl index 80ac4af8..1fb4cc3c 100755 --- a/gpxe/src/util/disrom.pl +++ b/gpxe/src/util/disrom.pl @@ -36,41 +36,46 @@ die "ROM image truncated (is $filelength, should be $romlength)\n" if $filelength < $romlength; printf "ROM header:\n\n"; -printf " Length:\t0x%02x (%d)\n", $rom->{length}, ( $rom->{length} * 512 ); -printf " Checksum:\t0x%02x (0x%02x)\n", $rom->{checksum}, $rom->checksum; -printf " Init:\t\t0x%04x\n", $rom->{init}; -printf " UNDI header:\t0x%04x\n", $rom->{undi_header}; -printf " PCI header:\t0x%04x\n", $rom->{pci_header}; -printf " PnP header:\t0x%04x\n", $rom->{pnp_header}; +printf " %-16s 0x%02x (%d)\n", "Length:", $rom->{length}, ( $rom->{length} * 512 ); +printf " %-16s 0x%02x (%s0x%02x)\n", "Checksum:", $rom->{checksum}, + ( ( $rom->checksum == 0 ) ? "" : "INCORRECT: " ), $rom->checksum; +printf " %-16s 0x%04x\n", "Init:", $rom->{init}; +printf " %-16s 0x%04x\n", "UNDI header:", $rom->{undi_header}; +printf " %-16s 0x%04x\n", "PCI header:", $rom->{pci_header}; +printf " %-16s 0x%04x\n", "PnP header:", $rom->{pnp_header}; printf "\n"; my $pci = $rom->pci_header(); if ( $pci ) { printf "PCI header:\n\n"; - printf " Signature:\t%s\n", $pci->{signature}; - printf " Vendor id:\t0x%04x\n", $pci->{vendor_id}; - printf " Device id:\t0x%04x\n", $pci->{device_id}; - printf " Device class:\t0x%02x%02x%02x\n", + printf " %-16s %s\n", "Signature:", $pci->{signature}; + printf " %-16s 0x%04x\n", "Vendor ID:", $pci->{vendor_id}; + printf " %-16s 0x%04x\n", "Device ID:", $pci->{device_id}; + printf " %-16s 0x%02x%02x%02x\n", "Device class:", $pci->{base_class}, $pci->{sub_class}, $pci->{prog_intf}; - printf " Image length:\t0x%04x (%d)\n", + printf " %-16s 0x%04x (%d)\n", "Image length:", $pci->{image_length}, ( $pci->{image_length} * 512 ); - printf " Runtime length:\t0x%04x (%d)\n", + printf " %-16s 0x%04x (%d)\n", "Runtime length:", $pci->{runtime_length}, ( $pci->{runtime_length} * 512 ); - printf " Config header:\t0x%04x\n", $pci->{conf_header}; - printf " CLP entry:\t0x%04x\n", $pci->{clp_entry}; + if ( exists $pci->{conf_header} ) { + printf " %-16s 0x%04x\n", "Config header:", $pci->{conf_header}; + printf " %-16s 0x%04x\n", "CLP entry:", $pci->{clp_entry}; + } printf "\n"; } my $pnp = $rom->pnp_header(); if ( $pnp ) { printf "PnP header:\n\n"; - printf " Signature:\t%s\n", $pnp->{signature}; - printf " Checksum:\t0x%02x (0x%02x)\n", $pnp->{checksum}, $pnp->checksum; - printf " Manufacturer:\t0x%04x \"%s\"\n", + printf " %-16s %s\n", "Signature:", $pnp->{signature}; + printf " %-16s 0x%02x (%s0x%02x)\n", "Checksum:", $pnp->{checksum}, + ( ( $pnp->checksum == 0 ) ? "" : "INCORRECT: " ), $pnp->checksum; + printf " %-16s 0x%04x \"%s\"\n", "Manufacturer:", $pnp->{manufacturer}, $pnp->manufacturer; - printf " Product:\t0x%04x \"%s\"\n", $pnp->{product}, $pnp->product; - printf " BCV:\t\t0x%04x\n", $pnp->{bcv}; - printf " BDV:\t\t0x%04x\n", $pnp->{bdv}; - printf " BEV:\t\t0x%04x\n", $pnp->{bev}; + printf " %-16s 0x%04x \"%s\"\n", "Product:", + $pnp->{product}, $pnp->product; + printf " %-16s 0x%04x\n", "BCV:", $pnp->{bcv}; + printf " %-16s 0x%04x\n", "BDV:", $pnp->{bdv}; + printf " %-16s 0x%04x\n", "BEV:", $pnp->{bev}; printf "\n"; } diff --git a/gpxe/src/util/efirom.c b/gpxe/src/util/efirom.c new file mode 100644 index 00000000..9369db87 --- /dev/null +++ b/gpxe/src/util/efirom.c @@ -0,0 +1,280 @@ +/* + * Copyright (C) 2009 Michael Brown <mbrown@fensystems.co.uk>. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of the + * License, or any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +#include <stdint.h> +#include <stddef.h> +#include <stdlib.h> +#include <stdio.h> +#include <string.h> +#include <sys/stat.h> +#include <unistd.h> +#include <errno.h> +#include <assert.h> +#include <getopt.h> +#include <gpxe/efi/efi.h> +#include <gpxe/efi/IndustryStandard/PeImage.h> +#include <gpxe/efi/IndustryStandard/Pci22.h> + +#define eprintf(...) fprintf ( stderr, __VA_ARGS__ ) + +/** Command-line options */ +struct options { + uint16_t vendor; + uint16_t device; +}; + +/** + * Allocate memory + * + * @v len Length of memory to allocate + * @ret ptr Pointer to allocated memory + */ +static void * xmalloc ( size_t len ) { + void *ptr; + + ptr = malloc ( len ); + if ( ! ptr ) { + eprintf ( "Could not allocate %zd bytes\n", len ); + exit ( 1 ); + } + + return ptr; +} + +/** + * Get file size + * + * @v file File + * @v len File size + */ +static size_t file_size ( FILE *file ) { + ssize_t len; + + return len; +} + +/** + * Read information from PE headers + * + * @v pe PE file + * @ret machine Machine type + * @ret subsystem EFI subsystem + */ +static void read_pe_info ( void *pe, uint16_t *machine, + uint16_t *subsystem ) { + EFI_IMAGE_DOS_HEADER *dos; + union { + EFI_IMAGE_NT_HEADERS32 nt32; + EFI_IMAGE_NT_HEADERS64 nt64; + } *nt; + + /* Locate NT header */ + dos = pe; + nt = ( pe + dos->e_lfanew ); + + /* Parse out PE information */ + *machine = nt->nt32.FileHeader.Machine; + switch ( *machine ) { + case EFI_IMAGE_MACHINE_IA32: + *subsystem = nt->nt32.OptionalHeader.Subsystem; + break; + case EFI_IMAGE_MACHINE_X64: + *subsystem = nt->nt64.OptionalHeader.Subsystem; + break; + default: + eprintf ( "Unrecognised machine type %04x\n", *machine ); + exit ( 1 ); + } +} + +/** + * Convert EFI image to ROM image + * + * @v pe EFI file + * @v rom ROM file + */ +static void make_efi_rom ( FILE *pe, FILE *rom, struct options *opts ) { + struct { + EFI_PCI_EXPANSION_ROM_HEADER rom; + PCI_DATA_STRUCTURE pci __attribute__ (( aligned ( 4 ) )); + uint8_t checksum; + } *headers; + struct stat pe_stat; + size_t pe_size; + size_t rom_size; + void *buf; + void *payload; + unsigned int i; + uint8_t checksum; + + /* Determine PE file size */ + if ( fstat ( fileno ( pe ), &pe_stat ) != 0 ) { + eprintf ( "Could not stat PE file: %s\n", + strerror ( errno ) ); + exit ( 1 ); + } + pe_size = pe_stat.st_size; + + /* Determine ROM file size */ + rom_size = ( ( pe_size + sizeof ( *headers ) + 511 ) & ~511 ); + + /* Allocate ROM buffer and read in PE file */ + buf = xmalloc ( rom_size ); + memset ( buf, 0, rom_size ); + headers = buf; + payload = ( buf + sizeof ( *headers ) ); + if ( fread ( payload, pe_size, 1, pe ) != 1 ) { + eprintf ( "Could not read PE file: %s\n", + strerror ( errno ) ); + exit ( 1 ); + } + + /* Construct ROM header */ + headers->rom.Signature = PCI_EXPANSION_ROM_HEADER_SIGNATURE; + headers->rom.InitializationSize = ( rom_size / 512 ); + headers->rom.EfiSignature = EFI_PCI_EXPANSION_ROM_HEADER_EFISIGNATURE; + read_pe_info ( payload, &headers->rom.EfiMachineType, + &headers->rom.EfiSubsystem ); + headers->rom.EfiImageHeaderOffset = sizeof ( *headers ); + headers->rom.PcirOffset = + offsetof ( typeof ( *headers ), pci ); + headers->pci.Signature = PCI_DATA_STRUCTURE_SIGNATURE; + headers->pci.VendorId = opts->vendor; + headers->pci.DeviceId = opts->device; + headers->pci.Length = sizeof ( headers->pci ); + headers->pci.ClassCode[0] = PCI_CLASS_NETWORK; + headers->pci.ImageLength = ( rom_size / 512 ); + headers->pci.CodeType = 0x03; /* No constant in EFI headers? */ + headers->pci.Indicator = 0x80; /* No constant in EFI headers? */ + + /* Fix image checksum */ + for ( i = 0, checksum = 0 ; i < rom_size ; i++ ) + checksum += *( ( uint8_t * ) buf + i ); + headers->checksum -= checksum; + + /* Write out ROM */ + if ( fwrite ( buf, rom_size, 1, rom ) != 1 ) { + eprintf ( "Could not write ROM file: %s\n", + strerror ( errno ) ); + exit ( 1 ); + } +} + +/** + * Print help + * + * @v program_name Program name + */ +static void print_help ( const char *program_name ) { + eprintf ( "Syntax: %s [--vendor=VVVV] [--device=DDDD] " + "infile outfile\n", program_name ); +} + +/** + * Parse command-line options + * + * @v argc Argument count + * @v argv Argument list + * @v opts Options structure to populate + */ +static int parse_options ( const int argc, char **argv, + struct options *opts ) { + char *end; + int c; + + while (1) { + int option_index = 0; + static struct option long_options[] = { + { "vendor", required_argument, NULL, 'v' }, + { "device", required_argument, NULL, 'd' }, + { "help", 0, NULL, 'h' }, + { 0, 0, 0, 0 } + }; + + if ( ( c = getopt_long ( argc, argv, "v:d:h", + long_options, + &option_index ) ) == -1 ) { + break; + } + + switch ( c ) { + case 'v': + opts->vendor = strtoul ( optarg, &end, 16 ); + if ( *end ) { + eprintf ( "Invalid vendor \"%s\"\n", optarg ); + exit ( 2 ); + } + break; + case 'd': + opts->device = strtoul ( optarg, &end, 16 ); + if ( *end ) { + eprintf ( "Invalid device \"%s\"\n", optarg ); + exit ( 2 ); + } + break; + case 'h': + print_help ( argv[0] ); + exit ( 0 ); + case '?': + default: + exit ( 2 ); + } + } + return optind; +} + +int main ( int argc, char **argv ) { + struct options opts = { + }; + unsigned int infile_index; + const char *infile_name; + const char *outfile_name; + FILE *infile; + FILE *outfile; + + /* Parse command-line arguments */ + infile_index = parse_options ( argc, argv, &opts ); + if ( argc != ( infile_index + 2 ) ) { + print_help ( argv[0] ); + exit ( 2 ); + } + infile_name = argv[infile_index]; + outfile_name = argv[infile_index + 1]; + + /* Open input and output files */ + infile = fopen ( infile_name, "r" ); + if ( ! infile ) { + eprintf ( "Could not open %s for reading: %s\n", + infile_name, strerror ( errno ) ); + exit ( 1 ); + } + outfile = fopen ( outfile_name, "w" ); + if ( ! outfile ) { + eprintf ( "Could not open %s for writing: %s\n", + outfile_name, strerror ( errno ) ); + exit ( 1 ); + } + + /* Convert file */ + make_efi_rom ( infile, outfile, &opts ); + + fclose ( outfile ); + fclose ( infile ); + + return 0; +} diff --git a/gpxe/src/util/elf2efi.c b/gpxe/src/util/elf2efi.c new file mode 100644 index 00000000..886777d9 --- /dev/null +++ b/gpxe/src/util/elf2efi.c @@ -0,0 +1,803 @@ +/* + * Copyright (C) 2009 Michael Brown <mbrown@fensystems.co.uk>. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of the + * License, or any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +#define _GNU_SOURCE +#include <stdint.h> +#include <stddef.h> +#include <stdlib.h> +#include <stdio.h> +#include <string.h> +#include <unistd.h> +#include <errno.h> +#include <assert.h> +#include <getopt.h> +#include <bfd.h> +#include <gpxe/efi/efi.h> +#include <gpxe/efi/IndustryStandard/PeImage.h> + +#define eprintf(...) fprintf ( stderr, __VA_ARGS__ ) + +#define EFI_FILE_ALIGN 0x20 + +struct pe_section { + struct pe_section *next; + EFI_IMAGE_SECTION_HEADER hdr; + uint8_t contents[0]; +}; + +struct pe_relocs { + struct pe_relocs *next; + unsigned long start_rva; + unsigned int used_relocs; + unsigned int total_relocs; + uint16_t *relocs; +}; + +struct pe_header { + EFI_IMAGE_DOS_HEADER dos; + uint8_t padding[128]; +#if defined(MDE_CPU_IA32) + EFI_IMAGE_NT_HEADERS32 nt; +#elif defined(MDE_CPU_X64) + EFI_IMAGE_NT_HEADERS64 nt; +#endif +}; + +static struct pe_header efi_pe_header = { + .dos = { + .e_magic = EFI_IMAGE_DOS_SIGNATURE, + .e_lfanew = offsetof ( typeof ( efi_pe_header ), nt ), + }, + .nt = { + .Signature = EFI_IMAGE_NT_SIGNATURE, + .FileHeader = { +#if defined(MDE_CPU_IA32) + .Machine = EFI_IMAGE_MACHINE_IA32, +#elif defined(MDE_CPU_X64) + .Machine = EFI_IMAGE_MACHINE_X64, +#endif + .TimeDateStamp = 0x10d1a884, + .SizeOfOptionalHeader = + sizeof ( efi_pe_header.nt.OptionalHeader ), + .Characteristics = ( EFI_IMAGE_FILE_DLL | +#if defined(MDE_CPU_IA32) + EFI_IMAGE_FILE_32BIT_MACHINE | +#endif + EFI_IMAGE_FILE_EXECUTABLE_IMAGE ), + }, + .OptionalHeader = { +#if defined(MDE_CPU_IA32) + .Magic = EFI_IMAGE_NT_OPTIONAL_HDR32_MAGIC, +#elif defined(MDE_CPU_X64) + .Magic = EFI_IMAGE_NT_OPTIONAL_HDR64_MAGIC, +#endif + .SectionAlignment = EFI_FILE_ALIGN, + .FileAlignment = EFI_FILE_ALIGN, + .SizeOfImage = sizeof ( efi_pe_header ), + .SizeOfHeaders = sizeof ( efi_pe_header ), + .NumberOfRvaAndSizes = + EFI_IMAGE_NUMBER_OF_DIRECTORY_ENTRIES, + }, + }, +}; + +/** Command-line options */ +struct options { + unsigned int subsystem; +}; + +/** + * Allocate memory + * + * @v len Length of memory to allocate + * @ret ptr Pointer to allocated memory + */ +static void * xmalloc ( size_t len ) { + void *ptr; + + ptr = malloc ( len ); + if ( ! ptr ) { + eprintf ( "Could not allocate %zd bytes\n", len ); + exit ( 1 ); + } + + return ptr; +} + +/** + * Align section within PE file + * + * @v offset Unaligned offset + * @ret aligned_offset Aligned offset + */ +static unsigned long efi_file_align ( unsigned long offset ) { + return ( ( offset + EFI_FILE_ALIGN - 1 ) & ~( EFI_FILE_ALIGN - 1 ) ); +} + +/** + * Generate entry in PE relocation table + * + * @v pe_reltab PE relocation table + * @v rva RVA + * @v size Size of relocation entry + */ +static void generate_pe_reloc ( struct pe_relocs **pe_reltab, + unsigned long rva, size_t size ) { + unsigned long start_rva; + uint16_t reloc; + struct pe_relocs *pe_rel; + uint16_t *relocs; + + /* Construct */ + start_rva = ( rva & ~0xfff ); + reloc = ( rva & 0xfff ); + switch ( size ) { + case 8: + reloc |= 0xa000; + break; + case 4: + reloc |= 0x3000; + break; + case 2: + reloc |= 0x2000; + break; + default: + eprintf ( "Unsupported relocation size %zd\n", size ); + exit ( 1 ); + } + + /* Locate or create PE relocation table */ + for ( pe_rel = *pe_reltab ; pe_rel ; pe_rel = pe_rel->next ) { + if ( pe_rel->start_rva == start_rva ) + break; + } + if ( ! pe_rel ) { + pe_rel = xmalloc ( sizeof ( *pe_rel ) ); + memset ( pe_rel, 0, sizeof ( *pe_rel ) ); + pe_rel->next = *pe_reltab; + *pe_reltab = pe_rel; + pe_rel->start_rva = start_rva; + } + + /* Expand relocation list if necessary */ + if ( pe_rel->used_relocs < pe_rel->total_relocs ) { + relocs = pe_rel->relocs; + } else { + pe_rel->total_relocs = ( pe_rel->total_relocs ? + ( pe_rel->total_relocs * 2 ) : 256 ); + relocs = xmalloc ( pe_rel->total_relocs * + sizeof ( pe_rel->relocs[0] ) ); + memset ( relocs, 0, + pe_rel->total_relocs * sizeof ( pe_rel->relocs[0] ) ); + memcpy ( relocs, pe_rel->relocs, + pe_rel->used_relocs * sizeof ( pe_rel->relocs[0] ) ); + free ( pe_rel->relocs ); + pe_rel->relocs = relocs; + } + + /* Store relocation */ + pe_rel->relocs[ pe_rel->used_relocs++ ] = reloc; +} + +/** + * Calculate size of binary PE relocation table + * + * @v pe_reltab PE relocation table + * @v buffer Buffer to contain binary table, or NULL + * @ret size Size of binary table + */ +static size_t output_pe_reltab ( struct pe_relocs *pe_reltab, + void *buffer ) { + struct pe_relocs *pe_rel; + unsigned int num_relocs; + size_t size; + size_t total_size = 0; + + for ( pe_rel = pe_reltab ; pe_rel ; pe_rel = pe_rel->next ) { + num_relocs = ( ( pe_rel->used_relocs + 1 ) & ~1 ); + size = ( sizeof ( uint32_t ) /* VirtualAddress */ + + sizeof ( uint32_t ) /* SizeOfBlock */ + + ( num_relocs * sizeof ( uint16_t ) ) ); + if ( buffer ) { + *( (uint32_t *) ( buffer + total_size + 0 ) ) + = pe_rel->start_rva; + *( (uint32_t *) ( buffer + total_size + 4 ) ) = size; + memcpy ( ( buffer + total_size + 8 ), pe_rel->relocs, + ( num_relocs * sizeof ( uint16_t ) ) ); + } + total_size += size; + } + + return total_size; +} + +/** + * Open input BFD file + * + * @v filename File name + * @ret ibfd BFD file + */ +static bfd * open_input_bfd ( const char *filename ) { + bfd *bfd; + + /* Open the file */ + bfd = bfd_openr ( filename, NULL ); + if ( ! bfd ) { + eprintf ( "Cannot open %s: ", filename ); + bfd_perror ( NULL ); + exit ( 1 ); + } + + /* The call to bfd_check_format() must be present, otherwise + * we get a segfault from later BFD calls. + */ + if ( bfd_check_format ( bfd, bfd_object ) < 0 ) { + eprintf ( "%s is not an object file\n", filename ); + exit ( 1 ); + } + + return bfd; +} + +/** + * Read symbol table + * + * @v bfd BFD file + */ +static asymbol ** read_symtab ( bfd *bfd ) { + long symtab_size; + asymbol **symtab; + long symcount; + + /* Get symbol table size */ + symtab_size = bfd_get_symtab_upper_bound ( bfd ); + if ( symtab_size < 0 ) { + bfd_perror ( "Could not get symbol table upper bound" ); + exit ( 1 ); + } + + /* Allocate and read symbol table */ + symtab = xmalloc ( symtab_size ); + symcount = bfd_canonicalize_symtab ( bfd, symtab ); + if ( symcount < 0 ) { + bfd_perror ( "Cannot read symbol table" ); + exit ( 1 ); + } + + return symtab; +} + +/** + * Read relocation table + * + * @v bfd BFD file + * @v symtab Symbol table + * @v section Section + * @v symtab Symbol table + * @ret reltab Relocation table + */ +static arelent ** read_reltab ( bfd *bfd, asymbol **symtab, + asection *section ) { + long reltab_size; + arelent **reltab; + long numrels; + + /* Get relocation table size */ + reltab_size = bfd_get_reloc_upper_bound ( bfd, section ); + if ( reltab_size < 0 ) { + bfd_perror ( "Could not get relocation table upper bound" ); + exit ( 1 ); + } + + /* Allocate and read relocation table */ + reltab = xmalloc ( reltab_size ); + numrels = bfd_canonicalize_reloc ( bfd, section, reltab, symtab ); + if ( numrels < 0 ) { + bfd_perror ( "Cannot read relocation table" ); + exit ( 1 ); + } + + return reltab; +} + +/** + * Process section + * + * @v bfd BFD file + * @v pe_header PE file header + * @v section Section + * @ret new New PE section + */ +static struct pe_section * process_section ( bfd *bfd, + struct pe_header *pe_header, + asection *section ) { + struct pe_section *new; + size_t section_memsz; + size_t section_filesz; + unsigned long flags = bfd_get_section_flags ( bfd, section ); + unsigned long code_start; + unsigned long code_end; + unsigned long data_start; + unsigned long data_mid; + unsigned long data_end; + unsigned long start; + unsigned long end; + unsigned long *applicable_start; + unsigned long *applicable_end; + + /* Extract current RVA limits from file header */ + code_start = pe_header->nt.OptionalHeader.BaseOfCode; + code_end = ( code_start + pe_header->nt.OptionalHeader.SizeOfCode ); +#if defined(MDE_CPU_IA32) + data_start = pe_header->nt.OptionalHeader.BaseOfData; +#elif defined(MDE_CPU_X64) + data_start = code_end; +#endif + data_mid = ( data_start + + pe_header->nt.OptionalHeader.SizeOfInitializedData ); + data_end = ( data_mid + + pe_header->nt.OptionalHeader.SizeOfUninitializedData ); + + /* Allocate PE section */ + section_memsz = bfd_section_size ( bfd, section ); + section_filesz = ( ( flags & SEC_LOAD ) ? + efi_file_align ( section_memsz ) : 0 ); + new = xmalloc ( sizeof ( *new ) + section_filesz ); + memset ( new, 0, sizeof ( *new ) + section_filesz ); + + /* Fill in section header details */ + strncpy ( ( char * ) new->hdr.Name, section->name, + sizeof ( new->hdr.Name ) ); + new->hdr.Misc.VirtualSize = section_memsz; + new->hdr.VirtualAddress = bfd_get_section_vma ( bfd, section ); + new->hdr.SizeOfRawData = section_filesz; + + /* Fill in section characteristics and update RVA limits */ + if ( flags & SEC_CODE ) { + /* .text-type section */ + new->hdr.Characteristics = + ( EFI_IMAGE_SCN_CNT_CODE | + EFI_IMAGE_SCN_MEM_NOT_PAGED | + EFI_IMAGE_SCN_MEM_EXECUTE | + EFI_IMAGE_SCN_MEM_READ ); + applicable_start = &code_start; + applicable_end = &code_end; + } else if ( flags & SEC_DATA ) { + /* .data-type section */ + new->hdr.Characteristics = + ( EFI_IMAGE_SCN_CNT_INITIALIZED_DATA | + EFI_IMAGE_SCN_MEM_NOT_PAGED | + EFI_IMAGE_SCN_MEM_READ | + EFI_IMAGE_SCN_MEM_WRITE ); + applicable_start = &data_start; + applicable_end = &data_mid; + } else if ( flags & SEC_READONLY ) { + /* .rodata-type section */ + new->hdr.Characteristics = + ( EFI_IMAGE_SCN_CNT_INITIALIZED_DATA | + EFI_IMAGE_SCN_MEM_NOT_PAGED | + EFI_IMAGE_SCN_MEM_READ ); + applicable_start = &data_start; + applicable_end = &data_mid; + } else if ( ! ( flags & SEC_LOAD ) ) { + /* .bss-type section */ + new->hdr.Characteristics = + ( EFI_IMAGE_SCN_CNT_UNINITIALIZED_DATA | + EFI_IMAGE_SCN_MEM_NOT_PAGED | + EFI_IMAGE_SCN_MEM_READ | + EFI_IMAGE_SCN_MEM_WRITE ); + applicable_start = &data_mid; + applicable_end = &data_end; + } + + /* Copy in section contents */ + if ( flags & SEC_LOAD ) { + if ( ! bfd_get_section_contents ( bfd, section, new->contents, + 0, section_memsz ) ) { + eprintf ( "Cannot read section %s: ", section->name ); + bfd_perror ( NULL ); + exit ( 1 ); + } + } + + /* Update RVA limits */ + start = new->hdr.VirtualAddress; + end = ( start + new->hdr.Misc.VirtualSize ); + if ( ( ! *applicable_start ) || ( *applicable_start >= start ) ) + *applicable_start = start; + if ( *applicable_end < end ) + *applicable_end = end; + if ( data_start < code_end ) + data_start = code_end; + if ( data_mid < data_start ) + data_mid = data_start; + if ( data_end < data_mid ) + data_end = data_mid; + + /* Write RVA limits back to file header */ + pe_header->nt.OptionalHeader.BaseOfCode = code_start; + pe_header->nt.OptionalHeader.SizeOfCode = ( code_end - code_start ); +#if defined(MDE_CPU_IA32) + pe_header->nt.OptionalHeader.BaseOfData = data_start; +#endif + pe_header->nt.OptionalHeader.SizeOfInitializedData = + ( data_mid - data_start ); + pe_header->nt.OptionalHeader.SizeOfUninitializedData = + ( data_end - data_mid ); + + /* Update remaining file header fields */ + pe_header->nt.FileHeader.NumberOfSections++; + pe_header->nt.OptionalHeader.SizeOfHeaders += sizeof ( new->hdr ); + pe_header->nt.OptionalHeader.SizeOfImage = + efi_file_align ( data_end ); + + return new; +} + +/** + * Process relocation record + * + * @v bfd BFD file + * @v section Section + * @v rel Relocation entry + * @v pe_reltab PE relocation table to fill in + */ +static void process_reloc ( bfd *bfd, asection *section, arelent *rel, + struct pe_relocs **pe_reltab ) { + reloc_howto_type *howto = rel->howto; + asymbol *sym = *(rel->sym_ptr_ptr); + unsigned long offset = ( bfd_get_section_vma ( bfd, section ) + + rel->address ); + + if ( bfd_is_abs_section ( sym->section ) ) { + /* Skip absolute symbols; the symbol value won't + * change when the object is loaded. + */ + } else if ( strcmp ( howto->name, "R_X86_64_64" ) == 0 ) { + /* Generate an 8-byte PE relocation */ + generate_pe_reloc ( pe_reltab, offset, 8 ); + } else if ( ( strcmp ( howto->name, "R_386_32" ) == 0 ) || + ( strcmp ( howto->name, "R_X86_64_32" ) == 0 ) ) { + /* Generate a 4-byte PE relocation */ + generate_pe_reloc ( pe_reltab, offset, 4 ); + } else if ( strcmp ( howto->name, "R_386_16" ) == 0 ) { + /* Generate a 2-byte PE relocation */ + generate_pe_reloc ( pe_reltab, offset, 2 ); + } else if ( ( strcmp ( howto->name, "R_386_PC32" ) == 0 ) || + ( strcmp ( howto->name, "R_X86_64_PC32" ) == 0 ) ) { + /* Skip PC-relative relocations; all relative offsets + * remain unaltered when the object is loaded. + */ + } else { + eprintf ( "Unrecognised relocation type %s\n", howto->name ); + exit ( 1 ); + } +} + +/** + * Create relocations section + * + * @v pe_header PE file header + * @v pe_reltab PE relocation table + * @ret section Relocation section + */ +static struct pe_section * +create_reloc_section ( struct pe_header *pe_header, + struct pe_relocs *pe_reltab ) { + struct pe_section *reloc; + size_t section_memsz; + size_t section_filesz; + EFI_IMAGE_DATA_DIRECTORY *relocdir; + + /* Allocate PE section */ + section_memsz = output_pe_reltab ( pe_reltab, NULL ); + section_filesz = efi_file_align ( section_memsz ); + reloc = xmalloc ( sizeof ( *reloc ) + section_filesz ); + memset ( reloc, 0, sizeof ( *reloc ) + section_filesz ); + + /* Fill in section header details */ + strncpy ( ( char * ) reloc->hdr.Name, ".reloc", + sizeof ( reloc->hdr.Name ) ); + reloc->hdr.Misc.VirtualSize = section_memsz; + reloc->hdr.VirtualAddress = pe_header->nt.OptionalHeader.SizeOfImage; + reloc->hdr.SizeOfRawData = section_filesz; + reloc->hdr.Characteristics = ( EFI_IMAGE_SCN_CNT_INITIALIZED_DATA | + EFI_IMAGE_SCN_MEM_NOT_PAGED | + EFI_IMAGE_SCN_MEM_READ ); + + /* Copy in section contents */ + output_pe_reltab ( pe_reltab, reloc->contents ); + + /* Update file header details */ + pe_header->nt.FileHeader.NumberOfSections++; + pe_header->nt.OptionalHeader.SizeOfHeaders += sizeof ( reloc->hdr ); + pe_header->nt.OptionalHeader.SizeOfImage += section_filesz; + relocdir = &(pe_header->nt.OptionalHeader.DataDirectory + [EFI_IMAGE_DIRECTORY_ENTRY_BASERELOC]); + relocdir->VirtualAddress = reloc->hdr.VirtualAddress; + relocdir->Size = reloc->hdr.Misc.VirtualSize; + + return reloc; +} + +/** + * Create debug section + * + * @v pe_header PE file header + * @ret section Debug section + */ +static struct pe_section * +create_debug_section ( struct pe_header *pe_header, const char *filename ) { + struct pe_section *debug; + size_t section_memsz; + size_t section_filesz; + EFI_IMAGE_DATA_DIRECTORY *debugdir; + struct { + EFI_IMAGE_DEBUG_DIRECTORY_ENTRY debug; + EFI_IMAGE_DEBUG_CODEVIEW_RSDS_ENTRY rsds; + char name[ strlen ( filename ) + 1 ]; + } *contents; + + /* Allocate PE section */ + section_memsz = sizeof ( *contents ); + section_filesz = efi_file_align ( section_memsz ); + debug = xmalloc ( sizeof ( *debug ) + section_filesz ); + memset ( debug, 0, sizeof ( *debug ) + section_filesz ); + contents = ( void * ) debug->contents; + + /* Fill in section header details */ + strncpy ( ( char * ) debug->hdr.Name, ".debug", + sizeof ( debug->hdr.Name ) ); + debug->hdr.Misc.VirtualSize = section_memsz; + debug->hdr.VirtualAddress = pe_header->nt.OptionalHeader.SizeOfImage; + debug->hdr.SizeOfRawData = section_filesz; + debug->hdr.Characteristics = ( EFI_IMAGE_SCN_CNT_INITIALIZED_DATA | + EFI_IMAGE_SCN_MEM_NOT_PAGED | + EFI_IMAGE_SCN_MEM_READ ); + + /* Create section contents */ + contents->debug.TimeDateStamp = 0x10d1a884; + contents->debug.Type = EFI_IMAGE_DEBUG_TYPE_CODEVIEW; + contents->debug.SizeOfData = + ( sizeof ( *contents ) - sizeof ( contents->debug ) ); + contents->debug.RVA = ( debug->hdr.VirtualAddress + + offsetof ( typeof ( *contents ), rsds ) ); + contents->rsds.Signature = CODEVIEW_SIGNATURE_RSDS; + snprintf ( contents->name, sizeof ( contents->name ), "%s", + filename ); + + /* Update file header details */ + pe_header->nt.FileHeader.NumberOfSections++; + pe_header->nt.OptionalHeader.SizeOfHeaders += sizeof ( debug->hdr ); + pe_header->nt.OptionalHeader.SizeOfImage += section_filesz; + debugdir = &(pe_header->nt.OptionalHeader.DataDirectory + [EFI_IMAGE_DIRECTORY_ENTRY_DEBUG]); + debugdir->VirtualAddress = debug->hdr.VirtualAddress; + debugdir->Size = debug->hdr.Misc.VirtualSize; + + return debug; +} + +/** + * Write out PE file + * + * @v pe_header PE file header + * @v pe_sections List of PE sections + * @v pe Output file + */ +static void write_pe_file ( struct pe_header *pe_header, + struct pe_section *pe_sections, + FILE *pe ) { + struct pe_section *section; + unsigned long fpos = 0; + + /* Assign raw data pointers */ + fpos = efi_file_align ( pe_header->nt.OptionalHeader.SizeOfHeaders ); + for ( section = pe_sections ; section ; section = section->next ) { + if ( section->hdr.SizeOfRawData ) { + section->hdr.PointerToRawData = fpos; + fpos += section->hdr.SizeOfRawData; + fpos = efi_file_align ( fpos ); + } + } + + /* Write file header */ + if ( fwrite ( pe_header, sizeof ( *pe_header ), 1, pe ) != 1 ) { + perror ( "Could not write PE header" ); + exit ( 1 ); + } + + /* Write section headers */ + for ( section = pe_sections ; section ; section = section->next ) { + if ( fwrite ( §ion->hdr, sizeof ( section->hdr ), + 1, pe ) != 1 ) { + perror ( "Could not write section header" ); + exit ( 1 ); + } + } + + /* Write sections */ + for ( section = pe_sections ; section ; section = section->next ) { + if ( fseek ( pe, section->hdr.PointerToRawData, + SEEK_SET ) != 0 ) { + eprintf ( "Could not seek to %lx: %s\n", + section->hdr.PointerToRawData, + strerror ( errno ) ); + exit ( 1 ); + } + if ( section->hdr.SizeOfRawData && + ( fwrite ( section->contents, section->hdr.SizeOfRawData, + 1, pe ) != 1 ) ) { + eprintf ( "Could not write section %.8s: %s\n", + section->hdr.Name, strerror ( errno ) ); + exit ( 1 ); + } + } +} + +/** + * Convert ELF to PE + * + * @v elf_name ELF file name + * @v pe_name PE file name + */ +static void elf2pe ( const char *elf_name, const char *pe_name, + struct options *opts ) { + bfd *bfd; + asymbol **symtab; + asection *section; + arelent **reltab; + arelent **rel; + struct pe_relocs *pe_reltab = NULL; + struct pe_section *pe_sections = NULL; + struct pe_section **next_pe_section = &pe_sections; + struct pe_header pe_header; + FILE *pe; + + /* Open the file */ + bfd = open_input_bfd ( elf_name ); + symtab = read_symtab ( bfd ); + + /* Initialise the PE header */ + memcpy ( &pe_header, &efi_pe_header, sizeof ( pe_header ) ); + pe_header.nt.OptionalHeader.AddressOfEntryPoint = + bfd_get_start_address ( bfd ); + pe_header.nt.OptionalHeader.Subsystem = opts->subsystem; + + /* For each input section, build an output section and create + * the appropriate relocation records + */ + for ( section = bfd->sections ; section ; section = section->next ) { + /* Discard non-allocatable sections */ + if ( ! ( bfd_get_section_flags ( bfd, section ) & SEC_ALLOC ) ) + continue; + /* Create output section */ + *(next_pe_section) = process_section ( bfd, &pe_header, + section ); + next_pe_section = &(*next_pe_section)->next; + /* Add relocations from this section */ + reltab = read_reltab ( bfd, symtab, section ); + for ( rel = reltab ; *rel ; rel++ ) + process_reloc ( bfd, section, *rel, &pe_reltab ); + free ( reltab ); + } + + /* Create the .reloc section */ + *(next_pe_section) = create_reloc_section ( &pe_header, pe_reltab ); + next_pe_section = &(*next_pe_section)->next; + + /* Create the .reloc section */ + *(next_pe_section) = create_debug_section ( &pe_header, + basename ( pe_name ) ); + next_pe_section = &(*next_pe_section)->next; + + /* Write out PE file */ + pe = fopen ( pe_name, "w" ); + if ( ! pe ) { + eprintf ( "Could not open %s for writing: %s\n", + pe_name, strerror ( errno ) ); + exit ( 1 ); + } + write_pe_file ( &pe_header, pe_sections, pe ); + fclose ( pe ); + + /* Close BFD file */ + bfd_close ( bfd ); +} + +/** + * Print help + * + * @v program_name Program name + */ +static void print_help ( const char *program_name ) { + eprintf ( "Syntax: %s [--subsystem=<number>] infile outfile\n", + program_name ); +} + +/** + * Parse command-line options + * + * @v argc Argument count + * @v argv Argument list + * @v opts Options structure to populate + */ +static int parse_options ( const int argc, char **argv, + struct options *opts ) { + char *end; + int c; + + while (1) { + int option_index = 0; + static struct option long_options[] = { + { "subsystem", required_argument, NULL, 's' }, + { "help", 0, NULL, 'h' }, + { 0, 0, 0, 0 } + }; + + if ( ( c = getopt_long ( argc, argv, "s:h", + long_options, + &option_index ) ) == -1 ) { + break; + } + + switch ( c ) { + case 's': + opts->subsystem = strtoul ( optarg, &end, 0 ); + if ( *end ) { + eprintf ( "Invalid subsytem \"%s\"\n", + optarg ); + exit ( 2 ); + } + break; + case 'h': + print_help ( argv[0] ); + exit ( 0 ); + case '?': + default: + exit ( 2 ); + } + } + return optind; +} + +int main ( int argc, char **argv ) { + struct options opts = { + .subsystem = EFI_IMAGE_SUBSYSTEM_EFI_APPLICATION, + }; + unsigned int infile_index; + const char *infile; + const char *outfile; + + /* Initialise libbfd */ + bfd_init(); + + /* Parse command-line arguments */ + infile_index = parse_options ( argc, argv, &opts ); + if ( argc != ( infile_index + 2 ) ) { + print_help ( argv[0] ); + exit ( 2 ); + } + infile = argv[infile_index]; + outfile = argv[infile_index + 1]; + + /* Convert file */ + elf2pe ( infile, outfile, &opts ); + + return 0; +} diff --git a/gpxe/src/util/geniso b/gpxe/src/util/geniso index 7642ed36..d7ddbd2b 100755 --- a/gpxe/src/util/geniso +++ b/gpxe/src/util/geniso @@ -52,5 +52,5 @@ do echo "" KERNEL $g cp -p $f $dir/$g done >> $cfg -mkisofs -l -o $out -c boot.cat -b isolinux.bin -no-emul-boot -boot-load-size 4 -boot-info-table $dir +mkisofs -q -l -o $out -c boot.cat -b isolinux.bin -no-emul-boot -boot-load-size 4 -boot-info-table $dir rm -fr $dir diff --git a/gpxe/src/util/mergerom.pl b/gpxe/src/util/mergerom.pl index f9c52502..f9c52502 100644..100755 --- a/gpxe/src/util/mergerom.pl +++ b/gpxe/src/util/mergerom.pl diff --git a/gpxe/src/util/mkconfig.pl b/gpxe/src/util/mkconfig.pl deleted file mode 100755 index e55c2ca8..00000000 --- a/gpxe/src/util/mkconfig.pl +++ /dev/null @@ -1,205 +0,0 @@ -#!/usr/bin/perl -w - -use File::Spec::Functions qw ( :ALL ); -use File::stat; -use strict; -use warnings; - -my $cfgdir = "config"; -my $config_h = shift || "config.h"; -my @input_files; - -# Read in a whole file -# -sub read_file { - my $file = shift; - - open my $fh, "<$file" or die "Could not open file $file: $!\n"; - local $/; - my $data = <$fh>; - close $fh; - return $data; -} - -# Write out a whole file -# -sub write_file { - my $file = shift; - my $data = shift; - - open my $fh, ">$file" or die "Could not write $file: $!\n"; - print $fh $data; - close $fh; -} - -# Delete a file -# -sub delete_file { - my $file = shift; - - unlink $file or die "Could not delete $file: $!\n"; -} - -# Get a file modification time -# -sub file_mtime { - my $file = shift; - - my $stat = stat ( $file ) or die "Could not stat $file: $!\n"; - return $stat->mtime; -} - -# Read all the .h files in a directory -# -sub read_dir { - my $dir = shift; - - opendir my $dh, $dir or die "Could not open directory $dir: $!\n"; - my @entries = grep { /\.h$/ } readdir $dh; - closedir $dh; - return @entries; -} - -# Get the current configuration by reading the configuration file -# fragments -# -sub current_config { - my $dir = shift; - - my $cfg = {}; - foreach my $file ( read_dir ( $dir ) ) { - $cfg->{$file} = read_file ( catfile ( $dir, $file ) ); - } - return $cfg; -} - -# Calculate guard name for a header file -# -sub guard { - my $name = shift; - - $name =~ s/\W/_/g; - return "CONFIG_".( uc $name ); -} - -# Calculate preamble for a header file -# -sub preamble { - my $name = shift; - my $master = shift; - - my $guard = guard ( $name ); - my $preamble = <<"EOF"; -/* - * This file is automatically generated from $master. Do not edit this - * file; edit $master instead. - * - */ - -#ifndef $guard -#define $guard -EOF - return $preamble; -} - -# Calculate postamble for a header file -# -sub postamble { - my $name = shift; - - my $guard = guard ( $name ); - return "\n#endif /* $guard */\n"; -} - -# Parse one config.h file into an existing configuration -# -sub parse_config { - my $file = shift; - my $cfg = shift; - my $cursor = ""; - - push ( @input_files, $file ); - - open my $fh, "<$file" or die "Could not open $file: $!\n"; - while ( <$fh> ) { - if ( ( my $newcursor, my $suffix ) = /\@BEGIN\s+(\w+\.h)(.*)$/ ) { - die "Missing \"\@END $cursor\" before \"\@BEGIN $1\"" - ." at $file line $.\n" if $cursor; - $cursor = $newcursor; - $cfg->{$cursor} = preamble ( $cursor, $file ) - unless exists $cfg->{$cursor}; - $cfg->{$cursor} .= "\n/*".$suffix."\n"; - } elsif ( ( my $prefix, my $oldcursor ) = /^(.*)\@END\s+(\w+\.h)/ ) { - die "Missing \"\@BEGIN $oldcursor\" before \"\@END $oldcursor\"" - ." at $file line $.\n" unless $cursor eq $oldcursor; - $cfg->{$cursor} .= $prefix."*/\n"; - $cursor = ""; - } elsif ( ( my $newfile ) = /\@TRYSOURCE\s+([\w\-]+\.h)/ ) { - die "Missing \"\@END $cursor\" before \"\@TRYSOURCE $newfile\"" - ." at $file line $.\n" if $cursor; - parse_config ( $newfile, $cfg ) if -e $newfile; - } else { - $cfg->{$cursor} .= $_ if $cursor; - } - } - close $fh; - die "Missing \"\@END $cursor\" in $file\n" if $cursor; -} - -# Get the new configuration by splitting config.h file using the -# @BEGIN/@END tags -# -sub new_config { - my $file = shift; - my $cfg = {}; - - parse_config ( $file, $cfg ); - - foreach my $cursor ( keys %$cfg ) { - $cfg->{$cursor} .= postamble ( $cursor ); - } - - return $cfg; -} - -############################################################################# -# -# Main program - -# Read in current config file fragments -# -my $current = current_config ( $cfgdir ); - -# Read in config.h and split it into fragments -# -my $new = new_config ( $config_h ); - -# Delete any no-longer-wanted config file fragments -# -foreach my $file ( keys %$current ) { - unlink catfile ( $cfgdir, $file ) unless exists $new->{$file}; -} - -# Write out any modified fragments, and find the oldest timestamp of -# any unmodified fragments. -# -my $oldest = time (); -foreach my $file ( keys %$new ) { - if ( $current->{$file} && $new->{$file} eq $current->{$file} ) { - # Unmodified - my $time = file_mtime ( catfile ( $cfgdir, $file ) ); - $oldest = $time if $time < $oldest; - } else { - write_file ( catfile ( $cfgdir, $file ), $new->{$file} ); - } -} - -# If we now have fragments that are older than config.h, set the -# timestamp on each input file to match the oldest fragment, to -# prevent make from always attempting to rebuild the fragments. -# -foreach my $file ( @input_files ) { - if ( $oldest < file_mtime ( $file ) ) { - utime time(), $oldest, $file or die "Could not touch $file: $!\n"; - } -} diff --git a/gpxe/src/util/sortobjdump.pl b/gpxe/src/util/sortobjdump.pl index 8ad7314b..1373a7ff 100755 --- a/gpxe/src/util/sortobjdump.pl +++ b/gpxe/src/util/sortobjdump.pl @@ -8,7 +8,7 @@ use warnings; # linker maps produced by "make bin/%.map" by also showing the values # of all non-global symbols. -my %section_idx = ( "*ABS*" => "." ); +my %section_idx = ( "*ABS*" => ".", "*UND*" => "_" ); my %lines; while ( <> ) { if ( /^\s+(\d+)\s+([\.\*]\S+)\s+[0-9a-fA-F]+\s+[0-9a-fA-F]/ ) { diff --git a/gpxe/src/util/zbin.c b/gpxe/src/util/zbin.c index b24f401e..c1082b31 100644 --- a/gpxe/src/util/zbin.c +++ b/gpxe/src/util/zbin.c @@ -6,6 +6,8 @@ #include "nrv2b.c" FILE *infile, *outfile; +#define DEBUG 0 + struct input_file { void *buf; size_t len; @@ -151,6 +153,11 @@ static int process_zinfo_copy ( struct input_file *input, return -1; } + if ( DEBUG ) { + fprintf ( stderr, "COPY [%#zx,%#zx) to [%#zx,%#zx)\n", offset, ( offset + len ), + output->len, ( output->len + len ) ); + } + memcpy ( ( output->buf + output->len ), ( input->buf + offset ), len ); output->len += len; @@ -184,6 +191,11 @@ static int process_zinfo_pack ( struct input_file *input, return -1; } + if ( DEBUG ) { + fprintf ( stderr, "PACK [%#zx,%#zx) to [%#zx,%#zx)\n", offset, ( offset + len ), + output->len, ( output->len + packed_len ) ); + } + output->len += packed_len; if ( output->len > output->max_len ) { fprintf ( stderr, "Output buffer overrun on pack\n" ); @@ -200,6 +212,8 @@ static int process_zinfo_subtract ( struct input_file *input, size_t offset = subtract->offset; void *target; long delta; + unsigned long old; + unsigned long new; if ( ( offset + datasize ) > output->len ) { fprintf ( stderr, "Subtract at %#zx outside output buffer\n", @@ -214,21 +228,34 @@ static int process_zinfo_subtract ( struct input_file *input, switch ( datasize ) { case 1: { uint8_t *byte = target; + old = *byte; *byte += delta; + new = *byte; break; } case 2: { uint16_t *word = target; + old = *word; *word += delta; + new = *word; break; } case 4: { uint32_t *dword = target; + old = *dword; *dword += delta; + new = *dword; break; } default: fprintf ( stderr, "Unsupported subtract datasize %d\n", datasize ); return -1; } + + if ( DEBUG ) { + fprintf ( stderr, "SUBx [%#zx,%#zx) (%#lx+(%#lx/%#lx)-(%#lx/%#lx)) = %#lx\n", + offset, ( offset + datasize ), old, output->len, subtract->divisor, + input->len, subtract->divisor, new ); + } + return 0; } |