david/ipxe
david
/
ipxe
Archived
1
0
Fork 0

Initial revision

This commit is contained in:
Michael Brown 2005-03-08 18:53:11 +00:00
commit 3d6123e69a
373 changed files with 114041 additions and 0 deletions

2
src/.cvsignore Normal file
View File

@ -0,0 +1,2 @@
bin
gcccheck

450
src/Config Normal file
View File

@ -0,0 +1,450 @@
#
# Config for Etherboot/32
#
# Do not delete the tag OptionDescription and /OptionDescription
# It is used to automatically generate the documentation.
#
# @OptionDescription@
# User interaction options:
#
# -DASK_BOOT=n
# Ask "Boot from (N)etwork ... or (Q)uit? "
# at startup, timeout after n seconds (0 = no timeout).
# If unset or negative, don't ask and boot immediately
# using the default.
# -DBOOT_FIRST
# -DBOOT_SECOND
# -DBOOT_THIRD
# On timeout or Return key from previous
# question, selects the order to try to boot from
# various devices.
# (alternatives: BOOT_NIC, BOOT_DISK,
# BOOT_FLOPPY, BOOT_NOTHING)
# See etherboot.h for prompt and answer strings.
# BOOT_DISK and BOOT_FLOPPY work only where a driver
# exists, e.g. in LinuxBIOS.
# They have no effect on PCBIOS.
# -DBOOT_INDEX The device to boot from 0 == any device.
# 1 == The first nic found.
# 2 == The second nic found
# ...
# BOOT_INDEX only applies to the BOOT_FIRST. BOOT_SECOND
# and BOOT_THIRD search through all of the boot devices.
# -DBAR_PROGRESS
# Use rotating bar instead of sequential dots
# to indicate an IP packet transmitted.
#
# Boot order options:
#
# -DBOOT_CLASS_FIRST
# -DBOOT_CLASS_SECOND
# -DBOOT_CLASS_THIRD
# Select the priority of the boot classes
# Valid values are:
# BOOT_NIC
# BOOT_DISK
# BOOT_FLOPPY
# BOOT_DISK and BOOT_FLOPPY work only where a driver exists,
# e.g. in LinuxBIOS. They have no effect on PCBIOS.
#
# Boot autoconfiguration protocol options:
#
# -DALTERNATE_DHCP_PORTS_1067_1068
# Use ports 1067 and 1068 for DHCP instead of 67 and 68.
# As these ports are non-standard, you need to configure
# your DHCP server to use them. This option gets around
# existing DHCP servers which cannot be touched, for
# one reason or another, at the cost of non-standard
# boot images.
# -DNO_DHCP_SUPPORT
# Use BOOTP instead of DHCP.
# -DRARP_NOT_BOOTP
# Use RARP instead of BOOTP/DHCP.
# -DREQUIRE_VCI_ETHERBOOT
# Require an encapsulated Vendor Class Identifier
# of "Etherboot" in the DHCP reply
# Requires DHCP support.
# -DDHCP_CLIENT_ID=\"Identifier\"
# -DDHCP_CLIENT_ID_LEN=<Client ID length in octets>
# -DDHCP_CLIENT_ID_TYPE=<Client ID type>
# Specify a RFC2132 Client Identifier option, length and type.
# Requires DHCP support.
# -DDHCP_USER_CLASS=\"UserClass\"
# -DDHCP_USER_CLASS_LEN=<User Class length in octets>
# Specify a RFC3004 User Class option and length. Use this
# option to set a UC (or multiple UCs) rather than munge the
# client Vendor Class ID.
# Requires DHCP support.
# -DALLOW_ONLY_ENCAPSULATED
# Ignore Etherboot-specific options that are not within
# the Etherboot encapsulated options field. This option
# should be enabled unless you have a legacy DHCP server
# configuration from the bad old days before the use of
# encapsulated Etherboot options.
# -DDEFAULT_BOOTFILE=\"default_bootfile_name\"
# Define a default bootfile for the case where your DHCP
# server does not provide the information. Example:
# -DDEFAULT_BOOTFILE="tftp:///tftpboot/kernel"
# If you do not specify this option, then DHCP offers that
# do not specify bootfiles will be ignored.
#
# NIC tuning parameters:
#
# -DALLMULTI
# Turns on multicast reception in the NICs.
#
# Boot tuning parameters:
#
# -DCONGESTED
# Turns on packet retransmission. Use it on a
# congested network, where the normal operation
# can't boot the image.
# -DBACKOFF_LIMIT
# Sets the maximum RFC951 backoff exponent to n.
# Do not set this unreasonably low, because on networks
# with many machines they can saturate the link
# (the delay corresponding to the exponent is a random
# time in the range 0..3.5*2^n seconds). Use 5 for a
# VERY small network (max. 2 minutes delay), 7 for a
# medium sized network (max. 7.5 minutes delay) or 10
# for a really huge network with many clients, frequent
# congestions (max. 1 hour delay). On average the
# delay time will be half the maximum value. If in
# doubt about the consequences, use a larger value.
# Also keep in mind that the number of retransmissions
# is not changed by this setting, so the default of 20
# may no longer be appropriate. You might need to set
# MAX_ARP_RETRIES, MAX_BOOTP_RETRIES, MAX_TFTP_RETRIES
# and MAX_RPC_RETRIES to a larger value.
# -DTIMEOUT=n
# Use with care!! See above.
# Sets the base of RFC2131 sleep interval to n.
# This can be used with -DBACKOFF_LIMIT=0 to get a small
# and constant (predictable) retry interval for embedded
# devices. This is to achieve short boot delays if both
# the DHCP Server and the embedded device will be powered
# on the same time. Otherwise if the DHCP server is ready
# the client could sleep the next exponentially timeout,
# e.g. 70 seconds or more. This is not what you want.
# n should be a multiple of TICKS_PER_SEC (18).
#
# Boot device options:
#
# -DTRY_FLOPPY_FIRST
# If > 0, tries that many times to read the boot
# sector from a floppy drive before booting from
# ROM. If successful, does a local boot.
# It assumes the floppy is bootable.
# -DEXIT_IF_NO_OFFER
# If no IP offer is obtained, exit and
# let the BIOS continue.
# The accessibility of the TFTP server has no effect,
# so configure your DHCP/BOOTP server properly.
# You should probably reduce MAX_BOOTP_RETRIES
# to a small number like 3.
#
# Boot image options:
#
# -DTAGGED_IMAGE
# Add tagged image kernel boot support (recommended).
# -DAOUT_IMAGE
# Add a.out kernel boot support (generic).
# -DELF_IMAGE
# Add generic ELF kernel boot support (recommended).
# -DEL64F_IMAGE
# Add generic ELF64 kernel boot support (useful for > 4GB disks).
# -DWINCE_IMAGE
# Add the ability to boot WINCE.... now only sis630 OK!
# -DPXE_IMAGE
# Add the ability to boot PXE NBPs. Requires
# PXE_EXPORT. Currently not supported on
# anything other than i386
# -DFREEBSD_PXEEMU
# Add the ability to boot PXE images... only FreeBSD supported
# -DIMAGE_MULTIBOOT
# Add Multiboot image support (currently only
# for ELF images).
# Without this, generic ELF support is selected.
# -DIMAGE_FREEBSD
# Add FreeBSD image loading support (requires at least
# -DAOUT_IMAGE and/or -DELF_IMAGE).
# -DFREEBSD_KERNEL_ENV
# Pass in FreeBSD kernel environment
# -DAOUT_LYNX_KDI
# Add Lynx a.out KDI support
# -DMULTICAST_LEVEL1
# Support for sending multicast packets
# -DMULTICAST_LEVEL2
# Support for receiving multicast packets
# -DDNS_RESOLVER
# Support for resolving hostnames in bootfile name (experimental)
# -DDOWNLOAD_PROTO_TFTP
# If defined, includes TFTP support (recommended).
# -DDOWNLOAD_PROTO_NFS
# If defined, includes NFS support.
# -DDEFAULT_PROTO_NFS
# If defined, makes NFS the default protocol instead
# of TFTP. Requires DOWNLOAD_PROTO_NFS.
# -DDOWNLOAD_PROTO_SLAM
# If defined, includes Scalable Local Area Multicast
# support.
# -DDOWNLOAD_PROTO_TFTM
# If defined, includes TFTP Multicast mode support.
# -DDOWNLOAD_PROTO_HTTP
# If defined, includes HTTP support.
#
# Console options:
#
# -DCONSOLE_FIRMWARE
# Set for firmware/BIOS provided (default if nothing else is set).
# Normally this is shows up on your CRT.
# -DCONSOLE_SERIAL
# Set for serial console.
# -DCONSOLE_DUAL
# Both of the above
# -DCONSOLE_DIRECT_VGA
# Set for direct VGA console (only for x86).
# -DCOMCONSOLE
# Set port, e.g. 0x3F8.
# -DCONSPEED
# Set speed, e.g. 57600.
# -DCOMPARM
# Set Line Control Register value for data bits, stop
# bits and parity. See a National Semiconditor 8250/
# 16450/16550 data sheet for bit meanings.
# If undefined, defaults to 0x03 = 8N1.
# -DCOMPRESERVE
# Ignore COMSPEED and COMPARAM and instead preserve
# the com port parameters from the previous user
# of the com port. Examples of previous user are a BIOS
# that implements console redirection, lilo and LinuxBIOS.
# This makes it trivial to keep the serial port
# speed setting in sync between multiple users.
# You set the speed in the first user and the
# rest follow along.
#
# Interface export options:
#
# -DPXE_EXPORT
# Export a PXE API interface. This is work in
# progress. Note that you won't be able to load
# PXE NBPs unless you also use -DPXE_IMAGE.
# -DPXE_STRICT
# Strict(er) compliance with the PXE
# specification as published by Intel. This may
# or may not be a good thing depending on your
# view of the spec...
# -DPXE_DHCP_STRICT
# Strict compliance of the DHCP request packets
# with the PXE specification as published by
# Intel. This may or may not be a good thing
# depending on your view of whether requesting
# vendor options which don't actually exist is
# pointless or not. You probably want this
# option if you intend to use Windows RIS or
# similar.
#
# Obscure options you probably don't need to touch:
#
# -DPOWERSAVE
# Halt the processor when waiting for keyboard input
# which saves power while waiting for user interaction.
# Good for compute clusters and VMware emulation.
# But may not work for all CPUs.
# -DBUILD_SERIAL
# Include an auto-incrementing build number in
# the Etherboot welcome message. Useful when
# developing, to be sure that the file you
# compiled is the one you're currently testing.
# -DBUILD_ID
# Include a build ID string in the Etherboot
# welcome message. Useful when developing, if
# you have multiple builds with different
# configurations and want to check you're
# running the one you think you are. Requires
# -DBUILD_SERIAL.
#
# BUS options:
#
# -DCONFIG_PCI
# Include support for devices using the pci bus.
# -DCONFIG_ISA
# Include support for devices using isa bus.
# -DCONFIG_PCMCIA
# Include support for PCMCIA in general *development*
# @/OptionDescription@
# These default settings compile Etherboot with a small number of options.
# You may wish to enable more of the features if the size of your ROM allows.
# Select which buses etherboot should support
CFLAGS+= -DCONFIG_PCI -DCONFIG_ISA
# CFLAGS+= -DCONFIG_PCMCIA
# For prompting and default on timeout
CFLAGS+= -DASK_BOOT=3 -DBOOT_FIRST=BOOT_NIC
# If you would like to attempt to boot from other devices as well as the network.
# CFLAGS+= -DBOOT_SECOND=BOOT_FLOPPY
# CFLAGS+= -DBOOT_THIRD=BOOT_DISK
# CFLAGS+= -DBOOT_INDEX=0
# If you prefer the old style rotating bar progress display
# CFLAGS+= -DBAR_PROGRESS
# Show size indicator
# CFLAGS+= -DSIZEINDICATOR
# Enabling this creates non-standard images which use ports 1067 and 1068
# for DHCP/BOOTP
# CFLAGS+= -DALTERNATE_DHCP_PORTS_1067_1068
# Enabling this makes the boot ROM require a Vendor Class Identifier
# of "Etherboot" in the Vendor Encapsulated Options
# This can be used to reject replies from servers other than the one
# we want to give out addresses to us, but it will prevent Etherboot
# from getting an IP lease until you have configured DHCPD correctly
# CFLAGS+= -DREQUIRE_VCI_ETHERBOOT
# EXPERIMENTAL! Set DHCP_CLIENT_ID to create a Client Identifier (DHCP
# option 61, see RFC2132 section 9.14) when Etherboot sends the DHCP
# DISCOVER and REQUEST packets. This ID must UNIQUELY identify each
# client on your local network. Set DHCP_CLIENT_ID_TYPE to the
# appropriate hardware type as described in RFC2132 / RFC1700; this
# almost certainly means using '1' if the Client ID is an Ethernet MAC
# address and '0' otherwise. Set DHCP_CLIENT_ID_LEN to the length of
# the Client ID in octets (this is not a null terminated C string, do
# NOT add 1 for a terminator and do NOT add an extra 1 for the
# hardware type octet). Note that to identify your client using the
# normal default MAC address of your NIC, you do NOT need to set this
# option, as the MAC address is automatically used in the
# hwtype/chaddr field; note also that this field only sets the DHCP
# option: it does NOT change the MAC address used by the client.
# CFLAGS+= -DDHCP_CLIENT_ID="'C','L','I','E','N','T','0','0','1'" \
# -DDHCP_CLIENT_ID_LEN=9 -DDHCP_CLIENT_ID_TYPE=0
# CFLAGS+= -DDHCP_CLIENT_ID="0xDE,0xAD,0xBE,0xEF,0xDE,0xAD" \
# -DDHCP_CLIENT_ID_LEN=6 -DDHCP_CLIENT_ID_TYPE=1
# EXPERIMENTAL! Set DHCP_USER_CLASS to create a User Class option (see
# RFC3004) when Etherboot sends the DHCP DISCOVER and REQUEST packets.
# This can be used for classification of clients, typically so that a
# DHCP server can send an appropriately tailored reply. Normally, a
# string identifies a class of to which this client instance belongs
# which is useful in your network, such as a department ('FINANCE' or
# 'MARKETING') or hardware type ('THINCLIENT' or 'KIOSK'). Set
# DHCP_USER_CLASS_LEN to the length of DHCP_USER_CLASS in octets.
# This is NOT a null terminated C string, do NOT add 1 for a
# terminator. RFC3004 advises how to lay out multiple User Class
# options by using an octet for the length of each string, as in this
# example. It is, of course, up to the server to parse this.
# CFLAGS+= -DDHCP_USER_CLASS="'T','E','S','T','C','L','A','S','S'" \
# -DDHCP_USER_CLASS_LEN=9
# CFLAGS+= -DDHCP_USER_CLASS="5,'A','L','P','H','A',4,'B','E','T','A'" \
# -DDHCP_USER_CLASS_LEN=11
# for btext console support
# CFLAGS+= -DCONSOLE_BTEXT
# for direct PC kbd support
# CFLAGS+= -DCONSOLE_PC_KBD
# Set to enable FILO support
# for FILO support it will make main call pci_init
# INCLUDE_FILO=y
ifdef INCLUDE_FILO
CFLAGS+= -DCONFIG_FILO
endif
# Enabling this causes Etherboot to ignore Etherboot-specific options
# that are not within an Etherboot encapsulated options field.
# This option should be enabled unless you have a legacy DHCP server
# configuration from the bad old days before the use of
# encapsulated Etherboot options.
CFLAGS+= -DALLOW_ONLY_ENCAPSULATED
# Disable DHCP support
# CFLAGS+= -DNO_DHCP_SUPPORT
# Specify a default bootfile to be used if the DHCP server does not
# provide the information. If you do not specify this option, then
# DHCP offers that do not contain bootfiles will be ignored.
# CFLAGS+= -DDEFAULT_BOOTFILE=\"tftp:///tftpboot/kernel\"
# Limit the delay on packet loss/congestion to a more bearable value. See
# description above. If unset, do not limit the delay between resend.
CFLAGS+= -DBACKOFF_LIMIT=7 -DCONGESTED
# More optional features
# CFLAGS+= -DTRY_FLOPPY_FIRST=4
# CFLAGS+= -DEXIT_IF_NO_OFFER
# For a serial console, which can run in parallel with FIRMWARE console
# CFLAGS+= -DCONSOLE_DUAL -DCOMCONSOLE=0x3F8 -DCONSPEED=9600
# Enable tagged image, generic ELF, Multiboot ELF
# or FreeBSD ELF/a.out boot image support
CFLAGS+= -DTAGGED_IMAGE -DELF_IMAGE
# CFLAGS+= -DAOUT_IMAGE -DIMAGE_MULTIBOOT -DIMAGE_FREEBSD
# CFLAGS+= -DAOUT_IMAGE -DAOUT_LYNX_KDI
# CFLAGS+= -DCOFF_IMAGE
# CFLAGS+= -DRAW_IMAGE
# Download files via TFTP
CFLAGS+= -DDOWNLOAD_PROTO_TFTP
# Change download protocol to NFS, default is TFTP
# CFLAGS+= -DDOWNLOAD_PROTO_NFS
# Change download protocol to HTTP, default is TFTP
# CFLAGS+= -DDOWNLOAD_PROTO_HTTP
# Change default protocol to NFS
# CFLAGS+= -DDEFAULT_PROTO_NFS
# Support to resolve hostnames in boot filename
# CFLAGS+= -DDNS_RESOLVER
# Multicast Support
# CFLAGS+= -DALLMULTI -DMULTICAST_LEVEL1 -DMULTICAST_LEVEL2 -DDOWNLOAD_PROTO_TFTM
# Etherboot as a PXE network protocol ROM
CFLAGS+= -DPXE_IMAGE -DPXE_EXPORT
# Etherboot stricter as a PXE network protocol ROM
# CFLAGS+= -DPXE_DHCP_STRICT
# Support for PXE emulation. Works only with FreeBSD to load the kernel
# via pxeboot, use only with DOWNLOAD_PROTO_NFS
# CFLAGS+= -DFREEBSD_PXEEMU
# Include an auto-incrementing build serial number and optional build
# ID string
# CFLAGS+= -DBUILD_SERIAL
# CFLAGS+= -DBUILD_SERIAL -DBUILD_ID=\"testing\"
# Do not relocate
# core/relocate.c should really be moved to an arch specific directory
# 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

133
src/Families Normal file
View File

@ -0,0 +1,133 @@
# 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

15
src/Makefile Normal file
View File

@ -0,0 +1,15 @@
# 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:=
include Config
include arch/$(ARCH)/Config
include Makefile.main

18
src/Makefile-armnommu Normal file
View File

@ -0,0 +1,18 @@
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

18
src/Makefile-e1 Normal file
View File

@ -0,0 +1,18 @@
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

18
src/Makefile-i386 Normal file
View File

@ -0,0 +1,18 @@
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

18
src/Makefile-ia64 Normal file
View File

@ -0,0 +1,18 @@
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

450
src/Makefile.main Normal file
View File

@ -0,0 +1,450 @@
#
# 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:
# Utilities
$(BIN)/lzhuf: util/lzhuf.c
$(HOST_CC) -O2 -DENCODE -DDECODE -DMAIN -DVERBOSE -o $@ $<
# 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)

90
src/README.pixify Normal file
View File

@ -0,0 +1,90 @@
This file documents the driver changes needed to support use as part
of a PXE stack.
PROPER WAY
==========
1. The probe() routine.
There are three additional fields that need to be filled in the nic
structure: ioaddr, irqno and irq.
ioaddr is the base I/O address and seems to be for information only;
no use will be made of this value other than displaying it on the
screen.
irqno must be the IRQ number for the NIC. For PCI NICs this can
simply be copied from pci->irq.
irq is a function pointer, like poll and transmit. It must point to
the driver's irq() function.
2. The poll() routine.
This must take an additional parameter: "int retrieve". Calling
poll() with retrieve!=0 should function exactly as before. Calling
poll() with retrieve==0 indicates that poll() should check for the
presence of a packet to read, but must *not* read the packet. The
packet will be read by a subsequent call to poll() with retrieve!=0.
The easiest way to implement this is to insert the line
if ( ! retrieve ) return 1;
between the "is there a packet ready" and the "fetch packet" parts of
the existing poll() routine.
Care must be taken that a call to poll() with retrieve==0 does not
clear the NIC's "packet ready" status indicator, otherwise the
subsequent call to poll() with retrieve!=0 will fail because it will
think that there is no packet to read.
poll() should also acknowledge and clear the NIC's "packet received"
interrupt. It does not need to worry about enabling/disabling
interrupts; this is taken care of by calls to the driver's irq()
routine.
Etherboot will forcibly regenerate an interrupt if a packet remains
pending after all interrupts have been acknowledged. You can
therefore get away with having poll() just acknolwedge and clear all
NIC interrupts, without particularly worrying about exactly when this
should be done.
3. The irq() routine.
This is a new routine, with prototype
void DRIVER_irq ( struct nic *nic, irq_action_t action );
"action" takes one of three possible values: ENABLE, DISABLE or FORCE.
ENABLE and DISABLE mean to enable/disable the NIC's "packet received"
interrupt. FORCE means that the NIC should be forced to generate a
fake "packet received" interrupt.
If you are unable to implement FORCE, your NIC will not work when
being driven via the UNDI interface under heavy network traffic
conditions. Since Etherboot's UNDI driver (make bin/undi.zpxe) is the
only program known to use this interface, it probably doesn't really
matter.
QUICK AND DIRTY WAY
===================
It is possible to use the system timer interrupt (IRQ 0) rather than a
genuine NIC interrupt. Since there is a constant stream of timer
interrupts, the net upshot is a whole load of spurious "NIC"
interrupts that have no effect other than to cause unnecessary PXE API
calls. It's inefficient but it works.
To achieve this, simply set nic->irqno=0 in probe() and point nic->irq
to a dummy routine that does nothing. Add the line
if ( ! retrieve ) return 1;
at the beginning of poll(), to prevent the packet being read (and
discarded) when poll() is called with retrieve==0;
UNCONVERTED DRIVERS
===================
Drivers that have not yet been converted should continue to function
when not used as part of a PXE stack, although there will be a
harmless compile-time warning about assignment from an incompatible
pointer type in the probe() function, since the prototype for the
poll() function is missing the "int retrieve" parameter.

23
src/arch/armnommu/Config Normal file
View File

@ -0,0 +1,23 @@
# Config for armnommu Etherboot
#
# For a clean compilation, switch in global Config
# off: -DCONFIG_PCI, -DTAGGED_IMAGE, -DELF_IMAGE, -DPXE*, -DRELOCATE and INCLUDE_FILO
# on : -DRAW_IMAGE
# Serial line settings
CFLAGS+= -DCONSOLE_SERIAL -DCONSPEED=57600
# System Frequency
CFLAGS+= -DSYSCLK=73728000
# Image Download Address
CFLAGS+= -DRAWADDR=0x40100000
# NIC Debug Outputs
#CFLAGS+= -DDEBUG_NIC
# Fixed MAC address
# p2001_eth has no flash and fixed mac address
#CFLAGS+= -DMAC_HW_ADDR_DRV="'H','Y','L','N','X','1'"
CFLAGS+= -DMAC_HW_ADDR_DRV="0x00,0x09,0x4F,0x00,0x00,0x02"

View File

@ -0,0 +1,58 @@
ARCH_FORMAT= armnommu
ROMLIMIT= 20480
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)/start.o
SRCS+= arch/armnommu/core/arm_timer.c
SRCS+= arch/armnommu/core/start.S
SRCS+= arch/armnommu/core/serial.c
SRCS+= arch/armnommu/core/mem.c
SRCS+= arch/armnommu/core/setjmp.S
SRCS+= arch/armnommu/drivers/net/p2001_eth.c
# not greater than 100kB
ROMLIMIT:=1024000
include $(BIN)/Roms
ROMS= $(BIN)/p2001_eth.rom
IMGS= $(BIN)/p2001_eth.img
allfiles: $(ROMS)
BOBJS+= $(BIN)/arm_timer.o
BOBJS+= $(BIN)/serial.o
BOBJS+= $(BIN)/mem.o
BOBJS+= $(BIN)/setjmp.o
BOBJS+= $(BIN)/lib1funcs.o
# Utilities
$(BIN)/nrv2b: util/nrv2b.c
$(HOST_CC) -O2 -DENCODE -DDECODE -DMAIN -DVERBOSE -DNDEBUG -DBITSIZE=32 -DENDIAN=0 -o $@ $<
# Pattern Rules
# General for compiling/assembly source files
$(BIN)/%.o: arch/armnommu/core/%.c $(MAKEDEPS)
$(CC) $(CFLAGS) -o $@ -c $<
$(BIN)/%.o: arch/armnommu/drivers/net/%.c $(MAKEDEPS)
$(CC) $(CFLAGS) -o $@ -c $<
$(BIN)/%.S: arch/armnommu/core/%.c $(MAKEDEPS)
$(CC) $(CFLAGS) -S -o $@ -c $<
$(BIN)/%.o: arch/armnommu/core/%.S $(MAKEDEPS)
$(CPP) $(CFLAGS) -D ASSEMBLY $< | $(AS) $(ASFLAGS) -o $@
# general ruls for generating .img files
$(BIN)/%.tmp: $(BIN)/%.o $(START) $(BIN)/config.o arch/$(ARCH)/core/etherboot.lds $(LIBS) $(STDDEPS) $(MAKEDEPS)
$(LD) $(LDFLAGS) -T arch/$(ARCH)/core/etherboot.lds -o $@ $(START) $(BIN)/config.o $< $(LIBS)
@$(SIZE) $@ | $(CHECKSIZE)
$(BIN)/%.img: $(BIN)/%.tmp $(MAKEDEPS)
$(OBJCOPY) -O binary $< $@

View File

@ -0,0 +1,77 @@
/*
* Copyright (C) 2004 Tobias Lorenz
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*/
#include "etherboot.h"
#include "timer.h"
#include "latch.h"
#include "hardware.h"
/* get timer returns the contents of the timer */
static unsigned long get_timer(void)
{
return P2001_TIMER->Freerun_Timer;
}
/* ------ Calibrate the TSC -------
* Time how long it takes to excute a loop that runs in known time.
* And find the convertion needed to get to CLOCK_TICK_RATE
*/
static unsigned long configure_timer(void)
{
return (1);
}
static unsigned long clocks_per_tick = 1;
void setup_timers(void)
{
if (!clocks_per_tick) {
clocks_per_tick = configure_timer();
}
}
unsigned long currticks(void)
{
return get_timer(); /* /clocks_per_tick */
}
static unsigned long timer_timeout;
static int __timer_running(void)
{
return get_timer() < timer_timeout;
}
void udelay(unsigned int usecs)
{
unsigned long now;
now = get_timer();
timer_timeout = now + usecs * ((clocks_per_tick * TICKS_PER_SEC)/(1000*1000));
while(__timer_running());
}
void ndelay(unsigned int nsecs)
{
unsigned long now;
now = get_timer();
timer_timeout = now + nsecs * ((clocks_per_tick * TICKS_PER_SEC)/(1000*1000*1000));
while(__timer_running());
}
void load_timer2(unsigned int timer2_ticks)
{
unsigned long now;
unsigned long clocks;
now = get_timer();
clocks = timer2_ticks * ((clocks_per_tick * TICKS_PER_SEC)/CLOCK_TICK_RATE);
timer_timeout = now + clocks;
}
int timer2_running(void)
{
return __timer_running();
}

View File

@ -0,0 +1,55 @@
/*
* Copyright (C) 2004 Tobias Lorenz
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*/
OUTPUT_FORMAT("elf32-littlearm", "elf32-littlearm", "elf32-littlearm")
OUTPUT_ARCH(arm)
ENTRY(_start)
SECTIONS
{
/*. = 0x00000000;*/ /* PIC */
/*. = 0x00000400;*/ /* ROM Bootloader */
. = 0x40000000; /* SDRAM */
. = ALIGN(4);
_text = . ;
.text :
{
_start = .;
_virt_start = .;
bin/start.o (.text)
*(.text)
. = ALIGN(16);
isa_drivers = . ;
*(.drivers.isa);
isa_drivers_end = . ;
}
. = ALIGN(4);
.rodata : { *(.rodata) }
. = ALIGN(4);
.data : { *(.data) }
. = ALIGN(4);
.got : { *(.got) }
. = ALIGN(4);
_bss = . ;
.bss : { *(.bss) }
. = ALIGN(4);
_ebss = .;
_end = .;
. = ALIGN(16);
.text :
{
*(.dma.desc);
*(.dma.buffer);
}
}

View File

@ -0,0 +1,105 @@
/*
* Copyright (C) 2004 Tobias Lorenz
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*/
/*
* from gcc/config/udivmodsi4.c
*/
unsigned long
udivmodsi4(unsigned long num, unsigned long den, int modwanted)
{
unsigned long bit = 1;
unsigned long res = 0;
while (den < num && bit && !(den & (1L<<31)))
{
den <<=1;
bit <<=1;
}
while (bit)
{
if (num >= den)
{
num -= den;
res |= bit;
}
bit >>=1;
den >>=1;
}
if (modwanted) return num;
return res;
}
/*
* from gcc/config/udivmod.c
*/
long
__udivsi3 (long a, long b)
{
return udivmodsi4 (a, b, 0);
}
long
__umodsi3 (long a, long b)
{
return udivmodsi4 (a, b, 1);
}
/*
* from gcc/config/divmod.c
*/
long
__divsi3 (long a, long b)
{
int neg = 0;
long res;
if (a < 0)
{
a = -a;
neg = !neg;
}
if (b < 0)
{
b = -b;
neg = !neg;
}
res = udivmodsi4 (a, b, 0);
if (neg)
res = -res;
return res;
}
long
__modsi3 (long a, long b)
{
int neg = 0;
long res;
if (a < 0)
{
a = -a;
neg = 1;
}
if (b < 0)
b = -b;
res = udivmodsi4 (a, b, 1);
if (neg)
res = -res;
return res;
}

View File

@ -0,0 +1,27 @@
/*
* Copyright (C) 2004 Tobias Lorenz
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*/
#include "hooks.h"
#include "io.h"
#include "etherboot.h"
struct meminfo meminfo;
void get_memsizes(void)
{
/* We initialize the meminfo structure
* according to our development board's specs
* We do not have a way to automatically probe the
* memspace instead we initialize it manually
*/
meminfo.basememsize = 0x00000000;
meminfo.memsize = 0x00008000;
meminfo.map_count = 1;
meminfo.map[0].addr = 0x40000000;
meminfo.map[0].size = 0x01000000;
meminfo.map[0].type = E820_RAM;
}

View File

@ -0,0 +1,48 @@
/*
* Copyright (C) 2004 Tobias Lorenz
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*/
#ifdef RAW_IMAGE
static unsigned long raw_load_addr;
int mach_boot(register unsigned long entry_point)
{
void (*fnc)(void) = (void *) entry_point;
// r0 = 0
// r1 = 625 (machine nr. MACH_TYPE_P2001)
(*fnc)();
return 0; /* We should never reach this point ! */
}
static sector_t raw_download(unsigned char *data, unsigned int len, int eof)
{
memcpy(phys_to_virt(raw_load_addr), data, len);
raw_load_addr += len;
if (!eof)
return 0;
done(1);
printf("Starting program.\n");
mach_boot(RAWADDR);
printf("Bootsector returned?");
longjmp(restart_etherboot, -2);
return 1;
}
static os_download_t raw_probe(unsigned char *data __unused, unsigned int len __unused)
{
printf("(RAW");
// probe something here...
printf(")... \n");
//raw_load_addr = phys_to_virt(_end);
raw_load_addr = RAWADDR;
printf("Writing image to 0x%x\n", raw_load_addr);
return raw_download;
}
#endif

View File

@ -0,0 +1,66 @@
/*
* Copyright (C) 2004 Tobias Lorenz
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*/
#include "etherboot.h"
#include "hardware.h"
#ifdef CONSOLE_SERIAL
/*
* void serial_putc(int ch);
* Write character `ch' to port UART_BASE.
*/
void serial_putc(int ch)
{
/* wait for room in the 32 byte tx FIFO */
while ((P2001_UART->r.STATUS & 0x3f) > /* 30 */ 0) ;
P2001_UART->w.TX1 = ch & 0xff;
}
/*
* int serial_getc(void);
* Read a character from port UART_BASE.
*/
int serial_getc(void)
{
while (((P2001_UART->r.STATUS >> 6) & 0x3f) == 0) ;
return P2001_UART->r.RX1 & 0xff;
}
/*
* int serial_ischar(void);
* If there is a character in the input buffer of port UART_BASE,
* return nonzero; otherwise return 0.
*/
int serial_ischar(void)
{
return (P2001_UART->r.STATUS >> 6) & 0x3f;
}
/*
* int serial_init(void);
* Initialize port to speed 57.600, line settings 8N1.
*/
int serial_init(void)
{
static unsigned int N;
// const M=3
P2001_UART->w.Clear = 0; // clear
N = ((SYSCLK/8)*3)/CONSPEED;
P2001_UART->w.Baudrate = (N<<16)+3; // set 57.600 BAUD
P2001_UART->w.Config = 0xcc100; // set 8N1, *water = 12
return 1;
}
/*
* void serial_fini(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)
{
}
#endif

View File

@ -0,0 +1,33 @@
/*
* Copyright (C) 2004 Tobias Lorenz
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*/
.text
.global sigsetjmp;
.type sigsetjmp,%function
.align 4;
sigsetjmp:
/* Save registers */
stmia r0, {v1-v6, sl, fp, sp, lr}
mov r0, #0
bx lr
.size sigsetjmp,.-sigsetjmp;
.global longjmp;
.type longjmp,%function
.align 4;
longjmp:
mov ip, r0 /* save jmp_buf pointer */
movs r0, r1 /* get the return value in place */
moveq r0, #1 /* can't let setjmp() return zero! */
ldmia ip, {v1-v6, sl, fp, sp, pc}
.size longjmp,.-longjmp;

View File

