mirror of https://github.com/ipxe/ipxe.git
Merged mcb30-realmode-redesign back to HEAD
parent
de5d935135
commit
0ff80b477d
|
@ -1,2 +1,3 @@
|
|||
bin
|
||||
gcccheck
|
||||
.toolcheck
|
||||
TAGS*
|
||||
bin*
|
||||
|
|
151
src/Config
151
src/Config
|
@ -424,27 +424,134 @@ CFLAGS+= -DPXE_IMAGE -DPXE_EXPORT
|
|||
# but this is here for archs that don't support relocation
|
||||
# CFLAGS+= -DNORELOCATE
|
||||
|
||||
# you should normally not need to change these
|
||||
HOST_CC= gcc
|
||||
CPP= gcc -E -Wp,-Wall
|
||||
RM= rm -f
|
||||
TOUCH= touch
|
||||
PERL= /usr/bin/perl
|
||||
CC= gcc
|
||||
AS= as
|
||||
LD= ld
|
||||
SIZE= size
|
||||
AR= ar
|
||||
RANLIB= ranlib
|
||||
OBJCOPY= objcopy
|
||||
|
||||
CFLAGS+= -Os -ffreestanding
|
||||
CFLAGS+= -Wall -W -Wno-format
|
||||
CFLAGS+= $(EXTRA_CFLAGS)
|
||||
ASFLAGS+= $(EXTRA_ASFLAGS)
|
||||
LDFLAGS+= $(EXTRA_LDFLAGS)
|
||||
# For debugging
|
||||
# LDFLAGS+= -Map $@.map
|
||||
|
||||
# Location to place generated binaries, and files
|
||||
BIN=bin
|
||||
|
||||
# Garbage from Makefile.main temporarily placed here until a home can
|
||||
# be found for it.
|
||||
|
||||
# NS8390 options:
|
||||
# -DINCLUDE_NE - Include NE1000/NE2000 support
|
||||
# -DNE_SCAN=list - Probe for NE base address using list of
|
||||
# comma separated hex addresses
|
||||
# -DINCLUDE_3C503 - Include 3c503 support
|
||||
# -DT503_SHMEM - Use 3c503 shared memory mode (off by default)
|
||||
# -DINCLUDE_WD - Include Western Digital/SMC support
|
||||
# -DWD_DEFAULT_MEM- Default memory location for WD/SMC cards
|
||||
# -DWD_790_PIO - Read/write to WD/SMC 790 cards in PIO mode (default
|
||||
# is to use shared memory) Try this if you get "Bogus
|
||||
# packet, ignoring" messages, common on ISA/PCI hybrid
|
||||
# systems.
|
||||
# -DCOMPEX_RL2000_FIX
|
||||
#
|
||||
# If you have a Compex RL2000 PCI 32-bit (11F6:1401),
|
||||
# and the bootrom hangs in "Probing...[NE*000/PCI]",
|
||||
# try enabling this fix... it worked for me :).
|
||||
# In the first packet write somehow it somehow doesn't
|
||||
# get back the expected data so it is stuck in a loop.
|
||||
# I didn't bother to investigate what or why because it works
|
||||
# when I interrupt the loop if it takes more then COMPEX_RL2000_TRIES.
|
||||
# The code will notify if it does a abort.
|
||||
# SomniOne - somnione@gmx.net
|
||||
#
|
||||
# 3C509 option:
|
||||
# -DINCLUDE_3C509 - Include 3c509 support
|
||||
#
|
||||
# 3C90X options:
|
||||
# -DINCLUDE_3C90X - Include 3c90x support
|
||||
#
|
||||
# Warning Warning Warning
|
||||
# If you use any of the XCVR options below, please do not complain about
|
||||
# the behaviour with Linux drivers to the kernel developers. You are
|
||||
# on your own if you do this. Please read 3c90x.txt to understand
|
||||
# what they do. If you don't understand them, ask for help on the
|
||||
# Etherboot mailing list. And please document what you did to the NIC
|
||||
# on the NIC so that people after you won't get nasty surprises.
|
||||
#
|
||||
# -DCFG_3C90X_PRESERVE_XCVR - Reset the transceiver type to the value it
|
||||
# had initially just before the loaded code is started.
|
||||
# -DCFG_3C90X_XCVR - Hardcode the tranceiver type Etherboot uses.
|
||||
# -DCFG_3C90X_BOOTROM_FIX - If you have a 3c905B with buggy ROM
|
||||
# interface, setting this option might "fix" it. Use
|
||||
# with caution and read the docs in 3c90x.txt!
|
||||
#
|
||||
# See the documentation file 3c90x.txt for more details.
|
||||
#
|
||||
# CS89X0 (optional) options:
|
||||
# -DINCLUDE_CS89X0- Include CS89x0 support
|
||||
# -DCS_SCAN=list - Probe for CS89x0 base address using list of
|
||||
# comma separated hex addresses; increasing the
|
||||
# address by one (0x300 -> 0x301) will force a
|
||||
# more aggressive probing algorithm. This might
|
||||
# be neccessary after a soft-reset of the NIC.
|
||||
#
|
||||
# LANCE options:
|
||||
# -DINCLUDE_NE2100- Include NE2100 support
|
||||
# -DINCLUDE_NI6510- Include NI6510 support
|
||||
#
|
||||
# SK_G16 options:
|
||||
# -DINCLUDE_SK_G16- Include SK_G16 support
|
||||
#
|
||||
# I82586 options:
|
||||
# -DINCLUDE_3C507 - Include 3c507 support
|
||||
# -DINCLUDE_NI5210- Include NI5210 support
|
||||
# -DINCLUDE_EXOS205-Include EXOS205 support
|
||||
#
|
||||
# SMC9000 options:
|
||||
# -DINCLUDE_SMC9000 - Include SMC9000 driver
|
||||
# -DSMC9000_SCAN=list - List of I/O addresses to probe
|
||||
#
|
||||
# TIARA (Fujitsu Etherstar) options:
|
||||
# -DINCLUDE_TIARA - Include Tiara support
|
||||
#
|
||||
# NI5010 options:
|
||||
# -DINCLUDE_NI5010 - Include NI5010 support
|
||||
#
|
||||
# TULIP options:
|
||||
# -DINCLUDE_TULIP - Include Tulip support
|
||||
#
|
||||
# RTL8139 options:
|
||||
# -DINCLUDE_RTL8139 - Include RTL8139 support
|
||||
#
|
||||
# SIS900 options:
|
||||
# -DINCLUDE_SIS900 - Include SIS900 support
|
||||
#
|
||||
# NATSEMI options:
|
||||
# -DINCLUDE_NATSEMI - Include NATSEMI support
|
||||
#
|
||||
|
||||
CFLAGS_3c503 = -DINCLUDE_3C503 # -DT503_SHMEM
|
||||
MAKEROM_FLAGS_3c503= -3
|
||||
CFLAGS_3c507 = -DINCLUDE_3C507
|
||||
CFLAGS_3c509 = -DINCLUDE_3C509
|
||||
CFLAGS_3c529 = -DINCLUDE_3C529
|
||||
CFLAGS_3c595 = -DINCLUDE_3C595
|
||||
CFLAGS_3c90x = -DINCLUDE_3C90X
|
||||
CFLAGS_cs89x0 = -DINCLUDE_CS89X0
|
||||
CFLAGS_eepro = -DINCLUDE_EEPRO
|
||||
CFLAGS_eepro100 = -DINCLUDE_EEPRO100
|
||||
CFLAGS_e1000 = -DINCLUDE_E1000
|
||||
CFLAGS_epic100 = -DINCLUDE_EPIC100
|
||||
CFLAGS_exos205 = -DINCLUDE_EXOS205
|
||||
CFLAGS_lance = -DINCLUDE_LANCE # Lance/PCI!
|
||||
CFLAGS_ne2100 = -DINCLUDE_NE2100
|
||||
CFLAGS_ne = -DINCLUDE_NE -DNE_SCAN=0x300,0x280,0x320,0x340,0x380
|
||||
CFLAGS_ns8390 = -DINCLUDE_NS8390 # NE2000/PCI!
|
||||
CFLAGS_ni5010 = -DINCLUDE_NI5010
|
||||
CFLAGS_ni5210 = -DINCLUDE_NI5210
|
||||
CFLAGS_ni6510 = -DINCLUDE_NI6510
|
||||
CFLAGS_rtl8139 = -DINCLUDE_RTL8139
|
||||
CFLAGS_sk_g16 = -DINCLUDE_SK_G16
|
||||
CFLAGS_sis900 = -DINCLUDE_SIS900
|
||||
CFLAGS_natsemi = -DINCLUDE_NATSEMI
|
||||
CFLAGS_smc9000 = -DINCLUDE_SMC9000
|
||||
CFLAGS_sundance = -DINCLUDE_SUNDANCE
|
||||
CFLAGS_tlan = -DINCLUDE_TLAN
|
||||
CFLAGS_tiara = -DINCLUDE_TIARA
|
||||
CFLAGS_depca = -DINCLUDE_DEPCA
|
||||
# CFLAGS_depca += -DDEPCA_MODEL=DEPCA -DDEPCA_RAM_BASE=0xd0000
|
||||
CFLAGS_tulip = -DINCLUDE_TULIP
|
||||
CFLAGS_otulip = -DINCLUDE_OTULIP
|
||||
CFLAGS_via_rhine = -DINCLUDE_VIA_RHINE
|
||||
CFLAGS_wd = -DINCLUDE_WD -DWD_DEFAULT_MEM=0xCC000
|
||||
CFLAGS_w89c840 = -DINCLUDE_W89C840
|
||||
|
|
133
src/Families
133
src/Families
|
@ -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
|
154
src/Makefile
154
src/Makefile
|
@ -1,15 +1,145 @@
|
|||
# Override ARCH here or on the command line
|
||||
# ARCH=i386
|
||||
# Additionally you can supply extra compilation arguments, e.g. for x86_64
|
||||
# EXTRA_CFLAGS=-m32
|
||||
# EXTRA_ASFLAGS=--32
|
||||
# EXTRA_LDFLAGS=-m elf_i386
|
||||
ifndef ARCH
|
||||
ARCH:=$(shell uname -m | sed -e s,i[3456789]86,i386,)
|
||||
endif
|
||||
MAKEDEPS:=
|
||||
SUFFIXES:=
|
||||
# Initialise variables that get added to throughout the various Makefiles
|
||||
#
|
||||
MAKEDEPS := Makefile .toolcheck
|
||||
SRCDIRS :=
|
||||
SRCS :=
|
||||
NON_AUTO_SRCS :=
|
||||
DRIVERS :=
|
||||
ROMS :=
|
||||
MEDIA :=
|
||||
NON_AUTO_MEDIA :=
|
||||
|
||||
# Grab the central Config file.
|
||||
#
|
||||
MAKEDEPS += Config
|
||||
include Config
|
||||
|
||||
# If no architecture is specified in Config or on the command-line,
|
||||
# use that of the build machine.
|
||||
#
|
||||
ifndef ARCH
|
||||
ARCH := $(shell uname -m | sed -e s,i[3456789]86,i386,)
|
||||
endif
|
||||
|
||||
# Drag in architecture-specific Config
|
||||
#
|
||||
MAKEDEPS += arch/$(ARCH)/Config
|
||||
include arch/$(ARCH)/Config
|
||||
include Makefile.main
|
||||
|
||||
# If invoked with no build target, print out a helpfully suggestive
|
||||
# message.
|
||||
#
|
||||
noargs : blib
|
||||
@echo '===================================================='
|
||||
@echo 'No target specified. To specify a target, do: '
|
||||
@echo
|
||||
@echo ' $(MAKE) bin/<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
|
||||
|
|
|
@ -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
|
|
@ -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
|
|
@ -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
|
|
@ -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
|
|
@ -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)
|
|
@ -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)
|
|
@ -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 );
|
||||
|
|
|
@ -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 );
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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().
|
|
@ -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
|
||||
|
|
|
@ -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 */
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
#include "etherboot.h"
|
||||
#include "elf.h"
|
||||
#include "memsizes.h"
|
||||
|
||||
|
||||
#define NAME "Etherboot"
|
||||
|
|
|
@ -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 ( ®s_copy );
|
||||
}
|
||||
}
|
||||
|
||||
#else /* REALMODE */
|
||||
|
||||
/*
|
||||
* arch_main() : call main() and return
|
||||
*
|
||||
*/
|
||||
void arch_main ( struct i386_all_regs *regs ) {
|
||||
regs->eax = main();
|
||||
|
||||
/* Call registered per-object exit functions */
|
||||
call_exit_fns ();
|
||||
};
|
||||
|
||||
#endif /* REALMODE */
|
||||
|
|
|
@ -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 );
|
||||
|
|
|
@ -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 */
|
|
@ -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 */
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
|
@ -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:
|
|
@ -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:
|
|
@ -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
|
||||
|
|
|
@ -1,5 +1,4 @@
|
|||
#include "realmode.h"
|
||||
#include "segoff.h"
|
||||
|
||||
struct segheader
|
||||
{
|
||||
|
|
|
@ -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 );
|
||||
|
|
|
@ -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
|
|
@ -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 = {
|
||||
|
|
|
@ -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 */
|
||||
|
|
|
@ -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,
|
||||
};
|
|
@ -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 */
|
|
@ -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 */
|
||||
}
|
|
@ -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 );
|
||||
|
|
|
@ -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 */
|
|
@ -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 */
|
|
@ -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 );
|
||||
|
|
|
@ -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 */
|
||||
|
|
|
@ -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.
|
||||
|
|
|
@ -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 */
|
|
@ -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 */
|
|
@ -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 */
|
|
@ -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 */
|
|
@ -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 */
|
||||
|
|
|
@ -5,7 +5,6 @@
|
|||
#define PXE_CALLBACKS_H
|
||||
|
||||
#include "etherboot.h"
|
||||
#include "segoff.h"
|
||||
#include "pxe.h"
|
||||
|
||||
typedef struct {
|
||||
|
|
|
@ -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
|
||||
|
||||
|
|
|
@ -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 */
|
||||
|
|
|
@ -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 */
|
|
@ -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 */
|
|
@ -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 */
|
|
@ -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
|
|
@ -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 */
|
|
@ -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 */
|
||||
}
|
|
@ -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
|
||||
|
|
|
@ -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;
|
||||
}
|
|
@ -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
|
|
@ -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
|
|
@ -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 */
|
|
@ -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 );
|
||||
|
|
|
@ -0,0 +1 @@
|
|||
*
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
||||
|
|
|
@ -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;
|
||||
}
|
|
@ -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 );
|
||||
|
|
|
@ -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 ();
|
||||
}
|
||||
}
|
137
src/core/main.c
137
src/core/main.c
|
@ -23,12 +23,10 @@ Literature dealing with the network protocols:
|
|||
#include "http.h"
|
||||
#include "timer.h"
|
||||
#include "cpu.h"
|
||||
#include "console.h"
|
||||
#include "init.h"
|
||||
#include <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;
|
||||
}
|
||||
|
||||
|
|
143
src/core/misc.c
143
src/core/misc.c
|
@ -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
|
||||
|
||||
|
|
|
@ -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 */
|
||||
|
|
|
@ -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,
|
||||
};
|
||||
|
|
|
@ -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 );
|
||||
|
|
|
@ -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 );
|
||||
|
|
|
@ -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 ) */
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -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 );
|
||||
|
||||
|
|
|
@ -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" },
|
||||
|
|
|
@ -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
|
||||
|
||||
/*
|
||||
|
|
|
@ -812,3 +812,4 @@ static struct isa_driver t515_driver __isa_driver = {
|
|||
.probe = t515_probe,
|
||||
.ioaddrs = 0,
|
||||
};
|
||||
ISA_ROM("3c515","3c515, Fast EtherLink ISA");
|
||||
|
|
|
@ -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:
|
||||
|
|
|
@ -792,3 +792,4 @@ static struct isa_driver depca_driver __isa_driver = {
|
|||
.probe = depca_probe,
|
||||
.ioaddrs = 0,
|
||||
};
|
||||
ISA_ROM("depca","Digital DE100 and DE200");
|
||||
|
|
|
@ -623,3 +623,4 @@ static struct isa_driver eepro_driver __isa_driver = {
|
|||
.probe = eepro_probe,
|
||||
.ioaddrs = 0,
|
||||
};
|
||||
ISA_ROM("eepro","Intel Etherexpress Pro/10");
|
||||
|
|
|
@ -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[] =
|
||||
|
|
|
@ -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:
|
||||
*/
|
||||
|
||||
|
|
|
@ -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 = {
|
||||
|
|
|
@ -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");
|
||||
|
|
|
@ -542,3 +542,4 @@ static struct isa_driver smc9000_driver __isa_driver = {
|
|||
.probe = smc9000_probe,
|
||||
.ioaddrs = 0,
|
||||
};
|
||||
ISA_ROM("smc9000","SMC9000");
|
||||
|
|
376
src/genrules.pl
376
src/genrules.pl
|
@ -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
|
||||
}
|
||||
|
|
@ -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 */
|
||||
|
|
|
@ -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 */
|
|
@ -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 */
|
|
@ -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);
|
||||
|
|
|
@ -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 */
|
|
@ -0,0 +1,6 @@
|
|||
#ifndef MAIN_H
|
||||
#define MAIN_H
|
||||
|
||||
extern int main ( void );
|
||||
|
||||
#endif /* MAIN_H */
|
|
@ -18,7 +18,6 @@
|
|||
#include "setjmp.h"
|
||||
#include "latch.h"
|
||||
#include "callbacks.h"
|
||||
#include "hooks.h"
|
||||
|
||||
/* within 1MB of 4GB is too close.
|
||||
* MAX_ADDR is the maximum address we can easily do DMA to.
|
||||
|
|
|
@ -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 */
|
|
@ -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);
|
||||
|
|
|
@ -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;
|
|
@ -1,8 +0,0 @@
|
|||
#!/usr/bin/perl -w
|
||||
|
||||
use bytes;
|
||||
|
||||
local $/;
|
||||
$_ = <>;
|
||||
print length($_);
|
||||
exit;
|
Loading…
Reference in New Issue