david/ipxe
david
/
ipxe
Archived
1
0
Fork 0

Merged mcb30-realmode-redesign back to HEAD

This commit is contained in:
Michael Brown 2005-04-08 15:01:17 +00:00
parent de5d935135
commit 0ff80b477d
100 changed files with 4877 additions and 4263 deletions

View File

@ -1,2 +1,3 @@
bin
gcccheck
.toolcheck
TAGS*
bin*

View File

@ -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

View File

@ -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 <kenUNDERSCOREyap AT users PERIOD sourceforge PERIOD net>
# 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

View File

@ -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/<rom-name>.<output-format> '
@echo
@echo 'where <output-format> is one of [z]{$(MEDIA) }'
@echo
@echo 'or: '
@echo
@echo ' $(MAKE) all<output-format>s'
@echo
@echo 'to generate all possible images of format <output-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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

375
src/Makefile.housekeeping Normal file
View File

@ -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_<rom> and/or ROMS_<driver>.
#
# 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)

View File

@ -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/<rom-name>.<output-format> '
@echo
@echo 'where <output-format> is one of {zdsk, zrom, iso, liso, zlilo, zpxe, elf, com}'
@echo
@echo 'or: '
@echo
@echo ' $(MAKE) all<output-format>s'
@echo
@echo 'to generate all possible images of format <output-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)

View File

@ -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 );

View File

@ -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 );

View File

@ -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

View File

@ -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

197
src/arch/i386/README.i386 Normal file
View File

@ -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().

View File

@ -9,7 +9,6 @@
#include "etherboot.h"
#include "callbacks.h"
#include "realmode.h"
#include "segoff.h"
#include <stdarg.h>
/* Maximum amount of stack data that prefix may request to be passed

View File

@ -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 */

View File

@ -1,5 +1,6 @@
#include "etherboot.h"
#include "elf.h"
#include "memsizes.h"
#define NAME "Etherboot"

View File

@ -1,35 +1,93 @@
#include "etherboot.h"
#include "callbacks.h"
#include <stdarg.h>
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 ( &regs_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 */

View File

@ -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 );

View File

@ -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 */

View File

@ -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 */

View File

@ -3,9 +3,25 @@
* Initial version by Michael Brown <mbrown@fensystems.co.uk>, 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;

View File

@ -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

View File

@ -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

158
src/arch/i386/core/setup.S Normal file
View File

@ -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:

View File

@ -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:

View File

@ -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

View File

@ -1,5 +1,4 @@
#include "realmode.h"
#include "segoff.h"
struct segheader
{

View File

@ -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 <etherboot.h>
#include <vga.h>
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 );

View File

@ -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

View File

@ -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 = {

View File

@ -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 */

View File

@ -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,
};

View File

@ -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 */

View File

@ -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 */
}

View File

@ -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 );

View File

@ -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 */

View File

@ -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 */

View File

@ -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 );

View File

@ -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 */

View File

@ -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.

View File

@ -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 */

View File

@ -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 */

View File

@ -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 */

View File

@ -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 */

View File

@ -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 */

View File

@ -5,7 +5,6 @@
#define PXE_CALLBACKS_H
#include "etherboot.h"
#include "segoff.h"
#include "pxe.h"
typedef struct {

View File

@ -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

View File

@ -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 */

View File

@ -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 */

View File

@ -1,41 +0,0 @@
/*
* Segment:offset types and macros
*
* Initially written by Michael Brown (mcb30).
*/
#ifndef SEGOFF_H
#define SEGOFF_H
#include <stdint.h>
#include <osdep.h>
#include <io.h>
/* 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 */

View File

@ -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 */

View File

@ -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

View File

@ -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 */

View File

@ -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 */
}

View File

@ -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

View File

@ -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;
}

View File

@ -0,0 +1,243 @@
/*
* libkir: a transition library for -DKEEP_IT_REAL
*
* Michael Brown <mbrown@fensystems.co.uk>
*
*/
/****************************************************************************
* 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

View File

View File

@ -0,0 +1,691 @@
/*
* librm: a library for interfacing to real-mode code
*
* Michael Brown <mbrown@fensystems.co.uk>
*
*/
/* 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

View File

@ -0,0 +1,87 @@
/*
* librm: a library for interfacing to real-mode code
*
* Michael Brown <mbrown@fensystems.co.uk>
*
*/
#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 */

View File

@ -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 );

1
src/bin/.cvsignore Normal file
View File

@ -0,0 +1 @@
*

View File

@ -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

View File

@ -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

102
src/core/console.c Normal file
View File

@ -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;
}

View File

@ -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 );

44
src/core/init.c Normal file
View File

@ -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 ();
}
}

View File

@ -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 <stdarg.h>
#ifdef CONSOLE_BTEXT
#include "btext.h"
#endif
#ifdef CONFIG_FILO
#include <lib.h>
#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;
}

View File

@ -3,13 +3,7 @@ MISC Support Routines
**************************************************************************/
#include "etherboot.h"
#ifdef CONSOLE_BTEXT
#include <btext.h>
#endif
#ifdef CONSOLE_PC_KBD
#include <pc_kbd.h>
#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