@ -0,0 +1,184 @@
/*
* Copyright (C) 2004 Tobias Lorenz
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*/
.global _start
/* Mode definitions */
#define Mode_USR 0x10
#define Mode_FIQ 0x11
#define Mode_IRQ 0x12
#define Mode_SVC 0x13
#define Mode_ABT 0x17
#define Mode_UNDEF 0x1B
#define Mode_SYS 0x1F // only available on ARM Arch. v4
#define I_Bit 0x80
#define F_Bit 0x40
/* LPEC register definitions */
#define Adr_SYS_BASE 0x00100000
#define REL_Adr_SDRAM_Ctrl 0x10
#define REL_Adr_ExtMem_Ctrl 0x14
#define REL_Adr_WaitState_Ext 0x18
#define REL_Adr_WaitState_Asic 0x1c
#define Adr_TIMER_BASE 0x00110000
#define REL_Adr_Timer12_PreDiv 0x0c
#define REL_Adr_PLL_12000_config 0x30
#define REL_Adr_PLL_12288_config 0x34
#define REL_Adr_DIV_12288_config 0x38
#define REL_Adr_FSC_CONFIG 0x44
#define Adr_GPIO_BASE 0x00120000
#define REL_Adr_NRES_OUT 0x2c
/* Define entry point */
.arm // Next instruction will be ARM
_start:
/*
* Initialize memory system
*/
/*
* Initialize stack pointer registers
*/
/* Enter SVC mode and set up the SVC stack pointer */
mov r0, #(Mode_SVC|I_Bit|F_Bit)
msr cpsr_c, r0
ldr sp, SP_SVC
/*
* Initialize critical IO devices
*/
/* watchdog off */
mov r0, #Adr_TIMER_BASE
ldr r1, Timer12_PreDiv
str r1, [r0, #REL_Adr_Timer12_PreDiv]
/* NRES=1 */
mov r0, #Adr_GPIO_BASE
ldr r1, NRES_OUT
str r1, [r0, #REL_Adr_NRES_OUT]
/* ExtMem */
mov r0, #Adr_SYS_BASE
ldr r1, ExtMem_Ctrl
str r1, [r0, #REL_Adr_ExtMem_Ctrl]
/* SDRAM */
mov r0, #Adr_SYS_BASE
ldr r1, SDRAM_Ctrl
str r1, [r0, #REL_Adr_SDRAM_Ctrl]
/*
_wait_sdram_ctrl:
ldr r1, [r0]
tst r1, #0x20000
beq _wait_sdram_ctrl
*/
/* WaitState_Ext */
ldr r1, WaitState_Ext
str r1, [r0, #REL_Adr_WaitState_Ext]
/* WaitState_Asic */
ldr r1, WaitState_Asic
str r1, [r0, #REL_Adr_WaitState_Asic]
/* PLL_12288 */
mov r0, #Adr_TIMER_BASE
ldr r1, PLL_12288_config
str r1, [r0, #REL_Adr_PLL_12288_config]
/* DIV_12288 */
ldr r1, DIV_12288_config
str r1, [r0, #REL_Adr_DIV_12288_config]
/* PLL_12200 */
ldr r1, PLL_12000_config
str r1, [r0, #REL_Adr_PLL_12000_config]
/* FSC_CONFIG */
ldr r1, [r0, #REL_Adr_FSC_CONFIG]
bic r1, r1, #0x07
ldr r2, FSC_CONFIG
orr r1, r1, r2
str r1, [r0, #REL_Adr_FSC_CONFIG]
/*
* Initialize interrupt system variables here
*/
/*
* Initialize memory required by main C code
*/
/* jump to main program */
mov r0, #0
b main
Timer12_PreDiv:
.word 0x40bb0000 /* watchdog off */
NRES_OUT:
.word 0x00000003 /* NRES_OUT_DRV=1, NRES_OUT_DAT=1 */
#if SYSCLK == 73728000
ExtMem_Ctrl:
.word 0x000000e8 /* fuer FPGA 32 Bit konfiguriert */
SDRAM_Ctrl:
// .word 0x28fc0037 /* default */
.word 0xaef40027 /* p2001_bit_compact */
WaitState_Ext:
.word 0xa0001245 /* fuer 73 MHz */
// .word 0x0000fff3 /* rom bootloader */
WaitState_Asic:
.word 0x00ff8a5f /* fuer 85 MHz */
// .word 0x00000203 /* rom bootloader */
PLL_12288_config:
.word 0x00000004 /* fuer 73 MHz */
DIV_12288_config:
.word 0x00010601 /* fuer 73 MHz */
PLL_12000_config:
.word 0x10004e75 /* fuer 85 MHz */
FSC_CONFIG:
.word 0xc0000005 /* fuer 73 MHz */
#else
#error "Please define proper timings and wait states for that sysclk."
#endif
SP_SVC:
.word 0x40fffffc
#ifndef NORELOCATE
/**************************************************************************
RELOCATE_TO - relocate etherboot to the specified address
**************************************************************************/
.global relocate_to
relocate_to:
ldr r1, =_start
ldr r2, =_end
/* while (r1 < r2) { *(r0++) = *(r1++) } */
_relocate_loop:
cmp r1, r2
ldrcc r3, [r1], #4
strcc r3, [r0], #4
bcc _relocate_loop
mov pc, lr
#endif
.global __gccmain
__gccmain:
mov pc, lr /* return from subroutine */

View File

@ -0,0 +1,525 @@
/**************************************************************************
Etherboot - BOOTP/TFTP Bootstrap Program
P2001 NIC driver for Etherboot
***************************************************************************/
/*
* Copyright (C) 2004 Tobias Lorenz
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*/
/* to get some global routines like printf */
#include "etherboot.h"
/* to get the interface to the body of the program */
#include "nic.h"
/* to get the ISA support functions, if this is an ISA NIC */
#include "isa.h"
#include "hardware.h"
#include "lxt971a.h"
#include "timer.h"
/* NIC specific static variables go here */
static unsigned char MAC_HW_ADDR[6]={MAC_HW_ADDR_DRV};
/* DMA descriptors and buffers */
#define NUM_RX_DESC 4 /* Number of Rx descriptor registers. */
#define DMA_BUF_SIZE 2048 /* Buffer size */
static DMA_DSC txd __attribute__ ((__section__(".dma.desc")));
static DMA_DSC rxd[NUM_RX_DESC] __attribute__ ((__section__(".dma.desc")));
static unsigned char rxb[NUM_RX_DESC * DMA_BUF_SIZE] __attribute__ ((__section__(".dma.buffer")));
static unsigned char txb[ DMA_BUF_SIZE] __attribute__ ((__section__(".dma.buffer")));
static unsigned int cur_rx;
/* Device selectors */
static unsigned int cur_channel; // DMA channel : 0..3
static unsigned int cur_phy; // PHY Address : 0..31
static P2001_ETH_regs_ptr EU; // Ethernet Unit : 0x0018_000 with _=0..3
static P2001_ETH_regs_ptr MU; // Management Unit: 0x00180000
#define MDIO_MAXCOUNT 1000 /* mdio abort */
static unsigned int mdio_error; /* mdio error */
/* Function prototypes */
static void p2001_eth_mdio_init ();
static void p2001_eth_mdio_write(unsigned int phyadr, unsigned int regadr, unsigned int data);
static unsigned int p2001_eth_mdio_read (unsigned int phyadr, unsigned int regadr);
extern unsigned int p2001_eth_mdio_error;
static int p2001_eth_poll (struct nic *nic, int retrieve);
static void p2001_eth_transmit (struct nic *nic, const char *d,
unsigned int t, unsigned int s, const char *p);
static void p2001_eth_irq (struct nic *nic, irq_action_t action);
static void p2001_eth_init ();
static void p2001_eth_disable (struct dev *dev);
static int p2001_eth_check_link(unsigned int phy);
static int p2001_eth_probe (struct dev *dev, unsigned short *probe_addrs __unused);
/**************************************************************************
PHY MANAGEMENT UNIT - Read/write
***************************************************************************/
static void p2001_eth_mdio_init()
{
/* reset ethernet PHYs */
printf("Resetting PHYs...\n");
/* GPIO24/25: TX_ER2/TX_ER0 */
/* GPIO26/27: PHY_RESET/TX_ER1 */
P2001_GPIO->PIN_MUX |= 0x0018;
// 31-16: 0000 1111 0000 0000
P2001_GPIO->GPIO2_En |= 0x0400;
P2001_GPIO->GPIO2_Out |= 0x04000000;
P2001_GPIO->GPIO2_Out &= ~0x0400;
mdelay(500);
P2001_GPIO->GPIO2_Out |= 0x0400;
/* set management unit clock divisor */
// max. MDIO CLK = 2.048 MHz (EU.doc)
// max. MDIO CLK = 8.000 MHz (LXT971A)
// sysclk/(2*(n+1)) = MDIO CLK <= 2.048 MHz
// n >= sysclk/4.096 MHz - 1
#if SYSCLK == 73728000
P2001_MU->MU_DIV = 17; // 73.728 MHZ =17=> 2.020 MHz
#else
//MU->MU_DIV = (SYSCLK/4.096)-1;
#error "Please define a proper MDIO CLK divisor for that sysclk."
#endif
asm("nop \n nop");
}
static void p2001_eth_mdio_write(unsigned int phyadr, unsigned int regadr, unsigned int data)
{
static unsigned int count;
count = 0;
/* Warten bis Hardware inaktiv (MIU = "0") */
while ((MU->MU_CNTL & 0x8000) && (count < MDIO_MAXCOUNT))
count++;
/* Schreiben MU_DATA */
MU->MU_DATA = data;
/* Schreiben MU_CNTL */
MU->MU_CNTL = regadr + (phyadr<<5) + (1<<10);
/* Warten bis Hardware aktiv (MIU = "1") */
while (((MU->MU_CNTL & 0x8000) == 0) && (count < MDIO_MAXCOUNT))
count++;
//asm("nop \r\n nop");
/* Warten bis Hardware inaktiv (MIU = "0") */
while ((MU->MU_CNTL & 0x8000) && (count < MDIO_MAXCOUNT))
count++;
mdio_error = (count >= MDIO_MAXCOUNT);
}
static unsigned int p2001_eth_mdio_read(unsigned int phyadr, unsigned int regadr)
{
static unsigned int count;
count = 0;
do {
/* Warten bis Hardware inaktiv (MIU = "0") */
while ((MU->MU_CNTL & 0x8000) && (count < MDIO_MAXCOUNT))
count++;
/* Schreiben MU_CNTL */
MU->MU_CNTL = regadr + (phyadr<<5) + (2<<10);
/* Warten bis Hardware aktiv (MIU = "1") */
while (((MU->MU_CNTL & 0x8000) == 0) && (count < MDIO_MAXCOUNT))
count++;
//asm("nop \r\n nop");
/* Warten bis Hardware inaktiv (MIU = "0") */
while ((MU->MU_CNTL & 0x8000) && (count < MDIO_MAXCOUNT))
count++;
/* Fehler, wenn MDIO Read Error (MRE = "1") */
} while ((MU->MU_CNTL & 0x4000) && (count < MDIO_MAXCOUNT));
/* Lesen MU_DATA */
mdio_error = (count >= MDIO_MAXCOUNT);
return MU->MU_DATA;
}
/**************************************************************************
POLL - Wait for a frame
***************************************************************************/
/* Function: p2001_eth_poll
*
* Description: checks for a received packet and returns it if found.
*
* Arguments: struct nic *nic: NIC data structure
*
* Returns: 1 if a packet was received.
* 0 if no pacet was received.
*
* Side effects:
* Returns (copies) the packet to the array nic->packet.
* Returns the length of the packet in nic->packetlen.
*/
static int p2001_eth_poll(struct nic *nic, int retrieve)
{
/* return true if there's an ethernet packet ready to read */
/* nic->packet should contain data on return */
/* nic->packetlen should contain length of data */
int retstat = 0;
if (rxd[cur_rx].stat & (1<<31)) // OWN
return retstat;
if (!retrieve)
return 1;
nic->packetlen = rxd[cur_rx].cntl & 0xffff;
if (rxd[cur_rx].stat & ((1<<26)|(1<<25)|(1<<24)|(1<<23)|(1<<22))) {
/* corrupted packet received */
printf("p2001_eth_poll: Corrupted packet received, stat = %X\n",
rxd[cur_rx].stat);
retstat = 0;
} else {
/* give packet to higher routine */
memcpy(nic->packet, (rxb + cur_rx*DMA_BUF_SIZE), nic->packetlen);
retstat = 1;
}
#ifdef DEBUG_NIC
printf("p2001_eth_poll: packet from %! to %! received\n",
(rxb+cur_rx*DMA_BUF_SIZE)+ETH_ALEN,
(rxb+cur_rx*DMA_BUF_SIZE));
#endif
/* disable receiver */
// FIXME: is that ok? it can produce grave errors.
EU->RMAC_DMA_EN = 0; /* clear run bit */
/* return the descriptor and buffer to receive ring */
rxd[cur_rx].stat = (1<<31) | (1<<30) | (1<<29); // DSC0 OWN|START|END
rxd[cur_rx].cntl = (1<<23); // DSC1 RECEIVE
rxd[cur_rx].cntl |= cur_channel << 16; // DSC1 CHANNEL
rxd[cur_rx].cntl |= DMA_BUF_SIZE; // DSC1 LEN
if (++cur_rx == NUM_RX_DESC)
cur_rx = 0;
/* enable receiver */
if (!(EU->RMAC_DMA_EN & 0x01))
EU->RMAC_DMA_EN = 0x01; /* set run bit */
#ifdef DEBUG_NIC
printf("RMAC_MIB0..5: %d:%d:%d:%d:%d:%d\n",
EU->RMAC_MIB0, EU->RMAC_MIB1,
EU->RMAC_MIB2, EU->RMAC_MIB3,
EU->RMAC_MIB4, EU->RMAC_MIB5);
#endif
return retstat; /* initially as this is called to flush the input */
}
/**************************************************************************
TRANSMIT - Transmit a frame
***************************************************************************/
/* Function: p2001_eth_transmit
*
* Description: transmits a packet and waits for completion or timeout.
*
* Arguments: char d[6]: destination ethernet address.
* unsigned short t: ethernet protocol type.
* unsigned short s: size of the data-part of the packet.
* char *p: the data for the packet.
*
* Returns: void.
*/
static void p2001_eth_transmit(
struct nic *nic __unused,
const char *d, /* Destination */
unsigned int t, /* Type */
unsigned int s, /* size */
const char *p) /* Packet */
{
unsigned int nstype;
#ifdef DEBUG_NIC
unsigned int status;
#endif
/* assemble packet */
memcpy(txb, d, ETH_ALEN); // destination
memcpy(txb+ETH_ALEN, nic->node_addr, ETH_ALEN); // source
nstype = htons(t);
memcpy(txb+2*ETH_ALEN, (char*)&nstype, 2); // type
memcpy(txb+ETH_HLEN, p, s); // packet
s += ETH_HLEN;
/* pad to minimum packet size */
// while (s<ETH_ZLEN)
// txb[s++] = '\0';
// TMAC_CNTL.ATP does the same
#ifdef DEBUG_NIC
printf("p2001_eth_transmit: packet from %! to %! sent\n", txb+ETH_ALEN, txb);
#endif
/* configure descriptor */
txd.stat = (1<<31) | (1<<30) | (1<<29); // DSC0 OWN|START|END
txd.cntl = cur_channel << 16; // DSC1 CHANNEL
txd.cntl |= s; // DSC1 LEN
/* restart the transmitter */
EU->TMAC_DMA_EN = 0x01; /* set run bit */
while(EU->TMAC_DMA_EN & 0x01) ; /* wait */
#ifdef DEBUG_NIC
/* check status */
status = EU->TMAC_DMA_STAT;
if (status & ~(0x40))
printf("p2001_eth_transmit: dma status=0x%hx\n", status);
printf("TMAC_MIB6..7: %d:%d\n", EU->TMAC_MIB6, EU->TMAC_MIB7);
#endif
}
/**************************************************************************
IRQ - Enable, Disable or Force Interrupts
***************************************************************************/
/* Function: p2001_eth_irq
*
* Description: Enable, Disable, or Force, interrupts
*
* Arguments: struct nic *nic: NIC data structure
* irq_action_t action: Requested action
*
* Returns: void.
*/
static void
p2001_eth_irq(struct nic *nic __unused, irq_action_t action __unused)
{
switch ( action ) {
case DISABLE :
break;
case ENABLE :
break;
case FORCE :
break;
}
}
/**************************************************************************
INIT - Initialize device
***************************************************************************/
/* Function: p2001_init
*
* Description: resets the ethernet controller chip and various
* data structures required for sending and receiving packets.
*
* returns: void.
*/
static void p2001_eth_init()
{
static int i;
/* disable transceiver */
// EU->TMAC_DMA_EN = 0; /* clear run bit */
// EU->RMAC_DMA_EN = 0; /* clear run bit */
/* set rx filter (physical mac addresses) */
EU->RMAC_PHYU =
(MAC_HW_ADDR[0]<< 8) +
(MAC_HW_ADDR[1]<< 0);
EU->RMAC_PHYL =
(MAC_HW_ADDR[2]<<24) +
(MAC_HW_ADDR[3]<<16) +
(MAC_HW_ADDR[4]<<8 ) +
(MAC_HW_ADDR[5]<<0 );
/* initialize the tx descriptor ring */
// txd.stat = (1<<31) | (1<<30) | (1<<29); // DSC0 OWN|START|END
// txd.cntl = cur_channel << 16; // DSC1 CHANNEL
// txd.cntl |= DMA_BUF_SIZE; // DSC1 LEN
txd.buf = &txb; // DSC2 BUFFER
txd.next = &txd; // DSC3 NEXTDSC @self
EU->TMAC_DMA_DESC = &txd;
/* initialize the rx descriptor ring */
cur_rx = 0;
for (i = 0; i < NUM_RX_DESC; i++) {
rxd[i].stat = (1<<31) | (1<<30) | (1<<29); // DSC0 OWN|START|END
rxd[i].cntl = (1<<23); // DSC1 RECEIVE
rxd[i].cntl |= cur_channel << 16; // DSC1 CHANNEL
rxd[i].cntl |= DMA_BUF_SIZE; // DSC1 LEN
rxd[i].buf = &rxb[i*DMA_BUF_SIZE]; // DSC2 BUFFER (EU-RX data)
rxd[i].next = &rxd[i+1]; // DSC3 NEXTDSC @next
}
rxd[NUM_RX_DESC-1].next = &rxd[0]; // DSC3 NEXTDSC @first
EU->RMAC_DMA_DESC = &rxd[0];
/* set transmitter mode */
EU->TMAC_CNTL = (1<<4) | /* COI: Collision ignore */
//(1<<3) | /* CSI: Carrier Sense ignore */
(1<<2); /* ATP: Automatic Transmit Padding */
/* set receive mode */
EU->RMAC_CNTL = (1<<3) | /* BROAD: Broadcast packets */
(1<<1); /* PHY : Packets to out MAC address */
/* enable receiver */
EU->RMAC_DMA_EN = 1; /* set run bit */
}
/**************************************************************************
DISABLE - Turn off ethernet interface
***************************************************************************/
static void p2001_eth_disable(struct dev *dev __unused)
{
/* put the card in its initial state */
/* This function serves 3 purposes.
* This disables DMA and interrupts so we don't receive
* unexpected packets or interrupts from the card after
* etherboot has finished.
* This frees resources so etherboot may use
* this driver on another interface
* This allows etherboot to reinitialize the interface
* if something is something goes wrong.
*/
/* disable transmitter */
EU->TMAC_DMA_EN = 0; /* clear run bit */
/* disable receiver */
EU->RMAC_DMA_EN = 0; /* clear run bit */
}
/**************************************************************************
LINK - Check for valid link
***************************************************************************/
static int p2001_eth_check_link(unsigned int phy)
{
static int status;
static unsigned int count;
count = 0;
/* Use 0x3300 for restarting NWay */
printf("Starting auto-negotiation... ");
p2001_eth_mdio_write(phy, Adr_LXT971A_Control, 0x3300);
if (mdio_error)
goto failed;
/* Bits 1.5 and 17.7 are set to 1 once the Auto-Negotiation process to completed. */
do {
mdelay(500);
status = p2001_eth_mdio_read(phy, Adr_LXT971A_Status1);
if (mdio_error || (count++ > 6)) // 6*500ms = 3s timeout
goto failed;
} while (!(status & 0x20));
/* Bits 1.2 and 17.10 are set to 1 once the link is established. */
if (p2001_eth_mdio_read(phy, Adr_LXT971A_Status1) & 0x04) {
/* Bits 17.14 and 17.9 can be used to determine the link operation conditions (speed and duplex). */
printf("Valid link, operating at: %sMb-%s\n",
(p2001_eth_mdio_read(phy, Adr_LXT971A_Status2) & 0x4000) ? "100" : "10",
(p2001_eth_mdio_read(phy, Adr_LXT971A_Status2) & 0x0200) ? "FD" : "HD");
return 1;
}
failed:
if (mdio_error)
printf("Failed\n");
else
printf("No valid link\n");
return 0;
}
/**************************************************************************
PROBE - Look for an adapter, this routine's visible to the outside
***************************************************************************/
static int p2001_eth_probe(struct dev *dev, unsigned short *probe_addrs __unused)
{
struct nic *nic = (struct nic *)dev;
/* if probe_addrs is 0, then routine can use a hardwired default */
static int board_found;
static int valid_link;
/* reset phys and configure mdio clk */
p2001_eth_mdio_init();
/* find the correct PHY/DMA/MAC combination */
MU = P2001_MU; // MU for all PHYs is only in EU0
printf("Searching for P2001 NICs...\n");
for (cur_channel=0; cur_channel<4; cur_channel++) {
switch(cur_channel) {
case 0:
EU = P2001_EU0;
cur_phy = 0;
break;
case 1:
EU = P2001_EU1;
cur_phy = 1;
break;
case 2:
EU = P2001_EU2;
cur_phy = 2;
break;
case 3:
EU = P2001_EU3;
cur_phy = 3;
break;
}
/* first a non destructive test for initial value RMAC_TLEN=1518 */
board_found = (EU->RMAC_TLEN == 1518);
if (board_found) {
printf("Checking EU%d...\n", cur_channel);
valid_link = p2001_eth_check_link(cur_phy);
if (valid_link) {
/* initialize device */
p2001_eth_init(nic);
/* set node address */
printf("Setting MAC address to %!\n", MAC_HW_ADDR);
memcpy(nic->node_addr, MAC_HW_ADDR, 6);
/* point to NIC specific routines */
dev->disable = p2001_eth_disable;
nic->poll = p2001_eth_poll;
nic->transmit = p2001_eth_transmit;
nic->irq = p2001_eth_irq;
/* Report the ISA pnp id of the board */
dev->devid.vendor_id = htons(GENERIC_ISAPNP_VENDOR);
dev->devid.vendor_id = htons(0x1234);
return 1;
}
}
}
/* else */
return 0;
}
ISA_ROM("p2001_eth", "P2001 Ethernet Driver")
static struct isa_driver p2001_eth_driver __isa_driver = {
.type = NIC_DRIVER,
.name = "P2001 Ethernet Driver",
.probe = p2001_eth_probe,
.ioaddrs = 0,
};

View File

@ -0,0 +1,47 @@
/*
* Copyright (C) 2004 Tobias Lorenz
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*/
#ifndef ETHERBOOT_BITS_BYTESWAP_H
#define ETHERBOOT_BITS_BYTESWAP_H
/* We do not have byte swap functions ... We are
* RISC processor ...
*/
static inline unsigned short __swap16(volatile unsigned short v)
{
return ((v << 8) | (v >> 8));
}
static inline unsigned int __swap32(volatile unsigned long v)
{
return ((v << 24) | ((v & 0xff00) << 8) | ((v & 0xff0000) >> 8) | (v >> 24));
}
#define __bswap_constant_16(x) \
((uint16_t)((((uint16_t)(x) & 0x00ff) << 8) | \
(((uint16_t)(x) & 0xff00) >> 8)))
#define __bswap_constant_32(x) \
((uint32_t)((((uint32_t)(x) & 0x000000ffU) << 24) | \
(((uint32_t)(x) & 0x0000ff00U) << 8) | \
(((uint32_t)(x) & 0x00ff0000U) >> 8) | \
(((uint32_t)(x) & 0xff000000U) >> 24)))
# define __bswap_16(x) \
(__extension__ \
({ unsigned short int __bsx = (x); \
((((__bsx) >> 8) & 0xff) | (((__bsx) & 0xff) << 8)); }))
# define __bswap_32(x) \
(__extension__ \
({ unsigned int __bsx = (x); \
((((__bsx) & 0xff000000) >> 24) | (((__bsx) & 0x00ff0000) >> 8) | \
(((__bsx) & 0x0000ff00) << 8) | (((__bsx) & 0x000000ff) << 24)); }))
#endif /* ETHERBOOT_BITS_BYTESWAP_H */

View File

@ -0,0 +1,13 @@
/*
* Copyright (C) 2004 Tobias Lorenz
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*/
#ifndef ARM_BITS_CPU_H
#define ARM_BITS_CPU_H
#define cpu_setup() do {} while(0)
#endif /* ARM_BITS_CPU_H */

View File

@ -0,0 +1,18 @@
/*
* Copyright (C) 2004 Tobias Lorenz
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*/
#ifndef ARM_BITS_ELF_H
#define ARM_BITS_ELF_H
/* ELF Defines for the current architecture */
#define EM_CURRENT EM_ARM
#define ELFDATA_CURRENT ELFDATA2LSB
#define ELF_CHECK_ARCH(x) \
((x).e_machine == EM_CURRENT)
#endif /* ARM_BITS_ELF_H */

View File

@ -0,0 +1,17 @@
/*
* Copyright (C) 2004 Tobias Lorenz
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*/
#ifndef ETHERBOOT_BITS_ENDIAN_H
#define ETHERBOOT_BITS_ENDIAN_H
#ifdef __ARMEB__
#define __BYTE_ORDER __BIG_ENDIAN
#else
#define __BYTE_ORDER __LITTLE_ENDIAN
#endif
#endif /* ETHERBOOT_BITS_ENDIAN_H */

View File

@ -0,0 +1,11 @@
/*
* Copyright (C) 2004 Tobias Lorenz
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*/
#ifndef ETHERBOOT_BITS_STRING_H
#define ETHERBOOT_BITS_STRING_H
#endif /* ETHERBOOT_BITS_STRING_H */

View File

@ -0,0 +1 @@
/* empty file */

View File

@ -0,0 +1,179 @@
/*
* Copyright (C) 2004 Tobias Lorenz
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*/
/*
* Architecture: ARM9TDMI
* Processor : P2001
*/
#ifndef ARCH_HARDWARE_H
#define ARCH_HARDWARE_H
#ifndef __ASSEMBLY__
/* DMA descriptor */
typedef struct {
unsigned int stat; /* status: own, start, end, offset, status */
unsigned int cntl; /* control: loop, int, type, channel, length */
char *buf; /* buffer */
void *next; /* nextdsc */
} DMA_DSC;
/* The address definitions are from asic_bf.h */
typedef struct { // 0x00100000U
volatile unsigned int reserved1[0x3];
volatile unsigned int ArmDmaPri; // 0x0000000CU
volatile unsigned int SDRAM_Ctrl; // 0x00000010U
volatile unsigned int ExtMem_Ctrl; // 0x00000014U
volatile unsigned int WaitState_Ext; // 0x00000018U
volatile unsigned int WaitState_Asic; // 0x0000001CU
volatile unsigned int TOP; // 0x00000020U
volatile unsigned int reserved2[0x3];
volatile unsigned int Adr1_EQ_30Bit; // 0x00000030U
volatile unsigned int Adr2_EQ_30Bit; // 0x00000034U
volatile unsigned int Adr3_EQ_30Bit; // 0x00000038U
volatile unsigned int Dat3_EQ_32Bit; // 0x0000003CU
volatile unsigned int Adr4_HE_20Bit; // 0x00000040U
volatile unsigned int Adr4_LT_20Bit; // 0x00000044U
volatile unsigned int Adr5_HE_20Bit; // 0x00000048U
volatile unsigned int Adr5_LT_20Bit; // 0x0000004CU
volatile unsigned int Adr_Control; // 0x00000050U
volatile unsigned int ABORT_IA_32Bit; // 0x00000054U
} *P2001_SYS_regs_ptr;
#define P2001_SYS ((volatile P2001_SYS_regs_ptr) 0x00100000)
typedef struct { // 0x00110000U
volatile unsigned int Timer1; // 0x00000000U
volatile unsigned int Timer2; // 0x00000004U
volatile unsigned int TIMER_PRELOAD; // 0x00000008U
volatile unsigned int Timer12_PreDiv; // 0x0000000CU
volatile unsigned int TIMER_INT; // 0x00000010U
volatile unsigned int Freerun_Timer; // 0x00000014U
volatile unsigned int WatchDog_Timer; // 0x00000018U
volatile unsigned int PWM_CNT; // 0x00000020U
volatile unsigned int PWM_CNT2; // 0x00000024U
volatile unsigned int PLL_12000_config; // 0x00000030U
volatile unsigned int PLL_12288_config; // 0x00000034U
volatile unsigned int DIV_12288_config; // 0x00000038U
volatile unsigned int MOD_CNT_768; // 0x0000003CU
volatile unsigned int FSC_IRQ_STATUS; // 0x00000040U
volatile unsigned int FSC_CONFIG; // 0x00000044U
volatile unsigned int FSC_CONSTRUCT; // 0x00000048U
volatile unsigned int FSC_base_clk_reg; // 0x0000004CU
volatile unsigned int SYSCLK_SHAPE; // 0x00000050U
volatile unsigned int SDRAMCLK_SHAPE; // 0x00000054U
volatile unsigned int RING_OSZI; // 0x00000058U
} *P2001_TIMER_regs_ptr;
#define P2001_TIMER ((volatile P2001_TIMER_regs_ptr) 0x00110000)
typedef struct { // 0x00120000U
volatile unsigned int reserved1[0x5];
volatile unsigned int GPIO_Config; // 0x00000014U
volatile unsigned int GPIO_INT; // 0x00000018U
volatile unsigned int GPIO_Out; // 0x0000001CU
volatile unsigned int GPIO_IN; // 0x00000020U
volatile unsigned int GPIO_En; // 0x00000024U
volatile unsigned int PIN_MUX; // 0x00000028U
volatile unsigned int NRES_OUT; // 0x0000002CU
volatile unsigned int GPIO2_Out; // 0x00000030U
volatile unsigned int GPIO2_IN; // 0x00000034U
volatile unsigned int GPIO2_En; // 0x00000038U
volatile unsigned int GPIO_INT_SEL; // 0x0000003CU
volatile unsigned int GPI3_IN; // 0x00000040U
volatile unsigned int GPO4_OUT; // 0x00000044U
} *P2001_GPIO_regs_ptr;
#define P2001_GPIO ((volatile P2001_GPIO_regs_ptr) 0x00120000)
typedef struct { // 0x00130000U
volatile unsigned int Main_NFIQ_Int_Ctrl; // 0x00000000U
volatile unsigned int Main_NIRQ_Int_Ctrl; // 0x00000004U
volatile unsigned int Status_NFIQ; // 0x00000008U
volatile unsigned int Status_NIRQ; // 0x0000000CU
} *P2001_INT_CTRL_regs_ptr;
#define P2001_INT_CTRL ((volatile P2001_INT_CTRL_regs_ptr) 0x00130000)
typedef union { // 0x00140000U
struct { // write
volatile unsigned int TX1; // 0x00000000U
volatile unsigned int TX2; // 0x00000004U
volatile unsigned int TX3; // 0x00000008U
volatile unsigned int TX4; // 0x0000000CU
volatile unsigned int Baudrate; // 0x00000010U
volatile unsigned int reserved1[0x3];
volatile unsigned int Config; // 0x00000020U
volatile unsigned int Clear; // 0x00000024U
volatile unsigned int Echo_EN; // 0x00000028U
volatile unsigned int IRQ_Status; // 0x0000002CU
} w; // write
struct { // read
volatile unsigned int RX1; // 0x00000000U
volatile unsigned int RX2; // 0x00000004U
volatile unsigned int RX3; // 0x00000008U
volatile unsigned int RX4; // 0x0000000CU
volatile unsigned int reserved1[0x4];
volatile unsigned int PRE_STATUS; // 0x00000020U
volatile unsigned int STATUS; // 0x00000024U
volatile unsigned int reserved2[0x1];
volatile unsigned int IRQ_Status; // 0x0000002CU
} r; // read
} *P2001_UART_regs_ptr;
#define P2001_UART ((volatile P2001_UART_regs_ptr) 0x00140000)
typedef struct { // 0x0018_000U _=0,1,2,3
volatile DMA_DSC * RMAC_DMA_DESC; // 0x00000000U
volatile unsigned int RMAC_DMA_CNTL; // 0x00000004U
volatile unsigned int RMAC_DMA_STAT; // 0x00000008U
volatile unsigned int RMAC_DMA_EN; // 0x0000000CU
volatile unsigned int RMAC_CNTL; // 0x00000010U
volatile unsigned int RMAC_TLEN; // 0x00000014U
volatile unsigned int RMAC_PHYU; // 0x00000018U
volatile unsigned int RMAC_PHYL; // 0x0000001CU
volatile unsigned int RMAC_PFM0; // 0x00000020U
volatile unsigned int RMAC_PFM1; // 0x00000024U
volatile unsigned int RMAC_PFM2; // 0x00000028U
volatile unsigned int RMAC_PFM3; // 0x0000002CU
volatile unsigned int RMAC_PFM4; // 0x00000030U
volatile unsigned int RMAC_PFM5; // 0x00000034U
volatile unsigned int RMAC_PFM6; // 0x00000038U
volatile unsigned int RMAC_PFM7; // 0x0000003CU
volatile unsigned int RMAC_MIB0; // 0x00000040U
volatile unsigned int RMAC_MIB1; // 0x00000044U
volatile unsigned int RMAC_MIB2; // 0x00000048U
volatile unsigned int RMAC_MIB3; // 0x0000004CU
volatile unsigned int RMAC_MIB4; // 0x00000050U
volatile unsigned int RMAC_MIB5; // 0x00000054U
volatile unsigned int reserved1[0x1e8];
volatile unsigned int RMAC_DMA_DATA; // 0x000007F8U
volatile unsigned int RMAC_DMA_ADR; // 0x000007FCU
volatile DMA_DSC * TMAC_DMA_DESC; // 0x00000800U
volatile unsigned int TMAC_DMA_CNTL; // 0x00000804U
volatile unsigned int TMAC_DMA_STAT; // 0x00000808U
volatile unsigned int TMAC_DMA_EN; // 0x0000080CU
volatile unsigned int TMAC_CNTL; // 0x00000810U
volatile unsigned int TMAC_MIB6; // 0x00000814U
volatile unsigned int TMAC_MIB7; // 0x00000818U
volatile unsigned int reserved2[0x1];
volatile unsigned int MU_CNTL; // 0x00000820U
volatile unsigned int MU_DATA; // 0x00000824U
volatile unsigned int MU_DIV; // 0x00000828U
volatile unsigned int CONF_RMII; // 0x0000082CU
volatile unsigned int reserved3[0x1f2];
volatile unsigned int TMAC_DMA_DATA; // 0x00000FF8U
volatile unsigned int TMAC_DMA_ADR; // 0x00000FFCU
} *P2001_ETH_regs_ptr;
#define P2001_EU0 ((volatile P2001_ETH_regs_ptr) 0x00180000)
#define P2001_EU1 ((volatile P2001_ETH_regs_ptr) 0x00181000)
#define P2001_EU2 ((volatile P2001_ETH_regs_ptr) 0x00182000)
#define P2001_EU3 ((volatile P2001_ETH_regs_ptr) 0x00183000)
#define P2001_MU P2001_EU0
#endif
#endif /* ARCH_HARDWARE_H */

View File

@ -0,0 +1,25 @@
/*
* Copyright (C) 2004 Tobias Lorenz
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*/
#ifndef ETHERBOOT_ARM_HOOKS_H
#define ETHERBOOT_ARM_HOOKS_H
struct Elf_Bhdr;
#define arch_main(data, params) do {} while(0)
//void arch_main(in_call_data_t *data, va_list params);
#define arch_on_exit(status) do {} while(0)
//void arch_on_exit(int status);
#define arch_relocate_to(addr) do {} while(0)
//void arch_relocate_to(unsigned long addr);
#define arch_relocated_from(old_addr) do {} while(0)
//void arch_relocate_from(unsigned long old_addr);
#endif /* ETHERBOOT_ARM_HOOKS_H */

View File

@ -0,0 +1,27 @@
/*
* Copyright (C) 2004 Tobias Lorenz
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*/
#ifndef ETHERBOOT_IO_H
#define ETHERBOOT_IO_H
#define virt_to_phys(vaddr) ((unsigned long) (vaddr))
#define phys_to_virt(vaddr) ((void *) (vaddr))
#define virt_to_bus virt_to_phys
#define bus_to_virt phys_to_virt
#define iounmap(addr) ((void)0)
#define ioremap(physaddr, size) (physaddr)
extern unsigned char inb (unsigned long int port);
extern unsigned short int inw (unsigned long int port);
extern unsigned long int inl (unsigned long int port);
extern void outb (unsigned char value, unsigned long int port);
extern void outw (unsigned short value, unsigned long int port);
extern void outl (unsigned long value, unsigned long int port);
#endif /* ETHERBOOT_IO_H */

View File

@ -0,0 +1,15 @@
/*
* Copyright (C) 2004 Tobias Lorenz
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*/
#ifndef LATCH_H
#define LATCH_H
// Freerun_Timer is always at 12.288 MHZ
#define TICKS_PER_SEC (12288000UL)
//#define TICKS_PER_SEC (73728000UL)
#endif /* LATCH_H */

View File

@ -0,0 +1,43 @@
/*
* Copyright (C) 2004 Tobias Lorenz
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*/
#ifndef __LIMITS_H
#define __LIMITS_H 1
#define MB_LEN_MAX 16
#define CHAR_BIT 8
#define SCHAR_MIN (-128)
#define SCHAR_MAX 127
#define UCHAR_MAX 255
#define CHAR_MIN SCHAR_MIN
#define CHAR_MAX SCHAR_MAX
#define SHRT_MIN (-32768)
#define SHRT_MAX 32767
#define USHRT_MAX 65535
#define INT_MIN (-INT_MAX - 1)
#define INT_MAX 2147483647
#define UINT_MAX 4294967295U
#define LONG_MAX 2147483647L
#define LONG_MIN (-LONG_MAX - 1L)
#define ULONG_MAX 4294967295UL
#define LLONG_MAX 9223372036854775807LL
#define LLONG_MIN (-LLONG_MAX - 1LL)
#define ULLONG_MAX 18446744073709551615ULL
#endif

View File

@ -0,0 +1,30 @@
/*
* Copyright (C) 2004 Tobias Lorenz
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*/
/*
* Intel LXT971ALE (MII-compatible PHY)
*/
#define Adr_LXT971A_Control 0 /* Control Register */
#define Adr_LXT971A_Status1 1 /* MII Status Register #1 */
#define Adr_LXT971A_PHY_ID1 2 /* PHY Identification Register 1 */
#define Adr_LXT971A_PHY_ID2 3 /* PHY Identification Register 2 */
#define Adr_LXT971A_AN_Advertise 4 /* Auto Negotiation Advertisement Register */
#define Adr_LXT971A_AN_Link_Ability 5 /* Auto Negotiation Link Partner Base Page Ability Register */
#define Adr_LXT971A_AN_Expansion 6 /* Auto Negotiation Expansion */
#define Adr_LXT971A_AN_Next_Page_Txmit 7 /* Auto Negotiation Next Page Transmit Register */
#define Adr_LXT971A_AN_Link_Next_Page 8 /* Auto Negotiation Link Partner Next Page Receive Register */
#define Adr_LXT971A_Fast_Control 9 /* Not Implemented */
#define Adr_LXT971A_Fast_Status 10 /* Not Implemented */
#define Adr_LXT971A_Extended_Status 15 /* Not Implemented */
#define Adr_LXT971A_Port_Config 16 /* Configuration Register */
#define Adr_LXT971A_Status2 17 /* Status Register #2 */
#define Adr_LXT971A_Interrupt_Enable 18 /* Interrupt Enable Register */
#define Adr_LXT971A_Interrupt_Status 19 /* Interrupt Status Register */
#define Adr_LXT971A_LED_Config 20 /* LED Configuration Register */
#define Adr_LXT971A_Transmit_Control 30 /* Transmit Control Register */

View File

@ -0,0 +1,23 @@
/*
* Copyright (C) 2004 Tobias Lorenz
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*/
#ifndef ETHERBOOT_SETJMP_H
#define ETHERBOOT_SETJMP_H
#ifndef __ASSEMBLER__
/* Jump buffer contains v1-v6, sl, fp, sp and pc. Other registers are not
saved. */
//typedef int jmp_buf[22];
typedef int jmp_buf[10];
#endif
extern int sigsetjmp(jmp_buf __env, int __savemask);
extern void longjmp(jmp_buf __env, int __val) __attribute__((__noreturn__));
#define setjmp(env) sigsetjmp(env,0)
#endif /* ETHERBOOT_SETJMP_H */

View File

@ -0,0 +1,23 @@
/*
* Copyright (C) 2004 Tobias Lorenz
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*/
#ifndef STDINT_H
#define STDINT_H
typedef unsigned long size_t;
typedef unsigned char uint8_t;
typedef unsigned short uint16_t;
typedef unsigned long uint32_t;
typedef unsigned long long uint64_t;
typedef signed char int8_t;
typedef signed short int16_t;
typedef signed int int32_t;
typedef signed long long int64_t;
#endif /* STDINT_H */

7
src/arch/e1/Config Normal file
View File

@ -0,0 +1,7 @@
# Config for e1 Etherboot
#
CFLAGS+= -mgnu-param -DCONSOLE_SERIAL -DCOMCONSOLE=0x01C00000 -DCONSPEED=28800
CFLAGS+= -DSIZEINDICATOR -DNO_DHCP_SUPPORT -DBAR_PROGRESS
#CFLAGS+= -DEMBEDDED -DMAC_HW_ADDR_DRV="'H','Y','L','N','X','1'"

70
src/arch/e1/Makefile Normal file
View File

@ -0,0 +1,70 @@
ARCH_FORMAT= coff-e1
BUILD_ROMS= $(ROMS)
BUILD_COFFS= $(patsubst %img, %coff, $(IMGS))
SUFFIXES+= rom zrom coff
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
# DMAC_HW_ADDR_DRV holds the ethernet's MAC address. It is passed as
# flag to the low level driver instead of reading it from an
# external EEPROM, which we do not have!
EXTRA_CFLAGS = -DEMBEDDED -DMAC_HW_ADDR_DRV="'H','Y','L','N','X','1'"
START= $(BIN)/start.o
START16= $(BIN)/start.o
SRCS+= arch/e1/core/e132_xs.c
SRCS+= arch/e1/core/e1_timer.c
SRCS+= arch/e1/core/longjmp.c
SRCS+= arch/e1/core/memcmp.S
SRCS+= arch/e1/core/memcpy.S
SRCS+= arch/e1/core/memset.S
SRCS+= arch/e1/core/setjmp.c
SRCS+= arch/e1/core/strcmp.S
SRCS+= arch/e1/core/start.S
ROMLIMIT:=3276800
include $(BIN)/Roms
ROMS= $(BIN)/cs89x0.rom
IMGS= $(BIN)/cs89x0.img
#allfiles: $(BUILD_ROMS)
all: $(BUILD_COFFS)
BOBJS+= $(BIN)/e1_timer.o
BOBJS+= $(BIN)/memcmp.o $(BIN)/memcpy.o $(BIN)/memset.o
BOBJS+= $(BIN)/setjmp.o $(BIN)/longjmp.o
BOBJS+= $(BIN)/e132_xs.o
# Utilities
$(BIN)/nrv2b: util/nrv2b.c
$(HOST_CC) -O2 -DENCODE -DDECODE -DMAIN -DVERBOSE -DNDEBUG -DBITSIZE=32 -DENDIAN=0 -o $@ $<
# Pattern Rules
# General for compiling/assembly source files
$(BIN)/cs89x0.o: drivers/net/cs89x0.c $(MAKEDEPS)
$(CC) $(CFLAGS) $(EXTRA_CFLAGS) -o $@ -c $<
# With the current tools we have problem with the compilation
# of the vsprintf file when the -O2 is selected. So we compile
# the aforemntioned file with -O1 !!!
$(BIN)/vsprintf.o: core/vsprintf.c $(MAKEDEPS)
$(CC) $(CFLAGS) -O1 -o $@ -c $<
$(BIN)/%.o: arch/e1/core/%.c $(MAKEDEPS)
$(CC) $(CFLAGS) -o $@ -c $<
$(BIN)/%.o: arch/e1/core/%.S $(MAKEDEPS)
$(CPP) $(CFLAGS) -D ASSEMBLY $< | $(AS) $(ASFLAGS) -o $@
$(BIN)/%.coff: $(BIN)/%.tmp $(MAKEDEPS)
mv $< $(BIN)/etherboot.coff

View File

@ -0,0 +1,67 @@
ARCH_FORMAT= coff-e1
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
EXTRA_CFLAGS = -DEMBEDDED -DMAC_HW_ADDR_DRV="'H','Y','L','N','X','1'"
BUILD_ROMS= $(ROMS)
BUILD_COFFS= $(BIN)/cs89x0.coff
#BUILD_COFFS= $(patsubst %img, %coff, $(IMGS))
START= $(BIN)/start.o
START16= $(BIN)/start.o
#SRCS+= arch/e1/core/coff_loader.c
SRCS+= arch/e1/core/e132_xs.c
SRCS+= arch/e1/core/e1_timer.c
SRCS+= arch/e1/core/longjmp.c
SRCS+= arch/e1/core/memcmp.S
SRCS+= arch/e1/core/memcpy.S
SRCS+= arch/e1/core/memset.S
SRCS+= arch/e1/core/setjmp.c
SRCS+= arch/e1/core/strcmp.S
SRCS+= arch/e1/core/start.S
ROMLIMIT:=3276800
include $(BIN)/Roms
hyperstone: $(BUILD_COFFS)
coff: $(BUILD_COFFS)
BOBJS+= $(BIN)/e1_timer.o
BOBJS+= $(BIN)/memcmp.o $(BIN)/memcpy.o $(BIN)/memset.o
BOBJS+= $(BIN)/setjmp.o $(BIN)/longjmp.o
BOBJS+= $(BIN)/e132_xs.o
# Utilities
$(BIN)/nrv2b: util/nrv2b.c
$(HOST_CC) -O2 -DENCODE -DDECODE -DMAIN -DVERBOSE -DNDEBUG -DBITSIZE=32 -DENDIAN=0 -o $@ $<
# Pattern Rules
# General for compiling/assembly source files
$(BIN)/cs89x0.o: drivers/net/cs89x0.c $(MAKEDEPS)
$(CC) $(CFLAGS) $(EXTRA_CFLAGS) -o $@ -c $<
# With the current tools we have problem with the compilation
# of the vsprintf file when the -O2 is selected. So we compile
# the aforemntioned file with -O1 !!!
$(BIN)/vsprintf.o: core/vsprintf.c $(MAKEDEPS)
$(CC) $(CFLAGS) -O1 -o $@ -c $<
$(BIN)/%.o: arch/e1/core/%.c $(MAKEDEPS)
$(CC) $(CFLAGS) -o $@ -c $<
$(BIN)/%.o: arch/e1/core/%.S $(MAKEDEPS)
$(CPP) $(CFLAGS) -D ASSEMBLY $< | $(AS) $(ASFLAGS) -o $@
$(BIN)/%.coff: $(BIN)/%.tmp $(MAKEDEPS)
mv $< $(BIN)/etherboot.coff

80
src/arch/e1/README Normal file
View File

@ -0,0 +1,80 @@
Introduction
---------------------
This README file provides guideliness to compile successfully the
Etherboot for Hyperstone.
This directory (src/arch/e1) contains the files that depend on
Hyperstone's architecture. The header files that include the
configuration of the system are based on Hyperstone's E132-XS
development board. The can be very easily modified to support
anyother configuration environment.
Software Perquisites:
---------------------
The build environment requires a C compiler for the E1-32XS
processor. Normally you can simply install a cross-compiling tool
chain based on the GNU tools (that is binutils and gcc). If you
are running a Linux system on a x86 CPU then you can just download
the toolchain as a binary from Hyperstone's official web-site. The
binary distribution will untar the tools in the /usr/local/e1-coff
directory. On any other system you will need to build the tool
chain from the sources.
To compile successfully the following tools should be available:
- GNU toolchain:
- GCC ver 2.95.2 20030110 (release) e1-coff-gcc -v
- LD ver 2.12.90 20020726 e1-coff-ld -V
Hardware Perquisites:
---------------------
The etherboot has been successfully tested in the E1-32XS
development board. A second serial device is initialized
to act as a console. The standard messages
are redirected to the console. Nevertheless, if one wants not
to use the serial console he may omit the corresponding switches
from the Config file located under "src/arch/e1/" directory.
On the E1-32XS board that was used, a daughter-board was employed
to connect a second HyIce to the development board. Since the HyIce
embeds a standard 16550 device, the Etherboot's standard device
driver is used.
The position of the jumpers of the development board in order to
initialize both the second HyIce and the Ethernet device is
depicted in the following table:
Jumper: Position
------:--------------
J3 1-2 (default)
J4 1-2 (default)
J13 5-6
J5 1-2 (default)
J6 1-2 & 3-4
J7 3-4
J9 1-2 (default)
J10 1-2
J11 3-4
Compilation
---------------------
In order to compile Etherboot for Hyperstone, the following steps should be followed:
1) Edit the main Makefile (located under "src" directory") and comment-out
the ARCH variable (by putting a "#" in front of it). Append the following line:
ARCH:=e1
2) Edit the Config file (the one located under "src" directory) and make sure that
the CFLAGS variable will contain *only* the following swithces:
CFLAGS+= -DCONFIG_ISA
CFLAGS+= -DBOOT_FIRST=BOOT_NIC
CFLAGS+= -DALLOW_ONLY_ENCAPSULATED
CFLAGS+= -DBACKOFF_LIMIT=7 -DCONGESTED
CFLAGS+= -DCOFF_IMAGE
CFLAGS+= -DDOWNLOAD_PROTO_TFTP
Please note that extra or any other switches may cause failure of compilation!
3) type "make hyperstone" or "make coff"
4) the generated file will be located under the "src/bin" directory and will be called :
"etherboot.coff". Now you may download it with usual way using e1-coff-gdb ..
Have Fun
Yannis Mitsos, George Thanos
{gmitsos,gthanos}@telecom.ntua.gr

View File

@ -0,0 +1,176 @@
/*
* Copyright 2003 Yannis Mitsos and George Thanos
* {gmitsos@gthanos}@telecom.ntua.gr
* Released under GPL2, see the file COPYING in the top directory
* COFF loader is based on the source code of the ELF loader.
*
*/
#include "coff.h"
#define COFF_DEBUG 0
typedef struct {
COFF_filehdr coff32;
COFF_opthdr opthdr32;
union {
COFF_scnhdr scnhdr32[1];
unsigned char dummy[1024];
} p;
unsigned long curaddr;
signed int segment; /* current segment number, -1 for none */
unsigned int loc; /* start offset of current block */
unsigned int skip; /* padding to be skipped to current segment */
unsigned long toread; /* remaining data to be read in the segment */
}coff_state;
coff_state cstate;
static sector_t coff32_download(unsigned char *data, unsigned int len, int eof);
static inline os_download_t coff_probe(unsigned char *data, unsigned int len)
{
unsigned long phdr_size;
if (len < (sizeof(cstate.coff32)+ sizeof(cstate.opthdr32))) {
return 0;
}
memcpy(&cstate.coff32, data, (sizeof(cstate.coff32)+sizeof(cstate.opthdr32)));
if ((cstate.coff32.f_magic != EM_E1) ||
(cstate.opthdr32.magic != O_MAGIC)){
return 0;
}
printf("(COFF");
printf(")... \n");
if (cstate.coff32.f_opthdr == 0){
printf("No optional header in COFF file, cannot find the entry point\n");
return dead_download;
}
phdr_size = cstate.coff32.f_nscns * sizeof(cstate.p.scnhdr32);
if (sizeof(cstate.coff32) + cstate.coff32.f_opthdr + phdr_size > len) {
printf("COFF header outside first block\n");
return dead_download;
}
memcpy(&cstate.p.scnhdr32, data + (sizeof(cstate.coff32) + cstate.coff32.f_opthdr), phdr_size);
/* Check for Etherboot related limitations. Memory
* between _text and _end is not allowed.
* Reasons: the Etherboot code/data area.
*/
for (cstate.segment = 0; cstate.segment < cstate.coff32.f_nscns; cstate.segment++) {
unsigned long start, mid, end, istart, iend;
if ((cstate.p.scnhdr32[cstate.segment].s_flags != S_TYPE_TEXT) &&
(cstate.p.scnhdr32[cstate.segment].s_flags != S_TYPE_DATA) &&
(cstate.p.scnhdr32[cstate.segment].s_flags != S_TYPE_BSS)){ /* Do we realy need to check the BSS section ? */
#ifdef COFF_DEBUG
printf("Section <%s> in not a loadable section \n",cstate.p.scnhdr32[cstate.segment].s_name);
#endif
continue;
}
start = cstate.p.scnhdr32[cstate.segment].s_paddr;
mid = start + cstate.p.scnhdr32[cstate.segment].s_size;
end = start + cstate.p.scnhdr32[cstate.segment].s_size;
/* Do we need the following variables ? */
istart = 0x8000;
iend = 0x8000;
if (!prep_segment(start, mid, end, istart, iend)) {
return dead_download;
}
}
cstate.segment = -1;
cstate.loc = 0;
cstate.skip = 0;
cstate.toread = 0;
return coff32_download;
}
extern int mach_boot(unsigned long entry_point);
static sector_t coff32_download(unsigned char *data, unsigned int len, int eof)
{
unsigned long skip_sectors = 0;
unsigned int offset; /* working offset in the current data block */
int i;
offset = 0;
do {
if (cstate.segment != -1) {
if (cstate.skip) {
if (cstate.skip >= len - offset) {
cstate.skip -= len - offset;
break;
}
offset += cstate.skip;
cstate.skip = 0;
}
if (cstate.toread) {
unsigned int cplen;
cplen = len - offset;
if (cplen >= cstate.toread) {
cplen = cstate.toread;
}
memcpy(phys_to_virt(cstate.curaddr), data+offset, cplen);
cstate.curaddr += cplen;
cstate.toread -= cplen;
offset += cplen;
if (cstate.toread)
break;
}
}
/* Data left, but current segment finished - look for the next
* segment (in file offset order) that needs to be loaded.
* We can only seek forward, so select the program headers,
* in the correct order.
*/
cstate.segment = -1;
for (i = 0; i < cstate.coff32.f_nscns; i++) {
if ((cstate.p.scnhdr32[i].s_flags != S_TYPE_TEXT) &&
(cstate.p.scnhdr32[i].s_flags != S_TYPE_DATA))
continue;
if (cstate.p.scnhdr32[i].s_size == 0)
continue;
if (cstate.p.scnhdr32[i].s_scnptr < cstate.loc + offset)
continue; /* can't go backwards */
if ((cstate.segment != -1) &&
(cstate.p.scnhdr32[i].s_scnptr >= cstate.p.scnhdr32[cstate.segment].s_scnptr))
continue; /* search minimum file offset */
cstate.segment = i;
}
if (cstate.segment == -1) {
/* No more segments to be loaded, so just start the
* kernel. This saves a lot of network bandwidth if
* debug info is in the kernel but not loaded. */
goto coff_startkernel;
break;
}
cstate.curaddr = cstate.p.scnhdr32[cstate.segment].s_paddr;
cstate.skip = cstate.p.scnhdr32[cstate.segment].s_scnptr - (cstate.loc + offset);
cstate.toread = cstate.p.scnhdr32[cstate.segment].s_size;
#if COFF_DEBUG
printf("PHDR %d, size %#lX, curaddr %#lX\n",
cstate.segment, cstate.toread, cstate.curaddr);
#endif
} while (offset < len);
cstate.loc += len + (cstate.skip & ~0x1ff);
skip_sectors = cstate.skip >> 9;
cstate.skip &= 0x1ff;
if (eof) {
unsigned long entry;
coff_startkernel:
entry = cstate.opthdr32.entry;
done();
mach_boot(entry);
}
return skip_sectors;
}

View File

@ -0,0 +1,70 @@
/*
* Copyright 2003 Yannis Mitsos and George Thanos
* {gmitsos@gthanos}@telecom.ntua.gr
* Released under GPL2, see the file COPYING in the top directory
*
*/
#include "hooks.h"
#include "io.h"
#include "etherboot.h"
#include "e132_xs_board.h"
unsigned int io_periph[NR_CS] = {[0 ... NR_CS-1] = 0 };
/*
void arch_main(struct Elf_Bhdr *ptr __unused)
{
}
*/
void init_peripherals(void)
{
int i;
for(i=0; i< NR_CS; i++){
io_periph[i]= (SLOW_IO_ACCESS | i << 22);
}
io_periph[ETHERNET_CS] = (io_periph[ETHERNET_CS] | 1 << IOWait);
asm volatile("
ori SR, 0x20
movi FCR, 0x66ffFFFF"
:
:);
}
struct meminfo meminfo;
void get_memsizes(void)
{
/* We initialize the meminfo structure
* according to our development board's specs
* We do not have a way to automatically probe the
* memspace instead we initialize it manually
*/
meminfo.basememsize = BASEMEM;
meminfo.memsize = SDRAM_SIZE;
meminfo.map_count = NR_MEMORY_REGNS;
meminfo.map[0].addr = SDRAM_BASEMEM;
meminfo.map[0].size = SDRAM_SIZE;
meminfo.map[0].type = E820_RAM;
meminfo.map[1].addr = SRAM_BASEMEM;
meminfo.map[1].size = SRAM_SIZE;
meminfo.map[1].type = E820_RAM;
meminfo.map[2].addr = IRAM_BASEMEM;
meminfo.map[2].size = IRAM_SIZE;
meminfo.map[2].type = E820_RAM;
}
int mach_boot(register unsigned long entry_point)
{
asm volatile(
"mov PC, %0"
: /* no outputs */
: "l" (entry_point) );
return 0; /* We should never reach this point ! */
}

View File

@ -0,0 +1,94 @@
/*
* Copyright 2003 Yannis Mitsos and George Thanos
* {gmitsos@gthanos}@telecom.ntua.gr
* Released under GPL2, see the file COPYING in the top directory
*
*/
#include "etherboot.h"
#include "timer.h"
#include "e132_xs_board.h"
/* get timer returns the contents of the timer */
static inline unsigned long get_timer(void)
{
unsigned long result;
__asm__ __volatile__("
ORI SR, 0x20
mov %0, TR"
: "=l"(result));
return result;
}
/* ------ Calibrate the TSC -------
* Time how long it takes to excute a loop that runs in known time.
* And find the convertion needed to get to CLOCK_TICK_RATE
*/
static unsigned long configure_timer(void)
{
unsigned long TPR_value; /* Timer Prescalar Value */
TPR_value = 0x000C00000;
asm volatile ("
FETCH 4
ORI SR, 0x20
MOV TPR, %0
ORI SR, 0x20
MOVI TR, 0x0"
: /* no outputs */
: "l" (TPR_value)
);
printf("The time prescaler register is set to: <%#x>\n",TPR_value);
return (1);
}
static unsigned long clocks_per_tick;
void setup_timers(void)
{
if (!clocks_per_tick) {
clocks_per_tick = configure_timer();
}
}
unsigned long currticks(void)
{
return get_timer()/clocks_per_tick;
}
static unsigned long timer_timeout;
static int __timer_running(void)
{
return get_timer() < timer_timeout;
}
void udelay(unsigned int usecs)
{
unsigned long now;
now = get_timer();
timer_timeout = now + usecs * ((clocks_per_tick * TICKS_PER_SEC)/(1000*1000));
while(__timer_running());
}
void ndelay(unsigned int nsecs)
{
unsigned long now;
now = get_timer();
timer_timeout = now + nsecs * ((clocks_per_tick * TICKS_PER_SEC)/(1000*1000*1000));
while(__timer_running());
}
void load_timer2(unsigned int timer2_ticks)
{
unsigned long now;
unsigned long clocks;
now = get_timer();
clocks = timer2_ticks * ((clocks_per_tick * TICKS_PER_SEC)/CLOCK_TICK_RATE);
timer_timeout = now + clocks;
}
int timer2_running(void)
{
return __timer_running();
}

View File

@ -0,0 +1,126 @@
/* Default linker script, for normal executables */
OUTPUT_FORMAT("coff-e1-big")
MEMORY
{
romvec : ORIGIN = 0x2000000, LENGTH = 0x0000400
flash : ORIGIN = 0xE0000000, LENGTH = 0x20000
eflash : ORIGIN = 0x2200000, LENGTH = 0x20000
ram : ORIGIN = 0x00000000, LENGTH = 0x1000000
eram16MB : ORIGIN = 0x01000000, LENGTH = 0
sram : ORIGIN = 0x40000000, LENGTH = 0x40000
iram : ORIGIN = 0xC0000000, LENGTH = 0x4000
}
SEARCH_DIR("/usr/local/e1-coff/lib");
ENTRY(Main)
MEM0start = 0x00000000;
MEM0size = 0x40000000;
MEM1start = 0x40000000;
MEM1size = 0x40000000;
MEM2start = 0x80000000;
MEM2size = 0x40000000;
IRAMstart = 0xC0000000;
IRAMsize = 0x20000000;
MEM3start = 0xE0000000;
MEM3size = 0x20000000;
Stack1Reserve = 560;
_Stack1Size = DEFINED(_Stack1Size)? _Stack1Size : 1*1024;
_Stack2Size = DEFINED(_Stack2Size)? _Stack2Size : 16*1024;
_Stack1Base = DEFINED(_Stack1Base)? _Stack1Base : __bss_end__;
_Stack2Base = DEFINED(_Stack2Base)? _Stack2Base : __bss_end__ + _Stack1Size + Stack1Reserve;
_Mem0HeapBase = DEFINED(_Mem0HeapBase)? _Mem0HeapBase : _Stack2Base + _Stack2Size;
_Mem1HeapBase = DEFINED(_Mem1HeapBase)? _Mem1HeapBase : 0;
Priority = DEFINED(Priority) ? Priority : 31;
TextBase = DEFINED(TextBase) ? TextBase : 0xa00000;
SECTIONS
{
.G6 (DEFINED(G6Base) ? G6Base : 0x9000) : {
*(.G6)
}
.G7 (DEFINED(G7Base) ? G7Base : 0x40001000) : {
*(.G7)
}
.G8 (DEFINED(G8Base) ? G8Base : 0xC0000000) : {
*(.G8)
}
.G9 (DEFINED(G9Base) ? G9Base : 0) : {
*(.G9)
}
.G10 (DEFINED(G10Base) ? G10Base : 0) : {
*(.G10)
}
.G11 (DEFINED(G11Base) ? G11Base : 0) : {
*(.G11)
}
.G12 (DEFINED(G12Base) ? G12Base : 0) : {
*(.G12)
}
.G13 (DEFINED(G13Base) ? G13Base : 0) : {
*(.G13)
}
.text TextBase : {
__virt_start = .;
__text = . ;
*(.text)
*(.fini)
. = ALIGN(16);
_isa_drivers = . ;
*(.drivisa);
_isa_drivers_end = . ;
. = ALIGN(16);
*(.init)
_etext = . ;
/* _init = DEFINED(_init) ? _init : 0; */
/* _fini = DEFINED(_fini) ? _fini : 0; */
/* _argc = DEFINED(_argc) ? _argc : 0; */
/* _argv = DEFINED(_argv) ? _argv : 0; */
/* _envp = DEFINED(_envp) ? _envp : 0; */
/* _hwinit = DEFINED(_hwinit) ? _hwinit : 0; */
/* _atexit = DEFINED(_atexit) ? _atexit : 0; */
G6Size = SIZEOF(.G6);
G7Size = SIZEOF(.G7);
G8Size = SIZEOF(.G8);
G9Size = SIZEOF(.G9);
G10Size = SIZEOF(.G10);
G11Size = SIZEOF(.G11);
G12Size = SIZEOF(.G12);
G13Size = SIZEOF(.G13);
}
.data SIZEOF(.text) + ADDR(.text) : {
*(.data)
_edata = . ;
}
.bss SIZEOF(.data) + ADDR(.data) :
{
__bss_start__ = ALIGN( 0x10 ) ;
__bss = . ;
*(.bss)
*(COMMON)
__end = . ;
__bss_end__ = ALIGN( 0x10 ) ;
__ebss = . ;
}
.eram16MB :
{
___ramend = . - 0x7000;
} > eram16MB
.stab 0 (NOLOAD) :
{
[ .stab ]
}
.stabstr 0 (NOLOAD) :
{
[ .stabstr ]
}
_GOT_ 0 (NOLOAD) :
{
[ _GOT_ ]
}
}

View File

@ -0,0 +1,35 @@
/*
* Copyright 2003 Yannis Mitsos and George Thanos
* {gmitsos@gthanos}@telecom.ntua.gr
* Released under GPL2, see the file COPYING in the top directory
*
*/
#include "setjmp.h"
unsigned long jmpbuf_ptr;
void longjmp(jmp_buf state, int value )
{
if(!value)
state->__jmpbuf->ReturnValue = 1;
else
state->__jmpbuf->ReturnValue = value;
jmpbuf_ptr = (unsigned long)state;
#define _state_ ((struct __jmp_buf_tag*)jmpbuf_ptr)
asm volatile("mov L0, %0\n\t"
"mov L1, %1\n\t"
"mov L2, %2\n\t"
"mov G3, %3\n\t"
"mov G4, %4\n\t"
"ret PC, L1\n\t"
:/*no output*/
:"l"(_state_->__jmpbuf->ReturnValue),
"l"(_state_->__jmpbuf->SavedPC),
"l"(_state_->__jmpbuf->SavedSR),
"l"(_state_->__jmpbuf->G3),
"l"(_state_->__jmpbuf->G4)
:"%G3", "%G4", "%L0", "%L1" );
#undef _state_
}

54
src/arch/e1/core/memcmp.S Normal file
View File

@ -0,0 +1,54 @@
/*
* Derived from the Hyperstone's library source code.
* Modefied src in order to apply the -mgnu-param compiler option.
* Copyright (C) 2002-2003 GDT, Yannis Mitsos <gmitsos@telecom.ntua.gr>
* George Thanos <gthanos@telecom.ntua.gr>
*/
.text
.align 2
.global _memcmp
;ENTRY (_memcmp)
_memcmp:
FRAME L9, L3 # get incoming parameters
CMPBI L2,3 # check word alignment
BNZ byte_compare
CMPBI L1,3 # check word alignment
BNZ byte_compare
double_compare:
ADDI L0, -8
BLT is_equal
LDD.P L1, L5
LDD.P L2, L7
SUB L5, L7
DBNZ corr_8
SUB L6, L8
BZ double_compare
ADDI L0, 4
ADDI L2, -4
ADDI L1, -4
BR byte_compare
corr_8: ADDI L0, 8
ADDI L2, -8
ADDI L1, -8
byte_compare:
ADDI L0, -1
BLT equal
LDBU.N L2, L5, 1 # Load and compare bytes
LDBU.N L1, L6, 1
SUB L5, L6
BZ byte_compare
MOV L2, L5
RET PC, L3
is_equal: CMPI L0, -8
DBNE byte_compare
ADDI L0, 8
equal:
MOVI L2, 0
RET PC, L3
.END

79
src/arch/e1/core/memcpy.S Normal file
View File

@ -0,0 +1,79 @@
/*
* Derived from the Hyperstone's library source code.
* Modefied src in order to apply the -mgnu-param compiler option.
* Copyright (C) 2002-2003 GDT, Yannis Mitsos <gmitsos@telecom.ntua.gr>
* George Thanos <gthanos@telecom.ntua.gr>
*/
.text
.align 2
.global _memcpy
;ENTRY(_memcpy)
_memcpy:
FRAME L8, L3
MOV L7, L2 # Save for return
#*****************************
# Perform byte copy if both
# not on a word alignment
#*****************************
CMPBI L2, 3 # check word alignment
BNZ mem_except
CMPBI L1, 3 # check word alignment
BNZ mem_except
#*****************************
# Copy Double,Word,Halfword,
# then byte
#*****************************
DBL_LOOP:
CMPI L0, 8 # Copy Doubles
BLT DO_WORD
LDD.P L1, L5
ADDI L0, -8
DBR DBL_LOOP
STD.P L2, L5
DO_WORD:
CMPI L0, 4 # Copy leftover word
BLT DO_HALF
LDW.P L1, L5
ADDI L0, -4
DBZ DONE # Done if L0 is 0
STW.P L2, L5
DO_HALF:
CMPI L0, 2 # Copy leftover byte
BLT DO_BYTE
LDHU.N L1, L5, 2
ADDI L0, -2
DBZ DONE # Done if L0 is 0
STHU.N L2, L5, 2
DO_BYTE:
CMPI L0, 1 # Copy leftover byte
BLT DONE
LDBU.D L1, L5, 0
STBU.D L2, L5, 0
DONE: # Copy done
MOV L2, L7 # Return pointer
RET PC, L3
#****************************
# Byte memcpy
#****************************
mem_except:
DBR L_5
MOVI L6,0
L_3:
LDBS.D L1, L5, 0 # Transfer the byte
ADDI L6, 1
STBS.D L2, L5, 0
ADDI L2, 1
ADDI L1, 1
L_5: # Loop test
CMP L6, L0
BST L_3
MOV L2, L7 # Return pointer
RET PC, L3
.END

47
src/arch/e1/core/memset.S Normal file
View File

@ -0,0 +1,47 @@
/*
* Derived from the Hyperstone's library source code.
* Modefied src in order to apply the -mgnu-param compiler option.
* Copyright (C) 2002-2003 GDT, Yannis Mitsos <gmitsos@telecom.ntua.gr>
* George Thanos <gthanos@telecom.ntua.gr>
*/
.text
.align 2
.global _memset
;ENTRY(_memset)
_memset: FRAME L9, L3
MASK L5, L1, 0xFF
MOV L8, L2
CMPI L0, 0 # if n = 0 then return
BE retour
loop0: CMPBI L8, 0x3
BZ word_bound
ADDI L0, -1
DBNZ loop0
STBU.N L8, L5, 1
retour: RET PC, L3
word_bound:
CMPI L0, 8
DBLT loop2
MOV L7, L5
SHLI L7, 8
OR L5, L7
MOV L7, L5
SHLI L7, 16
OR L5, L7
MOV L6, L5
loop1: ADDI L0, -8
CMPI L0, 8
DBGE loop1
STD.P L8, L5
CMPI L0, 0
DBNZ loop2
ANDNI L5, ~ 0xFF
RET PC, L3
loop2: ADDI L0, -1
DBNZ loop2
STBU.N L8, L5, 1
RET PC, L3

26
src/arch/e1/core/setjmp.c Normal file
View File

@ -0,0 +1,26 @@
/*
* Copyright 2003 Yannis Mitsos and George Thanos
* {gmitsos@gthanos}@telecom.ntua.gr
* Released under GPL2, see the file COPYING in the top directory
*
*/
#include "setjmp.h"
int setjmp( jmp_buf state)
{
asm volatile( "mov %0, G3\n\t"
"mov %1, G4\n\t"
:"=l"(state->__jmpbuf->G3),
"=l"(state->__jmpbuf->G4)
:/*no input*/
:"%G3", "%G4" );
asm volatile( "setadr %0\n\t"
"mov %1, L1\n\t"
"mov %2, L2\n\t"
:"=l"(state->__jmpbuf->SavedSP),
"=l"(state->__jmpbuf->SavedPC),
"=l"(state->__jmpbuf->SavedSR)
:/*no input*/);
return 0;
}

111
src/arch/e1/core/start.S Normal file
View File

@ -0,0 +1,111 @@
/*
* Derived from the Hyperstone's library source code.
* Copyright (C) 2002-2003 GDT, Yannis Mitsos <gmitsos@telecom.ntua.gr>
* George Thanos <gthanos@telecom.ntua.gr>
*/
.global Priority ; Task-Priority
.global _Stack1Size ; Size of hardware stack
.global _Stack2Size ; Size of aggregate stack
.global _Stack1Base ; Base of hardware stack
.global _Stack2Base ; Base of aggregate stack
.global _Mem0HeapBase ; Base of Heap in Mem0
.global _Mem1HeapBase ; Base of Heap in Mem1
.global _init_peripherals
.global _main
.global Main
.global __exit
.global __fmode
.global __MaxArgCount
.text
BasePtrs:
.weak G6Base,G7Base,G8Base,G9Base,G10Base,G11Base,G12Base,G13Base
.long G6Base,G7Base,G8Base,G9Base,G10Base,G11Base,G12Base,G13Base
BasePtrsEnd:
HeapPtrs:
.long _Mem0HeapBase
.long _Mem1HeapBase
HeapPtrsEnd:
__MaxArgCount:
.long 32
__StandAloneMode:
.long 0 ; 0 indicate stand alone mode
;============================================================================;
; Startup-Code ;
;============================================================================;
.data
; do not change the order of: __argc,..
__argc:
.long 0
__argv:
.long 0
__IsShell:
.long 1
ErrorLevel:
.long 0
__lab:
.long 0
__fmode:
.long 0x4000 ; O_TEXT attribute
_isa_drivers:
.long 0
_isa_drivers_end:
.long 0
.text
Main:
StartUp:
FRAME L5, L0
MOVI L2, __bss_start__ ; clear the .bss segment
0: CMPI L2, __bss_end__
BHE 0f
DBR 0b
STW.P L2, 0
0: SUM L2, PC, BasePtrs-$ ; Load BasePtrs G6-G13
LDD.P L2, G6
LDD.P L2, G8
; LDD.P L2, G10
LDD.P L2, G12
MOVI L2, 1
SUM L3, PC, __StandAloneMode-$
STW.R L3, L2
;----------------------------------------------------------------;
; Call main C function ;
;----------------------------------------------------------------;
2: LDW.D PC, L2, __argc - $ ; pass count of arguments to main
LDW.D PC, L3, __argv - $ ; pass pointer array to main
CALL L4, PC, _init_peripherals - $
CALL L4, PC, _main - $ ; --> Call Main-Program
CHK PC, PC ; trap if execution arrives here
__exit:
FRAME L5, L1
STW.D PC, L0, ErrorLevel - $ ; Store ERRORLEVEL
CHK PC, PC
RET PC, L1
.global ___main
___main:
FRAME L4, L1
MOVI L3, 2
STW.D PC, L3, __StandAloneMode-$
RET PC, L1 ; does not return
.section _GOT_
.long Main+4 ; OnCreate
.long Main+8 ; OnError
.long BasePtrs ; G6
.long BasePtrs+4 ; G7
.long BasePtrs+8 ; G8
.END

76
src/arch/e1/core/strcmp.S Normal file
View File

@ -0,0 +1,76 @@
/*
* Derived from the Hyperstone's library source code.
* Modefied src in order to apply the -mgnu-param compiler option.
* Copyright (C) 2002-2003 GDT, Yannis Mitsos <gmitsos@telecom.ntua.gr>
* George Thanos <gthanos@telecom.ntua.gr>
*/
.text
.align 2
.global _strcmp
;ENTRY(_strcmp)
_strcmp:
FRAME L8,L2
CMPBI L1, 3 # check for word alignment
BNZ str_except
CMPBI L0, 3 # check for word alignment
BNZ str_except
start:
LDD.P L1, L4 # post inc mode
LDD.P L0, L6 # post inc mode
CMPBI L4, ANYBZ
BE correct1
CMP L4, L6
BNE correct1
CMP L5, L7
BNE correct
CMPBI L5, ANYBZ
BE correct
CMPBI L6, ANYBZ
BE correct1
CMPBI L7, ANYBZ
BNE start
correct: MASK L4, L5, 0xff000000
MASK L6, L7, 0xff000000
CMP L4, L6
BNE Exit
SHLI L5, 8
CMPI L4, 0
DBNE correct
SHLI L7, 8
MOV L1, L4
RET PC, L2
Exit: SUB L4, L6 # Subtract chars
SARI L4, 24
MOV L1, L4
RET PC, L2
correct1: MASK L5, L4, 0xff000000
MASK L7, L6, 0xff000000
CMP L5, L7
BNE Exit1
SHLI L4, 8
CMPI L5, 0
DBNE correct1
SHLI L6, 8
MOV L1, L5
RET PC, L2
Exit1: SUB L5, L7 # Subtract chars
SARI L5, 24
MOV L1, L5
RET PC, L2
testzero: CMPI L4, 0
BE L_5
str_except:
LDBU.N L1, L4, 1 # Load *s1, compare bytes
LDBU.N L0, L5, 1 # Load *s2, compare bytes
CMP L4, L5
BE testzero
SUB L4, L5 # Subtract chars
L_5: MOV L1, L4
RET PC, L2
.END

View File

@ -0,0 +1,39 @@
#ifndef ETHERBOOT_BITS_BYTESWAP_H
#define ETHERBOOT_BITS_BYTESWAP_H
/* We do not have byte swap functions ... We are
* RISC processor ...
*/
static inline unsigned short __swap16(volatile unsigned short v)
{
return ((v << 8) | (v >> 8));
}
static inline unsigned int __swap32(volatile unsigned long v)
{
return ((v << 24) | ((v & 0xff00) << 8) | ((v & 0xff0000) >> 8) | (v >> 24));
}
#define __bswap_constant_16(x) \
((uint16_t)((((uint16_t)(x) & 0x00ff) << 8) | \
(((uint16_t)(x) & 0xff00) >> 8)))
#define __bswap_constant_32(x) \
((uint32_t)((((uint32_t)(x) & 0x000000ffU) << 24) | \
(((uint32_t)(x) & 0x0000ff00U) << 8) | \
(((uint32_t)(x) & 0x00ff0000U) >> 8) | \
(((uint32_t)(x) & 0xff000000U) >> 24)))
#define __bswap_16(x) \
(__builtin_constant_p(x) ? \
__bswap_constant_16(x) : \
__swap16(x))
#define __bswap_32(x) \
(__builtin_constant_p(x) ? \
__bswap_constant_32(x) : \
__swap32(x))
#endif /* ETHERBOOT_BITS_BYTESWAP_H */

View File

@ -0,0 +1,6 @@
#ifndef E1_BITS_CPU_H
#define E1_BITS_CPU_H
#define cpu_setup() do {} while(0)
#endif /* E1_BITS_CPU_H */

View File

@ -0,0 +1,6 @@
#ifndef E1_BITS_ELF_H
#define E1_BITS_ELF_H
/* dummy file, needed for the compilation of core/nic.c */
#endif /* E1_BITS_ELF_H */

View File

@ -0,0 +1,6 @@
#ifndef ETHERBOOT_BITS_ENDIAN_H
#define ETHERBOOT_BITS_ENDIAN_H
#define __BYTE_ORDER __BIG_ENDIAN
#endif /* ETHERBOOT_BITS_ENDIAN_H */

View File

@ -0,0 +1,35 @@
#ifndef ETHERBOOT_BITS_STRING_H
#define ETHERBOOT_BITS_STRING_H
/* define inline optimized string functions here */
#define __HAVE_ARCH_MEMCPY
//extern void * memcpy(const void *d, const void *s, size_t count);
#define __HAVE_ARCH_MEMCMP
//extern int memcmp(const void * s ,const void * d ,size_t );
#define __HAVE_ARCH_MEMSET
//extern void * memset(const void * s, int c, size_t count);
#define __HAVE_ARCH_MEMMOVE
static inline void *memmove(void *s1, const void *s2, size_t n) {
unsigned int i;
char *tmp = s1;
char *cs2 = (char *) s2;
if (tmp < cs2) {
for(i=0; i<n; ++i, ++tmp, ++cs2)
*tmp = *cs2;
}
else {
tmp += n - 1;
cs2 += n - 1;
for(i=0; i<n; ++i, --tmp, --cs2)
*tmp = *cs2;
}
return(s1);
}
#endif /* ETHERBOOT_BITS_STRING_H */

View File

@ -0,0 +1,22 @@
#ifndef __E132_XS_BOARD_H
#define __E132_XS_BOARD_H
#define CONFIG_HYPERSTONE_OSC_FREQ_MHZ 15
#define NR_MEMORY_REGNS 3
#define BASEMEM 0x0
/* SDRAM mapping */
#define SDRAM_SIZE 0x01000000
#define SDRAM_BASEMEM BASEMEM
/* SRAM mapping */
#define SRAM_BASEMEM 0x40000000
#define SRAM_SIZE 0x0003FFFF
/* IRAM mapping */
#define IRAM_BASEMEM 0xC0000000
#define IRAM_SIZE 0x00003FFF
#endif /* __E132_XS_BOARD_H */

View File

@ -0,0 +1,9 @@
#ifndef ETHERBOOT_E1_HOOKS_H
#define ETHERBOOT_E1_HOOKS_H
#define arch_main(data,params) do {} while(0)
#define arch_on_exit(status) do {} while(0)
#define arch_relocate_to(addr) do {} while(0)
#define arch_relocated_from(old_addr) do {} while(0)
#endif /* ETHERBOOT_E1_HOOKS_H */

210
src/arch/e1/include/io.h Normal file
View File

@ -0,0 +1,210 @@
#ifndef ETHERBOOT_IO_H
#define ETHERBOOT_IO_H
/* Don't require identity mapped physical memory,
* osloader.c is the only valid user at the moment.
*/
#if 0
static inline unsigned long virt_to_phys(volatile const void *virt_addr)
{
return ((unsigned long)virt_addr);
}
#else
#define virt_to_phys(vaddr) ((unsigned long) (vaddr))
#endif
#if 0
static inline void *phys_to_virt(unsigned long phys_addr)
{
return (void *)(phys_addr);
}
#else
#define phys_to_virt(vaddr) ((void *) (vaddr))
#endif
/* virt_to_bus converts an addresss inside of etherboot [_start, _end]
* into a memory address cards can use.
*/
#define virt_to_bus virt_to_phys
/* bus_to_virt reverses virt_to_bus, the address must be output
* from virt_to_bus to be valid. This function does not work on
* all bus addresses.
*/
#define bus_to_virt phys_to_virt
#define iounmap(addr) ((void)0)
#define ioremap(physaddr, size) (physaddr)
#define IORegAddress 13
#define IOWait 11
#define IOSetupTime 8
#define IOAccessTime 5
#define IOHoldTime 3
#define SLOW_IO_ACCESS ( 0x3 << IOSetupTime | 0x0 << IOWait | 7 << IOAccessTime | 3 << IOHoldTime )
/* The development board can generate up to 15 Chip selects */
#define NR_CS 16
extern unsigned int io_periph[NR_CS];
#define ETHERNET_CS 4
static inline unsigned short _swapw(volatile unsigned short v)
{
return ((v << 8) | (v >> 8));
}
static inline unsigned int _swapl(volatile unsigned long v)
{
return ((v << 24) | ((v & 0xff00) << 8) | ((v & 0xff0000) >> 8) | (v >> 24));
}
#define hy_inpw(addr) \
({ register unsigned long dummy, dummy1; \
dummy = addr; \
asm volatile ("LDW.IOD %1, %0, 0" \
: "=l" (dummy1) \
: "l" (dummy)); dummy1; })
#define hy_outpw(x, addr) \
({ register unsigned long dummy0,dummy1; \
dummy0 = addr; \
dummy1 = x; \
asm volatile ("STW.IOD %1, %0, 0" \
: "=l" (dummy1) \
: "l"(dummy0), "l" (dummy1)); dummy1; })
#define readb(addr) ({ unsigned char __v = inregb(addr); __v; })
#define readw(addr) ({ unsigned short __v = inregw(addr); __v; })
#define readl(addr) ({ unsigned long __v = inregl(addr); __v; })
#define writeb(b,addr) (void)(outreg(b, addr))
#define writew(b,addr) (void)(outreg(b, addr))
#define writel(b,addr) (void)(outreg(b, addr))
static inline unsigned long common_io_access(unsigned long addr)
{
return io_periph[(addr & 0x03C00000) >> 22];
}
static inline volatile unsigned char inregb(volatile unsigned long reg)
{
unsigned char val;
val = hy_inpw(common_io_access(reg) | ((0xf & reg) << IORegAddress));
return val;
}
static inline volatile unsigned short inregw(volatile unsigned long reg)
{
unsigned short val;
val = hy_inpw(common_io_access(reg) | ((0xf & reg) << IORegAddress));
return val;
}
static inline volatile unsigned long inregl(volatile unsigned long reg)
{
unsigned long val;
val = hy_inpw(common_io_access(reg) | ((0xf & reg) << IORegAddress));
return val;
}
static inline void outreg(volatile unsigned long val, volatile unsigned long reg)
{
hy_outpw(val, (common_io_access(reg) | ((0xf & reg) << IORegAddress)));
}
static inline void io_outsb(unsigned int addr, void *buf, int len)
{
unsigned long tmp;
unsigned char *bp = (unsigned char *) buf;
tmp = (common_io_access(addr)) | ((0xf & addr) << IORegAddress);
while (len--){
hy_outpw(_swapw(*bp++), tmp);
}
}
static inline void io_outsw(volatile unsigned int addr, void *buf, int len)
{
unsigned long tmp;
unsigned short *bp = (unsigned short *) buf;
tmp = (common_io_access(addr)) | ((0xf & addr) << IORegAddress);
while (len--){
hy_outpw(_swapw(*bp++), tmp);
}
}
static inline void io_outsl(volatile unsigned int addr, void *buf, int len)
{
unsigned long tmp;
unsigned int *bp = (unsigned int *) buf;
tmp = (common_io_access(addr)) | ((0xf & addr) << IORegAddress);
while (len--){
hy_outpw(_swapl(*bp++), tmp);
}
}
static inline void io_insb(volatile unsigned int addr, void *buf, int len)
{
unsigned long tmp;
unsigned char *bp = (unsigned char *) buf;
tmp = (common_io_access(addr)) | ((0xf & addr) << IORegAddress);
while (len--)
*bp++ = hy_inpw((unsigned char) tmp);
}
static inline void io_insw(unsigned int addr, void *buf, int len)
{
unsigned long tmp;
unsigned short *bp = (unsigned short *) buf;
tmp = (common_io_access(addr)) | ((0xf & addr) << IORegAddress);
while (len--)
*bp++ = _swapw((unsigned short)hy_inpw(tmp));
}
static inline void io_insl(unsigned int addr, void *buf, int len)
{
unsigned long tmp;
unsigned int *bp = (unsigned int *) buf;
tmp = (common_io_access(addr)) | ((0xf & addr) << IORegAddress);
while (len--)
*bp++ = _swapl((unsigned int)hy_inpw(tmp));
}
#define inb(addr) readb(addr)
#define inw(addr) readw(addr)
#define inl(addr) readl(addr)
#define outb(x,addr) ((void) writeb(x,addr))
#define outw(x,addr) ((void) writew(x,addr))
#define outl(x,addr) ((void) writel(x,addr))
#define insb(a,b,l) io_insb(a,b,l)
#define insw(a,b,l) io_insw(a,b,l)
#define insl(a,b,l) io_insl(a,b,l)
#define outsb(a,b,l) io_outsb(a,b,l)
#define outsw(a,b,l) io_outsw(a,b,l)
#define outsl(a,b,l) io_outsl(a,b,l)
#define memcpy_fromio(a,b,c) memcpy((a),(void *)(b),(c))
#define memcpy_toio(a,b,c) memcpy((void *)(a),(b),(c))
#endif /* ETHERBOOT_IO_H */

View File

@ -0,0 +1,12 @@
#ifndef LATCH_H
#define LATCH_H
//#define TICKS_PER_SEC (1000000UL)
#define TICKS_PER_SEC (625000UL)
/* Fixed timer interval used for calibrating a more precise timer */
//#define LATCHES_PER_SEC 10
void sleep_latch(void);
#endif /* LATCH_H */

View File

@ -0,0 +1,34 @@
/*--------------------------------------------------------------------------*/
/* Project: ANSI C Standard Header Files */
/* File: LIMITS.H */
/* Edited by: hyperstone electronics GmbH */
/* Am Seerhein 8 */
/* D-78467 Konstanz, Germany */
/* Date: January 30, 1996 */
/*--------------------------------------------------------------------------*/
/* Purpose: */
/* The header file <limits.h> defines limits of ordinal types */
/* (char, short, int, long) */
/*--------------------------------------------------------------------------*/
#ifndef __LIMITS_H
#define __LIMITS_H 1
#define MB_LEN_MAX 1
#define CHAR_BIT 8
#define SCHAR_MIN -128L
#define SCHAR_MAX 127L
#define UCHAR_MAX 255
#define CHAR_MIN 0
#define CHAR_MAX UCHAR_MAX
#define SHRT_MIN -32768
#define SHRT_MAX 32767
#define USHRT_MAX 65535
#define INT_MIN 0x80000000
#define INT_MAX 0x7FFFFFFF
#define UINT_MAX 0xFFFFFFFFL
#define LONG_MIN INT_MIN
#define LONG_MAX INT_MAX
#define ULONG_MAX UINT_MAX
#endif

View File

@ -0,0 +1,23 @@
#ifndef _SETJMP_H
#define _SETJMP_H
typedef struct {
unsigned long G3;
unsigned long G4;
unsigned long SavedSP;
unsigned long SavedPC;
unsigned long SavedSR;
unsigned long ReturnValue;
} __jmp_buf[1];
typedef struct __jmp_buf_tag /* C++ doesn't like tagless structs. */
{
__jmp_buf __jmpbuf; /* Calling environment. */
int __mask_was_saved; /* Saved the signal mask? */
} jmp_buf[1];
void longjmp(jmp_buf state, int value );
int setjmp( jmp_buf state);
#endif

View File

@ -0,0 +1,16 @@
#ifndef STDINT_H
#define STDINT_H
typedef unsigned long size_t;
typedef unsigned char uint8_t;
typedef unsigned short uint16_t;
typedef unsigned long uint32_t;
typedef unsigned long long uint64_t;
typedef signed char int8_t;
typedef signed short int16_t;
typedef signed int int32_t;
typedef signed long long int64_t;
#endif /* STDINT_H */

131
src/arch/i386/Config Normal file
View File

@ -0,0 +1,131 @@
# Config for i386 Etherboot
#
# Do not delete the tag OptionDescription and /OptionDescription
# It is used to automatically generate the documentation.
#
# @OptionDescrition@
#
# BIOS interface options:
#
# -DPCBIOS
# Compile in support for the normal pcbios
# -DLINUXBIOS
# Compile in support for LinuxBIOS
# -DBBS_BUT_NOT_PNP_COMPLIANT
# Some BIOSes claim to be PNP but they don't conform
# to the BBS spec which specifies that ES:DI must
# point to the string $PnP on entry. This option
# works around those. This option must be added to
# LCONFIG.
# -DNO_DELAYED_INT
# Take control as soon as BIOS detects the ROM.
# Normally hooks onto INT18H or INT19H. Use only if you
# have a very non-conformant BIOS as it bypasses
# BIOS initialisation of devices. This only works for
# legacy ROMs, i.e. PCI_PNP_HEADER not defined.
# This option was formerly called NOINT19H.
# -DBOOT_INT18H
# Etherboot normally hooks onto INT19H for legacy ROMs.
# You can choose to hook onto INT18H (BASIC interpreter
# entry point) instead. This entry point is used when
# all boot devices have been exhausted. This option must
# be added to LCONFIG.
# -DCONFIG_PCI_DIRECT
# Define this for PCI BIOSes that do not implement
# BIOS32 or not correctly. Normally not needed.
# Only works for BIOSes of a certain era.
# -DCONFIG_TSC_CURRTICKS
# Uses the processor time stamp counter instead of reading
# the BIOS time counter. This allows Etherboot to work
# even without a BIOS. This only works on late model
# 486s and above.
# -DCONFIG_NO_TIMER2
# Some systems do not have timer2 implemented.
# If you have a RTC this will allow you to roughly calibrate
# it using outb instructions.
# -DIBM_L40
# This option uses the 0x92 method of controlling
# A20 instead of the traditional method of using the
# keyboard controller. An explanation of A20 is here:
# http://www.win.tue.nl/~aeb/linux/kbd/A20.html
# This occurs on MCA, EISA and some embedded boards,
# and sometimes with the Fast Gate A20 option on some
# BIOSes.
# Enable this only if you are sure of what you are doing.
#
# Extended cpu options
# -DCONFIG_X86_64
# Compile in support for booting x86_64 64bit binaries.
#
# PXE loader options:
#
# -DPXELOADER_KEEP_ALL
# Prevent PXE loader (prefix) from unloading the
# PXE stack. You will want to use this if, for
# example, you are booting via PXE-on-floppy.
# You may want to use it under certain
# circumstances when using the Etherboot UNDI
# driver; these are complex and best practice is
# not yet established.
#
# Obscure options you probably don't need to touch:
#
# -DIGNORE_E820_MAP
# Ignore the memory map returned by the E820 BIOS
# call. May be necessary on some buggy BIOSes.
# -DT503_AUI
# Use AUI by default on 3c503 cards.
# -DFLATTEN_REAL_MODE
# Use 4GB segment limits when calling out to or
# returning to real-mode code. This is necessary to
# work around some buggy code (e.g. OpenBSD's pxeboot)
# that uses flat real-mode without being sufficiently
# paranoid about the volatility of its segment limits.
#
# @/OptionDescription@
# BIOS select don't change unless you know what you are doing
CFLAGS+= -DPCBIOS
# Compile in k8/hammer support
# CFLAGS+= -DCONFIG_X86_64
# Options to make a version of Etherboot that will work under linuxBIOS.
# CFLAGS+= -DLINUXBIOS -DCONFIG_TSC_CURRTICKS -DCONSOLE_SERIAL -DCOMCONSOLE=0x3f8 -DCOMPRESERVE -DCONFIG_PCI_DIRECT -DELF_IMAGE
# These options affect the loader that is prepended to the Etherboot image
# LCONFIG+= -DBBS_BUT_NOT_PNP_COMPLIANT
# LCONFIG+= -DBOOT_INT18H
# Produce code that will work inside the Bochs emulator. The pnic
# driver is probably the best one to try.
# CFLAGS+= -DCONFIG_PCI_DIRECT
# Produce code that will work with OpenBSD's pxeboot
# CFLAGS+= -DFLATTEN_REAL_MODE
CFLAGS+= -fstrength-reduce -fomit-frame-pointer -march=i386
# Squeeze the code in as little space as possible.
# gcc3 needs a different syntax to gcc2 if you want to avoid spurious warnings.
GCC_VERSION = $(subst ., ,$(shell $(CC) -dumpversion))
GCC_MAJORVERSION = $(firstword $(GCC_VERSION))
ifeq ($(GCC_MAJORVERSION),2)
CFLAGS+= -malign-jumps=1 -malign-loops=1 -malign-functions=1
else
CFLAGS+= -falign-jumps=1 -falign-loops=1 -falign-functions=1
endif
GCC_MINORVERSION = $(word 2, $(GCC_VERSION))
ifneq ($(GCC_MINORVERSION),4)
CFLAGS+= -mcpu=i386
endif
LDFLAGS+= -N
ifeq "$(shell uname -s)" "FreeBSD"
CFLAGS+= -DIMAGE_FREEBSD -DELF_IMAGE -DAOUT_IMAGE
endif
# An alternate location for isolinux.bin can be set here
# ISOLINUX_BIN=/path/to/isolinux.bin

373
src/arch/i386/Makefile Normal file
View File

@ -0,0 +1,373 @@
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/unhuf.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 -D ASSEMBLY $< | $(AS) $(ASFLAGS) -o $@
$(BIN)/%.o: arch/i386/prefix/%.S $(MAKEDEPS)
$(CPP) $(CFLAGS) -Ui386 -D ASSEMBLY $< | $(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
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
# rule to make a floppy emulation ISO boot image
SUFFIXES += liso
%.liso: util/genliso %.zlilo
bash util/genliso $*.liso $*.zlilo

View File

@ -0,0 +1,144 @@
/* a.out */
struct exec {
unsigned long a_midmag; /* flags<<26 | mid<<16 | magic */
unsigned long a_text; /* text segment size */
unsigned long a_data; /* initialized data size */
unsigned long a_bss; /* uninitialized data size */
unsigned long a_syms; /* symbol table size */
unsigned long a_entry; /* entry point */
unsigned long a_trsize; /* text relocation size */
unsigned long a_drsize; /* data relocation size */
};
struct aout_state {
struct exec head;
unsigned long curaddr;
int segment; /* current segment number, -1 for none */
unsigned long loc; /* start offset of current block */
unsigned long skip; /* padding to be skipped to current segment */
unsigned long toread; /* remaining data to be read in the segment */
};
static struct aout_state astate;
static sector_t aout_download(unsigned char *data, unsigned int len, int eof);
static inline os_download_t aout_probe(unsigned char *data, unsigned int len)
{
unsigned long start, mid, end, istart, iend;
if (len < sizeof(astate.head)) {
return 0;
}
memcpy(&astate.head, data, sizeof(astate.head));
if ((astate.head.a_midmag & 0xffff) != 0x010BL) {
return 0;
}
printf("(a.out");
aout_freebsd_probe();
printf(")... ");
/* Check the aout image */
start = astate.head.a_entry;
mid = (((start + astate.head.a_text) + 4095) & ~4095) + astate.head.a_data;
end = ((mid + 4095) & ~4095) + astate.head.a_bss;
istart = 4096;
iend = istart + (mid - start);
if (!prep_segment(start, mid, end, istart, iend))
return dead_download;
astate.segment = -1;
astate.loc = 0;
astate.skip = 0;
astate.toread = 0;
return aout_download;
}
static sector_t aout_download(unsigned char *data, unsigned int len, int eof)
{
unsigned int offset; /* working offset in the current data block */
offset = 0;
#ifdef AOUT_LYNX_KDI
astate.segment++;
if (astate.segment == 0) {
astate.curaddr = 0x100000;
astate.head.a_entry = astate.curaddr + 0x20;
}
memcpy(phys_to_virt(astate.curaddr), data, len);
astate.curaddr += len;
return 0;
#endif
do {
if (astate.segment != -1) {
if (astate.skip) {
if (astate.skip >= len - offset) {
astate.skip -= len - offset;
break;
}
offset += astate.skip;
astate.skip = 0;
}
if (astate.toread) {
if (astate.toread >= len - offset) {
memcpy(phys_to_virt(astate.curaddr), data+offset,
len - offset);
astate.curaddr += len - offset;
astate.toread -= len - offset;
break;
}
memcpy(phys_to_virt(astate.curaddr), data+offset, astate.toread);
offset += astate.toread;
astate.toread = 0;
}
}
/* Data left, but current segment finished - look for the next
* segment. This is quite simple for a.out files. */
astate.segment++;
switch (astate.segment) {
case 0:
/* read text */
astate.curaddr = astate.head.a_entry;
astate.skip = 4096;
astate.toread = astate.head.a_text;
break;
case 1:
/* read data */
/* skip and curaddr may be wrong, but I couldn't find
* examples where this failed. There is no reasonable
* documentation for a.out available. */
astate.skip = ((astate.curaddr + 4095) & ~4095) - astate.curaddr;
astate.curaddr = (astate.curaddr + 4095) & ~4095;
astate.toread = astate.head.a_data;
break;
case 2:
/* initialize bss and start kernel */
astate.curaddr = (astate.curaddr + 4095) & ~4095;
astate.skip = 0;
astate.toread = 0;
memset(phys_to_virt(astate.curaddr), '\0', astate.head.a_bss);
goto aout_startkernel;
default:
break;
}
} while (offset < len);
astate.loc += len;
if (eof) {
unsigned long entry;
aout_startkernel:
entry = astate.head.a_entry;
done(1);
aout_freebsd_boot();
#ifdef AOUT_LYNX_KDI
xstart32(entry);
#endif
printf("unexpected a.out variant\n");
longjmp(restart_etherboot, -2);
}
return 0;
}

View File

@ -0,0 +1,107 @@
/* Callout/callback interface for Etherboot
*
* This file provides the mechanisms for making calls from Etherboot
* to external programs and vice-versa.
*
* Initial version by Michael Brown <mbrown@fensystems.co.uk>, January 2004.
*/
#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
* to its exit routine
*/
#define MAX_PREFIX_STACK_DATA 16
/* Prefix exit routine is defined in prefix object */
extern void prefix_exit ( void );
extern void prefix_exit_end ( void );
/*****************************************************************************
*
* IN_CALL INTERFACE
*
*****************************************************************************
*/
/* in_call(): entry point for calls in to Etherboot from external code.
*
* Parameters: some set up by assembly code _in_call(), others as
* passed from external code.
*/
uint32_t i386_in_call ( va_list ap, i386_pm_in_call_data_t pm_data,
uint32_t opcode ) {
uint32_t ret;
i386_rm_in_call_data_t rm_data;
in_call_data_t in_call_data = { &pm_data, NULL };
struct {
int data[MAX_PREFIX_STACK_DATA/4];
} in_stack;
/* Fill out rm_data if we were called from real mode */
if ( opcode & EB_CALL_FROM_REAL_MODE ) {
in_call_data.rm = &rm_data;
rm_data = va_arg ( ap, typeof(rm_data) );
/* Null return address indicates to use the special
* prefix exit mechanism, and that there are
* parameters on the stack that the prefix wants
* handed to its exit routine.
*/
if ( rm_data.ret_addr.offset == 0 ) {
int n = va_arg ( ap, int ) / 4;
int i;
for ( i = 0; i < n; i++ ) {
in_stack.data[i] = va_arg ( ap, int );
}
}
}
/* Hand off to main in_call() routine */
ret = in_call ( &in_call_data, opcode, ap );
/* If real-mode return address is null, it means that we
* should exit via the prefix's exit path, which is part of
* our image. (This arrangement is necessary since the prefix
* code itself may have been vapourised by the time we want to
* return.)
*/
if ( ( opcode & EB_CALL_FROM_REAL_MODE ) &&
( rm_data.ret_addr.offset == 0 ) ) {
real_call ( prefix_exit, &in_stack, NULL );
/* Should never return */
}
return ret;
}
#ifdef CODE16
/* install_rm_callback_interface(): install real-mode callback
* interface at specified address.
*
* Real-mode code may then call to this address (or lcall to this
* address plus RM_IN_CALL_FAR) in order to make an in_call() to
* Etherboot.
*
* Returns the size of the installed code, or 0 if the code could not
* be installed.
*/
int install_rm_callback_interface ( void *address, size_t available ) {
if ( available &&
( available < rm_callback_interface_size ) ) return 0;
/* Inform RM code where to find Etherboot */
rm_etherboot_location = virt_to_phys(_text);
/* Install callback interface */
memcpy ( address, &rm_callback_interface,
rm_callback_interface_size );
return rm_callback_interface_size;
}
#endif /* CODE16 */

86
src/arch/i386/core/cpu.c Normal file
View File

@ -0,0 +1,86 @@
#ifdef CONFIG_X86_64
#include "stdint.h"
#include "string.h"
#include "bits/cpu.h"
/* Standard macro to see if a specific flag is changeable */
static inline int flag_is_changeable_p(uint32_t flag)
{
uint32_t f1, f2;
asm("pushfl\n\t"
"pushfl\n\t"
"popl %0\n\t"
"movl %0,%1\n\t"
"xorl %2,%0\n\t"
"pushl %0\n\t"
"popfl\n\t"
"pushfl\n\t"
"popl %0\n\t"
"popfl\n\t"
: "=&r" (f1), "=&r" (f2)
: "ir" (flag));
return ((f1^f2) & flag) != 0;
}
/* Probe for the CPUID instruction */
static inline int have_cpuid_p(void)
{
return flag_is_changeable_p(X86_EFLAGS_ID);
}
static void identify_cpu(struct cpuinfo_x86 *c)
{
unsigned xlvl;
c->cpuid_level = -1; /* CPUID not detected */
c->x86_model = c->x86_mask = 0; /* So far unknown... */
c->x86_vendor_id[0] = '\0'; /* Unset */
memset(&c->x86_capability, 0, sizeof c->x86_capability);
if (!have_cpuid_p()) {
/* CPU doesn'thave CPUID */
/* If there are any capabilities, they'r vendor-specific */
/* enable_cpuid() would have set c->x86 for us. */
}
else {
/* CPU does have CPUID */
/* Get vendor name */
cpuid(0x00000000, &c->cpuid_level,
(int *)&c->x86_vendor_id[0],
(int *)&c->x86_vendor_id[8],
(int *)&c->x86_vendor_id[4]);
/* Initialize the standard set of capabilities */
/* Note that the vendor-specific code below might override */
/* Intel-defined flags: level 0x00000001 */
if ( c->cpuid_level >= 0x00000001 ) {
unsigned tfms, junk;
cpuid(0x00000001, &tfms, &junk, &junk,
&c->x86_capability[0]);
c->x86 = (tfms >> 8) & 15;
c->x86_model = (tfms >> 4) & 15;
c->x86_mask = tfms & 15;
}
/* AMD-defined flags: level 0x80000001 */
xlvl = cpuid_eax(0x80000000);
if ( (xlvl & 0xffff0000) == 0x80000000 ) {
if ( xlvl >= 0x80000001 )
c->x86_capability[1] = cpuid_edx(0x80000001);
}
}
}
struct cpuinfo_x86 cpu_info;
void cpu_setup(void)
{
identify_cpu(&cpu_info);
}
#endif /* CONFIG_X86_64 */

135
src/arch/i386/core/elf.c Normal file
View File

@ -0,0 +1,135 @@
#include "etherboot.h"
#include "elf.h"
#define NAME "Etherboot"
#if defined(PCBIOS)
#define FIRMWARE "PCBIOS"
#endif
#if defined(LINUXBIOS)
#define FIRMWARE "LinuxBIOS"
#endif
#if !defined(FIRMWARE)
#error "No BIOS selected"
#endif
#define SZ(X) ((sizeof(X)+3) & ~3)
#define CP(D,S) (memcpy(&(D), &(S), sizeof(S)))
struct elf_notes {
/* The note header */
struct Elf_Bhdr hdr;
/* First the Fixed sized entries that must be well aligned */
/* Pointer to bootp data */
Elf_Nhdr nf1;
char nf1_name[SZ(EB_PARAM_NOTE)];
uint32_t nf1_bootp_data;
/* Pointer to ELF header */
Elf_Nhdr nf2;
char nf2_name[SZ(EB_PARAM_NOTE)];
uint32_t nf2_header;
/* A copy of the i386 memory map */
Elf_Nhdr nf3;
char nf3_name[SZ(EB_PARAM_NOTE)];
struct meminfo nf3_meminfo;
/* Then the variable sized data string data where alignment does not matter */
/* The bootloader name */
Elf_Nhdr nv1;
char nv1_desc[SZ(NAME)];
/* The bootloader version */
Elf_Nhdr nv2;
char nv2_desc[SZ(VERSION)];
/* The firmware type */
Elf_Nhdr nv3;
char nv3_desc[SZ(FIRMWARE)];
/* Name of the loaded image */
Elf_Nhdr nv4;
char nv4_loaded_image[128];
/* An empty command line */
Elf_Nhdr nv5;
char nv5_cmdline[SZ("")];
};
#define ELF_NOTE_COUNT (3 + 5)
static struct elf_notes notes;
struct Elf_Bhdr *prepare_boot_params(void *header)
{
memset(&notes, 0, sizeof(notes));
notes.hdr.b_signature = ELF_BHDR_MAGIC;
notes.hdr.b_size = sizeof(notes);
notes.hdr.b_checksum = 0;
notes.hdr.b_records = ELF_NOTE_COUNT;
/* Initialize the fixed length entries. */
notes.nf1.n_namesz = sizeof(EB_PARAM_NOTE);
notes.nf1.n_descsz = sizeof(notes.nf1_bootp_data);
notes.nf1.n_type = EB_BOOTP_DATA;
CP(notes.nf1_name, EB_PARAM_NOTE);
notes.nf1_bootp_data = virt_to_phys(BOOTP_DATA_ADDR);
notes.nf2.n_namesz = sizeof(EB_PARAM_NOTE);
notes.nf2.n_descsz = sizeof(notes.nf2_header);
notes.nf2.n_type = EB_HEADER;
CP(notes.nf2_name, EB_PARAM_NOTE);
notes.nf2_header = virt_to_phys(header);
notes.nf3.n_namesz = sizeof(EB_PARAM_NOTE);
notes.nf3.n_descsz = sizeof(notes.nf3_meminfo);
notes.nf3.n_type = EB_I386_MEMMAP;
CP(notes.nf3_name, EB_PARAM_NOTE);
memcpy(&notes.nf3_meminfo, &meminfo, sizeof(meminfo));
/* Initialize the variable length entries */
notes.nv1.n_namesz = 0;
notes.nv1.n_descsz = sizeof(NAME);
notes.nv1.n_type = EBN_BOOTLOADER_NAME;
CP(notes.nv1_desc, NAME);
notes.nv2.n_namesz = 0;
notes.nv2.n_descsz = sizeof(VERSION);
notes.nv2.n_type = EBN_BOOTLOADER_VERSION;
CP(notes.nv2_desc, VERSION);
notes.nv3.n_namesz = 0;
notes.nv3.n_descsz = sizeof(FIRMWARE);
notes.nv3.n_type = EBN_FIRMWARE_TYPE;
CP(notes.nv3_desc, FIRMWARE);
/* Attempt to pass the name of the loaded image */
notes.nv4.n_namesz = 0;
notes.nv4.n_descsz = sizeof(notes.nv4_loaded_image);
notes.nv4.n_type = EBN_LOADED_IMAGE;
memcpy(&notes.nv4_loaded_image, KERNEL_BUF, sizeof(notes.nv4_loaded_image));
/* Pass an empty command line for now */
notes.nv5.n_namesz = 0;
notes.nv5.n_descsz = sizeof("");
notes.nv5.n_type = EBN_COMMAND_LINE;
CP(notes.nv5_cmdline, "");
notes.hdr.b_checksum = ipchksum(&notes, sizeof(notes));
/* Like UDP invert a 0 checksum to show that a checksum is present */
if (notes.hdr.b_checksum == 0) {
notes.hdr.b_checksum = 0xffff;
}
return &notes.hdr;
}
int elf_start(unsigned long machine __unused_i386, unsigned long entry, unsigned long params)
{
#if defined(CONFIG_X86_64)
if (machine == EM_X86_64) {
return xstart_lm(entry, params);
}
#endif
return xstart32(entry, params);
}

View File

@ -0,0 +1,90 @@
OUTPUT_FORMAT("elf32-i386", "elf32-i386", "elf32-i386")
OUTPUT_ARCH(i386)
ENTRY(_text)
SECTIONS {
. = ALIGN(16);
/* Start address of Etherboot in the virtual address space */
_virt_start = 0;
_text = . ;
.text.nocompress : {
*(.text*.nocompress)
. = ALIGN(16);
} = 0x9090
.text16 : {
_text16 = .;
*(.text16)
*(.text16.*)
_etext16 = . ;
}
.text.compress : {
*(.text)
*(.text.*)
} = 0x9090
.rodata : {
. = ALIGN(4);
*(.rodata)
*(.rodata.*)
}
. = ALIGN(4);
.drivers.pci : {
pci_drivers = . ;
*(.drivers.pci);
pci_drivers_end = . ;
}
. = ALIGN(4);
.drivers.isa : {
isa_drivers = . ;
*(.drivers.isa);
isa_drivers_end = .;
}
_etext = . ;
_data = . ;
.data : {
*(.data)
*(.data.*)
}
_edata = . ;
_uncompressed_verbatim_end = . ;
. = ALIGN(16);
.bss.preserve : {
*(.bss.preserve)
*(.bss.preserve.*)
}
_bss = . ;
.bss : {
*(.bss)
*(.bss.*)
}
. = ALIGN(16);
_ebss = .;
_stack = . ;
.stack : {
_stack_start = . ;
*(.stack)
*(.stack.*)
_stack_end = . ;
}
_bss_size = _ebss - _bss;
_stack_offset = _stack - _text ;
_stack_offset_pgh = _stack_offset / 16 ;
_stack_size = _stack_end - _stack_start ;
. = ALIGN(16);
_end = . ;
/DISCARD/ : {
*(.comment)
*(.note)
}
/* PXE-specific symbol calculations. The results of these are
* needed in romprefix.S, which is why they must be calculated
* here.
*/
_pxe_stack_size = _pxe_stack_t_size
+ _pxe_callback_interface_size
+ _rm_callback_interface_size
+ _e820mangler_size + 15 ;
}

View File

@ -0,0 +1,100 @@
OUTPUT_FORMAT("elf32-i386", "elf32-i386", "elf32-i386")
OUTPUT_ARCH(i386)
ENTRY(_prefix_start)
SECTIONS {
/* Prefix */
.prefix : {
_verbatim_start = . ;
_prefix_start = . ;
*(.prefix)
. = ALIGN(16);
_prefix_end = . ;
} = 0x9090
_prefix_size = _prefix_end - _prefix_start;
.text.nocompress : {
*(.prefix.udata)
} = 0x9090
decompress_to = . ;
.prefix.zdata : {
_compressed = . ;
*(.prefix.zdata)
_compressed_end = . ;
}
_compressed_size = _compressed_end - _compressed;
. = ALIGN(16);
_verbatim_end = . ;
/* Size of the core of etherboot in memory */
_base_size = _end - _text;
/* _prefix_size is the length of the non-core etherboot prefix */
_prefix_size = _prefix_end - _prefix_start;
/* _verbatim_size is the actual amount that has to be copied to base memory */
_verbatim_size = _verbatim_end - _verbatim_start;
/* _image_size is the amount of base memory needed to run */
_image_size = _base_size + _prefix_size;
/* Standard sizes rounded up to paragraphs */
_prefix_size_pgh = (_prefix_size + 15) / 16;
_verbatim_size_pgh = (_verbatim_size + 15) / 16;
_image_size_pgh = (_image_size + 15) / 16 ;
/* Standard sizes in sectors */
_prefix_size_sct = (_prefix_size + 511) / 512;
_verbatim_size_sct = (_verbatim_size + 511) / 512;
_image_size_sct = (_image_size + 511) / 512;
/* Symbol offsets and sizes for the exe prefix */
_exe_hdr_size = 32;
_exe_size = _verbatim_size; /* Should this be - 32 to exclude the header? */
_exe_size_tail = (_exe_size) % 512;
_exe_size_pages = ((_exe_size) + 511) / 512;
_exe_bss_size = ((_image_size - _verbatim_size) + 15) / 16;
_exe_ss_offset = (_stack_offset + _prefix_size - _exe_hdr_size + 15) / 16 ;
/* This is where we copy the compressed image before decompression.
* Prepare to decompress in place. The end mark is about 8.25 bytes long,
* and the worst case symbol is about 16.5 bytes long. Therefore
* We need to reserve at least 25 bytes of slack here.
* Currently I reserve 2048 bytes of just slack to be safe :)
* 2048 bytes easily falls within the BSS (the defualt stack is 4096 bytes)
* so we really are decompressing in place.
*
* Hmm. I missed a trick. In the very worst case (no compression)
* the encoded data is 9/8 the size as it started out so to be completely
* safe I need to be 1/8 of the uncompressed code size past the end.
* This will still fit compfortably into our bss in any conceivable scenario.
*/
_compressed_copy = _edata + _prefix_size - _compressed_size +
/* The amount to overflow _edata */
MAX( ((_edata - _text + 7) / 8) , 2016 ) + 32;
_assert = ASSERT( ( _compressed_copy - _prefix_size ) < _ebss , "Cannot decompress in place" ) ;
decompress = DEFINED(decompress) ? decompress : 0;
/DISCARD/ : {
*(.comment)
*(.note)
}
/* Symbols used by the prefixes whose addresses are inconvinient
* to compute, at runtime in the code.
*/
image_basemem_size = DEFINED(image_basemem_size)? image_basemem_size : 65536;
image_basemem = DEFINED(image_basemem)? image_basemem : 65536;
_prefix_real_to_prot = _real_to_prot + _prefix_size ;
_prefix_prot_to_real = _prot_to_real + _prefix_size ;
_prefix_image_basemem_size = image_basemem_size + _prefix_size ;
_prefix_image_basemem = image_basemem + _prefix_size ;
_prefix_rm_in_call = _rm_in_call + _prefix_size ;
_prefix_in_call = _in_call + _prefix_size ;
_prefix_rom = rom + _prefix_size ;
_prefix_rm_etherboot_location = rm_etherboot_location + _prefix_size ;
_prefix_stack_end = _stack_end + _prefix_size ;
}

View File

@ -0,0 +1,377 @@
/* bootinfo */
#define BOOTINFO_VERSION 1
#define NODEV (-1) /* non-existent device */
#define PAGE_SHIFT 12 /* LOG2(PAGE_SIZE) */
#define PAGE_SIZE (1<<PAGE_SHIFT) /* bytes/page */
#define PAGE_MASK (PAGE_SIZE-1)
#define N_BIOS_GEOM 8
struct bootinfo {
unsigned int bi_version;
const unsigned char *bi_kernelname;
struct nfs_diskless *bi_nfs_diskless;
/* End of fields that are always present. */
#define bi_endcommon bi_n_bios_used
unsigned int bi_n_bios_used;
unsigned long bi_bios_geom[N_BIOS_GEOM];
unsigned int bi_size;
unsigned char bi_memsizes_valid;
unsigned char bi_pad[3];
unsigned long bi_basemem;
unsigned long bi_extmem;
unsigned long bi_symtab;
unsigned long bi_esymtab;
/* Note that these are in the FreeBSD headers but were not here... */
unsigned long bi_kernend; /* end of kernel space */
unsigned long bi_envp; /* environment */
unsigned long bi_modulep; /* preloaded modules */
};
static struct bootinfo bsdinfo;
#ifdef ELF_IMAGE
static Elf32_Shdr *shdr; /* To support the FreeBSD kludge! */
static Address symtab_load;
static Address symstr_load;
static int symtabindex;
static int symstrindex;
#endif
static enum {
Unknown, Tagged, Aout, Elf, Aout_FreeBSD, Elf_FreeBSD,
} image_type = Unknown;
static unsigned int off;
#ifdef ELF_IMAGE
static void elf_freebsd_probe(void)
{
image_type = Elf;
if ( (estate.e.elf32.e_entry & 0xf0000000) &&
(estate.e.elf32.e_type == ET_EXEC))
{
image_type = Elf_FreeBSD;
printf("/FreeBSD");
off = -(estate.e.elf32.e_entry & 0xff000000);
estate.e.elf32.e_entry += off;
}
/* Make sure we have a null to start with... */
shdr = 0;
/* Clear the symbol index values... */
symtabindex = -1;
symstrindex = -1;
/* ...and the load addresses of the symbols */
symtab_load = 0;
symstr_load = 0;
}
static void elf_freebsd_fixup_segment(void)
{
if (image_type == Elf_FreeBSD) {
estate.p.phdr32[estate.segment].p_paddr += off;
}
}
static void elf_freebsd_find_segment_end(void)
{
/* Count the bytes read even for the last block
* as we will need to know where the last block
* ends in order to load the symbols correctly.
* (plus it could be useful elsewhere...)
* Note that we need to count the actual size,
* not just the end of the disk image size.
*/
estate.curaddr +=
(estate.p.phdr32[estate.segment].p_memsz -
estate.p.phdr32[estate.segment].p_filesz);
}
static int elf_freebsd_debug_loader(unsigned int offset)
{
/* No more segments to be loaded - time to start the
* nasty state machine to support the loading of
* FreeBSD debug symbols due to the fact that FreeBSD
* uses/exports the kernel's debug symbols in order
* to make much of the system work! Amazing (arg!)
*
* We depend on the fact that for the FreeBSD kernel,
* there is only one section of debug symbols and that
* the section is after all of the loaded sections in
* the file. This assumes a lot but is somewhat required
* to make this code not be too annoying. (Where do you
* load symbols when the code has not loaded yet?)
* Since this function is actually just a callback from
* the network data transfer code, we need to be able to
* work with the data as it comes in. There is no chance
* for doing a seek other than forwards.
*
* The process we use is to first load the section
* headers. Once they are loaded (shdr != 0) we then
* look for where the symbol table and symbol table
* strings are and setup some state that we found
* them and fall into processing the first one (which
* is the symbol table) and after that has been loaded,
* we try the symbol strings. Note that the order is
* actually required as the memory image depends on
* the symbol strings being loaded starting at the
* end of the symbol table. The kernel assumes this
* layout of the image.
*
* At any point, if we get to the end of the load file
* or the section requested is earlier in the file than
* the current file pointer, we just end up falling
* out of this and booting the kernel without this
* information.
*/
/* Make sure that the next address is long aligned... */
/* Assumes size of long is a power of 2... */
estate.curaddr = (estate.curaddr + sizeof(long) - 1) & ~(sizeof(long) - 1);
/* If we have not yet gotten the shdr loaded, try that */
if (shdr == 0)
{
estate.toread = estate.e.elf32.e_shnum * estate.e.elf32.e_shentsize;
estate.skip = estate.e.elf32.e_shoff - (estate.loc + offset);
if (estate.toread)
{
#if ELF_DEBUG
printf("shdr *, size %lX, curaddr %lX\n",
estate.toread, estate.curaddr);
#endif
/* Start reading at the curaddr and make that the shdr */
shdr = (Elf32_Shdr *)phys_to_virt(estate.curaddr);
/* Start to read... */
return 1;
}
}
else
{
/* We have the shdr loaded, check if we have found
* the indexs where the symbols are supposed to be */
if ((symtabindex == -1) && (symstrindex == -1))
{
int i;
/* Make sure that the address is page aligned... */
/* Symbols need to start in their own page(s)... */
estate.curaddr = (estate.curaddr + 4095) & ~4095;
/* Need to make new indexes... */
for (i=0; i < estate.e.elf32.e_shnum; i++)
{
if (shdr[i].sh_type == SHT_SYMTAB)
{
int j;
for (j=0; j < estate.e.elf32.e_phnum; j++)
{
/* Check only for loaded sections */
if ((estate.p.phdr32[j].p_type | 0x80) == (PT_LOAD | 0x80))
{
/* Only the extra symbols */
if ((shdr[i].sh_offset >= estate.p.phdr32[j].p_offset) &&
((shdr[i].sh_offset + shdr[i].sh_size) <=
(estate.p.phdr32[j].p_offset + estate.p.phdr32[j].p_filesz)))
{
shdr[i].sh_offset=0;
shdr[i].sh_size=0;
break;
}
}
}
if ((shdr[i].sh_offset != 0) && (shdr[i].sh_size != 0))
{
symtabindex = i;
symstrindex = shdr[i].sh_link;
}
}
}
}
/* Check if we have a symbol table index and have not loaded it */
if ((symtab_load == 0) && (symtabindex >= 0))
{
/* No symbol table yet? Load it first... */
/* This happens to work out in a strange way.
* If we are past the point in the file already,
* we will skip a *large* number of bytes which
* ends up bringing us to the end of the file and
* an old (default) boot. Less code and lets
* the state machine work in a cleaner way but this
* is a nasty side-effect trick... */
estate.skip = shdr[symtabindex].sh_offset - (estate.loc + offset);
/* And we need to read this many bytes... */
estate.toread = shdr[symtabindex].sh_size;
if (estate.toread)
{
#if ELF_DEBUG
printf("db sym, size %lX, curaddr %lX\n",
estate.toread, estate.curaddr);
#endif
/* Save where we are loading this... */
symtab_load = phys_to_virt(estate.curaddr);
*((long *)phys_to_virt(estate.curaddr)) = estate.toread;
estate.curaddr += sizeof(long);
/* Start to read... */
return 1;
}
}
else if ((symstr_load == 0) && (symstrindex >= 0))
{
/* We have already loaded the symbol table, so
* now on to the symbol strings... */
/* Same nasty trick as above... */
estate.skip = shdr[symstrindex].sh_offset - (estate.loc + offset);
/* And we need to read this many bytes... */
estate.toread = shdr[symstrindex].sh_size;
if (estate.toread)
{
#if ELF_DEBUG
printf("db str, size %lX, curaddr %lX\n",
estate.toread, estate.curaddr);
#endif
/* Save where we are loading this... */
symstr_load = phys_to_virt(estate.curaddr);
*((long *)phys_to_virt(estate.curaddr)) = estate.toread;
estate.curaddr += sizeof(long);
/* Start to read... */
return 1;
}
}
}
/* all done */
return 0;
}
static void elf_freebsd_boot(unsigned long entry)
{
if (image_type != Elf_FreeBSD)
return;
memset(&bsdinfo, 0, sizeof(bsdinfo));
bsdinfo.bi_basemem = meminfo.basememsize;
bsdinfo.bi_extmem = meminfo.memsize;
bsdinfo.bi_memsizes_valid = 1;
bsdinfo.bi_version = BOOTINFO_VERSION;
bsdinfo.bi_kernelname = virt_to_phys(KERNEL_BUF);
bsdinfo.bi_nfs_diskless = NULL;
bsdinfo.bi_size = sizeof(bsdinfo);
#define RB_BOOTINFO 0x80000000 /* have `struct bootinfo *' arg */
if(freebsd_kernel_env[0] != '\0'){
freebsd_howto |= RB_BOOTINFO;
bsdinfo.bi_envp = (unsigned long)freebsd_kernel_env;
}
/* Check if we have symbols loaded, and if so,
* made the meta_data needed to pass those to
* the kernel. */
if ((symtab_load !=0) && (symstr_load != 0))
{
unsigned long *t;
bsdinfo.bi_symtab = symtab_load;
/* End of symbols (long aligned...) */
/* Assumes size of long is a power of 2... */
bsdinfo.bi_esymtab = (symstr_load +
sizeof(long) +
*((long *)symstr_load) +
sizeof(long) - 1) & ~(sizeof(long) - 1);
/* Where we will build the meta data... */
t = phys_to_virt(bsdinfo.bi_esymtab);
#if ELF_DEBUG
printf("Metadata at %lX\n",t);
#endif
/* Set up the pointer to the memory... */
bsdinfo.bi_modulep = virt_to_phys(t);
/* The metadata structure is an array of 32-bit
* words where we store some information about the
* system. This is critical, as FreeBSD now looks
* only for the metadata for the extended symbol
* information rather than in the bootinfo.
*/
/* First, do the kernel name and the kernel type */
/* Note that this assumed x86 byte order... */
/* 'kernel\0\0' */
*t++=MODINFO_NAME; *t++= 7; *t++=0x6E72656B; *t++=0x00006C65;
/* 'elf kernel\0\0' */
*t++=MODINFO_TYPE; *t++=11; *t++=0x20666C65; *t++=0x6E72656B; *t++ = 0x00006C65;
/* Now the symbol start/end - note that they are
* here in local/physical address - the Kernel
* boot process will relocate the addresses. */
*t++=MODINFOMD_SSYM | MODINFO_METADATA; *t++=sizeof(*t); *t++=bsdinfo.bi_symtab;
*t++=MODINFOMD_ESYM | MODINFO_METADATA; *t++=sizeof(*t); *t++=bsdinfo.bi_esymtab;
*t++=MODINFO_END; *t++=0; /* end of metadata */
/* Since we have symbols we need to make
* sure that the kernel knows its own end
* of memory... It is not _end but after
* the symbols and the metadata... */
bsdinfo.bi_kernend = virt_to_phys(t);
/* Signal locore.s that we have a valid bootinfo
* structure that was completely filled in. */
freebsd_howto |= 0x80000000;
}
xstart32(entry, freebsd_howto, NODEV, 0, 0, 0,
virt_to_phys(&bsdinfo), 0, 0, 0);
longjmp(restart_etherboot, -2);
}
#endif
#ifdef AOUT_IMAGE
static void aout_freebsd_probe(void)
{
image_type = Aout;
if (((astate.head.a_midmag >> 16) & 0xffff) == 0) {
/* Some other a.out variants have a different
* value, and use other alignments (e.g. 1K),
* not the 4K used by FreeBSD. */
image_type = Aout_FreeBSD;
printf("/FreeBSD");
off = -(astate.head.a_entry & 0xff000000);
astate.head.a_entry += off;
}
}
static void aout_freebsd_boot(void)
{
if (image_type == Aout_FreeBSD) {
memset(&bsdinfo, 0, sizeof(bsdinfo));
bsdinfo.bi_basemem = meminfo.basememsize;
bsdinfo.bi_extmem = meminfo.memsize;
bsdinfo.bi_memsizes_valid = 1;
bsdinfo.bi_version = BOOTINFO_VERSION;
bsdinfo.bi_kernelname = virt_to_phys(KERNEL_BUF);
bsdinfo.bi_nfs_diskless = NULL;
bsdinfo.bi_size = sizeof(bsdinfo);
xstart32(astate.head.a_entry, freebsd_howto, NODEV, 0, 0, 0,
virt_to_phys(&bsdinfo), 0, 0, 0);
longjmp(restart_etherboot, -2);
}
}
#endif

View File

@ -0,0 +1,35 @@
#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();
#endif
}
void arch_relocated_from (unsigned long old_addr )
{
#ifdef PCBIOS
/* Deallocate base memory used for the Etherboot runtime,
* if applicable
*/
forget_runtime_base_memory( old_addr );
#endif
}
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.
*/
forget_real_mode_stack();
#endif
}

View File

@ -0,0 +1,191 @@
/* A couple of routines to implement a low-overhead timer for drivers */
/*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License as
* published by the Free Software Foundation; either version 2, or (at
* your option) any later version.
*/
#include "etherboot.h"
#include "timer.h"
#include "latch.h"
void __load_timer2(unsigned int ticks)
{
/*
* Now let's take care of PPC channel 2
*
* Set the Gate high, program PPC channel 2 for mode 0,
* (interrupt on terminal count mode), binary count,
* load 5 * LATCH count, (LSB and MSB) to begin countdown.
*
* Note some implementations have a bug where the high bits byte
* of channel 2 is ignored.
*/
/* Set up the timer gate, turn off the speaker */
/* Set the Gate high, disable speaker */
outb((inb(PPC_PORTB) & ~PPCB_SPKR) | PPCB_T2GATE, PPC_PORTB);
/* binary, mode 0, LSB/MSB, Ch 2 */
outb(TIMER2_SEL|WORD_ACCESS|MODE0|BINARY_COUNT, TIMER_MODE_PORT);
/* LSB of ticks */
outb(ticks & 0xFF, TIMER2_PORT);
/* MSB of ticks */
outb(ticks >> 8, TIMER2_PORT);
}
static int __timer2_running(void)
{
return ((inb(PPC_PORTB) & PPCB_T2OUT) == 0);
}
#if !defined(CONFIG_TSC_CURRTICKS)
void setup_timers(void)
{
return;
}
void load_timer2(unsigned int ticks)
{
return __load_timer2(ticks);
}
int timer2_running(void)
{
return __timer2_running();
}
void ndelay(unsigned int nsecs)
{
waiton_timer2((nsecs * CLOCK_TICK_RATE)/1000000000);
}
void udelay(unsigned int usecs)
{
waiton_timer2((usecs * TICKS_PER_MS)/1000);
}
#endif /* !defined(CONFIG_TSC_CURRTICKS) */
#if defined(CONFIG_TSC_CURRTICKS)
#define rdtsc(low,high) \
__asm__ __volatile__("rdtsc" : "=a" (low), "=d" (high))
#define rdtscll(val) \
__asm__ __volatile__ ("rdtsc" : "=A" (val))
/* Number of clock ticks to time with the rtc */
#define LATCH 0xFF
#define LATCHES_PER_SEC ((CLOCK_TICK_RATE + (LATCH/2))/LATCH)
#define TICKS_PER_LATCH ((LATCHES_PER_SEC + (TICKS_PER_SEC/2))/TICKS_PER_SEC)
static void sleep_latch(void)
{
__load_timer2(LATCH);
while(__timer2_running());
}
/* ------ Calibrate the TSC -------
* Time how long it takes to excute a loop that runs in known time.
* And find the convertion needed to get to CLOCK_TICK_RATE
*/
static unsigned long long calibrate_tsc(void)
{
unsigned long startlow, starthigh;
unsigned long endlow, endhigh;
rdtsc(startlow,starthigh);
sleep_latch();
rdtsc(endlow,endhigh);
/* 64-bit subtract - gcc just messes up with long longs */
__asm__("subl %2,%0\n\t"
"sbbl %3,%1"
:"=a" (endlow), "=d" (endhigh)
:"g" (startlow), "g" (starthigh),
"0" (endlow), "1" (endhigh));
/* Error: ECPUTOOFAST */
if (endhigh)
goto bad_ctc;
endlow *= TICKS_PER_LATCH;
return endlow;
/*
* The CTC wasn't reliable: we got a hit on the very first read,
* or the CPU was so fast/slow that the quotient wouldn't fit in
* 32 bits..
*/
bad_ctc:
printf("bad_ctc\n");
return 0;
}
static unsigned long clocks_per_tick;
void setup_timers(void)
{
if (!clocks_per_tick) {
clocks_per_tick = calibrate_tsc();
/* Display the CPU Mhz to easily test if the calibration was bad */
printf("CPU %ld Mhz\n", (clocks_per_tick/1000 * TICKS_PER_SEC)/1000);
}
}
unsigned long currticks(void)
{
unsigned long clocks_high, clocks_low;
unsigned long currticks;
/* Read the Time Stamp Counter */
rdtsc(clocks_low, clocks_high);
/* currticks = clocks / clocks_per_tick; */
__asm__("divl %1"
:"=a" (currticks)
:"r" (clocks_per_tick), "0" (clocks_low), "d" (clocks_high));
return currticks;
}
static unsigned long long timer_timeout;
static int __timer_running(void)
{
unsigned long long now;
rdtscll(now);
return now < timer_timeout;
}
void udelay(unsigned int usecs)
{
unsigned long long now;
rdtscll(now);
timer_timeout = now + usecs * ((clocks_per_tick * TICKS_PER_SEC)/(1000*1000));
while(__timer_running());
}
void ndelay(unsigned int nsecs)
{
unsigned long long now;
rdtscll(now);
timer_timeout = now + nsecs * ((clocks_per_tick * TICKS_PER_SEC)/(1000*1000*1000));
while(__timer_running());
}
void load_timer2(unsigned int timer2_ticks)
{
unsigned long long now;
unsigned long clocks;
rdtscll(now);
clocks = timer2_ticks * ((clocks_per_tick * TICKS_PER_SEC)/CLOCK_TICK_RATE);
timer_timeout = now + clocks;
}
int timer2_running(void)
{
return __timer_running();
}
#endif /* RTC_CURRTICKS */

305
src/arch/i386/core/init.S Normal file
View File

@ -0,0 +1,305 @@
#include "callbacks.h"
.equ CR0_PE, 1
.text
.arch i386
.section ".prefix", "ax", @progbits
#undef CODE16
#if defined(PCBIOS)
#define CODE16
#endif
/* We have two entry points: "conventional" (at the start of the file)
* and "callback" (at _entry, 2 bytes in). The "callback" entry
* should be used if the caller wishes to provide a specific opcode.
* It is equivalent to a call to in_call. Using the "conventional"
* entry point is equivalent to using the "callback" entry point with
* an opcode of EB_OPCODE_MAIN.
*
* Both entry points can be called in either 16-bit real or 32-bit
* protected mode with flat physical addresses. We detect which mode
* the processor is in and call either in_call or rm_in_call as
* appropriate. Note that the mode detection code must therefore be
* capable of doing the same thing in either mode, even though the
* machine code instructions will be interpreted differently.
*
* The decompressor will be invoked if necessary to decompress
* Etherboot before attempting to jump to it.
*/
/******************************************************************************
* Entry points and mode detection code
******************************************************************************
*/
.code32
/* "Conventional" entry point: caller provides no opcode */
.globl _start
_start:
/* Set flag to indicate conventional entry point used */
pushl $0 /* "pushw $0" in 16-bit code */
/* Fall through to "callback" entry point */
/* "Callback" entry point */
.globl _entry
_entry:
#ifdef CODE16
/* CPU mode detection code */
pushl %eax /* "pushw %ax" in 16-bit code */
pushw %ax /* "pushl %eax" in 16-bit code */
movl %cr0, %eax /* Test protected mode bit */
testb $CR0_PE, %al
popw %ax /* "popl %eax" in 16-bit code */
popl %eax /* "popw %eax" in 16-bit code */
jz rmode
#endif /* CODE16 */
/******************************************************************************
* Entered in protected mode
******************************************************************************
*/
.code32
pmode:
cmpl $0, 0(%esp) /* Conventional entry point used? */
jne 1f
/* Entered via conventional entry point: set up stack */
xchgl %eax, 4(%esp) /* %eax = return addr, store %eax */
movl %eax, 0(%esp) /* 0(%esp) = return address */
movl $(EB_OPCODE_MAIN|EB_USE_INTERNAL_STACK|EB_SKIP_OPCODE), %eax
xchgl %eax, 4(%esp) /* 4(%esp) = opcode, restore %eax */
1:
/* Run decompressor if necessary */
pushl %eax
movl $decompress, %eax
testl %eax, %eax
jz 1f
call decompress
1: popl %eax
/* Make in_call to Etherboot */
jmp _prefix_in_call
/******************************************************************************
* Entered in real mode
******************************************************************************
*/
#ifdef CODE16
.code16
rmode:
pushw %ax /* Padding */
pushw %bp
movw %sp, %bp
cmpw $0, 6(%bp) /* Conventional entry point used? */
jne 1f
/* Entered via conventional entry point: set up stack */
pushw %ax
movw 6(%bp), %ax
movw %ax, 2(%bp) /* Move return address down */
movl $(EB_OPCODE_MAIN|EB_USE_INTERNAL_STACK|EB_SKIP_OPCODE), 4(%bp)
popw %ax
popw %bp
jmp 2f
1: /* Entered via callback entry point: do nothing */
popw %bp
popw %ax
2:
/* Preserve registers */
pushw %ds
pushl %eax
/* Run decompressor if necessary. Decompressor is 32-bit
* code, so we must switch to pmode first. Save and restore
* GDT over transition to pmode.
*/
movl $decompress, %eax
testl %eax, %eax
jz 1f
pushw %ds
pushw %es
pushw %fs
pushw %gs
subw $8, %sp
pushw %bp
movw %sp, %bp
sgdt 2(%bp)
pushw %ss /* Store params for _prot_to_real */
pushw %cs
call _prefix_real_to_prot
.code32
call decompress
call _prefix_prot_to_real
.code16
popw %ax /* skip */
popw %ax /* skip */
lgdt 2(%bp)
popw %bp
addw $8, %sp
popw %gs
popw %fs
popw %es
popw %ds
1:
/* Set rm_etherboot_location */
xorl %eax, %eax
movw %cs, %ax
movw %ax, %ds
shll $4, %eax
addl $_prefix_size, %eax
movl %eax, _prefix_rm_etherboot_location
/* Restore registers */
popl %eax
popw %ds
/* Make real-mode in_call to Etherboot */
jmp _prefix_rm_in_call
#endif /* CODE16 */
/******************************************************************************
* Utility routines that can be called by the "prefix".
******************************************************************************
*/
#ifdef CODE16
/* Prelocate code: either to an area at the top of free base memory.
* Switch stacks to use the stack within the resulting
* Etherboot image.
*
* On entry, %cs:0000 must be the start of the prefix: this is used to
* locate the code to be copied.
*
* This routine takes a single word parameter: the number of bytes to
* be transferred from the old stack to the new stack (excluding the
* return address and this parameter itself, which will always be
* copied). If this value is negative, the stacks will not be
* switched.
*
* Control will "return" to the appropriate point in the relocated
* image.
*/
#define PRELOC_PRESERVE ( 20 )
#define PRELOC_OFFSET_RETADDR ( PRELOC_PRESERVE )
#define PRELOC_OFFSET_RETADDR_E ( PRELOC_OFFSET_RETADDR + 4 )
#define PRELOC_OFFSET_COPY ( PRELOC_OFFSET_RETADDR_E )
#define PRELOC_OFFSET_COPY_E ( PRELOC_OFFSET_COPY + 2 )
#define PRELOC_ALWAYS_COPY ( PRELOC_OFFSET_COPY_E )
.code16
.globl prelocate
prelocate:
/* Pad to allow for expansion of return address */
pushw %ax
/* Preserve registers */
pushaw
pushw %ds
pushw %es
/* Claim an area of base memory from the BIOS and put the
* payload there.
*/
movw $0x40, %bx
movw %bx, %es
movw %es:(0x13), %bx /* FBMS in kb to %ax */
shlw $6, %bx /* ... in paragraphs */
subw $_image_size_pgh, %bx /* Subtract space for image */
shrw $6, %bx /* Round down to nearest kb */
movw %bx, %es:(0x13) /* ...and claim memory from BIOS */
shlw $6, %bx
/* At this point %bx contains the segment address for the
* start of the image (image = prefix + runtime).
*/
/* Switch stacks */
movw %ss, %ax
movw %ax, %ds
movw %sp, %si /* %ds:si = current %ss:sp */
movw %ss:PRELOC_OFFSET_COPY(%si), %cx
testw %cx, %cx
js 1f
leaw _stack_offset_pgh(%bx), %ax /* %ax = new %ss */
movw %ax, %es
movw $_stack_size, %di
addw $PRELOC_ALWAYS_COPY, %cx
subw %cx, %di /* %es:di = new %ss:sp */
movw %ax, %ss /* Set new %ss:sp */
movw %di, %sp
cld
rep movsb /* Copy stack contents */
1:
/* Do the image copy backwards, since if there's overlap with
* a forward copy then it means we're going to get trashed
* during the copy anyway...
*/
pushal /* Preserve 32-bit registers */
movw %bx, %es /* Destination base for copy */
pushw %cs
popw %ds /* Source base for copy */
movl $_verbatim_size-1, %ecx /* Offset to last byte */
movl %ecx, %esi
movl %ecx, %edi
incl %ecx /* Length */
std /* Backwards copy of binary */
ADDR32 rep movsb
cld
popal /* Restore 32-bit registers */
/* Store (%bx<<4) as image_basemem to be picked up by
* basemem.c. Also store image_size, since there's no other
* way that we can later know how much memory we allocated.
* (_zfile_size is unavailable when rt2 is linked).
*/
pushl %eax
xorl %eax, %eax
movw %bx, %ax
shll $4, %eax
movl %eax, %es:_prefix_image_basemem
movl $_image_size, %es:_prefix_image_basemem_size
popl %eax
/* Expand original near return address into far return to new
* code location.
*/
movw %sp, %bp
xchgw %bx, (PRELOC_OFFSET_RETADDR+2)(%bp)
movw %bx, (PRELOC_OFFSET_RETADDR+0)(%bp)
/* Restore registers and return */
popw %es
popw %ds
popaw
lret /* Jump to relocated code */
/* Utility routine to free base memory allocated by prelocate.
* Ensure that said memory is not in use (e.g. for the CPU
* stack) before calling this routine.
*/
.globl deprelocate
deprelocate:
/* Claim an area of base memory from the BIOS and put the
* payload there.
*/
pushw %ax
pushw %es
movw $0x40, %ax
movw %ax, %es
movw %es:(0x13), %ax /* FBMS in kb to %ax */
shlw $6, %ax /* ... in paragraphs */
addw $_image_size_pgh+0x40-1, %ax /* Add space for image and... */
shrw $6, %ax /* ...round up to nearest kb */
movw %ax, %es:(0x13) /* Give memory back to BIOS */
popw %es
popw %ax
ret
#endif /* CODE16 */

View File

@ -0,0 +1,143 @@
/* Multiboot support
*
* 2003-07-02 mmap fix and header probe by SONE Takeshi
*/
struct multiboot_mods {
unsigned mod_start;
unsigned mod_end;
unsigned char *string;
unsigned reserved;
};
struct multiboot_mmap {
unsigned int size;
unsigned int base_addr_low;
unsigned int base_addr_high;
unsigned int length_low;
unsigned int length_high;
unsigned int type;
};
/* The structure of a Multiboot 0.6 parameter block. */
struct multiboot_info {
unsigned int flags;
#define MULTIBOOT_MEM_VALID 0x01
#define MULTIBOOT_BOOT_DEV_VALID 0x02
#define MULTIBOOT_CMDLINE_VALID 0x04
#define MULTIBOOT_MODS_VALID 0x08
#define MULTIBOOT_AOUT_SYMS_VALID 0x10
#define MULTIBOOT_ELF_SYMS_VALID 0x20
#define MULTIBOOT_MMAP_VALID 0x40
unsigned int memlower;
unsigned int memupper;
unsigned int bootdev;
unsigned int cmdline; /* physical address of the command line */
unsigned mods_count;
struct multiboot_mods *mods_addr;
unsigned syms_num;
unsigned syms_size;
unsigned syms_addr;
unsigned syms_shndx;
unsigned mmap_length;
unsigned mmap_addr;
/* The structure actually ends here, so I might as well put
* the ugly e820 parameters here...
*/
struct multiboot_mmap mmap[E820MAX];
};
/* Multiboot image header (minimal part) */
struct multiboot_header {
unsigned int magic;
#define MULTIBOOT_HEADER_MAGIC 0x1BADB002
unsigned int flags;
unsigned int checksum;
};
static struct multiboot_header *mbheader;
static struct multiboot_info mbinfo;
static void multiboot_probe(unsigned char *data, int len)
{
int offset;
struct multiboot_header *h;
/* Multiboot spec requires the header to be in first 8KB of the image */
if (len > 8192)
len = 8192;
for (offset = 0; offset < len; offset += 4) {
h = (struct multiboot_header *) (data + offset);
if (h->magic == MULTIBOOT_HEADER_MAGIC
&& h->magic + h->flags + h->checksum == 0) {
printf("/Multiboot");
mbheader = h;
return;
}
}
mbheader = 0;
}
static inline void multiboot_boot(unsigned long entry)
{
unsigned char cmdline[512], *c;
int i;
if (!mbheader)
return;
/* Etherboot limits the command line to the kernel name,
* default parameters and user prompted parameters. All of
* them are shorter than 256 bytes. As the kernel name and
* the default parameters come from the same BOOTP/DHCP entry
* (or if they don't, the parameters are empty), only two
* strings of the maximum size are possible. Note this buffer
* can overrun if a stupid file name is chosen. Oh well. */
c = cmdline;
for (i = 0; KERNEL_BUF[i] != 0; i++) {
switch (KERNEL_BUF[i]) {
case ' ':
case '\\':
case '"':
*c++ = '\\';
break;
default:
break;
}
*c++ = KERNEL_BUF[i];
}
(void)sprintf(c, " -retaddr %#lX", virt_to_phys(xend32));
mbinfo.flags = MULTIBOOT_MMAP_VALID | MULTIBOOT_MEM_VALID |MULTIBOOT_CMDLINE_VALID;
mbinfo.memlower = meminfo.basememsize;
mbinfo.memupper = meminfo.memsize;
mbinfo.bootdev = 0; /* not booted from disk */
mbinfo.cmdline = virt_to_phys(cmdline);
for (i = 0; i < (int) meminfo.map_count; i++) {
mbinfo.mmap[i].size = sizeof(struct multiboot_mmap)
- sizeof(unsigned int);
mbinfo.mmap[i].base_addr_low =
(unsigned int) meminfo.map[i].addr;
mbinfo.mmap[i].base_addr_high =
(unsigned int) (meminfo.map[i].addr >> 32);
mbinfo.mmap[i].length_low =
(unsigned int) meminfo.map[i].size;
mbinfo.mmap[i].length_high =
(unsigned int) (meminfo.map[i].size >> 32);
mbinfo.mmap[i].type = meminfo.map[i].type;
}
mbinfo.mmap_length = meminfo.map_count * sizeof(struct multiboot_mmap);
mbinfo.mmap_addr = virt_to_phys(mbinfo.mmap);
/* The Multiboot 0.6 spec requires all segment registers to be
* loaded with an unrestricted, writeable segment.
* xstart32 does this for us.
*/
/* Start the kernel, passing the Multiboot information record
* and the magic number. */
os_regs.eax = 0x2BADB002;
os_regs.ebx = virt_to_phys(&mbinfo);
xstart32(entry);
longjmp(restart_etherboot, -2);
}

352
src/arch/i386/core/pci_io.c Normal file
View File

@ -0,0 +1,352 @@
/*
** Support for NE2000 PCI clones added David Monro June 1997
** Generalised to other NICs by Ken Yap July 1997
**
** Most of this is taken from:
**
** /usr/src/linux/drivers/pci/pci.c
** /usr/src/linux/include/linux/pci.h
** /usr/src/linux/arch/i386/bios32.c
** /usr/src/linux/include/linux/bios32.h
** /usr/src/linux/drivers/net/ne.c
*/
#ifdef CONFIG_PCI
#include "etherboot.h"
#include "pci.h"
#ifdef CONFIG_PCI_DIRECT
#define PCIBIOS_SUCCESSFUL 0x00
#define DEBUG 0
/*
* Functions for accessing PCI configuration space with type 1 accesses
*/
#define CONFIG_CMD(bus, device_fn, where) (0x80000000 | (bus << 16) | (device_fn << 8) | (where & ~3))
int pcibios_read_config_byte(unsigned int bus, unsigned int device_fn,
unsigned int where, uint8_t *value)
{
outl(CONFIG_CMD(bus,device_fn,where), 0xCF8);
*value = inb(0xCFC + (where&3));
return PCIBIOS_SUCCESSFUL;
}
int pcibios_read_config_word (unsigned int bus,
unsigned int device_fn, unsigned int where, uint16_t *value)
{
outl(CONFIG_CMD(bus,device_fn,where), 0xCF8);
*value = inw(0xCFC + (where&2));
return PCIBIOS_SUCCESSFUL;
}
int pcibios_read_config_dword (unsigned int bus, unsigned int device_fn,
unsigned int where, uint32_t *value)
{
outl(CONFIG_CMD(bus,device_fn,where), 0xCF8);
*value = inl(0xCFC);
return PCIBIOS_SUCCESSFUL;
}
int pcibios_write_config_byte (unsigned int bus, unsigned int device_fn,
unsigned int where, uint8_t value)
{
outl(CONFIG_CMD(bus,device_fn,where), 0xCF8);
outb(value, 0xCFC + (where&3));
return PCIBIOS_SUCCESSFUL;
}
int pcibios_write_config_word (unsigned int bus, unsigned int device_fn,
unsigned int where, uint16_t value)
{
outl(CONFIG_CMD(bus,device_fn,where), 0xCF8);
outw(value, 0xCFC + (where&2));
return PCIBIOS_SUCCESSFUL;
}
int pcibios_write_config_dword (unsigned int bus, unsigned int device_fn, unsigned int where, uint32_t value)
{
outl(CONFIG_CMD(bus,device_fn,where), 0xCF8);
outl(value, 0xCFC);
return PCIBIOS_SUCCESSFUL;
}
#undef CONFIG_CMD
#else /* CONFIG_PCI_DIRECT not defined */
#if !defined(PCBIOS)
#error "The pcibios can only be used when the PCBIOS support is compiled in"
#endif
/* Macro for calling the BIOS32 service. This replaces the old
* bios32_call function. Use in a statement such as
* __asm__ ( BIOS32_CALL,
* : <output registers>
* : "S" ( bios32_entry ), <other input registers> );
*/
#define BIOS32_CALL "call _virt_to_phys\n\t" \
"pushl %%cs\n\t" \
"call *%%esi\n\t" \
"cli\n\t" \
"cld\n\t" \
"call _phys_to_virt\n\t"
static unsigned long bios32_entry;
static unsigned long pcibios_entry;
static unsigned long bios32_service(unsigned long service)
{
unsigned char return_code; /* %al */
unsigned long address; /* %ebx */
unsigned long length; /* %ecx */
unsigned long entry; /* %edx */
__asm__(BIOS32_CALL
: "=a" (return_code),
"=b" (address),
"=c" (length),
"=d" (entry)
: "0" (service),
"1" (0),
"S" (bios32_entry));
switch (return_code) {
case 0:
return address + entry;
case 0x80: /* Not present */
printf("bios32_service(%d) : not present\n", service);
return 0;
default: /* Shouldn't happen */
printf("bios32_service(%d) : returned %#X????\n",
service, return_code);
return 0;
}
}
int pcibios_read_config_byte(unsigned int bus,
unsigned int device_fn, unsigned int where, uint8_t *value)
{
unsigned long ret;
unsigned long bx = (bus << 8) | device_fn;
__asm__(BIOS32_CALL
"jc 1f\n\t"
"xor %%ah, %%ah\n"
"1:"
: "=c" (*value),
"=a" (ret)
: "1" (PCIBIOS_READ_CONFIG_BYTE),
"b" (bx),
"D" ((long) where),
"S" (pcibios_entry));
return (int) (ret & 0xff00) >> 8;
}
int pcibios_read_config_word(unsigned int bus,
unsigned int device_fn, unsigned int where, uint16_t *value)
{
unsigned long ret;
unsigned long bx = (bus << 8) | device_fn;
__asm__(BIOS32_CALL
"jc 1f\n\t"
"xor %%ah, %%ah\n"
"1:"
: "=c" (*value),
"=a" (ret)
: "1" (PCIBIOS_READ_CONFIG_WORD),
"b" (bx),
"D" ((long) where),
"S" (pcibios_entry));
return (int) (ret & 0xff00) >> 8;
}
int pcibios_read_config_dword(unsigned int bus,
unsigned int device_fn, unsigned int where, uint32_t *value)
{
unsigned long ret;
unsigned long bx = (bus << 8) | device_fn;
__asm__(BIOS32_CALL
"jc 1f\n\t"
"xor %%ah, %%ah\n"
"1:"
: "=c" (*value),
"=a" (ret)
: "1" (PCIBIOS_READ_CONFIG_DWORD),
"b" (bx),
"D" ((long) where),
"S" (pcibios_entry));
return (int) (ret & 0xff00) >> 8;
}
int pcibios_write_config_byte (unsigned int bus,
unsigned int device_fn, unsigned int where, uint8_t value)
{
unsigned long ret;
unsigned long bx = (bus << 8) | device_fn;
__asm__(BIOS32_CALL
"jc 1f\n\t"
"xor %%ah, %%ah\n"
"1:"
: "=a" (ret)
: "0" (PCIBIOS_WRITE_CONFIG_BYTE),
"c" (value),
"b" (bx),
"D" ((long) where),
"S" (pcibios_entry));
return (int) (ret & 0xff00) >> 8;
}
int pcibios_write_config_word (unsigned int bus,
unsigned int device_fn, unsigned int where, uint16_t value)
{
unsigned long ret;
unsigned long bx = (bus << 8) | device_fn;
__asm__(BIOS32_CALL
"jc 1f\n\t"
"xor %%ah, %%ah\n"
"1:"
: "=a" (ret)
: "0" (PCIBIOS_WRITE_CONFIG_WORD),
"c" (value),
"b" (bx),
"D" ((long) where),
"S" (pcibios_entry));
return (int) (ret & 0xff00) >> 8;
}
int pcibios_write_config_dword (unsigned int bus,
unsigned int device_fn, unsigned int where, uint32_t value)
{
unsigned long ret;
unsigned long bx = (bus << 8) | device_fn;
__asm__(BIOS32_CALL
"jc 1f\n\t"
"xor %%ah, %%ah\n"
"1:"
: "=a" (ret)
: "0" (PCIBIOS_WRITE_CONFIG_DWORD),
"c" (value),
"b" (bx),
"D" ((long) where),
"S" (pcibios_entry));
return (int) (ret & 0xff00) >> 8;
}
static void check_pcibios(void)
{
unsigned long signature;
unsigned char present_status;
unsigned char major_revision;
unsigned char minor_revision;
int pack;
if ((pcibios_entry = bios32_service(PCI_SERVICE))) {
__asm__(BIOS32_CALL
"jc 1f\n\t"
"xor %%ah, %%ah\n"
"1:\tshl $8, %%eax\n\t"
"movw %%bx, %%ax"
: "=d" (signature),
"=a" (pack)
: "1" (PCIBIOS_PCI_BIOS_PRESENT),
"S" (pcibios_entry)
: "bx", "cx");
present_status = (pack >> 16) & 0xff;
major_revision = (pack >> 8) & 0xff;
minor_revision = pack & 0xff;
if (present_status || (signature != PCI_SIGNATURE)) {
printf("ERROR: BIOS32 says PCI BIOS, but no PCI "
"BIOS????\n");
pcibios_entry = 0;
}
#if DEBUG
if (pcibios_entry) {
printf ("pcibios_init : PCI BIOS revision %hhX.%hhX"
" entry at %#X\n", major_revision,
minor_revision, pcibios_entry);
}
#endif
}
}
static void pcibios_init(void)
{
union bios32 *check;
unsigned char sum;
int i, length;
bios32_entry = 0;
/*
* Follow the standard procedure for locating the BIOS32 Service
* directory by scanning the permissible address range from
* 0xe0000 through 0xfffff for a valid BIOS32 structure.
*
*/
for (check = phys_to_virt(0xe0000); (void *)check <= phys_to_virt(0xffff0); ++check) {
if (check->fields.signature != BIOS32_SIGNATURE)
continue;
length = check->fields.length * 16;
if (!length)
continue;
sum = 0;
for (i = 0; i < length ; ++i)
sum += check->chars[i];
if (sum != 0)
continue;
if (check->fields.revision != 0) {
printf("pcibios_init : unsupported revision %d at %#X, mail drew@colorado.edu\n",
check->fields.revision, check);
continue;
}
#if DEBUG
printf("pcibios_init : BIOS32 Service Directory "
"structure at %#X\n", check);
#endif
if (!bios32_entry) {
if (check->fields.entry >= 0x100000) {
printf("pcibios_init: entry in high "
"memory, giving up\n");
return;
} else {
bios32_entry = check->fields.entry;
#if DEBUG
printf("pcibios_init : BIOS32 Service Directory"
" entry at %#X\n", bios32_entry);
#endif
}
}
}
if (bios32_entry)
check_pcibios();
}
#endif /* CONFIG_PCI_DIRECT not defined*/
unsigned long pcibios_bus_base(unsigned int bus __unused)
{
/* architecturally this must be 0 */
return 0;
}
void find_pci(int type, struct pci_device *dev)
{
#ifndef CONFIG_PCI_DIRECT
if (!pcibios_entry) {
pcibios_init();
}
if (!pcibios_entry) {
printf("pci_init: no BIOS32 detected\n");
return;
}
#endif
return scan_pci_bus(type, dev);
}
#endif /* CONFIG_PCI */

View File

@ -0,0 +1,331 @@
/*
* Basic support for controlling the 8259 Programmable Interrupt Controllers.
*
* Initially written by Michael Brown (mcb30).
*/
#include <etherboot.h>
#include "pic8259.h"
#include "realmode.h"
#ifdef DEBUG_IRQ
#define DBG(...) printf ( __VA_ARGS__ )
#else
#define DBG(...)
#endif
/* State of trivial IRQ handler */
irq_t trivial_irq_installed_on = IRQ_NONE;
static uint16_t trivial_irq_previous_trigger_count = 0;
/* The actual trivial IRQ handler
*
* Note: we depend on the C compiler not realising that we're putting
* variables in the ".text16" section and therefore not forcing them
* back to the ".data" section. I don't see any reason to expect this
* behaviour to change.
*
* These must *not* be the first variables to appear in this file; the
* first variable to appear gets the ".data" directive.
*/
RM_FRAGMENT(_trivial_irq_handler,
"pushw %bx\n\t"
"call 1f\n1:\tpopw %bx\n\t" /* PIC access to variables */
"incw %cs:(_trivial_irq_trigger_count-1b)(%bx)\n\t"
"popw %bx\n\t"
"iret\n\t"
"\n\t"
".globl _trivial_irq_trigger_count\n\t"
"_trivial_irq_trigger_count: .short 0\n\t"
"\n\t"
".globl _trivial_irq_chain_to\n\t"
"_trivial_irq_chain_to: .short 0,0\n\t"
"\n\t"
".globl _trivial_irq_chain\n\t"
"_trivial_irq_chain: .byte 0\n\t"
);
extern volatile uint16_t _trivial_irq_trigger_count;
extern segoff_t _trivial_irq_chain_to;
extern int8_t _trivial_irq_chain;
/* Current locations of trivial IRQ handler. These will change at
* runtime when relocation is used; the handler needs to be copied to
* base memory before being installed.
*/
void (*trivial_irq_handler)P((void)) = _trivial_irq_handler;
uint16_t volatile *trivial_irq_trigger_count = &_trivial_irq_trigger_count;
segoff_t *trivial_irq_chain_to = &_trivial_irq_chain_to;
uint8_t *trivial_irq_chain = &_trivial_irq_chain;
/* Install a handler for the specified IRQ. Address of previous
* handler will be stored in previous_handler. Enabled/disabled state
* of IRQ will be preserved across call, therefore if the handler does
* chaining, ensure that either (a) IRQ is disabled before call, or
* (b) previous_handler points directly to the place that the handler
* picks up its chain-to address.
*/
int install_irq_handler ( irq_t irq, segoff_t *handler,
uint8_t *previously_enabled,
segoff_t *previous_handler ) {
segoff_t *irq_vector = IRQ_VECTOR ( irq );
*previously_enabled = irq_enabled ( irq );
if ( irq > IRQ_MAX ) {
DBG ( "Invalid IRQ number %d\n" );
return 0;
}
previous_handler->segment = irq_vector->segment;
previous_handler->offset = irq_vector->offset;
if ( *previously_enabled ) disable_irq ( irq );
DBG ( "Installing handler at %hx:%hx for IRQ %d (vector 0000:%hx),"
" leaving %s\n",
handler->segment, handler->offset, irq, virt_to_phys(irq_vector),
( *previously_enabled ? "enabled" : "disabled" ) );
DBG ( "...(previous handler at %hx:%hx)\n",
previous_handler->segment, previous_handler->offset );
irq_vector->segment = handler->segment;
irq_vector->offset = handler->offset;
if ( *previously_enabled ) enable_irq ( irq );
return 1;
}
/* Remove handler for the specified IRQ. Routine checks that another
* handler has not been installed that chains to handler before
* uninstalling handler. Enabled/disabled state of the IRQ will be
* restored to that specified by previously_enabled.
*/
int remove_irq_handler ( irq_t irq, segoff_t *handler,
uint8_t *previously_enabled,
segoff_t *previous_handler ) {
segoff_t *irq_vector = IRQ_VECTOR ( irq );
if ( irq > IRQ_MAX ) {
DBG ( "Invalid IRQ number %d\n" );
return 0;
}
if ( ( irq_vector->segment != handler->segment ) ||
( irq_vector->offset != handler->offset ) ) {
DBG ( "Cannot remove handler for IRQ %d\n" );
return 0;
}
DBG ( "Removing handler for IRQ %d\n", irq );
disable_irq ( irq );
irq_vector->segment = previous_handler->segment;
irq_vector->offset = previous_handler->offset;
if ( *previously_enabled ) enable_irq ( irq );
return 1;
}
/* Install the trivial IRQ handler. This routine installs the
* handler, tests it and enables the IRQ.
*/
int install_trivial_irq_handler ( irq_t irq ) {
segoff_t trivial_irq_handler_segoff = SEGOFF(trivial_irq_handler);
if ( trivial_irq_installed_on != IRQ_NONE ) {
DBG ( "Can install trivial IRQ handler only once\n" );
return 0;
}
if ( SEGMENT(trivial_irq_handler) > 0xffff ) {
DBG ( "Trivial IRQ handler not in base memory\n" );
return 0;
}
DBG ( "Installing trivial IRQ handler on IRQ %d\n", irq );
if ( ! install_irq_handler ( irq, &trivial_irq_handler_segoff,
trivial_irq_chain,
trivial_irq_chain_to ) )
return 0;
trivial_irq_installed_on = irq;
DBG ( "Testing trivial IRQ handler\n" );
disable_irq ( irq );
*trivial_irq_trigger_count = 0;
trivial_irq_previous_trigger_count = 0;
fake_irq ( irq );
if ( ! trivial_irq_triggered ( irq ) ) {
DBG ( "Installation of trivial IRQ handler failed\n" );
remove_trivial_irq_handler ( irq );
return 0;
}
/* Send EOI just in case there was a leftover interrupt */
send_specific_eoi ( irq );
DBG ( "Trivial IRQ handler installed successfully\n" );
enable_irq ( irq );
return 1;
}
/* Remove the trivial IRQ handler.
*/
int remove_trivial_irq_handler ( irq_t irq ) {
segoff_t trivial_irq_handler_segoff = SEGOFF(trivial_irq_handler);
if ( trivial_irq_installed_on == IRQ_NONE ) return 1;
if ( irq != trivial_irq_installed_on ) {
DBG ( "Cannot uninstall trivial IRQ handler from IRQ %d; "
"is installed on IRQ %d\n", irq,
trivial_irq_installed_on );
return 0;
}
if ( ! remove_irq_handler ( irq, &trivial_irq_handler_segoff,
trivial_irq_chain,
trivial_irq_chain_to ) )
return 0;
if ( trivial_irq_triggered ( trivial_irq_installed_on ) ) {
DBG ( "Sending EOI for unwanted trivial IRQ\n" );
send_specific_eoi ( trivial_irq_installed_on );
}
trivial_irq_installed_on = IRQ_NONE;
return 1;
}
/* Safe method to detect whether or not trivial IRQ has been
* triggered. Using this call avoids potential race conditions. This
* call will return success only once per trigger.
*/
int trivial_irq_triggered ( irq_t irq ) {
uint16_t trivial_irq_this_trigger_count = *trivial_irq_trigger_count;
int triggered = ( trivial_irq_this_trigger_count -
trivial_irq_previous_trigger_count );
/* irq is not used at present, but we have it in the API for
* future-proofing; in case we want the facility to have
* multiple trivial IRQ handlers installed simultaneously.
*
* Avoid compiler warning about unused variable.
*/
if ( irq == IRQ_NONE ) {};
trivial_irq_previous_trigger_count = trivial_irq_this_trigger_count;
return triggered ? 1 : 0;
}
/* Copy trivial IRQ handler to a new location. Typically used to copy
* the handler into base memory; when relocation is being used we need
* to do this before installing the handler.
*
* Call with target=NULL in order to restore the handler to its
* original location.
*/
int copy_trivial_irq_handler ( void *target, size_t target_size ) {
irq_t currently_installed_on = trivial_irq_installed_on;
uint32_t offset = ( target == NULL ? 0 :
target - (void*)_trivial_irq_handler );
if (( target != NULL ) && ( target_size < TRIVIAL_IRQ_HANDLER_SIZE )) {
DBG ( "Insufficient space to copy trivial IRQ handler\n" );
return 0;
}
if ( currently_installed_on != IRQ_NONE ) {
DBG ("WARNING: relocating trivial IRQ handler while in use\n");
if ( ! remove_trivial_irq_handler ( currently_installed_on ) )
return 0;
}
/* Do the actual copy */
if ( target != NULL ) {
DBG ( "Copying trivial IRQ handler to %hx:%hx\n",
SEGMENT(target), OFFSET(target) );
memcpy ( target, _trivial_irq_handler,
TRIVIAL_IRQ_HANDLER_SIZE );
} else {
DBG ( "Restoring trivial IRQ handler to original location\n" );
}
/* Update all the pointers to structures within the handler */
trivial_irq_handler = ( void (*)P((void)) )
( (void*)_trivial_irq_handler + offset );
trivial_irq_trigger_count = (uint16_t*)
( (void*)&_trivial_irq_trigger_count + offset );
trivial_irq_chain_to = (segoff_t*)
( (void*)&_trivial_irq_chain_to + offset );
trivial_irq_chain = (uint8_t*)
( (void*)&_trivial_irq_chain + offset );
if ( currently_installed_on != IRQ_NONE ) {
if ( ! install_trivial_irq_handler ( currently_installed_on ) )
return 0;
}
return 1;
}
/* Send non-specific EOI(s). This seems to be inherently unsafe.
*/
void send_nonspecific_eoi ( irq_t irq ) {
DBG ( "Sending non-specific EOI for IRQ %d\n", irq );
if ( irq >= IRQ_PIC_CUTOFF ) {
outb ( ICR_EOI_NON_SPECIFIC, PIC2_ICR );
}
outb ( ICR_EOI_NON_SPECIFIC, PIC1_ICR );
}
/* Send specific EOI(s).
*/
void send_specific_eoi ( irq_t irq ) {
DBG ( "Sending specific EOI for IRQ %d\n", irq );
outb ( ICR_EOI_SPECIFIC | ICR_VALUE(irq), ICR_REG(irq) );
if ( irq >= IRQ_PIC_CUTOFF ) {
outb ( ICR_EOI_SPECIFIC | ICR_VALUE(CHAINED_IRQ),
ICR_REG(CHAINED_IRQ) );
}
}
/* Fake an IRQ
*/
void fake_irq ( irq_t irq ) {
struct {
uint16_t int_number;
} PACKED in_stack;
/* Convert IRQ to INT number:
*
* subb $0x08,%cl Invert bit 3, set bits 4-7 iff irq < 8
* xorb $0x70,%cl Invert bits 4-6
* andb $0x7f,%cl Clear bit 7
*
* No, it's not the most intuitive method, but I was proud to
* get it down to three lines of assembler when this routine
* was originally implemented in pcbios.S.
*/
in_stack.int_number = ( ( irq - 8 ) ^ 0x70 ) & 0x7f;
RM_FRAGMENT(rm_fake_irq,
"popw %ax\n\t" /* %ax = INT number */
"call 1f\n1:\tpop %bx\n\t"
"movb %al, %cs:(2f-1b+1)(%bx)\n\t" /* Overwrite INT number..*/
"\n2:\tint $0x00\n\t" /* ..in this instruction */
);
real_call ( rm_fake_irq, &in_stack, NULL );
}
/* Dump current 8259 status: enabled IRQs and handler addresses.
*/
#ifdef DEBUG_IRQ
void dump_irq_status ( void ) {
int irq = 0;
for ( irq = 0; irq < 16; irq++ ) {
if ( irq_enabled ( irq ) ) {
printf ( "IRQ%d enabled, ISR at %hx:%hx\n", irq,
IRQ_VECTOR(irq)->segment,
IRQ_VECTOR(irq)->offset );
}
}
}
#endif

View File

@ -0,0 +1,8 @@
OUTPUT_FORMAT("elf32-i386", "elf32-i386", "elf32-i386")
OUTPUT_ARCH(i386)
SECTIONS {
.prefix.udata : {
*(*)
}
}

View File

@ -0,0 +1,8 @@
OUTPUT_FORMAT("elf32-i386", "elf32-i386", "elf32-i386")
OUTPUT_ARCH(i386)
SECTIONS {
.prefix.zdata : {
*(*)
}
}

View File

@ -0,0 +1,364 @@
/* PXE callback mechanisms. This file contains only the portions
* specific to i386: i.e. the low-level mechanisms for calling in from
* an NBP to the PXE stack and for starting an NBP from the PXE stack.
*/
#ifdef PXE_EXPORT
#include "etherboot.h"
#include "callbacks.h"
#include "realmode.h"
#include "pxe.h"
#include "pxe_callbacks.h"
#include "pxe_export.h"
#include "hidemem.h"
#include <stdarg.h>
#define INSTALLED(x) ( (typeof(&x)) ( (void*)(&x) \
- &pxe_callback_interface \
+ (void*)&pxe_stack->arch_data ) )
#define pxe_intercept_int1a INSTALLED(_pxe_intercept_int1a)
#define pxe_intercepted_int1a INSTALLED(_pxe_intercepted_int1a)
#define pxe_pxenv_location INSTALLED(_pxe_pxenv_location)
#define INT1A_VECTOR ( (segoff_t*) ( phys_to_virt( 4 * 0x1a ) ) )
/* The overall size of the PXE stack is ( sizeof(pxe_stack_t) +
* pxe_callback_interface_size + rm_callback_interface_size ).
* Unfortunately, this isn't a compile-time constant, since
* {pxe,rm}_callback_interface_size depend on the length of the
* assembly code in these interfaces.
*
* We used to have a function pxe_stack_size() which returned this
* value. However, it actually needs to be a link-time constant, so
* that it can appear in the UNDIROMID structure in romprefix.S. We
* therefore export the three component sizes as absolute linker
* symbols, get the linker to add them together and generate a new
* absolute symbol _pxe_stack_size. We then import this value into a
* C variable pxe_stack_size, for access from C code.
*/
/* gcc won't let us use extended asm outside a function (compiler
* bug), ao we have to put these asm statements inside a dummy
* function.
*/
static void work_around_gcc_bug ( void ) __attribute__ ((used));
static void work_around_gcc_bug ( void ) {
/* Export sizeof(pxe_stack_t) as absolute linker symbol */
__asm__ ( ".globl _pxe_stack_t_size" );
__asm__ ( ".equ _pxe_stack_t_size, %c0"
: : "i" (sizeof(pxe_stack_t)) );
}
/* Import _pxe_stack_size absolute linker symbol into C variable */
extern int pxe_stack_size;
__asm__ ( "pxe_stack_size: .long _pxe_stack_size" );
/* Utility routine: byte checksum
*/
uint8_t byte_checksum ( void *address, size_t size ) {
unsigned int i, sum = 0;
for ( i = 0; i < size; i++ ) {
sum += ((uint8_t*)address)[i];
}
return (uint8_t)sum;
}
/* install_pxe_stack(): install PXE stack.
*
* Use base = NULL for auto-allocation of base memory
*
* IMPORTANT: no further allocation of base memory should take place
* before the PXE stack is removed. This is to work around a small
* but important deficiency in the PXE specification.
*/
pxe_stack_t * install_pxe_stack ( void *base ) {
pxe_t *pxe;
pxenv_t *pxenv;
void *pxe_callback_code;
void (*pxe_in_call_far)(void);
void (*pxenv_in_call_far)(void);
void *rm_callback_code;
void *e820mangler_code;
void *end;
/* If already installed, just return */
if ( pxe_stack != NULL ) return pxe_stack;
/* Allocate base memory if requested to do so
*/
if ( base == NULL ) {
base = allot_base_memory ( pxe_stack_size );
if ( base == NULL ) return NULL;
}
/* Round address up to 16-byte physical alignment */
pxe_stack = (pxe_stack_t *)
( phys_to_virt ( ( virt_to_phys(base) + 0xf ) & ~0xf ) );
/* Zero out allocated stack */
memset ( pxe_stack, 0, sizeof(*pxe_stack) );
/* Calculate addresses for portions of the stack */
pxe = &(pxe_stack->pxe);
pxenv = &(pxe_stack->pxenv);
pxe_callback_code = &(pxe_stack->arch_data);
pxe_in_call_far = _pxe_in_call_far +
( pxe_callback_code - &pxe_callback_interface );
pxenv_in_call_far = _pxenv_in_call_far +
( pxe_callback_code - &pxe_callback_interface );
rm_callback_code = pxe_callback_code + pxe_callback_interface_size;
e820mangler_code = (void*)(((int)rm_callback_code +
rm_callback_interface_size + 0xf ) & ~0xf);
end = e820mangler_code + e820mangler_size;
/* Initialise !PXE data structures */
memcpy ( pxe->Signature, "!PXE", 4 );
pxe->StructLength = sizeof(*pxe);
pxe->StructRev = 0;
pxe->reserved_1 = 0;
/* We don't yet have an UNDI ROM ID structure */
pxe->UNDIROMID.segment = 0;
pxe->UNDIROMID.offset = 0;
/* or a BC ROM ID structure */
pxe->BaseROMID.segment = 0;
pxe->BaseROMID.offset = 0;
pxe->EntryPointSP.segment = SEGMENT(pxe_stack);
pxe->EntryPointSP.offset = (void*)pxe_in_call_far - (void*)pxe_stack;
/* No %esp-compatible entry point yet */
pxe->EntryPointESP.segment = 0;
pxe->EntryPointESP.offset = 0;
pxe->StatusCallout.segment = -1;
pxe->StatusCallout.offset = -1;
pxe->reserved_2 = 0;
pxe->SegDescCn = 7;
pxe->FirstSelector = 0;
/* PXE specification doesn't say anything about when the stack
* space should get freed. We work around this by claiming it
* as our data segment as well.
*/
pxe->Stack.Seg_Addr = pxe->UNDIData.Seg_Addr = real_mode_stack >> 4;
pxe->Stack.Phy_Addr = pxe->UNDIData.Phy_Addr = real_mode_stack;
pxe->Stack.Seg_Size = pxe->UNDIData.Seg_Size = real_mode_stack_size;
/* Code segment has to be the one containing the data structures... */
pxe->UNDICode.Seg_Addr = SEGMENT(pxe_stack);
pxe->UNDICode.Phy_Addr = virt_to_phys(pxe_stack);
pxe->UNDICode.Seg_Size = end - (void*)pxe_stack;
/* No base code loaded */
pxe->BC_Data.Seg_Addr = 0;
pxe->BC_Data.Phy_Addr = 0;
pxe->BC_Data.Seg_Size = 0;
pxe->BC_Code.Seg_Addr = 0;
pxe->BC_Code.Phy_Addr = 0;
pxe->BC_Code.Seg_Size = 0;
pxe->BC_CodeWrite.Seg_Addr = 0;
pxe->BC_CodeWrite.Phy_Addr = 0;
pxe->BC_CodeWrite.Seg_Size = 0;
pxe->StructCksum -= byte_checksum ( pxe, sizeof(*pxe) );
/* Initialise PXENV+ data structures */
memcpy ( pxenv->Signature, "PXENV+", 6 );
pxenv->Version = 0x201;
pxenv->Length = sizeof(*pxenv);
pxenv->RMEntry.segment = SEGMENT(pxe_stack);
pxenv->RMEntry.offset = (void*)pxenv_in_call_far - (void*)pxe_stack;
pxenv->PMOffset = 0; /* "Do not use" says the PXE spec */
pxenv->PMSelector = 0; /* "Do not use" says the PXE spec */
pxenv->StackSeg = pxenv->UNDIDataSeg = real_mode_stack >> 4;
pxenv->StackSize = pxenv->UNDIDataSize = real_mode_stack_size;
pxenv->BC_CodeSeg = 0;
pxenv->BC_CodeSize = 0;
pxenv->BC_DataSeg = 0;
pxenv->BC_DataSize = 0;
/* UNDIData{Seg,Size} set above */
pxenv->UNDICodeSeg = SEGMENT(pxe_stack);
pxenv->UNDICodeSize = end - (void*)pxe_stack;
pxenv->PXEPtr.segment = SEGMENT(pxe);
pxenv->PXEPtr.offset = OFFSET(pxe);
pxenv->Checksum -= byte_checksum ( pxenv, sizeof(*pxenv) );
/* Mark stack as inactive */
pxe_stack->state = CAN_UNLOAD;
/* Install PXE and RM callback code and E820 mangler */
memcpy ( pxe_callback_code, &pxe_callback_interface,
pxe_callback_interface_size );
install_rm_callback_interface ( rm_callback_code, 0 );
install_e820mangler ( e820mangler_code );
return pxe_stack;
}
/* Use the UNDI data segment as our real-mode stack. This is for when
* we have been loaded via the UNDI loader
*/
void use_undi_ds_for_rm_stack ( uint16_t ds ) {
forget_real_mode_stack();
real_mode_stack = virt_to_phys ( VIRTUAL ( ds, 0 ) );
lock_real_mode_stack = 1;
}
/* Activate PXE stack (i.e. hook interrupt vectors). The PXE stack
* *can* be used before it is activated, but it really shoudln't.
*/
int hook_pxe_stack ( void ) {
if ( pxe_stack == NULL ) return 0;
if ( pxe_stack->state >= MIDWAY ) return 1;
/* Hook INT15 handler */
hide_etherboot();
/* Hook INT1A handler */
*pxe_intercepted_int1a = *INT1A_VECTOR;
pxe_pxenv_location->segment = SEGMENT(pxe_stack);
pxe_pxenv_location->offset = (void*)&pxe_stack->pxenv
- (void*)pxe_stack;
INT1A_VECTOR->segment = SEGMENT(&pxe_stack->arch_data);
INT1A_VECTOR->offset = (void*)pxe_intercept_int1a
- (void*)&pxe_stack->arch_data;
/* Mark stack as active */
pxe_stack->state = MIDWAY;
return 1;
}
/* Deactivate the PXE stack (i.e. unhook interrupt vectors).
*/
int unhook_pxe_stack ( void ) {
if ( pxe_stack == NULL ) return 0;
if ( pxe_stack->state <= CAN_UNLOAD ) return 1;
/* Restore original INT15 and INT1A handlers */
*INT1A_VECTOR = *pxe_intercepted_int1a;
if ( !unhide_etherboot() ) {
/* Cannot unhook INT15. We're up the creek without
* even a suitable log out of which to fashion a
* paddle. There are some very badly behaved NBPs
* that will ignore plaintive pleas such as
* PXENV_KEEP_UNDI and just zero out our code anyway.
* This means they end up vapourising an active INT15
* handler, which is generally not a good thing to do.
*/
return 0;
}
/* Mark stack as inactive */
pxe_stack->state = CAN_UNLOAD;
return 1;
}
/* remove_pxe_stack(): remove PXE stack installed by install_pxe_stack()
*/
void remove_pxe_stack ( void ) {
/* Ensure stack is deactivated, then free up the memory */
if ( ensure_pxe_state ( CAN_UNLOAD ) ) {
forget_base_memory ( pxe_stack, pxe_stack_size );
pxe_stack = NULL;
} else {
printf ( "Cannot remove PXE stack!\n" );
}
}
/* xstartpxe(): start up a PXE image
*/
int xstartpxe ( void ) {
int nbp_exit;
struct {
reg16_t bx;
reg16_t es;
segoff_t pxe;
} PACKED in_stack;
/* Set up registers and stack parameters to pass to PXE NBP */
in_stack.es.word = SEGMENT(&(pxe_stack->pxenv));
in_stack.bx.word = OFFSET(&(pxe_stack->pxenv));
in_stack.pxe.segment = SEGMENT(&(pxe_stack->pxe));
in_stack.pxe.offset = OFFSET(&(pxe_stack->pxe));
/* Real-mode trampoline fragment used to jump to PXE NBP
*/
RM_FRAGMENT(jump_to_pxe_nbp,
"popw %bx\n\t"
"popw %es\n\t"
"lcall $" RM_STR(PXE_LOAD_SEGMENT) ", $" RM_STR(PXE_LOAD_OFFSET) "\n\t"
);
/* Call to PXE image */
gateA20_unset();
nbp_exit = real_call ( jump_to_pxe_nbp, &in_stack, NULL );
gateA20_set();
return nbp_exit;
}
int pxe_in_call ( in_call_data_t *in_call_data, va_list params ) {
/* i386 calling conventions; the only two defined by Intel's
* PXE spec.
*
* Assembly code must pass a long containing the PXE version
* code (i.e. 0x201 for !PXE, 0x200 for PXENV+) as the first
* parameter after the in_call opcode. This is used to decide
* whether to take parameters from the stack (!PXE) or from
* registers (PXENV+).
*/
uint32_t api_version = va_arg ( params, typeof(api_version) );
uint16_t opcode;
segoff_t segoff;
t_PXENV_ANY *structure;
if ( api_version >= 0x201 ) {
/* !PXE calling convention */
pxe_call_params_t pxe_params
= va_arg ( params, typeof(pxe_params) );
opcode = pxe_params.opcode;
segoff = pxe_params.segoff;
} else {
/* PXENV+ calling convention */
opcode = in_call_data->pm->regs.bx;
segoff.segment = in_call_data->rm->seg_regs.es;
segoff.offset = in_call_data->pm->regs.di;
}
structure = VIRTUAL ( segoff.segment, segoff.offset );
return pxe_api_call ( opcode, structure );
}
#ifdef TEST_EXCLUDE_ALGORITHM
/* This code retained because it's a difficult algorithm to tweak with
* confidence
*/
int ___test_exclude ( int start, int len, int estart, int elen, int fixbase );
void __test_exclude ( int start, int len, int estart, int elen, int fixbase ) {
int newrange = ___test_exclude ( start, len, estart, elen, fixbase );
int newstart = ( newrange >> 16 ) & 0xffff;
int newlen = ( newrange & 0xffff );
printf ( "[%x,%x): excluding [%x,%x) %s gives [%x,%x)\n",
start, start + len,
estart, estart + elen,
( fixbase == 0 ) ? " " : "fb",
newstart, newstart + newlen );
}
void _test_exclude ( int start, int len, int estart, int elen ) {
__test_exclude ( start, len, estart, elen, 0 );
__test_exclude ( start, len, estart, elen, 1 );
}
void test_exclude ( void ) {
_test_exclude ( 0x8000, 0x1000, 0x0400, 0x200 ); /* before */
_test_exclude ( 0x8000, 0x1000, 0x9000, 0x200 ); /* after */
_test_exclude ( 0x8000, 0x1000, 0x7f00, 0x200 ); /* before overlap */
_test_exclude ( 0x8000, 0x1000, 0x8f00, 0x200 ); /* after overlap */
_test_exclude ( 0x8000, 0x1000, 0x8000, 0x200 ); /* align start */
_test_exclude ( 0x8000, 0x1000, 0x8e00, 0x200 ); /* align end */
_test_exclude ( 0x8000, 0x1000, 0x8100, 0x200 ); /* early overlap */
_test_exclude ( 0x8000, 0x1000, 0x8d00, 0x200 ); /* late overlap */
_test_exclude ( 0x8000, 0x1000, 0x7000, 0x3000 ); /* total overlap */
_test_exclude ( 0x8000, 0x1000, 0x8000, 0x1000 ); /* exact overlap */
}
#endif /* TEST_EXCLUDE_ALGORITHM */
#else /* PXE_EXPORT */
/* Define symbols used by the linker scripts, to prevent link errors */
__asm__ ( ".globl _pxe_stack_t_size" );
__asm__ ( ".equ _pxe_stack_t_size, 0" );
#endif /* PXE_EXPORT */

View File

@ -0,0 +1,94 @@
/*
* PXE image loader for Etherboot.
*
* Note: There is no signature check for PXE images because there is
* no signature. Well done, Intel! Consequently, pxe_probe() must be
* called last of all the image_probe() routines, because it will
* *always* claim the image.
*/
#ifndef PXE_EXPORT
#error PXE_IMAGE requires PXE_EXPORT
#endif
#include "etherboot.h"
#include "pxe_callbacks.h"
#include "pxe_export.h"
#include "pxe.h"
unsigned long pxe_load_offset;
static sector_t pxe_download ( unsigned char *data,
unsigned int len, int eof );
static inline os_download_t pxe_probe ( unsigned char *data __unused,
unsigned int len __unused ) {
printf("(PXE)");
pxe_load_offset = 0;
return pxe_download;
}
static sector_t pxe_download ( unsigned char *data,
unsigned int len, int eof ) {
unsigned long block_address = PXE_LOAD_ADDRESS + pxe_load_offset;
PXENV_STATUS_t nbp_exit;
/* Check segment will fit. We can't do this in probe()
* because there's nothing in the non-existent header to tell
* us how long the image is.
*/
if ( ! prep_segment ( block_address, block_address + len,
block_address + len,
pxe_load_offset, pxe_load_offset + len ) ) {
longjmp ( restart_etherboot, -2 );
}
/* Load block into memory, continue loading until eof */
memcpy ( phys_to_virt ( block_address ), data, len );
pxe_load_offset += len;
if ( ! eof ) {
return 0;
}
/* Start up PXE NBP */
done ( 0 );
/* Install and activate a PXE stack */
pxe_stack = install_pxe_stack ( NULL );
if ( ensure_pxe_state ( READY ) ) {
/* Invoke the NBP */
nbp_exit = xstartpxe();
} else {
/* Fake success so we tear down the stack */
nbp_exit = PXENV_STATUS_SUCCESS;
}
/* NBP has three exit codes:
* PXENV_STATUS_KEEP_UNDI : keep UNDI and boot next device
* PXENV_STATUS_KEEP_ALL : keep all and boot next device
* anything else : remove all and boot next device
*
* Strictly, we're meant to hand back to the BIOS, but this
* would prevent the useful combination of "PXE NBP fails, so
* let Etherboot try to boot its next device". We therefore
* take liberties.
*/
if ( nbp_exit != PXENV_STATUS_KEEP_UNDI &&
nbp_exit != PXENV_STATUS_KEEP_ALL ) {
/* Tear down PXE stack */
remove_pxe_stack();
}
/* Boot next device. Under strict PXE compliance, exit back
* to the BIOS, otherwise let Etherboot move to the next
* device.
*/
#ifdef PXE_STRICT
longjmp ( restart_etherboot, 255 );
#else
longjmp ( restart_etherboot, 4 );
#endif
/* Never reached; avoid compiler warning */
return ( 0 );
}

View File

@ -0,0 +1,148 @@
/* Real-mode interface: C portions.
*
* Initial version by Michael Brown <mbrown@fensystems.co.uk>, January 2004.
*/
#include "etherboot.h"
#include "realmode.h"
#include "segoff.h"
#define RM_STACK_SIZE ( 0x1000 )
/* gcc won't let us use extended asm outside a function (compiler
* bug), ao we have to put these asm statements inside a dummy
* function.
*/
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) );
}
/* 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;
}

View File

@ -0,0 +1,695 @@
/* Real-mode interface: assembly-language portions.
*
* Initial version by Michael Brown <mbrown@fensystems.co.uk>, January 2004.
*/
#include "realmode.h"
#include "callbacks.h"
#if 1 /* CODE16 */
#define BOCHSBP xchgw %bx,%bx
#define NUM_PUSHA_REGS (8)
#define NUM_SEG_REGS (6)
.text
.arch i386
.section ".text16.nocompress", "ax", @progbits
.code16
.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
/****************************************************************************
* 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
*
* Prepend this to rm_callback_interface to create a real-mode PXE
* callback interface.
****************************************************************************
*/
.section ".text16", "ax", @progbits
.globl pxe_callback_interface
.code16
pxe_callback_interface:
/* Macro to calculate offset of labels within code segment in
* installed copy of code.
*/
#define INSTALLED(x) ( (x) - pxe_callback_interface )
/****************************************************************************
* PXE entry points (!PXE and PXENV+ APIs)
****************************************************************************
*/
/* in_call mechanism for !PXE API calls */
.globl _pxe_in_call_far
_pxe_in_call_far:
/* Prepend "PXE API call" and "API version 0x201" to stack */
pushl $0x201
jmp 1f
/* in_call mechanism for PXENV+ API calls */
.globl _pxenv_in_call_far
_pxenv_in_call_far:
/* Prepend "PXE API call" and "API version 0x200" to stack */
pushl $0x200
1: pushl $EB_OPCODE_PXE
/* Perform real-mode in_call */
call pxe_rm_in_call
/* Return */
addw $8, %sp
lret
/****************************************************************************
* PXE installation check (INT 1A) code
****************************************************************************
*/
.globl _pxe_intercept_int1a
_pxe_intercept_int1a:
pushfw
cmpw $0x5650, %ax
jne 2f
1: /* INT 1A,5650 - Intercept */
popfw
/* Set up return values according to PXE spec: */
movw $0x564e, %ax /* AX := 564Eh (VN) */
pushw %cs:INSTALLED(_pxe_pxenv_segment)
popw %es /* ES:BX := &(PXENV+ structure) */
movw %cs:INSTALLED(_pxe_pxenv_offset), %bx
clc /* CF is cleared */
lret $2 /* 'iret' without reloading flags */
2: /* INT 1A,other - Do not intercept */
popfw
ljmp %cs:*INSTALLED(_pxe_intercepted_int1a)
.globl _pxe_intercepted_int1a
_pxe_intercepted_int1a: .word 0,0
.globl _pxe_pxenv_location
_pxe_pxenv_location:
_pxe_pxenv_offset: .word 0
_pxe_pxenv_segment: .word 0
pxe_rm_in_call:
pxe_attach_rm:
/* rm_callback_interface must be appended here */
pxe_callback_interface_end:
.globl _pxe_callback_interface_size
.equ _pxe_callback_interface_size, pxe_callback_interface_end - pxe_callback_interface
.globl pxe_callback_interface_size
pxe_callback_interface_size:
.word _pxe_callback_interface_size
#else /* PXE_EXPORT */
/* Define symbols used by the linker scripts, to prevent link errors */
.globl _pxe_callback_interface_size
.equ _pxe_callback_interface_size, 0
#endif /* PXE_EXPORT */
#else /* CODE16 */
/* Define symbols used by the linker scripts, to prevent link errors */
.globl _rm_callback_interface_size
.equ _rm_callback_interface_size, 0
.globl _pxe_callback_interface_size
.equ _pxe_callback_interface_size, 0
#endif /* CODE16 */

View File

@ -0,0 +1,285 @@
/*****************************************************************************
*
* THIS FILE IS NOW OBSOLETE.
*
* The functions of this file are now placed in init.S.
*
*****************************************************************************
*/
#ifndef PCBIOS
#error "16bit code is only supported with the PCBIOS"
#endif
#define CODE_SEG 0x08
#define DATA_SEG 0x10
#define EXEC_IN_SITU_MAGIC 0x45524548 /* 'HERE' */
.equ CR0_PE, 1
#ifdef GAS291
#define DATA32 data32;
#define ADDR32 addr32;
#define LJMPI(x) ljmp x
#else
#define DATA32 data32
#define ADDR32 addr32
/* newer GAS295 require #define LJMPI(x) ljmp *x */
#define LJMPI(x) ljmp x
#endif
/*****************************************************************************
*
* start16 : move payload to desired area of memory, set up for exit
* back to prefix, set up for 32-bit code.
*
* Enter (from prefix) with es:di = 0x4552:0x4548 if you want to
* prevent start16 from moving the payload. There are three
* motivations for moving the payload:
*
* 1. It may be in ROM, in which case we need to move it to RAM.
* 2. Whatever loaded us probably didn't know about our memory usage
* beyond the end of the image file. We should claim this memory
* before using it.
*
* Unless the prefix instructs us otherwise we will move the payload to:
*
* An area of memory claimed from the BIOS via 40:13.
*
* We use the main Etherboot stack (within the image target) as our
* stack; we don't rely on the prefix passing us a stack usable for
* anything other than the prefix's return address. The (first 512
* bytes of the) prefix code segment is copied to a safe archive
* location.
*
* When we return to the prefix (from start32), we copy this code back
* to a new area of memory, restore the prefix's ss:sp and ljmp back
* to the copy of the prefix. The prefix will see a return from
* start16 *but* may be executing at a new location. Code following
* the lcall to start16 must therefore be position-independent and
* must also be within [cs:0000,cs:01ff]. We make absolutely no
* guarantees about the stack contents when the prefix regains
* control.
*
* Trashes just about all registers, including all the segment
* registers.
*
*****************************************************************************
*/
.text
.code16
.arch i386
.org 0
.globl _start16
_start16:
/*****************************************************************************
* Work out where we are going to place our image (image = optional
* decompressor + runtime). Exit this stage with %ax containing the
* runtime target address divided by 16 (i.e. a real-mode segment
* address).
*****************************************************************************
*/
movw %es, %ax
cmpw $(EXEC_IN_SITU_MAGIC >> 16), %ax
jne exec_moved
cmpw $(EXEC_IN_SITU_MAGIC & 0xffff), %di
jne exec_moved
exec_in_situ:
/* Prefix has warned us not to move the payload. Simply
* calculate where the image is going to end up, so we can
* work out where to put our stack.
*/
movw %cs, %ax
addw $((payload-_start16)/16), %ax
jmp 99f
exec_moved:
/* Claim an area of base memory from the BIOS and put the
* payload there. arch_relocated_to() will deal with freeing
* up this memory once we've relocated to high memory.
*/
movw $0x40, %ax
movw %ax, %es
movw %es:(0x13), %ax /* FBMS in kb to %ax */
shlw $6, %ax /* ... in paragraphs */
subw $__image_size_pgh, %ax /* Subtract space for image */
shrw $6, %ax /* Round down to nearest kb */
movw %ax, %es:(0x13) /* ...and claim memory from BIOS */
shlw $6, %ax
99:
/* At this point %ax contains the segment address for the
* start of the image (image = optional decompressor + runtime).
*/
/*****************************************************************************
* Set up stack in start32's stack space within the place we're going
* to copy Etherboot to, reserve space for GDT, copy return address
* from prefix stack, store prefix stack address
*****************************************************************************
*/
popl %esi /* Return address */
mov %ss, %bx /* %es:di = prefix stack address */
mov %bx, %es /* (*after* pop of return address) */
movw %sp, %di
movw $__offset_stack_pgh, %bx /* Set up Etherboot stack */
addw %ax, %bx
movw %bx, %ss
movw $__stack_size, %sp
subw $(_gdt_end - _gdt), %sp /* Reserve space for GDT */
movw %sp, %bp /* Record GDT location */
/* Set up i386_rm_in_call_data_t structure on stack. This is
* the same structure as is set up by rm_in_call.
*/
pushl $0 /* Dummy opcode */
pushl %esi /* Prefix return address */
pushfw /* Flags */
pushw %di /* Prefix %sp */
pushw %gs /* Segment registers */
pushw %fs
pushw %es
pushw %ds
pushw %es /* Prefix %ss */
pushw %cs
/* Stack is now 32-bit aligned */
/* %ax still contains image target segment address */
/*****************************************************************************
* Calculate image target and prefix code physical addresses, store on stack
* for use in copy routine.
*****************************************************************************
*/
movzwl %es:-2(%di), %ebx /* Prefix code segment */
shll $4, %ebx
pushl %ebx /* Prefix code physical address */
movzwl %ax, %edi /* Image target segment */
shll $4, %edi
pushl %edi /* Image target physical address */
/*****************************************************************************
* Transition to 32-bit protected mode. Set up all segment
* descriptors to use flat physical addresses.
*****************************************************************************
*/
/* Copy gdt to area reserved on stack
*/
push %cs /* GDT source location -> %ds:%si */
pop %ds
mov $(_gdt - _start16), %si
push %ss /* GDT target location -> %es:%di */
pop %es
mov %bp, %di
mov $(_gdt_end - _gdt), %cx
cld
rep movsb /* Copy GDT to stack */
movl %ss, %eax
shll $4, %eax
movzwl %bp, %ebx
addl %eax, %ebx /* Physical addr of GDT copy -> %ebx */
movl %ebx, 2(%bp) /* Fill in addr field in GDT */
/* Compute the offset I am running at.
*/
movl %cs, %ebx
shll $4, %ebx /* %ebx = offset for start16 symbols */
/* Switch to 32bit protected mode.
*/
cli /* Disable interrupts */
lgdt (%bp) /* Load GDT from stack */
movl %cr0, %eax /* Set protected mode bit */
orb $CR0_PE, %al
movl %eax, %cr0
movl %ss, %eax /* Convert stack pointer to 32bit */
shll $4, %eax
movzwl %sp, %esp
addl %eax, %esp
movl $DATA_SEG, %eax /* Reload the segment registers */
movl %eax, %ds
movl %eax, %es
movl %eax, %ss
movl %eax, %fs
movl %eax, %gs
/* Flush prefetch queue, and reload %cs:%eip by effectively ljmping
* to code32_start. Do the jump via pushl and lret because the text
* may not be writable/
*/
pushl $CODE_SEG
ADDR32 leal (code32_start-_start16)(%ebx), %eax
pushl %eax
DATA32 lret /* DATA32 needed, because we're still in 16-bit mode */
_gdt:
gdtarg:
.word _gdt_end - _gdt - 1 /* limit */
.long 0 /* addr */
.word 0
_pmcs:
/* 32 bit protected mode code segment */
.word 0xffff, 0
.byte 0, 0x9f, 0xcf, 0
_pmds:
/* 32 bit protected mode data segment */
.word 0xffff,0
.byte 0,0x93,0xcf,0
_gdt_end:
.code32
code32_start:
/*****************************************************************************
* Copy payload to target location. Do the copy backwards, since if
* there's overlap with a forward copy then it means start16 is going
* to get trashed during the copy anyway...
*****************************************************************************
*/
popl %edi /* Image target physical address */
pushl %edi
leal (payload-_start16)(%ebx), %esi /* Image source physical addr */
movl $__payload_size, %ecx /* Payload size (not image size) */
addl %ecx, %edi /* Start at last byte (length - 1) */
decl %edi
addl %ecx, %esi
decl %esi
std /* Backward copy of image */
rep movsb
cld
popl %edi /* Restore image target physical address */
leal __decompressor_uncompressed(%edi), %ebx
subl $_text, %ebx /* %ebx = offset for runtime symbols */
/*****************************************************************************
* Copy prefix to storage area within Etherboot image.
*****************************************************************************
*/
popl %esi /* Prefix source physical address */
pushl %edi
leal _prefix_copy(%ebx), %edi /* Prefix copy phys. addr. */
leal _eprefix_copy(%ebx), %ecx
subl %edi, %ecx /* Prefix copy size */
rep movsb /* Forward copy of prefix */
popl %edi /* Restore image target physical address */
/*****************************************************************************
* Record base memory used by Etherboot image
*****************************************************************************
*/
movl %edi, _prefix_image_basemem (%ebx)
/*****************************************************************************
* Jump to start of the image (i.e. the decompressor, or start32 if
* non-compressed).
*****************************************************************************
*/
pushl $0 /* Inform start32 that exit path is 16-bit */
jmpl *%edi /* Jump to image */
.balign 16
/* Etherboot needs to be 16byte aligned or data that
* is virtually aligned is no longer physically aligned
* which is just nasty in general. 16byte alignment
* should be sufficient though.
*/
payload:

View File

@ -0,0 +1,8 @@
/* When linking with an uncompressed image, these symbols are not
* defined so we provide them here.
*/
__decompressor_uncompressed = 0 ;
__decompressor__start = 0 ;
INCLUDE arch/i386/core/start16z.lds

View File

@ -0,0 +1,65 @@
OUTPUT_FORMAT("elf32-i386", "elf32-i386", "elf32-i386")
OUTPUT_ARCH(i386)
/* Linker-generated symbols are prefixed with a double underscore.
* Decompressor symbols are prefixed with __decompressor_. All other
* symbols are the same as in the original object file, i.e. the
* runtime addresses.
*/
ENTRY(_start16)
SECTIONS {
.text : {
*(.text)
}
.payload : {
__payload_start = .;
*(.data)
__payload_end = .;
}
/* _payload_size is the size of the binary image appended to
* start16, in bytes.
*/
__payload_size = __payload_end - __payload_start ;
/* _size is the size of the runtime image
* (start32 + the C code), in bytes.
*/
__size = _end - _start ;
/* _decompressor_size is the size of the decompressor, in
* bytes. For a non-compressed image, start16.lds sets
* _decompressor_uncompressed = _decompressor__start = 0.
*/
__decompressor_size = __decompressor_uncompressed - __decompressor__start ;
/* image__size is the total size of the image, after
* decompression and including the decompressor if applicable.
* It is therefore the amount of memory that start16's payload
* needs in order to execute, in bytes.
*/
__image_size = __size + __decompressor_size ;
/* Amount to add to runtime symbols to obtain the offset of
* that symbol within the image.
*/
__offset_adjust = __decompressor_size - _start ;
/* Calculations for the stack
*/
__stack_size = _estack - _stack ;
__offset_stack = _stack + __offset_adjust ;
/* Some symbols will be larger than 16 bits but guaranteed to
* be multiples of 16. We calculate them in paragraphs and
* export these symbols which can be used in 16-bit code
* without risk of overflow.
*/
__image_size_pgh = ( __image_size / 16 );
__start_pgh = ( _start / 16 );
__decompressor_size_pgh = ( __decompressor_size / 16 );
__offset_stack_pgh = ( __offset_stack / 16 );
}

View File

@ -0,0 +1,767 @@
/* #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
.equ MSR_K6_EFER, 0xC0000080
.equ EFER_LME, 0x00000100
.equ X86_CR4_PAE, 0x00000020
.equ CR0_PG, 0x80000000
#ifdef GAS291
#define DATA32 data32;
#define ADDR32 addr32;
#define LJMPI(x) ljmp x
#else
#define DATA32 data32
#define ADDR32 addr32
/* newer GAS295 require #define LJMPI(x) ljmp *x */
#define LJMPI(x) ljmp x
#endif
#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
* registers must not be altered under any circumstance. All other registers
* may be clobbered without any negative side effects. If you don't follow
* this rule then you'll run into strange effects that only occur on some
* gcc versions (because the register allocator may use different registers).
*
* All the data32 prefixes for the ljmp instructions are necessary, because
* the assembler emits code with a relocation address of 0. This means that
* all destinations are initially negative, which the assembler doesn't grok,
* because for some reason negative numbers don't fit into 16 bits. The addr32
* prefixes are there for the same reasons, because otherwise the memory
* references are only 16 bit wide. Theoretically they are all superfluous.
* One last note about prefixes: the data32 prefixes on all call _real_to_prot
* instructions could be removed if the _real_to_prot function is changed to
* deal correctly with 16 bit return addresses. I tried it, but failed.
*/
/**************************************************************************
* 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
**************************************************************************/
.globl xstart32
xstart32:
/* Save the callee save registers */
movl %ebp, os_regs + 32
movl %esi, os_regs + 36
movl %edi, os_regs + 40
movl %ebx, os_regs + 44
/* save the return address */
popl %eax
movl %eax, os_regs + 48
/* save the stack pointer */
movl %esp, os_regs + 52
/* Get the new destination address */
popl %ecx
/* Store the physical address of xend on the stack */
movl $xend32, %ebx
addl virt_offset, %ebx
pushl %ebx
/* Store the destination address on the stack */
pushl $FLAT_CODE_SEG
pushl %ecx
/* Cache virt_offset */
movl virt_offset, %ebp
/* Switch to using physical addresses */
call _virt_to_phys
/* Save the target stack pointer */
movl %esp, os_regs + 12(%ebp)
leal os_regs(%ebp), %esp
/* Store the pointer to os_regs */
movl %esp, os_regs_ptr(%ebp)
/* Load my new registers */
popal
movl (-32 + 12)(%esp), %esp
/* Jump to the new kernel
* The lret switches to a flat code segment
*/
lret
.balign 4
.globl xend32
xend32:
/* Fixup %eflags */
nop
cli
cld
/* Load %esp with &os_regs + virt_offset */
.byte 0xbc /* movl $0, %esp */
os_regs_ptr:
.long 0
/* Save the result registers */
addl $32, %esp
pushal
/* Compute virt_offset */
movl %esp, %ebp
subl $os_regs, %ebp
/* Load the stack pointer */
movl 52(%esp), %esp
/* Enable the virtual addresses */
leal _phys_to_virt(%ebp), %eax
call *%eax
/* Restore the callee save registers */
movl os_regs + 32, %ebp
movl os_regs + 36, %esi
movl os_regs + 40, %edi
movl os_regs + 44, %ebx
movl os_regs + 48, %edx
movl os_regs + 52, %esp
/* Get the C return value */
movl os_regs + 28, %eax
jmpl *%edx
#ifdef CONFIG_X86_64
.arch sledgehammer
/**************************************************************************
XSTART_lm - Transfer control to the kernel just loaded in long mode
**************************************************************************/
.globl xstart_lm
xstart_lm:
/* Save the callee save registers */
pushl %ebp
pushl %esi
pushl %edi
pushl %ebx
/* Cache virt_offset && (virt_offset & 0xfffff000) */
movl virt_offset, %ebp
movl %ebp, %ebx
andl $0xfffff000, %ebx
/* Switch to using physical addresses */
call _virt_to_phys
/* Initialize the page tables */
/* Level 4 */
leal 0x23 + pgt_level3(%ebx), %eax
leal pgt_level4(%ebx), %edi
movl %eax, (%edi)
/* Level 3 */
leal 0x23 + pgt_level2(%ebx), %eax
leal pgt_level3(%ebx), %edi
movl %eax, 0x00(%edi)
addl $4096, %eax
movl %eax, 0x08(%edi)
addl $4096, %eax
movl %eax, 0x10(%edi)
addl $4096, %eax
movl %eax, 0x18(%edi)
/* Level 2 */
movl $0xe3, %eax
leal pgt_level2(%ebx), %edi
leal 16384(%edi), %esi
pgt_level2_loop:
movl %eax, (%edi)
addl $8, %edi
addl $0x200000, %eax
cmp %esi, %edi
jne pgt_level2_loop
/* Point at the x86_64 page tables */
leal pgt_level4(%ebx), %edi
movl %edi, %cr3
/* Setup for the return from 64bit mode */
/* 64bit align the stack */
movl %esp, %ebx /* original stack pointer + 16 */
andl $0xfffffff8, %esp
/* Save original stack pointer + 16 */
pushl %ebx
/* Save virt_offset */
pushl %ebp
/* Setup for the jmp to 64bit long mode */
leal start_lm(%ebp), %eax
movl %eax, 0x00 + start_lm_addr(%ebp)
movl $LM_CODE_SEG, %eax
movl %eax, 0x04 + start_lm_addr(%ebp)
/* Setup for the jump out of 64bit long mode */
leal end_lm(%ebp), %eax
movl %eax, 0x00 + end_lm_addr(%ebp)
movl $FLAT_CODE_SEG, %eax
movl %eax, 0x04 + end_lm_addr(%ebp)
/* Enable PAE mode */
movl %cr4, %eax
orl $X86_CR4_PAE, %eax
movl %eax, %cr4
/* Enable long mode */
movl $MSR_K6_EFER, %ecx
rdmsr
orl $EFER_LME, %eax
wrmsr
/* Start paging, entering 32bit compatiblity mode */
movl %cr0, %eax
orl $CR0_PG, %eax
movl %eax, %cr0
/* Enter 64bit long mode */
ljmp *start_lm_addr(%ebp)
.code64
start_lm:
/* Load 64bit data segments */
movl $LM_DATA_SEG, %eax
movl %eax, %ds
movl %eax, %es
movl %eax, %ss
andq $0xffffffff, %rbx
/* Get the address to jump to */
movl 20(%rbx), %edx
andq $0xffffffff, %rdx
/* Get the argument pointer */
movl 24(%rbx), %ebx
andq $0xffffffff, %rbx
/* Jump to the 64bit code */
call *%rdx
/* Preserve the result */
movl %eax, %edx
/* Fixup %eflags */
cli
cld
/* Switch to 32bit compatibility mode */
ljmp *end_lm_addr(%rip)
.code32
end_lm:
/* Disable paging */
movl %cr0, %eax
andl $~CR0_PG, %eax
movl %eax, %cr0
/* Disable long mode */
movl $MSR_K6_EFER, %ecx
rdmsr
andl $~EFER_LME, %eax
wrmsr
/* Disable PAE */
movl %cr4, %eax
andl $~X86_CR4_PAE, %eax
movl %eax, %cr4
/* Compute virt_offset */
popl %ebp
/* Compute the original stack pointer + 16 */
popl %ebx
movl %ebx, %esp
/* Enable the virtual addresses */
leal _phys_to_virt(%ebp), %eax
call *%eax
/* Restore the callee save registers */
popl %ebx
popl %esi
popl %edi
popl %ebp
/* Get the C return value */
movl %edx, %eax
/* Return */
ret
.arch i386
#endif /* CONFIG_X86_64 */
/**************************************************************************
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
/* Include a dummy space in case we are loaded badly aligned */
.space 4096
/* Reserve enough space for a page table convering 4GB with 2MB pages */
pgt_level4:
.space 4096
pgt_level3:
.space 4096
pgt_level2:
.space 16384
start_lm_addr:
.space 8
end_lm_addr:
.space 8
#endif

View File

@ -0,0 +1,201 @@
#include "realmode.h"
#include "segoff.h"
struct segheader
{
unsigned char length;
unsigned char vendortag;
unsigned char reserved;
unsigned char flags;
unsigned long loadaddr;
unsigned long imglength;
unsigned long memlength;
};
struct imgheader
{
unsigned long magic;
unsigned long length; /* and flags */
union
{
segoff_t segoff;
unsigned long location;
} u;
unsigned long execaddr;
};
/* Keep all context about loaded image in one place */
static struct tagged_context
{
struct imgheader img; /* copy of header */
unsigned long linlocation; /* addr of header */
unsigned long last0, last1; /* of prev segment */
unsigned long segaddr, seglen; /* of current segment */
unsigned char segflags;
unsigned char first;
unsigned long curaddr;
} tctx;
#define TAGGED_PROGRAM_RETURNS (tctx.img.length & 0x00000100) /* bit 8 */
#define LINEAR_EXEC_ADDR (tctx.img.length & 0x80000000) /* bit 31 */
static sector_t tagged_download(unsigned char *data, unsigned int len, int eof);
void xstart16 (unsigned long execaddr, segoff_t location,
void *bootp);
static inline os_download_t tagged_probe(unsigned char *data, unsigned int len)
{
struct segheader *sh;
unsigned long loc;
if (*((uint32_t *)data) != 0x1B031336L) {
return 0;
}
printf("(NBI)");
/* If we don't have enough data give up */
if (len < 512)
return dead_download;
/* Zero all context info */
memset(&tctx, 0, sizeof(tctx));
/* Copy first 4 longwords */
memcpy(&tctx.img, data, sizeof(tctx.img));
/* Memory location where we are supposed to save it */
tctx.segaddr = tctx.linlocation =
((tctx.img.u.segoff.segment) << 4) + tctx.img.u.segoff.offset;
if (!prep_segment(tctx.segaddr, tctx.segaddr + 512, tctx.segaddr + 512,
0, 512)) {
return dead_download;
}
/* Now verify the segments we are about to load */
loc = 512;
for(sh = (struct segheader *)(data
+ ((tctx.img.length & 0x0F) << 2)
+ ((tctx.img.length & 0xF0) >> 2) );
(sh->length > 0) && ((unsigned char *)sh < data + 512);
sh = (struct segheader *)((unsigned char *)sh
+ ((sh->length & 0x0f) << 2) + ((sh->length & 0xf0) >> 2)) ) {
if (!prep_segment(
sh->loadaddr,
sh->loadaddr + sh->imglength,
sh->loadaddr + sh->imglength,
loc, loc + sh->imglength)) {
return dead_download;
}
loc = loc + sh->imglength;
if (sh->flags & 0x04)
break;
}
if (!(sh->flags & 0x04))
return dead_download;
/* Grab a copy */
memcpy(phys_to_virt(tctx.segaddr), data, 512);
/* Advance to first segment descriptor */
tctx.segaddr += ((tctx.img.length & 0x0F) << 2)
+ ((tctx.img.length & 0xF0) >> 2);
/* Remember to skip the first 512 data bytes */
tctx.first = 1;
return tagged_download;
}
static sector_t tagged_download(unsigned char *data, unsigned int len, int eof)
{
int i;
if (tctx.first) {
tctx.first = 0;
if (len > 512) {
len -= 512;
data += 512;
/* and fall through to deal with rest of block */
} else
return 0;
}
for (;;) {
if (len == 0) /* Detect truncated files */
eof = 0;
while (tctx.seglen == 0) {
struct segheader sh;
if (tctx.segflags & 0x04) {
done(1);
if (LINEAR_EXEC_ADDR) {
int result;
/* no gateA20_unset for PM call */
result = xstart32(tctx.img.execaddr,
virt_to_phys(&loaderinfo),
tctx.linlocation,
virt_to_phys(BOOTP_DATA_ADDR));
printf("Secondary program returned %d\n",
result);
if (!TAGGED_PROGRAM_RETURNS) {
/* We shouldn't have returned */
result = -2;
}
if (result == 0)
result = -2;
longjmp(restart_etherboot, result);
} else {
gateA20_unset();
xstart16(tctx.img.execaddr,
tctx.img.u.segoff,
BOOTP_DATA_ADDR);
longjmp(restart_etherboot, -2);
}
}
sh = *((struct segheader *)phys_to_virt(tctx.segaddr));
tctx.seglen = sh.imglength;
if ((tctx.segflags = sh.flags & 0x03) == 0)
tctx.curaddr = sh.loadaddr;
else if (tctx.segflags == 0x01)
tctx.curaddr = tctx.last1 + sh.loadaddr;
else if (tctx.segflags == 0x02)
tctx.curaddr = (Address)(meminfo.memsize * 1024L
+ 0x100000L)
- sh.loadaddr;
else
tctx.curaddr = tctx.last0 - sh.loadaddr;
tctx.last1 = (tctx.last0 = tctx.curaddr) + sh.memlength;
tctx.segflags = sh.flags;
tctx.segaddr += ((sh.length & 0x0F) << 2)
+ ((sh.length & 0xF0) >> 2);
/* Avoid lock-up */
if ( sh.length == 0 ) longjmp(restart_etherboot, -2);
}
if ((len <= 0) && !eof)
break;
i = (tctx.seglen > len) ? len : tctx.seglen;
memcpy(phys_to_virt(tctx.curaddr), data, i);
tctx.seglen -= i;
tctx.curaddr += i;
len -= i;
data += i;
}
return 0;
}
void xstart16 (unsigned long execaddr, segoff_t location,
void *bootp) {
struct {
segoff_t execaddr;
segoff_t location;
segoff_t bootp;
} PACKED in_stack;
/* AFAICT, execaddr is actually already a segment:offset */
*((unsigned long *)&in_stack.execaddr) = execaddr;
in_stack.location = location;
in_stack.bootp.segment = SEGMENT(bootp);
in_stack.bootp.offset = OFFSET(bootp);
RM_FRAGMENT(rm_xstart16,
"popl %eax\n\t" /* Calculated lcall */
"pushw %cs\n\t"
"call 1f\n1:\tpopw %bp\n\t"
"leaw (2f-1b)(%bp), %bx\n\t"
"pushw %bx\n\t"
"pushl %eax\n\t"
"lret\n2:\n\t"
);
real_call ( rm_xstart16, &in_stack, NULL );
}

View File

@ -0,0 +1,94 @@
/*
*
* modified from linuxbios code
* by Cai Qiang <rimy2000@hotmail.com>
*
*/
#ifdef CONSOLE_DIRECT_VGA
#include <etherboot.h>
#include <vga.h>
static char *vidmem; /* The video buffer */
static int video_line, video_col;
#define VIDBUFFER 0xB8000
static void memsetw(void *s, int c, unsigned int n)
{
int i;
u16 *ss = (u16 *) s;
for (i = 0; i < n; i++) {
ss[i] = ( u16 ) c;
}
}
void video_init(void)
{
static int inited=0;
vidmem = (unsigned char *)phys_to_virt(VIDBUFFER);
if (!inited) {
video_line = 0;
video_col = 0;
memsetw(vidmem, VGA_ATTR_CLR_WHT, 2*1024); //
inited=1;
}
}
static void video_scroll(void)
{
int i;
memcpy(vidmem, vidmem + COLS * 2, (LINES - 1) * COLS * 2);
for (i = (LINES - 1) * COLS * 2; i < LINES * COLS * 2; i += 2)
vidmem[i] = ' ';
}
void vga_putc(unsigned char byte)
{
if (byte == '\n') {
video_line++;
video_col = 0;
} else if (byte == '\r') {
video_col = 0;
} else if (byte == '\b') {
video_col--;
} else if (byte == '\t') {
video_col += 4;
} else if (byte == '\a') {
//beep
//beep(500);
} else {
vidmem[((video_col + (video_line *COLS)) * 2)] = byte;
vidmem[((video_col + (video_line *COLS)) * 2) +1] = VGA_ATTR_CLR_WHT;
video_col++;
}
if (video_col < 0) {
video_col = 0;
}
if (video_col >= COLS) {
video_line++;
video_col = 0;
}
if (video_line >= LINES) {
video_scroll();
video_line--;
}
// move the cursor
write_crtc((video_col + (video_line *COLS)) >> 8, CRTC_CURSOR_HI);
write_crtc((video_col + (video_line *COLS)) & 0x0ff, CRTC_CURSOR_LO);
}
#endif

View File

@ -0,0 +1,273 @@
#define LOAD_DEBUG 0
static int get_x_header(unsigned char *data, unsigned long now);
static void jump_2ep();
static unsigned char ce_signature[] = {'B', '0', '0', '0', 'F', 'F', '\n',};
static char ** ep;
#define BOOT_ARG_PTR_LOCATION 0x001FFFFC
typedef struct _BOOT_ARGS{
unsigned char ucVideoMode;
unsigned char ucComPort;
unsigned char ucBaudDivisor;
unsigned char ucPCIConfigType;
unsigned long dwSig;
#define BOOTARG_SIG 0x544F4F42
unsigned long dwLen;
unsigned char ucLoaderFlags;
unsigned char ucEshellFlags;
unsigned char ucEdbgAdapterType;
unsigned char ucEdbgIRQ;
unsigned long dwEdbgBaseAddr;
unsigned long dwEdbgDebugZone;
unsigned long dwDHCPLeaseTime;
unsigned long dwEdbgFlags;
unsigned long dwEBootFlag;
unsigned long dwEBootAddr;
unsigned long dwLaunchAddr;
unsigned long pvFlatFrameBuffer;
unsigned short vesaMode;
unsigned short cxDisplayScreen;
unsigned short cyDisplayScreen;
unsigned short cxPhysicalScreen;
unsigned short cyPhysicalScreen;
unsigned short cbScanLineLength;
unsigned short bppScreen;
unsigned char RedMaskSize;
unsigned char REdMaskPosition;
unsigned char GreenMaskSize;
unsigned char GreenMaskPosition;
unsigned char BlueMaskSize;
unsigned char BlueMaskPosition;
} BOOT_ARGS;
BOOT_ARGS BootArgs;
static struct segment_info{
unsigned long addr; // Section Address
unsigned long size; // Section Size
unsigned long checksum; // Section CheckSum
} X;
#define PSIZE (1500) //Max Packet Size
#define DSIZE (PSIZE+12)
static unsigned long dbuffer_available =0;
static unsigned long not_loadin =0;
static unsigned long d_now =0;
unsigned long entry;
static unsigned long ce_curaddr;
static sector_t ce_loader(unsigned char *data, unsigned int len, int eof);
static os_download_t wince_probe(unsigned char *data, unsigned int len)
{
if (strncmp(ce_signature, data, sizeof(ce_signature)) != 0) {
return 0;
}
printf("(WINCE)");
return ce_loader;
}
static sector_t ce_loader(unsigned char *data, unsigned int len, int eof)
{
static unsigned char dbuffer[DSIZE];
int this_write = 0;
static int firsttime = 1;
/*
* new packet in, we have to
* [1] copy data to dbuffer,
*
* update...
* [2] dbuffer_available
*/
memcpy( (dbuffer+dbuffer_available), data, len); //[1]
dbuffer_available += len; // [2]
len = 0;
d_now = 0;
#if 0
printf("dbuffer_available =%ld \n", dbuffer_available);
#endif
if (firsttime)
{
d_now = sizeof(ce_signature);
printf("String Physical Address = %lx \n",
*(unsigned long *)(dbuffer+d_now));
d_now += sizeof(unsigned long);
printf("Image Size = %ld [%lx]\n",
*(unsigned long *)(dbuffer+d_now),
*(unsigned long *)(dbuffer+d_now));
d_now += sizeof(unsigned long);
dbuffer_available -= d_now;
d_now = (unsigned long)get_x_header(dbuffer, d_now);
firsttime = 0;
}
if (not_loadin == 0)
{
d_now = get_x_header(dbuffer, d_now);
}
while ( not_loadin > 0 )
{
/* dbuffer do not have enough data to loading, copy all */
#if LOAD_DEBUG
printf("[0] not_loadin = [%ld], dbuffer_available = [%ld] \n",
not_loadin, dbuffer_available);
printf("[0] d_now = [%ld] \n", d_now);
#endif
if( dbuffer_available <= not_loadin)
{
this_write = dbuffer_available ;
memcpy(phys_to_virt(ce_curaddr), (dbuffer+d_now), this_write );
ce_curaddr += this_write;
not_loadin -= this_write;
/* reset index and available in the dbuffer */
dbuffer_available = 0;
d_now = 0;
#if LOAD_DEBUG
printf("[1] not_loadin = [%ld], dbuffer_available = [%ld] \n",
not_loadin, dbuffer_available);
printf("[1] d_now = [%ld], this_write = [%d] \n",
d_now, this_write);
#endif
// get the next packet...
return (0);
}
/* dbuffer have more data then loading ... , copy partital.... */
else
{
this_write = not_loadin;
memcpy(phys_to_virt(ce_curaddr), (dbuffer+d_now), this_write);
ce_curaddr += this_write;
not_loadin = 0;
/* reset index and available in the dbuffer */
dbuffer_available -= this_write;
d_now += this_write;
#if LOAD_DEBUG
printf("[2] not_loadin = [%ld], dbuffer_available = [%ld] \n",
not_loadin, dbuffer_available);
printf("[2] d_now = [%ld], this_write = [%d] \n\n",
d_now, this_write);
#endif
/* dbuffer not empty, proceed processing... */
// don't have enough data to get_x_header..
if ( dbuffer_available < (sizeof(unsigned long) * 3) )
{
// printf("we don't have enough data remaining to call get_x. \n");
memcpy( (dbuffer+0), (dbuffer+d_now), dbuffer_available);
return (0);
}
else
{
#if LOAD_DEBUG
printf("with remaining data to call get_x \n");
printf("dbuffer available = %ld , d_now = %ld\n",
dbuffer_available, d_now);
#endif
d_now = get_x_header(dbuffer, d_now);
}
}
}
return (0);
}
static int get_x_header(unsigned char *dbuffer, unsigned long now)
{
X.addr = *(unsigned long *)(dbuffer + now);
X.size = *(unsigned long *)(dbuffer + now + sizeof(unsigned long));
X.checksum = *(unsigned long *)(dbuffer + now + sizeof(unsigned long)*2);
if (X.addr == 0)
{
entry = X.size;
done(1);
printf("Entry Point Address = [%lx] \n", entry);
jump_2ep();
}
if (!prep_segment(X.addr, X.addr + X.size, X.addr + X.size, 0, 0)) {
longjmp(restart_etherboot, -2);
}
ce_curaddr = X.addr;
now += sizeof(unsigned long)*3;
/* re-calculate dbuffer available... */
dbuffer_available -= sizeof(unsigned long)*3;
/* reset index of this section */
not_loadin = X.size;
#if 1
printf("\n");
printf("\t Section Address = [%lx] \n", X.addr);
printf("\t Size = %d [%lx]\n", X.size, X.size);
printf("\t Checksum = %ld [%lx]\n", X.checksum, X.checksum);
#endif
#if LOAD_DEBUG
printf("____________________________________________\n");
printf("\t dbuffer_now = %ld \n", now);
printf("\t dbuffer available = %ld \n", dbuffer_available);
printf("\t not_loadin = %ld \n", not_loadin);
#endif
return now;
}
static void jump_2ep()
{
BootArgs.ucVideoMode = 1;
BootArgs.ucComPort = 1;
BootArgs.ucBaudDivisor = 1;
BootArgs.ucPCIConfigType = 1; // do not fill with 0
BootArgs.dwSig = BOOTARG_SIG;
BootArgs.dwLen = sizeof(BootArgs);
if(BootArgs.ucVideoMode == 0)
{
BootArgs.cxDisplayScreen = 640;
BootArgs.cyDisplayScreen = 480;
BootArgs.cxPhysicalScreen = 640;
BootArgs.cyPhysicalScreen = 480;
BootArgs.bppScreen = 16;
BootArgs.cbScanLineLength = 1024;
BootArgs.pvFlatFrameBuffer = 0x800a0000; // ollie say 0x98000000
}
else if(BootArgs.ucVideoMode != 0xFF)
{
BootArgs.cxDisplayScreen = 0;
BootArgs.cyDisplayScreen = 0;
BootArgs.cxPhysicalScreen = 0;
BootArgs.cyPhysicalScreen = 0;
BootArgs.bppScreen = 0;
BootArgs.cbScanLineLength = 0;
BootArgs.pvFlatFrameBuffer = 0;
}
ep = phys_to_virt(BOOT_ARG_PTR_LOCATION);
*ep= virt_to_phys(&BootArgs);
xstart32(entry);
}

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,178 @@
/**************************************************************************
Etherboot - BOOTP/TFTP Bootstrap Program
UNDI NIC driver for Etherboot - header file
This file Copyright (C) 2003 Michael Brown <mbrown@fensystems.co.uk>
of Fen Systems Ltd. (http://www.fensystems.co.uk/). All rights
reserved.
$Id$
***************************************************************************/
/*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License as
* published by the Free Software Foundation; either version 2, or (at
* your option) any later version.
*/
#include "pxe.h"
#include "pic8259.h"
/* A union that can function as the parameter block for any UNDI API call.
*/
typedef t_PXENV_ANY pxenv_structure_t;
/* BIOS PnP parameter block. We scan for this so that we can pass it
* to the UNDI driver.
*/
#define PNP_BIOS_SIGNATURE ( ('$'<<0) + ('P'<<8) + ('n'<<16) + ('P'<<24) )
typedef struct pnp_bios {
uint32_t signature;
uint8_t version;
uint8_t length;
uint16_t control;
uint8_t checksum;
uint8_t dontcare[24];
} PACKED pnp_bios_t;
/* Structures within the PXE ROM.
*/
#define ROM_SIGNATURE 0xaa55
typedef struct rom {
uint16_t signature;
uint8_t unused[0x14];
uint16_t undi_rom_id_off;
uint16_t pcir_off;
uint16_t pnp_off;
} PACKED rom_t;
#define PCIR_SIGNATURE ( ('P'<<0) + ('C'<<8) + ('I'<<16) + ('R'<<24) )
typedef struct pcir_header {
uint32_t signature;
uint16_t vendor_id;
uint16_t device_id;
} PACKED pcir_header_t;
#define PNP_SIGNATURE ( ('$'<<0) + ('P'<<8) + ('n'<<16) + ('P'<<24) )
typedef struct pnp_header {
uint32_t signature;
uint8_t struct_revision;
uint8_t length;
uint16_t next;
uint8_t reserved;
uint8_t checksum;
uint16_t id[2];
uint16_t manuf_str_off;
uint16_t product_str_off;
uint8_t base_type;
uint8_t sub_type;
uint8_t interface_type;
uint8_t indicator;
uint16_t boot_connect_off;
uint16_t disconnect_off;
uint16_t initialise_off;
uint16_t reserved2;
uint16_t info;
} PACKED pnp_header_t;
#define UNDI_SIGNATURE ( ('U'<<0) + ('N'<<8) + ('D'<<16) + ('I'<<24) )
typedef struct undi_rom_id {
uint32_t signature;
uint8_t struct_length;
uint8_t struct_cksum;
uint8_t struct_rev;
uint8_t undi_rev[3];
uint16_t undi_loader_off;
uint16_t stack_size;
uint16_t data_size;
uint16_t code_size;
} PACKED undi_rom_id_t;
/* Nontrivial IRQ handler structure */
typedef struct {
segoff_t chain_to;
uint8_t irq_chain, pad1, pad2, pad3;
segoff_t entry;
uint16_t count_all;
uint16_t count_ours;
t_PXENV_UNDI_ISR undi_isr;
char code[0];
} PACKED undi_irq_handler_t ;
/* Storage buffers that we need in base memory. We collect these into
* a single structure to make allocation simpler.
*/
typedef struct undi_base_mem_xmit_data {
MAC_ADDR destaddr;
t_PXENV_UNDI_TBD tbd;
} undi_base_mem_xmit_data_t;
typedef struct undi_base_mem_data {
pxenv_structure_t pxs;
undi_base_mem_xmit_data_t xmit_data;
char xmit_buffer[ETH_FRAME_LEN];
/* Must be last in structure and paragraph-aligned */
union {
char e820mangler[0];
char irq_handler[0];
undi_irq_handler_t nontrivial_irq_handler;
} __attribute__ ((aligned(16)));
} undi_base_mem_data_t;
/* Macros and data structures used when freeing bits of base memory
* used by the UNDI driver.
*/
#define FIRING_SQUAD_TARGET_SIZE 8
#define FIRING_SQUAD_TARGET_INDEX(x) ( (x) / FIRING_SQUAD_TARGET_SIZE )
#define FIRING_SQUAD_TARGET_BIT(x) ( (x) % FIRING_SQUAD_TARGET_SIZE )
typedef struct firing_squad_lineup {
uint8_t targets[ 640 / FIRING_SQUAD_TARGET_SIZE ];
} firing_squad_lineup_t;
typedef enum firing_squad_shoot {
DONTSHOOT = 0,
SHOOT = 1
} firing_squad_shoot_t;
/* Driver private data structure.
*/
typedef struct undi {
/* Pointers to various data structures */
pnp_bios_t *pnp_bios;
rom_t *rom;
undi_rom_id_t *undi_rom_id;
pxe_t *pxe;
pxenv_structure_t *pxs;
undi_base_mem_xmit_data_t *xmit_data;
/* Pointers and sizes to keep track of allocated base memory */
undi_base_mem_data_t *base_mem_data;
void *driver_code;
size_t driver_code_size;
void *driver_data;
size_t driver_data_size;
char *xmit_buffer;
/* Flags. We keep our own instead of trusting the UNDI driver
* to have implemented PXENV_UNDI_GET_STATE correctly. Plus
* there's the small issue of PXENV_UNDI_GET_STATE being the
* same API call as PXENV_STOP_UNDI...
*/
uint8_t prestarted; /* pxenv_start_undi() has been called */
uint8_t started; /* pxenv_undi_startup() has been called */
uint8_t initialized; /* pxenv_undi_initialize() has been called */
uint8_t opened; /* pxenv_undi_open() has been called */
/* Parameters that we need to store for future reference
*/
struct pci_device pci;
irq_t irq;
} undi_t;
/* Constants
*/
#define HUNT_FOR_PIXIES 0
#define HUNT_FOR_UNDI_ROMS 1

View File

@ -0,0 +1,317 @@
#ifdef PCBIOS
#include "etherboot.h"
#include "realmode.h" /* for real_mode_stack */
/* Routines to allocate base memory in a BIOS-compatible way, by
* updating the Free Base Memory Size counter at 40:13h.
*
* Michael Brown <mbrown@fensystems.co.uk> (mcb30)
* $Id$
*/
#define fbms ( ( uint16_t * ) phys_to_virt ( 0x413 ) )
#define BASE_MEMORY_MAX ( 640 )
#define FREE_BLOCK_MAGIC ( ('!'<<0) + ('F'<<8) + ('R'<<16) + ('E'<<24) )
#define FREE_BASE_MEMORY ( (uint32_t) ( *fbms << 10 ) )
/* Prototypes */
void * _allot_base_memory ( size_t size );
void _forget_base_memory ( void *ptr, size_t size );
typedef struct free_base_memory_block {
uint32_t magic;
uint16_t size_kb;
} free_base_memory_block_t;
/* Return amount of free base memory in bytes
*/
uint32_t get_free_base_memory ( void ) {
return FREE_BASE_MEMORY;
}
/* Start of our image in base memory.
*/
#define __text16_nocompress __attribute__ ((section (".text16.nocompress")))
uint32_t image_basemem __text16_nocompress = 0;
uint32_t image_basemem_size __text16_nocompress = 0;
/* Allot/free the real-mode stack
*/
void allot_real_mode_stack ( void )
{
void *new_real_mode_stack;
if ( lock_real_mode_stack )
return;
/* This is evil hack.
* Until we have a real_mode stack use 0x7c00.
* Except for 0 - 0x600 membory below 0x7c00 is hardly every used.
* This stack should never be used unless the stack allocation fails,
* or if someone has placed a print statement in a dangerous location.
*/
if (!real_mode_stack) {
real_mode_stack = 0x7c00;
}
new_real_mode_stack = _allot_base_memory ( real_mode_stack_size );
if ( ! new_real_mode_stack ) {
printf ( "FATAL: No real-mode stack\n" );
while ( 1 ) {};
}
real_mode_stack = virt_to_phys ( new_real_mode_stack );
get_memsizes();
}
void forget_real_mode_stack ( void )
{
if ( lock_real_mode_stack )
return;
if ( real_mode_stack) {
_forget_base_memory ( phys_to_virt(real_mode_stack),
real_mode_stack_size );
/* get_memsizes() uses the real_mode stack we just freed
* for it's BIOS calls.
*/
get_memsizes();
real_mode_stack = 0;
}
}
/* Allocate N bytes of base memory. Amount allocated will be rounded
* up to the nearest kB, since that's the granularity of the BIOS FBMS
* counter. Returns NULL if memory cannot be allocated.
*/
static void * _allot_base_memory ( size_t size )
{
uint16_t size_kb = ( size + 1023 ) >> 10;
void *ptr = NULL;
#ifdef DEBUG_BASEMEM
printf ( "Trying to allocate %d kB of base memory from %d kB free\n",
size_kb, *fbms );
#endif
/* Free up any unused memory before we start */
free_unused_base_memory();
/* Check available base memory */
if ( size_kb > *fbms ) { return NULL; }
/* Reduce available base memory */
*fbms -= size_kb;
/* Calculate address of memory allocated */
ptr = phys_to_virt ( FREE_BASE_MEMORY );
/* Zero out memory. We do this so that allocation of
* already-used space will show up in the form of a crash as
* soon as possible.
*
* Update: there's another reason for doing this. If we don't
* zero the contents, then they could still retain our "free
* block" markers and be liable to being freed whenever a
* base-memory allocation routine is next called.
*/
memset ( ptr, 0, size_kb << 10 );
#ifdef DEBUG_BASEMEM
printf ( "Allocated %d kB at [%x,%x)\n", size_kb,
virt_to_phys ( ptr ),
virt_to_phys ( ptr ) + size_kb * 1024 );
#endif
return ptr;
}
void * allot_base_memory ( size_t size )
{
void *ptr;
/* Free real-mode stack, allocate memory, reallocate real-mode
* stack.
*/
forget_real_mode_stack();
ptr = _allot_base_memory ( size );
get_memsizes();
return ptr;
}
/* Free base memory allocated by allot_base_memory. The BIOS provides
* nothing better than a LIFO mechanism for freeing memory (i.e. it
* just has the single "total free memory" counter), but we improve
* upon this slightly; as long as you free all the allotted blocks, it
* doesn't matter what order you free them in. (This will only work
* for blocks that are freed via forget_base_memory()).
*
* Yes, it's annoying that you have to remember the size of the blocks
* you've allotted. However, since our granularity of allocation is
* 1K, the alternative is to risk wasting the occasional kB of base
* memory, which is a Bad Thing. Really, you should be using as
* little base memory as possible, so consider the awkwardness of the
* API to be a feature! :-)
*/
static void _forget_base_memory ( void *ptr, size_t size )
{
uint16_t remainder = virt_to_phys(ptr) & 1023;
uint16_t size_kb = ( size + remainder + 1023 ) >> 10;
free_base_memory_block_t *free_block =
( free_base_memory_block_t * ) ( ptr - remainder );
if ( ( ptr == NULL ) || ( size == 0 ) ) {
return;
}
#ifdef DEBUG_BASEMEM
printf ( "Trying to free %d bytes base memory at 0x%x\n",
size, virt_to_phys ( ptr ) );
if ( remainder > 0 ) {
printf ( "WARNING: destructively expanding free block "
"downwards to 0x%x\n",
virt_to_phys ( ptr - remainder ) );
}
#endif
/* Mark every kilobyte within this block as free. This is
* overkill for normal purposes, but helps when something has
* allocated base memory with a granularity finer than the
* BIOS granularity of 1kB. PXE ROMs tend to do this when
* they allocate their own memory. This method allows us to
* free their blocks (admittedly in a rather dangerous,
* tread-on-anything-either-side sort of way, but there's no
* other way to do it).
*
* Since we're marking every kB as free, there's actually no
* need for recording the size of the blocks. However, we
* keep this in so that debug messages are friendlier. It
* probably adds around 8 bytes to the overall code size.
*/
while ( size_kb > 0 ) {
/* Mark this block as unused */
free_block->magic = FREE_BLOCK_MAGIC;
free_block->size_kb = size_kb;
/* Move up by 1 kB */
free_block = (void *)(((char *)free_block) + (1 << 10));
size_kb--;
}
/* Free up unused base memory */
free_unused_base_memory();
}
void forget_base_memory ( void *ptr, size_t size )
{
/* Free memory, free real-mode stack, re-allocate real-mode
* stack. Do this so that we don't end up wasting a huge
* block of memory trapped behind the real-mode stack.
*/
_forget_base_memory ( ptr, size );
forget_real_mode_stack();
get_memsizes();
}
/* Do the actual freeing of memory. This is split out from
* forget_base_memory() so that it may be called separately. It
* should be called whenever base memory is deallocated by an external
* entity (if we can detect that it has done so) so that we get the
* chance to free up our own blocks.
*/
static void free_unused_base_memory ( void ) {
free_base_memory_block_t *free_block = NULL;
/* Try to release memory back to the BIOS. Free all
* consecutive blocks marked as free.
*/
while ( 1 ) {
/* Calculate address of next potential free block */
free_block = ( free_base_memory_block_t * )
phys_to_virt ( FREE_BASE_MEMORY );
/* Stop processing if we're all the way up to 640K or
* if this is not a free block
*/
if ( ( *fbms == BASE_MEMORY_MAX ) ||
( free_block->magic != FREE_BLOCK_MAGIC ) ) {
break;
}
/* Return memory to BIOS */
*fbms += free_block->size_kb;
#ifdef DEBUG_BASEMEM
printf ( "Freed %d kB base memory, %d kB now free\n",
free_block->size_kb, *fbms );
#endif
/* Zero out freed block. We do this in case
* the block contained any structures that
* might be located by scanning through
* memory.
*/
memset ( free_block, 0, free_block->size_kb << 10 );
}
}
/* Free base memory used by the prefix. Called once at start of
* Etherboot by arch_main().
*/
void forget_prefix_base_memory ( void )
{
/* runtime_start_kb is _text rounded down to a physical kB boundary */
uint32_t runtime_start_kb = virt_to_phys(_text) & ~0x3ff;
/* prefix_size_kb is the prefix size excluding any portion
* that overlaps into the first kB used by the runtime image
*/
uint32_t prefix_size_kb = runtime_start_kb - image_basemem;
#ifdef DEBUG_BASEMEM
printf ( "Attempting to free base memory used by prefix\n" );
#endif
/* If the decompressor is in allocated base memory
* *and* the Etherboot text is in base
* memory, then free the decompressor.
*/
if ( ( image_basemem >= FREE_BASE_MEMORY ) &&
( runtime_start_kb >= FREE_BASE_MEMORY ) &&
( runtime_start_kb <= ( BASE_MEMORY_MAX << 10 ) ) )
{
forget_base_memory ( phys_to_virt ( image_basemem ),
prefix_size_kb );
/* Update image_basemem and image_basemem_size to
* indicate that our allocation now starts with _text
*/
image_basemem = runtime_start_kb;
image_basemem_size -= prefix_size_kb;
}
}
/* Free base memory used by the runtime image. Called after
* relocation by arch_relocated_from().
*/
void forget_runtime_base_memory ( unsigned long old_addr )
{
/* text_start_kb is old _text rounded down to a physical KB boundary */
uint32_t old_text_start_kb = old_addr & ~0x3ff;
#ifdef DEBUG_BASEMEM
printf ( "Attempting to free base memory used by runtime image\n" );
#endif
if ( ( image_basemem >= FREE_BASE_MEMORY ) &&
( image_basemem == old_text_start_kb ) )
{
forget_base_memory ( phys_to_virt ( image_basemem ),
image_basemem_size );
/* Update image_basemem to show no longer in use */
image_basemem = 0;
image_basemem_size = 0;
}
}
#endif /* PCBIOS */

View File

@ -0,0 +1,155 @@
/* 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 CF ( 1 << 0 )
/**************************************************************************
CURRTICKS - Get Time
Use direct memory access to BIOS variables, longword 0040:006C (ticks
today) and byte 0040:0070 (midnight crossover flag) instead of calling
timeofday BIOS interrupt.
**************************************************************************/
#if defined(CONFIG_TSC_CURRTICKS)
#undef CONFIG_BIOS_CURRTICKS
#else
#define CONFIG_BIOS_CURRTICKS 1
#endif
#if defined(CONFIG_BIOS_CURRTICKS)
unsigned long currticks (void)
{
static uint32_t days = 0;
uint32_t *ticks = VIRTUAL(0x0040,0x006c);
uint8_t *midnight = VIRTUAL(0x0040,0x0070);
/* 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_call ( rm_currticks, NULL, NULL );
if ( *midnight ) {
*midnight = 0;
days += 0x1800b0;
}
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 );
}
#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 );
}
/**************************************************************************
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;
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"
);
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;
}
#endif /* TRY_FLOPPY_FIRST */
#endif /* PCBIOS */

View File

@ -0,0 +1,85 @@
/* Etherboot routines for PCBIOS firmware.
*
* Body of routines taken from old pcbios.S
*/
#ifdef PCBIOS
#include "etherboot.h"
#include "realmode.h"
#include "segoff.h"
#define ZF ( 1 << 6 )
/**************************************************************************
CONSOLE_PUTC - Print a character on console
**************************************************************************/
void console_putc ( int character )
{
struct {
reg16_t ax;
} PACKED in_stack;
RM_FRAGMENT(rm_console_putc,
"sti\n\t"
"popw %ax\n\t"
"movb $0x0e, %ah\n\t"
"movl $1, %ebx\n\t"
"int $0x10\n\t"
"cli\n\t"
);
in_stack.ax.l = character;
real_call ( rm_console_putc, &in_stack, NULL );
}
/**************************************************************************
CONSOLE_GETC - Get a character from console
**************************************************************************/
int console_getc ( void )
{
RM_FRAGMENT(rm_console_getc,
"sti\n\t"
"xorw %ax, %ax\n\t"
"int $0x16\n\t"
"xorb %ah, %ah\n\t"
"cli\n\t"
);
return real_call ( rm_console_getc, NULL, NULL );
}
/**************************************************************************
CONSOLE_ISCHAR - Check for keyboard interrupt
**************************************************************************/
int console_ischar ( void )
{
RM_FRAGMENT(rm_console_ischar,
"sti\n\t"
"movb $1, %ah\n\t"
"int $0x16\n\t"
"pushfw\n\t"
"popw %ax\n\t"
"cli\n\t"
);
return ( ( real_call ( rm_console_ischar, NULL, NULL ) & ZF ) == 0 );
}
/**************************************************************************
GETSHIFT - Get keyboard shift state
**************************************************************************/
int getshift ( void )
{
RM_FRAGMENT(rm_getshift,
"sti\n\t"
"movb $2, %ah\n\t"
"int $0x16\n\t"
"andw $0x3, %ax\n\t"
"cli\n\t"
);
return real_call ( rm_getshift, NULL, NULL );
}
#endif /* PCBIOS */

View File

@ -0,0 +1,296 @@
#undef CODE16
#if defined(PCBIOS)
#define CODE16
#endif
#ifdef CODE16
#define BOCHSBP xchgw %bx,%bx
.text
.arch i386
.section ".text16", "ax", @progbits
.code16
/****************************************************************************
* Memory map mangling code
****************************************************************************
*/
.globl e820mangler
e820mangler:
/* Macro to calculate offset of labels within code segment in
* installed copy of code.
*/
#define INSTALLED(x) ( (x) - e820mangler )
/****************************************************************************
* Intercept INT 15 memory calls and remove the hidden memory ranges
* from the resulting memory map.
****************************************************************************
*/
.globl _intercept_int15
_intercept_int15:
/* Preserve registers */
pushw %bp
/* Store %ax for future reference */
pushw %ax
/* Make INT-style call to old INT15 routine */
pushfw
lcall %cs:*INSTALLED(_intercepted_int15)
/* Preserve flags returned by original E820 routine */
pushfw
/* Check for valid INT15 routine */
jc intercept_int15_exit
/* Check for a routine we want to intercept */
movw %sp, %bp
cmpw $0xe820, 2(%bp)
je intercept_e820
cmpw $0xe801, 2(%bp)
je intercept_e801
cmpb $0x88, 3(%bp)
je intercept_88
intercept_int15_exit:
/* Restore registers and return */
popfw
popw %bp /* discard original %ax */
popw %bp
lret $2 /* 'iret' - flags already loaded */
.globl _intercepted_int15
_intercepted_int15: .word 0,0
/****************************************************************************
* Exclude an address range from a potentially overlapping address range
*
* Note: this *can* be called even if the range doesn't overlap; it
* will simply return the range unaltered. It copes with all the
* possible cases of overlap, including total overlap (which will
* modify the range to length zero). If the to-be-excluded range is
* in the middle of the target range, then the larger remaining
* portion will be returned. If %di is nonzero on entry then the
* range will only be truncated from the high end, i.e. the base
* address will never be altered. All this in less than 30
* instructions. :)
*
* Parameters:
* %eax Base address of memory range
* %ecx Length of memory range
* %ebx Base address of memory range to exclude
* %edx Length of memory range to exclude
* %di 0 => truncate either end, 1 => truncate high end only
* Returns:
* %eax Updated base address of range
* %ecx Updated length of range
* %ebx,%edx Undefined
* All other registers (including %di) preserved
*
* Note: "ja" is used rather than "jg" because we are comparing
* unsigned ints
****************************************************************************
*/
#ifdef TEST_EXCLUDE_ALGORITHM
.code32
#endif /* TEST_EXCLUDE_ALGORITHM */
exclude_memory_range:
/* Convert (start,length) to (start,end) */
addl %eax, %ecx
addl %ebx, %edx
/* Calculate "prefix" length */
subl %eax, %ebx /* %ebx = "prefix" length */
ja 1f
xorl %ebx, %ebx /* Truncate to zero if negative */
1: /* %di == 0 => truncate either end
* %di != 0 => truncate only high end
*/
testw %di, %di
je use_either
cmpl %eax, %edx
jbe 99f /* excl. range is below target range */
use_prefix: /* Use prefix, discard suffix */
addl %eax, %ebx /* %ebx = candidate end address */
cmpl %ecx, %ebx /* %ecx = min ( %ebx, %ecx ) */
ja 1f
movl %ebx, %ecx
1: jmp 99f
use_either:
/* Calculate "suffix" length */
subl %ecx, %edx /* %edx = -( "suffix" length ) */
jb 1f
xorl %edx, %edx /* Truncate to zero if negative */
1: negl %edx /* %edx = "suffix" length */
/* Use whichever is longest of "prefix" and "suffix" */
cmpl %ebx, %edx
jbe use_prefix
use_suffix: /* Use suffix, discard prefix */
negl %edx
addl %ecx, %edx /* %edx = candidate start address */
cmpl %eax, %edx /* %eax = max ( %eax, %edx ) */
jb 1f
movl %edx, %eax
1:
99: subl %eax, %ecx /* Convert back to (start,length) */
ret
#ifdef TEST_EXCLUDE_ALGORITHM
.globl __test_exclude
__test_exclude:
pushl %ebx
pushl %edi
movl 12(%esp), %eax
movl 16(%esp), %ecx
movl 20(%esp), %ebx
movl 24(%esp), %edx
movl 28(%esp), %edi
call exclude_memory_range
shll $16, %eax
orl %ecx, %eax
popl %edi
popl %ebx
ret
.code16
#endif /* TEST_EXCLUDE_ALGORITHM */
/****************************************************************************
* Exclude Etherboot-reserved address ranges from a potentially
* overlapping address range
*
* Parameters:
* %eax Base address of memory range
* %ecx Length of memory range
* %di 0 => truncate either end, 1 => truncate high end only
* Returns:
* %eax Updated base address of range
* %ecx Updated length of range
* All other registers (including %di) preserved
****************************************************************************
*/
exclude_hidden_memory_ranges:
pushw %si
pushl %ebx
pushl %edx
movw $INSTALLED(_hide_memory), %si
2: movl %cs:0(%si), %ebx
movl %cs:4(%si), %edx
call exclude_memory_range
addw $8, %si
cmpw $INSTALLED(_hide_memory_end), %si
jl 2b
popl %edx
popl %ebx
popw %si
ret
.globl _hide_memory
_hide_memory:
.long 0,0 /* Etherboot text (base,length) */
.long 0,0 /* Heap (base,length) */
_hide_memory_end:
/****************************************************************************
* Intercept INT 15,E820 calls and remove the hidden memory ranges
* from the resulting memory map.
****************************************************************************
*/
#define SMAP ( 0x534d4150 )
intercept_e820:
/* Check for valid E820 routine */
cmpl $SMAP, %eax
jne intercept_int15_exit
/* If base address isn't in the low 4GB, return unaltered
* (since we never claim memory above 4GB). WARNING: we cheat
* by assuming that no E820 region will straddle the 4GB
* boundary: if this is not a valid assumption then things
* will probably break.
*/
cmpl $0, %es:4(%di)
jne intercept_int15_exit
/* Preserve registers */
pushl %eax
pushl %ecx
/* Update returned memory range */
movl %es:0(%di), %eax /* Base */
movl %es:8(%di), %ecx /* Length */
pushw %di
xorw %di, %di /* "truncate either end" flag */
call exclude_hidden_memory_ranges
popw %di
movl %eax, %es:0(%di) /* Store updated base */
movl %ecx, %es:8(%di) /* Store updated length */
/* Restore registers and return */
popl %ecx
popl %eax
jmp intercept_int15_exit
/****************************************************************************
* Intercept INT 15,E801 calls and remove the hidden memory ranges
* from the resulting memory map.
****************************************************************************
*/
intercept_e801:
/* Adjust return values */
call e801_adjust
xchgw %ax, %cx
xchgw %bx, %dx
call e801_adjust
xchgw %ax, %cx
xchgw %bx, %dx
jmp intercept_int15_exit
/* %ax = #KB from 1MB+, %bx = #64KB from 16MB+
* Return with modified values in %ax, %bx. Preserver other regs.
*/
e801_adjust:
pushw %di
pushl %ecx
pushl %eax
movw $1, %di /* "truncate only high end" flag */
/* Truncate #64KB from 16MB+ as appropriate */
movw %bx, %cx /* (no need to zero high word) */
shll $16, %ecx /* %ecx = length in bytes */
movl $(1<<24), %eax /* 16MB start address */
call exclude_hidden_memory_ranges
shrl $16, %ecx /* %cx = updated length in 64KB */
movw %cx, %bx /* Return in %bx */
/* Truncate #KB from 1MB+ as appropriate */
popw %cx /* Orig. %ax (high word already 0) */
shll $10, %ecx /* %ecx = length in bytes */
shrl $4, %eax /* 1MB start address */
call exclude_hidden_memory_ranges
shrl $10, %ecx /* %cx = updated length in KB */
pushw %cx /* Will be picked up in %eax */
popl %eax
popl %ecx
popw %di
ret
/****************************************************************************
* Intercept INT 15,88 calls and remove the hidden memory ranges
* from the resulting memory map.
****************************************************************************
*/
intercept_88:
pushw %bx /* E801 adjust, ignore %bx */
call e801_adjust
popw %bx
jmp intercept_int15_exit
.globl e820mangler_end
e820mangler_end:
.globl _e820mangler_size
.equ _e820mangler_size, e820mangler_end - e820mangler
.globl e820mangler_size
e820mangler_size:
.word _e820mangler_size
#else
.globl _e820mangler_size
.equ _e820mangler_size, 0
#endif /* CODE16 */

View File

@ -0,0 +1,94 @@
/* Utility functions to hide Etherboot by manipulating the E820 memory
* map. These could go in memsizes.c, but are placed here because not
* all images will need them.
*/
#include "etherboot.h"
#include "hidemem.h"
#ifdef CODE16
static int mangling = 0;
static void *mangler = NULL;
#define INSTALLED(x) ( (typeof(&x)) ( (void*)(&x) - (void*)e820mangler \
+ mangler ) )
#define intercept_int15 INSTALLED(_intercept_int15)
#define intercepted_int15 INSTALLED(_intercepted_int15)
#define hide_memory INSTALLED(_hide_memory)
#define INT15_VECTOR ( (segoff_t*) ( phys_to_virt( 4 * 0x15 ) ) )
int install_e820mangler ( void *new_mangler ) {
if ( mangling ) return 0;
memcpy ( new_mangler, &e820mangler, e820mangler_size );
mangler = new_mangler;
return 1;
}
/* Intercept INT15 calls and pass them through the mangler. The
* mangler must have been copied to base memory before making this
* call, and "mangler" must point to the base memory copy, which must
* be 16-byte aligned.
*/
int hide_etherboot ( void ) {
if ( mangling ) return 1;
if ( !mangler ) return 0;
/* Hook INT15 handler */
*intercepted_int15 = *INT15_VECTOR;
(*hide_memory)[0].start = virt_to_phys(_text);
(*hide_memory)[0].length = _end - _text;
/* IMPORTANT, possibly even FIXME:
*
* Etherboot has a tendency to claim a very large area of
* memory as possible heap; enough to make it impossible to
* load an OS if we hide all of it. We hide only the portion
* that's currently in use. This means that we MUST NOT
* perform further allocations from the heap while the mangler
* is active.
*/
(*hide_memory)[1].start = heap_ptr;
(*hide_memory)[1].length = heap_bot - heap_ptr;
INT15_VECTOR->segment = SEGMENT(mangler);
INT15_VECTOR->offset = 0;
mangling = 1;
return 1;
}
int unhide_etherboot ( void ) {
if ( !mangling ) return 1;
/* Restore original INT15 handler
*/
if ( VIRTUAL(INT15_VECTOR->segment,INT15_VECTOR->offset) != mangler ) {
/* Oh dear... */
#ifdef WORK_AROUND_BPBATCH_BUG
/* BpBatch intercepts INT15, so can't unhook it, and
* then proceeds to ignore our PXENV_KEEP_UNDI return
* status, which means that it ends up zeroing out the
* INT15 handler routine.
*
* This rather ugly hack involves poking into
* BpBatch's code and changing it's stored value for
* the "next handler" in the INT15 chain.
*/
segoff_t *bp_chain = VIRTUAL ( 0x0060, 0x8254 );
if ( ( bp_chain->segment == SEGMENT(mangler) ) &&
( bp_chain->offset == 0 ) ) {
printf ( "\nBPBATCH bug workaround enabled\n" );
*bp_chain = *intercepted_int15;
}
#endif /* WORK_AROUND_BPBATCH_BUG */
return 0;
}
*INT15_VECTOR = *intercepted_int15;
mangling = 0;
return 1;
}
#endif /* CODE16 */

View File

@ -0,0 +1,201 @@
#ifdef PCBIOS
#include "etherboot.h"
#include "realmode.h"
#define CF ( 1 << 0 )
#ifndef MEMSIZES_DEBUG
#define MEMSIZES_DEBUG 0
#endif
/* by Eric Biederman */
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 );
}
/**************************************************************************
MEMSIZE - Determine size of extended memory
**************************************************************************/
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;
int memsize;
RM_FRAGMENT(rm_memsize,
/* 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"
);
/* 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;
} else {
/* Use cx,dx */
memsize = ( out_stack.dx.word<<6 ) + out_stack.cx.word;
}
}
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;
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;
}
return index;
}
void get_memsizes(void)
{
/* Ensure we don't stomp bios data structutres.
* the interrupt table: 0x000 - 0x3ff
* the bios data area: 0x400 - 0x502
* Dos variables: 0x502 - 0x5ff
*/
static const unsigned min_addr = 0x600;
unsigned i;
unsigned basemem;
basemem = get_free_base_memory();
meminfo.basememsize = basememsize();
meminfo.memsize = memsize();
#ifndef IGNORE_E820_MAP
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 */
meminfo.map_count = 2;
meminfo.map[0].addr = 0;
meminfo.map[0].size = meminfo.basememsize << 10;
meminfo.map[0].type = E820_RAM;
meminfo.map[1].addr = 1024*1024;
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) {
continue;
}
/* Reserve the bios data structures */
if (meminfo.map[i].addr < min_addr) {
unsigned long delta;
delta = min_addr - meminfo.map[i].addr;
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
*/
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++) {
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
}
}
#endif
}
#endif /* PCBIOS */

