diff --git a/src/.cvsignore b/src/.cvsignore index 2e0d941a..ef29930b 100644 --- a/src/.cvsignore +++ b/src/.cvsignore @@ -1,2 +1,3 @@ -bin -gcccheck +.toolcheck +TAGS* +bin* diff --git a/src/Config b/src/Config index 7be549b1..b1c72a05 100644 --- a/src/Config +++ b/src/Config @@ -424,27 +424,134 @@ CFLAGS+= -DPXE_IMAGE -DPXE_EXPORT # but this is here for archs that don't support relocation # CFLAGS+= -DNORELOCATE -# you should normally not need to change these -HOST_CC= gcc -CPP= gcc -E -Wp,-Wall -RM= rm -f -TOUCH= touch -PERL= /usr/bin/perl -CC= gcc -AS= as -LD= ld -SIZE= size -AR= ar -RANLIB= ranlib -OBJCOPY= objcopy -CFLAGS+= -Os -ffreestanding -CFLAGS+= -Wall -W -Wno-format -CFLAGS+= $(EXTRA_CFLAGS) -ASFLAGS+= $(EXTRA_ASFLAGS) -LDFLAGS+= $(EXTRA_LDFLAGS) -# For debugging -# LDFLAGS+= -Map $@.map -# Location to place generated binaries, and files -BIN=bin + +# Garbage from Makefile.main temporarily placed here until a home can +# be found for it. + +# NS8390 options: +# -DINCLUDE_NE - Include NE1000/NE2000 support +# -DNE_SCAN=list - Probe for NE base address using list of +# comma separated hex addresses +# -DINCLUDE_3C503 - Include 3c503 support +# -DT503_SHMEM - Use 3c503 shared memory mode (off by default) +# -DINCLUDE_WD - Include Western Digital/SMC support +# -DWD_DEFAULT_MEM- Default memory location for WD/SMC cards +# -DWD_790_PIO - Read/write to WD/SMC 790 cards in PIO mode (default +# is to use shared memory) Try this if you get "Bogus +# packet, ignoring" messages, common on ISA/PCI hybrid +# systems. +# -DCOMPEX_RL2000_FIX +# +# If you have a Compex RL2000 PCI 32-bit (11F6:1401), +# and the bootrom hangs in "Probing...[NE*000/PCI]", +# try enabling this fix... it worked for me :). +# In the first packet write somehow it somehow doesn't +# get back the expected data so it is stuck in a loop. +# I didn't bother to investigate what or why because it works +# when I interrupt the loop if it takes more then COMPEX_RL2000_TRIES. +# The code will notify if it does a abort. +# SomniOne - somnione@gmx.net +# +# 3C509 option: +# -DINCLUDE_3C509 - Include 3c509 support +# +# 3C90X options: +# -DINCLUDE_3C90X - Include 3c90x support +# +# Warning Warning Warning +# If you use any of the XCVR options below, please do not complain about +# the behaviour with Linux drivers to the kernel developers. You are +# on your own if you do this. Please read 3c90x.txt to understand +# what they do. If you don't understand them, ask for help on the +# Etherboot mailing list. And please document what you did to the NIC +# on the NIC so that people after you won't get nasty surprises. +# +# -DCFG_3C90X_PRESERVE_XCVR - Reset the transceiver type to the value it +# had initially just before the loaded code is started. +# -DCFG_3C90X_XCVR - Hardcode the tranceiver type Etherboot uses. +# -DCFG_3C90X_BOOTROM_FIX - If you have a 3c905B with buggy ROM +# interface, setting this option might "fix" it. Use +# with caution and read the docs in 3c90x.txt! +# +# See the documentation file 3c90x.txt for more details. +# +# CS89X0 (optional) options: +# -DINCLUDE_CS89X0- Include CS89x0 support +# -DCS_SCAN=list - Probe for CS89x0 base address using list of +# comma separated hex addresses; increasing the +# address by one (0x300 -> 0x301) will force a +# more aggressive probing algorithm. This might +# be neccessary after a soft-reset of the NIC. +# +# LANCE options: +# -DINCLUDE_NE2100- Include NE2100 support +# -DINCLUDE_NI6510- Include NI6510 support +# +# SK_G16 options: +# -DINCLUDE_SK_G16- Include SK_G16 support +# +# I82586 options: +# -DINCLUDE_3C507 - Include 3c507 support +# -DINCLUDE_NI5210- Include NI5210 support +# -DINCLUDE_EXOS205-Include EXOS205 support +# +# SMC9000 options: +# -DINCLUDE_SMC9000 - Include SMC9000 driver +# -DSMC9000_SCAN=list - List of I/O addresses to probe +# +# TIARA (Fujitsu Etherstar) options: +# -DINCLUDE_TIARA - Include Tiara support +# +# NI5010 options: +# -DINCLUDE_NI5010 - Include NI5010 support +# +# TULIP options: +# -DINCLUDE_TULIP - Include Tulip support +# +# RTL8139 options: +# -DINCLUDE_RTL8139 - Include RTL8139 support +# +# SIS900 options: +# -DINCLUDE_SIS900 - Include SIS900 support +# +# NATSEMI options: +# -DINCLUDE_NATSEMI - Include NATSEMI support +# + +CFLAGS_3c503 = -DINCLUDE_3C503 # -DT503_SHMEM +MAKEROM_FLAGS_3c503= -3 +CFLAGS_3c507 = -DINCLUDE_3C507 +CFLAGS_3c509 = -DINCLUDE_3C509 +CFLAGS_3c529 = -DINCLUDE_3C529 +CFLAGS_3c595 = -DINCLUDE_3C595 +CFLAGS_3c90x = -DINCLUDE_3C90X +CFLAGS_cs89x0 = -DINCLUDE_CS89X0 +CFLAGS_eepro = -DINCLUDE_EEPRO +CFLAGS_eepro100 = -DINCLUDE_EEPRO100 +CFLAGS_e1000 = -DINCLUDE_E1000 +CFLAGS_epic100 = -DINCLUDE_EPIC100 +CFLAGS_exos205 = -DINCLUDE_EXOS205 +CFLAGS_lance = -DINCLUDE_LANCE # Lance/PCI! +CFLAGS_ne2100 = -DINCLUDE_NE2100 +CFLAGS_ne = -DINCLUDE_NE -DNE_SCAN=0x300,0x280,0x320,0x340,0x380 +CFLAGS_ns8390 = -DINCLUDE_NS8390 # NE2000/PCI! +CFLAGS_ni5010 = -DINCLUDE_NI5010 +CFLAGS_ni5210 = -DINCLUDE_NI5210 +CFLAGS_ni6510 = -DINCLUDE_NI6510 +CFLAGS_rtl8139 = -DINCLUDE_RTL8139 +CFLAGS_sk_g16 = -DINCLUDE_SK_G16 +CFLAGS_sis900 = -DINCLUDE_SIS900 +CFLAGS_natsemi = -DINCLUDE_NATSEMI +CFLAGS_smc9000 = -DINCLUDE_SMC9000 +CFLAGS_sundance = -DINCLUDE_SUNDANCE +CFLAGS_tlan = -DINCLUDE_TLAN +CFLAGS_tiara = -DINCLUDE_TIARA +CFLAGS_depca = -DINCLUDE_DEPCA +# CFLAGS_depca += -DDEPCA_MODEL=DEPCA -DDEPCA_RAM_BASE=0xd0000 +CFLAGS_tulip = -DINCLUDE_TULIP +CFLAGS_otulip = -DINCLUDE_OTULIP +CFLAGS_via_rhine = -DINCLUDE_VIA_RHINE +CFLAGS_wd = -DINCLUDE_WD -DWD_DEFAULT_MEM=0xCC000 +CFLAGS_w89c840 = -DINCLUDE_W89C840 diff --git a/src/Families b/src/Families deleted file mode 100644 index 8a2af713..00000000 --- a/src/Families +++ /dev/null @@ -1,133 +0,0 @@ -# This is the config file for creating Makefile rules for Etherboot ROMs -# -# To make a ROM for a supported NIC locate the appropriate family -# and add a line of the form -# -# ROM PCI-IDs Comment -# -# ROM is the desired output name for both .rom and .lzrom images. -# PCI IDs are the PCI vendor and device IDs of the PCI NIC -# For ISA NICs put - -# -# All PCI ROMs that share a single driver are only built once (because they -# only have different PCI-IDs, but identical code). ISA ROMS are built for -# each ROM type, because different vendors used a different logic around the -# basic chip. The most popular example is the NS8390, which some cards use -# in PIO mode, some in DMA mode. Two chips currently don't fit into this nice -# black-and-white scheme (the Lance and the NS8390). Their driver deals -# with both PCI and ISA cards. These drivers will be treated similarly to -# ISA only drivers by genrules.pl and are compiled for each ROM type that is -# ISA, and additionally compiled for the PCI card type. -# -# Then do: make clean, make Roms and make -# -# Please send additions to this file to - -# Start of configuration - -family drivers/net/skel - -family arch/ia64/drivers/net/undi_nii -undi_nii - - -# 3c59x cards (Vortex) and 3c900 cards -# If your 3c900 NIC detects but fails to work, e.g. no link light, with -# the 3c90x driver, try using the 3c595 driver. I have one report that the -# 3c595 driver handles these NICs properly. (The 595 driver uses the -# programmed I/O mode of operation, whereas the 90x driver uses the bus -# mastering mode. These NICs are capable of either mode.) When it comes to -# making a ROM, as usual, you must choose the correct image, the one that -# contains the same PCI IDs as your NIC. -family drivers/net/3c595 - -# 3Com 3c90x cards -family drivers/net/3c90x - -# Intel Etherexpress Pro/100 -family drivers/net/eepro100 - -#Intel Etherexpress Pro/1000 -family drivers/net/e1000 - -#Broadcom Tigon 3 -family drivers/net/tg3 - -family drivers/net/pcnet32 - -# National Semiconductor ns83820 (Gigabit) family -family drivers/net/ns83820 - -family drivers/net/tulip - -family drivers/net/davicom - -family drivers/net/rtl8139 - -family drivers/net/r8169 - -family drivers/net/via-rhine - -family drivers/net/w89c840 - -family drivers/net/sis900 - -family drivers/net/natsemi - -family drivers/net/prism2_plx - -family drivers/net/prism2_pci -# Various Prism2.5 (PCI) devices that manifest themselves as Harris Semiconductor devices -# (with the actual vendor appearing as the vendor of the first subsystem) -hwp01170 0x1260,0x3873 ActionTec HWP01170 -dwl520 0x1260,0x3873 DLink DWL-520 - -family drivers/net/ns8390 -wd - WD8003/8013, SMC8216/8416, SMC 83c790 (EtherEZ) -ne - NE1000/2000 and clones -3c503 - 3Com503, Etherlink II[/16] - -family drivers/net/epic100 - -family drivers/net/3c509 -3c509 - 3c509, ISA/EISA -3c529 - 3c529 == MCA 3c509 - -family drivers/net/3c515 -3c515 - 3c515, Fast EtherLink ISA - -family drivers/net/eepro -eepro - Intel Etherexpress Pro/10 - -family drivers/net/cs89x0 -cs89x0 - Crystal Semiconductor CS89x0 - -family drivers/net/depca -depca - Digital DE100 and DE200 - -family drivers/net/forcedeth - -family drivers/net/sk_g16 -sk_g16 - Schneider and Koch G16 - -family drivers/net/smc9000 -smc9000 - SMC9000 - -family drivers/net/sundance - -family drivers/net/tlan - -family drivers/disk/ide_disk -ide_disk 0x0000,0x0000 Generic IDE disk support - -family drivers/disk/pc_floppy - -family arch/i386/drivers/net/undi -undi 0x0000,0x0000 UNDI driver support - -family drivers/net/pnic - -family arch/armnommu/drivers/net/p2001_eth - -family drivers/net/mtd80x - -family drivers/net/dmfe diff --git a/src/Makefile b/src/Makefile index afb1618e..7d7d76d4 100644 --- a/src/Makefile +++ b/src/Makefile @@ -1,15 +1,145 @@ -# Override ARCH here or on the command line -# ARCH=i386 -# Additionally you can supply extra compilation arguments, e.g. for x86_64 -# EXTRA_CFLAGS=-m32 -# EXTRA_ASFLAGS=--32 -# EXTRA_LDFLAGS=-m elf_i386 -ifndef ARCH -ARCH:=$(shell uname -m | sed -e s,i[3456789]86,i386,) -endif -MAKEDEPS:= -SUFFIXES:= +# Initialise variables that get added to throughout the various Makefiles +# +MAKEDEPS := Makefile .toolcheck +SRCDIRS := +SRCS := +NON_AUTO_SRCS := +DRIVERS := +ROMS := +MEDIA := +NON_AUTO_MEDIA := +# Grab the central Config file. +# +MAKEDEPS += Config include Config + +# If no architecture is specified in Config or on the command-line, +# use that of the build machine. +# +ifndef ARCH +ARCH := $(shell uname -m | sed -e s,i[3456789]86,i386,) +endif + +# Drag in architecture-specific Config +# +MAKEDEPS += arch/$(ARCH)/Config include arch/$(ARCH)/Config -include Makefile.main + +# If invoked with no build target, print out a helpfully suggestive +# message. +# +noargs : blib + @echo '====================================================' + @echo 'No target specified. To specify a target, do: ' + @echo + @echo ' $(MAKE) bin/. ' + @echo + @echo 'where is one of [z]{$(MEDIA) }' + @echo + @echo 'or: ' + @echo + @echo ' $(MAKE) alls' + @echo + @echo 'to generate all possible images of format ' + @echo + @echo 'For example, ' + @echo + @echo ' make allzroms ' + @echo + @echo 'will generate all possible .zrom (rom burnable) images, and' + @echo + @echo ' make allzdsks' + @echo + @echo 'will generate all possible .zdsk (bootable floppy) images, or' + @echo + @echo '====================================================' + @exit 1 + +# Locations of utilities +# +HOST_CC ?= gcc +CPP ?= gcc -E -Wp,-Wall +RM ?= rm -f +TOUCH ?= touch +MKDIR ?= mkdir +PERL ?= /usr/bin/perl +CC ?= $(CROSS_COMPILE)gcc +AS ?= $(CROSS_COMPILE)as +LD ?= $(CROSS_COMPILE)ld +SIZE ?= $(CROSS_COMPILE)size +AR ?= $(CROSS_COMPILE)ar +RANLIB ?= $(CROSS_COMPILE)ranlib +OBJCOPY ?= $(CROSS_COMPILE)objcopy +PARSEROM ?= $(PERL) ./util/parserom.pl +MAKEROM ?= $(PERL) ./util/makerom.pl +NRV2B ?= ./util/nrv2b + +# Location to place generated files +# +BIN ?= bin + +# Library containing all compiled objects +BLIB = $(BIN)/blib.a + +# Common flags +# +CFLAGS += -I include -I arch/$(ARCH)/include -DARCH=$(ARCH) +CFLAGS += -Os -ffreestanding +CFLAGS += -Wall -W -Wno-format +CFLAGS += $(EXTRA_CFLAGS) +ASFLAGS += $(EXTRA_ASFLAGS) +LDFLAGS += $(EXTRA_LDFLAGS) + +# CFLAGS for specific object types +# +CFLAGS_c += +CFLAGS_S += -DASSEMBLY + +# 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_$(basename $(@F))) \ + -DOBJECT=$(subst -,_,$(basename $(@F))) +$(BIN)/%.flags : + @echo $(OBJ_CFLAGS) + +# Rules for specific object types. +# +COMPILE_c = $(CC) $(CFLAGS) $(CFLAGS_c) $(OBJ_CFLAGS) +RULE_c = $(COMPILE_c) -c $< -o $@ +RULE_c_to_s = $(COMPILE_c) -S -c $< -o $@ +RULE_c_to_c = $(COMPILE_c) -E -c $< > $@ + +PREPROCESS_S = $(CPP) $(CFLAGS) $(CFLAGS_S) $(OBJ_CFLAGS) +ASSEMBLE_S = $(AS) $(ASFLAGS) +RULE_S = $(PREPROCESS_S) $< | $(ASSEMBLE_S) -o $@ +RULE_S_to_s = $(PREPROCESS_S) $< > $@ + +DEBUG_TARGETS += c s + +# SRCDIRS lists all directories containing source files. +# +SRCDIRS += core drivers/net drivers/disk + +# NON_AUTO_SRCS lists files that are excluded from the normal +# automatic build system. +# +NON_AUTO_SRCS += core/elf_loader.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. +# +FINALISE_rom = $(MAKEROM) $(MAKEROM_FLAGS) $(TGT_MAKEROM_FLAGS) \ + -i$(IDENT) $@ + +# Drag in architecture-specific Makefile +# +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/src/Makefile-armnommu b/src/Makefile-armnommu deleted file mode 100644 index 04c4002b..00000000 --- a/src/Makefile-armnommu +++ /dev/null @@ -1,18 +0,0 @@ -ARCH:=armnommu -MAKEDEPS:= - -include Config -include arch/$(ARCH)/Config - -CC= $(CROSS_COMPILE)gcc -AS= $(CROSS_COMPILE)as -LD= $(CROSS_COMPILE)ld -SIZE= $(CROSS_COMPILE)size -AR= $(CROSS_COMPILE)ar -RANLIB= $(CROSS_COMPILE)ranlib -OBJCOPY= $(CROSS_COMPILE)objcopy - -MAKEDEPS+=Makefile-armnommu -BIN=bin - -include Makefile.main diff --git a/src/Makefile-e1 b/src/Makefile-e1 deleted file mode 100644 index bdd4917a..00000000 --- a/src/Makefile-e1 +++ /dev/null @@ -1,18 +0,0 @@ -ARCH:=e1 -MAKEDEPS:= - -include arch/$(ARCH)/Config -include Config - -CC= e1-coff-gcc -AS= e1-coff-as -LD= e1-coff-ld -SIZE= e1-coff-size -AR= e1-coff-ar -RANLIB= e1-coff-ranlib -OBJCOPY=e1-coff-objcopy - -MAKEDEPS+=Makefile-e1 -BIN=bin-e1 - -include Makefile.main diff --git a/src/Makefile-i386 b/src/Makefile-i386 deleted file mode 100644 index d6268520..00000000 --- a/src/Makefile-i386 +++ /dev/null @@ -1,18 +0,0 @@ -ARCH:=i386 -MAKEDEPS:= - -include arch/$(ARCH)/Config -include Config - -CC= i386-linux-gcc -AS= i386-linux-as -LD= i386-linux-ld -SIZE= i386-linux-size -AR= i386-linux-ar -RANLIB= i386-linux-ranlib -OBJCOPY= i386-linux-objcopy - -MAKEDEPS+=Makefile-i386 -BIN=bin-i386 - -include Makefile.main diff --git a/src/Makefile-ia64 b/src/Makefile-ia64 deleted file mode 100644 index 503f7e03..00000000 --- a/src/Makefile-ia64 +++ /dev/null @@ -1,18 +0,0 @@ -ARCH:=ia64 -MAKEDEPS:= - -include arch/$(ARCH)/Config -include Config - -CC= ia64-linux-gcc -AS= ia64-linux-as -LD= ia64-linux-ld -SIZE= ia64-linux-size -AR= ia64-linux-ar -RANLIB= ia64-linux-ranlib -OBJCOPY= ia64-linux-objcopy - -MAKEDEPS+=Makefile-ia64 -BIN=bin-ia64 - -include Makefile.main diff --git a/src/Makefile.housekeeping b/src/Makefile.housekeeping new file mode 100644 index 00000000..57538bef --- /dev/null +++ b/src/Makefile.housekeeping @@ -0,0 +1,375 @@ +# -*- 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 = 5 +VERSION_MINOR = 3 +VERSION_PATCH = 14 +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) + +# Check for tools that can cause failed builds +# +.toolcheck : Makefile Config + @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 + +# Check for an old version of gas (binutils 2.9.1) +# +OLDGAS := $(shell $(AS) --version | grep -q '2\.9\.1' && echo -DGAS291) +CFLAGS += $(OLDGAS) +oldgas : + @echo $(oldgas) + +# SRCDIRS lists all directories containing source files. +srcdirs : + @echo $(SRCDIRS) + +# SRCS lists all .c or .S files found in any SRCDIR +# +SRCS += $(wildcard $(patsubst %,%/*.c,$(SRCDIRS))) +SRCS += $(wildcard $(patsubst %,%/*.S,$(SRCDIRS))) +srcs : + @echo $(SRCS) + +# AUTO_SRCS lists all files in SRCS that are not mentioned in +# NON_AUTO_SRCS. Files should be added to NON_AUTO_SRCS if they +# cannot be built using the standard build template. +# +AUTO_SRCS = $(filter-out $(NON_AUTO_SRCS),$(SRCS)) +autosrcs : + @echo $(AUTO_SRCS) + +# 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. + +# src_template : generate Makefile rules for a given source file +# +# $(1) is the full path to the source file (e.g. "drivers/net/rtl8139.c") +# $(2) is the full path to the .d file (e.g. "bin/deps/drivers/net/rtl8139.d") +# $(3) is the source type (e.g. "c") +# $(4) is the source base name (e.g. "rtl8139") +# +define src_template + + @echo "Generating Makefile rules for $(1)" + @$(MKDIR) -p $(dir $(2)) + @$(RM) $(2) + @$(TOUCH) $(2) + $(foreach OBJ,$(if $(OBJS_$(4)),$(OBJS_$(4)),$(4)), \ + $(call obj_template,$(1),$(2),$(3),$(OBJ))) + @$(PARSEROM) $(1) >> $(2) + +endef + +# obj_template : generate Makefile rules for a given resultant object +# of a particular source file. (We can have multiple objects per +# source file via the OBJS_xxx list.) +# +# $(1) is the full path to the source file (e.g. "drivers/net/rtl8139.c") +# $(2) is the full path to the .d file (e.g. "bin/deps/drivers/net/rtl8139.d") +# $(3) is the source type (e.g. "c") +# $(4) is the object name (e.g. "rtl8139") +# +define obj_template + + @$(CPP) $(CFLAGS) $(CFLAGS_$(3)) $(CFLAGS_$(4)) \ + -M $(1) -MT "$(4)_DEPS" | tr : = >> $(2) + @echo -e '\n$$(BIN)/$(4).o : $(1) $$(MAKEDEPS) $$($(4)_DEPS)' \ + '\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$$(RULE_$(3)_to_$(TGT))\n' ) ) \ + '\n$(2) : $$($(4)_DEPS)\n' \ + '\nTAGS : $$($(4)_DEPS)\n' \ + >> $(2) + +endef + +# Rule to generate the Makefile rules files to be included +# +$(BIN)/deps/%.d : % $(MAKEDEPS) $(PARSEROM) + $(if $(filter $(AUTO_SRCS),$<),$(call src_template,$<,$@,$(subst .,,$(suffix $<)),$(basename $(notdir $<))),@echo 'ERROR: $< is not an AUTO_SRC' ; exit 1) + +# Calculate and include the list of Makefile rules files +# +AUTO_DEPS = $(patsubst %,$(BIN)/deps/%.d,$(AUTO_SRCS)) +include $(AUTO_DEPS) +autodeps : + @echo $(AUTO_DEPS) +VERYCLEANUP += $(BIN)/deps + +# The following variables are created by the Makefile rules files +# +bobjs : + @echo $(BOBJS) +drivers : + @echo $(DRIVERS) +.PHONY : drivers +roms : + @echo $(ROMS) + +# Generate the NIC file from the parsed source files. The NIC file is +# only for rom-o-matic. +# +$(BIN)/NIC : $(AUTO_DEPS) + @echo '# This is an automatically generated file, do not edit' > $@ + @echo '# It does not affect anything in the build, ' \ + 'it is only for rom-o-matic' >> $@ + @echo >> $@ + @perl -ne 'chomp; print "$$1\n" if /\# NIC\t(.*)$$/' $^ >> $@ +CLEANUP += $(BIN)/NIC + +# Library of all objects +# +$(BLIB) : $(BOBJS) + $(AR) r $@ $(BOBJS) + $(RANLIB) $@ +blib : $(BLIB) + +# Analyse a target name (e.g. "bin/dfe538--prism2_pci.zrom.tmp") and +# derive the variables: +# +# TGT_ELEMENTS : the elements of the target (e.g. "dfe538 prism2_pci") +# TGT_PREFIX : the prefix type (e.g. "zrom") +# TGT_DRIVERS : the driver for each element (e.g. "rtl8139 prism2_pci") +# TGT_ROM_NAME : the ROM name (e.g. "dfe538") +# TGT_MEDIA : the media type (e.g. "rom") +# +TGT_ELEMENTS = $(subst --, ,$(firstword $(subst ., ,$(notdir $@)))) +TGT_PREFIX = $(word 2,$(subst ., ,$(notdir $@))) +TGT_DRIVERS = $(strip $(foreach TGT_ELEMENT,$(TGT_ELEMENTS), \ + $(firstword $(DRIVER_$(TGT_ELEMENT)) $(TGT_ELEMENT)))) +TGT_ROM_NAME = $(firstword $(TGT_ELEMENTS)) +TGT_MEDIA = $(subst z,,$(TGT_PREFIX)) + +# Look up ROM type and IDs for the current target +# (e.g. "bin/dfe538--prism2_pci.zrom.tmp") and derive the variables: +# +# TGT_ROM_TYPE : PCI/ISA indicator (e.g. "pci") +# TGT_PCI_VENDOR : the PCI vendor ID (e.g. "0x1186") +# TGT_PCI_DEVICE : the PCI device ID (e.g. "0x1300") +# +TGT_ROM_TYPE = $(ROM_TYPE_$(TGT_ROM_NAME)) +TGT_PCI_VENDOR = $(PCI_VENDOR_$(TGT_ROM_NAME)) +TGT_PCI_DEVICE = $(PCI_DEVICE_$(TGT_ROM_NAME)) + +# Calculate link-time options for the current target +# (e.g. "bin/dfe538--prism2_pci.zrom.tmp") and derive the variables: +# +# TGT_LD_DRIVERS : symbols to require in order to drag in the relevant drivers +# (e.g. "obj_rtl8139 obj_prism2_pci") +# TGT_LD_PREFIX : symbols to require in order to drag in the relevant prefix +# (e.g. "obj_zpciprefix") +# TGT_LD_IDS : symbols to define in order to fill in ID structures in the +# ROM header (e.g. "pci_vendor=0x1186 pci_device=0x1300") +# +TGT_LD_DRIVERS = $(subst -,_,$(patsubst %,obj_%,$(TGT_DRIVERS))) +TGT_LD_PREFIX = obj_$(subst rom,$(TGT_ROM_TYPE),$(TGT_PREFIX))prefix +TGT_LD_IDS = $(if $(TGT_PCI_VENDOR),pci_vendor=$(TGT_PCI_VENDOR)) \ + $(if $(TGT_PCI_DEVICE),pci_device=$(TGT_PCI_DEVICE)) + +# Calculate linker flags based on link-time options for the current +# target type (e.g. "bin/dfe538--prism2_pci.zrom.tmp") and derive the +# variables: +# +# TGT_LD_FLAGS : target-specific flags to pass to linker (e.g. +# "-u obj_zpciprefix -u obj_rtl8139 -u obj_prism2_pci +# --defsym pci_vendor=0x1186 --defsym pci_device=0x1300") +# +TGT_LD_FLAGS = $(foreach SYM,$(TGT_LD_PREFIX) $(TGT_LD_DRIVERS) obj_config,\ + -u $(SYM) --defsym check_$(SYM)=$(SYM) ) \ + $(patsubst %,--defsym %,$(TGT_LD_IDS)) + +# Calculate makerom flags for the specific target +# (e.g. "bin/dfe538--prism2_pci.zrom.tmp") and derive the variables: +# +# TGT_MAKEROM_FLAGS : target-specific flags for makerom (e.g. +# "-p 0x1186,0x1300") +# +TGT_MAKEROM_FLAGS = $(strip $(MAKEROM_FLAGS_$(TGT_ROM_NAME)) \ + $(if $(TGT_PCI_VENDOR),$(strip -p $(TGT_PCI_VENDOR),$(TGT_PCI_DEVICE)))) + +# Print out all derived information for a given target. +# +$(BIN)/%.info : + @echo 'Elements : $(TGT_ELEMENTS)' + @echo 'Prefix : $(TGT_PREFIX)' + @echo 'Drivers : $(TGT_DRIVERS)' + @echo 'ROM name : $(TGT_ROM_NAME)' + @echo 'Media : $(TGT_MEDIA)' + @echo + @echo 'ROM type : $(TGT_ROM_TYPE)' + @echo 'PCI vendor : $(TGT_PCI_VENDOR)' + @echo 'PCI device : $(TGT_PCI_DEVICE)' + @echo + @echo 'LD driver symbols : $(TGT_LD_DRIVERS)' + @echo 'LD prefix symbols : $(TGT_LD_PREFIX)' + @echo 'LD ID symbols : $(TGT_LD_IDS)' + @echo + @echo 'LD target flags : $(TGT_LD_FLAGS)' + @echo + @echo 'makerom target flags : $(TGT_MAKEROM_FLAGS)' + +# Build an intermediate object file from the objects required for the +# specified target. +# +$(BIN)/%.tmp : $(BLIB) $(MAKEDEPS) $(LDSCRIPT) + $(LD) $(LDFLAGS) -T $(LDSCRIPT) $(TGT_LD_FLAGS) $< -o $@ \ + -Map $(BIN)/$*.tmp.map + +# Show a linker map for the specified target +# +$(BIN)/%.map : $(BIN)/%.tmp + @less $(BIN)/$*.tmp.map + +# 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. +# +# Note that there's an alternative way to generate most .rom images: +# they can be copied from their 'master' ROM image using cp and +# reprocessed with makerom to add the PCI IDs and ident string. The +# relevant rule would look something like: +# +# $(BIN)/dfe538%rom : $(BIN)/rtl8139%rom +# cat $< $@ +# $(FINALISE_rom) +# +# You can derive the ROM/driver relationships using the variables +# DRIVER_ and/or ROMS_. +# +# We don't currently do this, because (a) it would require generating +# yet more Makefile fragments (since you need a rule for each ROM in +# ROMS), and (b) the linker is so fast that it probably wouldn't make +# much difference to the overall build time. + +media : + @echo $(MEDIA) + +AUTO_MEDIA = $(filter-out $(NON_AUTO_MEDIA),$(MEDIA)) +automedia : + @echo $(AUTO_MEDIA) + +# media_template : create Makefile rules for specified media +# +# $(1) is the media name (e.g. "rom") +# $(2) is the full path to the .d file (e.g. "bin/deps/rom.media.d") +# +define media_template + + @echo "Generating Makefile rules for $(1) media" + @$(MKDIR) -p $(dir $(2)) + @$(RM) $(2) + @$(TOUCH) $(2) + @echo -e '$$(BIN)/%$(1) : $$(BIN)/%$(1).tmp' \ + '\n\t$$(OBJCOPY) -O binary $$< $$@' \ + '\n\t$$(FINALISE_$(1))' \ + > $(2) + +endef + +# Rule to generate the Makefile rules to be included +# +$(BIN)/deps/%.media.d : $(MAKEDEPS) + $(if $(filter $(AUTO_MEDIA),$*), \ + $(call media_template,$*,$@), \ + @echo 'ERROR: $* is not an AUTO_MEDIA' ; exit 1) + +# Calculate and include the list of Makefile rules files +# +MEDIA_DEPS = $(patsubst %,$(BIN)/deps/%.media.d,$(AUTO_MEDIA)) +mediadeps : + @echo $(MEDIA_DEPS) +include $(MEDIA_DEPS) + +# The "allXXXs" targets for each suffix +# +allroms allzroms : all%s : $(foreach ROM,$(ROMS),$(BIN)/$(ROM).%) +all%s : $(foreach DRIVER,$(DRIVERS),$(BIN)/$(DRIVER).%) + +# The compressor utility +# +$(NRV2B) : util/nrv2b.c $(MAKEDEPS) + $(HOST_CC) -O2 -DENCODE -DDECODE -DMAIN -DVERBOSE -DNDEBUG \ + -DBITSIZE=32 -DENDIAN=0 -o $@ $< +CLEANUP += $(NRV2B) + +# 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. +# +BUILDSERIAL_H = include/.buildserial.h + +$(BUILDSERIAL_H) : + @if [ ! -s $@ ]; then echo '#define BUILD_SERIAL_NUM 0' > $@; fi + @perl -pi -e 's/(BUILD_SERIAL_NUM)\s+(\d+)/"$${1} ".($${2}+1)/e' $@ + +bs : $(BUILDSERIAL_H) + @perl -n -e '/BUILD_SERIAL_NUM\s+(\d+)/ && ' \ + -e 'print "Build serial number is $$1\n";' $< + +ifeq ($(filter bs,$(MAKECMDGOALS)),bs) +.PHONY : $(BUILDSERIAL_H) +endif + +# Ensure that include/.buildserial.h always exists, to solve the +# problem of bootstrapping a BUILD_SERIAL-enabled build. +# +ifeq ($(wildcard $(BUILDSERIAL_H)),) +$(shell $(TOUCH) $(BUILDSERIAL_H)) +endif + +# List of available architectures +# +ARCHS = $(filter-out CVS,$(patsubst arch/%,%,$(wildcard arch/*))) +archs : + @echo $(ARCHS) + +OTHER_ARCHS = $(filter-out $(ARCH),$(ARCHS)) +otherarchs : + @echo $(OTHER_ARCHS) + +# Build the TAGS file for emacs +# +TAGS : TAGS.$(ARCH) + +TAGS.$(ARCH) : + ctags -e -R -f $@ $(foreach ARCH,$(OTHER_ARCHS),--exclude=arch/$(ARCH)) +CLEANUP += TAGS* + +# Clean-up +# +clean : + $(RM) $(CLEANUP) + +veryclean : clean + $(RM) -r $(VERYCLEANUP) diff --git a/src/Makefile.main b/src/Makefile.main deleted file mode 100644 index 1c7b6e5d..00000000 --- a/src/Makefile.main +++ /dev/null @@ -1,445 +0,0 @@ -# -# Makefile for Etherboot -# -# Most of the time you should edit Config -# -# Common options: -# VERSION_*=v - Set the major and minor version numbers -# -# NS8390 options: -# -DINCLUDE_NE - Include NE1000/NE2000 support -# -DNE_SCAN=list - Probe for NE base address using list of -# comma separated hex addresses -# -DINCLUDE_3C503 - Include 3c503 support -# -DT503_SHMEM - Use 3c503 shared memory mode (off by default) -# -DINCLUDE_WD - Include Western Digital/SMC support -# -DWD_DEFAULT_MEM- Default memory location for WD/SMC cards -# -DWD_790_PIO - Read/write to WD/SMC 790 cards in PIO mode (default -# is to use shared memory) Try this if you get "Bogus -# packet, ignoring" messages, common on ISA/PCI hybrid -# systems. -# -DCOMPEX_RL2000_FIX -# -# If you have a Compex RL2000 PCI 32-bit (11F6:1401), -# and the bootrom hangs in "Probing...[NE*000/PCI]", -# try enabling this fix... it worked for me :). -# In the first packet write somehow it somehow doesn't -# get back the expected data so it is stuck in a loop. -# I didn't bother to investigate what or why because it works -# when I interrupt the loop if it takes more then COMPEX_RL2000_TRIES. -# The code will notify if it does a abort. -# SomniOne - somnione@gmx.net -# -# 3C509 option: -# -DINCLUDE_3C509 - Include 3c509 support -# -# 3C90X options: -# -DINCLUDE_3C90X - Include 3c90x support -# -# Warning Warning Warning -# If you use any of the XCVR options below, please do not complain about -# the behaviour with Linux drivers to the kernel developers. You are -# on your own if you do this. Please read 3c90x.txt to understand -# what they do. If you don't understand them, ask for help on the -# Etherboot mailing list. And please document what you did to the NIC -# on the NIC so that people after you won't get nasty surprises. -# -# -DCFG_3C90X_PRESERVE_XCVR - Reset the transceiver type to the value it -# had initially just before the loaded code is started. -# -DCFG_3C90X_XCVR - Hardcode the tranceiver type Etherboot uses. -# -DCFG_3C90X_BOOTROM_FIX - If you have a 3c905B with buggy ROM -# interface, setting this option might "fix" it. Use -# with caution and read the docs in 3c90x.txt! -# -# See the documentation file 3c90x.txt for more details. -# -# CS89X0 (optional) options: -# -DINCLUDE_CS89X0- Include CS89x0 support -# -DCS_SCAN=list - Probe for CS89x0 base address using list of -# comma separated hex addresses; increasing the -# address by one (0x300 -> 0x301) will force a -# more aggressive probing algorithm. This might -# be neccessary after a soft-reset of the NIC. -# -# LANCE options: -# -DINCLUDE_NE2100- Include NE2100 support -# -DINCLUDE_NI6510- Include NI6510 support -# -# SK_G16 options: -# -DINCLUDE_SK_G16- Include SK_G16 support -# -# I82586 options: -# -DINCLUDE_3C507 - Include 3c507 support -# -DINCLUDE_NI5210- Include NI5210 support -# -DINCLUDE_EXOS205-Include EXOS205 support -# -# SMC9000 options: -# -DINCLUDE_SMC9000 - Include SMC9000 driver -# -DSMC9000_SCAN=list - List of I/O addresses to probe -# -# TIARA (Fujitsu Etherstar) options: -# -DINCLUDE_TIARA - Include Tiara support -# -# NI5010 options: -# -DINCLUDE_NI5010 - Include NI5010 support -# -# TULIP options: -# -DINCLUDE_TULIP - Include Tulip support -# -# RTL8139 options: -# -DINCLUDE_RTL8139 - Include RTL8139 support -# -# SIS900 options: -# -DINCLUDE_SIS900 - Include SIS900 support -# -# NATSEMI options: -# -DINCLUDE_NATSEMI - Include NATSEMI support -# - -SRCS:= -BOBJS:= - -MAKEROM= $(PERL) ./util/makerom.pl -VERSION_MAJOR= 5 -VERSION_MINOR= 3 -VERSION_PATCH= 14 -EXTRAVERSION= -VERSION= $(VERSION_MAJOR).$(VERSION_MINOR).$(VERSION_PATCH)$(EXTRAVERSION) -MM_VERSION= $(VERSION_MAJOR).$(VERSION_MINOR) -CFLAGS+= -DVERSION_MAJOR=$(VERSION_MAJOR) \ - -DVERSION_MINOR=$(VERSION_MINOR) \ - -DVERSION=\"$(VERSION)\" $(OLDGAS) \ - -I include -I arch/$(ARCH)/include \ - -DARCH=$(ARCH) -FILO=filo -FILO_PROGRAM_NAME = FILO -FILO_PROGRAM_VERSION = 0.4.1 -FILO_BUILD_INFO = ($(shell whoami)@$(shell hostname)) $(shell LANG=C date) - -GCCINCDIR = $(shell $(CC) -print-search-dirs | head -n 1 | cut -d' ' -f2)include -CPPFLAGS = -nostdinc -imacros filo/config.h -#-Ifilo/include -I$(GCCINCDIR) -MD -ASFLAGS_X = -D__ASSEMBLY__ - -IDENT= '$(@F) $(VERSION) (GPL) etherboot.org' - -# Find out if we're using binutils 2.9.1 which uses a different syntax in some -# places (most prominently in the opcode prefix area). -OLDGAS:= $(shell $(AS) --version | grep -q '2\.9\.1' && echo -DGAS291) - -BUILD_LIBS= $(BLIB) -BUILD_IMGS= $(IMGS) - -3C503FLAGS= -DINCLUDE_3C503 # -DT503_SHMEM -# Note that the suffix to MAKEROM_ is the (mixed case) basename of the ROM file -MAKEROM_3c503= -3 -3C507FLAGS= -DINCLUDE_3C507 -3C509FLAGS= -DINCLUDE_3C509 -3C529FLAGS= -DINCLUDE_3C529 -3C595FLAGS= -DINCLUDE_3C595 -3C90XFLAGS= -DINCLUDE_3C90X -CS89X0FLAGS= -DINCLUDE_CS89X0 -EEPROFLAGS= -DINCLUDE_EEPRO -EEPRO100FLAGS= -DINCLUDE_EEPRO100 -E1000FLAGS= -DINCLUDE_E1000 -EPIC100FLAGS= -DINCLUDE_EPIC100 -EXOS205FLAGS= -DINCLUDE_EXOS205 -LANCEFLAGS= -DINCLUDE_LANCE # Lance/PCI! -NE2100FLAGS= -DINCLUDE_NE2100 -NEFLAGS= -DINCLUDE_NE -DNE_SCAN=0x300,0x280,0x320,0x340,0x380 -NS8390FLAGS= -DINCLUDE_NS8390 # NE2000/PCI! -NI5010FLAGS= -DINCLUDE_NI5010 -NI5210FLAGS= -DINCLUDE_NI5210 -NI6510FLAGS= -DINCLUDE_NI6510 -RTL8139FLAGS= -DINCLUDE_RTL8139 -SK_G16FLAGS= -DINCLUDE_SK_G16 -SIS900FLAGS= -DINCLUDE_SIS900 -NATSEMIFLAGS= -DINCLUDE_NATSEMI -SMC9000FLAGS= -DINCLUDE_SMC9000 -SUNDANCEFLAGS= -DINCLUDE_SUNDANCE -TLANFLAGS= -DINCLUDE_TLAN -TIARAFLAGS= -DINCLUDE_TIARA -DEPCAFLAGS= -DINCLUDE_DEPCA # -DDEPCA_MODEL=DEPCA -DDEPCA_RAM_BASE=0xd0000 -TULIPFLAGS= -DINCLUDE_TULIP -OTULIPFLAGS= -DINCLUDE_OTULIP -VIA_RHINEFLAGS= -DINCLUDE_VIA_RHINE -WDFLAGS= -DINCLUDE_WD -DWD_DEFAULT_MEM=0xCC000 -W89C840FLAGS= -DINCLUDE_W89C840 - -SRCS+= core/serial.c - -SRCS+= core/btext.c core/pc_kbd.c - -SRCS+= core/main.c core/pci.c core/osloader.c core/nfs.c -SRCS+= core/misc.c core/config.c core/isa_probe.c core/pci_probe.c -SRCS+= core/relocate.c core/heap.c -SRCS+= drivers/disk/floppy.c core/nic.c core/disk.c core/timer.c -SRCS+= core/proto_eth_slow.c -SRCS+= core/proto_slam.c core/proto_tftm.c core/proto_http.c -SRCS+= core/isapnp.c -SRCS+= core/pcmcia.c core/i82365.c -SRCS+= core/pxe_export.c core/dns_resolver.c - -FILO_SRCS+= $(FILO)/drivers/ide_x.c -FILO_SRCS+= $(FILO)/fs/blockdev.c $(FILO)/fs/eltorito.c $(FILO)/fs/fsys_ext2fs.c $(FILO)/fs/fsys_fat.c $(FILO)/fs/fsys_iso9660.c -FILO_SRCS+= $(FILO)/fs/fsys_reiserfs.c $(FILO)/fs/vfs.c $(FILO)/fs/fsys_jfs.c $(FILO)/fs/fsys_minix.c $(FILO)/fs/fsys_xfs.c -FILO_SRCS+= $(FILO)/main/elfload.c $(FILO)/main/elfnote.c $(FILO)/main/filo_x.c $(FILO)/main/lib.c $(FILO)/main/linuxbios_x.c -FILO_SRCS+= $(FILO)/main/pci_x.c $(FILO)/main/malloc_x.c $(FILO)/main/printf_x.c $(FILO)/main/console_x.c -FILO_SRCS+= $(FILO)/$(ARCH)/context.c $(FILO)/$(ARCH)/linux_load.c $(FILO)/$(ARCH)/segment.c $(FILO)/$(ARCH)/sys_info.c -FILO_SRCS+= $(FILO)/$(ARCH)/switch.S $(FILO)/usb/debug_x.c $(FILO)/usb/scsi_cmds.c $(FILO)/usb/uhci.c $(FILO)/usb/usb.c -FILO_SRCS+= $(FILO)/usb/ohci.c $(FILO)/usb/usb_scsi_low.c $(FILO)/usb/usb_x.c - - -BOBJS+= $(BIN)/main.o $(BIN)/osloader.o $(BIN)/nfs.o $(BIN)/misc.o -BOBJS+= $(BIN)/proto_slam.o $(BIN)/proto_tftm.o $(BIN)/proto_http.o -BOBJS+= $(BIN)/floppy.o -BOBJS+= $(BIN)/serial.o $(BIN)/timer.o $(BIN)/relocate.o $(BIN)/heap.o -BOBJS+= $(BIN)/btext.o $(BIN)/pc_kbd.o -BOBJS+= $(BIN)/nic.o $(BIN)/disk.o -BOBJS+= $(BIN)/isapnp.o -BOBJS+= $(BIN)/pci.o $(BIN)/isa_probe.o $(BIN)/pci_probe.o -BOBJS+= $(BIN)/vsprintf.o $(BIN)/string.o -BOBJS+= $(BIN)/pcmcia.o $(BIN)/i82365.o -BOBJS+= $(BIN)/pxe_export.o $(BIN)/dns_resolver.o - -FILO_OBJS+= $(BIN)/ide_x.o $(BIN)/pci_x.o -FILO_OBJS+= $(BIN)/blockdev.o $(BIN)/eltorito.o $(BIN)/fsys_ext2fs.o $(BIN)/fsys_fat.o $(BIN)/fsys_iso9660.o $(BIN)/fsys_reiserfs.o $(BIN)/vfs.o -FILO_OBJS+= $(BIN)/fsys_jfs.o $(BIN)/fsys_minix.o $(BIN)/fsys_xfs.o -FILO_OBJS+= $(BIN)/elfload.o $(BIN)/elfnote.o $(BIN)/filo_x.o $(BIN)/lib.o $(BIN)/linuxbios_x.o $(BIN)/malloc_x.o $(BIN)/printf_x.o $(BIN)/console_x.o -FILO_OBJS+= $(BIN)/context.o $(BIN)/linux_load.o $(BIN)/segment.o $(BIN)/sys_info.o $(BIN)/switch.o -FILO_OBJS+= $(BIN)/debug_x.o $(BIN)/scsi_cmds.o $(BIN)/uhci.o $(BIN)/usb.o $(BIN)/ohci.o $(BIN)/usb_scsi_low.o $(BIN)/usb_x.o - -BLIB= $(BIN)/bootlib.a -FILOLIB= $(BIN)/filolib.a -LIBS= $(BLIB) -ifdef INCLUDE_FILO -LIBS+= $(FILOLIB) -endif -UTILS+= $(BIN)/nrv2b -STDDEPS= $(START) $(UTILS) -# MAKEDEPS is the one target that is depended by all ROMs, so we check gcc here -# If you are confident that gcc 2.96 works for you, you can remove the lines -# that check gcc in the toolcheck rule -MAKEDEPS+= Makefile Makefile.main Config genrules.pl Families -MAKEDEPS+= $(BIN)/toolcheck -MAKEDEPS+= arch/$(ARCH)/Makefile arch/$(ARCH)/Config - -# Start of targets - -.PHONY: noargs -noargs: $(BIN)/toolcheck - @echo '====================================================' - @echo 'No target specified. To specify a target, do: ' - @echo - @echo ' $(MAKE) bin/. ' - @echo - @echo 'where is one of {zdsk, zrom, iso, liso, zlilo, zpxe, elf, com}' - @echo - @echo 'or: ' - @echo - @echo ' $(MAKE) alls' - @echo - @echo 'to generate all possible images of format ' - @echo - @echo 'For example, ' - @echo - @echo ' make allzroms ' - @echo - @echo 'will generate all possible .zrom (rom burnable) images, and' - @echo - @echo ' make allzdsks' - @echo - @echo 'will generate all possible .zdsk (bootable floppy) images, or' - @echo - @echo '====================================================' - @exit 1 - -$(BIN)/toolcheck: Makefile Config - @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; \ - else \ - touch $(BIN)/toolcheck; \ - fi; \ - if [ `perl -e 'use bytes; print chr(255)' | wc -c` = 2 ]; \ - then \ - echo 'Your Perl version has a Unicode handling bug'; \ - echo 'To workaround, execute this before compiling Etherboot:'; \ - echo 'export LANG=$${LANG%.UTF-8}'; \ - exit 1; \ - fi - -include arch/$(ARCH)/Makefile - -# Common files - -$(BLIB): $(BOBJS) - $(AR) r $@ $(BOBJS) - $(RANLIB) $@ - -$(FILOLIB): $(FILO_OBJS) - $(AR) r $@ $(FILO_OBJS) - $(RANLIB) $@ - -# LinuxBIOS support code -$(BIN)/linuxbios.o: firmware/linuxbios/linuxbios.c include/etherboot.h include/dev.h firmware/linuxbios/linuxbios_tables.h - -# Do not add driver specific dependencies here unless it's something the -# genrules.pl script *can't* deal with, i.e. if it is not C code. - -$(FILO)/config.h: $(FILO)/Config - /bin/echo -e '/* GENERATED FILE, DO NOT EDIT */\n' >$@ - sed -e 's/#.*//' -e '/=/!d' -e 's/\([^[:space:]]*\)[[:space:]]*=[[:space:]]*\(.*\).*/#define \1 \2/' -e 's/^#define \([^ ]*\) 0$$/#undef \1/' $^ >>$@ - -filo_version: $(FILO)/main/version.h - -$(FILO)/main/version.h: FORCE - echo '#define PROGRAM_NAME "$(FILO_PROGRAM_NAME)"' > $@ - echo '#define PROGRAM_VERSION "$(FILO_PROGRAM_VERSION) $(FILO_BUILD_INFO)"' >> $@ - -FORCE: - - -# Roms file -# Builds almost silently because this rule is triggered for just about -# every modification to sources. - -$(BIN)/Roms $(BIN)/NIC: genrules.pl Families $(SRCS) - @mkdir -p $(@D) - @echo Scanning for ROMs and dependencies... - @$(PERL) ./genrules.pl Families $(BIN)/NIC $(ARCH) $(SRCS) > $(BIN)/Roms - -# Pattern Rules - -# general rules for compiling/assembling source files -$(BIN)/%.o: core/%.c $(MAKEDEPS) - $(CC) $(CFLAGS) -o $@ -c $< - -$(BIN)/%.s: core/%.c $(MAKEDEPS) - $(CC) $(CFLAGS) -S -o $@ -c $< - -$(BIN)/%.o: drivers/disk/%.c $(MAKEDEPS) - $(CC) $(CFLAGS) -o $@ -c $< - -$(BIN)/%.o: drivers/net/%.c $(MAKEDEPS) - $(CC) $(CFLAGS) -o $@ -c $< - -$(BIN)/%.o: firmware/linuxbios/%.c $(MAKEDEPS) - $(CC) $(CFLAGS) -o $@ -c $< - -$(BIN)/%.o: $(FILO)/drivers/%.c $(MAKEDEPS) $(FILO)/config.h - $(CC) $(CFLAGS) -imacros $(FILO)/config.h -o $@ -c $< - -$(BIN)/%.o: $(FILO)/fs/%.c $(MAKEDEPS) $(FILO)/config.h - $(CC) $(CFLAGS) -imacros $(FILO)/config.h -o $@ -c $< - -$(BIN)/%.o: $(FILO)/$(ARCH)/%.c $(MAKEDEPS) $(FILO)/config.h - $(CC) $(CFLAGS) -imacros $(FILO)/config.h -o $@ -c $< - -$(BIN)/%.o: $(FILO)/$(ARCH)/%.S $(MAKEDEPS) $(FILO)/config.h - $(CC) $(ASFLAGS_X) $(CPPFLAGS) -c $< -o $@ - -$(BIN)/%.o: $(FILO)/main/%.c $(MAKEDEPS) $(FILO)/config.h filo_version - $(CC) $(CFLAGS) -imacros $(FILO)/config.h -o $@ -c $< - -$(BIN)/%.o: $(FILO)/usb/%.c $(MAKEDEPS) $(FILO)/config.h - $(CC) $(CFLAGS) -imacros $(FILO)/config.h -o $@ -c $< - -# Rule for the super etherboot image. -$(BIN)/etherboot.o: $(DOBJS) - $(LD) $(LDFLAGS) -r $(DOBJS) -o $@ - -$(BIN)/etherboot-pci.o: $(PCIOBJS) - $(LD) $(LDFLAGS) -r $(PCIOBJS) -o $@ - -# General rules for generating runtime (rt) files -$(BIN)/%.rt.o: $(BIN)/%.o $(START) $(BIN)/config.o $(LIBS) $(STDDEPS) $(MAKEDEPS) - $(LD) $(LDFLAGS) -r $(START) $(BIN)/config.o $< $(LIBS) -o $@ - -# Rule for $(BIN)/%.FORMAT.rt is architecture and target-format specific - -$(BIN)/%.rt.bin: $(BIN)/%.rt $(MAKEDEPS) - $(OBJCOPY) -O binary -R .prefix $< $@ - -$(BIN)/%.rt1.bin: $(BIN)/%.rt $(MAKEDEPS) - $(OBJCOPY) -O binary -j .text.nocompress $< $@ - -$(BIN)/%.rt2.bin: $(BIN)/%.rt $(MAKEDEPS) - $(OBJCOPY) -O binary -R .prefix -R .text.nocompress $< $@ - -# Rules for generating prefix binary files - -# Rule for $(BIN)/%.FORMAT.prf is architecture and target-format specific -$(BIN)/%.prf.bin: $(BIN)/%.prf $(MAKEDEPS) - $(OBJCOPY) -j .prefix -O binary $< $@ - -# general rule for .z (compressed binary code), may be overridden -$(BIN)/%.zbin: $(BIN)/%.bin $(BIN)/nrv2b $(MAKEDEPS) - $(BIN)/nrv2b e $< $@ - -# Housekeeping - -clean: - $(RM) $(BIN)/* - $(RM) $(FILO)/config.h $(FILO)/main/version.h - -../index.html: ../index.xhtml - (cd ..; m4 -P -DHOSTSITE=SOURCEFORGE index.xhtml > index.html) - -../index-berlios.html: ../index.xhtml - (cd ..; m4 -P -DHOSTSITE=BERLIOS index.xhtml > index-berlios.html) - -tarball: ../index.html ../index-berlios.html - (echo -n $(VERSION) ''; date -u +'%Y-%m-%d') > ../VERSION - (cd ../..; tar cf /tmp/etherboot-$(VERSION).tar --exclude CVS --exclude doc etherboot-$(VERSION)) - bzip2 -9 < /tmp/etherboot-$(VERSION).tar > /tmp/etherboot-$(VERSION).tar.bz2 - gzip -9 < /tmp/etherboot-$(VERSION).tar > /tmp/etherboot-$(VERSION).tar.gz - -# Auto-incrementing build serial number. Is auto-incremented for each -# make run that specifies a final image file (e.g. bin/undi.zpxe) as a -# target, or a target of the form "all*". Enable via -DBUILD_SERIAL -# in Config. - -ifneq ($(findstring -DBUILD_SERIAL,$(CFLAGS)),) - -# If no make goals are specified, it means "make all" -REALGOALS = $(if $(MAKECMDGOALS),$(MAKECMDGOALS),all) - -# Filter to see if there are any targets to trigger an auto-increment -BUILDGOALS = $(filter all,$(REALGOALS)) $(filter all%,$(REALGOALS)) \ - $(foreach SUFFIX,$(SUFFIXES),$(filter %.$(SUFFIX),$(REALGOALS))) - -ifneq ($(strip $(BUILDGOALS)),) -# This is an auto-incrementing build. Forcibly rebuild .buildserial.h -# and mark config.o as depending on it to force its rebuilding. -bin/config.o : include/.buildserial.h -.PHONY : include/.buildserial.h -endif # BUILDGOALS - -include/.buildserial.h : - @if [ ! -f $@ ]; then echo '#define BUILD_SERIAL_NUM 0' > $@; fi - @perl -pi -e 's/(BUILD_SERIAL_NUM)\s+(\d+)/"$${1} ".($${2}+1)/e' $@ - -buildserial : include/.buildserial.h - @perl -n -e '/BUILD_SERIAL_NUM\s+(\d+)/ && ' \ - -e 'print "Build serial number is $$1\n";' $< - -else # -DBUILD_SERIAL - -buildserial : - @echo Build serial number is disabled. Enable -DBUILD_SERIAL in Config. - -endif # -DBUILD_SERIAL - -bs : buildserial - -version: - @echo $(VERSION) - -romlimit: - @echo $(ROMLIMIT) - -sources: - @echo $(SRCS) diff --git a/src/arch/armnommu/core/arm_timer.c b/src/arch/armnommu/core/arm_timer.c index b858ca8d..fef20e7b 100644 --- a/src/arch/armnommu/core/arm_timer.c +++ b/src/arch/armnommu/core/arm_timer.c @@ -9,7 +9,7 @@ #include "timer.h" #include "latch.h" #include "hardware.h" - +#include "init.h" /* get timer returns the contents of the timer */ static unsigned long get_timer(void) @@ -29,7 +29,7 @@ static unsigned long configure_timer(void) static unsigned long clocks_per_tick = 1; -void setup_timers(void) +static void setup_timers(void) { if (!clocks_per_tick) { clocks_per_tick = configure_timer(); @@ -75,3 +75,5 @@ int timer2_running(void) { return __timer_running(); } + +INIT_FN ( INIT_TIMERS, setup_timers, NULL, NULL ); diff --git a/src/arch/e1/core/e1_timer.c b/src/arch/e1/core/e1_timer.c index d3ddb644..4ed9a0fb 100644 --- a/src/arch/e1/core/e1_timer.c +++ b/src/arch/e1/core/e1_timer.c @@ -7,6 +7,7 @@ #include "etherboot.h" #include "timer.h" #include "e132_xs_board.h" +#include "init.h" /* get timer returns the contents of the timer */ static inline unsigned long get_timer(void) @@ -46,7 +47,7 @@ static unsigned long configure_timer(void) static unsigned long clocks_per_tick; -void setup_timers(void) +static void setup_timers(void) { if (!clocks_per_tick) { clocks_per_tick = configure_timer(); @@ -92,3 +93,5 @@ int timer2_running(void) { return __timer_running(); } + +INIT_FN ( INIT_TIMERS, setup_timers, NULL, NULL ); diff --git a/src/arch/i386/Config b/src/arch/i386/Config index e8ac91b8..a2126527 100644 --- a/src/arch/i386/Config +++ b/src/arch/i386/Config @@ -129,3 +129,8 @@ endif # An alternate location for isolinux.bin can be set here # ISOLINUX_BIN=/path/to/isolinux.bin + +# These seem to have some relevance to compiling on x86_64 +# EXTRA_CFLAGS=-m32 +# EXTRA_ASFLAGS=--32 +# EXTRA_LDFLAGS=-m elf_i386 diff --git a/src/arch/i386/Makefile b/src/arch/i386/Makefile index 0a80ff94..a4139e74 100644 --- a/src/arch/i386/Makefile +++ b/src/arch/i386/Makefile @@ -1,375 +1,130 @@ -ARCH_FORMAT= elf32-i386 - -# For debugging, don't delete intermediates -#.SECONDARY: - -LDSCRIPT= arch/i386/core/etherboot.lds -PLDSCRIPT= arch/i386/core/etherboot.prefix.lds - -LCONFIG+= -Ui386 - -ROMLIMIT= 524288 -CHECKSIZE= { read d1; read d1 d2 d3 size d4; [ $$size -gt $(ROMLIMIT) ] &&\ - { $(RM) $@; echo "ERROR: code size exceeds limit!"; exit 1; }; exit 0; } - -START= $(BIN)/start32.o $(BIN)/linuxbios.o \ - $(BIN)/bios.o $(BIN)/console.o $(BIN)/memsizes.o $(BIN)/basemem.o \ - $(BIN)/hidemem.o $(BIN)/e820mangler.o \ - $(BIN)/realmode.o $(BIN)/realmode_asm.o \ - $(BIN)/callbacks.o $(BIN)/pxe_callbacks.o - -SRCS+= arch/i386/prefix/floppyprefix.S -SRCS+= arch/i386/prefix/unnrv2b.S -SRCS+= arch/i386/firmware/pcbios/bios.c -SRCS+= arch/i386/firmware/pcbios/console.c -SRCS+= arch/i386/firmware/pcbios/memsizes.c -SRCS+= arch/i386/firmware/pcbios/basemem.c -SRCS+= arch/i386/firmware/pcbios/hidemem.c -SRCS+= arch/i386/firmware/pcbios/e820mangler.S -SRCS+= arch/i386/prefix/liloprefix.S -SRCS+= arch/i386/prefix/elfprefix.S -SRCS+= arch/i386/prefix/lmelf_prefix.S -SRCS+= arch/i386/prefix/elf_dprefix.S -SRCS+= arch/i386/prefix/lmelf_dprefix.S -SRCS+= arch/i386/prefix/comprefix.S -SRCS+= arch/i386/prefix/exeprefix.S -SRCS+= arch/i386/prefix/pxeprefix.S -SRCS+= arch/i386/prefix/romprefix.S - -SRCS+= arch/i386/core/init.S -SRCS+= arch/i386/core/start32.S -SRCS+= arch/i386/core/pci_io.c -SRCS+= arch/i386/core/i386_timer.c -SRCS+= arch/i386/core/elf.c -SRCS+= arch/i386/core/cpu.c -SRCS+= arch/i386/core/video_subr.c -SRCS+= arch/i386/core/pic8259.c -SRCS+= arch/i386/core/hooks.c -SRCS+= arch/i386/core/callbacks.c -SRCS+= arch/i386/core/realmode.c -SRCS+= arch/i386/core/realmode_asm.S -SRCS+= arch/i386/core/pxe_callbacks.c - -# ROM loaders: ISA and PCI versions -ISAPREFIX= $(BIN)/isaprefix.o -ISAENTRY= $(BIN)/isaprefix.entry.o -ISAEXIT= $(BIN)/isaprefix.exit.o -PCIPREFIX= $(BIN)/pciprefix.o -PCIENTRY= $(BIN)/pciprefix.entry.o -PCIEXIT= $(BIN)/pciprefix.exit.o -# Variables xxx_ROMTYPE are defined by genrules.pl. ROMENTRY and -# ROMEXIT will evaluate to give the correct objects to use. -TARGETBASE=$(patsubst $(BIN)/%,%,$(firstword $(subst ., ,$@))) -ROMCARD=$(firstword $(subst --, ,$(TARGETBASE))) -ROMTYPE=$(firstword $(ROMTYPE_$(ROMCARD)) ISA) -romENTRY=$($(ROMTYPE)ENTRY) -romEXIT=$($(ROMTYPE)EXIT) - -# Target type for generic prf rules -TARGETTYPE=$(patsubst .%,%, $(suffix $(basename $@))) -TARGETENTRY=$($(TARGETTYPE)ENTRY) -TARGETEXIT=$($(TARGETTYPE)EXIT) - -# Other real-mode entry loaders -dskPREFIX= $(BIN)/floppyprefix.o -dskENTRY= $(BIN)/floppyprefix.entry.o -dskEXIT= $(BIN)/floppyprefix.exit.o -comPREFIX= $(BIN)/comprefix.o -comENTRY= $(BIN)/comprefix.entry.o -comEXIT= $(BIN)/comprefix.exit.o -exePREFIX= $(BIN)/exeprefix.o -exeENTRY= $(BIN)/exeprefix.entry.o -exeEXIT= $(BIN)/exeprefix.exit.o -liloPREFIX= $(BIN)/liloprefix.o -liloENTRY= $(BIN)/liloprefix.entry.o -liloEXIT= $(BIN)/liloprefix.exit.o -bImagePREFIX= $(BIN)/bImageprefix.o -bImageENTRY= $(BIN)/bImageprefix.entry.o -bImageEXIT= $(BIN)/bImageprefix.exit.o -pxePREFIX= $(BIN)/pxeprefix.o -pxeENTRY= $(BIN)/pxeprefix.entry.o -pxeEXIT= $(BIN)/pxeprefix.exit.o -rawPREFIX= $(BIN)/nullprefix.o -rawENTRY= $(BIN)/nullprefix.entry.o -rawEXIT= $(BIN)/nullprefix.exit.o - -# Protected mode entry loaders -elfPREFIX= $(BIN)/elfprefix.o -elfENTRY= $(BIN)/elfprefix.entry.o -elfEXIT= $(BIN)/elfprefix.exit.o -lmelfPREFIX= $(BIN)/lmelf_prefix.o -lmelfENTRY= $(BIN)/lmelf_prefix.entry.o -lmelfEXIT= $(BIN)/lmelf_prefix.exit.o -elfdPREFIX= $(BIN)/elf_dprefix.o -elfdENTRY= $(BIN)/elf_dprefix.entry.o -elfdEXIT= $(BIN)/elf_dprefix.exit.o -lmelfdPREFIX= $(BIN)/lmelf_dprefix.o -lmelfdENTRY= $(BIN)/lmelf_dprefix.entry.o -lmelfdEXIT= $(BIN)/lmelf_dprefix.exit.o - -include $(BIN)/Roms - -all: $(ROMS) -allroms: $(ROMS) -allzroms: $(ROMS) -alldsks: $(EB_DSKS) -allzdsks: $(EB_ZDSKS) -alllilos: $(EB_LILOS) -allzlilos: $(EB_ZLILOS) -allbImages: $(EB_BIMAGES) -allbzImages: $(EB_BZIMAGES) -allpxes: $(EB_PXES) -allzpxes: $(EB_ZPXES) -allelfs: $(EB_ELFS) -allzelfs: $(EB_ZELFS) -alllmelfs: $(EB_LMELFS) -allzlmelfs: $(EB_ZLMELFS) -allelfds: $(EB_ELFDS) -allzelfds: $(EB_ZELFDS) -alllmelfds: $(EB_LMELFDS) -allzlmelfds: $(EB_ZLMELFDS) -allcoms: $(EB_COMS) -allexes: $(EB_EXES) -allisos: $(EB_ISOS) -alllisos: $(EB_LISOS) - -BOBJS+= $(BIN)/pci_io.o $(BIN)/i386_timer.o -BOBJS+= $(BIN)/elf.o $(BIN)/cpu.o $(BIN)/video_subr.o -BOBJS+= $(BIN)/pic8259.o $(BIN)/hooks.o - -# ROM loaders - -$(ISAPREFIX): arch/i386/prefix/romprefix.S $(MAKEDEPS) - $(CPP) $(CFLAGS) $(LCONFIG) -Ui386 -D ASSEMBLY $< \ - | $(AS) $(ASFLAGS) -o $@ - -$(PCIPREFIX): arch/i386/prefix/romprefix.S $(MAKEDEPS) - $(CPP) -DPCI_PNP_HEADER $(CFLAGS) $(LCONFIG) -Ui386 -D ASSEMBLY $< \ - | $(AS) $(ASFLAGS) -o $@ - -# Prefix splitters -$(BIN)/%prefix.entry.o: $(BIN)/%prefix.o $(MAKEDEPS) - $(OBJCOPY) -R .text16 $< $@ - -$(BIN)/%prefix.exit.o: $(BIN)/%prefix.o $(MAKEDEPS) - $(OBJCOPY) -R .prefix $< $@ - -# Generic prefix objects -PREFIXOBJS = $(BIN)/init.o -ZPREFIXOBJS = $(BIN)/init.o $(BIN)/unnrv2b.o - -# Utilities -$(BIN)/nrv2b: util/nrv2b.c - $(HOST_CC) -O2 -DENCODE -DDECODE -DMAIN -DVERBOSE -DNDEBUG -DBITSIZE=32 -DENDIAN=0 -o $@ $< - -ZFILELEN = perl util/zfilelen.pl - -# Pattern Rules - -# General for compiling/assembly source files - -$(BIN)/%.o: arch/i386/core/%.c $(MAKEDEPS) - $(CC) $(CFLAGS) -o $@ -c $< - -$(BIN)/%.o: arch/i386/core/%.S $(MAKEDEPS) - $(CPP) $(CFLAGS) -Ui386 -D ASSEMBLY $< | $(AS) $(ASFLAGS) -o $@ - -$(BIN)/%.o: arch/i386/firmware/pcbios/%.c $(MAKEDEPS) - $(CC) $(CFLAGS) -o $@ -c $< - -$(BIN)/%.o: arch/i386/firmware/pcbios/%.S $(MAKEDEPS) - $(CPP) $(CFLAGS) -Ui386 -DASSEMBLY $< | $(AS) $(ASFLAGS) -o $@ - -$(BIN)/%.o: arch/i386/prefix/%.S $(MAKEDEPS) - $(CPP) $(CFLAGS) -Ui386 -DASSEMBLY $< | $(AS) $(ASFLAGS) -o $@ - -$(BIN)/%16.o: arch/i386/prefix/%.S $(MAKEDEPS) - $(CPP) $(CFLAGS) -Ui386 -DASSEMBLY -DCODE16 $< | $(AS) $(ASFLAGS) -o $@ - -# general rule for 16bit .o, may be overridden -$(BIN)/%.o: $(BIN)/%.s - $(AS) $(ASFLAGS) -o $@ $< - -# general rule for .bin (plain binary loader code), may be overridden -$(BIN)/%.bin: $(BIN)/%.o - $(OBJCOPY) -O binary $< $@ - -# general rule for .z (compressed binary code), may be overridden -# rule for .z is in top level Makefile -# Give the directory name, e.g. use $(BIN)/rtl8139.com as the target. - -$(BIN)/%.zo: $(BIN)/%.zbin arch/i386/core/prefixzdata.lds $(MAKEDEPS) - $(LD) -T arch/i386/core/prefixzdata.lds -b binary $< -o $@ - -$(BIN)/%.uo: $(BIN)/%.bin arch/i386/core/prefixudata.lds $(MAKEDEPS) - $(LD) -T arch/i386/core/prefixudata.lds -b binary $< -o $@ - -# Intermediate prf rules - -%.prf: %.rt $(PREFIXOBJS) %.rt1.uo %.rt2.uo $(MAKEDEPS) - $(MAKE) $(TARGETENTRY) - $(LD) $(LDFLAGS) -T $(PLDSCRIPT) $(TARGETENTRY) -R $(subst $(MAKEDEPS),,$^) -o $@ - -%.zprf: %.rt $(ZPREFIXOBJS) %.rt1.uo %.rt2.zo $(MAKEDEPS) - $(MAKE) $(TARGETENTRY) - $(LD) $(LDFLAGS) -T $(PLDSCRIPT) $(TARGETENTRY) -R $(subst $(MAKEDEPS),,$^) -o $@ - -# general rules for normal/compressed ROM images, may be overridden -SUFFIXES += rom zrom - -$(BIN)/%.rom.rt: $(BIN)/%.rt.o $(ISAENTRY) $(PCIENTRY) $(ISAEXIT) $(PCIEXIT) $(LDSCRIPT) $(MAKEDEPS) - $(LD) $(LDFLAGS) -T $(LDSCRIPT) -o $@ $(romEXIT) $< - @$(SIZE) $@ | $(CHECKSIZE) - -$(BIN)/%.rom: $(BIN)/%.rom.prf - $(OBJCOPY) -O binary $< $@ - $(MAKEROM) $(MAKEROM_FLAGS) $(MAKEROM_$(ROMCARD)) $(MAKEROM_ID_$(ROMCARD)) -i$(IDENT) $@ - -$(BIN)/%.zrom: $(BIN)/%.rom.zprf - $(OBJCOPY) -O binary $< $@ - $(MAKEROM) $(MAKEROM_FLAGS) $(MAKEROM_$(ROMCARD)) $(MAKEROM_ID_$(ROMCARD)) -i$(IDENT) $@ - -# general rules for ELF images -SUFFIXES += elf zelf -$(BIN)/%.elf.rt: $(BIN)/%.rt.o $(elfENTRY) $(elfEXIT) $(LDSCRIPT) $(MAKEDEPS) - $(LD) $(LDFLAGS) -T $(LDSCRIPT) -o $@ $(elfEXIT) $< - -$(BIN)/%.elf: $(BIN)/%.elf.prf - $(OBJCOPY) -O binary $< $@ - -$(BIN)/%.zelf: $(BIN)/%.elf.zprf - $(OBJCOPY) -O binary $< $@ - -# general rules for Long Mode ELF images -SUFFIXES += lmelf zlmelf -$(BIN)/%.lmelf.rt: $(BIN)/%.rt.o $(lmelfENTRY) $(lmelfEXIT) $(LDSCRIPT) $(MAKEDEPS) - $(LD) $(LDFLAGS) -T $(LDSCRIPT) -o $@ $(lmelfEXIT) $< - -$(BIN)/%.lmelf: $(BIN)/%.lmelf.prf - $(OBJCOPY) -O binary $< $@ - -$(BIN)/%.zlmelf: $(BIN)/%.lmelf.zprf - $(OBJCOPY) -O binary $< $@ - -# general rules for ELF dynamic images -SUFFIXES += elfd zelfd -$(BIN)/%.elfd.rt: $(BIN)/%.rt.o $(elfdENTRY) $(elfdEXIT) $(LDSCRIPT) $(MAKEDEPS) - $(LD) $(LDFLAGS) -T $(LDSCRIPT) -o $@ $(elfdEXIT) $< - -$(BIN)/%.elfd: $(BIN)/%.elfd.prf - $(OBJCOPY) -O binary $< $@ - -$(BIN)/%.zelfd: $(BIN)/%.elfd.zprf - $(OBJCOPY) -O binary $< $@ - -# general rules for Long Mode ELF dynamic images -SUFFIXES += lmelfd zlmelfd -$(BIN)/%.lmelfd.rt: $(BIN)/%.rt.o $(lmelfdENTRY) $(lmelfdEXIT) $(LDSCRIPT) $(MAKEDEPS) - $(LD) $(LDFLAGS) -T $(LDSCRIPT) -o $@ $(lmelfdEXIT) $< - -$(BIN)/%.lmelfd: $(BIN)/%.lmelfd.prf - $(OBJCOPY) -O binary $< $@ - -$(BIN)/%.zlmelfd: $(BIN)/%.lmelfd.zprf - $(OBJCOPY) -O binary $< $@ - -# rules to generate a DOS loadable .com executable -SUFFIXES += com -$(BIN)/%.com.rt: $(BIN)/%.rt.o $(comENTRY) $(comEXIT) $(LDSCRIPT) $(MAKEDEPS) - $(LD) $(LDFLAGS) -T $(LDSCRIPT) -o $@ $< $(comEXIT) - -$(BIN)/%.com: $(BIN)/%.com.zprf - $(OBJCOPY) -O binary $< $@ - -# rules to generate a DOS loadable .exe executable -SUFFIXES += exe -$(BIN)/%.exe.rt: $(BIN)/%.rt.o $(exeENTRY) $(exeEXIT) $(LDSCRIPT) $(MAKEDEPS) - $(LD) $(LDFLAGS) -T $(LDSCRIPT) -o $@ $< $(exeEXIT) - @$(SIZE) $@ | $(CHECKSIZE) - -$(BIN)/%.exe: $(BIN)/%.exe.prf - $(OBJCOPY) -O binary $< $@ - -# rules to make a LILO loadable image -SUFFIXES += lilo zlilo - -$(BIN)/%.lilo.rt: $(BIN)/%.rt.o $(liloENTRY) $(liloEXIT) $(LDSCRIPT) $(MAKEDEPS) - $(LD) $(LDFLAGS) -T $(LDSCRIPT) -o $@ $< $(liloEXIT) - @$(SIZE) $@ | $(CHECKSIZE) - -$(BIN)/%.lilo: $(BIN)/%.lilo.prf - $(OBJCOPY) -O binary $< $@ - -$(BIN)/%.zlilo: $(BIN)/%.lilo.zprf - $(OBJCOPY) -O binary $< $@ - -# rules to make big linux boot protocol image -SUFFIXES += bImage bzImage - -$(BIN)/%.bImage.rt: $(BIN)/%.rt.o $(bImageENTRY) $(bImageEXIT) $(LDSCRIPT) $(MAKEDEPS) - $(LD) $(LDFLAGS) -T $(LDSCRIPT) -o $@ $< $(bImageEXIT) - -$(BIN)/%.bImage: $(BIN)/%.bImage.prf - $(OBJCOPY) -O binary $< $@ - -$(BIN)/%.bzImage: $(BIN)/%.bImage.zprf - $(OBJCOPY) -O binary $< $@ - - -# rules to generate a PXE loadable image -SUFFIXES += pxe zpxe - -$(BIN)/%.pxe.rt: $(BIN)/%.rt.o $(pxeENTRY) $(pxeEXIT) $(LDSCRIPT) $(MAKEDEPS) - $(LD) $(LDFLAGS) -T $(LDSCRIPT) -o $@ $< $(pxeEXIT) - @$(SIZE) $@ | $(CHECKSIZE) - -$(BIN)/%.pxe: $(BIN)/%.pxe.prf - $(OBJCOPY) -O binary $< $@ - -$(BIN)/%.zpxe: $(BIN)/%.pxe.zprf - $(OBJCOPY) -O binary $< $@ - -# rules to generate the .dsk/.zdsk floppy images -SUFFIXES += dsk zdsk - -$(BIN)/%.dsk.rt: $(BIN)/%.rt.o $(dskENTRY) $(dskEXIT) $(LDSCRIPT) $(MAKEDEPS) - $(LD) $(LDFLAGS) -T $(LDSCRIPT) -o $@ $< $(dskEXIT) - @$(SIZE) $@ | $(CHECKSIZE) - -$(BIN)/%.dsk: $(BIN)/%.dsk.prf - $(OBJCOPY) -O binary $< $@ - -$(BIN)/%.zdsk: $(BIN)/%.dsk.zprf - $(OBJCOPY) -O binary $< $@ - -# rules to write the .dsk/.zdsk image onto a blank floppy -SUFFIXES += fd0 zfd0 -%.fd0: %.dsk +# i386-specific directories containing source files +# +SRCDIRS += arch/i386/core arch/i386/transitions arch/i386/prefix +SRCDIRS += arch/i386/firmware/pcbios arch/i386/firmware/linuxbios +SRCDIRS += arch/i386/drivers/net + +# The various xxx_loader.c files are #included into core/loader.c and +# should not be compiled directly. +# +NON_AUTO_SRCS += arch/i386/core/aout_loader.c +NON_AUTO_SRCS += arch/i386/core/freebsd_loader.c +NON_AUTO_SRCS += arch/i386/core/multiboot_loader.c +NON_AUTO_SRCS += arch/i386/core/tagged_loader.c +NON_AUTO_SRCS += arch/i386/core/wince_loader.c + +# setup.S and unnrv2b.S are both used to generate 16-bit as well as +# 32-bit objects. +# +OBJS_setup = setup setup16 +CFLAGS_setup16 = -DCODE16 +OBJS_unnrv2b = unnrv2b unnrv2b16 +CFLAGS_unnrv2b16 = -DCODE16 + +# hooks.c is used to generate hooks.o and hooks_rm.o +# +OBJS_hooks = hooks hooks_rm +CFLAGS_hooks_rm = -DREALMODE + +# We need to undefine the default macro "i386" when compiling .S +# files, otherwise ".arch i386" translates to ".arch 1"... +# +CFLAGS_S += -Ui386 + +# The i386 linker script +# +LDSCRIPT = arch/i386/scripts/i386.lds + +# Media types. +# +# It's ugly that we have to define these repetitive combinations by +# hand. Unforunately, $(eval ...) is available only in make >= 3.80, +# and using an external Makefile fragment doesn't work because +# OBJS_xxx need to be defined *before* the external Makefile fragments +# for the source files are generated... + +CFLAGS_ZPREFIX = -DCOMPRESS + +MEDIA += rom +OBJS_romprefix = isaprefix zisaprefix pciprefix zpciprefix +CFLAGS_isaprefix = +CFLAGS_zisaprefix = $(CFLAGS_ZPREFIX) +CFLAGS_pciprefix = -DPCI_PNP_HEADER +CFLAGS_zpciprefix = $(CFLAGS_pciprefix) $(CFLAGS_ZPREFIX) + +MEDIA += pxe +OBJS_pxeprefix = pxeprefix zpxeprefix +CFLAGS_zpxeprefix = $(CFLAGS_ZPREFIX) + +MEDIA += elf +OBJS_elfprefix = elfprefix zelfprefix +CFLAGS_zelfprefix = $(CFLAGS_ZPREFIX) + +MEDIA += elfd +OBJS_elfdprefix = elfdprefix zelfdprefix +CFLAGS_zelfdprefix = $(CFLAGS_ZPREFIX) + +MEDIA += lmelf +OBJS_lmelfprefix = lmelfprefix zlmelfprefix +CFLAGS_zlmelfprefix = $(CFLAGS_ZPREFIX) + +MEDIA += lmelfd +OBJS_lmelfdprefix = lmelfdprefix zlmelfdprefix +CFLAGS_zlmelfdprefix = $(CFLAGS_ZPREFIX) + +MEDIA += lilo +OBJS_liloprefix = liloprefix zliloprefix +CFLAGS_zliloprefix = $(CFLAGS_ZPREFIX) + +MEDIA += bImage +OBJS_bImageprefix = bImageprefix zbImageprefix +CFLAGS_zbImageprefix = $(CFLAGS_ZPREFIX) + +MEDIA += dsk +OBJS_dskprefix = dskprefix zdskprefix +CFLAGS_zdskprefix = $(CFLAGS_ZPREFIX) + +MEDIA += raw +OBJS_rawprefix = rawprefix zrawprefix +CFLAGS_zrawprefix = $(CFLAGS_ZPREFIX) + +# These media cannot handle compressed payloads + +MEDIA += com + +MEDIA += exe + +# Some suffixes (e.g. %.zfd0) are generated directly from other +# finished files (e.g. %.zdsk), rather than having their own prefix. + +# rule to write disk images to /dev/fd0 +NON_AUTO_MEDIA += fd0 +%fd0 : %dsk dd if=$< bs=512 conv=sync of=/dev/fd0 sync -%.zfd0: %.zdsk - dd if=$< bs=512 conv=sync of=/dev/fd0 - sync - -# rules to create raw executable images -SUFFIXES += raw zraw -$(BIN)/%.raw.rt: $(BIN)/%.rt.o $(rawENTRY) $(rawEXIT) $(LDSCRIPT) $(MAKEDEPS) - $(LD) $(LDFLAGS) -T $(LDSCRIPT) -o $@ $< $(rawEXIT) - -$(BIN)/%.raw: $(BIN)/%.raw.prf - $(OBJCOPY) -O binary $< $@ - -$(BIN)/%.zraw: $(BIN)/%.raw.zprf - $(OBJCOPY) -O binary $< $@ - # rule to make a non-emulation ISO boot image -SUFFIXES += iso -%.iso: util/geniso %.zlilo - ISOLINUX_BIN=${ISOLINUX_BIN} bash util/geniso $*.iso $*.zlilo +NON_AUTO_MEDIA += iso +%iso: %lilo util/geniso + ISOLINUX_BIN=$(ISOLINUX_BIN) bash util/geniso $@ $< # rule to make a floppy emulation ISO boot image -SUFFIXES += liso -%.liso: util/genliso %.zlilo - bash util/genliso $*.liso $*.zlilo +NON_AUTO_MEDIA += liso +%liso: %lilo util/genliso + bash util/genliso $@ $< +# 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/src/arch/i386/README.i386 b/src/arch/i386/README.i386 new file mode 100644 index 00000000..b9b79cc4 --- /dev/null +++ b/src/arch/i386/README.i386 @@ -0,0 +1,197 @@ +Etherboot/NILO i386 initialisation path and external call interface +=================================================================== + +1. Background + +GCC compiles 32-bit code. It is capable of producing +position-independent code, but the resulting binary is about 25% +bigger than the corresponding fixed-position code. Since one main use +of Etherboot is as firmware to be burned into an EPROM, code size must +be kept as small as possible. + +This means that we want to compile fixed-position code with GCC, and +link it to have a predetermined start address. The problem then is +that we must know the address that the code will be loaded to when it +runs. There are several ways to solve this: + +1. Pick an address, link the code with this start address, then make + sure that the code gets loaded at that location. This is + problematic, because we may pick an address that we later end up + wanting to use to load the operating system that we're booting. + +2. Pick an address, link the code with this start address, then set up + virtual addressing so that the virtual addresses match the + link-time addresses regardless of the real physical address that + the code is loaded to. This enables us to relocate Etherboot to + the top of high memory, where it will be out of the way of any + loading operating system. + +3. Link the code with a text start address of zero and a data start + address also of zero. Use 16-bit real mode and the + quasi-position-independence it gives you via segment addressing. + Doing this requires that we generate 16-bit code, rather than + 32-bit code, and restricts us to a maximum of 64kB in each segment. + +There are other possible approaches (e.g. including a relocation table +and code that performs standard dynamic relocation), but the three +options listed above are probably the best available. + +Etherboot can be invoked in a variety of ways (ROM, floppy, as a PXE +NBP, etc). Several of these ways involve control being passed to +Etherboot with the CPU in 16-bit real mode. Some will involve the CPU +being in 32-bit protected mode, and there's an outside chance that +some may involve the CPU being in 16-bit protected mode. We will +almost certainly have to effect a CPU mode change in order to reach +the mode we want to be in to execute the C code. + +Additionally, Etherboot may wish to call external routines, such as +BIOS interrupts, which must be called in 16-bit real mode. When +providing a PXE API, Etherboot must provide a mechanism for external +code to call it from 16-bit real mode. + +Not all i386 builds of Etherboot will want to make real-mode calls. +For example, when built for LinuxBIOS rather than the standard PCBIOS, +no real-mode calls are necessary. + +For the ultimate in PXE compatibility, we may want to build Etherboot +to run permanently in real mode. + +There is a wide variety of potential combinations of mode switches +that we may wish to implement. There are additional complications, +such as the inability to access a high-memory stack when running in +real mode. + +2. Transition libraries + +To handle all these various combinations of mode switches, we have +several "transition" libraries in Etherboot. We also have the concept +of an "internal" and an "external" environment. The internal +environment is the environment within which we can execute C code. +The external environment is the environment of whatever external code +we're trying to interface to, such as the system BIOS or a PXE NBP. + +As well as having a separate addressing scheme, the internal +environment also has a separate stack. + +The transition libraries are: + +a) librm + +librm handles transitions between an external 16-bit real-mode +environment and an internal 32-bit protected-mode environment with +virtual addresses. + +b) libkir + +libkir handles transitions between an external 16-bit real-mode (or +16:16 or 16:32 protected-mode) environment and an internal 16-bit +real-mode (or 16:16 protected-mode) environment. + +c) libpm + +libpm handles transitions between an external 32-bit protected-mode +environment with flat physical addresses and an internal 32-bit +protected-mode environment with virtual addresses. + +The transition libraries handle the transitions required when +Etherboot is started up for the first time, the transitions required +to execute any external code, and the transitions required when +Etherboot exits (if it exits). When Etherboot provides a PXE API, +they also handle the transitions required when a PXE client makes a +PXE API call to Etherboot. + +Etherboot may use multiple transition libraries. For example, an +Etherboot ELF image does not require librm for its initial transitions +from prefix to runtime, but may require librm for calling external +real-mode functions. + +3. Setup and initialisation + +Etherboot is conceptually divided into the prefix, the decompressor, +and the runtime image. (For non-compressed images, the decompressor +is a no-op.) The complete image comprises all three parts and is +distinct from the runtime image, which exclude the prefix and the +decompressor. + +The prefix does several tasks: + + Load the complete image into memory. (For example, the floppy + prefix issues BIOS calls to load the remainder of the complete image + from the floppy disk into RAM, and the ISA ROM prefix copies the ROM + contents into RAM for faster access.) + + Call the decompressor, if the runtime image is compressed. This + decompresses the runtime image. + + Call the runtime image's setup() routine. This is a routine + implemented in assembly code which sets up the internal environment + so that C code can execute. + + Call the runtime image's arch_initialise() routine. This is a + routine implemented in C which does some basic startup tasks, such + as initialising the console device, obtaining a memory map and + relocating the runtime image to high memory. + + Call the runtime image's arch_main() routine. This records the exit + mechanism requested by the prefix and calls main(). (The prefix + needs to register an exit mechanism because by the time main() + returns, the memory occupied by the prefix has most likely been + overwritten.) + +When acting as a PXE ROM, the ROM prefix contains an UNDI loader +routine in addition to its usual code. The UNDI loader performs a +similar sequence of steps: + + Load the complete image into memory. + + Call the decompressor. + + Call the runtime image's setup() routine. + + Call the runtime image's arch_initialise() routine. + + Call the runtime image's install_pxe_stack() routine. + + Return to caller. + +The runtime image's setup() routine will perform the following steps: + + Switch to the internal environment using an appropriate transition + library. This will record the parameters of the external + environment. + + Set up the internal environment: load a stack, and set up a GDT for + virtual addressing if virtual addressing is to be used. + + Switch back to the external environment using the transition + library. This will record the parameters of the internal + environment. + +Once the setup() routine has returned, the internal environment has been +set up ready for C code to run. The prefix can call C routines using +a function from the transition library. + +The runtime image's arch_initialise() routine will perform the +following steps: + + Zero the bss + + Initialise the console device(s) and print a welcome message. + + Obtain a memory map via the INT 15,E820 BIOS call or suitable + fallback mechanism. [not done if libkir is being used] + + Relocate the runtime image to the top of high memory. [not done if + libkir is being used] + + Install librm to base memory. [done only if librm is being used] + + Call initialise(). + + Return to the prefix, setting registers to indicate to the prefix + the new location of the transition library, if applicable. Which + registers these are is specific to the transition library being + used. + +Once the arch_initialise() routine has returned, the prefix will +probably call arch_main(). diff --git a/src/arch/i386/core/callbacks.c b/src/arch/i386/core/callbacks.c index d45e63e2..8818e146 100644 --- a/src/arch/i386/core/callbacks.c +++ b/src/arch/i386/core/callbacks.c @@ -9,7 +9,6 @@ #include "etherboot.h" #include "callbacks.h" #include "realmode.h" -#include "segoff.h" #include /* Maximum amount of stack data that prefix may request to be passed diff --git a/src/arch/i386/core/cpu.c b/src/arch/i386/core/cpu.c index 8a0f7333..7b2533f4 100644 --- a/src/arch/i386/core/cpu.c +++ b/src/arch/i386/core/cpu.c @@ -2,6 +2,7 @@ #include "stdint.h" #include "string.h" #include "bits/cpu.h" +#include "init.h" /* Standard macro to see if a specific flag is changeable */ @@ -83,4 +84,7 @@ void cpu_setup(void) { identify_cpu(&cpu_info); } + +INIT_FN ( INIT_CPU, cpu_setup, NULL, NULL ); + #endif /* CONFIG_X86_64 */ diff --git a/src/arch/i386/core/elf.c b/src/arch/i386/core/elf.c index 6ef78c71..40a18a1f 100644 --- a/src/arch/i386/core/elf.c +++ b/src/arch/i386/core/elf.c @@ -1,5 +1,6 @@ #include "etherboot.h" #include "elf.h" +#include "memsizes.h" #define NAME "Etherboot" diff --git a/src/arch/i386/core/hooks.c b/src/arch/i386/core/hooks.c index 9ca6f480..32a137b1 100644 --- a/src/arch/i386/core/hooks.c +++ b/src/arch/i386/core/hooks.c @@ -1,35 +1,93 @@ -#include "etherboot.h" -#include "callbacks.h" -#include - -void arch_main ( in_call_data_t *data __unused, va_list params __unused ) -{ -#ifdef PCBIOS - /* Deallocate base memory used for the prefix, if applicable - */ - forget_prefix_base_memory(); +#include "stdint.h" +#include "stddef.h" +#include "registers.h" +#include "string.h" +#include "hooks.h" +#include "init.h" +#include "main.h" +#ifdef REALMODE +#include "realmode.h" #endif -} +/* Symbols defined by the linker */ +extern char _bss[], _ebss[]; -void arch_relocated_from (unsigned long old_addr ) +/* + * This file provides the basic entry points from assembly code. See + * README.i386 for a description of the entry code path. + * + * This file is compiled to two different object files: hooks.o and + * hooks_rm.o. REALMODE is defined when compiling hooks_rm.o + * + */ + +/* + * arch_initialise(): perform any required initialisation such as + * setting up the console device and relocating to high memory. Note + * that if we relocate to high memory and the prefix is in base + * memory, then we will need to install a copy of librm in base memory + * and adjust retaddr so that we return to the installed copy. + * + */ +#ifdef REALMODE +void arch_rm_initialise ( struct i386_all_regs *regs, + void (*retaddr) (void) ) +#else /* REALMODE */ +void arch_initialise ( struct i386_all_regs *regs, + void (*retaddr) (void) __unused ) +#endif /* REALMODE */ { + /* Zero the BSS */ + memset ( _bss, 0, _ebss - _bss ); -#ifdef PCBIOS - /* Deallocate base memory used for the Etherboot runtime, - * if applicable + /* Call all registered initialisation functions. */ - forget_runtime_base_memory( old_addr ); -#endif - + call_init_fns (); } -void arch_on_exit ( int exit_status __unused ) -{ -#ifdef PCBIOS - /* Deallocate the real-mode stack now. We will reallocate - * the stack if are going to use it after this point. +#ifdef REALMODE + +/* + * arch_rm_main() : call main() and then exit via whatever exit mechanism + * the prefix requested. + * + */ +void arch_rm_main ( struct i386_all_regs *regs ) { + struct i386_all_regs regs_copy; + void (*exit_fn) ( struct i386_all_regs *regs ); + + /* Take a copy of the registers, because the memory holding + * them will probably be trashed by the time main() returns. */ - forget_real_mode_stack(); -#endif + regs_copy = *regs; + exit_fn = ( typeof ( exit_fn ) ) regs_copy.eax; + + /* Call to main() */ + regs_copy.eax = main(); + + /* Call registered per-object exit functions */ + call_exit_fns (); + + if ( exit_fn ) { + /* Prefix requested that we use a particular function + * as the exit path, so we call this function, which + * must not return. + */ + exit_fn ( ®s_copy ); + } } + +#else /* REALMODE */ + +/* + * arch_main() : call main() and return + * + */ +void arch_main ( struct i386_all_regs *regs ) { + regs->eax = main(); + + /* Call registered per-object exit functions */ + call_exit_fns (); +}; + +#endif /* REALMODE */ diff --git a/src/arch/i386/core/i386_timer.c b/src/arch/i386/core/i386_timer.c index 531183d4..c9aa406f 100644 --- a/src/arch/i386/core/i386_timer.c +++ b/src/arch/i386/core/i386_timer.c @@ -10,6 +10,7 @@ #include "etherboot.h" #include "timer.h" #include "latch.h" +#include "init.h" void __load_timer2(unsigned int ticks) { @@ -40,7 +41,7 @@ static int __timer2_running(void) } #if !defined(CONFIG_TSC_CURRTICKS) -void setup_timers(void) +static void setup_timers(void) { return; } @@ -126,7 +127,7 @@ bad_ctc: } static unsigned long clocks_per_tick; -void setup_timers(void) +static void setup_timers(void) { if (!clocks_per_tick) { clocks_per_tick = calibrate_tsc(); @@ -189,3 +190,5 @@ int timer2_running(void) } #endif /* RTC_CURRTICKS */ + +INIT_FN ( INIT_TIMERS, setup_timers, NULL, NULL ); diff --git a/src/arch/i386/core/init.S b/src/arch/i386/core/init.S deleted file mode 100644 index 71717c25..00000000 --- a/src/arch/i386/core/init.S +++ /dev/null @@ -1,305 +0,0 @@ -#include "callbacks.h" - .equ CR0_PE, 1 - - .text - .arch i386 - .section ".prefix", "ax", @progbits - -#undef CODE16 -#if defined(PCBIOS) -#define CODE16 -#endif - -/* We have two entry points: "conventional" (at the start of the file) - * and "callback" (at _entry, 2 bytes in). The "callback" entry - * should be used if the caller wishes to provide a specific opcode. - * It is equivalent to a call to in_call. Using the "conventional" - * entry point is equivalent to using the "callback" entry point with - * an opcode of EB_OPCODE_MAIN. - * - * Both entry points can be called in either 16-bit real or 32-bit - * protected mode with flat physical addresses. We detect which mode - * the processor is in and call either in_call or rm_in_call as - * appropriate. Note that the mode detection code must therefore be - * capable of doing the same thing in either mode, even though the - * machine code instructions will be interpreted differently. - * - * The decompressor will be invoked if necessary to decompress - * Etherboot before attempting to jump to it. - */ - -/****************************************************************************** - * Entry points and mode detection code - ****************************************************************************** - */ - - .code32 -/* "Conventional" entry point: caller provides no opcode */ - .globl _start -_start: - /* Set flag to indicate conventional entry point used */ - pushl $0 /* "pushw $0" in 16-bit code */ - /* Fall through to "callback" entry point */ - -/* "Callback" entry point */ - .globl _entry -_entry: - -#ifdef CODE16 - /* CPU mode detection code */ - pushl %eax /* "pushw %ax" in 16-bit code */ - pushw %ax /* "pushl %eax" in 16-bit code */ - movl %cr0, %eax /* Test protected mode bit */ - testb $CR0_PE, %al - popw %ax /* "popl %eax" in 16-bit code */ - popl %eax /* "popw %eax" in 16-bit code */ - jz rmode -#endif /* CODE16 */ - -/****************************************************************************** - * Entered in protected mode - ****************************************************************************** - */ - - .code32 -pmode: - cmpl $0, 0(%esp) /* Conventional entry point used? */ - jne 1f - /* Entered via conventional entry point: set up stack */ - xchgl %eax, 4(%esp) /* %eax = return addr, store %eax */ - movl %eax, 0(%esp) /* 0(%esp) = return address */ - movl $(EB_OPCODE_MAIN|EB_USE_INTERNAL_STACK|EB_SKIP_OPCODE), %eax - xchgl %eax, 4(%esp) /* 4(%esp) = opcode, restore %eax */ -1: - /* Run decompressor if necessary */ - pushl %eax - movl $decompress, %eax - testl %eax, %eax - jz 1f - call decompress -1: popl %eax - - /* Make in_call to Etherboot */ - jmp _prefix_in_call - -/****************************************************************************** - * Entered in real mode - ****************************************************************************** - */ - -#ifdef CODE16 - .code16 -rmode: - pushw %ax /* Padding */ - pushw %bp - movw %sp, %bp - cmpw $0, 6(%bp) /* Conventional entry point used? */ - jne 1f - /* Entered via conventional entry point: set up stack */ - pushw %ax - movw 6(%bp), %ax - movw %ax, 2(%bp) /* Move return address down */ - movl $(EB_OPCODE_MAIN|EB_USE_INTERNAL_STACK|EB_SKIP_OPCODE), 4(%bp) - popw %ax - popw %bp - jmp 2f -1: /* Entered via callback entry point: do nothing */ - popw %bp - popw %ax -2: - /* Preserve registers */ - pushw %ds - pushl %eax - - /* Run decompressor if necessary. Decompressor is 32-bit - * code, so we must switch to pmode first. Save and restore - * GDT over transition to pmode. - */ - movl $decompress, %eax - testl %eax, %eax - jz 1f - pushw %ds - pushw %es - pushw %fs - pushw %gs - subw $8, %sp - pushw %bp - movw %sp, %bp - sgdt 2(%bp) - pushw %ss /* Store params for _prot_to_real */ - pushw %cs - call _prefix_real_to_prot - .code32 - call decompress - call _prefix_prot_to_real - .code16 - popw %ax /* skip */ - popw %ax /* skip */ - lgdt 2(%bp) - popw %bp - addw $8, %sp - popw %gs - popw %fs - popw %es - popw %ds -1: - - /* Set rm_etherboot_location */ - xorl %eax, %eax - movw %cs, %ax - movw %ax, %ds - shll $4, %eax - addl $_prefix_size, %eax - movl %eax, _prefix_rm_etherboot_location - - /* Restore registers */ - popl %eax - popw %ds - - /* Make real-mode in_call to Etherboot */ - jmp _prefix_rm_in_call -#endif /* CODE16 */ - -/****************************************************************************** - * Utility routines that can be called by the "prefix". - ****************************************************************************** - */ - -#ifdef CODE16 - -/* Prelocate code: either to an area at the top of free base memory. - * Switch stacks to use the stack within the resulting - * Etherboot image. - * - * On entry, %cs:0000 must be the start of the prefix: this is used to - * locate the code to be copied. - * - * This routine takes a single word parameter: the number of bytes to - * be transferred from the old stack to the new stack (excluding the - * return address and this parameter itself, which will always be - * copied). If this value is negative, the stacks will not be - * switched. - * - * Control will "return" to the appropriate point in the relocated - * image. - */ - -#define PRELOC_PRESERVE ( 20 ) -#define PRELOC_OFFSET_RETADDR ( PRELOC_PRESERVE ) -#define PRELOC_OFFSET_RETADDR_E ( PRELOC_OFFSET_RETADDR + 4 ) -#define PRELOC_OFFSET_COPY ( PRELOC_OFFSET_RETADDR_E ) -#define PRELOC_OFFSET_COPY_E ( PRELOC_OFFSET_COPY + 2 ) - -#define PRELOC_ALWAYS_COPY ( PRELOC_OFFSET_COPY_E ) - - .code16 - .globl prelocate -prelocate: - /* Pad to allow for expansion of return address */ - pushw %ax - - /* Preserve registers */ - pushaw - pushw %ds - pushw %es - - /* Claim an area of base memory from the BIOS and put the - * payload there. - */ - movw $0x40, %bx - movw %bx, %es - movw %es:(0x13), %bx /* FBMS in kb to %ax */ - shlw $6, %bx /* ... in paragraphs */ - subw $_image_size_pgh, %bx /* Subtract space for image */ - shrw $6, %bx /* Round down to nearest kb */ - movw %bx, %es:(0x13) /* ...and claim memory from BIOS */ - shlw $6, %bx - - /* At this point %bx contains the segment address for the - * start of the image (image = prefix + runtime). - */ - - /* Switch stacks */ - movw %ss, %ax - movw %ax, %ds - movw %sp, %si /* %ds:si = current %ss:sp */ - movw %ss:PRELOC_OFFSET_COPY(%si), %cx - testw %cx, %cx - js 1f - leaw _stack_offset_pgh(%bx), %ax /* %ax = new %ss */ - movw %ax, %es - movw $_stack_size, %di - addw $PRELOC_ALWAYS_COPY, %cx - subw %cx, %di /* %es:di = new %ss:sp */ - movw %ax, %ss /* Set new %ss:sp */ - movw %di, %sp - cld - rep movsb /* Copy stack contents */ -1: - - /* Do the image copy backwards, since if there's overlap with - * a forward copy then it means we're going to get trashed - * during the copy anyway... - */ - pushal /* Preserve 32-bit registers */ - movw %bx, %es /* Destination base for copy */ - pushw %cs - popw %ds /* Source base for copy */ - movl $_verbatim_size-1, %ecx /* Offset to last byte */ - movl %ecx, %esi - movl %ecx, %edi - incl %ecx /* Length */ - std /* Backwards copy of binary */ - ADDR32 rep movsb - cld - popal /* Restore 32-bit registers */ - - /* Store (%bx<<4) as image_basemem to be picked up by - * basemem.c. Also store image_size, since there's no other - * way that we can later know how much memory we allocated. - * (_zfile_size is unavailable when rt2 is linked). - */ - pushl %eax - xorl %eax, %eax - movw %bx, %ax - shll $4, %eax - movl %eax, %es:_prefix_image_basemem - movl $_image_size, %es:_prefix_image_basemem_size - popl %eax - - /* Expand original near return address into far return to new - * code location. - */ - movw %sp, %bp - xchgw %bx, (PRELOC_OFFSET_RETADDR+2)(%bp) - movw %bx, (PRELOC_OFFSET_RETADDR+0)(%bp) - - /* Restore registers and return */ - popw %es - popw %ds - popaw - lret /* Jump to relocated code */ - - /* Utility routine to free base memory allocated by prelocate. - * Ensure that said memory is not in use (e.g. for the CPU - * stack) before calling this routine. - */ - .globl deprelocate -deprelocate: - /* Claim an area of base memory from the BIOS and put the - * payload there. - */ - pushw %ax - pushw %es - movw $0x40, %ax - movw %ax, %es - movw %es:(0x13), %ax /* FBMS in kb to %ax */ - shlw $6, %ax /* ... in paragraphs */ - addw $_image_size_pgh+0x40-1, %ax /* Add space for image and... */ - shrw $6, %ax /* ...round up to nearest kb */ - movw %ax, %es:(0x13) /* Give memory back to BIOS */ - popw %es - popw %ax - ret - -#endif /* CODE16 */ diff --git a/src/arch/i386/core/pxe_callbacks.c b/src/arch/i386/core/pxe_callbacks.c index 344d34fe..df522329 100644 --- a/src/arch/i386/core/pxe_callbacks.c +++ b/src/arch/i386/core/pxe_callbacks.c @@ -3,6 +3,31 @@ * an NBP to the PXE stack and for starting an NBP from the PXE stack. */ +#warning "pxe_callbacks.c is temporarily broken" + +void xstartpxe ( void ) { +} + +void install_pxe_stack ( void ) { +} + +void remove_pxe_stack ( void ) { +} + +void hook_pxe_stack ( void ) { +} + +void unhook_pxe_stack ( void ) { +} + +void pxe_in_call ( void ) { +} + +void use_undi_ds_for_rm_stack ( void ) { +} + +#if 0 + #ifdef PXE_EXPORT #include "etherboot.h" @@ -362,3 +387,5 @@ __asm__ ( ".globl _pxe_stack_t_size" ); __asm__ ( ".equ _pxe_stack_t_size, 0" ); #endif /* PXE_EXPORT */ + +#endif /* 0 */ diff --git a/src/arch/i386/core/realmode.c b/src/arch/i386/core/realmode.c index ef4ede86..32252bd3 100644 --- a/src/arch/i386/core/realmode.c +++ b/src/arch/i386/core/realmode.c @@ -3,9 +3,25 @@ * Initial version by Michael Brown , January 2004. */ -#include "etherboot.h" #include "realmode.h" -#include "segoff.h" + +/* + * Copy data to/from base memory. + * + */ + +#ifdef KEEP_IT_REAL + +void memcpy_to_real ( segoff_t dest, void *src, size_t n ) { + +} + +void memcpy_from_real ( void *dest, segoff_t src, size_t n ) { + +} + +#endif /* KEEP_IT_REAL */ + #define RM_STACK_SIZE ( 0x1000 ) @@ -16,133 +32,9 @@ static void work_around_gcc_bug ( void ) __attribute__ ((used)); static void work_around_gcc_bug ( void ) { /* Export _real_mode_stack_size as absolute linker symbol */ - __asm__ ( ".globl _real_mode_stack_size" ); - __asm__ ( ".equ _real_mode_stack_size, %c0" : : "i" (RM_STACK_SIZE) ); + __asm__ ( ".globl real_mode_stack_size" ); + __asm__ ( ".equ real_mode_stack_size, %c0" : : "i" (RM_STACK_SIZE) ); } -/* While Etherboot remains in base memory the real-mode stack is - * placed in the Etherboot main stack. The first allocation or - * deallocation of base memory will cause a 'proper' real-mode stack - * to be allocated. This will happen before Etherboot is relocated to - * high memory. - */ -uint32_t real_mode_stack = 0; -size_t real_mode_stack_size = RM_STACK_SIZE; -int lock_real_mode_stack = 0; /* Set to make stack immobile */ - -/* Make a call to a real-mode code block. - */ - -/* These is the structure that exists on the stack as the paramters - * passed in to _real_call. We pass a pointer to this struct to - * prepare_real_call(), to save stack space. - */ -typedef struct { - void *fragment; - int fragment_len; - void *in_stack; - int in_stack_len; - void *out_stack; - int out_stack_len; -} real_call_params_t; - -uint32_t prepare_real_call ( real_call_params_t *p, - int local_stack_len, char *local_stack ) { - char *stack_base; - char *stack_end; - char *stack; - char *s; - prot_to_real_params_t *p2r_params; - real_to_prot_params_t *r2p_params; - - /* Work out where we're putting the stack */ - if ( virt_to_phys(local_stack) < 0xa0000 ) { - /* Current stack is in base memory. We can therefore - * use it directly, with a constraint on the size that - * we don't know; assume that we can use up to - * real_mode_stack_size. (Not a valid assumption, but - * it will do). - */ - stack_end = local_stack + local_stack_len; - stack_base = stack_end - real_mode_stack_size; - } else { - if (!real_mode_stack) { - allot_real_mode_stack(); - } - /* Use the allocated real-mode stack in base memory. - * This has fixed start and end points. - */ - stack_base = phys_to_virt(real_mode_stack); - stack_end = stack_base + real_mode_stack_size; - } - s = stack = stack_end - local_stack_len; - - /* Compile input stack and trampoline code to stack */ - if ( p->in_stack_len ) { - memcpy ( s, p->in_stack, p->in_stack_len ); - s += p->in_stack_len; - } - memcpy ( s, _prot_to_real_prefix, prot_to_real_prefix_size ); - s += prot_to_real_prefix_size; - p2r_params = (prot_to_real_params_t*) ( s - sizeof(*p2r_params) ); - memcpy ( s, p->fragment, p->fragment_len ); - s += p->fragment_len; - memcpy ( s, _real_to_prot_suffix, real_to_prot_suffix_size ); - s += real_to_prot_suffix_size; - r2p_params = (real_to_prot_params_t*) ( s - sizeof(*r2p_params) ); - - /* Set parameters within compiled stack */ - p2r_params->ss = p2r_params->cs = SEGMENT ( stack_base ); - p2r_params->esp = virt_to_phys ( stack ); - p2r_params->r2p_params = virt_to_phys ( r2p_params ); - r2p_params->out_stack = ( p->out_stack == NULL ) ? - 0 : virt_to_phys ( p->out_stack ); - r2p_params->out_stack_len = p->out_stack_len; - - return virt_to_phys ( stack + p->in_stack_len ); -} - - -/* Parameters are not genuinely unused; they are passed to - * prepare_real_call() as part of a real_call_params_t struct. - */ -uint16_t _real_call ( void *fragment, int fragment_len, - void *in_stack __unused, int in_stack_len, - void *out_stack __unused, int out_stack_len __unused ) { - uint16_t retval; - - /* This code is basically equivalent to - * - * uint32_t trampoline; - * char local_stack[ in_stack_len + prot_to_real_prefix_size + - * fragment_len + real_to_prot_suffix_size ]; - * trampoline = prepare_real_call ( &fragment, local_stack ); - * __asm__ ( "call _virt_to_phys\n\t" - * "call %%eax\n\t" - * "call _phys_to_virt\n\t" - * : "=a" (retval) : "0" (trampoline) ); - * - * but implemented in assembly to avoid problems with not - * being certain exactly how gcc handles %esp. - */ - - __asm__ ( "pushl %%ebp\n\t" - "movl %%esp, %%ebp\n\t" /* %esp preserved via %ebp */ - "subl %%ecx, %%esp\n\t" /* space for inline RM stack */ - "pushl %%esp\n\t" /* set up RM stack */ - "pushl %%ecx\n\t" - "pushl %%eax\n\t" - "call prepare_real_call\n\t" /* %eax = trampoline addr */ - "addl $12, %%esp\n\t" - "call _virt_to_phys\n\t" /* switch to phys addr */ - "call *%%eax\n\t" /* call to trampoline */ - "call _phys_to_virt\n\t" /* switch to virt addr */ - "movl %%ebp, %%esp\n\t" /* restore %esp & %ebp */ - "popl %%ebp\n\t" - : "=a" ( retval ) - : "0" ( &fragment ) - , "c" ( ( ( in_stack_len + prot_to_real_prefix_size + - fragment_len + real_to_prot_suffix_size ) - + 0x3 ) & ~0x3 ) ); - return retval; -} +char *real_mode_stack; +int lock_real_mode_stack; diff --git a/src/arch/i386/core/realmode_asm.S b/src/arch/i386/core/realmode_asm.S index 28a5bfed..db8bc22b 100644 --- a/src/arch/i386/core/realmode_asm.S +++ b/src/arch/i386/core/realmode_asm.S @@ -31,570 +31,6 @@ #define LJMPI(x) ljmp x #endif -/**************************************************************************** - * REAL-MODE CALLBACK INTERFACE - * - * This must be copied down to base memory in order for external - * programs to be able to make calls in to Etherboot. Store the - * current physical address of Etherboot (i.e. virt_to_phys(_text)) in - * (uint32_t)rm_etherboot_location, then copy - * (uint16_t)rm_callback_interface_size bytes starting at - * &((void)rm_callback_interface). - * - * There are two defined entry points: - * Offset RM_IN_CALL = 0 Near call entry point - * Offset RM_IN_CALL_FAR = 2 Far call entry point - * - * Note that the routines _prot_to_real and _real_to_prot double as - * trampoline fragments for external calls (calls from Etherboot to - * real-mode code). _prot_to_real does not automatically re-enable - * interrupts; this is to allow for the potential of using Etherboot - * code as an ISR. _real_to_prot does automatically disable - * interrupts, since we don't have a protected-mode IDT. - **************************************************************************** - */ - - .globl rm_callback_interface - .code16 -rm_callback_interface: - .globl _rm_in_call -_rm_in_call: - jmp _real_in_call - .globl _rm_in_call_far -_rm_in_call_far: - jmp _real_in_call_far - -/**************************************************************************** - * _real_in_call - * - * Parameters: - * 16-bit real-mode near/far return address (implicit from [l]call - * to routine) Other parameters as for _in_call_far(). - * - * This routine will convert the 16-bit real-mode far return address - * to a 32-bit real-mode far return address, switch to protected mode - * using _real_to_prot and call in to _in_call_far. - **************************************************************************** - */ - -#define RIC_PRESERVE ( 8 ) -#define RIC_OFFSET_CALLADDR ( RIC_PRESERVE ) -#define RIC_OFFSET_CALLADDR_E ( RIC_OFFSET_CALLADDR + 4 ) -#define RIC_OFFSET_CONTADDR ( RIC_OFFSET_CALLADDR_E ) -#define RIC_OFFSET_CONTADDR_E ( RIC_OFFSET_CONTADDR + 4 ) -#define RIC_OFFSET_OPCODE ( RIC_OFFSET_CONTADDR_E ) -#define RIC_OFFSET_OPCODE_E ( RIC_OFFSET_OPCODE + 4 ) -#define RIC_OFFSET_SEG_REGS ( RIC_OFFSET_OPCODE_E ) -#define RIC_OFFSET_SEG_REGS_E ( RIC_OFFSET_SEG_REGS + ( NUM_SEG_REGS * 2 ) ) -#define RIC_OFFSET_PAD ( RIC_OFFSET_SEG_REGS_E ) -#define RIC_OFFSET_PAD_E ( RIC_OFFSET_PAD + 2 ) -#define RIC_OFFSET_FLAGS ( RIC_OFFSET_PAD_E ) -#define RIC_OFFSET_FLAGS_E ( RIC_OFFSET_FLAGS + 2 ) -#define RIC_OFFSET_RETADDR ( RIC_OFFSET_FLAGS_E ) -#define RIC_OFFSET_RETADDR_E ( RIC_OFFSET_RETADDR + 4 ) -#define RIC_OFFSET_ORIG_OPCODE ( RIC_OFFSET_RETADDR_E ) -#define RIC_INSERT_LENGTH ( RIC_OFFSET_OPCODE_E - RIC_OFFSET_CALLADDR ) - - .code16 -_real_in_call: - /* Expand near return address to far return address - */ - pushw %ax /* Extend stack, store %ax */ - pushfw - pushw %bp - movw %sp, %bp - movw %cs, %ax - xchgw %ax, 6(%bp) - xchgw %ax, 4(%bp) /* also restores %ax */ - popw %bp - popfw - /* Fall through to _real_in_call_far */ - -_real_in_call_far: - /* Store flags and pad */ - pushfw - pushw %ax - - /* Store segment registers. Order matches that of seg_regs_t */ - pushw %gs - pushw %fs - pushw %es - pushw %ds - pushw %ss - pushw %cs - - /* Switch to protected mode */ - call _real_to_prot - .code32 - - /* Allow space for expanded stack */ - subl $RIC_INSERT_LENGTH, %esp - - /* Store temporary registers */ - pushl %ebp - pushl %eax - - /* Copy opcode, set EB_CALL_FROM_REAL_MODE and EP_SKIP_OPCODE. - * Copy it because _in_call() and i386_in_call() expect it at - * a fixed position, not as part of the va_list. - */ - movl RIC_OFFSET_ORIG_OPCODE(%esp), %eax - orl $(EB_CALL_FROM_REAL_MODE|EB_SKIP_OPCODE), %eax - movl %eax, RIC_OFFSET_OPCODE(%esp) - - /* Set up call and return addresses */ - call 1f -1: popl %ebp - subl $1b, %ebp /* %ebp = offset */ - movl rm_etherboot_location(%ebp), %eax /* Etherboot phys addr */ - subl $_text, %eax - addl $_in_call, %eax /* _in_call phys addr */ - movl %eax, RIC_OFFSET_CALLADDR(%esp) - leal 2f(%ebp), %eax /* continuation address */ - movl %eax, RIC_OFFSET_CONTADDR(%esp) - - /* Restore temporary registers */ - popl %eax - popl %ebp - - /* Call to _in_call */ - ret - /* opcode will be popped automatically thanks to EB_SKIP_OPCODE */ - -2: /* Continuation point */ - call _prot_to_real /* Return to real mode */ - /* Note: the first two words of our segment register store - * happens to be exactly what we need to pass as parameters to - * _prot_to_real. - */ - .code16 - popw %ds /* Restore segment registers */ - popw %ds /* (skip cs&ss since these */ - popw %ds /* have already been set by */ - popw %es /* _prot_to_real */ - popw %fs - popw %gs - addw $2, %sp /* skip pad */ - - /* Check for EB_SKIP_OPCODE */ - pushw %bp - movw %sp, %bp - testl $EB_SKIP_OPCODE, 6(%bp) - popw %bp - jnz 1f - /* Normal return */ - popfw /* Restore interrupt status */ - lret /* Back to caller */ -1: /* Return and skip opcode */ - popfw - lret $4 - -/**************************************************************************** - * rm_etherboot_location: the current physical location of Etherboot. - * Needed so that real-mode callback routines can locate Etherboot. - **************************************************************************** - */ - .globl rm_etherboot_location -rm_etherboot_location: .long 0 - -/**************************************************************************** - * _prot_to_real_prefix - * - * Trampoline fragment. Switch from 32-bit protected mode with flat - * physical addresses to 16-bit real mode. Store registers in the - * trampoline for restoration by _real_to_prot_suffix. Switch to - * stack in base memory. - **************************************************************************** - */ - - .globl _prot_to_real_prefix - .code32 -_prot_to_real_prefix: - /* Registers to preserve */ - pushl %ebx - pushl %esi - pushl %edi - pushl %ebp - - /* Calculate offset */ - call 1f -1: popl %ebp - subl $1b, %ebp /* %ebp = offset for labels in p2r*/ - - /* Preserve registers and return address in r2p_params */ - movl p2r_r2p_params(%ebp), %ebx - subl $r2p_params, %ebx /* %ebx = offset for labels in r2p */ - popl r2p_ebp(%ebx) - popl r2p_edi(%ebx) - popl r2p_esi(%ebx) - popl r2p_ebx(%ebx) - popl r2p_ret_addr(%ebx) - movl %esp, r2p_esp(%ebx) - - /* Switch stacks */ - movl p2r_esp(%ebp), %esp - - /* Switch to real mode */ - pushl p2r_segments(%ebp) - call _prot_to_real - .code16 - addw $4, %sp - - /* Fall through to next trampoline fragment */ - jmp _prot_to_real_prefix_end - -/**************************************************************************** - * _prot_to_real - * - * Switch from 32-bit protected mode with flat physical addresses to - * 16-bit real mode. Stack and code must be in base memory when - * called. %cs, %ss, %eip, %esp are changed to real-mode values, - * other segment registers are destroyed, all other registers are - * preserved. Interrupts are *not* enabled. - * - * Parameters: - * %cs Real-mode code segment (word) - * %ss Real-mode stack segment (word) - **************************************************************************** - */ - -#define P2R_PRESERVE ( 12 ) -#define P2R_OFFSET_RETADDR ( P2R_PRESERVE ) -#define P2R_OFFSET_RETADDR_E ( P2R_OFFSET_RETADDR + 4 ) -#define P2R_OFFSET_CS ( P2R_OFFSET_RETADDR_E ) -#define P2R_OFFSET_CS_E ( P2R_OFFSET_CS + 2 ) -#define P2R_OFFSET_SS ( P2R_OFFSET_CS_E ) -#define P2R_OFFSET_SS_E ( P2R_OFFSET_SS + 2 ) - - .globl _prot_to_real - .code32 -_prot_to_real: - /* Preserve registers */ - pushl %ebp - pushl %ebx - pushl %eax - - /* Calculate offset */ - call 1f -1: popl %ebp - subl $1b, %ebp /* %ebp = offset for labels in p2r*/ - - /* Set up GDT with real-mode limits and appropriate bases for - * real-mode %cs and %ss. Set up protected-mode continuation - * point on stack. - */ - /* Fixup GDT */ - leal p2r_gdt(%ebp), %eax - movl %eax, p2r_gdt_addr(%ebp) - - /* Calculate CS base address: set GDT code segment, adjust - * return address, set up continuation address on stack. - */ - movzwl P2R_OFFSET_CS(%esp), %eax - shll $4, %eax - /* Change return address to real-mode far address */ - subl %eax, P2R_OFFSET_RETADDR(%esp) - movl %eax, %ebx - shrl $4, %ebx - movw %bx, (P2R_OFFSET_RETADDR+2)(%esp) - /* First real mode address */ - movl %eax, %ebx - shrl $4, %ebx - pushw %bx - leal 3f(%ebp), %ebx - subl %eax, %ebx - pushw %bx - /* Continuation address */ - pushl $(p2r_rmcs - p2r_gdt) - leal 2f(%ebp), %ebx - subl %eax, %ebx - pushl %ebx - /* Code segment in GDT */ - movw %ax, (p2r_rmcs+2)(%ebp) - shrl $16, %eax /* Remainder of cs base addr */ - movb %al, (p2r_rmcs+4)(%ebp) - movb %ah, (p2r_rmcs+7)(%ebp) - - /* Calculate SS base address: set GDT data segment, retain to - * use for adjusting %esp. - */ - movzwl (12+P2R_OFFSET_SS)(%esp), %eax /* Set ss base address */ - shll $4, %eax - movw %ax, (p2r_rmds+2)(%ebp) - movl %eax, %ebx - shrl $16, %ebx - movb %bl, (p2r_rmds+4)(%ebp) - movb %bh, (p2r_rmds+7)(%ebp) - - /* Load GDT */ - lgdt p2r_gdt(%ebp) - /* Reload all segment registers and adjust %esp */ - movw $(p2r_rmds - p2r_gdt), %bx /* Pmode DS */ - movw %bx, %ss - subl %eax, %esp /* %esp now less than 0x10000 */ - movw %bx, %ds - movw %bx, %es - movw %bx, %fs - movw %bx, %gs - lret /* %cs:eip */ -2: /* Segment registers now have 16-bit limits. */ - .code16 - - /* Switch to real mode */ - movl %cr0, %ebx - andb $0!CR0_PE, %bl - movl %ebx, %cr0 - - /* Make intersegment jmp to flush the processor pipeline - * and reload %cs:%eip (to clear upper 16 bits of %eip). - */ - lret -3: - - /* Load real-mode segment value to %ss. %sp already OK */ - shrl $4, %eax - movw %ax, %ss - - /* Restore registers */ - popl %eax - popl %ebx - popl %ebp - - /* Return to caller in real-mode */ - lret - -#ifdef FLATTEN_REAL_MODE -#define RM_LIMIT_16_19__AVL__SIZE__GRANULARITY 0x8f -#else -#define RM_LIMIT_16_19__AVL__SIZE__GRANULARITY 0x00 -#endif - -p2r_gdt: -p2r_gdtarg: -p2r_gdt_limit: .word p2r_gdt_end - p2r_gdt - 1 -p2r_gdt_addr: .long 0 -p2r_gdt_padding: .word 0 -p2r_rmcs: - /* 16 bit real mode code segment */ - .word 0xffff,(0&0xffff) - .byte (0>>16),0x9b,RM_LIMIT_16_19__AVL__SIZE__GRANULARITY,(0>>24) -p2r_rmds: - /* 16 bit real mode data segment */ - .word 0xffff,(0&0xffff) - .byte (0>>16),0x93,RM_LIMIT_16_19__AVL__SIZE__GRANULARITY,(0>>24) -p2r_gdt_end: - - /* This is the end of the trampoline prefix code. When used - * as a prefix, fall through to the following code in the - * trampoline. - */ -p2r_params: /* Structure must match prot_to_real_params_t in realmode.h */ -p2r_esp: .long 0 -p2r_segments: -p2r_cs: .word 0 -p2r_ss: .word 0 -p2r_r2p_params: .long 0 - .globl _prot_to_real_prefix_end -_prot_to_real_prefix_end: - - .globl _prot_to_real_prefix_size - .equ _prot_to_real_prefix_size, _prot_to_real_prefix_end - _prot_to_real_prefix - .globl prot_to_real_prefix_size -prot_to_real_prefix_size: - .word _prot_to_real_prefix_size - -/**************************************************************************** - * _real_to_prot_suffix - * - * Trampoline fragment. Switch from 16-bit real-mode to 32-bit - * protected mode with flat physical addresses. Copy returned stack - * parameters to output_stack. Restore registers preserved by - * _prot_to_real_prefix. Restore stack to previous location. - **************************************************************************** - */ - - .globl _real_to_prot_suffix - .code16 -_real_to_prot_suffix: - - /* Switch to protected mode */ - call _real_to_prot - .code32 - - /* Calculate offset */ - call 1f -1: popl %ebp - subl $1b, %ebp /* %ebp = offset for labels in r2p */ - - /* Copy stack to out_stack */ - movl r2p_out_stack(%ebp), %edi - movl r2p_out_stack_len(%ebp), %ecx - movl %esp, %esi - cld - rep movsb - - /* Switch back to original stack */ - movl r2p_esp(%ebp), %esp - - /* Restore registers and return */ - pushl r2p_ret_addr(%ebp) /* Set up return address on stack */ - movl r2p_ebx(%ebp), %ebx - movl r2p_esi(%ebp), %esi - movl r2p_edi(%ebp), %edi - movl r2p_ebp(%ebp), %ebp - ret - -/**************************************************************************** - * _real_to_prot - * - * Switch from 16-bit real-mode to 32-bit protected mode with flat - * physical addresses. All segment registers are destroyed, %eip and - * %esp are changed to flat physical values, all other registers are - * preserved. Interrupts are disabled. - * - * Parameters: none - **************************************************************************** - */ - -#define R2P_PRESERVE ( 12 ) -#define R2P_OFFSET_RETADDR ( R2P_PRESERVE ) -#define R2P_OFFSET_ORIG_RETADDR ( R2P_OFFSET_RETADDR + 2 ) - - .globl _real_to_prot - .code16 -_real_to_prot: - /* Disable interrupts */ - cli - /* zero extend the return address */ - pushw $0 - - /* Preserve registers */ - pushl %ebp - pushl %ebx - pushl %eax - - /* Convert 16-bit real-mode near return address to - * 32-bit pmode physical near return address - */ - movw %sp, %bp - xorl %ebx, %ebx - push %cs - popw %bx - movw %bx, %ds - shll $4, %ebx - movzwl %ss:R2P_OFFSET_ORIG_RETADDR(%bp), %eax - addl %ebx, %eax - movl %eax, %ss:(R2P_OFFSET_RETADDR)(%bp) - - /* Store the code segment physical base address in %ebp */ - movl %ebx, %ebp - - /* Find the offset within the code segment that I am running at */ - xorl %ebx, %ebx - call 1f -1: popw %bx - - /* Set up GDT */ - leal (r2p_gdt-1b)(%bx), %eax /* %ds:ebx = %ds:bx = &(r2p_gdt) */ - addl %ebp, %eax /* %eax = &r2p_gdt (physical) */ - movl %eax, %ds:(r2p_gdt-1b+2)(%bx) /* Set phys. addr. in r2p_gdt */ - - /* Compute the first protected mode physical address */ - leal (2f-1b)(%bx), %eax - addl %ebp, %eax - movl %eax, %ds:(r2p_paddr-1b)(%bx) - - /* Calculate new %esp */ - xorl %eax, %eax - push %ss - popw %ax - shll $4, %eax - movzwl %sp, %ebp - addl %eax, %ebp /* %ebp = new %esp */ - - /* Load GDT */ - DATA32 lgdt %ds:(r2p_gdt-1b)(%bx) /* Load GDT */ - - /* Switch to protected mode */ - movl %cr0, %eax - orb $CR0_PE, %al - movl %eax, %cr0 - - /* flush prefetch queue, and reload %cs:%eip */ - DATA32 ljmp %ds:(r2p_paddr-1b)(%bx) - .code32 -2: - - /* Load segment registers, adjust %esp */ - movw $(r2p_pmds-r2p_gdt), %ax - movw %ax, %ss - movl %ebp, %esp - movw %ax, %ds - movw %ax, %es - movw %ax, %fs - movw %ax, %gs - - /* Restore registers */ - popl %eax - popl %ebx - popl %ebp - - /* return to caller */ - ret - -r2p_gdt: - .word r2p_gdt_end - r2p_gdt - 1 /* limit */ - .long 0 /* addr */ - .word 0 -r2p_pmcs: - /* 32 bit protected mode code segment, physical addresses */ - .word 0xffff, 0 - .byte 0, 0x9f, 0xcf, 0 -r2p_pmds: - /* 32 bit protected mode data segment, physical addresses */ - .word 0xffff,0 - .byte 0,0x93,0xcf,0 -r2p_gdt_end: - -r2p_paddr: - .long 2b - .word r2p_pmcs - r2p_gdt, 0 - - - /* This is the end of the trampoline suffix code. - */ -r2p_params: /* Structure must match real_to_prot_params_t in realmode.h */ -r2p_ret_addr: .long 0 -r2p_esp: .long 0 -r2p_ebx: .long 0 -r2p_esi: .long 0 -r2p_edi: .long 0 -r2p_ebp: .long 0 -r2p_out_stack: .long 0 -r2p_out_stack_len: .long 0 - .globl _real_to_prot_suffix_end -_real_to_prot_suffix_end: - - .globl _real_to_prot_suffix_size - .equ _real_to_prot_suffix_size, _real_to_prot_suffix_end - _real_to_prot_suffix - .globl real_to_prot_suffix_size -real_to_prot_suffix_size: - .word _real_to_prot_suffix_size - -rm_callback_interface_end: - - .globl _rm_callback_interface_size - .equ _rm_callback_interface_size, rm_callback_interface_end - rm_callback_interface - .globl rm_callback_interface_size -rm_callback_interface_size: - .word _rm_callback_interface_size - -/**************************************************************************** - * END OF REAL-MODE CALLBACK INTERFACE - **************************************************************************** - */ - - #ifdef PXE_EXPORT /**************************************************************************** * PXE CALLBACK INTERFACE diff --git a/src/arch/i386/core/setjmp.S b/src/arch/i386/core/setjmp.S new file mode 100644 index 00000000..59a1b7cb --- /dev/null +++ b/src/arch/i386/core/setjmp.S @@ -0,0 +1,40 @@ +/* setjmp and longjmp. Use of these functions is deprecated. */ + + .text + .arch i386 + .code32 + +/************************************************************************** +SETJMP - Save stack context for non-local goto +**************************************************************************/ + .globl setjmp +setjmp: + movl 4(%esp),%ecx /* jmpbuf */ + movl 0(%esp),%edx /* return address */ + movl %edx,0(%ecx) + movl %ebx,4(%ecx) + movl %esp,8(%ecx) + movl %ebp,12(%ecx) + movl %esi,16(%ecx) + movl %edi,20(%ecx) + movl $0,%eax + ret + +/************************************************************************** +LONGJMP - Non-local jump to a saved stack context +**************************************************************************/ + .globl longjmp +longjmp: + movl 4(%esp),%edx /* jumpbuf */ + movl 8(%esp),%eax /* result */ + movl 0(%edx),%ecx + movl 4(%edx),%ebx + movl 8(%edx),%esp + movl 12(%edx),%ebp + movl 16(%edx),%esi + movl 20(%edx),%edi + cmpl $0,%eax + jne 1f + movl $1,%eax +1: movl %ecx,0(%esp) + ret diff --git a/src/arch/i386/core/setup.S b/src/arch/i386/core/setup.S new file mode 100644 index 00000000..b2dd3b16 --- /dev/null +++ b/src/arch/i386/core/setup.S @@ -0,0 +1,158 @@ +/**************************************************************************** + * This file provides the setup() and setup16() functions. The + * purpose of these functions is to set up the internal environment so + * that C code can execute. This includes setting up the internal + * stack and (where applicable) setting up a GDT for virtual + * addressing. + * + * These functions are designed to be called by the prefix. + * + * The same basic assembly code is used to compile both setup() + * and setup16(). + **************************************************************************** + */ + + .text + .arch i386 + +#ifdef CODE16 +/**************************************************************************** + * setup16 (real-mode far call) + * + * This function can be called by a 16-bit prefix in order to set up + * the internal (either 16-bit or 32-bit) environment. + * + * Parameters: none + * + * %cs:0000, %ds:0000 and %es:0000 must point to the start of the + * (decompressed) runtime image. + * + * If KEEP_IT_REAL is defined, then %ds:0000 may instead point to the + * start of the (decompressed) data segment portion of the runtime + * image. If %ds==%cs, then it will be assumed that the data segment + * follows immediately after the code segment. + **************************************************************************** + */ + +#ifdef KEEP_IT_REAL + +#define ENTER_FROM_EXTERNAL call ext_to_kir +#define RETURN_TO_EXTERNAL call kir_to_ext +#define ENTRY_POINT kir_call + +#else /* KEEP_IT_REAL */ + +#define ENTER_FROM_EXTERNAL \ + pushw %cs ; \ + call real_to_prot ; \ + .code32 +#define RETURN_TO_EXTERNAL \ + call prot_to_real ; \ + .code16 +#define ENTRY_POINT _prot_call /* _prot_call = OFFSET ( prot_call ) in librm */ + +#endif /* KEEP_IT_REAL */ + +#define ENTRY_POINT_REGISTER di + + .section ".text16" + .code16 + .globl setup16 +setup16: + +#else /* CODE16 */ + +/**************************************************************************** + * setup (32-bit protected-mode near call) + * + * This function can be called by a 32-bit prefix in order to set up + * the internal 32-bit environment. + * + * Parameters: none + **************************************************************************** + */ + +#define ENTER_FROM_EXTERNAL call ext_to_int +#define RETURN_TO_EXTERNAL call int_to_ext +#define ENTRY_POINT int_call +#define ENTRY_POINT_REGISTER edi + + .section ".text" + .code32 + .globl setup +setup: + +#endif /* CODE16 */ + + /* Preserve flags (including interrupt status) */ + pushfl + + /* Switch to (uninitialised) internal environment. This will + * preserve the external environment for when we call + * RETURN_TO_EXTERNAL. + */ + ENTER_FROM_EXTERNAL + /* NOTE: We may have only four bytes of stack at this point */ + +#if defined(CODE16) && defined(KEEP_IT_REAL) + + /* If %ds == %cs, then the data segment is located immediately + * after the code segment. + */ + pushw %ax + pushw %bx + movw %cs, %ax + movw %ds, %bx + cmpw %ax, %bx + jne 1f + addw $_text_load_size_pgh, %ax + movw %ax, %ds +1: popw %bx + popw %ax + + /* Switch to internal stack */ + pushw %ds + popw %ss + movl $_estack, %esp + +#else /* CODE16 && KEEP_IT_REAL */ + + /* Work out where we're running */ + call 1f +1: popl %ebp + + /* Switch to internal pmode stack */ + leal (_estack-1b)(%ebp), %esp + + /* Set up GDT for virtual addressing */ + call run_here + +#endif /* CODE16 && KEEP_IT_REAL */ + + /* Switch back to external environment. This will preserve + * the internal environment ready for the next call. + */ + RETURN_TO_EXTERNAL + + /* Pass pointer to entry-point function back to prefix. %es + * may, by now, have been destroyed, so we re-initialise it + * from %cs. + */ + pushw %cs + popw %es + mov $ENTRY_POINT, %ENTRY_POINT_REGISTER + + /* Restore flags (including interrupt status) */ + popfl + + lret + +/**************************************************************************** + * Internal stack + **************************************************************************** + */ + .section ".stack" + .align 8 +_stack: + .space 4096 +_estack: diff --git a/src/arch/i386/core/start16.S b/src/arch/i386/core/start16.S deleted file mode 100644 index 72fcfbfb..00000000 --- a/src/arch/i386/core/start16.S +++ /dev/null @@ -1,285 +0,0 @@ -/***************************************************************************** - * - * THIS FILE IS NOW OBSOLETE. - * - * The functions of this file are now placed in init.S. - * - ***************************************************************************** - */ - -#ifndef PCBIOS -#error "16bit code is only supported with the PCBIOS" -#endif - -#define CODE_SEG 0x08 -#define DATA_SEG 0x10 - -#define EXEC_IN_SITU_MAGIC 0x45524548 /* 'HERE' */ - - .equ CR0_PE, 1 - -#ifdef GAS291 -#define DATA32 data32; -#define ADDR32 addr32; -#define LJMPI(x) ljmp x -#else -#define DATA32 data32 -#define ADDR32 addr32 -/* newer GAS295 require #define LJMPI(x) ljmp *x */ -#define LJMPI(x) ljmp x -#endif - -/***************************************************************************** - * - * start16 : move payload to desired area of memory, set up for exit - * back to prefix, set up for 32-bit code. - * - * Enter (from prefix) with es:di = 0x4552:0x4548 if you want to - * prevent start16 from moving the payload. There are three - * motivations for moving the payload: - * - * 1. It may be in ROM, in which case we need to move it to RAM. - * 2. Whatever loaded us probably didn't know about our memory usage - * beyond the end of the image file. We should claim this memory - * before using it. - * - * Unless the prefix instructs us otherwise we will move the payload to: - * - * An area of memory claimed from the BIOS via 40:13. - * - * We use the main Etherboot stack (within the image target) as our - * stack; we don't rely on the prefix passing us a stack usable for - * anything other than the prefix's return address. The (first 512 - * bytes of the) prefix code segment is copied to a safe archive - * location. - * - * When we return to the prefix (from start32), we copy this code back - * to a new area of memory, restore the prefix's ss:sp and ljmp back - * to the copy of the prefix. The prefix will see a return from - * start16 *but* may be executing at a new location. Code following - * the lcall to start16 must therefore be position-independent and - * must also be within [cs:0000,cs:01ff]. We make absolutely no - * guarantees about the stack contents when the prefix regains - * control. - * - * Trashes just about all registers, including all the segment - * registers. - * - ***************************************************************************** - */ - - .text - .code16 - .arch i386 - .org 0 - .globl _start16 -_start16: - -/***************************************************************************** - * Work out where we are going to place our image (image = optional - * decompressor + runtime). Exit this stage with %ax containing the - * runtime target address divided by 16 (i.e. a real-mode segment - * address). - ***************************************************************************** - */ - movw %es, %ax - cmpw $(EXEC_IN_SITU_MAGIC >> 16), %ax - jne exec_moved - cmpw $(EXEC_IN_SITU_MAGIC & 0xffff), %di - jne exec_moved -exec_in_situ: - /* Prefix has warned us not to move the payload. Simply - * calculate where the image is going to end up, so we can - * work out where to put our stack. - */ - movw %cs, %ax - addw $((payload-_start16)/16), %ax - jmp 99f -exec_moved: - /* Claim an area of base memory from the BIOS and put the - * payload there. arch_relocated_to() will deal with freeing - * up this memory once we've relocated to high memory. - */ - movw $0x40, %ax - movw %ax, %es - movw %es:(0x13), %ax /* FBMS in kb to %ax */ - shlw $6, %ax /* ... in paragraphs */ - subw $__image_size_pgh, %ax /* Subtract space for image */ - shrw $6, %ax /* Round down to nearest kb */ - movw %ax, %es:(0x13) /* ...and claim memory from BIOS */ - shlw $6, %ax -99: - /* At this point %ax contains the segment address for the - * start of the image (image = optional decompressor + runtime). - */ - -/***************************************************************************** - * Set up stack in start32's stack space within the place we're going - * to copy Etherboot to, reserve space for GDT, copy return address - * from prefix stack, store prefix stack address - ***************************************************************************** - */ - popl %esi /* Return address */ - mov %ss, %bx /* %es:di = prefix stack address */ - mov %bx, %es /* (*after* pop of return address) */ - movw %sp, %di - movw $__offset_stack_pgh, %bx /* Set up Etherboot stack */ - addw %ax, %bx - movw %bx, %ss - movw $__stack_size, %sp - subw $(_gdt_end - _gdt), %sp /* Reserve space for GDT */ - movw %sp, %bp /* Record GDT location */ - /* Set up i386_rm_in_call_data_t structure on stack. This is - * the same structure as is set up by rm_in_call. - */ - pushl $0 /* Dummy opcode */ - pushl %esi /* Prefix return address */ - pushfw /* Flags */ - pushw %di /* Prefix %sp */ - pushw %gs /* Segment registers */ - pushw %fs - pushw %es - pushw %ds - pushw %es /* Prefix %ss */ - pushw %cs - /* Stack is now 32-bit aligned */ - - /* %ax still contains image target segment address */ - -/***************************************************************************** - * Calculate image target and prefix code physical addresses, store on stack - * for use in copy routine. - ***************************************************************************** - */ - movzwl %es:-2(%di), %ebx /* Prefix code segment */ - shll $4, %ebx - pushl %ebx /* Prefix code physical address */ - movzwl %ax, %edi /* Image target segment */ - shll $4, %edi - pushl %edi /* Image target physical address */ - -/***************************************************************************** - * Transition to 32-bit protected mode. Set up all segment - * descriptors to use flat physical addresses. - ***************************************************************************** - */ - /* Copy gdt to area reserved on stack - */ - push %cs /* GDT source location -> %ds:%si */ - pop %ds - mov $(_gdt - _start16), %si - push %ss /* GDT target location -> %es:%di */ - pop %es - mov %bp, %di - mov $(_gdt_end - _gdt), %cx - cld - rep movsb /* Copy GDT to stack */ - movl %ss, %eax - shll $4, %eax - movzwl %bp, %ebx - addl %eax, %ebx /* Physical addr of GDT copy -> %ebx */ - movl %ebx, 2(%bp) /* Fill in addr field in GDT */ - - /* Compute the offset I am running at. - */ - movl %cs, %ebx - shll $4, %ebx /* %ebx = offset for start16 symbols */ - - /* Switch to 32bit protected mode. - */ - cli /* Disable interrupts */ - lgdt (%bp) /* Load GDT from stack */ - movl %cr0, %eax /* Set protected mode bit */ - orb $CR0_PE, %al - movl %eax, %cr0 - movl %ss, %eax /* Convert stack pointer to 32bit */ - shll $4, %eax - movzwl %sp, %esp - addl %eax, %esp - movl $DATA_SEG, %eax /* Reload the segment registers */ - movl %eax, %ds - movl %eax, %es - movl %eax, %ss - movl %eax, %fs - movl %eax, %gs - /* Flush prefetch queue, and reload %cs:%eip by effectively ljmping - * to code32_start. Do the jump via pushl and lret because the text - * may not be writable/ - */ - pushl $CODE_SEG - ADDR32 leal (code32_start-_start16)(%ebx), %eax - pushl %eax - DATA32 lret /* DATA32 needed, because we're still in 16-bit mode */ - -_gdt: -gdtarg: - .word _gdt_end - _gdt - 1 /* limit */ - .long 0 /* addr */ - .word 0 -_pmcs: - /* 32 bit protected mode code segment */ - .word 0xffff, 0 - .byte 0, 0x9f, 0xcf, 0 -_pmds: - /* 32 bit protected mode data segment */ - .word 0xffff,0 - .byte 0,0x93,0xcf,0 -_gdt_end: - - .code32 -code32_start: - -/***************************************************************************** - * Copy payload to target location. Do the copy backwards, since if - * there's overlap with a forward copy then it means start16 is going - * to get trashed during the copy anyway... - ***************************************************************************** - */ - popl %edi /* Image target physical address */ - pushl %edi - leal (payload-_start16)(%ebx), %esi /* Image source physical addr */ - movl $__payload_size, %ecx /* Payload size (not image size) */ - addl %ecx, %edi /* Start at last byte (length - 1) */ - decl %edi - addl %ecx, %esi - decl %esi - std /* Backward copy of image */ - rep movsb - cld - popl %edi /* Restore image target physical address */ - leal __decompressor_uncompressed(%edi), %ebx - subl $_text, %ebx /* %ebx = offset for runtime symbols */ - -/***************************************************************************** - * Copy prefix to storage area within Etherboot image. - ***************************************************************************** - */ - popl %esi /* Prefix source physical address */ - pushl %edi - leal _prefix_copy(%ebx), %edi /* Prefix copy phys. addr. */ - leal _eprefix_copy(%ebx), %ecx - subl %edi, %ecx /* Prefix copy size */ - rep movsb /* Forward copy of prefix */ - popl %edi /* Restore image target physical address */ - -/***************************************************************************** - * Record base memory used by Etherboot image - ***************************************************************************** - */ - movl %edi, _prefix_image_basemem (%ebx) - -/***************************************************************************** - * Jump to start of the image (i.e. the decompressor, or start32 if - * non-compressed). - ***************************************************************************** - */ - pushl $0 /* Inform start32 that exit path is 16-bit */ - jmpl *%edi /* Jump to image */ - - .balign 16 - /* Etherboot needs to be 16byte aligned or data that - * is virtually aligned is no longer physically aligned - * which is just nasty in general. 16byte alignment - * should be sufficient though. - */ -payload: diff --git a/src/arch/i386/core/start32.S b/src/arch/i386/core/start32.S index 6dc3f203..e82454bb 100644 --- a/src/arch/i386/core/start32.S +++ b/src/arch/i386/core/start32.S @@ -1,18 +1,5 @@ -/* #defines because ljmp wants a number, probably gas bug */ -/* .equ KERN_CODE_SEG,_pmcs-_gdt */ -#define KERN_CODE_SEG 0x08 - .equ KERN_DATA_SEG,_pmds-_gdt -/* .equ REAL_CODE_SEG,_rmcs-_gdt */ -#define REAL_CODE_SEG 0x18 - .equ REAL_DATA_SEG,_rmds-_gdt - .equ FLAT_CODE_SEG,_pmcs2-_gdt - .equ FLAT_DATA_SEG,_pmds2-_gdt - .equ CR0_PE,1 -#ifdef CONFIG_X86_64 - .equ LM_CODE_SEG, _lmcs-_gdt - .equ LM_DATA_SEG, _lmds-_gdt -#endif - +#include "virtaddr.h" + .equ MSR_K6_EFER, 0xC0000080 .equ EFER_LME, 0x00000100 .equ X86_CR4_PAE, 0x00000020 @@ -29,12 +16,6 @@ #define LJMPI(x) ljmp x #endif -#define BOCHSBP xchgw %bx, %bx - -#include "callbacks.h" -#define NUM_PUSHA_REGS (8) -#define NUM_SEG_REGS (6) - /* * 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 @@ -54,226 +35,10 @@ * deal correctly with 16 bit return addresses. I tried it, but failed. */ -/************************************************************************** - * START - * - * This file is no longer enterered from the top. init.S will jump to - * either _in_call or _rm_in_call, depending on the processor mode - * when init.S was entered. - **************************************************************************/ .text .arch i386 .code32 -/************************************************************************** -_IN_CALL - make a call in to Etherboot. -**************************************************************************/ - -/* There are two 32-bit entry points: _in_call and _in_call_far, for - * near calls and far calls respectively. Both should be called with - * flat physical addresses. They will result in a call to the C - * routine in_call(); see there for API details. - * - * Note that this routine makes fairly heavy use of the stack and no - * use of fixed data areas. This is because it must be re-entrant; - * there may be more than one concurrent call in to Etherboot. - */ - -#define IC_OFFSET_VA_LIST_PTR ( 0 ) -#define IC_OFFSET_VA_LIST_PTR_E ( IC_OFFSET_VA_LIST_PTR + 4 ) -#define IC_OFFSET_REGISTERS ( IC_OFFSET_VA_LIST_PTR_E ) -#define IC_OFFSET_REGISTERS_E ( IC_OFFSET_REGISTERS + ( NUM_PUSHA_REGS * 4 ) ) -#define IC_OFFSET_SEG_REGS ( IC_OFFSET_REGISTERS_E ) -#define IC_OFFSET_SEG_REGS_E ( IC_OFFSET_SEG_REGS + ( NUM_SEG_REGS * 2 ) ) -#define IC_OFFSET_GDT ( IC_OFFSET_SEG_REGS_E ) -#define IC_OFFSET_GDT_E ( IC_OFFSET_GDT + 8 ) -#define IC_OFFSET_FLAGS ( IC_OFFSET_GDT_E ) -#define IC_OFFSET_FLAGS_E ( IC_OFFSET_FLAGS + 4 ) -#define IC_OFFSET_RETADDR ( IC_OFFSET_FLAGS_E ) -#define IC_OFFSET_RETADDR_E ( IC_OFFSET_RETADDR + 8 ) -#define IC_OFFSET_ORIG_STACK ( IC_OFFSET_RETADDR ) -#define IC_OFFSET_OPCODE ( IC_OFFSET_ORIG_STACK + 8 ) -#define IC_OFFSET_OPCODE_E ( IC_OFFSET_OPCODE + 4 ) -#define IC_OFFSET_VA_LIST ( IC_OFFSET_OPCODE_E ) - - .code32 - .globl _in_call - .globl _in_call_far -_in_call: - /* Expand to far return address */ - pushl %eax /* Store %eax */ - xorl %eax, %eax - movw %cs, %ax - xchgl %eax, 4(%esp) /* 4(%esp) = %cs, %eax = ret addr */ - xchgl %eax, 0(%esp) /* 0(%esp) = ret addr, restore %eax */ -_in_call_far: - /* Store flags */ - pushfl - /* Store the GDT */ - subl $8, %esp - sgdt 0(%esp) - /* Store segment register values */ - pushw %gs - pushw %fs - pushw %es - pushw %ds - pushw %ss - pushw %cs - /* Store general-purpose register values */ - pushal - /* Replace %esp in store with physical %esp value on entry */ - leal (IC_OFFSET_ORIG_STACK - IC_OFFSET_REGISTERS)(%esp), %eax - movl %eax, (IC_OFFSET_REGISTERS - IC_OFFSET_REGISTERS + 12)(%esp) - /* Store va_list pointer (physical address) */ - leal (IC_OFFSET_VA_LIST - IC_OFFSET_VA_LIST_PTR_E)(%esp), %eax - pushl %eax - /* IC_OFFSET_*(%esp) are now valid */ - - /* Switch to virtual addresses */ - call _phys_to_virt - - /* Fixup the va_list pointer */ - movl virt_offset, %ebp - subl %ebp, IC_OFFSET_VA_LIST_PTR(%esp) - - /* Check opcode for EB_USE_INTERNAL_STACK flag */ - movl IC_OFFSET_OPCODE(%esp), %eax - testl $EB_USE_INTERNAL_STACK, %eax - je 2f - /* Use internal stack flag set */ - /* Check %esp is not already in internal stack range */ - leal _stack, %esi /* %esi = bottom of internal stack */ - leal _estack, %edi /* %edi = top of internal stack */ - cmpl %esi, %esp - jb 1f - cmpl %edi, %esp - jbe 2f -1: /* %esp not currently in internal stack range */ - movl %esp, %esi /* %esi = original stack */ - movl $IC_OFFSET_OPCODE_E, %ecx /* %ecx = length to transfer */ - subl %ecx, %edi /* %edi = internal stack pos */ - movl %edi, %esp /* = new %esp */ - rep movsb /* Copy data to internal stack */ -2: - - /* Call to C code */ - call i386_in_call - - /* Set %eax (return code from C) in registers structure on - * stack, so that we return it to the caller. - */ - movl %eax, (IC_OFFSET_REGISTERS + 28)(%esp) - - /* Calculate physical continuation address */ - movl virt_offset, %ebp - movzwl (IC_OFFSET_SEG_REGS + 0)(%esp), %eax /* %cs */ - movzwl (IC_OFFSET_SEG_REGS + 2)(%esp), %ebx /* %ss */ - pushl %eax /* Continuation segment */ - leal 1f(%ebp), %eax - pushl %eax /* Continuation offset */ - - /* Restore caller's GDT */ - cli /* Temporarily disable interrupts */ - lgdt (8+IC_OFFSET_GDT)(%esp) - /* Reset %ss and adjust %esp */ - movw %bx, %ss - addl %ebp, %esp - lret /* Reload %cs:eip, flush prefetch */ -1: - - /* Skip va_list ptr */ - popl %eax - /* Reload general-purpose registers to be returned */ - popal - /* Reload segment registers as passed in from caller */ - popw %gs - popw %fs - popw %es - popw %ds - addl $(4+8), %esp /* Skip %cs, %ss and GDT (already reloaded) */ - /* Restore flags (including revert of interrupt status) */ - popfl - - /* Restore physical %esp from entry. It will only be - * different if EB_USE_INTERNAL_STACK was specified. - */ - movl ( 12 + IC_OFFSET_REGISTERS - IC_OFFSET_RETADDR )(%esp), %esp - - /* Check for EB_SKIP_OPCODE */ - pushfl - testl $EB_SKIP_OPCODE, 12(%esp) - jnz 1f - /* Normal return */ - popfl - lret -1: /* Return and skip opcode */ - popfl - lret $4 - -/************************************************************************** -RELOCATE_TO - relocate etherboot to the specified address -**************************************************************************/ - .globl relocate_to -relocate_to: - /* Save the callee save registers */ - pushl %ebp - pushl %esi - pushl %edi - - /* Compute the virtual destination address */ - movl 16(%esp), %edi # dest - subl virt_offset, %edi - - - /* Compute the new value of virt_offset */ - movl 16(%esp), %ebp # virt_offset - subl $_text, %ebp - - /* Fixup the gdt */ - pushl $_pmcs - pushl %ebp # virt_offset - call set_seg_base - addl $8, %esp - - /* Fixup gdtarg */ - leal _gdt(%ebp), %eax - movl %eax, gdtarg +2 - - /* Fixup virt_offset */ - movl %ebp, virt_offset - - /* Load the move parameters */ - movl $_text, %esi - movl $_end, %ecx - subl %esi, %ecx - - /* Move etherboot uses %esi, %edi, %ecx */ - rep - movsb - - /* Reload the gdt */ - cs - lgdt gdtarg - - /* Reload %cs */ - ljmp $KERN_CODE_SEG, $1f -1: - /* reload other segment registers */ - movl $KERN_DATA_SEG, %eax - movl %eax,%ds - movl %eax,%es - movl %eax,%ss - movl %eax,%fs - movl %eax,%gs - - /* Restore the callee save registers */ - popl %edi - popl %esi - popl %ebp - - /* return */ - ret - /************************************************************************** XSTART32 - Transfer control to the kernel just loaded **************************************************************************/ @@ -301,7 +66,7 @@ xstart32: pushl %ebx /* Store the destination address on the stack */ - pushl $FLAT_CODE_SEG + pushl $PHYSICAL_CS pushl %ecx /* Cache virt_offset */ @@ -536,218 +301,6 @@ end_lm: .arch i386 #endif /* CONFIG_X86_64 */ -/************************************************************************** -SETJMP - Save stack context for non-local goto -**************************************************************************/ - .globl setjmp -setjmp: - movl 4(%esp),%ecx /* jmpbuf */ - movl 0(%esp),%edx /* return address */ - movl %edx,0(%ecx) - movl %ebx,4(%ecx) - movl %esp,8(%ecx) - movl %ebp,12(%ecx) - movl %esi,16(%ecx) - movl %edi,20(%ecx) - movl $0,%eax - ret - -/************************************************************************** -LONGJMP - Non-local jump to a saved stack context -**************************************************************************/ - .globl longjmp -longjmp: - movl 4(%esp),%edx /* jumpbuf */ - movl 8(%esp),%eax /* result */ - movl 0(%edx),%ecx - movl 4(%edx),%ebx - movl 8(%edx),%esp - movl 12(%edx),%ebp - movl 16(%edx),%esi - movl 20(%edx),%edi - cmpl $0,%eax - jne 1f - movl $1,%eax -1: movl %ecx,0(%esp) - ret - -/************************************************************************** -_VIRT_TO_PHYS - Transition from virtual to physical addresses - Preserves all preservable registers and flags -**************************************************************************/ - .globl _virt_to_phys -_virt_to_phys: - pushfl - pushl %ebp - pushl %eax - movl virt_offset, %ebp /* Load virt_offset */ - addl %ebp, 12(%esp) /* Adjust the return address */ - - /* reload the code segment */ - pushl $FLAT_CODE_SEG - leal 1f(%ebp), %eax - pushl %eax - lret - -1: - /* reload other segment registers */ - movl $FLAT_DATA_SEG, %eax - movl %eax, %ds - movl %eax, %es - movl %eax, %ss - addl %ebp, %esp /* Adjust the stack pointer */ - movl %eax, %fs - movl %eax, %gs - - popl %eax - popl %ebp - popfl - ret - - -/************************************************************************** -_PHYS_TO_VIRT - Transition from using physical to virtual addresses - Preserves all preservable registers and flags -**************************************************************************/ - .globl _phys_to_virt -_phys_to_virt: - pushfl - pushl %ebp - pushl %eax - - call 1f -1: popl %ebp - subl $1b, %ebp - movl %ebp, virt_offset(%ebp) - - /* Fixup the gdt */ - leal _pmcs(%ebp), %eax - pushl %eax - pushl %ebp - call set_seg_base - addl $8, %esp - - /* Fixup gdtarg */ - leal _gdt(%ebp), %eax - movl %eax, (gdtarg+2)(%ebp) - - /* Load the global descriptor table */ - cli - lgdt %cs:gdtarg(%ebp) - ljmp $KERN_CODE_SEG, $1f -1: - /* reload other segment regsters */ - movl $KERN_DATA_SEG, %eax - movl %eax, %ds - movl %eax, %es - movl %eax, %ss - subl %ebp, %esp /* Adjust the stack pointer */ - movl %eax, %fs - movl %eax, %gs - - subl %ebp, 12(%esp) /* Adjust the return address */ - popl %eax - popl %ebp - popfl - ret - - -/************************************************************************** -SET_SEG_BASE - Set the base address of a segment register -**************************************************************************/ - .globl set_seg_base -set_seg_base: - pushl %eax - pushl %ebx - movl 12(%esp), %eax /* %eax = base address */ - movl 16(%esp), %ebx /* %ebx = &code_descriptor */ - movw %ax, (0+2)(%ebx) /* CS base bits 0-15 */ - movw %ax, (8+2)(%ebx) /* DS base bits 0-15 */ - shrl $16, %eax - movb %al, (0+4)(%ebx) /* CS base bits 16-23 */ - movb %al, (8+4)(%ebx) /* DS base bits 16-23 */ - movb %ah, (0+7)(%ebx) /* CS base bits 24-31 */ - movb %ah, (8+7)(%ebx) /* DS base bits 24-31 */ - popl %ebx - popl %eax - ret - -/************************************************************************** -GLOBAL DESCRIPTOR TABLE -**************************************************************************/ - .data - .align 4 - - .globl _gdt - .globl gdtarg -_gdt: -gdtarg: - .word _gdt_end - _gdt - 1 /* limit */ - .long _gdt /* addr */ - .word 0 - - .globl _pmcs -_pmcs: - /* 32 bit protected mode code segment */ - .word 0xffff,0 - .byte 0,0x9f,0xcf,0 - -_pmds: - /* 32 bit protected mode data segment */ - .word 0xffff,0 - .byte 0,0x93,0xcf,0 - -_rmcs: - /* 16 bit real mode code segment */ - .word 0xffff,(0&0xffff) - .byte (0>>16),0x9b,0x00,(0>>24) - -_rmds: - /* 16 bit real mode data segment */ - .word 0xffff,(0&0xffff) - .byte (0>>16),0x93,0x00,(0>>24) - -_pmcs2: - /* 32 bit protected mode code segment, base 0 */ - .word 0xffff,0 - .byte 0,0x9f,0xcf,0 - -_pmds2: - /* 32 bit protected mode data segment, base 0 */ - .word 0xffff,0 - .byte 0,0x93,0xcf,0 - -#ifdef CONFIG_X86_64 -_lmcs: - /* 64bit long mode code segment, base 0 */ - .word 0xffff, 0 - .byte 0x00, 0x9f, 0xaf , 0x00 -_lmds: - /* 64bit long mode data segment, base 0 */ - .word 0xffff, 0 - .byte 0x00, 0x93, 0xcf, 0x00 -#endif -_gdt_end: - - /* The initial register contents */ - .balign 4 - .globl initial_regs -initial_regs: - .fill 8, 4, 0 - - /* The virtual address offset */ - .globl virt_offset -virt_offset: - .long 0 - - .section ".stack" - .p2align 3 - /* allocate a 4K stack in the stack segment */ - .globl _stack -_stack: - .space 4096 - .globl _estack -_estack: #ifdef CONFIG_X86_64 .section ".bss" .p2align 12 diff --git a/src/arch/i386/core/tagged_loader.c b/src/arch/i386/core/tagged_loader.c index 9c6d6c25..8955b0f8 100644 --- a/src/arch/i386/core/tagged_loader.c +++ b/src/arch/i386/core/tagged_loader.c @@ -1,5 +1,4 @@ #include "realmode.h" -#include "segoff.h" struct segheader { diff --git a/src/arch/i386/core/video_subr.c b/src/arch/i386/core/video_subr.c index dccdd97c..dbcfc73d 100644 --- a/src/arch/i386/core/video_subr.c +++ b/src/arch/i386/core/video_subr.c @@ -5,10 +5,14 @@ * */ -#ifdef CONSOLE_DIRECT_VGA +#include "stddef.h" +#include "string.h" +#include "io.h" +#include "console.h" +#include "init.h" +#include "vga.h" -#include -#include +static struct console_driver vga_console; static char *vidmem; /* The video buffer */ static int video_line, video_col; @@ -17,7 +21,7 @@ static int video_line, video_col; static void memsetw(void *s, int c, unsigned int n) { - int i; + unsigned int i; u16 *ss = (u16 *) s; for (i = 0; i < n; i++) { @@ -25,7 +29,7 @@ static void memsetw(void *s, int c, unsigned int n) } } -void video_init(void) +static void video_init(void) { static int inited=0; @@ -50,7 +54,7 @@ static void video_scroll(void) vidmem[i] = ' '; } -void vga_putc(unsigned char byte) +static void vga_putc(int byte) { if (byte == '\n') { video_line++; @@ -90,5 +94,9 @@ void vga_putc(unsigned char byte) write_crtc((video_col + (video_line *COLS)) & 0x0ff, CRTC_CURSOR_LO); } -#endif +static struct console_driver vga_console __console_driver = { + .putchar = vga_putc, + .disabled = 1, +}; +INIT_FN ( INIT_CONSOLE, video_init, NULL, NULL ); diff --git a/src/arch/i386/core/virtaddr.S b/src/arch/i386/core/virtaddr.S new file mode 100644 index 00000000..ed495c35 --- /dev/null +++ b/src/arch/i386/core/virtaddr.S @@ -0,0 +1,317 @@ +/* + * Functions to support the virtual addressing method of relocation + * that Etherboot uses. + * + */ + +#include "virtaddr.h" + + .arch i386 + +/**************************************************************************** + * GDT for initial transition to protected mode + * + * The segment values, PHYSICAL_CS et al, are defined in an external + * header file virtaddr.h, since they need to be shared with librm. + **************************************************************************** + */ + .data + .align 16 + +gdt: +gdt_limit: .word gdt_length - 1 +gdt_addr: .long 0 + .word 0 /* padding */ + + .org gdt + PHYSICAL_CS +physical_cs: + /* 32 bit protected mode code segment, physical addresses */ + .word 0xffff,0 + .byte 0,0x9f,0xcf,0 + + .org gdt + PHYSICAL_DS +physical_ds: + /* 32 bit protected mode data segment, physical addresses */ + .word 0xffff,0 + .byte 0,0x93,0xcf,0 + + .org gdt + VIRTUAL_CS +virtual_cs: + /* 32 bit protected mode code segment, virtual addresses */ + .word 0xffff,0 + .byte 0,0x9f,0xcf,0 + + .org gdt + VIRTUAL_DS +virtual_ds: + /* 32 bit protected mode data segment, virtual addresses */ + .word 0xffff,0 + .byte 0,0x93,0xcf,0 + +#ifdef CONFIG_X86_64 + + .org gdt + LONG_CS +long_cs: + /* 64bit long mode code segment, base 0 */ + .word 0xffff, 0 + .byte 0x00, 0x9f, 0xaf , 0x00 + + .org gdt + LONG_DS +long_ds: + /* 64bit long mode data segment, base 0 */ + .word 0xffff, 0 + .byte 0x00, 0x93, 0xcf, 0x00 + +#endif /* CONFIG_X86_64 */ + +gdt_end: + .equ gdt_length, gdt_end - gdt + + /* The virtual address offset */ + .globl virt_offset +virt_offset: .long 0 + + .text + .code32 + +/**************************************************************************** + * run_here (flat physical addressing, position-independent) + * + * Set up a GDT to run Etherboot at the current location with virtual + * addressing. This call does not switch to virtual addresses or move + * the stack pointer. The GDT will be located within the copy of + * Etherboot. All registers are preserved. + * + * This gets called at startup and at any subsequent relocation of + * Etherboot. + * + * Parameters: none + **************************************************************************** + */ + .globl run_here +run_here: + /* Preserve registers */ + pushl %eax + pushl %ebp + + /* Find out where we're running */ + call 1f +1: popl %ebp + subl $1b, %ebp + + /* Store as virt_offset */ + movl %ebp, virt_offset(%ebp) + + /* Set segment base addresses in GDT */ + leal virtual_cs(%ebp), %eax + pushl %eax + pushl %ebp + call set_seg_base + popl %eax /* discard */ + popl %eax /* discard */ + + /* Set physical location of GDT */ + leal gdt(%ebp), %eax + movl %eax, gdt_addr(%ebp) + + /* Load the new GDT */ + lgdt gdt(%ebp) + + /* Reload new flat physical segment registers */ + movl $PHYSICAL_DS, %eax + movl %eax, %ds + movl %eax, %es + movl %eax, %fs + movl %eax, %gs + movl %eax, %ss + + /* Restore registers, convert return address to far return + * address. + */ + popl %ebp + movl $PHYSICAL_CS, %eax + xchgl %eax, 4(%esp) /* cs now on stack, ret offset now in eax */ + xchgl %eax, 0(%esp) /* ret offset now on stack, eax restored */ + + /* Return to caller, reloading %cs with new value */ + lret + +/**************************************************************************** + * set_seg_base (any addressing, position-independent) + * + * Set the base address of a pair of segments in the GDT. This relies + * on the layout of the GDT being (CS,DS) pairs. + * + * Parameters: + * uint32_t base_address + * struct gdt_entry * code_segment + * Returns: + * none + **************************************************************************** + */ + .globl set_seg_base +set_seg_base: + pushl %eax + pushl %ebx + movl 12(%esp), %eax /* %eax = base address */ + movl 16(%esp), %ebx /* %ebx = &code_descriptor */ + movw %ax, (0+2)(%ebx) /* CS base bits 0-15 */ + movw %ax, (8+2)(%ebx) /* DS base bits 0-15 */ + shrl $16, %eax + movb %al, (0+4)(%ebx) /* CS base bits 16-23 */ + movb %al, (8+4)(%ebx) /* DS base bits 16-23 */ + movb %ah, (0+7)(%ebx) /* CS base bits 24-31 */ + movb %ah, (8+7)(%ebx) /* DS base bits 24-31 */ + popl %ebx + popl %eax + ret + +/**************************************************************************** + * _virt_to_phys (virtual addressing) + * + * Switch from virtual to flat physical addresses. %esp is adjusted + * to a physical value. Segment registers are set to flat physical + * selectors. All other registers are preserved. Flags are + * preserved. + * + * Parameters: none + * Returns: none + **************************************************************************** + */ + .globl _virt_to_phys +_virt_to_phys: + /* Preserve registers and flags */ + pushfl + pushl %eax + pushl %ebp + + /* Change return address to a physical address */ + movl virt_offset, %ebp + addl %ebp, 12(%esp) + + /* Switch to physical code segment */ + pushl $PHYSICAL_CS + leal 1f(%ebp), %eax + pushl %eax + lret +1: + /* Reload other segment registers and adjust %esp */ + movl $PHYSICAL_DS, %eax + movl %eax, %ds + movl %eax, %es + movl %eax, %fs + movl %eax, %gs + movl %eax, %ss + addl %ebp, %esp + + /* Restore registers and flags, and return */ + popl %ebp + popl %eax + popfl + ret + +/**************************************************************************** + * _phys_to_virt (flat physical addressing) + * + * Switch from flat physical to virtual addresses. %esp is adjusted + * to a virtual value. Segment registers are set to virtual + * selectors. All other registers are preserved. Flags are + * preserved. + * + * Note that this depends on the GDT already being correctly set up + * (e.g. by a call to run_here()). + * + * Parameters: none + * Returns: none + **************************************************************************** + */ + .globl _phys_to_virt +_phys_to_virt: + /* Preserve registers and flags */ + pushfl + pushl %eax + pushl %ebp + + /* Switch to virtual code segment */ + ljmp $VIRTUAL_CS, $1f +1: + /* Reload data segment registers */ + movl $VIRTUAL_DS, %eax + movl %eax, %ds + movl %eax, %es + movl %eax, %fs + movl %eax, %gs + + /* Reload stack segment and adjust %esp */ + movl virt_offset, %ebp + movl %eax, %ss + subl %ebp, %esp + + /* Change the return address to a virtual address */ + subl %ebp, 12(%esp) + + /* Restore registers and flags, and return */ + popl %ebp + popl %eax + popfl + ret + +/**************************************************************************** + * relocate_to (virtual addressing) + * + * Relocate Etherboot to the specified address. The runtime image + * (excluding the prefix, decompressor and compressed image) is copied + * to a new location, and execution continues in the new copy. This + * routine is designed to be called from C code. + * + * Parameters: + * uint32_t new_phys_addr + **************************************************************************** + */ + .globl relocate_to +relocate_to: + /* Save the callee save registers */ + pushl %ebp + pushl %esi + pushl %edi + + /* Compute the physical source address and data length */ + movl $_text, %esi + movl $_end, %ecx + subl %esi, %ecx + addl virt_offset, %esi + + /* Compute the physical destination address */ + movl 16(%esp), %edi + + /* Switch to flat physical addressing */ + call _virt_to_phys + + /* Do the copy */ + cld + rep movsb + + /* Calculate offset to new image */ + subl %esi, %edi + + /* Switch to executing in new image */ + call 1f +1: popl %ebp + leal (2f-1b)(%ebp,%edi), %eax + jmpl *%eax +2: + /* Switch to stack in new image */ + addl %edi, %esp + + /* Call run_here() to set up GDT */ + call run_here + + /* Switch to virtual addressing */ + call _phys_to_virt + + /* Restore the callee save registers */ + popl %edi + popl %esi + popl %ebp + + /* return */ + ret diff --git a/src/arch/i386/drivers/net/undi.c b/src/arch/i386/drivers/net/undi.c index 084fc18a..7e3e7df8 100644 --- a/src/arch/i386/drivers/net/undi.c +++ b/src/arch/i386/drivers/net/undi.c @@ -1436,7 +1436,7 @@ static int undi_isa_probe ( struct dev *dev, * this list. */ static struct pci_id undi_nics[] = { - /* PCI_ROM(0x0000, 0x0000, "undi", "UNDI adaptor"), */ + PCI_ROM(0x0000, 0x0000, "undi", "UNDI driver support"), }; static struct pci_driver undi_driver __pci_driver = { diff --git a/src/arch/i386/firmware/pcbios/bios.c b/src/arch/i386/firmware/pcbios/bios.c index 70f26703..fcbe7f32 100644 --- a/src/arch/i386/firmware/pcbios/bios.c +++ b/src/arch/i386/firmware/pcbios/bios.c @@ -3,11 +3,11 @@ * Body of routines taken from old pcbios.S */ -#ifdef PCBIOS - -#include "etherboot.h" +#include "stdint.h" #include "realmode.h" -#include "segoff.h" +#include "compiler.h" + +#define BIOS_DATA_SEG 0x0040 #define CF ( 1 << 0 ) @@ -23,133 +23,101 @@ timeofday BIOS interrupt. #define CONFIG_BIOS_CURRTICKS 1 #endif #if defined(CONFIG_BIOS_CURRTICKS) -unsigned long currticks (void) -{ +unsigned long currticks ( void ) { static uint32_t days = 0; - uint32_t *ticks = VIRTUAL(0x0040,0x006c); - uint8_t *midnight = VIRTUAL(0x0040,0x0070); + uint32_t ticks; + uint8_t midnight; /* Re-enable interrupts so that the timer interrupt can occur */ - RM_FRAGMENT(rm_currticks, - "sti\n\t" - "nop\n\t" - "nop\n\t" - "cli\n\t" - ); + REAL_EXEC ( rm_currticks, + "sti\n\t" + "nop\n\t" + "nop\n\t" + "cli\n\t", + 0, + OUT_CONSTRAINTS (), + IN_CONSTRAINTS (), + CLOBBER ( "eax" ) ); /* can't have an empty clobber list */ - real_call ( rm_currticks, NULL, NULL ); + get_real ( ticks, BIOS_DATA_SEG, 0x006c ); + get_real ( midnight, BIOS_DATA_SEG, 0x0070 ); - if ( *midnight ) { - *midnight = 0; + if ( midnight ) { + midnight = 0; + put_real ( midnight, BIOS_DATA_SEG, 0x0070 ); days += 0x1800b0; } - return ( days + *ticks ); + return ( days + ticks ); } #endif /* CONFIG_BIOS_CURRTICKS */ -/************************************************************************** -INT15 - Call Interrupt 0x15 -**************************************************************************/ -int int15 ( int ax ) -{ - struct { - reg16_t ax; - } PACKED in_stack; - struct { - reg16_t flags; - } PACKED out_stack; - reg16_t ret_ax; - - RM_FRAGMENT(rm_int15, - "sti\n\t" - "popw %ax\n\t" - "stc\n\t" - "int $0x15\n\t" - "pushf\n\t" - "cli\n\t" - ); - - in_stack.ax.word = ax; - ret_ax.word = real_call ( rm_int15, &in_stack, &out_stack ); - - /* Carry flag clear indicates function not supported */ - if ( ! ( out_stack.flags.word & CF ) ) return 0; - return ret_ax.h; -} - -#ifdef POWERSAVE /************************************************************************** CPU_NAP - Save power by halting the CPU until the next interrupt **************************************************************************/ -void cpu_nap ( void ) -{ - RM_FRAGMENT(rm_cpu_nap, - "sti\n\t" - "hlt\n\t" - "cli\n\t" - ); - - real_call ( rm_cpu_nap, NULL, NULL ); +void cpu_nap ( void ) { + REAL_EXEC ( rm_cpu_nap, + "sti\n\t" + "hlt\n\t" + "cli\n\t", + 0, + OUT_CONSTRAINTS (), + IN_CONSTRAINTS (), + CLOBBER ( "eax" ) ); /* can't have an empty clobber list */ } -#endif /* POWERSAVE */ #if (TRY_FLOPPY_FIRST > 0) /************************************************************************** DISK_INIT - Initialize the disk system **************************************************************************/ -void disk_init ( void ) -{ - RM_FRAGMENT(rm_disk_init, - "sti\n\t" - "xorw %ax,%ax\n\t" - "movb $0x80,%dl\n\t" - "int $0x13\n\t" - "cli\n\t" - ); - - real_call ( rm_disk_init, NULL, NULL ); +void disk_init ( void ) { + REAL_EXEC ( rm_disk_init, + "sti\n\t" + "xorw %ax,%ax\n\t" + "movb $0x80,%dl\n\t" + "int $0x13\n\t" + "cli\n\t", + 0, + OUT_CONSTRAINTS (), + IN_CONSTRAINTS (), + CLOBBER ( "eax", "ebx", "ecx", "edx", + "ebp", "esi", "edi" ) ); } /************************************************************************** DISK_READ - Read a sector from disk **************************************************************************/ unsigned int pcbios_disk_read ( int drive, int cylinder, int head, int sector, - char *buf ) { - struct { - reg16_t ax; - reg16_t cx; - reg16_t dx; - segoff_t buffer; - } PACKED in_stack; - struct { - reg16_t flags; - } PACKED out_stack; - reg16_t ret_ax; + char *fixme_buf ) { + uint16_t ax, flags, discard_c, discard_d; + segoff_t buf = SEGOFF ( fixme_buf ); - RM_FRAGMENT(rm_pcbios_disk_read, - "sti\n\t" - "popw %ax\n\t" - "popw %cx\n\t" - "popw %dx\n\t" - "popw %bx\n\t" - "popw %es\n\t" - "int $0x13\n\t" - "pushfw\n\t" - "cli\n\t" + /* FIXME: buf should be passed in as a segoff_t rather than a + * char * + */ + + REAL_EXEC ( rm_pcbios_disk_read, + "sti\n\t" + "pushl %%ebx\n\t" /* Convert %ebx to %es:bx */ + "popl %%bx\n\t" + "popl %%es\n\t" + "movb $0x02, %%ah\n\t" /* INT 13,2 - Read disk sector */ + "movb $0x01, %%al\n\t" /* Read one sector */ + "int $0x13\n\t" + "pushfw\n\t" + "popw %%bx\n\t" + "cli\n\t", + 4, + OUT_CONSTRAINTS ( "=a" ( ax ), "=b" ( flags ), + "=c" ( discard_c ), "=d" ( discard_d ) ), + IN_CONSTRAINTS ( "c" ( ( ( cylinder & 0xff ) << 8 ) | + ( ( cylinder >> 8 ) & 0x3 ) | + sector ), + "d" ( ( head << 8 ) | drive ), + "b" ( buf ) ), + CLOBBER ( "ebp", "esi", "edi" ) ); ); - in_stack.ax.h = 2; /* INT 13,2 - Read disk sector */ - in_stack.ax.l = 1; /* Read one sector */ - in_stack.cx.h = cylinder & 0xff; - in_stack.cx.l = ( ( cylinder >> 8 ) & 0x3 ) | sector; - in_stack.dx.h = head; - in_stack.dx.l = drive; - in_stack.buffer.segment = SEGMENT ( buf ); - in_stack.buffer.offset = OFFSET ( buf ); - ret_ax.word = real_call ( rm_pcbios_disk_read, &in_stack, &out_stack ); - return ( out_stack.flags.word & CF ) ? ret_ax.word : 0; + return ( flags & CF ) ? ax : 0; } #endif /* TRY_FLOPPY_FIRST */ - -#endif /* PCBIOS */ diff --git a/src/arch/i386/firmware/pcbios/bios_console.c b/src/arch/i386/firmware/pcbios/bios_console.c new file mode 100644 index 00000000..b0bee1ab --- /dev/null +++ b/src/arch/i386/firmware/pcbios/bios_console.c @@ -0,0 +1,76 @@ +/* Etherboot routines for PCBIOS firmware. + * + * Body of routines taken from old pcbios.S + */ + +#include "compiler.h" +#include "realmode.h" +#include "console.h" + +#define ZF ( 1 << 6 ) + +/************************************************************************** +bios_putchar - Print a character on console +**************************************************************************/ +static void bios_putchar ( int character ) { + REAL_EXEC ( rm_console_putc, + "sti\n\t" + "movb $0x0e, %%ah\n\t" + "movl $1, %%ebx\n\t" + "int $0x10\n\t" + "cli\n\t", + 1, + OUT_CONSTRAINTS ( "=a" ( character ) ), + IN_CONSTRAINTS ( "a" ( character ) ), + CLOBBER ( "ebx", "ecx", "edx", "ebp", "esi", "edi" ) ); + + /* NOTE: %eax may be clobbered, so must be specified as an output + * parameter, even though we don't then do anything with it. + */ +} + +/************************************************************************** +bios_getchar - Get a character from console +**************************************************************************/ +static int bios_getchar ( void ) { + uint16_t character; + + REAL_EXEC ( rm_console_getc, + "sti\n\t" + "xorw %%ax, %%ax\n\t" + "int $0x16\n\t" + "cli\n\t", + 1, + OUT_CONSTRAINTS ( "=a" ( character ) ), + IN_CONSTRAINTS (), + CLOBBER ( "ebx", "ecx", "edx", "ebp", "esi", "edi" ) ); + + return ( character & 0xff ); +} + +/************************************************************************** +bios_iskey - Check for keyboard interrupt +**************************************************************************/ +static int bios_iskey ( void ) { + uint16_t flags; + + REAL_EXEC ( rm_console_ischar, + "sti\n\t" + "movb $1, %%ah\n\t" + "int $0x16\n\t" + "pushfw\n\t" + "popw %%ax\n\t" + "cli\n\t", + 1, + OUT_CONSTRAINTS ( "=a" ( flags ) ), + IN_CONSTRAINTS (), + CLOBBER ( "ebx", "ecx", "edx", "ebp", "esi", "edi" ) ); + + return ( ( flags & ZF ) == 0 ); +} + +static struct console_driver bios_console __console_driver = { + .putchar = bios_putchar, + .getchar = bios_getchar, + .iskey = bios_iskey, +}; diff --git a/src/arch/i386/firmware/pcbios/console.c b/src/arch/i386/firmware/pcbios/console.c deleted file mode 100644 index f994f06e..00000000 --- a/src/arch/i386/firmware/pcbios/console.c +++ /dev/null @@ -1,85 +0,0 @@ -/* Etherboot routines for PCBIOS firmware. - * - * Body of routines taken from old pcbios.S - */ - -#ifdef PCBIOS - -#include "etherboot.h" -#include "realmode.h" -#include "segoff.h" - -#define ZF ( 1 << 6 ) - -/************************************************************************** -CONSOLE_PUTC - Print a character on console -**************************************************************************/ -void console_putc ( int character ) -{ - struct { - reg16_t ax; - } PACKED in_stack; - - RM_FRAGMENT(rm_console_putc, - "sti\n\t" - "popw %ax\n\t" - "movb $0x0e, %ah\n\t" - "movl $1, %ebx\n\t" - "int $0x10\n\t" - "cli\n\t" - ); - - in_stack.ax.l = character; - real_call ( rm_console_putc, &in_stack, NULL ); -} - -/************************************************************************** -CONSOLE_GETC - Get a character from console -**************************************************************************/ -int console_getc ( void ) -{ - RM_FRAGMENT(rm_console_getc, - "sti\n\t" - "xorw %ax, %ax\n\t" - "int $0x16\n\t" - "xorb %ah, %ah\n\t" - "cli\n\t" - ); - - return real_call ( rm_console_getc, NULL, NULL ); -} - -/************************************************************************** -CONSOLE_ISCHAR - Check for keyboard interrupt -**************************************************************************/ -int console_ischar ( void ) -{ - RM_FRAGMENT(rm_console_ischar, - "sti\n\t" - "movb $1, %ah\n\t" - "int $0x16\n\t" - "pushfw\n\t" - "popw %ax\n\t" - "cli\n\t" - ); - - return ( ( real_call ( rm_console_ischar, NULL, NULL ) & ZF ) == 0 ); -} - -/************************************************************************** -GETSHIFT - Get keyboard shift state -**************************************************************************/ -int getshift ( void ) -{ - RM_FRAGMENT(rm_getshift, - "sti\n\t" - "movb $2, %ah\n\t" - "int $0x16\n\t" - "andw $0x3, %ax\n\t" - "cli\n\t" - ); - - return real_call ( rm_getshift, NULL, NULL ); -} - -#endif /* PCBIOS */ diff --git a/src/arch/i386/firmware/pcbios/gateA20.c b/src/arch/i386/firmware/pcbios/gateA20.c new file mode 100644 index 00000000..bbee376d --- /dev/null +++ b/src/arch/i386/firmware/pcbios/gateA20.c @@ -0,0 +1,90 @@ +#include "realmode.h" +#include "timer.h" +#include "latch.h" +#include "bios.h" + +#define K_RDWR 0x60 /* keyboard data & cmds (read/write) */ +#define K_STATUS 0x64 /* keyboard status */ +#define K_CMD 0x64 /* keybd ctlr command (write-only) */ + +#define K_OBUF_FUL 0x01 /* output buffer full */ +#define K_IBUF_FUL 0x02 /* input buffer full */ + +#define KC_CMD_WIN 0xd0 /* read output port */ +#define KC_CMD_WOUT 0xd1 /* write output port */ +#define KB_SET_A20 0xdf /* enable A20, + enable output buffer full interrupt + enable data line + disable clock line */ +#define KB_UNSET_A20 0xdd /* enable A20, + enable output buffer full interrupt + enable data line + disable clock line */ + +enum { Disable_A20 = 0x2400, Enable_A20 = 0x2401, Query_A20_Status = 0x2402, + Query_A20_Support = 0x2403 }; + +#define CF ( 1 << 0 ) + +#ifndef IBM_L40 +static void empty_8042 ( void ) +{ + unsigned long time; + char st; + + time = currticks() + TICKS_PER_SEC; /* max wait of 1 second */ + while ((((st = inb(K_CMD)) & K_OBUF_FUL) || + (st & K_IBUF_FUL)) && + currticks() < time) + inb(K_RDWR); +} +#endif /* IBM_L40 */ + +/* + * Gate A20 for high memory + * + * Note that this function gets called as part of the return path from + * librm's real_call, which is used to make the int15 call if librm is + * being used. To avoid an infinite recursion, we make gateA20_set + * return immediately if it is already part of the call stack. + */ +void gateA20_set ( void ) { + static char reentry_guard = 0; + uint16_t flags, status; + + if ( reentry_guard ) + return; + reentry_guard = 1; + + REAL_EXEC ( rm_enableA20, + "sti\n\t" + "stc\n\t" + "int $0x15\n\t" + "pushfw\n\t" + "popw %%bx\n\t" + "cli\n\t", + 2, + OUT_CONSTRAINTS ( "=a" ( status ), "=b" ( flags ) ), + IN_CONSTRAINTS ( "a" ( Enable_A20 ) ), + CLOBBER ( "ecx", "edx", "ebp", "esi", "edi" ) ); + + if ( ( flags & CF ) || + ( ( status >> 8 ) & 0xff ) ) { + /* INT 15 method failed, try alternatives */ +#ifdef IBM_L40 + outb(0x2, 0x92); +#else /* IBM_L40 */ + empty_8042(); + outb(KC_CMD_WOUT, K_CMD); + empty_8042(); + outb(KB_SET_A20, K_RDWR); + empty_8042(); +#endif /* IBM_L40 */ + } + + reentry_guard = 0; +} + +void gateA20_unset ( void ) { + /* Not currently implemented */ +} diff --git a/src/arch/i386/firmware/pcbios/memsizes.c b/src/arch/i386/firmware/pcbios/memsizes.c index 18ae86da..3284e1ef 100644 --- a/src/arch/i386/firmware/pcbios/memsizes.c +++ b/src/arch/i386/firmware/pcbios/memsizes.c @@ -1,7 +1,8 @@ -#ifdef PCBIOS - -#include "etherboot.h" +#include "stdint.h" +#include "stddef.h" #include "realmode.h" +#include "init.h" +#include "memsizes.h" #define CF ( 1 << 0 ) @@ -16,109 +17,131 @@ struct meminfo meminfo; /************************************************************************** BASEMEMSIZE - Get size of the conventional (base) memory **************************************************************************/ -unsigned short basememsize ( void ) -{ - RM_FRAGMENT(rm_basememsize, - "int $0x12\n\t" - ); - return real_call ( rm_basememsize, NULL, NULL ); +static unsigned short basememsize ( void ) { + uint16_t int12_basememsize, fbms_basememsize; + + /* There are two methods for retrieving the base memory size: + * INT 12 and the BIOS FBMS counter at 40:13. We read both + * and use the smaller value, to be paranoid. + */ + + REAL_EXEC ( rm_basememsize, + "int $0x12\n\t", + 1, + OUT_CONSTRAINTS ( "=a" ( int12_basememsize ) ), + IN_CONSTRAINTS (), + CLOBBER ( "ebx", "ecx", "edx", "ebp", "esi", "edi" ) ); + + get_real ( fbms_basememsize, 0x40, 0x13 ); + + return ( int12_basememsize < fbms_basememsize ? + int12_basememsize : fbms_basememsize ); } /************************************************************************** -MEMSIZE - Determine size of extended memory +MEMSIZE - Determine size of extended memory, in kB **************************************************************************/ -unsigned int memsize ( void ) -{ - struct { - reg16_t ax; - } PACKED in_stack; - struct { - reg16_t ax; - reg16_t bx; - reg16_t cx; - reg16_t dx; - reg16_t flags; - } PACKED out_stack; +static unsigned int memsize ( void ) { + uint16_t extmem_1m_to_16m_k, extmem_16m_plus_64k; + uint16_t confmem_1m_to_16m_k, confmem_16m_plus_64k; + uint16_t flags; int memsize; - RM_FRAGMENT(rm_memsize, - /* Some buggy BIOSes don't clear/set carry on pass/error of + /* Try INT 15,e801 first + * + * Some buggy BIOSes don't clear/set carry on pass/error of * e801h memory size call or merely pass cx,dx through without * changing them, so we set carry and zero cx,dx before call. */ - "stc\n\t" - "xorw %cx,%cx\n\t" - "xorw %dx,%dx\n\t" - "popw %ax\n\t" - "int $0x15\n\t" - "pushfw\n\t" - "pushw %dx\n\t" - "pushw %cx\n\t" - "pushw %bx\n\t" - "pushw %ax\n\t" - ); + REAL_EXEC ( rm_mem_e801, + "stc\n\t" + "int $0x15\n\t" + "pushfw\n\t" /* flags -> %di */ + "popw %%di\n\t", + 5, + OUT_CONSTRAINTS ( "=a" ( extmem_1m_to_16m_k ), + "=b" ( extmem_16m_plus_64k ), + "=c" ( confmem_1m_to_16m_k ), + "=d" ( confmem_16m_plus_64k ), + "=D" ( flags ) ), + IN_CONSTRAINTS ( "a" ( 0xe801 ), + "c" ( 0 ), + "d" ( 0 ) ), + CLOBBER ( "ebp", "esi" ) ); - /* Try INT 15,e801 first */ - in_stack.ax.word = 0xe801; - real_call ( rm_memsize, &in_stack, &out_stack ); - if ( out_stack.flags.word & CF ) { - /* INT 15,e801 not supported: try INT 15,88 */ - in_stack.ax.word = 0x8800; - memsize = real_call ( rm_memsize, &in_stack, &out_stack ); - } else { - /* Some BIOSes report extended memory via ax,bx rather - * than cx,dx - */ - if ( (out_stack.cx.word==0) && (out_stack.dx.word==0) ) { - /* Use ax,bx */ - memsize = ( out_stack.bx.word<<6 ) + out_stack.ax.word; + if ( ! ( flags & CF ) ) { + /* INT 15,e801 succeeded */ + if ( confmem_1m_to_16m_k || confmem_16m_plus_64k ) { + /* Use confmem (cx,dx) values */ + memsize = confmem_1m_to_16m_k + + ( confmem_16m_plus_64k << 6 ); } else { - /* Use cx,dx */ - memsize = ( out_stack.dx.word<<6 ) + out_stack.cx.word; + /* Use extmem (ax,bx) values */ + memsize = extmem_1m_to_16m_k + + ( extmem_16m_plus_64k << 6 ); } + } else { + /* INT 15,e801 failed; fall back to INT 15,88 + * + * CF is apparently unreliable and should be ignored. + */ + REAL_EXEC ( rm_mem_88, + "int $0x15\n\t", + 1, + OUT_CONSTRAINTS ( "=a" ( extmem_1m_to_16m_k ) ), + IN_CONSTRAINTS ( "a" ( 0x88 << 8 ) ), + CLOBBER ( "ebx", "ecx", "edx", + "ebp", "esi", "edi" ) ); + memsize = extmem_1m_to_16m_k; } + return memsize; } -#define SMAP ( 0x534d4150 ) -int meme820 ( struct e820entry *buf, int count ) -{ - struct { - reg16_t flags; - reg32_t eax; - reg32_t ebx; - struct e820entry entry; - } PACKED stack; - int index = 0; +/************************************************************************** +MEME820 - Retrieve the E820 BIOS memory map +**************************************************************************/ +#define SMAP ( 0x534d4150 ) /* "SMAP" */ +static int meme820 ( struct e820entry *buf, int count ) { + int index; + uint16_t basemem_entry; + uint32_t smap, next; + uint16_t flags; + uint32_t discard_c, discard_d; - RM_FRAGMENT(rm_meme820, - "addw $6, %sp\n\t" /* skip flags, eax */ - "popl %ebx\n\t" - "pushw %ss\n\t" /* es:di = ss:sp */ - "popw %es\n\t" - "movw %sp, %di\n\t" - "movl $0xe820, %eax\n\t" - "movl $" RM_STR(SMAP) ", %edx\n\t" - "movl $" RM_STR(E820ENTRY_SIZE) ", %ecx\n\t" - "int $0x15\n\t" - "pushl %ebx\n\t" - "pushl %eax\n\t" - "pushfw\n\t" - ); - - stack.ebx.dword = 0; /* 'EOF' marker */ - while ( ( index < count ) && - ( ( index == 0 ) || ( stack.ebx.dword != 0 ) ) ) { - real_call ( rm_meme820, &stack, &stack ); - if ( stack.eax.dword != SMAP ) return 0; - if ( stack.flags.word & CF ) return 0; - buf[index++] = stack.entry; - } + index = 0; + next = 0; + do { + basemem_entry = BASEMEM_PARAMETER_INIT ( buf[index] ); + REAL_EXEC ( rm_mem_e820, + "int $0x15\n\t" + "pushfw\n\t" /* flags -> %di */ + "popw %%di\n\t", + 5, + OUT_CONSTRAINTS ( "=a" ( smap ), + "=b" ( next ), + "=c" ( discard_c ), + "=d" ( discard_d ), + "=D" ( flags ) ), + IN_CONSTRAINTS ( "a" ( 0xe820 ), + "b" ( next ), + "c" ( sizeof (struct e820entry) ), + "d" ( SMAP ), + "D" ( basemem_entry ) ), + CLOBBER ( "ebp", "esi" ) ); + BASEMEM_PARAMETER_DONE ( buf[index] ); + if ( smap != SMAP ) return 0; + if ( flags & CF ) break; + index++; + } while ( ( index < count ) && ( next != 0 ) ); + return index; } -void get_memsizes(void) -{ +/************************************************************************** +GET_MEMSIZES - Retrieve the system memory map via any available means +**************************************************************************/ +void get_memsizes ( void ) { /* Ensure we don't stomp bios data structutres. * the interrupt table: 0x000 - 0x3ff * the bios data area: 0x400 - 0x502 @@ -127,16 +150,19 @@ void get_memsizes(void) static const unsigned min_addr = 0x600; unsigned i; unsigned basemem; - basemem = get_free_base_memory(); + + /* Retrieve memory information from the BIOS */ meminfo.basememsize = basememsize(); + basemem = meminfo.basememsize << 10; meminfo.memsize = memsize(); #ifndef IGNORE_E820_MAP - meminfo.map_count = meme820(meminfo.map, E820MAX); + meminfo.map_count = meme820 ( meminfo.map, E820MAX ); #else meminfo.map_count = 0; #endif - if (meminfo.map_count == 0) { - /* If we don't have an e820 memory map fake it */ + + /* If we don't have an e820 memory map fake it */ + if ( meminfo.map_count == 0 ) { meminfo.map_count = 2; meminfo.map[0].addr = 0; meminfo.map[0].size = meminfo.basememsize << 10; @@ -145,57 +171,56 @@ void get_memsizes(void) meminfo.map[1].size = meminfo.memsize << 10; meminfo.map[1].type = E820_RAM; } + /* Scrub the e820 map */ - for(i = 0; i < meminfo.map_count; i++) { - if (meminfo.map[i].type != E820_RAM) { + for ( i = 0; i < meminfo.map_count; i++ ) { + if ( meminfo.map[i].type != E820_RAM ) { continue; } + /* Reserve the bios data structures */ - if (meminfo.map[i].addr < min_addr) { + if ( meminfo.map[i].addr < min_addr ) { unsigned long delta; delta = min_addr - meminfo.map[i].addr; - if (delta > meminfo.map[i].size) { + if ( delta > meminfo.map[i].size ) { delta = meminfo.map[i].size; } meminfo.map[i].addr = min_addr; meminfo.map[i].size -= delta; } - /* Ensure the returned e820 map is in sync - * with the actual memory state + + /* Ensure the returned e820 map is in sync with the + * actual memory state */ - if ((meminfo.map[i].addr < 0xa0000) && - ((meminfo.map[i].addr + meminfo.map[i].size) > basemem)) - { - if (meminfo.map[i].addr <= basemem) { - meminfo.map[i].size = basemem - meminfo.map[i].addr; + if ( ( meminfo.map[i].addr < 0xa0000 ) && + (( meminfo.map[i].addr+meminfo.map[i].size ) > basemem )){ + if ( meminfo.map[i].addr <= basemem ) { + meminfo.map[i].size = basemem + - meminfo.map[i].addr; } else { meminfo.map[i].addr = basemem; meminfo.map[i].size = 0; } } } + #if MEMSIZES_DEBUG -{ - int i; - printf("basememsize %d\n", meminfo.basememsize); - printf("memsize %d\n", meminfo.memsize); - printf("Memory regions(%d):\n", meminfo.map_count); - for(i = 0; i < meminfo.map_count; i++) { + printf ( "basememsize %d\n", meminfo.basememsize ); + printf ( "memsize %d\n", meminfo.memsize ); + printf ( "Memory regions(%d):\n", meminfo.map_count ); + for ( i = 0; i < meminfo.map_count; i++ ) { unsigned long long r_start, r_end; r_start = meminfo.map[i].addr; r_end = r_start + meminfo.map[i].size; - printf("[%X%X, %X%X) type %d\n", - (unsigned long)(r_start >> 32), - (unsigned long)r_start, - (unsigned long)(r_end >> 32), - (unsigned long)r_end, - meminfo.map[i].type); -#if defined(CONSOLE_FIRMWARE) - sleep(1); /* No way to see 32 entries on a standard 80x25 screen... */ -#endif + printf ( "[%X%X, %X%X) type %d\n", + ( unsigned long ) ( r_start >> 32 ), + ( unsigned long ) r_start, + ( unsigned long ) ( r_end >> 32 ), + ( unsigned long ) r_end, + meminfo.map[i].type ); } -} #endif + } -#endif /* PCBIOS */ +INIT_FN ( INIT_MEMSIZES, get_memsizes, NULL, NULL ); diff --git a/src/arch/i386/include/bios.h b/src/arch/i386/include/bios.h new file mode 100644 index 00000000..afc648ba --- /dev/null +++ b/src/arch/i386/include/bios.h @@ -0,0 +1,10 @@ +#ifndef BIOS_H +#define BIOS_H + +extern unsigned long currticks ( void ); +extern void cpu_nap ( void ); +extern void disk_init ( void ); +extern unsigned int pcbios_disk_read ( int drive, int cylinder, int head, + int sector, char *fixme_buf ); + +#endif /* BIOS_H */ diff --git a/src/arch/i386/include/bochs.h b/src/arch/i386/include/bochs.h new file mode 100644 index 00000000..73f43c36 --- /dev/null +++ b/src/arch/i386/include/bochs.h @@ -0,0 +1,27 @@ +#ifndef BOCHS_H +#define BOCHS_H + +/* + * This file defines "bochsbp", the magic breakpoint instruction that + * is incredibly useful when debugging under bochs. + * + */ + +#ifdef ASSEMBLY + +/* Breakpoint for when debugging under bochs */ +#define bochsbp xchgw %bx, %bx +#define BOCHSBP bochsbp + +#else /* ASSEMBLY */ + +/* Breakpoint for when debugging under bochs */ +static inline void bochsbp ( void ) { + __asm__ __volatile__ ( "xchgw %bx, %bx" ); +} + +#endif /* ASSEMBLY */ + +#warning "bochs.h should not be included into production code" + +#endif /* BOCHS_H */ diff --git a/src/arch/i386/include/hidemem.h b/src/arch/i386/include/hidemem.h index 600a8692..71b0905f 100644 --- a/src/arch/i386/include/hidemem.h +++ b/src/arch/i386/include/hidemem.h @@ -1,7 +1,7 @@ #ifndef HIDEMEM_H #define HIDEMEM_H -#include "segoff.h" +#include "realmode.h" extern int install_e820mangler ( void *new_mangler ); extern int hide_etherboot ( void ); diff --git a/src/arch/i386/include/hooks.h b/src/arch/i386/include/hooks.h index 0764edaf..a4e4b397 100644 --- a/src/arch/i386/include/hooks.h +++ b/src/arch/i386/include/hooks.h @@ -1,9 +1,14 @@ -#ifndef ETHERBOOT_I386_HOOKS_H -#define ETHERBOOT_I386_HOOKS_H +#ifndef HOOKS_H +#define HOOKS_H -void arch_main(in_call_data_t *data, va_list params); -void arch_on_exit(int status); -#define arch_relocate_to(addr) -void arch_relocated_from ( uint32_t old_addr ); +/* in hooks.o */ +extern void arch_initialise ( struct i386_all_regs *regs, + void (*retaddr) (void) ); +extern void arch_main ( struct i386_all_regs *regs ); -#endif /* ETHERBOOT_I386_HOOKS_H */ +/* in hooks_rm.o */ +extern void arch_rm_initialise ( struct i386_all_regs *regs, + void (*retaddr) (void) ); +extern void arch_rm_main ( struct i386_all_regs *regs ); + +#endif /* HOOKS_H */ diff --git a/src/arch/i386/include/io.h b/src/arch/i386/include/io.h index e351a0c1..5b6a6243 100644 --- a/src/arch/i386/include/io.h +++ b/src/arch/i386/include/io.h @@ -1,22 +1,8 @@ #ifndef ETHERBOOT_IO_H #define ETHERBOOT_IO_H - -/* Amount of relocation etherboot is experiencing */ -extern unsigned long virt_offset; - -/* Don't require identity mapped physical memory, - * osloader.c is the only valid user at the moment. - */ -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); -} +#include "compiler.h" +#include "virtaddr.h" /* virt_to_bus converts an addresss inside of etherboot [_start, _end] * into a memory access cards can use. diff --git a/src/arch/i386/include/kir.h b/src/arch/i386/include/kir.h new file mode 100644 index 00000000..84633d26 --- /dev/null +++ b/src/arch/i386/include/kir.h @@ -0,0 +1,18 @@ +#ifndef KIR_H +#define KIR_H + +#ifndef KEEP_IT_REAL +#error "kir.h can be used only with -DKEEP_IT_REAL" +#endif + +#ifdef ASSEMBLY + +#define code32 code16gcc + +#else /* ASSEMBLY */ + +__asm__ ( ".code16gcc" ); + +#endif /* ASSEMBLY */ + +#endif /* KIR_H */ diff --git a/src/arch/i386/include/libkir.h b/src/arch/i386/include/libkir.h new file mode 100644 index 00000000..5bac42d8 --- /dev/null +++ b/src/arch/i386/include/libkir.h @@ -0,0 +1,184 @@ +#ifndef LIBKIR_H +#define LIBKIR_H + +#include "realmode.h" + +#ifndef ASSEMBLY + +/* + * Full API documentation for these functions is in realmode.h. + * + */ + +/* Copy to/from base memory */ + +static inline void copy_to_real_libkir ( uint16_t dest_seg, uint16_t dest_off, + void *src, size_t n ) { + __asm__ ( "movw %4, %%es\n\t" + "cld\n\t" + "rep movsb\n\t" + "pushw %%ds\n\t" /* restore %es */ + "popw %%es\n\t" + : "=S" ( src ), "=D" ( dest_off ), "=c" ( n ) /* clobbered */ + : "S" ( src ), "r" ( dest_seg ), "D" ( dest_off ), "c" ( n ) + : "memory" + ); +} + +static inline void copy_from_real_libkir ( void *dest, + uint16_t src_seg, uint16_t src_off, + size_t n ) { + __asm__ ( "movw %%ax, %%ds\n\t" + "cld\n\t" + "rep movsb\n\t" + "pushw %%es\n\t" /* restore %ds */ + "popw %%ds\n\t" + : "=S" ( src_off ), "=D" ( dest ), "=c" ( n ) /* clobbered */ + : "a" ( src_seg ), "S" ( src_off ), "D" ( dest ), "c" ( n ) + : "memory" + ); +} +#define copy_to_real copy_to_real_libkir +#define copy_from_real copy_from_real_libkir + +/* + * Transfer individual values to/from base memory. There may well be + * a neater way to do this. We have two versions: one for constant + * offsets (where the mov instruction must be of the form "mov + * %es:123, %xx") and one for non-constant offsets (where the mov + * instruction must be of the form "mov %es:(%xx), %yx". If it's + * possible to incorporate both forms into one __asm__ instruction, I + * don't know how to do it. + * + * Ideally, the mov instruction should be "mov%z0"; the "%z0" is meant + * to expand to either "b", "w" or "l" depending on the size of + * operand 0. This would remove the (minor) ambiguity in the mov + * instruction. However, gcc on at least my system barfs with an + * "internal compiler error" when confronted with %z0. + * + */ + +#define put_real_kir_const_off( var, seg, off ) \ + __asm__ ( "movw %w1, %%es\n\t" \ + "mov %0, %%es:%c2\n\t" \ + "pushw %%ds\n\t" /* restore %es */ \ + "popw %%es\n\t" \ + : \ + : "r,r" ( var ), "rm,rm" ( seg ), "i,!r" ( off ) \ + ) + +#define put_real_kir_nonconst_off( var, seg, off ) \ + __asm__ ( "movw %w1, %%es\n\t" \ + "mov %0, %%es:(%2)\n\t" \ + "pushw %%ds\n\t" /* restore %es */ \ + "popw %%es\n\t" \ + : \ + : "r" ( var ), "rm" ( seg ), "r" ( off ) \ + ) + +#define put_real_kir( var, seg, off ) \ + do { \ + if ( __builtin_constant_p ( off ) ) \ + put_real_kir_const_off ( var, seg, off ); \ + else \ + put_real_kir_nonconst_off ( var, seg, off ); \ + } while ( 0 ) + +#define get_real_kir_const_off( var, seg, off ) \ + __asm__ ( "movw %w1, %%es\n\t" \ + "mov %%es:%c2, %0\n\t" \ + "pushw %%ds\n\t" /* restore %es */ \ + "popw %%es\n\t" \ + : "=r,r" ( var ) \ + : "rm,rm" ( seg ), "i,!r" ( off ) \ + ) + +#define get_real_kir_nonconst_off( var, seg, off ) \ + __asm__ ( "movw %w1, %%es\n\t" \ + "mov %%es:(%2), %0\n\t" \ + "pushw %%ds\n\t" /* restore %es */ \ + "popw %%es\n\t" \ + : "=r" ( var ) \ + : "rm" ( seg ), "r" ( off ) \ + ) + +#define get_real_kir( var, seg, off ) \ + do { \ + if ( __builtin_constant_p ( off ) ) \ + get_real_kir_const_off ( var, seg, off ); \ + else \ + get_real_kir_nonconst_off ( var, seg, off ); \ + } while ( 0 ) + +#define put_real put_real_kir +#define get_real get_real_kir + +/* Place/remove parameter on real-mode stack in a way that's + * compatible with libkir + */ +#define BASEMEM_PARAMETER_INIT_LIBKIR( param ) \ + ( ( uint16_t ) ( ( uint32_t ) & ( param ) ) ) +#define BASEMEM_PARAMETER_DONE_LIBKIR( param ) +#define BASEMEM_PARAMETER_INIT BASEMEM_PARAMETER_INIT_LIBKIR +#define BASEMEM_PARAMETER_DONE BASEMEM_PARAMETER_DONE_LIBKIR + +/* REAL_CALL: call an external real-mode routine */ +#define OUT_CONSTRAINTS(...) __VA_ARGS__ +#define IN_CONSTRAINTS(...) "m" ( __routine ), ## __VA_ARGS__ +#define CLOBBER(...) __VA_ARGS__ +#define REAL_CALL( routine, num_out_constraints, out_constraints, \ + in_constraints, clobber ) \ + do { \ + segoff_t __routine = routine; \ + __asm__ __volatile__ ( \ + "pushl %" #num_out_constraints "\n\t" \ + ".code16\n\t" \ + "pushw %%gs\n\t" /* preserve segs */ \ + "pushw %%fs\n\t" \ + "pushw %%es\n\t" \ + "pushw %%ds\n\t" \ + "pushw %%cs\n\t" /* lcall to routine */ \ + "call 1f\n\t" \ + "jmp 2f\n\t" \ + "\n1:\n\t" \ + "addr32 pushl 12(%%esp)\n\t" \ + "lret\n\t" \ + "\n2:\n\t" \ + "popw %%ds\n\t" /* restore segs */ \ + "popw %%es\n\t" \ + "popw %%fs\n\t" \ + "popw %%gs\n\t" \ + "addw $4, %%sp\n\t" \ + ".code16gcc\n\t" \ + : out_constraints : in_constraints : clobber \ + ); \ + } while ( 0 ) + +/* REAL_EXEC: execute some inline assembly code in a way that matches + * the interface of librm + */ + +#define IN_CONSTRAINTS_NO_ROUTINE( routine, ... ) __VA_ARGS__ +#define REAL_EXEC( name, asm_code_str, num_out_constraints, out_constraints, \ + in_constraints, clobber ) \ + __asm__ __volatile__ ( \ + ".code16\n\t" \ + "pushw %%gs\n\t" \ + "pushw %%fs\n\t" \ + "pushw %%es\n\t" \ + "pushw %%ds\n\t" \ + "\n" #name ":\n\t" \ + asm_code_str \ + "popw %%ds\n\t" \ + "popw %%es\n\t" \ + "popw %%fs\n\t" \ + "popw %%gs\n\t" \ + ".code16gcc\n\t" \ + : out_constraints \ + : IN_CONSTRAINTS_NO_ROUTINE ( in_constraints ) \ + : clobber \ + ); + +#endif /* ASSEMBLY */ + +#endif /* LIBKIR_H */ diff --git a/src/arch/i386/include/librm.h b/src/arch/i386/include/librm.h new file mode 100644 index 00000000..16bfc089 --- /dev/null +++ b/src/arch/i386/include/librm.h @@ -0,0 +1,186 @@ +#ifndef LIBRM_H +#define LIBRM_H + +/* Drag in protected-mode segment selector values */ +#include "virtaddr.h" +#include "realmode.h" + +#ifndef ASSEMBLY + +#include "stddef.h" +#include "string.h" + +/* + * Data structures and type definitions + * + */ + +/* Real-mode call parameter block, as passed to real_call */ +struct real_call_params { + struct i386_seg_regs; + struct i386_regs; + segoff_t rm_code; + segoff_t reserved; +} PACKED; + +/* Current location of librm in base memory */ +extern char *installed_librm; + +/* Start and size of our source copy of librm (i.e. the one that we + * can install by copying it to base memory and setting + * installed_librm) + */ +extern char librm[]; +extern size_t _librm_size[]; + +/* Linker symbols for offsets within librm. Other symbols should + * almost certainly not be referred to from C code. + */ +extern void (*_real_to_prot[]) ( void ); +extern void (*_prot_to_real[]) ( void ); +extern void (*_prot_call[]) ( void ); +extern void (*_real_call[]) ( void ); +extern segoff_t _rm_stack[]; +extern uint32_t _pm_stack[]; +extern char _librm_ref_count[]; + +/* Symbols within current installation of librm */ +#define LIBRM_VAR( sym ) \ + ( * ( ( typeof ( * _ ## sym ) * ) \ + & ( installed_librm [ (int) _ ## sym ] ) ) ) +#define LIBRM_FN( sym ) \ + ( ( typeof ( * _ ## sym ) ) \ + & ( installed_librm [ (int) _ ## sym ] ) ) +#define LIBRM_CONSTANT( sym ) \ + ( ( typeof ( * _ ## sym ) ) ( _ ## sym ) ) +#define inst_real_to_prot LIBRM_FN ( real_to_prot ) +#define inst_prot_to_real LIBRM_FN ( prot_to_real ) +#define inst_prot_call LIBRM_FN ( prot_call ) +#define inst_real_call LIBRM_FN ( real_call ) +#define inst_rm_stack LIBRM_VAR ( rm_stack ) +#define inst_pm_stack LIBRM_VAR ( pm_stack ) +#define inst_librm_ref_count LIBRM_VAR ( librm_ref_count ) +#define librm_size LIBRM_CONSTANT ( librm_size ) + +/* Functions that librm expects to be able to link to. Included here + * so that the compiler will catch prototype mismatches. + */ +extern void _phys_to_virt ( void ); +extern void _virt_to_phys ( void ); +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 void copy_to_real_librm ( uint16_t dest_seg, uint16_t dest_off, + void *src, size_t n ) { + memcpy ( VIRTUAL ( dest_seg, dest_off ), src, n ); +} +static inline void copy_from_real_librm ( void *dest, + uint16_t src_seg, uint16_t 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 + +/* Copy to/from real-mode stack */ +extern uint16_t copy_to_rm_stack ( void *data, size_t size ); +extern void remove_from_rm_stack ( void *data, size_t size ); + +/* Place/remove parameter on real-mode stack in a way that's + * compatible with libkir + */ +#define BASEMEM_PARAMETER_INIT_LIBRM( param ) \ + copy_to_rm_stack ( & ( param ), sizeof ( param ) ) +#define BASEMEM_PARAMETER_DONE_LIBRM( param ) \ + remove_from_rm_stack ( & ( param ), sizeof ( param ) ) +#define BASEMEM_PARAMETER_INIT BASEMEM_PARAMETER_INIT_LIBRM +#define BASEMEM_PARAMETER_DONE BASEMEM_PARAMETER_DONE_LIBRM + +/* REAL_FRAGMENT: Declare and define a real-mode code fragment in .text16 */ +#define REAL_FRAGMENT( name, asm_code_str ) \ + extern void name ( void ); \ + extern char name ## _size[]; \ + __asm__ __volatile__ ( \ + ".section \".text16\"\n\t" \ + ".code16\n\t" \ + ".arch i386\n\t" \ + #name ":\n\t" \ + asm_code_str "\n\t" \ + "lret\n\t" \ + #name "_end:\n\t" \ + ".equ " #name "_size, " #name "_end - " #name "\n\t" \ + ".code32\n\t" \ + ".previous\n\t" \ + : : \ + ) +#define FRAGMENT_SIZE( fragment ) ( (size_t) fragment ## _size ) + +/* REAL_CALL: call a real-mode routine via librm */ +#define OUT_CONSTRAINTS(...) __VA_ARGS__ +#define IN_CONSTRAINTS(...) "m" ( __routine ), ## __VA_ARGS__ +#define CLOBBER(...) __VA_ARGS__ +#define REAL_CALL( routine, num_out_constraints, out_constraints, \ + in_constraints, clobber ) \ + do { \ + segoff_t __routine = routine; \ + __asm__ __volatile__ ( \ + "pushl %" #num_out_constraints "\n\t" \ + "call 1f\n\t" \ + "jmp 2f\n\t" \ + "\n1:\n\t" \ + "pushl installed_librm\n\t" \ + "addl $_real_call, 0(%%esp)\n\t" \ + "ret\n\t" \ + "\n2:\n\t" \ + "addl $4, %%esp\n\t" \ + : out_constraints \ + : in_constraints \ + : clobber \ + ); \ + } while ( 0 ) + +/* REAL_EXEC: combine RM_FRAGMENT and REAL_CALL into one handy unit */ +#define PASSTHRU(...) __VA_ARGS__ +#define REAL_EXEC( name, asm_code_str, num_out_constraints, out_constraints, \ + in_constraints, clobber ) \ + do { \ + segoff_t fragment; \ + \ + REAL_FRAGMENT ( name, asm_code_str ); \ + \ + fragment.segment = inst_rm_stack.segment; \ + fragment.offset = \ + copy_to_rm_stack ( name, FRAGMENT_SIZE ( name ) ); \ + \ + REAL_CALL ( fragment, num_out_constraints, \ + PASSTHRU ( out_constraints ), \ + PASSTHRU ( in_constraints ), \ + PASSTHRU ( clobber ) ); \ + \ + remove_from_rm_stack ( NULL, FRAGMENT_SIZE ( name ) ); \ + } while ( 0 ) + +#endif /* ASSEMBLY */ + +#endif /* LIBRM_H */ diff --git a/src/arch/i386/include/memsizes.h b/src/arch/i386/include/memsizes.h new file mode 100644 index 00000000..a5bb3f2d --- /dev/null +++ b/src/arch/i386/include/memsizes.h @@ -0,0 +1,34 @@ +#ifndef MEMSIZES_H +#define MEMSIZES_H + +/* + * These structures seem to be very i386 (and, in fact, PCBIOS) + * specific, so I've moved them out of etherboot.h. + * + */ + +struct e820entry { + uint64_t addr; + uint64_t size; + uint32_t type; +#define E820_RAM 1 +#define E820_RESERVED 2 +#define E820_ACPI 3 /* usable as RAM once ACPI tables have been read */ +#define E820_NVS 4 +} __attribute__ (( packed )); +#define E820ENTRY_SIZE 20 +#define E820MAX 32 + +struct meminfo { + uint16_t basememsize; + uint16_t pad; + uint32_t memsize; + uint32_t map_count; + struct e820entry map[E820MAX]; +} __attribute__ (( packed )); + +extern struct meminfo meminfo; + +extern void get_memsizes ( void ); + +#endif /* MEMSIZES_H */ diff --git a/src/arch/i386/include/pic8259.h b/src/arch/i386/include/pic8259.h index 694e9d13..d3f9b879 100644 --- a/src/arch/i386/include/pic8259.h +++ b/src/arch/i386/include/pic8259.h @@ -8,7 +8,7 @@ #define PIC8259_H /* For segoff_t */ -#include "segoff.h" +#include "realmode.h" #define IRQ_PIC_CUTOFF (8) @@ -90,7 +90,7 @@ void dump_irq_status ( void ); * handler code, so we put prototypes and the size macro here. */ extern void _trivial_irq_handler ( void ); -extern void _trivial_irq_handler_end ( void ); +extern char _trivial_irq_handler_size[]; #define TRIVIAL_IRQ_HANDLER_SIZE FRAGMENT_SIZE(_trivial_irq_handler) #endif /* PIC8259_H */ diff --git a/src/arch/i386/include/pxe_callbacks.h b/src/arch/i386/include/pxe_callbacks.h index 9b941931..cf5a7a87 100644 --- a/src/arch/i386/include/pxe_callbacks.h +++ b/src/arch/i386/include/pxe_callbacks.h @@ -5,7 +5,6 @@ #define PXE_CALLBACKS_H #include "etherboot.h" -#include "segoff.h" #include "pxe.h" typedef struct { diff --git a/src/arch/i386/include/pxe_types.h b/src/arch/i386/include/pxe_types.h index 7b093e6a..45736a2b 100644 --- a/src/arch/i386/include/pxe_types.h +++ b/src/arch/i386/include/pxe_types.h @@ -10,7 +10,7 @@ /* SEGOFF16_t defined in separate header */ -#include "segoff.h" +#include "realmode.h" typedef segoff_t I386_SEGOFF16_t; #define SEGOFF16_t I386_SEGOFF16_t diff --git a/src/arch/i386/include/realmode.h b/src/arch/i386/include/realmode.h index eca92b9b..d641869f 100644 --- a/src/arch/i386/include/realmode.h +++ b/src/arch/i386/include/realmode.h @@ -1,124 +1,124 @@ -/* Real-mode interface - */ +#ifndef REALMODE_H +#define REALMODE_H #ifndef ASSEMBLY -#include "etherboot.h" -#include "segoff.h" +#include "stdint.h" +#include "compiler.h" +#include "registers.h" +#include "io.h" -typedef union { - struct { - union { - uint8_t l; - uint8_t byte; - }; - uint8_t h; - } PACKED; - uint16_t word; -} PACKED reg16_t; - -typedef union { - reg16_t w; - uint32_t dword; -} PACKED reg32_t; - -/* Macros to help with defining inline real-mode trampoline fragments. +/* + * Data structures and type definitions + * */ -#define RM_XSTR(x) #x /* Macro hackery needed to stringify */ + +/* All i386 registers, as passed in by prot_call or kir_call */ +struct real_mode_regs { + struct i386_all_regs; +} PACKED; + +/* Segment:offset structure. Note that the order within the structure + * is offset:segment. + */ +typedef struct { + uint16_t offset; + uint16_t segment; +} segoff_t PACKED; + +/* Macro hackery needed to stringify bits of inline assembly */ +#define RM_XSTR(x) #x #define RM_STR(x) RM_XSTR(x) -#define RM_FRAGMENT(name, asm_code_str) \ - extern void name ( void ); \ - extern void name ## _end (void); \ - __asm__( \ - ".section \".text16\"\n\t" \ - ".code16\n\t" \ - ".arch i386\n\t" \ - ".globl " #name " \n\t" \ - #name ":\n\t" \ - asm_code_str "\n\t" \ - ".globl " #name "_end\n\t" \ - #name "_end:\n\t" \ - ".code32\n\t" \ - ".previous\n\t" \ - ) -#define FRAGMENT_SIZE(fragment) ( (size_t) ( ( (void*) fragment ## _end )\ - - ( (void*) (fragment) ) ) ) - -/* Data structures in _prot_to_real and _real_to_prot. These - * structures are accessed by assembly code as well as C code. - */ -typedef struct { - uint32_t esp; - uint16_t cs; - uint16_t ss; - uint32_t r2p_params; -} PACKED prot_to_real_params_t; - -typedef struct { - uint32_t ret_addr; - uint32_t esp; - uint32_t ebx; - uint32_t esi; - uint32_t edi; - uint32_t ebp; - uint32_t out_stack; - uint32_t out_stack_len; -} PACKED real_to_prot_params_t; - -/* Function prototypes: realmode.c - */ -#define real_call( fragment, in_stack, out_stack ) \ - _real_call ( fragment, FRAGMENT_SIZE(fragment), \ - (void*)(in_stack), \ - ( (in_stack) == NULL ? 0 : sizeof(*(in_stack)) ), \ - (void*)(out_stack), \ - ( (out_stack) == NULL ? 0 : sizeof(*(out_stack)) ) ) -extern uint16_t _real_call ( void *fragment, int fragment_len, - void *in_stack, int in_stack_len, - void *out_stack, int out_stack_len ); -/* Function prototypes: realmode_asm.S - */ -extern void rm_callback_interface; -extern uint16_t rm_callback_interface_size; -extern uint32_t rm_etherboot_location; -extern void _rm_in_call ( void ); -extern void _rm_in_call_far ( void ); - -extern void _prot_to_real_prefix ( void ); -extern void _prot_to_real_prefix_end ( void ); -extern uint16_t prot_to_real_prefix_size; - -extern void _real_to_prot_suffix ( void ); -extern void _real_to_prot_suffix_end ( void ); -extern uint16_t real_to_prot_suffix_size; - -/* PXE assembler bits */ -extern void pxe_callback_interface; -extern uint16_t pxe_callback_interface_size; -extern void _pxe_in_call_far ( void ); -extern void _pxenv_in_call_far ( void ); -extern void _pxe_intercept_int1a ( void ); -extern segoff_t _pxe_intercepted_int1a; -extern segoff_t _pxe_pxenv_location; - -/* Global variables - */ -extern uint32_t real_mode_stack; -extern size_t real_mode_stack_size; -extern int lock_real_mode_stack; - - -/* Function prototypes from basemem.c - */ -#ifdef LINUXBIOS -/* A silly hard code that let's the code compile and work. - * When this becomes a problem feel free to implement - * something better. - */ -static inline void allot_real_mode_stack(void) { real_mode_stack = 0x7c00; } +/* Drag in the selected real-mode transition library header */ +#ifdef KEEP_IT_REAL +#include "libkir.h" #else -void allot_real_mode_stack(void); +#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. + * + */ + +/* + * 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 ) + * + * These functions can be used to copy data to and from arbitrary + * locations in base memory. + */ + +/* + * put_real ( variable, uint16_t dest_seg, uint16_t dest_off ) + * get_real ( variable, uint16_t src_seg, uint16_t src_off ) + * + * 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. + */ + +/* + * REAL_CALL ( routine, num_out_constraints, out_constraints, + * in_constraints, clobber ) + * REAL_EXEC ( name, asm_code_str, num_out_constraints, out_constraints, + * in_constraints, clobber ) + * + * If you have a pre-existing real-mode routine that you want to make + * a far call to, use REAL_CALL. If you have a code fragment that you + * want to copy down to base memory, execute, and then remove, use + * REAL_EXEC. + * + * out_constraints must be of the form OUT_CONSTRAINTS(constraints), + * and in_constraints must be of the form IN_CONSTRAINTS(constraints), + * where "constraints" is a constraints list as would be used in an + * inline __asm__() + * + * clobber must be of the form CLOBBER ( clobber_list ), where + * "clobber_list" is a clobber list as would be used in an inline + * __asm__(). + * + * These are best illustrated by example. To write a character to the + * console using INT 10, you would do something like: + * + * REAL_EXEC ( rm_test_librm, + * "int $0x10", + * 1, + * OUT_CONSTRAINTS ( "=a" ( discard ) ), + * IN_CONSTRAINTS ( "a" ( 0x0e00 + character ), + * "b" ( 1 ) ), + * CLOBBER ( "ebx", "ecx", "edx", "ebp", "esi", "edi" ) ); + * + * IMPORTANT: gcc does not automatically assume that input operands + * get clobbered. The only way to specify that an input operand may + * be modified is to also specify it as an output operand; hence the + * "(discard)" in the above code. + */ + +#warning "realmode.h contains placeholders for obsolete macros" + + +/* Just for now */ +#define SEGMENT(x) ( virt_to_phys ( x ) >> 4 ) +#define OFFSET(x) ( virt_to_phys ( x ) & 0xf ) +#define SEGOFF(x) { OFFSET(x), SEGMENT(x) } + +/* To make basemem.c compile */ +extern int lock_real_mode_stack; +extern char *real_mode_stack; +extern char real_mode_stack_size[]; + +#define RM_FRAGMENT(name,asm) \ + void name ( void ) {} \ + extern char name ## _size[]; + + + #endif /* ASSEMBLY */ + +#endif /* REALMODE_H */ diff --git a/src/arch/i386/include/registers.h b/src/arch/i386/include/registers.h new file mode 100644 index 00000000..2e78d418 --- /dev/null +++ b/src/arch/i386/include/registers.h @@ -0,0 +1,93 @@ +#ifndef REGISTERS_H +#define REGISTERS_H + +#include "stdint.h" +#include "compiler.h" + +/* Basic 16-bit and 32-bit register types */ +typedef union { + struct { + union { + uint8_t l; + uint8_t byte; + }; + uint8_t h; + } PACKED; + uint16_t word; +} PACKED reg16_t; + +typedef union { + reg16_t; + uint32_t dword; +} PACKED reg32_t; + +/* As created by pushal / read by popal */ +struct i386_regs { + union { + uint16_t di; + uint32_t edi; + }; + union { + uint16_t si; + uint32_t esi; + }; + union { + uint16_t bp; + uint32_t ebp; + }; + union { + uint16_t sp; + uint32_t esp; + }; + union { + struct { + uint8_t bl; + uint8_t bh; + } PACKED; + uint16_t bx; + uint32_t ebx; + }; + union { + struct { + uint8_t dl; + uint8_t dh; + } PACKED; + uint16_t dx; + uint32_t edx; + }; + union { + struct { + uint8_t cl; + uint8_t ch; + } PACKED; + uint16_t cx; + uint32_t ecx; + }; + union { + struct { + uint8_t al; + uint8_t ah; + } PACKED; + uint16_t ax; + uint32_t eax; + }; +} PACKED; + +/* Our pushal/popal equivalent for segment registers */ +struct i386_seg_regs { + uint16_t cs; + uint16_t ss; + uint16_t ds; + uint16_t es; + uint16_t fs; + uint16_t gs; +} PACKED; + +/* All i386 registers, as passed in by prot_call or kir_call */ +struct i386_all_regs { + struct i386_seg_regs; + struct i386_regs; + uint32_t i386_flags; +} PACKED; + +#endif /* REGISTERS_H */ diff --git a/src/arch/i386/include/segoff.h b/src/arch/i386/include/segoff.h deleted file mode 100644 index 822ddd33..00000000 --- a/src/arch/i386/include/segoff.h +++ /dev/null @@ -1,41 +0,0 @@ -/* - * Segment:offset types and macros - * - * Initially written by Michael Brown (mcb30). - */ - -#ifndef SEGOFF_H -#define SEGOFF_H - -#include -#include -#include - -/* Segment:offset structure. Note that the order within the structure - * is offset:segment. - */ -typedef struct { - uint16_t offset; - uint16_t segment; -} segoff_t; - -/* Macros for converting from virtual to segment:offset addresses, - * when we don't actually care which of the many isomorphic results we - * get. - */ -#ifdef DEBUG_SEGMENT -uint16_t SEGMENT ( const void * const ptr ) { - uint32_t phys = virt_to_phys ( ptr ); - if ( phys > 0xfffff ) { - printf ( "FATAL ERROR: segment address out of range\n" ); - } - return phys >> 4; -} -#else -#define SEGMENT(x) ( virt_to_phys ( x ) >> 4 ) -#endif -#define OFFSET(x) ( virt_to_phys ( x ) & 0xf ) -#define SEGOFF(x) { OFFSET(x), SEGMENT(x) } -#define VIRTUAL(x,y) ( phys_to_virt ( ( ( x ) << 4 ) + ( y ) ) ) - -#endif /* SEGOFF_H */ diff --git a/src/arch/i386/include/virtaddr.h b/src/arch/i386/include/virtaddr.h new file mode 100644 index 00000000..15fad1cc --- /dev/null +++ b/src/arch/i386/include/virtaddr.h @@ -0,0 +1,85 @@ +#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 PHYSICAL_CS 0x08 +#define PHYSICAL_DS 0x10 +#define VIRTUAL_CS 0x18 +#define VIRTUAL_DS 0x20 +#define LONG_CS 0x28 +#define LONG_DS 0x30 + +#ifndef ASSEMBLY + +#include "stdint.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 ); +} + +#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/src/arch/i386/kir-Makefile b/src/arch/i386/kir-Makefile new file mode 100644 index 00000000..cc37a91a --- /dev/null +++ b/src/arch/i386/kir-Makefile @@ -0,0 +1,29 @@ +# Makefile to build a KEEP_IT_REAL flavour +# +# KEEP_IT_REAL, by its nature, requires a different build of every +# single object file, since the inclusion of ".code16gcc" will +# generate different machine code from the assembly. Unlike the other +# config options, there is no way that this global dependency can ever +# be reduced, so it makes sense to be able to build both the normal +# and the KIR versions without having to force a full rebuild each +# time. + +# Add this Makefile to MAKEDEPS +# +MAKEDEPS += arch/i386/kir-Makefile + +# Place binaries in bin-kir +# +BIN = bin-kir + +# Compile with -DKEEP_IT_REAL, forcibly include kir.h at the start of +# each file to drag in ".code16gcc" +# +CFLAGS += -DKEEP_IT_REAL -include kir.h + +# Link with _data_link_addr = 0; data symbols are relative to the data +# segment. +# +LDFLAGS += --defsym _data_link_addr=0 + +include Makefile diff --git a/src/arch/i386/prefix/floppyprefix.S b/src/arch/i386/prefix/dskprefix.S similarity index 88% rename from src/arch/i386/prefix/floppyprefix.S rename to src/arch/i386/prefix/dskprefix.S index 18bed4c8..d1f64e7a 100644 --- a/src/arch/i386/prefix/floppyprefix.S +++ b/src/arch/i386/prefix/dskprefix.S @@ -1,3 +1,5 @@ +#include "compiler.h" + /* NOTE: this boot sector contains instructions that need at least an 80186. * Yes, as86 has a bug somewhere in the valid instruction set checks. * @@ -115,7 +117,6 @@ got_sectors: /* ok, we've written the Loading... message, now we want to load the system */ - pushw %es /* = ds */ movw $SYSSEG, %ax movw %ax,%es /* segment of SYSSEG<<4 */ pushw %es @@ -130,8 +131,6 @@ got_sectors: call print_nl pop %es /* = SYSSEG */ - pop %es /* balance push/pop es */ -sigok: /* Restore original disk parameters */ movw $0x78, %bx @@ -142,20 +141,47 @@ sigok: movw %di,(%bx) movw %si,2(%bx) -/* after that (everything loaded), we call to the .ROM file loaded. */ + /* Everything now loaded. %es = SYSSEG, so %es:0000 points to + * start of loaded image. + */ - pushl $0 /* No parameters to preserve for exit path */ - pushw $0 /* Use prefix exit path mechanism */ - ljmp $SYSSEG, $_start +start_runtime: - .section ".text16", "ax", @progbits - .globl prefix_exit -prefix_exit: - xchgw %bx, %bx - int $0x19 /* should try to boot machine */ - .globl prefix_exit_end -prefix_exit_end: - .previous +#ifdef COMPRESS + /* Decompress runtime image. %es:0000 points to decompressed + * image on exit. + */ + lcall $SYSSEG, $decompress16 +#endif + + /* Set up internal environment. Address of entry-point + * function is returned in %es:di. + */ + pushw %es /* setup16 says %ds:0000 must point to image */ + popw %ds + movw $setup16, %di + pushw %cs + call ljmp_to_es_di + + /* Call initialisation routine. Relocation may be done. New + * address of entry-point function is returned in %es:di. + */ + pushl $arch_rm_initialise + pushw %cs /* == lcall %es:di */ + call ljmp_to_es_di + + /* Call to arch_rm_main. Register INT19 as an exit path. This + * call will never return. + */ + movl $exit_via_int19, %eax + pushl $arch_rm_main + pushl %eax /* Dummy return address */ + + /* Do the equivalent of ljmp *%es:di */ +ljmp_to_es_di: + pushw %es + pushw %di + lret /* This routine loads the system at address SYSSEG<<4, making sure no 64kB * boundaries are crossed. We try to load it as fast as possible, loading whole @@ -164,7 +190,7 @@ prefix_exit_end: * in: es - starting address segment (normally SYSSEG) */ read_it: - movw $0,sread /* read whole image incl boot sector */ + movw $1,sread /* don't reload the prefix */ movw %es,%ax testw $0x0fff, %ax die: jne die /* es must be at 64kB boundary */ diff --git a/src/arch/i386/prefix/int19exit.c b/src/arch/i386/prefix/int19exit.c new file mode 100644 index 00000000..e7be0624 --- /dev/null +++ b/src/arch/i386/prefix/int19exit.c @@ -0,0 +1,13 @@ +#include "bochs.h" +#include "realmode.h" + +/* + * The "exit via INT 19" exit path. INT 19 is the old (pre-BBS) "boot + * system" interrupt. + * + */ + +void exit_via_int19 ( struct real_mode_regs *rm_regs ) { + bochsbp(); + /* Placeholder */ +} diff --git a/src/arch/i386/prefix/unnrv2b.S b/src/arch/i386/prefix/unnrv2b.S index 1836fa71..50776dc9 100644 --- a/src/arch/i386/prefix/unnrv2b.S +++ b/src/arch/i386/prefix/unnrv2b.S @@ -15,115 +15,159 @@ * - Structure modified to be a subroutine call rather than an * executable prefix. * Michael Brown 30 Mar 2004 + * + * - Modified to be compilable as either 16-bit or 32-bit code. + * Michael Brown 9 Mar 2005 */ +/**************************************************************************** + * This file provides the decompress_block() and decompress_block16() + * functions which can be called in order to decompress an image + * compressed with the nrv2b utility in src/util. + * + * These functions are designed to be called by the prefix. They are + * position-independent code. + * + * The same basic assembly code is used to compile both + * decompress_block() and decompress_block16(). + **************************************************************************** + */ .text .arch i386 .section ".prefix", "ax", @progbits - .code32 + +#ifdef CODE16 +/**************************************************************************** + * decompress_block16 (real-mode near call, position independent) + * + * Parameters (passed via registers): + * %ds:%si - Pointer to compressed input data + * %es:%di - Pointer to output buffer + * Returns: + * All registers are preserved + * + * NOTE: The compressed data size must be in the range [1,65533-%si] + * and the uncompressed data size must be in the range [1,65536-%di] + * (where %si and %di are the input values for those registers). Note + * particularly that the lower limit is 1, not 0, and that the upper + * limit on the input (compressed) data really is 65533, since the + * algorithm may read up to three bytes beyond the end of the input + * data, since it reads dwords. + * + * Although splitting up the data into (almost) 64kB chunks for + * compression is awkward and worsens the compression ratio, it has + * little to no practical effect since our image size is currently + * <64kB for all single drivers. Having a decompression routine that + * can run in real-mode avoids the need to duplicate RM-to-PM + * transition code from librm (or have part of librm kept + * uncompressed, which is itself awkward) and means that we don't need + * to set up the PM stack until we hit the setup routine itself. + **************************************************************************** + */ + +#define REG(x) x + + .code16 + .globl decompress_block16 +decompress_block16: - .globl decompress -decompress: - /* Save the initial register values */ +#else /* CODE16 */ + +/**************************************************************************** + * decompress_block (32-bit protected-mode near call, position independent) + * + * Parameters (passed via registers): + * %ds:%esi - Pointer to compressed input data + * %es:%edi - Pointer to output buffer + * Returns: + * All registers are preserved + **************************************************************************** + */ + +#define REG(x) e ## x + + .code32 + .globl decompress_block +decompress_block: + +#endif /* CODE16 */ + +#define xAX REG(ax) +#define xCX REG(cx) +#define xBP REG(bp) +#define xSI REG(si) +#define xDI REG(di) + + /* Save registers */ pushal - - /* - * See where I am running, and compute %ebp - * %ebp holds delta between physical and virtual addresses. - */ - call 1f -1: popl %ebp - subl $1b, %ebp - - /* "compressed" and "decompress_to" defined by linker script */ - /* move compressed image up to temporary area before decompressing */ - std - movl $_compressed_size, %ecx - leal _compressed+4-1(%ebp, %ecx), %esi - leal _compressed_copy-1(%ebp, %ecx), %edi - rep movsb - /* Setup to run the decompressor */ + /* Do the decompression */ cld - leal _compressed_copy(%ebp), %esi - leal decompress_to(%ebp), %edi - movl $-1, %ebp /* last_m_off = -1 */ + xor %xBP, %xBP + dec %xBP /* last_m_off = -1 */ jmp dcl1_n2b - -/* ------------- DECOMPRESSION ------------- - - Input: - %esi - source - %edi - dest - %ebp - -1 - cld - - Output: - %eax - 0 - %ecx - 0 -*/ - -.macro getbit bits -.if \bits == 1 - addl %ebx, %ebx - jnz 1f -.endif - movl (%esi), %ebx - subl $-4, %esi /* sets carry flag */ - adcl %ebx, %ebx -1: -.endm - + decompr_literals_n2b: movsb - decompr_loop_n2b: addl %ebx, %ebx jnz dcl2_n2b dcl1_n2b: - getbit 32 + call getbit32 dcl2_n2b: jc decompr_literals_n2b - xorl %eax, %eax - incl %eax /* m_off = 1 */ + xor %xAX, %xAX + inc %xAX /* m_off = 1 */ loop1_n2b: - getbit 1 - adcl %eax, %eax /* m_off = m_off*2 + getbit() */ - getbit 1 + call getbit1 + adc %xAX, %xAX /* m_off = m_off*2 + getbit() */ + call getbit1 jnc loop1_n2b /* while(!getbit()) */ - xorl %ecx, %ecx - subl $3, %eax + sub $3, %xAX jb decompr_ebpeax_n2b /* if (m_off == 2) goto decompr_ebpeax_n2b ? */ - shll $8, %eax - movb (%esi), %al /* m_off = (m_off - 3)*256 + src[ilen++] */ - incl %esi - xorl $-1, %eax + shl $8, %xAX + movb (%xSI), %al /* m_off = (m_off - 3)*256 + src[ilen++] */ + inc %xSI + not %xAX jz decompr_end_n2b /* if (m_off == 0xffffffff) goto decomp_end_n2b */ - movl %eax, %ebp /* last_m_off = m_off ?*/ + mov %xAX, %xBP /* last_m_off = m_off ?*/ decompr_ebpeax_n2b: - getbit 1 - adcl %ecx, %ecx /* m_len = getbit() */ - getbit 1 - adcl %ecx, %ecx /* m_len = m_len*2 + getbit()) */ + xor %xCX, %xCX + call getbit1 + adc %xCX, %xCX /* m_len = getbit() */ + call getbit1 + adc %xCX, %xCX /* m_len = m_len*2 + getbit()) */ jnz decompr_got_mlen_n2b /* if (m_len == 0) goto decompr_got_mlen_n2b */ - incl %ecx /* m_len++ */ + inc %xCX /* m_len++ */ loop2_n2b: - getbit 1 - adcl %ecx, %ecx /* m_len = m_len*2 + getbit() */ - getbit 1 + call getbit1 + adc %xCX, %xCX /* m_len = m_len*2 + getbit() */ + call getbit1 jnc loop2_n2b /* while(!getbit()) */ - incl %ecx - incl %ecx /* m_len += 2 */ + inc %xCX + inc %xCX /* m_len += 2 */ decompr_got_mlen_n2b: - cmpl $-0xd00, %ebp - adcl $1, %ecx /* m_len = m_len + 1 + (last_m_off > 0xd00) */ - pushl %esi - leal (%edi,%ebp), %esi /* m_pos = dst + olen + -m_off */ + cmp $-0xd00, %xBP + adc $1, %xCX /* m_len = m_len + 1 + (last_m_off > 0xd00) */ + push %xSI + lea (%xBP,%xDI), %xSI /* m_pos = dst + olen + -m_off */ rep - movsb /* dst[olen++] = *m_pos++ while(m_len > 0) */ - popl %esi + es movsb /* dst[olen++] = *m_pos++ while(m_len > 0) */ + pop %xSI jmp decompr_loop_n2b + + +getbit1: + addl %ebx, %ebx + jnz 1f +getbit32: + movl (%xSI), %ebx + sub $-4, %xSI /* sets carry flag */ + adcl %ebx, %ebx +1: + ret + decompr_end_n2b: - /* Restore the initial register values */ + /* Restore registers and return */ popal ret diff --git a/src/arch/i386/scripts/i386.lds b/src/arch/i386/scripts/i386.lds new file mode 100644 index 00000000..4f9df561 --- /dev/null +++ b/src/arch/i386/scripts/i386.lds @@ -0,0 +1,263 @@ +/* -*- sh -*- */ + +/* + * Linker script for i386 images + * + */ + +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. + * + * The linker symbols {prefix,decompress,text,data}_link_addr, + * load_addr, and _max_align may be specified explicitly. If not + * specified, they will default to: + * + * _prefix_link_addr = 0 + * _decompress_link_addr = 0 + * _text_link_addr = 0 + * _data_link_addr = _text_link_addr + sizeof ( text sections ) + * _load_addr = 0 + * _max_align = 16 + * + * We guarantee alignment of virtual addresses to any alignment + * specified by the constituent object files (e.g. via + * __attribute__((aligned(x)))). Load addresses are guaranteed + * only up to _max_align. Provided that all loader and relocation + * code honours _max_align, this means that physical addresses are + * also guaranteed up to _max_align. + * + * Note that when using -DKEEP_IT_REAL, the UNDI segments are only + * guaranteed to be loaded on a paragraph boundary (i.e. 16-byte + * alignment). Using _max_align>16 will therefore not guarantee + * >16-byte alignment of physical addresses when -DKEEP_IT_REAL is + * used (though virtual addresses will still be fully aligned). + * + * The real-mode prefixes rely on _text_link_addr and + * _decompress_link_addr being 0, since they issue far calls into + * those sections, thus requiring that symbol_value == + * symbol_offset therein. Using the linker to calculate + * e.g. offset_setup16=setup16-_text will not work, since you then + * cannot use the reference from the prefix to setup16 to drag in + * setup16.o. Life is hard. + * + * If librm is included, then it must go at offset 0 within the + * text section. This is because librm is dual-usage: it is + * called from setup16 with %cs:0000 pointing to the start of the + * text section, and later it will be copied to base memory and + * called with %cs:0000 pointing to the start of librm. + * + * The decompressor is designed to decompress in-place. After + * calling the decompressor, the image will look exactly the same + * as the uncompressed image; the compressed data and the + * decompressor code itself will have been overwritten. + */ + + /* + * The prefix + */ + + _prefix_link_addr = DEFINED ( _prefix_link_addr ) ? _prefix_link_addr : 0; + . = _prefix_link_addr; + _prefix = .; + + .prefix : AT ( _prefix_load_offset + __prefix ) { + __prefix = .; + _entry = .; + *(.prefix) + *(.prefix.*) + } + + _eprefix = .; + + /* + * The decompressor (may be absent) + */ + + _decompress_link_addr = DEFINED ( _decompress_link_addr ) ? + _decompress_link_addr : 0; + . = _decompress_link_addr; + _decompress = .; + + .decompress : AT ( _decompress_load_offset + __decompress ) { + __decompress = .; + *(.decompress) + *(.decompress.*) + } + + _edecompress = .; + + /* + * The text sections + */ + + _text_link_addr = DEFINED ( _text_link_addr ) ? _text_link_addr : 0; + . = _text_link_addr; + _text = .; + + .text16 : AT ( _text_load_offset + __text16 ) { + __text16 = .; + + /* librm is a special case; it must go at the start of the + * text section if it is included. + */ + _assert = ASSERT ( ( . == _text_link_addr ), "librm cannot go first" ); + *(.librm) + + *(.text16) + *(.text16.*) + } = 0x9090 + + .text : AT ( _text_load_offset + __text ) { + __text = .; + *(.text) + *(.text.*) + } = 0x9090 + + _etext = .; + + /* + * The data sections + */ + + _data_link_addr = DEFINED ( _data_link_addr ) ? _data_link_addr : .; + . = _data_link_addr; + _data = .; + + .rodata : AT ( _data_load_offset + __rodata ) { + __rodata = .; + *(.rodata) + *(.rodata.*) + } + + .data : AT ( _data_load_offset + __data ) { + __data = .; + *(.data) + *(.data.*) + pci_drivers = .; + *(.drivers.pci) + pci_drivers_end = .; + isa_drivers = .; + *(.drivers.isa) + isa_drivers_end = .; + console_drivers = .; + *(.drivers.console) + console_drivers_end = .; + init_fns = .; + *(SORT(.init_fns.*)) + init_fns_end = .; + + _progbits_end = .; + } + + .bss : AT ( _data_load_offset + __bss ) { + __bss = .; + _bss = .; + *(.bss) + *(.bss.*) + *(COMMON) + _ebss = .; + } + + .stack : AT ( _data_load_offset + __stack ) { + __stack = .; + *(.stack) + *(.stack.*) + } + + _edata = .; + + _end = .; + + /* + * Dispose of the comment and note sections to make the link map + * easier to read + */ + + /DISCARD/ : { + *(.comment) + *(.note) + } + + /* + * Load address calculations. The slightly obscure nature of the + * calculations is because ALIGN(x) can only operate on the + * location counter. + */ + + _max_align = DEFINED ( _max_align ) ? _max_align : 16; + _load_addr = DEFINED ( _load_addr ) ? _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_load_addr + _prefix_size; + + . -= _decompress_link_addr; + _decompress_load_offset = ALIGN ( _max_align ); + _decompress_load_addr = _decompress_link_addr + _decompress_load_offset; + _decompress_size = _edecompress - _decompress; + . = _decompress_load_addr + _decompress_size; + + . -= _text_link_addr; + _text_load_offset = ALIGN ( _max_align ); + _text_load_addr = _text_link_addr + _text_load_offset; + _text_size = _etext - _text; + . = _text_load_addr + _text_size; + + . -= _data_link_addr; + _data_load_offset = ALIGN ( _max_align ); + _data_load_addr = _data_link_addr + _data_load_offset; + _data_size = _edata - _data; + . = _data_load_addr + _data_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" ); + + . = _decompress_load_addr - _prefix_link_addr; + _assert = ASSERT ( ( . == ALIGN ( _max_align ) ), + "_decompress is badly aligned" ); + + . = _text_load_addr - _text_link_addr; + _assert = ASSERT ( ( . == ALIGN ( _max_align ) ), + "_text is badly aligned" ); + + . = _data_load_addr - _data_link_addr; + _assert = ASSERT ( ( . == ALIGN ( _max_align ) ), + "_data is badly aligned" ); + + /* + * setup16 needs to know this when KEEP_IT_REAL is used. There + * are no harmful side-effects of calculating it all the time. + */ + _text_load_size_pgh = ( _data_load_addr - _text_load_addr ) / 16 ; + + /* + * Useful-to-know values. + */ + + /* Size of the decompressed runtime image */ + _runtime_size = _edata - _text; + /* Size of the initialised-contents portion of the runtime image */ + _runtime_progbits_size = _progbits_end - _text; + /* Size of the (non-compressed) binary file */ + _file_size = _prefix_size + _runtime_progbits_size; + /* Size of the non-compressed portion of the compressed binary file */ + _zfile_noncompressed_size = _prefix_size + _decompress_size; +} diff --git a/src/arch/i386/transitions/libkir.S b/src/arch/i386/transitions/libkir.S new file mode 100644 index 00000000..79a0aa00 --- /dev/null +++ b/src/arch/i386/transitions/libkir.S @@ -0,0 +1,243 @@ +/* + * libkir: a transition library for -DKEEP_IT_REAL + * + * Michael Brown + * + */ + +/**************************************************************************** + * This file defines libkir: an interface between external and + * internal environments when -DKEEP_IT_REAL is used, so that both + * internal and external environments are in real mode. It deals with + * switching data segments and the stack. It provides the following + * functions: + * + * ext_to_kir & switch between external and internal (kir) + * kir_to_ext environments, preserving all non-segment + * registers + * + * kir_call issue a call to an internal routine from external + * code + * + * libkir is written to avoid assuming that segments are anything + * other than opaque data types, and also avoids assuming that the + * stack pointer is 16-bit. This should enable it to run just as well + * in 16:16 or 16:32 protected mode as in real mode. + **************************************************************************** + */ + +/* Breakpoint for when debugging under bochs */ +#define BOCHSBP xchgw %bx, %bx + + .text + .arch i386 + .section ".text16", "awx", @progbits + .code16 + +/**************************************************************************** + * ext_to_kir (real-mode or 16:xx protected-mode near call) + * + * Switch from external stack and segment registers to internal stack + * and segment registers. %ss:sp is restored from the saved kir_ds + * and kir_sp. %ds, %es, %fs and %gs are all restored from the saved + * kir_ds. All other registers are preserved. + * + * %cs:0000 must point to the start of the runtime image code segment + * on entry. + * + * Note that this routine can be called *without* having first set up + * a stored kir_ds and kir_sp. If you do this, ext_to_kir will return + * without altering the segment registers or stack pointer. + * + * Parameters: none + **************************************************************************** + */ + + .globl ext_to_kir +ext_to_kir: + /* Record external segment registers */ + movw %ds, %cs:ext_ds + pushw %cs + popw %ds /* Set %ds = %cs for easier access to variables */ + movw %es, %ds:ext_es + movw %fs, %ds:ext_fs + movw %gs, %ds:ext_fs + + /* Preserve registers */ + movw %ax, %ds:save_ax + + /* Extract near return address from stack */ + popw %ds:save_retaddr + + /* Record external %ss:esp */ + movw %ss, %ds:ext_ss + movl %esp, %ds:ext_esp + + /* Load internal segment registers and stack pointer, if available */ + movw %ds:kir_ds, %ax + testw %ax, %ax + jz 1f + movw %ax, %ss + movzwl %ds:kir_sp, %esp + movw %ax, %ds + movw %ax, %es + movw %ax, %fs + movw %ax, %gs +1: + + /* Place return address on new stack */ + pushw %cs:save_retaddr + + /* Restore registers and return */ + movw %cs:save_ax, %ax + ret + +/**************************************************************************** + * kir_to_ext (real-mode or 16:xx protected-mode near call) + * + * Switch from internal stack and segment registers to external stack + * and segment registers. %ss:%esp is restored from the saved ext_ss + * and ext_esp. Other segment registers are restored from the + * corresponding locations. All other registers are preserved. + * + * Note that it is actually %ss that is recorded as kir_ds, on the + * assumption that %ss == %ds when kir_to_ext is called. + * + * Parameters: none + **************************************************************************** + */ + + .globl kir_to_ext +kir_to_ext: + /* Record near return address */ + pushw %cs + popw %ds /* Set %ds = %cs for easier access to variables */ + popw %ds:save_retaddr + + /* Record internal segment registers and %sp */ + movw %ss, %ds:kir_ds + movw %sp, %ds:kir_sp + + /* Load external segment registers and stack pointer */ + movw %ds:ext_ss, %ss + movl %ds:ext_esp, %esp + movw %ds:ext_gs, %gs + movw %ds:ext_fs, %fs + movw %ds:ext_es, %es + movw %ds:ext_ds, %ds + + /* Return */ + pushw %cs:save_retaddr + ret + +/**************************************************************************** + * kir_call (real-mode or 16:xx protected-mode far call) + * + * Call a specific C function in the internal code. The prototype of + * the C function must be + * void function ( struct real_mode_regs *rm_regs ); + * rm_regs will point to a struct containing the real-mode registers + * at entry to kir_call. + * + * All registers will be preserved across kir_call(), unless the C + * function explicitly overwrites values in rm_regs. Interrupt status + * will also be preserved. + * + * Parameters: + * function : (16-bit) virtual address of protected-mode function to call + * + * Example usage: + * pushw $pxe_api_call + * lcall $UNDI_CS, $kir_call + * addw $2, %sp + * to call in to the C function + * void pxe_api_call ( struct real_mode_regs *rm_regs ); + **************************************************************************** + */ + + .globl kir_call +kir_call: + + /* Preserve flags. Must do this before any operation that may + * affect flags. + */ + pushfl + popl %cs:save_flags + + /* Disable interrupts. We do funny things with the stack, and + * we're not re-entrant. + */ + cli + + /* Extract address of internal routine from stack. We must do + * this without using (%bp), because we may be called with + * either a 16-bit or a 32-bit stack segment. + */ + popl %cs:save_retaddr /* Scratch location */ + popw %cs:save_function + subl $6, %esp /* Restore %esp */ + + /* Switch to internal stack. Note that the external stack is + * inaccessible once we're running internally (since we have + * no concept of 48-bit far pointers) + */ + call ext_to_kir + + /* Store external registers on internal stack */ + pushl %cs:save_flags + pushal + pushl %cs:ext_fs_and_gs + pushl %cs:ext_ds_and_es + pushl %cs:ext_cs_and_ss + + /* Push &rm_regs on stack and call function */ + pushl %esp + data32 call *%cs:save_function + popl %eax /* discard */ + + /* Restore external registers from internal stack */ + popl %cs:ext_cs_and_ss + popl %cs:ext_ds_and_es + popl %cs:ext_fs_and_gs + popal + popl %cs:save_flags + + /* Switch to external stack */ + call kir_to_ext + + /* Restore flags */ + pushl %cs:save_flags + popfl + + /* Return */ + lret + +/**************************************************************************** + * Stored internal and external stack and segment registers + **************************************************************************** + */ + +ext_cs_and_ss: +ext_cs: .word 0 +ext_ss: .word 0 +ext_ds_and_es: +ext_ds: .word 0 +ext_es: .word 0 +ext_fs_and_gs: +ext_fs: .word 0 +ext_gs: .word 0 +ext_esp: .long 0 + + .globl kir_ds +kir_ds: .word 0 + .globl kir_sp +kir_sp: .word 0 + +/**************************************************************************** + * Temporary variables + **************************************************************************** + */ +save_ax: .word 0 +save_retaddr: .word 0 +save_flags: .long 0 +save_function: .long 0 diff --git a/src/arch/i386/transitions/libpm.S b/src/arch/i386/transitions/libpm.S new file mode 100644 index 00000000..e69de29b diff --git a/src/arch/i386/transitions/librm.S b/src/arch/i386/transitions/librm.S new file mode 100644 index 00000000..6dc6b4fd --- /dev/null +++ b/src/arch/i386/transitions/librm.S @@ -0,0 +1,691 @@ +/* + * librm: a library for interfacing to real-mode code + * + * Michael Brown + * + */ + +/* Drag in local definitions */ +#include "librm.h" + +/**************************************************************************** + * This file defines librm: a block of code that is designed to reside + * permanently in base memory and provide the interface between + * real-mode code running in base memory and protected-mode code + * running in high memory. It provides the following functions: + * + * real_to_prot & switch between real and protected mode + * prot_to_real while running in base memory, preserving + * all non-segment registers + * + * real_call issue a call to a real-mode routine from + * protected-mode code running in high memory + * + * prot_call issue a call to a protected-mode routine from + * real-mode code running in base memory + * + * librm requires the following functions to be present in the + * protected-mode code: + * + * _phys_to_virt Switch from physical to virtual addressing. This + * routine must be position-independent and must + * *not* assume that it is genuinely running with + * flat physical addresses + * + * _virt_to_phys Switch from virtual to physical addresses. + * + * gateA20_set Enable the A20 line to permit access to the odd + * megabytes of RAM. (This function will be called + * with virtual addresses set up). + * + * librm needs to be linked against the protected-mode binary so that + * it can import the symbols for these functions. + * + * librm requires that the protected-mode code set up the following + * segments: + * + * PHYSICAL_CS 32-bit pmode code and data segments with flat + * PHYSICAL_DS physical addresses. + * + * VIRTUAL_CS 32-bit pmode code segment with virtual + * addressing, such that a protected-mode routine + * can always be found at $VIRTUAL_CS:routine. + * + * These segments must be set as #define constants when compiling + * librm. Edit librm.h to change the values. + * + * librm does not know the location of the code executing in high + * memory. It relies on the code running in high memory setting up a + * GDT such that the high-memory code is accessible at virtual + * addresses fixed at compile-time. + * + * librm symbols are exported as absolute values and represent offsets + * into librm. This is the most useful form of the symbols, since + * librm is basically a binary blob that you place somewhere in base + * memory. + * + * librm.h provides convenient ways to use these symbols: you simply + * set the pointer ( char * ) installed_librm to point to wherever + * librm is installed, and can then use e.g. inst_rm_stack just like + * any other variable and have it automatically refer to the value of + * rm_stack in the installed librm. Macro trickery makes this + * completely transparent, and the resulting assembler code is + * amazingly efficient. + * + * Note that librm must be called in genuine real mode, not 16:16 or + * 16:32 protected mode. It makes the assumption that + * physical_address = 16*segment+offset, and also that it can use + * OFFSET(%bp) to access stack variables. The former assumption will + * break in either protected mode, the latter may break in 16:32 + * protected mode. + **************************************************************************** + */ + +/* + * Default values for pmode segments if not defined + */ +#ifndef PHYSICAL_CS +#warning "Assuming PHYSICAL_CS = 0x08" +#define PHYSICAL_CS 0x08 +#endif +#ifndef PHYSICAL_DS +#warning "Assuming PHYSICAL_DS = 0x10" +#define PHYSICAL_DS 0x10 +#endif +#ifndef VIRTUAL_CS +#warning "Assuming VIRTUAL_CS = 0x18" +#define VIRTUAL_CS 0x18 +#endif + +/* For switches to/from protected mode */ +#define CR0_PE 1 + +/* Size of various C data structures */ +#define SIZEOF_I386_SEG_REGS 12 +#define SIZEOF_I386_REGS 32 +#define SIZEOF_I386_ALL_REGS ( SIZEOF_I386_SEG_REGS + SIZEOF_I386_REGS ) +#define SIZEOF_I386_FLAGS 4 +#define SIZEOF_REAL_MODE_REGS ( SIZEOF_I386_ALL_REGS + SIZEOF_I386_FLAGS ) +#define SIZEOF_SEGOFF_T 4 +#define SIZEOF_REAL_CALL_PARAMS ( SIZEOF_I386_ALL_REGS + 2 * SIZEOF_SEGOFF_T ) + + .text + .arch i386 + .section ".librm", "awx", @progbits + .align 16 + + .globl librm +librm: + +_librm_start: + +#undef OFFSET +#define OFFSET(sym) ( sym - _librm_start ) + +#undef EXPORT +#define EXPORT(sym) \ + .globl sym ; \ + .globl _ ## sym ; \ + .equ _ ## sym, OFFSET(sym) ; \ + sym + +/**************************************************************************** + * GDT for initial transition to protected mode + * + * PHYSICAL_CS and PHYSICAL_DS are defined in an external header file. + * We use only those selectors, and construct our GDT to match the + * selector values we're asked to use. Use PHYSICAL_CS=0x08 and + * PHYSICAL_DS=0x10 to minimise the space occupied by this GDT. + * + * Note: pm_gdt is also used to store the location of the + * protected-mode GDT as recorded on entry to prot_to_real. + **************************************************************************** + */ + .align 16 +pm_gdt: +pm_gdt_limit: .word pm_gdt_length - 1 +pm_gdt_addr: .long 0 + .word 0 /* padding */ + + .org pm_gdt + PHYSICAL_CS +pm_gdt_pm_cs: + /* 32 bit protected mode code segment, physical addresses */ + .word 0xffff, 0 + .byte 0, 0x9f, 0xcf, 0 + + .org pm_gdt + PHYSICAL_DS +pm_gdt_pm_ds: + /* 32 bit protected mode data segment, physical addresses */ + .word 0xffff,0 + .byte 0,0x93,0xcf,0 + +pm_gdt_end: + .equ pm_gdt_length, pm_gdt_end - pm_gdt + +/**************************************************************************** + * GDT for transition to real mode + * + * This is used primarily to set 64kB segment limits. Define + * FLATTEN_REAL_MODE if you want to use so-called "flat real mode" + * with 4GB limits instead. The base address of each of the segments + * will be adjusted at run-time. + * + * NOTE: This must be located before prot_to_real, otherwise gas + * throws a "can't handle non absolute segment in `ljmp'" error due to + * not knowing the value of RM_CS when the ljmp is encountered. + * + * Note also that putting ".word rm_gdt_end - rm_gdt - 1" directly + * into rm_gdt_limit, rather than going via rm_gdt_length, will also + * produce the "non absolute segment" error. This is most probably a + * bug in gas. + **************************************************************************** + */ + +#ifdef FLATTEN_REAL_MODE +#define RM_LIMIT_16_19__AVL__SIZE__GRANULARITY 0x8f +#else +#define RM_LIMIT_16_19__AVL__SIZE__GRANULARITY 0x00 +#endif + .align 16 +rm_gdt: +rm_gdt_limit: .word rm_gdt_length - 1 +rm_gdt_base: .long 0 + .word 0 /* padding */ + +rm_gdt_rm_cs: /* 16 bit real mode code segment */ + .equ RM_CS, rm_gdt_rm_cs - rm_gdt + .word 0xffff,(0&0xffff) + .byte (0>>16),0x9b,RM_LIMIT_16_19__AVL__SIZE__GRANULARITY,(0>>24) + +rm_gdt_rm_ds: /* 16 bit real mode data segment */ + .equ RM_DS, rm_gdt_rm_ds - rm_gdt + .word 0xffff,(0&0xffff) + .byte (0>>16),0x93,RM_LIMIT_16_19__AVL__SIZE__GRANULARITY,(0>>24) + +rm_gdt_end: + .equ rm_gdt_length, rm_gdt_end - rm_gdt + +/**************************************************************************** + * real_to_prot (real-mode far call) + * + * Switch from 16-bit real-mode to 32-bit protected mode with flat + * physical addresses. %esp is restored from the saved pm_esp. All + * segment registers are set to flat physical-mode values. All other + * registers are preserved. Interrupts are disabled. + * + * Note that this routine can be called *without* having first set up + * a stored pm_esp or stored GDT. If you do this, real_to_prot will + * return with a temporary stack that is only *FOUR BYTES* in size. + * This is just enough to enable you to do a "call 1f; popl %ebp" + * sequence in order to find out your physical address and then load a + * proper 32-bit protected-mode stack pointer. Do *NOT* use more than + * four bytes since this will overwrite code in librm! + * + * Parameters: none + **************************************************************************** + */ + + .code16 +EXPORT(real_to_prot): + /* Disable interrupts */ + cli + + /* Set %ds = %cs, for easier access to variables */ + pushw %cs + popw %ds + + /* Preserve registers */ + movl %eax, %ds:OFFSET(save_eax) + movl %ebx, %ds:OFFSET(save_ebx) + + /* Extract real-mode far return address from stack */ + popl %ds:OFFSET(save_retaddr) + + /* Record real-mode stack pointer */ + movw %sp, %ds:OFFSET(rm_sp) + pushw %ss + popw %ds:OFFSET(rm_ss) + + /* Physical base address of librm to %ebx */ + xorl %ebx, %ebx + movw %cs, %bx + shll $4, %ebx + + /* Check base address of stored protected-mode GDT. If it's + * zero, set it up to use our internal GDT (with physical + * segments only). + */ + movl %ds:OFFSET(pm_gdt_addr), %eax + testl %eax, %eax + jnz 1f + /* Use internal GDT */ + movl %ebx, %eax + addl $OFFSET(pm_gdt), %eax + movl %eax, %ds:OFFSET(pm_gdt_addr) +1: + + /* Set up protected-mode continuation address on real-mode stack */ + pushl $PHYSICAL_CS + movl %ebx, %eax + addl $OFFSET(1f), %eax + pushl %eax + + /* Restore protected-mode GDT */ + lgdt %ds:OFFSET(pm_gdt) + + /* Switch to protected mode */ + movl %cr0, %eax + orb $CR0_PE, %al + movl %eax, %cr0 + + /* Flush prefetch queue and reload %cs:eip */ + data32 lret +1: .code32 + + /* Set up protected-mode stack and data segments */ + movw $PHYSICAL_DS, %ax + movw %ax, %ds + movw %ax, %es + movw %ax, %fs + movw %ax, %gs + movw %ax, %ss + + /* Switch to saved protected-mode stack. Note that there may + * not actually *be* a saved protected-mode stack. + */ + movl OFFSET(pm_esp)(%ebx), %esp + testl %esp, %esp + jnz 1f + /* No stack - use save_retaddr as a 4-byte temporary stack */ + leal OFFSET(save_retaddr+4)(%ebx), %esp +1: + + /* Convert real-mode far return address to physical address + * and place on stack + */ + pushl OFFSET(save_retaddr)(%ebx) + xorl %eax, %eax + xchgw 2(%esp), %ax + shll $4, %eax + addl %eax, 0(%esp) + + /* Restore registers and return */ + movl OFFSET(save_eax)(%ebx), %eax + movl OFFSET(save_ebx)(%ebx), %ebx + ret + +/**************************************************************************** + * prot_to_real (protected-mode near call, physical addresses) + * + * Switch from 32-bit protected mode with flat physical addresses to + * 16-bit real mode. %ss:sp is restored from the saved rm_ss and + * rm_sp. %cs is set such that %cs:0000 is the start of librm. All + * other segment registers are set to %ss. All other registers are + * preserved. Interrupts are *not* enabled, since we want to be able + * to use this routine inside an ISR. + * + * Note that since %cs:0000 points to the start of librm on exit, it + * follows that the code calling prot_to_real must be located within + * 64kB of the start of librm. + * + * Parameters: none + **************************************************************************** + */ + + .code32 +EXPORT(prot_to_real): + /* Calculate physical base address of librm in %ebx, preserve + * original %eax and %ebx in save_eax and save_ebx + */ + pushl %ebx + call 1f +1: popl %ebx + subl $OFFSET(1b), %ebx + popl OFFSET(save_ebx)(%ebx) + movl %eax, OFFSET(save_eax)(%ebx) + + /* Extract return address from the stack, convert to offset + * within librm and save in save_retaddr + */ + popl %eax + subl %ebx, %eax + movl %eax, OFFSET(save_retaddr)(%ebx) + + /* Record protected-mode stack pointer */ + movl %esp, OFFSET(pm_esp)(%ebx) + + /* Record protected-mode GDT */ + sgdt OFFSET(pm_gdt)(%ebx) + + /* Set up real-mode GDT */ + leal OFFSET(rm_gdt)(%ebx), %eax + movl %eax, OFFSET(rm_gdt_base)(%ebx) + movl %ebx, %eax + rorl $16, %eax + movw %bx, OFFSET(rm_gdt_rm_cs+2)(%ebx) + movb %al, OFFSET(rm_gdt_rm_cs+4)(%ebx) + movw %bx, OFFSET(rm_gdt_rm_ds+2)(%ebx) + movb %al, OFFSET(rm_gdt_rm_ds+4)(%ebx) + + /* Switch to real-mode GDT and reload segment registers to get + * 64kB limits. Stack is invalidated by this process. + */ + lgdt OFFSET(rm_gdt)(%ebx) + ljmp $RM_CS, $1f +1: .code16 + movw $RM_DS, %ax + movw %ax, %ds + movw %ax, %es + movw %ax, %fs + movw %ax, %gs + movw %ax, %ss + + /* Calculate real-mode code segment in %ax and store in ljmp + * instruction + */ + movl %ebx, %eax + shrl $4, %eax + movw %ax, OFFSET(p2r_ljmp) + 3 + + /* Switch to real mode */ + movl %cr0, %ebx + andb $0!CR0_PE, %bl + movl %ebx, %cr0 + + /* Intersegment jump to flush prefetch queue and reload + * %cs:eip. The segment gets filled in by the above code. We + * can't just use lret to achieve this, because we have no + * stack at the moment. + */ +p2r_ljmp: + ljmp $0, $OFFSET(1f) +1: + + /* Set %ds to point to code segment for easier data access */ + movw %ax, %ds + + /* Restore registers */ + movl OFFSET(save_eax), %eax + movl OFFSET(save_ebx), %ebx + + /* Set up real-mode data segments and stack */ + movw OFFSET(rm_ss), %ss + movw OFFSET(rm_sp), %sp + pushw %ss + pushw %ss + pushw %ss + pushw %ss + popw %ds + popw %es + popw %fs + popw %gs + + /* Set up return address on stack and return */ + pushw %cs:OFFSET(save_retaddr) + ret + +/**************************************************************************** + * prot_call (real-mode far call) + * + * Call a specific C function in the protected-mode code. The + * prototype of the C function must be + * void function ( struct real_mode_regs *rm_regs, + * void (*retaddr) (void) ); + * rm_regs will point to a struct containing the real-mode registers + * at entry to prot_call. retaddr will point to the (virtual) return + * address from "function". This return address will point into + * librm. It is included so that "function" may, if desired, relocate + * librm and return via the new copy. It must not be directly called + * as a function, i.e. you may not do "*retaddr()"; you must instead + * do something like: + * *retaddr += ( new_librm_location - old_librm_location ); + * return; + * + * All registers will be preserved across prot_call(), unless the C + * function explicitly overwrites values in rm_regs. Interrupt status + * will also be preserved. Gate A20 will be enabled. + * + * Parameters: + * function : virtual address of protected-mode function to call + * + * Example usage: + * pushl $pxe_api_call + * lcall $LIBRM_SEGMENT, $prot_call + * addw $4, %sp + * to call in to the C function + * void pxe_api_call ( struct real_mode_regs *rm_regs ); + **************************************************************************** + */ + +#define PC_OFFSET_RM_REGS ( 0 ) +#define PC_OFFSET_RETADDR ( PC_OFFSET_RM_REGS + SIZEOF_REAL_MODE_REGS ) +#define PC_OFFSET_FUNCTION ( PC_OFFSET_RETADDR + 4 ) + + .code16 +EXPORT(prot_call): + /* Preserve registers and flags on RM stack */ + pushfl + pushal + pushw %gs + pushw %fs + pushw %es + pushw %ds + pushw %ss + pushw %cs + + /* Record RM stack pointer */ + xorl %ebp, %ebp + movw %sp, %bp + + /* Physical address of RM stack pointer to %esi */ + xorl %esi, %esi + pushw %ss + popw %si + shll $4, %esi + addl %ebp, %esi + + /* Address of pmode function to %ebx */ + movl %ss:(PC_OFFSET_FUNCTION)(%bp), %ebx + + /* Switch to protected mode */ + pushw %cs + call real_to_prot + .code32 + + /* Copy rm_regs from RM stack to PM stack */ + movl $SIZEOF_REAL_MODE_REGS, %ecx + subl %ecx, %esp + movl %esp, %edi + cld + rep movsb + + /* Switch to virtual addresses. */ + call 1f + jmp 2f +1: ljmp $VIRTUAL_CS, $_phys_to_virt +2: + + /* Enable A20 line */ + pushal + lcall $VIRTUAL_CS, $gateA20_set + popl %eax /* discard */ + popal + + /* Push &rm_regs and &retaddr on the stack, and call function */ + movl %esp, %ebp + pushl %esp + subl $12, 0(%esp) + pushl %ebp + call *%ebx + popl %eax /* discard */ + popl %eax /* discard */ + + /* Switch to physical addresses, discard PM register store */ + lcall $VIRTUAL_CS, $_virt_to_phys + addl $SIZEOF_REAL_MODE_REGS+4, %esp /* also discard lcall seg */ + + /* Switch to real mode */ + call prot_to_real + .code16 + + /* Restore registers and flags, and return */ + popw %ax /* skip %cs */ + popw %ax /* skip %ss */ + popw %ds + popw %es + popw %fs + popw %gs + popal + popfl + lret + +/**************************************************************************** + * real_call (protected-mode near call, virtual addresses) + * + * Call a real-mode function from protected-mode code. + * + * The non-segment register values will be passed directly to the + * real-mode code. The segment registers will be set as per + * prot_to_real. The non-segment register values set by the real-mode + * function will be passed back to the protected-mode caller. A + * result of this is that this routine cannot be called directly from + * C code, since it clobbers registers that the C ABI expects the + * callee to preserve. Gate A20 will be re-enabled in case the + * real-mode routine disabled it. + * + * librm.h defines two convenient macros for using real_call: + * REAL_CALL and REAL_EXEC. See librm.h and realmode.h for details + * and examples. + * + * Parameters: + * far pointer to real-mode function to call + * + * Returns: none + **************************************************************************** + */ + +#define RC_OFFSET_PRESERVE_REGS ( 0 ) +#define RC_OFFSET_RETADDR ( RC_OFFSET_PRESERVE_REGS + 8 ) +#define RC_OFFSET_RM_FUNCTION ( RC_OFFSET_RETADDR + 4 ) + + .code32 +EXPORT(real_call): + /* Preserve registers */ + pushl %ebp + pushl %eax + + /* Switch to physical addresses */ + lcall $VIRTUAL_CS, $_virt_to_phys + addl $4, %esp + + /* Extract real-mode function address and store in ljmp instruction */ + call 1f +1: popl %ebp + movl RC_OFFSET_RM_FUNCTION(%esp), %eax + movl %eax, (rc_ljmp + 1 - 1b)(%ebp) + + /* Restore registers */ + popl %eax + popl %ebp + + /* Switch to real mode, preserving non-segment registers */ + call prot_to_real + .code16 + + /* Far call to real-mode routine */ + pushw %cs + call rc_ljmp + jmp 2f +rc_ljmp: + ljmp $0, $0 /* address filled in by above code */ +2: + + /* Switch to protected mode */ + pushw %cs + call real_to_prot + .code32 + + /* Switch to virtual addresses */ + call 1f + jmp 2f +1: ljmp $VIRTUAL_CS, $_phys_to_virt +2: + + /* Enable A20 line */ + pushal + lcall $VIRTUAL_CS, $gateA20_set + popl %eax /* discard */ + popal + + /* Return */ + ret + +/**************************************************************************** + * Relocation lock counter + * + * librm may be moved in base memory only when this counter is zero. + * The counter gets incremented whenever a reference to librm is + * generated (e.g. a real_call is made, resulting in a return address + * pointing to librm being placed on the stack), and decremented when + * the reference goes out of scope (e.g. the real_call returns). + **************************************************************************** + */ +EXPORT(librm_ref_count): .byte 0 + +/**************************************************************************** + * Stored real-mode and protected-mode stack pointers + * + * The real-mode stack pointer is stored here whenever real_to_prot + * is called and restored whenever prot_to_real is called. The + * converse happens for the protected-mode stack pointer. + * + * Despite initial appearances this scheme is, in fact re-entrant, + * because program flow dictates that we always return via the point + * we left by. For example: + * PXE API call entry + * 1 real => prot + * ... + * Print a text string + * ... + * 2 prot => real + * INT 10 + * 3 real => prot + * ... + * ... + * 4 prot => real + * PXE API call exit + * + * At point 1, the RM mode stack value, say RPXE, is stored in + * rm_ss,sp. We want this value to still be present in rm_ss,sp when + * we reach point 4. + * + * At point 2, the RM stack value is restored from RPXE. At point 3, + * the RM stack value is again stored in rm_ss,sp. This *does* + * overwrite the RPXE that we have stored there, but it's the same + * value, since the code between points 2 and 3 has managed to return + * to us. + **************************************************************************** + */ + +EXPORT(rm_stack): /* comprises rm_ss and rm_sp */ +rm_sp: .word 0 +rm_ss: .word 0 + +EXPORT(pm_stack): +pm_esp: .long 0 + +/**************************************************************************** + * Temporary variables + **************************************************************************** + */ +save_eax: .long 0 +save_ebx: .long 0 +save_retaddr: .long 0 + +/**************************************************************************** + * End of librm + **************************************************************************** + */ +_librm_end: + .globl _librm_size + .equ _librm_size, _librm_end - _librm_start diff --git a/src/arch/i386/transitions/librm_mgmt.c b/src/arch/i386/transitions/librm_mgmt.c new file mode 100644 index 00000000..bfe963d4 --- /dev/null +++ b/src/arch/i386/transitions/librm_mgmt.c @@ -0,0 +1,87 @@ +/* + * librm: a library for interfacing to real-mode code + * + * Michael Brown + * + */ + +#ifdef KEEP_IT_REAL +/* Build a null object under -DKEEP_IT_REAL */ +#else + +#include "stdint.h" +#include "stddef.h" +#include "string.h" +#include "librm.h" + +/* + * This file provides functions for managing librm. + * + */ + +/* Current location of librm in base memory */ +char *installed_librm = librm; + +/* + * Install librm to base memory + * + */ +void install_librm ( void *addr ) { + memcpy ( addr, librm, librm_size ); + installed_librm = addr; +} + +/* + * Increment lock count of librm + * + */ +void lock_librm ( void ) { + inst_librm_ref_count++; +} + +/* + * Decrement lock count of librm + * + */ +void unlock_librm ( void ) { +#ifdef DEBUG_LIBRM + if ( inst_librm_ref_count == 0 ) { + printf ( "librm: ref count gone negative\n" ); + lockup(); + } +#endif + inst_librm_ref_count--; +} + +/* + * Allocate space on the real-mode stack and copy data there. + * + */ +uint16_t copy_to_rm_stack ( void *data, size_t size ) { +#ifdef DEBUG_LIBRM + if ( inst_rm_stack.offset <= size ) { + printf ( "librm: out of space in RM stack\n" ); + lockup(); + } +#endif + inst_rm_stack.offset -= size; + copy_to_real ( inst_rm_stack.segment, inst_rm_stack.offset, + data, size ); + return inst_rm_stack.offset; +}; + +/* + * Deallocate space on the real-mode stack, optionally copying back + * data. + * + */ +void remove_from_rm_stack ( void *data, size_t size ) { + if ( data ) { + copy_from_real ( data, + inst_rm_stack.segment, inst_rm_stack.offset, + size ); + } + inst_rm_stack.offset += size; +}; + +#endif /* KEEP_IT_REAL */ diff --git a/src/arch/ia64/core/ia64_timer.c b/src/arch/ia64/core/ia64_timer.c index 3115714a..b7f54739 100644 --- a/src/arch/ia64/core/ia64_timer.c +++ b/src/arch/ia64/core/ia64_timer.c @@ -2,6 +2,7 @@ #include "timer.h" #include "sal.h" #include "pal.h" +#include "init.h" static inline unsigned long get_cycles(void) { @@ -39,7 +40,7 @@ static unsigned long calibrate_cycles(void) } static unsigned long clocks_per_tick; -void setup_timers(void) +static void setup_timers(void) { if (!clocks_per_tick) { clocks_per_tick = calibrate_cycles(); @@ -87,3 +88,5 @@ int timer2_running(void) { return __timer_running(); } + +INIT_FN ( INIT_TIMERS, setup_timers, NULL, NULL ); diff --git a/src/bin/.cvsignore b/src/bin/.cvsignore new file mode 100644 index 00000000..72e8ffc0 --- /dev/null +++ b/src/bin/.cvsignore @@ -0,0 +1 @@ +* diff --git a/src/core/btext.c b/src/core/btext.c index 12afb8d5..546b7be3 100644 --- a/src/core/btext.c +++ b/src/core/btext.c @@ -1,5 +1,3 @@ -#ifdef CONSOLE_BTEXT -#ifdef CONFIG_PCI /* * Procedures for drawing on the screen early on in the boot process. * @@ -10,6 +8,8 @@ */ #include "etherboot.h" +#include "console.h" +#include "init.h" #include "pci.h" #ifdef CONFIG_FILO @@ -36,6 +36,8 @@ static void draw_byte_16(unsigned char *bits, u32 *base, u32 rb); #endif static void draw_byte_8(unsigned char *bits, u32 *base, u32 rb); +static int pci_find_device_x(int vendorx, int devicex, int index, struct pci_device *dev); + static u32 g_loc_X; static u32 g_loc_Y; static u32 g_max_loc_X; @@ -62,7 +64,7 @@ boot_infos_t disp_bi; /* This function will enable the early boot text when doing OF booting. This * way, xmon output should work too */ -void +static void btext_setup_display(u32 width, u32 height, u32 depth, u32 pitch, unsigned long address) { @@ -73,7 +75,7 @@ btext_setup_display(u32 width, u32 height, u32 depth, u32 pitch, g_max_loc_X = width / 8; g_max_loc_Y = height / 16; // bi->logicalDisplayBase = (unsigned char *)address; - bi->dispDeviceBase = (unsigned char *)address; + bi->dispDeviceBase = address; bi->dispDeviceRowBytes = pitch; bi->dispDeviceDepth = depth; bi->dispDeviceRect[0] = bi->dispDeviceRect[1] = 0; @@ -93,7 +95,7 @@ btext_setup_display(u32 width, u32 height, u32 depth, u32 pitch, * changes. */ -void +static void map_boot_text(void) { boot_infos_t *bi = &disp_bi; @@ -113,18 +115,19 @@ static unsigned char * BTEXT calc_base(boot_infos_t *bi, u32 x, u32 y) { unsigned char *base; -#if 1 base = bi->logicalDisplayBase; +#if 0 + /* Ummm... which moron wrote this? */ if (base == 0) -#endif base = bi->dispDeviceBase; +#endif base += (x + bi->dispDeviceRect[0]) * (bi->dispDeviceDepth >> 3); base += (y + bi->dispDeviceRect[1]) * bi->dispDeviceRowBytes; return base; } -void BTEXT btext_clearscreen(void) +static void BTEXT btext_clearscreen(void) { boot_infos_t* bi = &disp_bi; u32 *base = (u32 *)calc_base(bi, 0, 0); @@ -147,7 +150,7 @@ __inline__ void dcbst(const void* addr) __asm__ __volatile__ ("dcbst 0,%0" :: "r" (addr)); } -void BTEXT btext_flushscreen(void) +static void BTEXT btext_flushscreen(void) { boot_infos_t* bi = &disp_bi; u32 *base = (unsigned long *)calc_base(bi, 0, 0); @@ -198,7 +201,7 @@ scrollscreen(void) } #endif /* ndef NO_SCROLL */ -void BTEXT btext_drawchar(char c) +static void BTEXT btext_drawchar(char c) { u32 cline = 0; @@ -246,7 +249,7 @@ void BTEXT btext_drawchar(char c) #endif } #if 0 -void BTEXT +static void BTEXT btext_drawstring(const char *c) { if (!boot_text_mapped) @@ -254,7 +257,7 @@ btext_drawstring(const char *c) while (*c) btext_drawchar(*c++); } -void BTEXT +static void BTEXT btext_drawhex(u32 v) { static char hex_table[] = "0123456789abcdef"; @@ -394,7 +397,7 @@ draw_byte_8(unsigned char *font, u32 *base, u32 rb) #endif -void btext_init(void) +static void btext_init(void) { #if 0 // for debug @@ -402,14 +405,16 @@ void btext_init(void) #else uint32_t frame_buffer;// 0xfc000000 - struct pci_device *dev = 0; - #if USE_FILO_PCI_FIND==0 + struct pci_device dev; + pci_find_device_x(0x1002, 0x4752, 0, &dev); if(dev.vendor==0) return; // no fb frame_buffer = (uint32_t)dev.membase; #else + struct pci_device *dev = 0; + pci_init(); dev = pci_find_device(0x1002, 0x4752, -1, -1, 0); if(!dev) { @@ -422,21 +427,21 @@ void btext_init(void) #endif btext_setup_display(640, 480, 8, 640,frame_buffer); -// btext_clearscreen(); //move to main -// map_boot_text(); //move console_init + btext_clearscreen(); + map_boot_text(); } -void btext_putc(int c) +static void btext_putc(int c) { btext_drawchar((unsigned char)c); } -#if 0 -static struct console_driver btext_console __console = { - .init = btext_init, - .tx_byte = btext_tx_byte, - .rx_byte = 0, - .tst_byte = 0, + +static struct console_driver btext_console __console_driver = { + .putchar = btext_putc, + .disabled = 1, }; -#endif + +INIT_FN ( INIT_CONSOLE, btext_init, NULL, NULL ); + #if USE_FILO_PCI_FIND==0 int pci_find_device_x(int vendorx, int devicex, int index, struct pci_device *dev) { @@ -445,7 +450,6 @@ int pci_find_device_x(int vendorx, int devicex, int index, struct pci_device *de #if 1 unsigned char hdr_type = 0; #endif - uint32_t class; uint16_t vendor, device; uint32_t l, membase; #if 0 @@ -5192,5 +5196,3 @@ static unsigned char vga_font[cmapsz] BTDATA = { 0x00, /* 00000000 */ #endif }; -#endif -#endif diff --git a/src/core/config.c b/src/core/config.c index 180b0669..d85ca242 100644 --- a/src/core/config.c +++ b/src/core/config.c @@ -7,6 +7,7 @@ #include "etherboot.h" #include "nic.h" +#include "console.h" #ifdef BUILD_SERIAL #include ".buildserial.h" #define xstr(s) str(s) @@ -104,6 +105,9 @@ void print_config(void) "DNS " #endif "\n"); +#ifdef KEEP_IT_REAL + printf( "Keeping It Real [EXPERIMENTAL]\n" ); +#endif } static const char *driver_name[] = { @@ -159,3 +163,48 @@ void disable(struct dev *dev) dev->disable = 0; } } + + +/* + * Drag in all requested console types + * + * At least one of the CONSOLE_xxx has to be set. CONSOLE_DUAL sets + * both CONSOLE_FIRMWARE and CONSOLE_SERIAL for legacy compatibility. + * If no CONSOLE_xxx is set, CONSOLE_FIRMWARE is assumed. + */ + +#ifdef CONSOLE_CRT +#define CONSOLE_FIRMWARE +#endif + +#ifdef CONSOLE_DUAL +#undef CONSOLE_FIRMWARE +#define CONSOLE_FIRMWARE +#undef CONSOLE_SERIAL +#define CONSOLE_SERIAL +#endif + +#if !defined(CONSOLE_FIRMWARE) && !defined(CONSOLE_SERIAL) +#define CONSOLE_FIRMWARE +#endif + +#ifdef CONSOLE_FIRMWARE +REQUIRE_OBJECT ( bios_console ); +#endif + +#ifdef CONSOLE_SERIAL +REQUIRE_OBJECT ( serial ); +#endif + +#ifdef CONSOLE_DIRECT_VGA +REQUIRE_OBJECT ( video_subr ); +#endif + +#ifdef CONSOLE_BTEXT +REQUIRE_OBJECT ( btext ); +#endif + +#ifdef CONSOLE_PC_KBD +REQUIRE_OBJECT ( pc_kbd ); +#endif + diff --git a/src/core/console.c b/src/core/console.c new file mode 100644 index 00000000..6e92cb54 --- /dev/null +++ b/src/core/console.c @@ -0,0 +1,102 @@ +/* + * Central console switch. Various console devices can be selected + * via the build options CONSOLE_FIRMWARE, CONSOLE_SERIAL etc. + * config.c picks up on these definitions and drags in the relevant + * objects. The linker compiles the console_drivers table for us; we + * simply delegate to each console_driver that we find in the table. + * + * Doing it this way allows for changing CONSOLE_XXX without + * rebuilding anything other than config.o. This is extremely useful + * for rom-o-matic. + */ + +#include "stddef.h" +#include "console.h" + +/* FIXME: 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. + */ +#include "bios.h" + +extern struct console_driver console_drivers[]; +extern struct console_driver console_drivers_end[]; + +/***************************************************************************** + * putchar : write a single character to each console + ***************************************************************************** + */ + +void putchar ( int character ) { + struct console_driver *console; + + /* Automatic LF -> CR,LF translation */ + if ( character == '\n' ) + putchar ( '\r' ); + + for ( console = console_drivers; console < console_drivers_end ; + console++ ) { + if ( ( ! console->disabled ) && console->putchar ) + console->putchar ( character ); + } +} + +/***************************************************************************** + * has_input : check to see if any input is available on any console, + * and return a pointer to the console device if so + ***************************************************************************** + */ +static struct console_driver * has_input ( void ) { + struct console_driver *console; + + for ( console = console_drivers; console < console_drivers_end ; + console++ ) { + if ( ( ! console->disabled ) && console->iskey ) { + if ( console->iskey () ) + return console; + } + } + return NULL; +} + +/***************************************************************************** + * getchar : read a single character from any console + * + * NOTE : this function does not echo the character, and it does block + ***************************************************************************** + */ + +int getchar ( void ) { + struct console_driver *console; + int character = 256; + + while ( character == 256 ) { + /* Doze for a while (until the next interrupt). This works + * fine, because the keyboard is interrupt-driven, and the + * timer interrupt (approx. every 50msec) takes care of the + * serial port, which is read by polling. This reduces the + * power dissipation of a modern CPU considerably, and also + * makes Etherboot waiting for user interaction waste a lot + * less CPU time in a VMware session. + */ + cpu_nap(); + + console = has_input(); + if ( console && console->getchar ) + character = console->getchar (); + } + + /* CR -> LF translation */ + if ( character == '\r' ) + character = '\n'; + + return character; +} + +/***************************************************************************** + * iskey : check to see if any input is available on any console + ***************************************************************************** + */ + +int iskey ( void ) { + return has_input() ? 1 : 0; +} diff --git a/src/core/heap.c b/src/core/heap.c index 51ce47d7..7f69829d 100644 --- a/src/core/heap.c +++ b/src/core/heap.c @@ -1,8 +1,12 @@ #include "etherboot.h" +#include "init.h" +#include "memsizes.h" size_t heap_ptr, heap_top, heap_bot; -void init_heap(void) +#define _virt_start 0 + +static void init_heap(void) { size_t size; size_t start, end; @@ -82,6 +86,11 @@ void init_heap(void) heap_ptr = heap_bot; } +static void reset_heap(void) +{ + heap_ptr = heap_bot; +} + void *allot(size_t size) { void *ptr; @@ -166,3 +175,5 @@ void forget2(void *ptr) } heap_ptr = addr; } + +INIT_FN ( INIT_HEAP, init_heap, reset_heap, NULL ); diff --git a/src/core/init.c b/src/core/init.c new file mode 100644 index 00000000..3dc87691 --- /dev/null +++ b/src/core/init.c @@ -0,0 +1,44 @@ +/************************************************************************** + * call_{init,reset,exit}_fns () + * + * Call the various initialisation and exit functions. We use a + * function table so that we don't end up dragging in an object just + * because we call its initialisation function. + ************************************************************************** + */ + +#include "init.h" + +extern struct init_fn init_fns[]; +extern struct init_fn init_fns_end[]; + +void call_init_fns ( void ) { + struct init_fn *init_fn; + + for ( init_fn = init_fns; init_fn < init_fns_end ; init_fn++ ) { + if ( init_fn->init ) + init_fn->init (); + } +} + +void call_reset_fns ( void ) { + struct init_fn *init_fn; + + for ( init_fn = init_fns; init_fn < init_fns_end ; init_fn++ ) { + if ( init_fn->reset ) + init_fn->reset (); + } +} + +void call_exit_fns ( void ) { + struct init_fn *init_fn; + + /* + * Exit functions are called in reverse order to + * initialisation functions. + */ + for ( init_fn = init_fns_end - 1; init_fn >= init_fns ; init_fn-- ) { + if ( init_fn->exit ) + init_fn->exit (); + } +} diff --git a/src/core/main.c b/src/core/main.c index e92d2929..9cd89c22 100644 --- a/src/core/main.c +++ b/src/core/main.c @@ -23,12 +23,10 @@ Literature dealing with the network protocols: #include "http.h" #include "timer.h" #include "cpu.h" +#include "console.h" +#include "init.h" #include -#ifdef CONSOLE_BTEXT -#include "btext.h" -#endif - #ifdef CONFIG_FILO #include #endif @@ -43,51 +41,6 @@ int freebsd_howto = 0; char freebsd_kernel_env[FREEBSD_KERNEL_ENV_SIZE]; #endif -/* in_call(): the entry point to Etherboot. Generally called from - * arch_in_call(), which in turn will have been invoked from - * platform-specific assembly code. - */ -int in_call ( in_call_data_t *data, uint32_t opcode, va_list params ) { - int old_as_main_program = as_main_program; - int ret = 0; - - /* Set flat to indicate that we are not running as the main - * program (i.e. we are something like a PXE stack). - */ - as_main_program = 0; - - /* NOTE: params will cease to be valid if we relocate, since - * it represents a virtual address - */ - switch ( EB_OPCODE(opcode) ) { - - case EB_OPCODE_CHECK: - /* Installation check - */ - ret = EB_CHECK_RESULT; - break; - case EB_OPCODE_MAIN: - /* Start up Etherboot as a standalone program. */ - as_main_program = 1; - ret = main ( data, params ); - break; -#ifdef PXE_EXPORT - case EB_OPCODE_PXE: - /* !PXE API call */ - ret = pxe_in_call ( data, params ); - break; -#endif - default: - printf ( "Unsupported API \"%c%c\"\n", - EB_OPCODE(opcode) >> 8, EB_OPCODE(opcode) & 0xff ); - ret = -1; - break; - } - - as_main_program = old_as_main_program; - return ret; -} - static inline unsigned long ask_boot(unsigned *index) { unsigned long order = DEFAULT_BOOT_ORDER; @@ -166,26 +119,6 @@ static inline void try_floppy_first(void) #endif /* TRY_FLOPPY_FIRST */ } -void console_init(void) -{ -#ifdef CONSOLE_SERIAL - (void)serial_init(); -#endif -#ifdef CONSOLE_DIRECT_VGA - video_init(); -#endif -#ifdef CONSOLE_BTEXT - map_boot_text(); -#endif -} - -static void console_fini(void) -{ -#ifdef CONSOLE_SERIAL - (void)serial_fini(); -#endif -} - static struct class_operations { struct dev *dev; int (*probe)(struct dev *dev); @@ -204,44 +137,16 @@ static int exit_ok; static int exit_status; static int initialized; + /************************************************************************** MAIN - Kick off routine **************************************************************************/ -int main(in_call_data_t *data, va_list params) -{ - char *p; +int main ( void ) { int state; - for (p = _bss; p < _ebss; p++) - *p = 0; /* Zero BSS */ - - console_init(); - arch_main(data,params); - -#if 0 -#ifdef CONSOLE_BTEXT - btext_init(); - map_boot_text(); - btext_clearscreen(); -#endif -#endif - - if ( rom.rom_segment ) { - printf ( "ROM segment %#hx length %#hx reloc %#x\n", - rom.rom_segment, rom.rom_length, _text ); - } - - cpu_setup(); - setup_timers(); - gateA20_set(); print_config(); - get_memsizes(); cleanup(); -#ifdef CONFIG_PCMCIA - pcmcia_init_all(); -#endif - /* -1: timeout or ESC -2: error return from loader -3: finish the current run. @@ -258,10 +163,7 @@ int main(in_call_data_t *data, va_list params) for(;state != 255;) { state = main_loop(state); } - arch_on_exit(exit_status); -#ifdef CONFIG_PCMCIA - pcmcia_shutdown_all(); -#endif + /* arch_on_exit(exit_status) */ return exit_status; } @@ -283,13 +185,11 @@ static int main_loop(int state) static unsigned boot_index; static struct dev * dev = 0; static struct class_operations *ops; - static void *heap_base; static int type; static int i; if (!initialized) { initialized = 1; - console_init(); if (dev && (state >= 1) && (state <= 2)) { dev->how_probe = PROBE_AWAKE; dev->how_probe = ops->probe(dev); @@ -304,21 +204,8 @@ static int main_loop(int state) static int firsttime = 1; /* First time through */ if (firsttime) { - relocate(); + /* relocate(); */ cleanup(); - console_init(); - init_heap(); -#ifdef CONSOLE_BTEXT - //I need to all allot - btext_init(); - map_boot_text(); - btext_clearscreen(); -#else - #ifdef CONFIG_FILO - pci_init(); - #endif -#endif - firsttime = 0; } #ifdef EXIT_IF_NO_OFFER @@ -327,7 +214,6 @@ static int main_loop(int state) exit(0); } #endif - heap_base = allot(0); i = -1; state = 4; dev = 0; @@ -339,8 +225,7 @@ static int main_loop(int state) } case 4: cleanup(); - console_init(); - forget(heap_base); + call_reset_fns(); /* Find a dev entry to probe with */ if (!dev) { int boot; @@ -377,7 +262,12 @@ static int main_loop(int state) break; case 3: state = -1; - heap_base = allot(0); + /* Removed the following line because it was causing + * heap.o to be dragged in unnecessarily. It's also + * slightly puzzling: by resetting heap_base, doesn't + * this mean that we permanently leak memory? + */ + /* heap_base = allot(0); */ dev->how_probe = ops->probe(dev); if (dev->how_probe == PROBE_FAILED) { dev = 0; @@ -518,7 +408,6 @@ void cleanup(void) /* Stop receiving packets */ eth_disable(); disk_disable(); - console_fini(); initialized = 0; } diff --git a/src/core/misc.c b/src/core/misc.c index f5ce9d8f..0fe6cb47 100644 --- a/src/core/misc.c +++ b/src/core/misc.c @@ -3,13 +3,7 @@ MISC Support Routines **************************************************************************/ #include "etherboot.h" -#ifdef CONSOLE_BTEXT -#include -#endif -#ifdef CONSOLE_PC_KBD -#include -#endif - +#include "console.h" /************************************************************************** IPCHKSUM - Checksum IP Header @@ -170,7 +164,6 @@ int inet_aton(const char *start, in_addr *i) return p - start; } - unsigned long strtoul(const char *p, const char **endp, int base) { unsigned long ret = 0; @@ -185,140 +178,6 @@ unsigned long strtoul(const char *p, const char **endp, int base) } -#define K_RDWR 0x60 /* keyboard data & cmds (read/write) */ -#define K_STATUS 0x64 /* keyboard status */ -#define K_CMD 0x64 /* keybd ctlr command (write-only) */ - -#define K_OBUF_FUL 0x01 /* output buffer full */ -#define K_IBUF_FUL 0x02 /* input buffer full */ - -#define KC_CMD_WIN 0xd0 /* read output port */ -#define KC_CMD_WOUT 0xd1 /* write output port */ -#define KB_SET_A20 0xdf /* enable A20, - enable output buffer full interrupt - enable data line - disable clock line */ -#define KB_UNSET_A20 0xdd /* enable A20, - enable output buffer full interrupt - enable data line - disable clock line */ - -enum { Disable_A20 = 0x2400, Enable_A20 = 0x2401, Query_A20_Status = 0x2402, - Query_A20_Support = 0x2403 }; - -#if defined(PCBIOS) && !defined(IBM_L40) -static void empty_8042(void) -{ - unsigned long time; - char st; - - time = currticks() + TICKS_PER_SEC; /* max wait of 1 second */ - while ((((st = inb(K_CMD)) & K_OBUF_FUL) || - (st & K_IBUF_FUL)) && - currticks() < time) - inb(K_RDWR); -} -#endif /* IBM_L40 */ - -#if defined(PCBIOS) -/* - * Gate A20 for high memory - */ -void gateA20_set(void) -{ -#warning "gateA20_set should test to see if it is already set" - if (int15(Enable_A20) == 0) { - return; - } -#ifdef IBM_L40 - outb(0x2, 0x92); -#else /* IBM_L40 */ - empty_8042(); - outb(KC_CMD_WOUT, K_CMD); - empty_8042(); - outb(KB_SET_A20, K_RDWR); - empty_8042(); -#endif /* IBM_L40 */ -} -#endif - - -int last_putchar; // From filo - -void -putchar(int c) -{ - c &= 0xff; - last_putchar = c; - - if (c == '\n') - putchar('\r'); -#ifdef CONSOLE_FIRMWARE - console_putc(c); -#endif -#ifdef CONSOLE_DIRECT_VGA - vga_putc(c); -#endif -#ifdef CONSOLE_BTEXT - btext_putc(c); -#endif -#ifdef CONSOLE_SERIAL - serial_putc(c); -#endif -} - -/************************************************************************** -GETCHAR - Read the next character from input device WITHOUT ECHO -**************************************************************************/ -int getchar(void) -{ - int c = 256; - - do { -#if defined(PCBIOS) && defined(POWERSAVE) - /* Doze for a while (until the next interrupt). This works - * fine, because the keyboard is interrupt-driven, and the - * timer interrupt (approx. every 50msec) takes care of the - * serial port, which is read by polling. This reduces the - * power dissipation of a modern CPU considerably, and also - * makes Etherboot waiting for user interaction waste a lot - * less CPU time in a VMware session. */ - cpu_nap(); -#endif /* POWERSAVE */ -#ifdef CONSOLE_FIRMWARE - if (console_ischar()) - c = console_getc(); -#endif -#ifdef CONSOLE_SERIAL - if (serial_ischar()) - c = serial_getc(); -#endif -#ifdef CONSOLE_PC_KBD - if (kbd_ischar()) - c = kbd_getc(); -#endif - } while (c==256); - if (c == '\r') - c = '\n'; - return c; -} - -int iskey(void) -{ -#ifdef CONSOLE_FIRMWARE - if (console_ischar()) - return 1; -#endif -#ifdef CONSOLE_SERIAL - if (serial_ischar()) - return 1; -#endif -#ifdef CONSOLE_PC_KBD - if (kbd_ischar()) - return 1; -#endif - return 0; -} #if DEBUG_UTILS diff --git a/src/core/osloader.c b/src/core/osloader.c index ae67b34d..f70aeacd 100644 --- a/src/core/osloader.c +++ b/src/core/osloader.c @@ -30,6 +30,22 @@ Modifications: Ken Yap (for Etherboot/16) */ #include "etherboot.h" +#include "memsizes.h" + +#ifdef KEEP_IT_REAL + +#warning "All download mechanisms are broken under KEEP_IT_REAL" + +os_download_t probe_image(unsigned char *data, unsigned int len) { + return 0; +} + +int load_block(unsigned char *data, unsigned int block, unsigned int len, int eof) { + return 1; +} + +#else /* KEEP_IT_REAL */ + struct os_entry_regs os_regs; @@ -128,7 +144,7 @@ static void done(int do_cleanup) */ if ( do_cleanup ) { cleanup(); - arch_on_exit(0); + /* arch_on_exit(0); */ } } @@ -261,6 +277,7 @@ PROBE_IMAGE - Detect image file type os_download_t probe_image(unsigned char *data, unsigned int len) { os_download_t os_download = 0; + #ifdef AOUT_IMAGE if (!os_download) os_download = aout_probe(data, len); #endif @@ -286,6 +303,7 @@ os_download_t probe_image(unsigned char *data, unsigned int len) #ifdef RAW_IMAGE if (!os_download) os_download = raw_probe(data, len); #endif + return os_download; } @@ -363,3 +381,4 @@ int load_block(unsigned char *data, unsigned int block, unsigned int len, int eo * End: */ +#endif /* KEEP_IT_REAL */ diff --git a/src/core/pc_kbd.c b/src/core/pc_kbd.c index 9fe82924..84a3c640 100644 --- a/src/core/pc_kbd.c +++ b/src/core/pc_kbd.c @@ -9,8 +9,9 @@ * 2004-04 moved by LYH From filo to Etherboot * yhlu@tyan.com */ -#ifdef CONSOLE_PC_KBD -#include "etherboot.h" + +#include "io.h" +#include "console.h" static char key_map[][128] = { { @@ -69,14 +70,14 @@ static int get_scancode(void) return scan; } -int kbd_havekey(void) +static int kbd_havekey(void) { if (!cur_scan) cur_scan = get_scancode(); return cur_scan != 0; } -int kbd_ischar(void) +static int kbd_ischar(void) { if (!kbd_havekey()) return 0; @@ -87,7 +88,7 @@ int kbd_ischar(void) return 1; } -int kbd_getc(void) +static int kbd_getc(void) { int c; @@ -105,4 +106,7 @@ int kbd_getc(void) cur_scan = 0; return c; } -#endif + +static struct console_driver pc_kbd_console __console_driver = { + .getchar = kbd_getc, +}; diff --git a/src/core/pcmcia.c b/src/core/pcmcia.c index 2a7cf2b8..03a96de8 100644 --- a/src/core/pcmcia.c +++ b/src/core/pcmcia.c @@ -1,5 +1,3 @@ -#ifdef CONFIG_PCMCIA - /* * pcmcia.c * @@ -25,13 +23,13 @@ * at some point. If there's anything obvious or better, not-so-obvious, * please contact me by e-mail: anselm (AT) hoffmeister (DOT) be *THANKS* */ -#include "../include/pcmcia.h" -#include "../include/i82365.h" +#include "pcmcia.h" +#include "i82365.h" #define CODE_STATUS "alpha" #define CODE_VERSION "0.1.3" - -#include "../include/pcmcia-opts.h" -#include "../include/pcmcia.h" +#include "pcmcia-opts.h" +#include "console.h" +#include "init.h" int sockets; /* AHTODO: Phase this out! */ u_int pccsocks; @@ -55,7 +53,7 @@ void sleepticks(int numticks ) { return; } -int pcmcia_init_all(void) { +static void pcmcia_init_all(void) { u_int i, j, k, l, m, n, ui, configs = 0; u_int multicard[8]; u_char *uc, upc; @@ -253,17 +251,15 @@ int pcmcia_init_all(void) { getchar(); } - return 0; } -int pcmcia_shutdown_all(void) { +static void pcmcia_shutdown_all(void) { int i; //if ( PDEBUG > 2 ) {printf("\n" ); getchar(); } for ( i = 0; i < pccsocks; ++i ) { driver[pccsock[i].drivernum].f(SHUTDOWN,pccsock[i].internalid,0,0,0); } printf("Shutdown of PCMCIA subsystem completed"); - return 0; } -#endif /* CONFIG_PCMCIA */ +INIT_FN ( INIT_PCMCIA, pcmcia_init_all, NULL, pcmcia_shutdown_all ); diff --git a/src/core/pxe_export.c b/src/core/pxe_export.c index 0199de28..b2ecee19 100644 --- a/src/core/pxe_export.c +++ b/src/core/pxe_export.c @@ -1230,17 +1230,11 @@ PXENV_EXIT_t pxenv_undi_loader ( undi_loader_t *loader ) { * this, but it's currently split interestingly between main() * and main_loop()... */ - console_init(); - cpu_setup(); - setup_timers(); - gateA20_set(); print_config(); get_memsizes(); cleanup(); relocate(); cleanup(); - console_init(); - init_heap(); /* We have relocated; the loader pointer is now invalid */ loader = phys_to_virt ( loader_phys ); diff --git a/src/core/relocate.c b/src/core/relocate.c index d20846a8..436432e5 100644 --- a/src/core/relocate.c +++ b/src/core/relocate.c @@ -1,6 +1,7 @@ #ifndef NORELOCATE #include "etherboot.h" +#include "memsizes.h" /* by Eric Biederman */ @@ -93,10 +94,10 @@ void relocate(void) printf("Relocating _text from: [%lx,%lx) to [%lx,%lx)\n", old_addr, virt_to_phys(_end), addr, eaddr); - arch_relocate_to(addr); + /* arch_relocate_to ( addr ) */ cleanup(); relocate_to(addr); - arch_relocated_from(old_addr); + /* arch_relocated_from ( addr ) */ } } diff --git a/src/core/serial.c b/src/core/serial.c index 72207e8d..2c187860 100644 --- a/src/core/serial.c +++ b/src/core/serial.c @@ -1,7 +1,3 @@ -#include "etherboot.h" -#include "timer.h" -#ifdef CONSOLE_SERIAL - /* * The serial port interface routines implement a simple polled i/o * interface to a standard serial port. Due to the space restrictions @@ -15,25 +11,27 @@ * parity, 1 stop bit (8N1). This can be changed in init_serial(). */ -static int found = 0; +#include "stddef.h" +#include "console.h" +#include "init.h" +#include "io.h" +#include "timer.h" + +/* Set default values if none specified */ + +#ifndef COMCONSOLE +#define COMCONSOLE ( 0x3f8 ) +#endif + +#ifndef CONSPEED +#define CONSPEED ( 9600 ) +#endif -#if defined(COMCONSOLE) #undef UART_BASE #define UART_BASE COMCONSOLE -#endif -#ifndef UART_BASE -#error UART_BASE not defined -#endif - -#if defined(CONSPEED) #undef UART_BAUD #define UART_BAUD CONSPEED -#endif - -#ifndef UART_BAUD -#define UART_BAUD 115200 -#endif #if ((115200%UART_BAUD) != 0) #error Bad ttys0 baud rate @@ -83,18 +81,15 @@ static int found = 0; #define uart_writeb(val,addr) outb((val),(addr)) #endif +static struct console_driver serial_console; + /* * void serial_putc(int ch); * Write character `ch' to port UART_BASE. */ -void serial_putc(int ch) -{ +static void serial_putc ( int ch ) { int i; int status; - if (!found) { - /* no serial interface */ - return; - } i = 1000; /* timeout */ while(--i > 0) { status = uart_readb(UART_BASE + UART_LSR); @@ -111,8 +106,7 @@ void serial_putc(int ch) * int serial_getc(void); * Read a character from port UART_BASE. */ -int serial_getc(void) -{ +static int serial_getc ( void ) { int status; int ch; do { @@ -131,11 +125,8 @@ int serial_getc(void) * If there is a character in the input buffer of port UART_BASE, * return nonzero; otherwise return 0. */ -int serial_ischar(void) -{ +static int serial_ischar ( void ) { int status; - if (!found) - return 0; status = uart_readb(UART_BASE + UART_LSR); /* line status reg; */ return status & 1; /* rx char available */ } @@ -144,15 +135,10 @@ int serial_ischar(void) * int serial_init(void); * Initialize port UART_BASE to speed CONSPEED, line settings 8N1. */ -int serial_init(void) -{ - int initialized = 0; +static void serial_init ( void ) { int status; int divisor, lcs; - if (found) - return 1; - divisor = COMBRD; lcs = UART_LCS; @@ -207,10 +193,9 @@ int serial_init(void) /* line status reg */ status = uart_readb(UART_BASE + UART_LSR); } while(status & UART_LSR_DR); - initialized = 1; + serial_console.disabled = 0; out: - found = initialized; - return initialized; + return; } /* @@ -218,10 +203,9 @@ int serial_init(void) * Cleanup our use of the serial port, in particular flush the * output buffer so we don't accidentially loose characters. */ -void serial_fini(void) -{ +static void serial_fini ( void ) { int i, status; - if (!found) { + if (serial_console.disabled) { /* no serial interface */ return; } @@ -232,5 +216,15 @@ void serial_fini(void) do { status = uart_readb(UART_BASE + UART_LSR); } while((--i > 0) && !(status & UART_LSR_TEMPT)); + /* Don't mark it as disabled; it's still usable */ } -#endif + +static struct console_driver serial_console __console_driver = { + .putchar = serial_putc, + .getchar = serial_getc, + .iskey = serial_ischar, + .disabled = 1, +}; + +INIT_FN ( INIT_CONSOLE, serial_init, NULL, serial_fini ); + diff --git a/src/drivers/disk/ide_disk.c b/src/drivers/disk/ide_disk.c index be0fa310..d7e62aca 100644 --- a/src/drivers/disk/ide_disk.c +++ b/src/drivers/disk/ide_disk.c @@ -759,7 +759,8 @@ static int ide_pci_probe(struct dev *dev, struct pci_device *pci) } #define PCI_DEVICE_ID_INTEL_82801CA_11 0x248b static struct pci_id ide_controllers[] = { -{ PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82801CA_11, "PIIX4" }, + PCI_ROM(0x0000, 0x0000, "ide_disk", "Generic IDE disk support"), +/* { PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82801CA_11, "PIIX4" },*/ #if 0 /* Currently I don't need any entries in this table so ignore it */ { PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82371FB_0, "PIIX" }, { PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82371FB_1, "PIIX" }, diff --git a/src/drivers/net/3c509.c b/src/drivers/net/3c509.c index 0a7187ed..6375e8c7 100644 --- a/src/drivers/net/3c509.c +++ b/src/drivers/net/3c509.c @@ -653,6 +653,7 @@ static struct isa_driver t509_driver __isa_driver = { .probe = t509_probe, .ioaddrs = 0, }; +ISA_ROM("3c509","3c509, ISA/EISA"); #endif #ifdef INCLUDE_3C529 @@ -662,6 +663,7 @@ static struct isa_driver t529_driver __isa_driver = { .probe = t529_probe, .ioaddrs = 0, }; +ISA_ROM("3c529","3c529 == MCA 3c509"); #endif /* diff --git a/src/drivers/net/3c515.c b/src/drivers/net/3c515.c index f185acef..7c21b45e 100644 --- a/src/drivers/net/3c515.c +++ b/src/drivers/net/3c515.c @@ -812,3 +812,4 @@ static struct isa_driver t515_driver __isa_driver = { .probe = t515_probe, .ioaddrs = 0, }; +ISA_ROM("3c515","3c515, Fast EtherLink ISA"); diff --git a/src/drivers/net/cs89x0.c b/src/drivers/net/cs89x0.c index 42de1f2a..f418dc1b 100644 --- a/src/drivers/net/cs89x0.c +++ b/src/drivers/net/cs89x0.c @@ -711,6 +711,7 @@ static struct isa_driver cs89x0_driver __isa_driver = { .probe = cs89x0_probe, .ioaddrs = 0, }; +ISA_ROM("cs89x0","Crystal Semiconductor CS89x0"); /* * Local variables: diff --git a/src/drivers/net/depca.c b/src/drivers/net/depca.c index 29266b10..ca456803 100644 --- a/src/drivers/net/depca.c +++ b/src/drivers/net/depca.c @@ -792,3 +792,4 @@ static struct isa_driver depca_driver __isa_driver = { .probe = depca_probe, .ioaddrs = 0, }; +ISA_ROM("depca","Digital DE100 and DE200"); diff --git a/src/drivers/net/eepro.c b/src/drivers/net/eepro.c index b27c9f7f..a191a163 100644 --- a/src/drivers/net/eepro.c +++ b/src/drivers/net/eepro.c @@ -623,3 +623,4 @@ static struct isa_driver eepro_driver __isa_driver = { .probe = eepro_probe, .ioaddrs = 0, }; +ISA_ROM("eepro","Intel Etherexpress Pro/10"); diff --git a/src/drivers/net/ns83820.c b/src/drivers/net/ns83820.c index 16b41f8b..34f6f50d 100755 --- a/src/drivers/net/ns83820.c +++ b/src/drivers/net/ns83820.c @@ -370,25 +370,6 @@ struct ring_desc { }; #endif -/* Define the TX Descriptor */ -static struct ring_desc tx_ring[NR_TX_DESC] - __attribute__ ((aligned(8))); - -/* Create a static buffer of size REAL_RX_BUF_SIZE for each -TX Descriptor. All descriptors point to a -part of this buffer */ -static unsigned char txb[NR_TX_DESC * REAL_RX_BUF_SIZE]; - -/* Define the TX Descriptor */ -static struct ring_desc rx_ring[NR_RX_DESC] - __attribute__ ((aligned(8))); - -/* Create a static buffer of size REAL_RX_BUF_SIZE for each -RX Descriptor All descriptors point to a -part of this buffer */ -static unsigned char rxb[NR_RX_DESC * REAL_RX_BUF_SIZE] - __attribute__ ((aligned(8))); - /* Private Storage for the NIC */ struct ns83820_private { u8 *base; @@ -412,6 +393,25 @@ struct ns83820_private { } nsx; static struct ns83820_private *ns; +/* Define the TX Descriptor */ +static struct ring_desc tx_ring[NR_TX_DESC] + __attribute__ ((aligned(8))); + +/* Create a static buffer of size REAL_RX_BUF_SIZE for each +TX Descriptor. All descriptors point to a +part of this buffer */ +static unsigned char txb[NR_TX_DESC * REAL_RX_BUF_SIZE]; + +/* Define the TX Descriptor */ +static struct ring_desc rx_ring[NR_RX_DESC] + __attribute__ ((aligned(8))); + +/* Create a static buffer of size REAL_RX_BUF_SIZE for each +RX Descriptor All descriptors point to a +part of this buffer */ +static unsigned char rxb[NR_RX_DESC * REAL_RX_BUF_SIZE] + __attribute__ ((aligned(8))); + static void phy_intr(struct nic *nic __unused) { static char *speeds[] = diff --git a/src/drivers/net/ns8390.c b/src/drivers/net/ns8390.c index dddc0819..5a18c8e6 100644 --- a/src/drivers/net/ns8390.c +++ b/src/drivers/net/ns8390.c @@ -961,6 +961,7 @@ static struct isa_driver wd_driver __isa_driver = { .probe = wd_probe, .ioaddrs = 0, }; +ISA_ROM("wd","WD8003/8013, SMC8216/8416, SMC 83c790 (EtherEZ)"); #endif #ifdef INCLUDE_3C503 @@ -970,6 +971,7 @@ static struct isa_driver t503_driver __isa_driver = { .probe = t503_probe, .ioaddrs = 0, }; +ISA_ROM("3c503","3Com503, Etherlink II[/16]"); #endif #ifdef INCLUDE_NE @@ -979,6 +981,7 @@ static struct isa_driver ne_driver __isa_driver = { .probe = ne_probe, .ioaddrs = 0, }; +ISA_ROM("ne","NE1000/2000 and clones"); #endif #ifdef INCLUDE_NS8390 @@ -1013,4 +1016,3 @@ static struct pci_driver nepci_driver __pci_driver = { * c-basic-offset: 8 * End: */ - diff --git a/src/drivers/net/prism2_pci.c b/src/drivers/net/prism2_pci.c index be2b06cc..4aafb4ff 100644 --- a/src/drivers/net/prism2_pci.c +++ b/src/drivers/net/prism2_pci.c @@ -18,7 +18,9 @@ $Id$ #include "prism2.c" static struct pci_id prism2_pci_nics[] = { -PCI_ROM(0x1260, 0x3873, "prism2_pci", "Harris Semiconductor Prism2.5 clone"), /* Generic Prism2.5 PCI device */ +PCI_ROM(0x1260, 0x3873, "prism2_pci", "Harris Semiconductor Prism2.5 clone"), +PCI_ROM(0x1260, 0x3873, "hwp01170", "ActionTec HWP01170"), +PCI_ROM(0x1260, 0x3873, "dwl520", "DLink DWL-520"), }; static struct pci_driver prism2_pci_driver __pci_driver = { diff --git a/src/drivers/net/sk_g16.c b/src/drivers/net/sk_g16.c index 6591c020..f65118d7 100644 --- a/src/drivers/net/sk_g16.c +++ b/src/drivers/net/sk_g16.c @@ -1187,3 +1187,4 @@ static struct isa_driver SK_driver __isa_driver = { .probe = SK_probe, .ioaddrs = 0, }; +ISA_ROM("sk_g16","Schneider and Koch G16"); diff --git a/src/drivers/net/smc9000.c b/src/drivers/net/smc9000.c index a05521e8..6a935e35 100644 --- a/src/drivers/net/smc9000.c +++ b/src/drivers/net/smc9000.c @@ -542,3 +542,4 @@ static struct isa_driver smc9000_driver __isa_driver = { .probe = smc9000_probe, .ioaddrs = 0, }; +ISA_ROM("smc9000","SMC9000"); diff --git a/src/genrules.pl b/src/genrules.pl deleted file mode 100755 index 0a129c80..00000000 --- a/src/genrules.pl +++ /dev/null @@ -1,376 +0,0 @@ -#!/usr/bin/perl -w -# -# Helper program to generate Makefile rules into file Rom from table in -# file NIC -# -# GPL, Ken Yap 2001, with major contributions by Klaus Espenlaub -# Revised 2002 -# - -use strict; - -use bytes; - -use File::Basename; - -use vars qw($familyfile $nic @families $curfam %drivers %pcient %isaent %isalist %buildent $arch @srcs); - -sub __gendep ($$$) -{ - my ($file, $deps, $driver_dep) = @_; - foreach my $source (@$deps) { - my $inc; - my @collect_dep = (); - $inc = "arch/$arch/include/$source" unless ! -e "arch/$arch/include/$source"; - $inc = "include/$source" unless ! -e "include/$source"; - $inc = dirname($file) . "/$source" unless ! -e dirname($file) . "/$source"; - unless (defined($inc)) { - print STDERR "$source from $file not found (shouldn't happen)\n"; - next; - }; - next if (exists ${$driver_dep}{$inc}); - ${$driver_dep}{$inc} = $inc; -# Warn about failure to open, then skip, rather than soldiering on with the read - unless (open(INFILE, "$inc")) { - print STDERR "$inc: $! (shouldn't happen)\n"; - next; - }; - while () { - chomp($_); -# This code is not very smart: no C comments or CPP conditionals processing is -# done. This may cause unexpected (or incorrect) additional dependencies. -# However, ignoring the CPP conditionals is in some sense correct: we need to -# figure out a superset of all the headers for the driver source. - next unless (s/^\s*#include\s*"([^"]*)".*$/$1/); -# Ignore system includes, like the ones in osdep.h - next if ($_ =~ m:^/:); -# Ignore "special" includes, like .buildserial.h - next if /^\./; - push(@collect_dep, $_); - } - close(INFILE); - if (@collect_dep) { - &__gendep($inc, \@collect_dep, $driver_dep); - } - } -} - -sub gendep ($) { - my ($driver) = @_; - - # Automatically generate the dependencies for the driver sources. - my %driver_dep = (); - __gendep( "", [ $driver ], \%driver_dep); - return sort values %driver_dep -} - -# Make sure that every rom name exists only once. -# make will warn if it finds duplicate rules, but it is better to stop -sub checkduplicate (\%$$) { - my ($anyent, $curfam, $romname) = @_; - foreach my $family (@families) { - if (exists($$anyent{$family})) { - my $aref = $$anyent{$family}; - foreach my $entry (@$aref) { - if ($entry->[0] eq $romname) { - print STDERR "\nROM name $romname defined twice. Please correct.\n"; - exit 1; - } - } - } - } -} - -sub genroms($) { - my ($driver) = @_; - - # Automatically discover the ROMS this driver can produce. - unless (open(INFILE, "$driver")) { - print STDERR "$driver: %! (shouldn't happen)\n"; - next; - }; - while () { - chomp($_); - if ($_ =~ m/^\s*PCI_ROM\(\s*0x([0-9A-Fa-f]*)\s*,\s*0x([0-9A-Fa-f]*)\s*,\s*"([^"]*)"\s*,\s*"([^"]*)"\)/) { - - # We store a list of PCI IDs and comments for each PC target - my ($vendor_id, $device_id, $rom, $comment) = (hex($1), hex($2), $3, $4); - my $ids = sprintf("0x%04x,0x%04x", $vendor_id, $device_id); - checkduplicate(%pcient, $curfam, $rom); - push(@{$pcient{$curfam}}, [$rom, $ids, $comment]); - } - elsif($_ =~ m/^\s*ISA_ROM\(\s*"([^"]*)"\s*,\s*"([^"]*)"\)/) { - my ($rom, $comment) = ($1, $2); - # We store the base driver file for each ISA target - $isalist{$rom} = $curfam; - $buildent{$rom} = 1; - checkduplicate(%isaent, $curfam, $rom); - push(@{$isaent{$curfam}}, [$rom, $comment]); - } - elsif($_ =~ m/^\s*PCI_ROM/ or $_ =~ m/^\s*ISA_ROM/) { - # Complain since we cannot parse this. Of course it would be nicer if we could parse... - print STDERR "\nFound incomplete PCI_ROM or ISA_ROM macro in file $driver.\n"; - print STDERR "ROM macros spanning more than one line are not supported,\n"; - print STDERR "please adjust $driver accordingly.\n\n\n"; - exit 1; - } - } -} - -sub addfam ($) { - my ($family) = @_; - - push(@families, $family); - # We store the list of dependencies in the hash for each family - my @deps = &gendep("$family.c"); - $drivers{$family} = join(' ', @deps); - $pcient{$family} = []; - genroms("$family.c"); -} - -sub addrom ($) { - my ($rom, $ids, $comment) = split(' ', $_[0], 3); - - # defaults if missing - $ids = '-' unless ($ids); - $comment = $rom unless ($comment); - if ($ids ne '-') { - # We store a list of PCI IDs and comments for each PCI target - checkduplicate(%pcient, $curfam, $rom); - push(@{$pcient{$curfam}}, [$rom, $ids, $comment]); - } else { - # We store the base driver file for each ISA target - $isalist{$rom} = $curfam; - $buildent{$rom} = 1; - checkduplicate(%isaent, $curfam, $rom); - push(@{$isaent{$curfam}}, [$rom, $comment]); - } -} - -# Return true if this driver is ISA only -sub isaonly ($) { - my $aref = $pcient{$_[0]}; - - return ($#$aref < 0); -} - -$#ARGV >= 1 or die "Usage: $0 Families bin/NIC arch sources...\n"; -$familyfile = shift(@ARGV); -$nic = shift(@ARGV); -$arch = shift(@ARGV); -@srcs = @ARGV; -open FAM, "<$familyfile" or die "Could not open $familyfile: $!\n"; - -$curfam = ''; -while ( ) { - chomp($_); - next if (/^\s*(#.*)?$/); - my ($keyword) = split(' ', $_ , 2); - if ($keyword eq 'family') { - my ($keyword, $driver) = split(' ', $_, 2); - $curfam = ''; - if (! -e "$driver.c") { - print STDERR "Driver file $driver.c not found, skipping...\n"; - next; - } - if ($driver =~ "^arch" && $driver !~ "^arch/$arch") { -# This warning just makes noise for most compilations. -# print STDERR "Driver file $driver.c not for arch $arch, skipping...\n"; - next; - } - &addfam($curfam = $driver); - } else { - # skip until we have a valid family - next if ($curfam eq ''); - &addrom($_); - } -} -close FAM; - -open(N,">$nic") or die "$nic: $!\n"; -print N <[0]; - my $ids = $entry->[1]; - my $comment = $entry->[2]; - print N "$rom\t$ids\t$comment\n"; - } - } - if (exists($isaent{$family})) { - my $aref = $isaent{$family}; - foreach my $entry (@$aref) { - my $rom = $entry->[0]; - my $comment = $entry->[1]; - print N "$rom\t-\t$comment\n"; - } - } - print N "\n"; -} -close(N); - -# Generate the normal source dependencies -print "# Core object file dependencies\n"; -foreach my $source (@srcs) { - next if ($source !~ '[.][cS]$'); - my @deps = &gendep($source); - my $obj = $source; - $obj =~ s/^.*?([^\/]+)\.[cS]/bin\/$1.o/; - foreach my $dep (@deps) { - print "$obj: $dep\n"; - } - print("\n"); -} - -# Generate the assignments to DOBJS and BINS -print "# Driver object files and ROM image files\n"; -print "DOBJS\t:=\n"; -print "PCIOBJS\t:=\n"; - -print "# Target formats\n"; -print "EB_ISOS\t:=\n"; -print "EB_LISOS\t:=\n"; -print "EB_COMS\t:=\n"; -print "EB_EXES\t:=\n"; -print "EB_LILOS\t:=\n"; -print "EB_ZLILOS\t:=\n"; -print "EB_PXES\t:=\n"; -print "EB_ZPXES\t:=\n"; -print "EB_DSKS\t:=\n"; -print "EB_ZDSKS\t:=\n"; -print "EB_ELFS\t:=\n"; -print "EB_ZELFS\t:=\n"; -print "EB_LMELFS\t:=\n"; -print "EB_ZLMELFS\t:=\n"; -print "EB_ELFDS\t:=\n"; -print "EB_ZELFDS\t:=\n"; -print "EB_LMELFDS\t:=\n"; -print "EB_ZLMELFDS\t:=\n"; - -foreach my $pci (sort keys %pcient) { - my $img = basename($pci); - - print "DOBJS\t+= \$(BIN)/$img.o\n"; - print "PCIOBJS\t+= \$(BIN)/$img.o\n" unless isaonly($pci); - -# Output targets - print "EB_LILOS\t+= \$(BIN)/$img.lilo \nEB_ZLILOS\t+= \$(BIN)/$img.zlilo\n"; - print "EB_PXES\t+= \$(BIN)/$img.pxe \nEB_ZPXES\t+= \$(BIN)/$img.zpxe\n"; - print "EB_DSKS\t+= \$(BIN)/$img.dsk \nEB_ZDSKS\t+= \$(BIN)/$img.zdsk\n"; - print "EB_ELFS\t+= \$(BIN)/$img.elf \nEB_ZELFS\t+= \$(BIN)/$img.zelf\n"; - print "EB_LMELFS\t+= \$(BIN)/$img.lmelf \nEB_ZLMELFS\t+= \$(BIN)/$img.zlmelf\n"; - print "EB_ELFDS\t+= \$(BIN)/$img.elfd \nEB_ZELFDS\t+= \$(BIN)/$img.zelfd\n"; - print "EB_LMELFDS\t+= \$(BIN)/$img.lmelfd \nEB_ZLMELFDS\t+= \$(BIN)/$img.zlmelfd\n"; - print "EB_BIMAGES\t+= \$(BIN)/$img.bImage \nEB_BZIMAGES\t+= \$(BIN)/$img.bzImage\n"; - print "EB_ISOS\t+= \$(BIN)/$img.iso\n"; - print "EB_LISOS\t+= \$(BIN)/$img.liso\n"; - print "EB_COMS\t+= \$(BIN)/$img.com\n"; - print "EB_EXES\t+= \$(BIN)/$img.exe\n"; -} - -foreach my $img (sort keys %buildent) { - - print "DOBJS\t+= \$(BIN)/$img.o\n"; - -# Output targets - print "EB_LILOS\t+= \$(BIN)/$img.lilo \nEB_ZLILOS\t+= \$(BIN)/$img.zlilo\n"; - print "EB_PXES\t+= \$(BIN)/$img.pxe \nEB_ZPXES\t+= \$(BIN)/$img.zpxe\n"; - print "EB_DSKS\t+= \$(BIN)/$img.dsk \nEB_ZDSKS\t+= \$(BIN)/$img.zdsk\n"; - print "EB_ELFS\t+= \$(BIN)/$img.elf \nEB_ZELFS\t+= \$(BIN)/$img.zelf\n"; - print "EB_LMELFS\t+= \$(BIN)/$img.lmelf \nEB_ZLMELFS\t+= \$(BIN)/$img.zlmelf\n"; - print "EB_ELFDS\t+= \$(BIN)/$img.elfd \nEB_ZELFDS\t+= \$(BIN)/$img.zelfd\n"; - print "EB_LMELFDS\t+= \$(BIN)/$img.lmelfd \nEB_ZLMELFDS\t+= \$(BIN)/$img.zlmelfd\n"; - print "EB_BIMAGES\t+= \$(BIN)/$img.bImage \nEB_BZIMAGE\t+= \$(BIN)/$img.bzImage\n"; - print "EB_ISOS\t+= \$(BIN)/$img.iso\n"; - print "EB_LISOS\t+= \$(BIN)/$img.liso\n"; - print "EB_COMS\t+= \$(BIN)/$img.com\n"; - print "EB_EXES\t+= \$(BIN)/$img.exe\n"; -} - -print "ROMS\t:=\n"; -foreach my $family (sort keys %pcient) { - my $aref = $pcient{$family}; - foreach my $entry (@$aref) { - my $rom = $entry->[0]; - print "ROMS\t+= \$(BIN)/$rom.rom \$(BIN)/$rom.zrom\n"; - } -} -foreach my $isa (sort keys %isalist) { - print "ROMS\t+= \$(BIN)/$isa.rom \$(BIN)/$isa.zrom\n"; -} - -# Generate the *.o rules -print "\n# Rules to build the driver object files\n"; -foreach my $pci (sort keys %drivers) { - # For ISA the rule for .o will generated later - next if isaonly($pci); - # PCI drivers are compiled only once for all ROMs - (my $macro = basename($pci)) =~ tr/\-/_/; - my $obj = basename($pci); - my $deps = $drivers{$pci}; - print < \$@ - \$(MAKEROM) \$(MAKEROM_FLAGS) \$(MAKEROM_\$(ROMCARD)) \$(MAKEROM_ID_\$(ROMCARD)) -i\$(IDENT) \$@ - -EOF - } -} - -# ISA ROMs are prepared from the matching code images -# Think this can probably be removed, but not sure -foreach my $isa (sort keys %isalist) { - print < */ -extern void btext_clearscreen(void); - extern boot_infos_t disp_bi; extern u32 boot_text_mapped; -void btext_setup_display(u32 width, u32 height, u32 depth, u32 pitch, - unsigned long address); -void map_boot_text(void); - -void btext_drawchar(char c); -void btext_drawstring(const char *str); -void btext_drawhex(u32 v); - -void btext_putc(int c); - -void btext_init(void); - #endif /* _BTEXT_H */ diff --git a/src/include/compiler.h b/src/include/compiler.h new file mode 100644 index 00000000..401d4e45 --- /dev/null +++ b/src/include/compiler.h @@ -0,0 +1,41 @@ +#ifndef COMPILER_H +#define COMPILER_H + +/* We export the symbol obj_OBJECT (OBJECT is defined on command-line) + * as a global symbol, so that the linker can drag in selected object + * files from the library using -u obj_OBJECT. + * + * Not quite sure why cpp requires two levels of macro call in order + * to actually expand OBJECT... + */ +#undef _H1 +#define _H1( x, y ) x ## y +#undef _H2 +#define _H2( x, y ) _H1 ( x, y ) +#define OBJECT_SYMBOL _H2 ( obj_, OBJECT ) +#undef _STR +#define _STR(s) #s +#undef _XSTR +#define _XSTR(s) _STR(s) +#define OBJECT_SYMBOL_STR _XSTR ( OBJECT_SYMBOL ) + +#ifdef ASSEMBLY + + .globl OBJECT_SYMBOL + .equ OBJECT_SYMBOL, 0 + +#else /* ASSEMBLY */ + +__asm__ ( ".globl\t" OBJECT_SYMBOL_STR ); +__asm__ ( ".equ\t" OBJECT_SYMBOL_STR ", 0" ); + +#define REQUIRE_OBJECT(object) \ + __asm__ ( ".equ\tneed_" #object ", obj_" #object ); + +#define PACKED __attribute__((packed)) +#define __unused __attribute__((unused)) +#define __used __attribute__((used)) + +#endif /* ASSEMBLY */ + +#endif /* COMPILER_H */ diff --git a/src/include/console.h b/src/include/console.h new file mode 100644 index 00000000..ce2e5392 --- /dev/null +++ b/src/include/console.h @@ -0,0 +1,28 @@ +#ifndef CONSOLE_H +#define CONSOLE_H + +#include "stdint.h" + +/* + * Consoles that cannot be used before their INIT_FN() has completed + * should set disabled = 1 initially. This allows other console + * devices to still be used to print out early debugging messages. + */ + +struct console_driver { + int disabled; + void ( *putchar ) ( int character ); + int ( *getchar ) ( void ); + int ( *iskey ) ( void ); +}; + +#define __console_driver \ + __attribute__ (( used, __section__ ( ".drivers.console" ) )) + +/* Function prototypes */ + +extern void putchar ( int character ); +extern int getchar ( void ); +extern int iskey ( void ); + +#endif /* CONSOLE_H */ diff --git a/src/include/etherboot.h b/src/include/etherboot.h index 44ada538..f4a4f126 100644 --- a/src/include/etherboot.h +++ b/src/include/etherboot.h @@ -49,28 +49,6 @@ #define DEFAULT_BOOTFILE PXENFSROOTPATH "/boot/pxeboot" #endif -/* Clean up console settings... mainly CONSOLE_FIRMWARE and CONSOLE_SERIAL are used - * in the sources (except start.S and serial.S which cannot include - * etherboot.h). At least one of the CONSOLE_xxx has to be set, and - * CONSOLE_DUAL sets both CONSOLE_CRT and CONSOLE_SERIAL. If none is set, - * CONSOLE_CRT is assumed. */ -#ifdef CONSOLE_CRT -#define CONSOLE_FIRMWARE -#endif -#ifdef CONSOLE_DUAL -#undef CONSOLE_FIRMWARE -#define CONSOLE_FIRMWARE -#undef CONSOLE_SERIAL -#define CONSOLE_SERIAL -#endif -#if defined(CONSOLE_FIRMWARE) && defined(CONSOLE_SERIAL) -#undef CONSOLE_DUAL -#define CONSOLE_DUAL -#endif -#if !defined(CONSOLE_FIRMWARE) && !defined(CONSOLE_SERIAL) -#define CONSOLE_FIRMWARE -#endif - #if !defined(DOWNLOAD_PROTO_TFTP) && !defined(DOWNLOAD_PROTO_NFS) && !defined(DOWNLOAD_PROTO_SLAM) && !defined(DOWNLOAD_PROTO_TFTM) && !defined(DOWNLOAD_PROTO_DISK) && !defined(DOWNLOAD_PROTO_HTTP) #error No download protocol defined! #endif @@ -204,7 +182,7 @@ External prototypes struct Elf_Bhdr; extern int in_call(in_call_data_t *data, uint32_t opcode, va_list params); extern void console_init(void); -extern int main(in_call_data_t *data, va_list params); +extern int main(); extern int loadkernel P((const char *fname)); extern char as_main_program; /* nic.c */ @@ -287,26 +265,6 @@ extern unsigned long strtoul P((const char *p, const char **, int base)); extern void printf P((const char *, ...)); extern int sprintf P((char *, const char *, ...)); extern int inet_aton P((const char *p, in_addr *i)); -#ifdef PCBIOS -extern void gateA20_set P((void)); -#define gateA20_unset() -#else -#define gateA20_set() -#define gateA20_unset() -#endif -extern void putchar P((int)); -extern int getchar P((void)); -extern int iskey P((void)); - -/* pcbios.S */ -extern int console_getc P((void)); -extern void console_putc P((int)); -extern int console_ischar P((void)); -extern int getshift P((void)); -extern int int15 P((int)); -#ifdef POWERSAVE -extern void cpu_nap P((void)); -#endif /* POWERSAVE */ /* basemem.c */ extern uint32_t get_free_base_memory ( void ); @@ -318,26 +276,6 @@ extern void free_unused_base_memory ( void ); extern void forget_prefix_base_memory ( void ); extern void forget_runtime_base_memory ( uint32_t old_addr ); -struct e820entry { - uint64_t addr; - uint64_t size; - uint32_t type; -#define E820_RAM 1 -#define E820_RESERVED 2 -#define E820_ACPI 3 /* usable as RAM once ACPI tables have been read */ -#define E820_NVS 4 -} PACKED; -#define E820ENTRY_SIZE 20 -#define E820MAX 32 -struct meminfo { - uint16_t basememsize; - uint16_t pad; - uint32_t memsize; - uint32_t map_count; - struct e820entry map[E820MAX]; -} PACKED; -extern struct meminfo meminfo; -extern void get_memsizes(void); extern unsigned long get_boot_order(unsigned long order, unsigned *index); #ifndef NORELOCATE extern void relocate(void); diff --git a/src/include/init.h b/src/include/init.h new file mode 100644 index 00000000..9ec9dedc --- /dev/null +++ b/src/include/init.h @@ -0,0 +1,58 @@ +#ifndef INIT_H +#define INIT_H + +/* + * In order to avoid having objects dragged in just because main() + * calls their initialisation function, we allow each object to + * specify that it has a function that must be called to initialise + * that object. The function call_init_fns() will call all the + * included objects' initialisation functions. + * + * Objects that require initialisation should include init.h and + * register the initialisation function using INIT_FN(). + * + * Objects may register up to three functions: init, reset and exit. + * init gets called only once, at the point that Etherboot is + * initialised (before the call to main()). reset gets called between + * each boot attempt. exit gets called only once, just before the + * loaded OS starts up (or just before Etherboot exits, if it exits, + * or when the PXE NBP calls UNDI_SHUTDOWN, if it's a PXE NBP). + * + * The syntax is: + * INIT_FN ( init_order, init_function, reset_function, exit_function ); + * where init_order is an ordering taken from the list below. Any + * function may be left as NULL. + */ + +/* An entry in the initialisation function table */ + +struct init_fn { + void ( *init ) ( void ); + void ( *reset ) ( void ); + void ( *exit ) ( void ); +}; + +/* Use double digits to avoid problems with "10" < "9" on alphabetic sort */ +#define INIT_CONSOLE "00" +#define INIT_CPU "01" +#define INIT_TIMERS "02" +#define INIT_PCMCIA "03" +#define INIT_MEMSIZES "04" +#define INIT_HEAP "05" + +/* Macro for creating an initialisation function table entry */ +#define INIT_FN( init_order, init_func, reset_func, exit_func ) \ + static struct init_fn init_ ## init_func ## _ ## exit_func \ + __attribute__ ((used,__section__(".init_fns." init_order))) = { \ + .init = init_func, \ + .reset = reset_func, \ + .exit = exit_func, \ + }; + +/* Function prototypes */ + +void call_init_fns ( void ); +void call_reset_fns ( void ); +void call_exit_fns ( void ); + +#endif /* INIT_H */ diff --git a/src/include/main.h b/src/include/main.h new file mode 100644 index 00000000..2b2a96c0 --- /dev/null +++ b/src/include/main.h @@ -0,0 +1,6 @@ +#ifndef MAIN_H +#define MAIN_H + +extern int main ( void ); + +#endif /* MAIN_H */ diff --git a/src/include/osdep.h b/src/include/osdep.h index 1b03e567..d7e1af47 100644 --- a/src/include/osdep.h +++ b/src/include/osdep.h @@ -18,7 +18,6 @@ #include "setjmp.h" #include "latch.h" #include "callbacks.h" -#include "hooks.h" /* within 1MB of 4GB is too close. * MAX_ADDR is the maximum address we can easily do DMA to. diff --git a/src/include/stddef.h b/src/include/stddef.h new file mode 100644 index 00000000..ee1f1541 --- /dev/null +++ b/src/include/stddef.h @@ -0,0 +1,13 @@ +#ifndef STDDEF_H +#define STDDEF_H + +/* for size_t */ +#include "stdint.h" + +#undef NULL +#define NULL ((void *)0) + +#undef offsetof +#define offsetof(TYPE, MEMBER) ((size_t) &((TYPE *)0)->MEMBER) + +#endif /* STDDEF_H */ diff --git a/src/include/timer.h b/src/include/timer.h index 6b68f5f3..0044d0c0 100644 --- a/src/include/timer.h +++ b/src/include/timer.h @@ -53,7 +53,6 @@ extern void load_timer2(unsigned int ticks); extern inline int timer2_running(void); extern void waiton_timer2(unsigned int ticks); -extern void setup_timers(void); extern void ndelay(unsigned int nsecs); extern void udelay(unsigned int usecs); extern void mdelay(unsigned int msecs); diff --git a/src/util/parserom.pl b/src/util/parserom.pl new file mode 100644 index 00000000..56bb9445 --- /dev/null +++ b/src/util/parserom.pl @@ -0,0 +1,63 @@ +#!/usr/bin/perl -w +# +# Parse PCI_ROM and ISA_ROM entries from a source file on stdin and +# output the relevant Makefile variable definitions to stdout +# +# Based upon portions of Ken Yap's genrules.pl + +use strict; +use warnings; + +die "Syntax: $0 driver_source.c" unless @ARGV == 1; +my $source = shift; +open DRV, "<$source" or die "Could not open $source: $!\n"; + +( my $family, my $driver_name ) = ( $source =~ /^(.*?([^\/]+))\..$/ ) + or die "Could not parse source file name \"$source\"\n"; + +my $printed_family; + +sub rom { + ( my $type, my $image, my $desc, my $vendor, my $device ) = @_; + my $ids = $vendor ? "$vendor,$device" : "-"; + unless ( $printed_family ) { + print "\n"; + print "# NIC\t\n"; + print "# NIC\tfamily\t$family\n"; + print "DRIVERS += $driver_name\n"; + $printed_family = 1; + } + print "\n"; + print "# NIC\t$image\t$ids\t$desc\n"; + print "DRIVER_$image = $driver_name\n"; + print "ROM_TYPE_$image = $type\n"; + print "ROM_DESCRIPTION_$image = \"$desc\"\n"; + print "PCI_VENDOR_$image = $vendor\n" if $vendor; + print "PCI_DEVICE_$image = $device\n" if $device; + print "ROMS += $image\n"; + print "ROMS_$driver_name += $image\n"; +} + +while ( ) { + next unless /(PCI|ISA)_ROM\s*\(/; + + if ( /^\s*PCI_ROM\s*\( + \s*(0x[0-9A-Fa-f]{4})\s*, # PCI vendor + \s*(0x[0-9A-Fa-f]{4})\s*, # PCI device + \s*\"([^\"]*)\"\s*, # Image + \s*\"([^\"]*)\"\s* # Description + \)/x ) { + ( my $vendor, my $device, my $image, my $desc ) = ( lc $1, lc $2, $3, $4 ); + rom ( "pci", $image, $desc, $vendor, $device ); + } elsif ( /^\s*ISA_ROM\s*\( + \s*\"([^\"]*)\"\s*, # Image + \s*\"([^\"]*)\"\s* # Description + \)/x ) { + ( my $image, my $desc ) = ( $1, $2 ); + rom ( "isa", $image, $desc ); + } else { + warn "Malformed PCI_ROM or ISA_ROM macro on line $. of $source\n"; + } +} + +close DRV; diff --git a/src/util/zfilelen.pl b/src/util/zfilelen.pl deleted file mode 100755 index 1f58ff9e..00000000 --- a/src/util/zfilelen.pl +++ /dev/null @@ -1,8 +0,0 @@ -#!/usr/bin/perl -w - -use bytes; - -local $/; -$_ = <>; -print length($_); -exit;