View File

@ -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 */

View File

@ -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,
};

View File

@ -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("<press key to continue>\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 );

View File

@ -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 );

View File

@ -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 ) */
}
}

View File

@ -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 );

View File

@ -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" },

View File

@ -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
/*

View File

@ -812,3 +812,4 @@ static struct isa_driver t515_driver __isa_driver = {
.probe = t515_probe,
.ioaddrs = 0,
};
ISA_ROM("3c515","3c515, Fast EtherLink ISA");

View File

@ -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:

View File

@ -792,3 +792,4 @@ static struct isa_driver depca_driver __isa_driver = {
.probe = depca_probe,
.ioaddrs = 0,
};
ISA_ROM("depca","Digital DE100 and DE200");

View File

@ -623,3 +623,4 @@ static struct isa_driver eepro_driver __isa_driver = {
.probe = eepro_probe,
.ioaddrs = 0,
};
ISA_ROM("eepro","Intel Etherexpress Pro/10");

View File

@ -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[] =

View File

@ -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:
*/

View File

@ -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 = {

View File

@ -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");

View File

@ -542,3 +542,4 @@ static struct isa_driver smc9000_driver __isa_driver = {
.probe = smc9000_probe,
.ioaddrs = 0,
};
ISA_ROM("smc9000","SMC9000");

View File

@ -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 (<INFILE>) {
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 (<INFILE>) {
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 ( <FAM> ) {
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 <<EOF;
# This is an automatically generated file, do not edit
# It does not affect anything in the build, it's only for rom-o-matic
EOF
foreach my $family (@families) {
print N "family\t$family\n";
if (exists($pcient{$family})) {
my $aref = $pcient{$family};
foreach my $entry (@$aref) {
my $rom = $entry->[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 <<EOF;
\$(BIN)/$obj.o: $pci.c \$(MAKEDEPS) $deps
\$(CC) \$(CFLAGS) \$(\U$macro\EFLAGS) -o \$@ -c \$<
\$(BIN)/$obj--%.o: \$(BIN)/%.o \$(BIN)/$obj.o \$(MAKEDEPS)
\$(LD) -r \$(BIN)/$obj.o \$< -o \$@
EOF
}
# Do the ISA entries
foreach my $isa (sort keys %isalist) {
(my $macro = $isa) =~ tr/\-/_/;
my $base = $isalist{$isa};
my $deps = $drivers{$base};
print <<EOF;
\$(BIN)/$isa.o: $base.c \$(MAKEDEPS) $deps
\$(CC) \$(CFLAGS) \$(\U$macro\EFLAGS) -o \$@ -c \$<
\$(BIN)/$isa--%.o: \$(BIN)/%.o \$(BIN)/$isa.o \$(MAKEDEPS)
\$(LD) -r \$(BIN)/$isa.o \$< -o \$@
EOF
}
# Generate the Rom rules
print "# Rules to build the ROM files\n";
foreach my $family (sort keys %pcient) {
next if isaonly($family);
my $img = basename($family);
print <<EOF;
ROMTYPE_$img = PCI
EOF
my $aref = $pcient{$family};
foreach my $entry (@$aref) {
my ($rom, $ids, $comment) = @$entry;
next if ($ids eq '-');
print <<EOF;
ROMTYPE_$rom = PCI
MAKEROM_ID_$rom = -p $ids
EOF
next if($rom eq $img);
print <<EOF;
\$(BIN)/$rom\%rom: \$(BIN)/$img\%rom
cat \$< > \$@
\$(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 <<EOF;
EOF
}

View File

@ -32,7 +32,7 @@ typedef struct boot_infos
/* Some infos about the current MacOS display */
u32 dispDeviceRect[4]; /* left,top,right,bottom */
u32 dispDeviceDepth; /* (8, 16 or 32) */
u8* dispDeviceBase; /* base address (physical) */
u32 dispDeviceBase; /* base address (physical) */
u32 dispDeviceRowBytes; /* rowbytes (in bytes) */
u32 dispDeviceColorsOffset; /* Colormap (8 bits only) or 0 (*) */
@ -56,21 +56,7 @@ typedef struct boot_infos
* Benjamin Herrenschmidt <benh@kernel.crashing.org>
*/
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 */

41
src/include/compiler.h Normal file
View File

@ -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 */

28
src/include/console.h Normal file
View File

@ -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 */

View File

@ -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);

58
src/include/init.h Normal file
View File

@ -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 */

6
src/include/main.h Normal file
View File

@ -0,0 +1,6 @@
#ifndef MAIN_H
#define MAIN_H
extern int main ( void );
#endif /* MAIN_H */

View File

@ -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.

13
src/include/stddef.h Normal file
View File

@ -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 */

View File

@ -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);

63
src/util/parserom.pl Normal file
View File

@ -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 ( <DRV> ) {
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;

View File

@ -1,8 +0,0 @@
#!/usr/bin/perl -w
use bytes;
local $/;
$_ = <>;
print length($_);
exit;