View File

@ -0,0 +1,45 @@
#ifndef ETHERBOOT_BITS_BYTESWAP_H
#define ETHERBOOT_BITS_BYTESWAP_H
static inline uint16_t __i386_bswap_16(uint16_t x)
{
__asm__("xchgb %b0,%h0\n\t"
: "=q" (x)
: "0" (x));
return x;
}
static inline uint32_t __i386_bswap_32(uint32_t x)
{
__asm__("xchgb %b0,%h0\n\t"
"rorl $16,%0\n\t"
"xchgb %b0,%h0"
: "=q" (x)
: "0" (x));
return x;
}
#define __bswap_constant_16(x) \
((uint16_t)((((uint16_t)(x) & 0x00ff) << 8) | \
(((uint16_t)(x) & 0xff00) >> 8)))
#define __bswap_constant_32(x) \
((uint32_t)((((uint32_t)(x) & 0x000000ffU) << 24) | \
(((uint32_t)(x) & 0x0000ff00U) << 8) | \
(((uint32_t)(x) & 0x00ff0000U) >> 8) | \
(((uint32_t)(x) & 0xff000000U) >> 24)))
#define __bswap_16(x) \
((uint16_t)(__builtin_constant_p(x) ? \
__bswap_constant_16(x) : \
__i386_bswap_16(x)))
#define __bswap_32(x) \
((uint32_t)(__builtin_constant_p(x) ? \
__bswap_constant_32(x) : \
__i386_bswap_32(x)))
#endif /* ETHERBOOT_BITS_BYTESWAP_H */

