diff options
author | H. Peter Anvin <hpa@zytor.com> | 2009-02-17 20:17:17 -0800 |
---|---|---|
committer | H. Peter Anvin <hpa@zytor.com> | 2009-02-17 20:17:17 -0800 |
commit | d0c6656a62113b913948361779d6298fe76f6e61 (patch) | |
tree | efa2541a1abae4760717c6db421ea818114ab6f7 /gpxe | |
parent | 85b92a462dab7ce36c48614ea18314f8fc83ca9c (diff) | |
download | syslinux-elf-d0c6656a62113b913948361779d6298fe76f6e61.tar.gz syslinux-elf-d0c6656a62113b913948361779d6298fe76f6e61.tar.xz syslinux-elf-d0c6656a62113b913948361779d6298fe76f6e61.zip |
Update gPXE to version 0.9.6+ 277b84c6e7d49f3cf01c855007f591de8c7cb75f
Update gPXE to version 0.9.6+, from commit
277b84c6e7d49f3cf01c855007f591de8c7cb75f in the main gPXE repository.
The only differences is src/config/general.h which has a few protocols
added, and src/arch/i386/prefix/boot1a.S which was called boot1a.s in
the upstream repository.
Diffstat (limited to 'gpxe')
430 files changed, 45138 insertions, 13535 deletions
diff --git a/gpxe/.gitignore b/gpxe/.gitignore new file mode 100644 index 00000000..0517ab74 --- /dev/null +++ b/gpxe/.gitignore @@ -0,0 +1 @@ +/contrib diff --git a/gpxe/Makefile b/gpxe/Makefile index c846e939..7a34f8a7 100644 --- a/gpxe/Makefile +++ b/gpxe/Makefile @@ -1,6 +1,6 @@ ## ----------------------------------------------------------------------- ## -## Copyright 2008 H. Peter Anvin - All Rights Reserved +## Copyright 2008-2009 H. Peter Anvin - All Rights Reserved ## ## This program is free software; you can redistribute it and/or modify ## it under the terms of the GNU General Public License as published by @@ -32,8 +32,9 @@ spotless: clean dist installer: -src/bin/undionly.kpxe: ../core/pxelinux.0 - $(MAKE) -C src EMBEDDED_IMAGE=../$< NO_WERROR=1 bin/undionly.kpxe +src/bin/undionly.kkpxe: pxelinux.gpxe ../core/pxelinux.0 + $(MAKE) -C src bin/undionly.kkpxe NO_WERROR=1 \ + EMBEDDED_IMAGE=../pxelinux.gpxe,../../core/pxelinux.0 -gpxelinux.0: src/bin/undionly.kpxe +gpxelinux.0: src/bin/undionly.kkpxe cp -f $< $@ diff --git a/gpxe/VERSION b/gpxe/VERSION index 010605b1..69b51101 100644 --- a/gpxe/VERSION +++ b/gpxe/VERSION @@ -1 +1 @@ -0.9.5 2008-10-01 +0.9.6+ 2008-11-23 diff --git a/gpxe/pxelinux.gpxe b/gpxe/pxelinux.gpxe new file mode 100644 index 00000000..51fe222e --- /dev/null +++ b/gpxe/pxelinux.gpxe @@ -0,0 +1,4 @@ +#!gpxe +dhcp net0 +imgload pxelinux.0 +boot pxelinux.0 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, |