mirror of https://github.com/ipxe/ipxe.git
Initial revision
commit
3d6123e69a
|
@ -0,0 +1,2 @@
|
|||
bin
|
||||
gcccheck
|
|
@ -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
|
|
@ -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
|
|
@ -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
|
|
@ -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
|
|
@ -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
|
|
@ -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
|
|
@ -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
|
|
@ -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)
|
|
@ -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.
|
|
@ -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"
|
|
@ -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 $< $@
|
|
@ -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();
|
||||
}
|
|
@ -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);
|
||||
}
|
||||
}
|
|
@ -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;
|
||||
}
|
|
@ -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;
|
||||
}
|
|
@ -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
|
|
@ -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
|
|
@ -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;
|
|
@ -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 */
|
|
@ -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,
|
||||
};
|
|
@ -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 */
|
|
@ -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 */
|
|
@ -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 */
|
|
@ -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 */
|
|
@ -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 */
|
|
@ -0,0 +1 @@
|
|||
/* empty 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 */
|
|
@ -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 */
|
|
@ -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 */
|
|
@ -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 */
|
|
@ -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
|
|
@ -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 */
|
|
@ -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 */
|
|
@ -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 */
|
|
@ -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'"
|
||||
|
|
@ -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
|
|
@ -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
|
||||
|
|
@ -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
|
||||
|
|
@ -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;
|
||||
}
|
|
@ -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 ! */
|
||||
|
||||
}
|
||||
|
|
@ -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();
|
||||
}
|
|
@ -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_ ]
|
||||
}
|
||||
}
|
|
@ -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_
|
||||
}
|
|
@ -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
|
||||
|
|
@ -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
|
|
@ -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
|
|
@ -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;
|
||||
}
|
|
@ -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
|
|
@ -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
|
||||
|
|
@ -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 */
|
|
@ -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 */
|
|
@ -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 */
|
|
@ -0,0 +1,6 @@
|
|||
#ifndef ETHERBOOT_BITS_ENDIAN_H
|
||||
#define ETHERBOOT_BITS_ENDIAN_H
|
||||
|
||||
#define __BYTE_ORDER __BIG_ENDIAN
|
||||
|
||||
#endif /* ETHERBOOT_BITS_ENDIAN_H */
|
|
@ -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 */
|
|
@ -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 */
|
|
@ -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 */
|
|
@ -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 */
|
|
@ -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 */
|
|
@ -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
|
|
@ -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
|
|
@ -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 */
|
|
@ -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
|
|
@ -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
|
||||
|
|
@ -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;
|
||||
}
|
|
@ -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 */
|
|
@ -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 */
|
|
@ -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(¬es, 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(¬es.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(¬es.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(¬es, 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 ¬es.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);
|
||||
}
|
|
@ -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 ;
|
||||
|
||||
}
|
|
@ -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 ;
|
||||
}
|
|
@ -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
|
|
@ -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
|
||||
}
|
|
@ -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 */
|
|
@ -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 */
|
|
@ -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);
|
||||
}
|
|
@ -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 */
|
|
@ -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
|
|
@ -0,0 +1,8 @@
|
|||
OUTPUT_FORMAT("elf32-i386", "elf32-i386", "elf32-i386")
|
||||
OUTPUT_ARCH(i386)
|
||||
|
||||
SECTIONS {
|
||||
.prefix.udata : {
|
||||
*(*)
|
||||
}
|
||||
}
|
|
@ -0,0 +1,8 @@
|
|||
OUTPUT_FORMAT("elf32-i386", "elf32-i386", "elf32-i386")
|
||||
OUTPUT_ARCH(i386)
|
||||
|
||||
SECTIONS {
|
||||
.prefix.zdata : {
|
||||
*(*)
|
||||
}
|
||||
}
|
|
@ -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 */
|
|
@ -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 );
|
||||
}
|
|
@ -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;
|
||||
}
|
|
@ -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 */
|
|
@ -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:
|
|
@ -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
|
|
@ -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 );
|
||||
}
|
||||
|
|
@ -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
|
|
@ -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 );
|
||||
}
|
|
@ -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
|
||||
|
|
@ -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
|
@ -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
|
|
@ -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 */
|
|
@ -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 */
|
|
@ -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 */
|
|
@ -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 */
|
|
@ -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 */
|
|
@ -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 */
|
|
@ -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 */
|
|
@ -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
Loading…
Reference in New Issue