View File

@ -0,0 +1,243 @@
#ifndef I386_BITS_CPU_H
#define I386_BITS_CPU_H
/* Sample usage: CPU_FEATURE_P(cpu.x86_capability, FPU) */
#define CPU_FEATURE_P(CAP, FEATURE) \
(!!(CAP[(X86_FEATURE_##FEATURE)/32] & ((X86_FEATURE_##FEATURE) & 0x1f)))
#define NCAPINTS 4 /* Currently we have 4 32-bit words worth of info */
/* Intel-defined CPU features, CPUID level 0x00000001, word 0 */
#define X86_FEATURE_FPU (0*32+ 0) /* Onboard FPU */
#define X86_FEATURE_VME (0*32+ 1) /* Virtual Mode Extensions */
#define X86_FEATURE_DE (0*32+ 2) /* Debugging Extensions */
#define X86_FEATURE_PSE (0*32+ 3) /* Page Size Extensions */
#define X86_FEATURE_TSC (0*32+ 4) /* Time Stamp Counter */
#define X86_FEATURE_MSR (0*32+ 5) /* Model-Specific Registers, RDMSR, WRMSR */
#define X86_FEATURE_PAE (0*32+ 6) /* Physical Address Extensions */
#define X86_FEATURE_MCE (0*32+ 7) /* Machine Check Architecture */
#define X86_FEATURE_CX8 (0*32+ 8) /* CMPXCHG8 instruction */
#define X86_FEATURE_APIC (0*32+ 9) /* Onboard APIC */
#define X86_FEATURE_SEP (0*32+11) /* SYSENTER/SYSEXIT */
#define X86_FEATURE_MTRR (0*32+12) /* Memory Type Range Registers */
#define X86_FEATURE_PGE (0*32+13) /* Page Global Enable */
#define X86_FEATURE_MCA (0*32+14) /* Machine Check Architecture */
#define X86_FEATURE_CMOV (0*32+15) /* CMOV instruction (FCMOVCC and FCOMI too if FPU present) */
#define X86_FEATURE_PAT (0*32+16) /* Page Attribute Table */
#define X86_FEATURE_PSE36 (0*32+17) /* 36-bit PSEs */
#define X86_FEATURE_PN (0*32+18) /* Processor serial number */
#define X86_FEATURE_CLFLSH (0*32+19) /* Supports the CLFLUSH instruction */
#define X86_FEATURE_DTES (0*32+21) /* Debug Trace Store */
#define X86_FEATURE_ACPI (0*32+22) /* ACPI via MSR */
#define X86_FEATURE_MMX (0*32+23) /* Multimedia Extensions */
#define X86_FEATURE_FXSR (0*32+24) /* FXSAVE and FXRSTOR instructions (fast save and restore */
/* of FPU context), and CR4.OSFXSR available */
#define X86_FEATURE_XMM (0*32+25) /* Streaming SIMD Extensions */
#define X86_FEATURE_XMM2 (0*32+26) /* Streaming SIMD Extensions-2 */
#define X86_FEATURE_SELFSNOOP (0*32+27) /* CPU self snoop */
#define X86_FEATURE_HT (0*32+28) /* Hyper-Threading */
#define X86_FEATURE_ACC (0*32+29) /* Automatic clock control */
#define X86_FEATURE_IA64 (0*32+30) /* IA-64 processor */
/* AMD-defined CPU features, CPUID level 0x80000001, word 1 */
/* Don't duplicate feature flags which are redundant with Intel! */
#define X86_FEATURE_SYSCALL (1*32+11) /* SYSCALL/SYSRET */
#define X86_FEATURE_MMXEXT (1*32+22) /* AMD MMX extensions */
#define X86_FEATURE_LM (1*32+29) /* Long Mode (x86-64) */
#define X86_FEATURE_3DNOWEXT (1*32+30) /* AMD 3DNow! extensions */
#define X86_FEATURE_3DNOW (1*32+31) /* 3DNow! */
/* Transmeta-defined CPU features, CPUID level 0x80860001, word 2 */
#define X86_FEATURE_RECOVERY (2*32+ 0) /* CPU in recovery mode */
#define X86_FEATURE_LONGRUN (2*32+ 1) /* Longrun power control */
#define X86_FEATURE_LRTI (2*32+ 3) /* LongRun table interface */
/* Other features, Linux-defined mapping, word 3 */
/* This range is used for feature bits which conflict or are synthesized */
#define X86_FEATURE_CXMMX (3*32+ 0) /* Cyrix MMX extensions */
#define X86_FEATURE_K6_MTRR (3*32+ 1) /* AMD K6 nonstandard MTRRs */
#define X86_FEATURE_CYRIX_ARR (3*32+ 2) /* Cyrix ARRs (= MTRRs) */
#define X86_FEATURE_CENTAUR_MCR (3*32+ 3) /* Centaur MCRs (= MTRRs) */
#define MAX_X86_VENDOR_ID 16
struct cpuinfo_x86 {
uint8_t x86; /* CPU family */
uint8_t x86_model;
uint8_t x86_mask;
int cpuid_level; /* Maximum supported CPUID level, -1=no CPUID */
unsigned x86_capability[NCAPINTS];
char x86_vendor_id[MAX_X86_VENDOR_ID];
};
#define X86_VENDOR_INTEL 0
#define X86_VENDOR_CYRIX 1
#define X86_VENDOR_AMD 2
#define X86_VENDOR_UMC 3
#define X86_VENDOR_NEXGEN 4
#define X86_VENDOR_CENTAUR 5
#define X86_VENDOR_RISE 6
#define X86_VENDOR_TRANSMETA 7
#define X86_VENDOR_NSC 8
#define X86_VENDOR_UNKNOWN 0xff
/*
* EFLAGS bits
*/
#define X86_EFLAGS_CF 0x00000001 /* Carry Flag */
#define X86_EFLAGS_PF 0x00000004 /* Parity Flag */
#define X86_EFLAGS_AF 0x00000010 /* Auxillary carry Flag */
#define X86_EFLAGS_ZF 0x00000040 /* Zero Flag */
#define X86_EFLAGS_SF 0x00000080 /* Sign Flag */
#define X86_EFLAGS_TF 0x00000100 /* Trap Flag */
#define X86_EFLAGS_IF 0x00000200 /* Interrupt Flag */
#define X86_EFLAGS_DF 0x00000400 /* Direction Flag */
#define X86_EFLAGS_OF 0x00000800 /* Overflow Flag */
#define X86_EFLAGS_IOPL 0x00003000 /* IOPL mask */
#define X86_EFLAGS_NT 0x00004000 /* Nested Task */
#define X86_EFLAGS_RF 0x00010000 /* Resume Flag */
#define X86_EFLAGS_VM 0x00020000 /* Virtual Mode */
#define X86_EFLAGS_AC 0x00040000 /* Alignment Check */
#define X86_EFLAGS_VIF 0x00080000 /* Virtual Interrupt Flag */
#define X86_EFLAGS_VIP 0x00100000 /* Virtual Interrupt Pending */
#define X86_EFLAGS_ID 0x00200000 /* CPUID detection flag */
/*
* Generic CPUID function
*/
static inline void cpuid(int op,
unsigned int *eax, unsigned int *ebx, unsigned int *ecx, unsigned int *edx)
{
__asm__("cpuid"
: "=a" (*eax),
"=b" (*ebx),
"=c" (*ecx),
"=d" (*edx)
: "0" (op));
}
/*
* CPUID functions returning a single datum
*/
static inline unsigned int cpuid_eax(unsigned int op)
{
unsigned int eax;
__asm__("cpuid"
: "=a" (eax)
: "0" (op)
: "bx", "cx", "dx");
return eax;
}
static inline unsigned int cpuid_ebx(unsigned int op)
{
unsigned int eax, ebx;
__asm__("cpuid"
: "=a" (eax), "=b" (ebx)
: "0" (op)
: "cx", "dx" );
return ebx;
}
static inline unsigned int cpuid_ecx(unsigned int op)
{
unsigned int eax, ecx;
__asm__("cpuid"
: "=a" (eax), "=c" (ecx)
: "0" (op)
: "bx", "dx" );
return ecx;
}
static inline unsigned int cpuid_edx(unsigned int op)
{
unsigned int eax, edx;
__asm__("cpuid"
: "=a" (eax), "=d" (edx)
: "0" (op)
: "bx", "cx");
return edx;
}
/*
* Intel CPU features in CR4
*/
#define X86_CR4_VME 0x0001 /* enable vm86 extensions */
#define X86_CR4_PVI 0x0002 /* virtual interrupts flag enable */
#define X86_CR4_TSD 0x0004 /* disable time stamp at ipl 3 */
#define X86_CR4_DE 0x0008 /* enable debugging extensions */
#define X86_CR4_PSE 0x0010 /* enable page size extensions */
#define X86_CR4_PAE 0x0020 /* enable physical address extensions */
#define X86_CR4_MCE 0x0040 /* Machine check enable */
#define X86_CR4_PGE 0x0080 /* enable global pages */
#define X86_CR4_PCE 0x0100 /* enable performance counters at ipl 3 */
#define X86_CR4_OSFXSR 0x0200 /* enable fast FPU save and restore */
#define X86_CR4_OSXMMEXCPT 0x0400 /* enable unmasked SSE exceptions */
#define MSR_K6_EFER 0xC0000080
/* EFER bits: */
#define _EFER_SCE 0 /* SYSCALL/SYSRET */
#define _EFER_LME 8 /* Long mode enable */
#define _EFER_LMA 10 /* Long mode active (read-only) */
#define _EFER_NX 11 /* No execute enable */
#define EFER_SCE (1<<_EFER_SCE)
#define EFER_LME (1<<EFER_LME)
#define EFER_LMA (1<<EFER_LMA)
#define EFER_NX (1<<_EFER_NX)
#define rdmsr(msr,val1,val2) \
__asm__ __volatile__("rdmsr" \
: "=a" (val1), "=d" (val2) \
: "c" (msr))
#define wrmsr(msr,val1,val2) \
__asm__ __volatile__("wrmsr" \
: /* no outputs */ \
: "c" (msr), "a" (val1), "d" (val2))
#define read_cr0() ({ \
unsigned int __dummy; \
__asm__( \
"movl %%cr0, %0\n\t" \
:"=r" (__dummy)); \
__dummy; \
})
#define write_cr0(x) \
__asm__("movl %0,%%cr0": :"r" (x));
#define read_cr3() ({ \
unsigned int __dummy; \
__asm__( \
"movl %%cr3, %0\n\t" \
:"=r" (__dummy)); \
__dummy; \
})
#define write_cr3x(x) \
__asm__("movl %0,%%cr3": :"r" (x));
#define read_cr4() ({ \
unsigned int __dummy; \
__asm__( \
"movl %%cr4, %0\n\t" \
:"=r" (__dummy)); \
__dummy; \
})
#define write_cr4x(x) \
__asm__("movl %0,%%cr4": :"r" (x));
extern struct cpuinfo_x86 cpu_info;
#ifdef CONFIG_X86_64
extern void cpu_setup(void);
#else
#define cpu_setup() do {} while(0)
#endif
#endif /* I386_BITS_CPU_H */

Some files were not shown because too many files have changed in this diff Show More