Compare commits

...

31 Commits

Author SHA1 Message Date
900f1f98d3 [librm] Test for FXSAVE/FXRSTOR instruction support
Assume that preservation of the %xmm registers is unnecessary during
installation of iPXE into memory, since this is an operation that by
its nature substantially disrupts large portions of the system anyway
(such as the E820 memory map).  This assumption allows us to utilise
the existing CPUID code to check that FXSAVE/FXRSTOR are supported.

Test for support during the call to init_librm and store the flag for
use during subsequent calls to virt_call.

Reduce the scope of TIVOLI_VMM_WORKAROUND to affecting only the call
to check_fxsr(), to reduce #ifdef pollution in the remaining code.

Debugged-by: Johannes Heimansberg <git@jhe.dedyn.io>
Signed-off-by: Michael Brown <mcb30@ipxe.org>
2021-02-18 15:38:56 +00:00
e63b8c3302 [librm] Add missing __asmcall on init_idt()
The __asmcall declaration has no effect on a void function with no
parameters, but should be included for completeness since the function
is called directly from assembly code.

Signed-off-by: Michael Brown <mcb30@ipxe.org>
2021-02-18 14:52:25 +00:00
22bb29eabc [prefix] Add a generic raw image prefix
Provide a generic raw image prefix, which assumes that the iPXE image
has been loaded in its entirety on a paragraph boundary.

The resulting .raw image can be loaded via RPL using an rpld.conf file
such as:

    HOST {
        ethernet = 00:00:00:00:00:00/6;
        FILE {
            path="ipxe.raw";
            load=0x2000;
        };
        execute=0x2000;
    };

Debugged-by: Johannes Heimansberg <git@jhe.dedyn.io>
Signed-off-by: Michael Brown <mcb30@ipxe.org>
2021-02-18 13:53:26 +00:00
8446a439b3 [initrd] Allow for zero-length initrd files
A zero-length initrd file will currently cause an endless loop during
reshuffling as the empty image is repeatedly swapped with itself.

Fix by terminating the inner loop before considering an image as a
candidate to be swapped with itself.

Reported-by: Pico Mitchell <pico@randomapplications.com>
Signed-off-by: Michael Brown <mcb30@ipxe.org>
2021-02-18 01:49:23 +00:00
4039b54ba3 [cloud] Do not enable serial console on EFI platforms
Most EFI firmware builds (including those found on ARM64 instances in
AWS EC2) will already send console output to the serial port.

Do not enable direct serial console output in EFI builds using
CONFIG=cloud.

Signed-off-by: Michael Brown <mcb30@ipxe.org>
2021-02-17 22:38:38 +00:00
cd3de55ea5 [efi] Record cached DHCPACK from loaded image's device handle, if present
Record the cached DHCPACK obtained from the EFI_PXE_BASE_CODE_PROTOCOL
instance installed on the loaded image's device handle, if present.

This allows a chainloaded UEFI iPXE to reuse the IPv4 address and DHCP
options previously obtained by the built-in PXE stack, as is already
done for a chainloaded BIOS iPXE.

Signed-off-by: Michael Brown <mcb30@ipxe.org>
2021-02-17 18:11:43 +00:00
d562339fca [efi] Defer autoboot link-layer address and autoexec script probing
The code to detect the autoboot link-layer address and to load the
autoexec script currently runs before the call to initialise() and so
has to function without a working heap.

This requirement can be relaxed by deferring this code to run via an
initialisation function.  This gives the code a normal runtime
environment, but still invokes it early enough to guarantee that the
original loaded image device handle has not yet been invalidated.

Signed-off-by: Michael Brown <mcb30@ipxe.org>
2021-02-17 17:14:19 +00:00
e39cd79a00 [efi] Split out autoexec script portions of efi_autoboot.c
The "autoboot device" and "autoexec script" functionalities in
efi_autoboot.c are unrelated except in that they both need to be
invoked by efiprefix.c before device drivers are loaded.

Split out the autoexec script portions to a separate file to avoid
potential confusion.

Signed-off-by: Michael Brown <mcb30@ipxe.org>
2021-02-17 17:14:19 +00:00
057674bb1f [pxe] Split out platform-independent portions of cachedhcp.c
Split out the portions of cachedhcp.c that can be shared between BIOS
and UEFI (both of which can provide a buffer containing a previously
obtained DHCP packet, and neither of which provide a means to
determine the length of this DHCP packet).

Signed-off-by: Michael Brown <mcb30@ipxe.org>
2021-02-17 15:59:52 +00:00
19d0fab40f [ath5k] Add missing AR5K_EEPROM_READ in ath5k_eeprom_read_turbo_modes
The GCC11 compiler pointed out something that apparently no previous
compiler noticed: in ath5k_eeprom_pread_turbo_modes, local variable
val is used uninitialized. From what I can see, the code is just
missing an initial AR5K_EEPROM_READ. Add it right before the switch
statement.

Signed-off-by: Bruce Rogers <brogers@suse.com>
Signed-off-by: Michael Brown <mcb30@ipxe.org>
2021-02-16 23:35:24 +00:00
fa012dd020 [cloud] Enable IPv6 and HTTPS in cloud boot images
Signed-off-by: Michael Brown <mcb30@ipxe.org>
2021-02-16 10:58:42 +00:00
d16535aa4f [cloud] Add utility for importing images to AWS EC2
Add a utility that can be used to upload an iPXE disk image to AWS EC2
as an Amazon Machine Image (AMI).  For example:

  make CONFIG=cloud EMBED=config/cloud/aws.ipxe bin/ipxe.usb

  ../contrib/cloud/aws-import -p -n "iPXE 1.21.1" bin/ipxe.usb

Uploads are performed in parallel across all regions, and use the EBS
direct APIs to avoid the need to store temporary files in S3 or to run
VM import tasks.

Signed-off-by: Michael Brown <mcb30@ipxe.org>
2021-02-16 00:27:40 +00:00
1b99ba2a93 [build] Work around stray sections introduced by some binutils versions
Some versions of GNU ld (observed with binutils 2.36 on Arch Linux)
introduce a .note.gnu.property section marked as loadable at a high
address and with non-empty contents.  This adds approximately 128MB of
garbage to the BIOS .usb disk images.

Fix by using a custom linker script for the prefix-only binaries such
as the USB disk partition table and MBR, in order to allow unwanted
sections to be explicitly discarded.

Reported-by: Christian Hesse <mail@eworm.de>
Tested-by: Christian Hesse <mail@eworm.de>
Signed-off-by: Michael Brown <mcb30@ipxe.org>
2021-02-15 10:02:32 +00:00
83516ba7f0 [cloud] Use PCIAPI_DIRECT for cloud images
The version of SeaBIOS found on some AWS EC2 instances (observed with
t3a.nano in eu-west-1) has no support for the INT 1A PCI BIOS calls.

Bring config/ioapi.h into the named-configuration set of headers, and
specify the use of PCIAPI_DIRECT for CONFIG=cloud, to work around the
missing PCI BIOS support.

Switching to a different named configuration will now unfortunately
cause an almost complete rebuild of iPXE.  As described in commit
c801cb2 ("[build] Allow for named configurations at build time"), this
is the reason why config/ioapi.h was not originally in the
named-configuration set of header files.

This rebuild cost is acceptable given that build times are
substantially faster now than seven years ago, and that very few
people are likely to be switching named configurations on a regular
basis.

Signed-off-by: Michael Brown <mcb30@ipxe.org>
2021-02-13 19:41:03 +00:00
0049243367 [ena] Switch to two-phase reset mechanism
The Linux and FreeBSD drivers for the (totally undocumented) ENA
adapters use a two-phase reset mechanism: first set ENA_CTRL.RESET and
wait for this to be reflected in ENA_STAT.RESET, then clear
ENA_CTRL.RESET and again wait for it to be reflected in
ENA_STAT.RESET.

The iPXE driver currently assumes a self-clearing reset mechanism,
which appeared to work at the time that the driver was created but
seems no longer to function, at least on the t3.nano and t3a.nano
instance types found in eu-west-1.

Switch to a simplified version of the two-phase reset mechanism as
used by Linux and FreeBSD.

Signed-off-by: Michael Brown <mcb30@ipxe.org>
2021-02-13 19:08:45 +00:00
c160fb2593 [build] Use .balign directive instead of .align
The semantics of the assembler's .align directive vary by CPU
architecture.  For the ARM builds, it specifies a power of two rather
than a number of bytes.  This currently leads to the .einfo entries
(which do not appear in the final binary) having an alignment of 256
bytes for the ARM builds.

Fix by switching to the GNU-specific directive .balign, which is
consistent across architectures

Signed-off-by: Michael Brown <mcb30@ipxe.org>
2021-02-12 23:22:54 +00:00
b539e9a7e9 [build] Remove support for building with the Intel C compiler
Support for building with the Intel C compiler (icc) was added in 2009
in the expectation that UEFI support would eventually involve
compiling iPXE to EFI Byte Code.

EFI Byte Code has never found any widespread use: no widely available
compilers can emit it, Microsoft refuses to sign EFI Byte Code
binaries for UEFI Secure Boot, and I have personally never encountered
any examples of EFI Byte Code in the wild.

The support for using the Intel C compiler has not been tested in over
a decade, and would almost certainly require modification to work with
current releases of the compiler.

Simplify the build process by removing this old legacy code.

Signed-off-by: Michael Brown <mcb30@ipxe.org>
2021-02-12 22:08:41 +00:00
df16df2c85 [build] Report detailed errors when unable to find a usable mkisofs
As of commit 7c3d186 ("[build] Check that mkisofs equivalent supports
the required options"), we may refuse to use a mkisofs equivalent if
it does not support the options required to produce the requested
output file.

This can result in confusing error messages since the user is unaware
of the reason for which the installed mkisofs or genisoimage has been
rejected.

Fix by explicitly reporting the reason why each possible mkisofs
equivalent could not be used.

Signed-off-by: Michael Brown <mcb30@ipxe.org>
2021-02-12 12:16:48 +00:00
d79f504c0c [ci] Disable redundant scheduled execution of Coverity Scan
The scheduled Coverity Scan run is triggered by an external mechanism
that synchronises the coverity_scan branch with the master branch.

Signed-off-by: Michael Brown <mcb30@ipxe.org>
2021-02-05 11:59:27 +00:00
831f17f66f [ci] Disable Travis CI
Signed-off-by: Michael Brown <mcb30@ipxe.org>
2021-02-04 16:41:56 +00:00
1259580dde [ci] Add GitHub action for Coverity Scan
Signed-off-by: Michael Brown <mcb30@ipxe.org>
2021-02-04 16:41:55 +00:00
eeca29a1e0 [ci] Add GitHub action for build testing
Signed-off-by: Michael Brown <mcb30@ipxe.org>
2021-02-04 16:41:55 +00:00
e8393c3728 [build] Work around distros that use -fcf-protection=full by default
Some patched versions of gcc (observed with gcc 9.3.0 on Ubuntu 20.04)
enable -fcf-protection=full by default.  This breaks code that is not
explicitly written to expect the use of this flag.  The breakage
occurs only at runtime if the affected code (such as setjmp()) happens
to execute, and is therefore a particularly pernicious class of bug to
be introduced into working code by a broken compiler.

Work around these broken patched versions of gcc by detecting support
for -fcf-protection and explicitly setting -fcf-protection=none if
found.

If any Ubuntu maintainers are listening: PLEASE STOP DOING THIS.  It's
extremely unhelpful to have to keep working around breakages that you
introduce by modifying the compiler's default behaviour.  Do what Red
Hat does instead: set your preferred CFLAGS within the package build
system rather than by patching the compiler to behave in violation of
its own documentation.

Signed-off-by: Michael Brown <mcb30@ipxe.org>
2021-02-04 11:24:05 +00:00
e80299c56b [build] Work around -fPIE patched versions of gcc on all architectures
Several distributions include versions of gcc that are patched to
create position-independent executables by default.  These have caused
multiple problems over the years: see e.g. commits fe61f6d ("[build]
Fix compilation when gcc is patched to default to -fPIE -Wl,-pie"),
5de1346 ("[build] Apply the "-fno-PIE -nopie" workaround only to i386
builds"), 7c395b0 ("[build] Use -no-pie on newer versions of gcc"),
and decee20 ("[build] Disable position-independent code for ARM64 EFI
builds").

The build system currently attempts to work around these mildly broken
patched versions of gcc for the i386 and arm64 architectures.  This
misses the relatively obscure bin-x86_64-pcbios build platform, which
turns out to also require the same workaround.

Attempt to preempt the next such required workaround by moving the
existing i386 version to apply to all platforms and all architectures,
unless -fpie has been requested explicitly by another Makefile (as is
done by arch/x86_64/Makefile.efi).

Signed-off-by: Michael Brown <mcb30@ipxe.org>
2021-02-04 02:53:25 +00:00
bfb72ec234 [build] Avoid spurious "make clean" when building for the first time
The function trace recorder build logic defaults to making "clean" a
dependency of the first build in a clean checkout.  This is redundant
and causes problems if the build process spins up multiple make
invocations to handle multiple build architectures.

Fix by replacing with logic based on the known-working patterns used
for the ASSERT and PROFILE build parameters.

Signed-off-by: Michael Brown <mcb30@ipxe.org>
2021-02-04 02:53:25 +00:00
885c6d6e98 [efi] Fix erroneous comparison of a pointer against userptr_t
Signed-off-by: Michael Brown <mcb30@ipxe.org>
2021-02-03 16:00:06 +00:00
5bdb75c9d0 [contrib] Update bochsrc.txt to work with current versions
Signed-off-by: Michael Brown <mcb30@ipxe.org>
2021-02-02 00:01:41 +00:00
1af0fe04f8 [hermon] Add support for ConnectX-3 based cards
After a ton of tedious work, I am pleased to finally introduce full
support for ConnectX-3 cards in iPXE!

The work has been done by finding all publicly available versions of
the Mellanox Flexboot sources, cleaning them up, synthesizing a git
history from them, cleaning out non-significant changes, and
correlating with the iPXE upstream git history.

After this, a proof-of-concept diff was produced, that allowed iPXE to
be compiled with rudimentary ConnectX-3 support. This diff was over
10k lines, and contained many changes that were not part of the core
driver.

Special thanks to Michael Brown <mcb30@ipxe.org> for answering my
barrage of questions, and helping brainstorm the development along the
way.

Signed-off-by: Christian Iversen <ci@iversenit.dk>
2021-02-02 00:37:43 +01:00
0c94659a8a [autoboot] Avoid closing and immediately reopening network device
Some network devices can take a substantial time to close and reopen.
Avoid closing the device from which we are about to attempt booting,
in case it happens to be already open.

Suggested-by: Christian Iversen <ci@iversenit.dk>
Signed-off-by: Michael Brown <mcb30@ipxe.org>
2021-02-01 23:33:50 +00:00
6f1cb791ee [hermon] Avoid parsing length field on completion errors
The CQE length field will not be valid for a completion in error.
Avoid parsing the length field and just call the completion handler
directly.

In debug builds, also dump the queue pair context to allow for
inspection of the error.

Signed-off-by: Michael Brown <mcb30@ipxe.org>
2021-02-01 23:08:49 +00:00
8747241b3e [hermon] Make hermon_dump_xxx() functions no-ops on non-debug builds
Signed-off-by: Michael Brown <mcb30@ipxe.org>
2021-02-01 23:00:05 +00:00
54 changed files with 1561 additions and 1049 deletions

69
.github/workflows/build.yml vendored Normal file
View File

@ -0,0 +1,69 @@
name: Build
on: push
jobs:
x86:
name: x86
runs-on: ubuntu-20.04
steps:
- name: Check out code
uses: actions/checkout@v2
with:
fetch-depth: 0
- name: Install packages
run: |
sudo apt update
sudo apt install -y -o Acquire::Retries=50 \
mtools syslinux isolinux libc6-dev-i386 valgrind
- name: Build (BIOS)
run: |
make -j 4 -C src
- name: Build (Everything)
run: |
make -j 4 -C src everything
- name: Test
run: |
valgrind ./src/bin-i386-linux/tests.linux
valgrind ./src/bin-x86_64-linux/tests.linux
arm32:
name: ARM32
runs-on: ubuntu-20.04
steps:
- name: Check out code
uses: actions/checkout@v2
with:
fetch-depth: 0
- name: Install packages
run: |
sudo apt update
sudo apt install -y -o Acquire::Retries=50 \
mtools syslinux isolinux gcc-arm-none-eabi
- name: Build
run: |
make -j 4 -C src CROSS=arm-none-eabi- \
bin-arm32-efi/intel.efi \
bin-arm32-efi/intel.usb \
bin-arm32-efi/intel.iso
arm64:
name: ARM64
runs-on: ubuntu-20.04
steps:
- name: Check out code
uses: actions/checkout@v2
with:
fetch-depth: 0
- name: Install packages
run: |
sudo apt update
sudo apt install -y -o Acquire::Retries=50 \
mtools syslinux isolinux gcc-aarch64-linux-gnu
- name: Build
run: |
make -j 4 -C src CROSS=aarch64-linux-gnu- \
bin-arm64-efi/ipxe.efi \
bin-arm64-efi/ipxe.usb \
bin-arm64-efi/ipxe.iso

37
.github/workflows/coverity.yml vendored Normal file
View File

@ -0,0 +1,37 @@
name: Coverity Scan
on:
push:
branches:
- coverity_scan
jobs:
submit:
name: Submit
runs-on: ubuntu-20.04
steps:
- name: Check out code
uses: actions/checkout@v2
- name: Download Coverity Scan
run: |
curl --form token=${{ secrets.COVERITY_SCAN_TOKEN }} \
--form project=${{ github.repository }} \
--output coverity.tar.gz \
https://scan.coverity.com/download/cxx/linux64
mkdir -p /opt/coverity
sudo tar xvzf coverity.tar.gz --strip 1 --directory /opt/coverity
- name: Build via Coverity Scan
run: |
make -C src bin/deps
/opt/coverity/bin/cov-build --dir cov-int make -C src bin/blib.a
- name: Create submission
run : |
tar cvzf cov-int.tar.gz cov-int
- name: Submit to Coverity Scan
run: |
curl --form token=${{ secrets.COVERITY_SCAN_TOKEN }} \
--form email=${{ secrets.COVERITY_SCAN_EMAIL }} \
--form file=@cov-int.tar.gz \
--form version=${{ github.sha }} \
--form description=${{ github.ref }} \
https://scan.coverity.com/builds?project=${{ github.repository }}

View File

@ -1,58 +0,0 @@
dist: xenial
sudo: false
git:
depth: false
language: c
cache: ccache
compiler:
- gcc
addons:
apt:
packages:
- binutils-dev
- liblzma-dev
- syslinux
- isolinux
- genisoimage
coverity_scan:
project:
name: "ipxe/ipxe"
version: $TRAVIS_COMMIT
build_command_prepend: "make -C src bin/deps"
build_command: "make -C src bin/blib.a"
branch_pattern: coverity_scan
env:
global:
- MAKEFLAGS="-j 4"
script:
- make -C src bin/blib.a
- make -C src bin/ipxe.pxe
- make -C src bin/ipxe.usb
- make -C src bin/ipxe.iso
- make -C src bin/8086100e.mrom
- make -C src bin-x86_64-pcbios/blib.a
- make -C src bin-x86_64-pcbios/ipxe.pxe
- make -C src bin-x86_64-pcbios/ipxe.usb
- make -C src bin-x86_64-pcbios/ipxe.iso
- make -C src bin-x86_64-pcbios/8086100e.mrom
- make -C src bin-x86_64-efi/blib.a
- make -C src bin-x86_64-efi/ipxe.efi
- make -C src bin-x86_64-efi/intel.efidrv
- make -C src bin-x86_64-efi/intel.efirom
- make -C src bin-i386-efi/blib.a
- make -C src bin-i386-efi/ipxe.efi
- make -C src bin-i386-efi/intel.efidrv
- make -C src bin-i386-efi/intel.efirom
- make -C src bin-x86_64-linux/blib.a
- make -C src bin-x86_64-linux/tap.linux
- make -C src bin-x86_64-linux/af_packet.linux
- make -C src bin-x86_64-linux/tests.linux
- ./src/bin-x86_64-linux/tests.linux

100
contrib/cloud/aws-import Executable file
View File

@ -0,0 +1,100 @@
#!/usr/bin/env python3
import argparse
from base64 import b64encode
from concurrent.futures import ThreadPoolExecutor, as_completed
from hashlib import sha256
from itertools import count
import boto3
BLOCKSIZE = 512 * 1024
def create_snapshot(region, description, image):
"""Create an EBS snapshot"""
client = boto3.client('ebs', region_name=region)
snapshot = client.start_snapshot(VolumeSize=1,
Description=description)
snapshot_id = snapshot['SnapshotId']
with open(image, 'rb') as fh:
for block in count():
data = fh.read(BLOCKSIZE)
if not data:
break
data = data.ljust(BLOCKSIZE, b'\0')
checksum = b64encode(sha256(data).digest()).decode()
client.put_snapshot_block(SnapshotId=snapshot_id,
BlockIndex=block,
BlockData=data,
DataLength=BLOCKSIZE,
Checksum=checksum,
ChecksumAlgorithm='SHA256')
client.complete_snapshot(SnapshotId=snapshot_id,
ChangedBlocksCount=block)
return snapshot_id
def import_image(region, name, architecture, image, public):
"""Import an AMI image"""
client = boto3.client('ec2', region_name=region)
resource = boto3.resource('ec2', region_name=region)
description = '%s (%s)' % (name, architecture)
snapshot_id = create_snapshot(region=region, description=description,
image=image)
client.get_waiter('snapshot_completed').wait(SnapshotIds=[snapshot_id])
image = client.register_image(Architecture=architecture,
BlockDeviceMappings=[{
'DeviceName': '/dev/sda1',
'Ebs': {
'SnapshotId': snapshot_id,
'VolumeType': 'standard',
},
}],
EnaSupport=True,
Name=description,
RootDeviceName='/dev/sda1',
SriovNetSupport='simple',
VirtualizationType='hvm')
image_id = image['ImageId']
client.get_waiter('image_available').wait(ImageIds=[image_id])
if public:
resource.Image(image_id).modify_attribute(Attribute='launchPermission',
OperationType='add',
UserGroups=['all'])
return image_id
# Parse command-line arguments
parser = argparse.ArgumentParser(description="Import AWS EC2 image (AMI)")
parser.add_argument('--architecture', '-a', default='x86_64',
help="CPU architecture")
parser.add_argument('--name', '-n', required=True,
help="Image name")
parser.add_argument('--public', '-p', action='store_true',
help="Make image public")
parser.add_argument('--region', '-r', action='append',
help="AWS region(s)")
parser.add_argument('image', help="iPXE disk image")
args = parser.parse_args()
# Use all regions if none specified
if not args.region:
args.region = sorted(x['RegionName'] for x in
boto3.client('ec2').describe_regions()['Regions'])
# Use one thread per region to maximise parallelism
with ThreadPoolExecutor(max_workers=len(args.region)) as executor:
futures = {executor.submit(import_image,
region=region,
name=args.name,
architecture=args.architecture,
image=args.image,
public=args.public): region
for region in args.region}
results = {futures[future]: future.result()
for future in as_completed(futures)}
# Show created images
for region in args.region:
print("%s: %s" % (region, results[region]))

File diff suppressed because it is too large Load Diff

View File

@ -48,7 +48,6 @@ ELF2EFI32 := ./util/elf2efi32
ELF2EFI64 := ./util/elf2efi64
EFIROM := ./util/efirom
EFIFATBIN := ./util/efifatbin
ICCFIX := ./util/iccfix
EINFO := ./util/einfo
GENKEYMAP := ./util/genkeymap.pl
DOXYGEN := doxygen

View File

@ -76,9 +76,7 @@ CCDEFS := $(shell $(CC) -E -x c -c /dev/null -dM | cut -d" " -f2)
ccdefs:
@$(ECHO) $(CCDEFS)
ifeq ($(filter __ICC,$(CCDEFS)),__ICC)
CCTYPE := icc
else
ifeq ($(filter __GNUC__,$(CCDEFS)),__GNUC__)
CCTYPE := gcc
endif
cctype:
@ -374,6 +372,43 @@ INCDIRS += arch/$(ARCH)/include
INCDIRS += arch/$(ARCH)/include/$(PLATFORM)
endif
###############################################################################
#
# Especially ugly workarounds
# Some widespread patched versions of gcc include -fPIE -Wl,-pie by
# default. Note that gcc will exit *successfully* if it fails to
# recognise an option that starts with "no", so we have to test for
# output on stderr instead of checking the exit status.
#
# Current versions of gcc require -no-pie; older versions require
# -nopie. We therefore test for both.
#
# This workaround must be determined only after the
# architecture-specific Makefile has been included, since some
# platforms (e.g. bin-x86_64-efi) will explicitly require the use of
# -fpie.
#
ifeq ($(filter -fpie,$(CFLAGS)),)
ifeq ($(CCTYPE),gcc)
PIE_TEST = [ -z "`$(CC) -fno-PIE -no-pie -x c -c /dev/null -o /dev/null 2>&1`" ]
PIE_FLAGS := $(shell $(PIE_TEST) && $(ECHO) '-fno-PIE -no-pie')
PIE_TEST2 = [ -z "`$(CC) -fno-PIE -nopie -x c -c /dev/null -o /dev/null 2>&1`" ]
PIE_FLAGS2 := $(shell $(PIE_TEST2) && $(ECHO) '-fno-PIE -nopie')
WORKAROUND_CFLAGS += $(PIE_FLAGS) $(PIE_FLAGS2)
endif
endif
# Some widespread patched versions of gcc include -fcf-protection=full
# by default.
#
ifeq ($(CCTYPE),gcc)
CFP_TEST = $(CC) -fcf-protection=none -x c -c /dev/null -o /dev/null \
>/dev/null 2>&1
CFP_FLAGS := $(shell $(CFP_TEST) && $(ECHO) '-fcf-protection=none')
WORKAROUND_CFLAGS += $(CFP_FLAGS)
endif
###############################################################################
#
# Source file handling
@ -429,32 +464,6 @@ CFLAGS += -fcommon
CFLAGS += -Wall -W -Wformat-nonliteral
HOST_CFLAGS += -Wall -W -Wformat-nonliteral
endif
ifeq ($(CCTYPE),icc)
CFLAGS += -fno-builtin
CFLAGS += -no-ip
CFLAGS += -no-gcc
CFLAGS += -diag-disable 111 # Unreachable code
CFLAGS += -diag-disable 128 # Unreachable loop
CFLAGS += -diag-disable 170 # Array boundary checks
CFLAGS += -diag-disable 177 # Unused functions
CFLAGS += -diag-disable 181 # printf() format checks
CFLAGS += -diag-disable 188 # enum strictness
CFLAGS += -diag-disable 193 # Undefined preprocessor identifiers
CFLAGS += -diag-disable 280 # switch ( constant )
CFLAGS += -diag-disable 310 # K&R parameter lists
CFLAGS += -diag-disable 424 # Extra semicolon
CFLAGS += -diag-disable 589 # Declarations mid-code
CFLAGS += -diag-disable 593 # Unused variables
CFLAGS += -diag-disable 810 # Casting ints to smaller ints
CFLAGS += -diag-disable 981 # Sequence point violations
CFLAGS += -diag-disable 1292 # Ignored attributes
CFLAGS += -diag-disable 1338 # void pointer arithmetic
CFLAGS += -diag-disable 1361 # Variable-length arrays
CFLAGS += -diag-disable 1418 # Missing prototypes
CFLAGS += -diag-disable 1419 # Missing prototypes
CFLAGS += -diag-disable 1599 # Hidden variables
CFLAGS += -Wall -Wmissing-declarations
endif
CFLAGS += $(WORKAROUND_CFLAGS) $(EXTRA_CFLAGS)
ASFLAGS += $(WORKAROUND_ASFLAGS) $(EXTRA_ASFLAGS)
LDFLAGS += $(WORKAROUND_LDFLAGS) $(EXTRA_LDFLAGS)
@ -468,35 +477,6 @@ ASFLAGS += --fatal-warnings
HOST_CFLAGS += -Werror
endif
# Function trace recorder state in the last build. This is needed
# in order to correctly rebuild whenever the function recorder is
# enabled/disabled.
#
FNREC_STATE := $(BIN)/.fnrec.state
ifeq ($(wildcard $(FNREC_STATE)),)
FNREC_OLD := <invalid>
else
FNREC_OLD := $(shell cat $(FNREC_STATE))
endif
ifeq ($(FNREC_OLD),$(FNREC))
$(FNREC_STATE) :
else
$(FNREC_STATE) : clean
$(shell $(ECHO) "$(FNREC)" > $(FNREC_STATE))
endif
VERYCLEANUP += $(FNREC_STATE)
MAKEDEPS += $(FNREC_STATE)
ifeq ($(FNREC),1)
# Enabling -finstrument-functions affects gcc's analysis and leads to spurious
# warnings about use of uninitialised variables.
#
CFLAGS += -Wno-uninitialized
CFLAGS += -finstrument-functions
CFLAGS += -finstrument-functions-exclude-file-list=core/fnrec.c
endif
# Enable per-item sections and section garbage collection. Note that
# some older versions of gcc support -fdata-sections but treat it as
# implying -fno-common, which would break our build. Some other older
@ -547,16 +527,6 @@ OBJ_CFLAGS = $(CFLAGS_$(OBJECT)) -DOBJECT=$(subst -,_,$(OBJECT))
$(BIN)/%.flags :
@$(ECHO) $(OBJ_CFLAGS)
# ICC requires postprocessing objects to fix up table alignments
#
ifeq ($(CCTYPE),icc)
POST_O = && $(ICCFIX) $@
POST_O_DEPS := $(ICCFIX)
else
POST_O :=
POST_O_DEPS :=
endif
# Debug level calculations
#
DBGLVL_MAX = -DDBGLVL_MAX=$(firstword $(subst ., ,$(1)))
@ -566,9 +536,9 @@ DBGLVL = $(call DBGLVL_MAX,$(1)) $(call DBGLVL_DFLT,$(1))
# Rules for specific object types.
#
COMPILE_c = $(CC) $(CFLAGS) $(CFLAGS_c) $(OBJ_CFLAGS)
RULE_c = $(Q)$(COMPILE_c) -c $< -o $@ $(POST_O)
RULE_c = $(Q)$(COMPILE_c) -c $< -o $@
RULE_c_to_ids.o = $(Q)$(ECHO_E) '$(OBJ_IDS_ASM_NL)' | $(ASSEMBLE_S) -o $@
RULE_c_to_dbg%.o= $(Q)$(COMPILE_c) $(call DBGLVL,$*) -c $< -o $@ $(POST_O)
RULE_c_to_dbg%.o= $(Q)$(COMPILE_c) $(call DBGLVL,$*) -c $< -o $@
RULE_c_to_c = $(Q)$(COMPILE_c) -E -c $< > $@
RULE_c_to_s = $(Q)$(COMPILE_c) -S -g0 -c $< -o $@
@ -808,6 +778,38 @@ include/ipxe/profile.h : $(PROFILE_LIST)
.PRECIOUS : include/ipxe/profile.h
# (Single-element) list of function recorder configuration
#
FNREC_LIST := $(BIN)/.fnrec.list
ifeq ($(wildcard $(FNREC_LIST)),)
FNREC_OLD := <invalid>
else
FNREC_OLD := $(shell cat $(FNREC_LIST))
endif
ifneq ($(FNREC_OLD),$(FNREC))
$(shell $(ECHO) "$(FNREC)" > $(FNREC_LIST))
endif
$(FNREC_LIST) : $(MAKEDEPS)
VERYCLEANUP += $(FNREC_LIST)
# Function recorder configuration
#
ifeq ($(FNREC),1)
# Enabling -finstrument-functions affects gcc's analysis and leads to spurious
# warnings about use of uninitialised variables.
#
CFLAGS += -Wno-uninitialized
CFLAGS += -finstrument-functions
CFLAGS += -finstrument-functions-exclude-file-list=core/fnrec.c
endif
include/compiler.h : $(FNREC_LIST)
$(Q)$(TOUCH) $@
.PRECIOUS : include/compiler.h
# These files use .incbin inline assembly to include a binary file.
# Unfortunately ccache does not detect this dependency and caches
# builds even when the binary file has changed.
@ -879,7 +881,7 @@ endef
# $(3) is the source base name (e.g. "rtl8139")
#
define rules_template_parts
$$(BIN)/$(3).o : $(1) $$(MAKEDEPS) $$(POST_O_DEPS) $$($(3)_DEPS)
$$(BIN)/$(3).o : $(1) $$(MAKEDEPS) $$($(3)_DEPS)
$$(QM)$(ECHO) " [BUILD] $$@"
$$(RULE_$(2))
BOBJS += $$(BIN)/$(3).o
@ -894,7 +896,7 @@ endef
# $(4) is the destination type (e.g. "dbg%.o")
#
define rules_template_target
$$(BIN)/$(3).$(4) : $(1) $$(MAKEDEPS) $$(POST_O_DEPS) $$($(3)_DEPS)
$$(BIN)/$(3).$(4) : $(1) $$(MAKEDEPS) $$($(3)_DEPS)
$$(QM)$(ECHO) " [BUILD] $$@"
$$(RULE_$(2)_to_$(4))
$(TGT)_OBJS += $$(BIN)/$(3).$(4)
@ -1433,15 +1435,6 @@ $(EFIFATBIN) : util/efifatbin.c $(MAKEDEPS)
$(Q)$(HOST_CC) $(HOST_CFLAGS) -idirafter include -o $@ $<
CLEANUP += $(EFIFATBIN)
###############################################################################
#
# The ICC fixup utility
#
$(ICCFIX) : util/iccfix.c $(MAKEDEPS)
$(QM)$(ECHO) " [HOSTCC] $@"
$(Q)$(HOST_CC) $(HOST_CFLAGS) -idirafter include -o $@ $<
CLEANUP += $(ICCFIX)
###############################################################################
#
# The error usage information utility

View File

@ -1,9 +1,5 @@
# -*- makefile -*- : Force emacs to use Makefile mode
# Avoid untranslatable relocations
#
CFLAGS += -fno-pic
# Specify EFI image builder
#
ELF2EFI = $(ELF2EFI64)

View File

@ -69,22 +69,6 @@ CFLAGS += -fshort-wchar
#
CFLAGS += -Ui386
# Some widespread patched versions of gcc include -fPIE -Wl,-pie by
# default. Note that gcc will exit *successfully* if it fails to
# recognise an option that starts with "no", so we have to test for
# output on stderr instead of checking the exit status.
#
# Current versions of gcc require -no-pie; older versions require
# -nopie. We therefore test for both.
#
ifeq ($(CCTYPE),gcc)
PIE_TEST = [ -z "`$(CC) -fno-PIE -no-pie -x c -c /dev/null -o /dev/null 2>&1`" ]
PIE_FLAGS := $(shell $(PIE_TEST) && $(ECHO) '-fno-PIE -no-pie')
PIE_TEST2 = [ -z "`$(CC) -fno-PIE -nopie -x c -c /dev/null -o /dev/null 2>&1`" ]
PIE_FLAGS2 := $(shell $(PIE_TEST2) && $(ECHO) '-fno-PIE -nopie')
WORKAROUND_CFLAGS += $(PIE_FLAGS) $(PIE_FLAGS2)
endif
# i386-specific directories containing source files
#
SRCDIRS += arch/i386/core

View File

@ -4,18 +4,15 @@
#
SRCDIRS += arch/x86/drivers/net
# The i386 linker script
# The linker scripts
#
LDSCRIPT = arch/x86/scripts/pcbios.lds
LDSCRIPT_PREFIX = arch/x86/scripts/prefixonly.lds
# Stop ld from complaining about our customised linker script
#
LDFLAGS += -N --no-check-sections
# Prefix always starts at address zero
#
LDFLAGS += --section-start=.prefix=0
# Media types.
#
MEDIA += rom
@ -73,12 +70,12 @@ NON_AUTO_MEDIA += fd0
# Special target for building Master Boot Record binary
$(BIN)/mbr.tmp : $(BIN)/mbr.o
$(QM)$(ECHO) " [LD] $@"
$(Q)$(LD) $(LDFLAGS) -o $@ -e mbr $<
$(Q)$(LD) $(LDFLAGS) -T $(LDSCRIPT_PREFIX) -o $@ -e mbr $<
# rule to make a USB disk image
$(BIN)/usbdisk.tmp : $(BIN)/usbdisk.o
$(QM)$(ECHO) " [LD] $@"
$(Q)$(LD) $(LDFLAGS) -o $@ -e mbr $<
$(Q)$(LD) $(LDFLAGS) -T $(LDSCRIPT_PREFIX) -o $@ -e mbr $<
NON_AUTO_MEDIA += usb
%usb: $(BIN)/usbdisk.bin %hd

View File

@ -13,7 +13,7 @@ FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL )
****************************************************************************
*/
.section ".stack", "aw", @nobits
.align 8
.balign 8
.globl _stack
_stack:
.space STACK_SIZE

View File

@ -7,7 +7,7 @@ FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL )
****************************************************************************
*/
.section ".stack16", "aw", @nobits
.align 8
.balign 8
.globl _stack16
_stack16:
.space 4096

View File

@ -175,18 +175,18 @@ static int initrd_swap_any ( userptr_t free, size_t free_len ) {
/* Search for adjacent image */
for_each_image ( high ) {
/* If we have found the adjacent image, swap and exit */
if ( high->data == adjacent ) {
initrd_swap ( low, high, free, free_len );
return 1;
}
/* Stop search if all remaining potential
* adjacent images are already in the correct
* order.
*/
if ( high == low )
break;
/* If we have found the adjacent image, swap and exit */
if ( high->data == adjacent ) {
initrd_swap ( low, high, free, free_len );
return 1;
}
}
}

View File

@ -42,6 +42,9 @@ struct x86_features {
/** Hypervisor is present */
#define CPUID_FEATURES_INTEL_ECX_HYPERVISOR 0x80000000UL
/** FXSAVE and FXRSTOR are supported */
#define CPUID_FEATURES_INTEL_EDX_FXSR 0x01000000UL
/** Get largest extended function */
#define CPUID_AMD_MAX_FN 0x80000000UL

View File

@ -0,0 +1,76 @@
/*
* Copyright (C) 2013 Michael Brown <mbrown@fensystems.co.uk>.
*
* 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 of the
* License, or any later version.
*
* This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
* 02110-1301, USA.
*
* You can also choose to distribute this program under the terms of
* the Unmodified Binary Distribution Licence (as given in the file
* COPYING.UBDL), provided that you have satisfied its requirements.
*/
FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
#include <stdint.h>
#include <ipxe/init.h>
#include <ipxe/cachedhcp.h>
#include <realmode.h>
#include <pxe_api.h>
/** @file
*
* Cached DHCP packet
*
*/
/** Cached DHCPACK physical address
*
* This can be set by the prefix.
*/
uint32_t __bss16 ( cached_dhcpack_phys );
#define cached_dhcpack_phys __use_data16 ( cached_dhcpack_phys )
/** Colour for debug messages */
#define colour &cached_dhcpack_phys
/**
* Cached DHCPACK initialisation function
*
*/
static void cachedhcp_init ( void ) {
int rc;
/* Do nothing if no cached DHCPACK is present */
if ( ! cached_dhcpack_phys ) {
DBGC ( colour, "CACHEDHCP found no cached DHCPACK\n" );
return;
}
/* Record cached DHCPACK */
if ( ( rc = cachedhcp_record ( phys_to_user ( cached_dhcpack_phys ),
sizeof ( BOOTPLAYER_t ) ) ) != 0 ) {
DBGC ( colour, "CACHEDHCP could not record DHCPACK: %s\n",
strerror ( rc ) );
return;
}
/* Mark as consumed */
cached_dhcpack_phys = 0;
}
/** Cached DHCPACK initialisation function */
struct init_fn cachedhcp_init_fn __init_fn ( INIT_NORMAL ) = {
.initialise = cachedhcp_init,
};

View File

@ -67,7 +67,7 @@ FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL )
****************************************************************************
*/
.section ".data16", "aw", @progbits
.align 16
.balign 16
.globl hidemem_base
.globl hidemem_umalloc
.globl hidemem_textdata

View File

@ -34,7 +34,7 @@ FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL )
*/
.section ".text16.data", "aw", @progbits
.globl ppxe
.align 16
.balign 16
ppxe:
.ascii "!PXE" /* Signature */
.byte pxe_length /* StructLength */
@ -72,7 +72,7 @@ undiheader:
*/
.section ".text16.data", "aw", @progbits
.globl pxenv
.align 16
.balign 16
pxenv:
.ascii "PXENV+" /* Signature */
.word 0x0201 /* Version */

View File

@ -110,7 +110,7 @@ overlay:
/* Overlay number */
.word 0
.align 16, 0
.balign 16, 0
.globl _exe_start
_exe_start:

View File

@ -492,7 +492,7 @@ mromheader:
.word 0
.size mromheader, . - mromheader
.align 4
.balign 4
mpciheader:
.ascii "PCIR" /* Signature */
.word pci_vendor_id /* Vendor identification */

View File

@ -0,0 +1,53 @@
/*
* Raw binary prefix
*
* Assumes that entire image is already loaded as a contiguous block
* on a paragraph boundary and entered in real mode.
*
*/
FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL )
.text
.arch i386
.org 0
.code16
#include <librm.h>
.section ".prefix", "ax", @progbits
.globl _raw_start
_raw_start:
/* Adjust %cs so that %cs:0000 is the start of the image */
movw %cs, %ax
call 1f
1: popw %bx
subw $1b, %bx
shrw $4, %bx
addw %bx, %ax
pushw %ax
pushw $2f
lret
2:
/* Install iPXE */
call install
/* Set up real-mode stack */
movw %bx, %ss
movw $_estack16, %sp
/* Jump to .text16 segment */
pushw %ax
pushw $1f
lret
.section ".text16", "awx", @progbits
1:
/* Run iPXE */
virtcall main
/* Uninstall iPXE */
call uninstall
/* Boot next device */
int $0x18

View File

@ -88,7 +88,7 @@ checksum:
.previous
.ifeqs BUSTYPE, "PCIR"
.align 4
.balign 4
pciheader:
.ascii "PCIR" /* Signature */
.word pci_vendor_id /* Vendor identification */
@ -136,7 +136,7 @@ pci_devlist_end:
* BIOSes will scan on 16-byte boundaries rather than using
* the offset stored at 0x1a
*/
.align 16
.balign 16
pnpheader:
.ascii "$PnP" /* Signature */
.byte 0x01 /* Structure revision */
@ -184,7 +184,7 @@ prodstr_pci_id:
.globl undiheader
.weak undiloader
.align 4
.balign 4
undiheader:
.ascii "UNDI" /* Signature */
.byte undiheader_len /* Length of structure */
@ -199,7 +199,7 @@ undiheader:
.equ undiheader_len, . - undiheader
.size undiheader, . - undiheader
.align 4
.balign 4
ipxeheader:
.ascii "iPXE" /* Signature */
.byte ipxeheader_len /* Length of structure */

View File

@ -231,7 +231,7 @@ rep_len_dec: .space sizeof__lzma_len_dec
literal: .rept ( ( 1 << LZMA_LC ) * 0x300 )
.word 0
.endr
.align 4
.balign 4
.equ sizeof__lzma_dec, . - lzma_dec
.previous

View File

@ -0,0 +1,29 @@
/* -*- ld-script -*- */
/*
* Linker script for prefix-only binaries (e.g. USB disk MBR)
*
*/
SECTIONS {
.prefix 0x0 : AT ( 0x0 ) {
*(.prefix)
}
/DISCARD/ : {
*(.comment)
*(.comment.*)
*(.note)
*(.note.*)
*(.eh_frame)
*(.eh_frame.*)
*(.rel)
*(.rel.*)
*(.einfo)
*(.einfo.*)
*(.discard)
*(.discard.*)
}
}

View File

@ -285,7 +285,7 @@ enable_a20:
ret
.section ".text16.early.data", "aw", @progbits
.align 2
.balign 2
enable_a20_method:
.word 0
.size enable_a20_method, . - enable_a20_method

View File

@ -99,7 +99,7 @@ FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL )
****************************************************************************
*/
.section ".data16.gdt", "aw", @progbits
.align 16
.balign 16
gdt:
gdtr: /* The first GDT entry is unused, the GDTR can fit here. */
gdt_limit: .word gdt_length - 1
@ -210,9 +210,7 @@ VC_TMP_CR3: .space 4
VC_TMP_CR4: .space 4
VC_TMP_EMER: .space 8
.endif
#ifdef TIVOLI_VMM_WORKAROUND
VC_TMP_FXSAVE: .space 512
#endif
VC_TMP_END:
.previous
@ -224,7 +222,7 @@ RC_TMP_END:
/* Shared temporary static buffer */
.section ".bss16.rm_tmpbuf", "aw", @nobits
.align 16
.balign 16
rm_tmpbuf:
.space VC_TMP_END
.size rm_tmpbuf, . - rm_tmpbuf
@ -350,6 +348,13 @@ init_librm_rmode:
/* Initialise IDT */
virtcall init_idt
#ifdef TIVOLI_VMM_WORKAROUND
/* Check for FXSAVE/FXRSTOR */
clc
virtcall check_fxsr
setnc fxsr_supported
#endif
/* Restore registers */
popl %edi
popl %ebx
@ -366,6 +371,10 @@ set_seg_base:
roll $16, %eax
ret
.section ".data16.fxsr_supported", "awx", @progbits
fxsr_supported: /* FXSAVE/FXRSTOR instructions supported */
.byte 0
/****************************************************************************
* real_to_prot (real-mode near call, 32-bit virtual return address)
*
@ -1007,10 +1016,11 @@ virt_call:
cli
movw %cs:rm_ds, %ds
#ifdef TIVOLI_VMM_WORKAROUND
/* Preserve FPU, MMX and SSE state in temporary static buffer */
testb $0xff, fxsr_supported
jz 1f
fxsave ( rm_tmpbuf + VC_TMP_FXSAVE )
#endif
1:
/* Preserve GDT and IDT in temporary static buffer */
sidt ( rm_tmpbuf + VC_TMP_IDT )
sgdt ( rm_tmpbuf + VC_TMP_GDT )
@ -1077,10 +1087,11 @@ vc_rmode:
wrmsr
.endif
#ifdef TIVOLI_VMM_WORKAROUND
/* Restore FPU, MMX and SSE state from temporary static buffer */
testb $0xff, fxsr_supported
jz 1f
fxrstor ( rm_tmpbuf + VC_TMP_FXSAVE )
#endif
1:
/* Restore registers and flags and return */
popl %eax /* skip %cs and %ss */
popw %ds
@ -1470,7 +1481,7 @@ interrupt_wrapper:
****************************************************************************
*/
.section ".pages", "aw", @nobits
.align SIZEOF_PT
.balign SIZEOF_PT
/* Page map level 4 entries (PML4Es)
*

View File

@ -14,6 +14,7 @@ FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
#include <realmode.h>
#include <pic8259.h>
#include <ipxe/shell.h>
#include <ipxe/cpuid.h>
/*
* This file provides functions for managing librm.
@ -118,7 +119,7 @@ void set_interrupt_vector ( unsigned int intr, void *vector ) {
* Initialise interrupt descriptor table
*
*/
void init_idt ( void ) {
__asmcall void init_idt ( void ) {
struct interrupt_vector *vec;
unsigned int intr;
@ -386,6 +387,21 @@ static void iounmap_pages ( volatile const void *io_addr ) {
io_addr, first, i );
}
/**
* Check for FXSAVE/FXRSTOR instruction support
*
*/
__asmcall void check_fxsr ( struct i386_all_regs *regs ) {
struct x86_features features;
/* Check for FXSR bit */
x86_features ( &features );
if ( ! ( features.intel.edx & CPUID_FEATURES_INTEL_EDX_FXSR ) )
regs->flags |= CF;
DBGC ( &features, "FXSAVE/FXRSTOR is%s supported\n",
( ( regs->flags & CF ) ? " not" : "" ) );
}
PROVIDE_UACCESS_INLINE ( librm, phys_to_user );
PROVIDE_UACCESS_INLINE ( librm, user_to_phys );
PROVIDE_UACCESS_INLINE ( librm, virt_to_user );

View File

@ -18,8 +18,13 @@
* Note that the serial port output from an AWS EC2 virtual machine is
* generally available (as the "System Log") only after the instance
* has been stopped.
*
* Enable only for non-EFI builds, on the assumption that the standard
* EFI firmware is likely to already be logging to the serial port.
*/
#ifndef PLATFORM_efi
#define CONSOLE_SERIAL
#endif
/* Log to partition on local disk
*

View File

@ -1,3 +1,7 @@
/* Enable IPv6 and HTTPS */
#define NET_PROTO_IPV6
#define DOWNLOAD_PROTO_HTTPS
/* Allow retrieval of metadata (such as an iPXE boot script) from
* Google Compute Engine metadata server.
*/

7
src/config/cloud/ioapi.h Normal file
View File

@ -0,0 +1,7 @@
/* Work around missing PCI BIOS calls in the cut-down SeaBIOS found in
* some AWS EC2 instances.
*/
#ifdef PLATFORM_pcbios
#undef PCIAPI_PCBIOS
#define PCIAPI_DIRECT
#endif

View File

@ -14,6 +14,9 @@ FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
//#undef PCIAPI_PCBIOS /* Access via PCI BIOS */
//#define PCIAPI_DIRECT /* Direct access via Type 1 accesses */
#include <config/named.h>
#include NAMED_CONFIG(ioapi.h)
#include <config/local/ioapi.h>
#include LOCAL_NAMED_CONFIG(ioapi.h)
#endif /* CONFIG_IOAPI_H */

0
src/config/qemu/ioapi.h Normal file
View File

0
src/config/rpi/ioapi.h Normal file
View File

0
src/config/vbox/ioapi.h Normal file
View File

View File

@ -25,11 +25,11 @@ FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
#include <stdint.h>
#include <stdlib.h>
#include <errno.h>
#include <ipxe/dhcppkt.h>
#include <ipxe/init.h>
#include <ipxe/netdevice.h>
#include <realmode.h>
#include <pxe_api.h>
#include <ipxe/cachedhcp.h>
/** @file
*
@ -37,50 +37,33 @@ FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
*
*/
/** Cached DHCPACK physical address
*
* This can be set by the prefix.
*/
uint32_t __bss16 ( cached_dhcpack_phys );
#define cached_dhcpack_phys __use_data16 ( cached_dhcpack_phys )
/** Colour for debug messages */
#define colour &cached_dhcpack_phys
/** Cached DHCPACK */
static struct dhcp_packet *cached_dhcpack;
/** Colour for debug messages */
#define colour &cached_dhcpack
/**
* Cached DHCPACK startup function
* Record cached DHCPACK
*
* @v data DHCPACK packet buffer
* @v max_len Maximum possible length
* @ret rc Return status code
*/
static void cachedhcp_init ( void ) {
int cachedhcp_record ( userptr_t data, size_t max_len ) {
struct dhcp_packet *dhcppkt;
struct dhcp_packet *tmp;
struct dhcphdr *dhcphdr;
size_t max_len;
size_t len;
/* Do nothing if no cached DHCPACK is present */
if ( ! cached_dhcpack_phys ) {
DBGC ( colour, "CACHEDHCP found no cached DHCPACK\n" );
return;
}
/* No reliable way to determine length before parsing packet;
* start by assuming maximum length permitted by PXE.
*/
max_len = sizeof ( BOOTPLAYER_t );
/* Allocate and populate DHCP packet */
dhcppkt = zalloc ( sizeof ( *dhcppkt ) + max_len );
if ( ! dhcppkt ) {
DBGC ( colour, "CACHEDHCP could not allocate copy\n" );
return;
return -ENOMEM;
}
dhcphdr = ( ( ( void * ) dhcppkt ) + sizeof ( *dhcppkt ) );
copy_from_user ( dhcphdr, phys_to_user ( cached_dhcpack_phys ), 0,
max_len );
copy_from_user ( dhcphdr, data, 0, max_len );
dhcppkt_init ( dhcppkt, dhcphdr, max_len );
/* Shrink packet to required length. If reallocation fails,
@ -98,10 +81,11 @@ static void cachedhcp_init ( void ) {
dhcppkt_init ( dhcppkt, dhcphdr, len );
/* Store as cached DHCPACK, and mark original copy as consumed */
DBGC ( colour, "CACHEDHCP found cached DHCPACK at %08x+%zx\n",
cached_dhcpack_phys, len );
DBGC ( colour, "CACHEDHCP found cached DHCPACK at %#08lx+%#zx/%#zx\n",
user_to_phys ( data, 0 ), len, max_len );
cached_dhcpack = dhcppkt;
cached_dhcpack_phys = 0;
return 0;
}
/**
@ -120,11 +104,6 @@ static void cachedhcp_startup ( void ) {
}
}
/** Cached DHCPACK initialisation function */
struct init_fn cachedhcp_init_fn __init_fn ( INIT_NORMAL ) = {
.initialise = cachedhcp_init,
};
/** Cached DHCPACK startup function */
struct startup_fn cachedhcp_startup_fn __startup_fn ( STARTUP_LATE ) = {
.name = "cachedhcp",

View File

@ -823,6 +823,11 @@ hermon_dump_cqctx ( struct hermon *hermon, struct ib_completion_queue *cq ) {
struct hermonprm_completion_queue_context cqctx;
int rc;
/* Do nothing unless debugging is enabled */
if ( ! DBG_LOG )
return 0;
/* Dump completion queue context */
memset ( &cqctx, 0, sizeof ( cqctx ) );
if ( ( rc = hermon_cmd_query_cq ( hermon, cq->cqn, &cqctx ) ) != 0 ) {
DBGC ( hermon, "Hermon %p CQN %#lx QUERY_CQ failed: %s\n",
@ -1099,16 +1104,30 @@ static uint8_t hermon_qp_st[] = {
*/
static __attribute__ (( unused )) int
hermon_dump_qpctx ( struct hermon *hermon, struct ib_queue_pair *qp ) {
struct hermon_queue_pair *hermon_qp = ib_qp_get_drvdata ( qp );
struct hermonprm_qp_ee_state_transitions qpctx;
unsigned int state;
int rc;
/* Do nothing unless debugging is enabled */
if ( ! DBG_LOG )
return 0;
/* Dump queue pair context */
memset ( &qpctx, 0, sizeof ( qpctx ) );
if ( ( rc = hermon_cmd_query_qp ( hermon, qp->qpn, &qpctx ) ) != 0 ) {
DBGC ( hermon, "Hermon %p QPN %#lx QUERY_QP failed: %s\n",
hermon, qp->qpn, strerror ( rc ) );
return rc;
}
DBGC ( hermon, "Hermon %p QPN %#lx context:\n", hermon, qp->qpn );
state = MLX_GET ( &qpctx, qpc_eec_data.state );
if ( state != hermon_qp->state ) {
DBGC ( hermon, "Hermon %p QPN %#lx state %d unexpected "
"(should be %d)\n",
hermon, qp->qpn, state, hermon_qp->state );
}
DBGC ( hermon, "Hermon %p QPN %#lx state %d context:\n",
hermon, qp->qpn, state );
DBGC_HDA ( hermon, 0, &qpctx.u.dwords[2], ( sizeof ( qpctx ) - 8 ) );
return 0;
@ -1789,6 +1808,11 @@ static int hermon_complete ( struct ib_device *ibdev,
if ( is_send ) {
/* Hand off to completion handler */
ib_complete_send ( ibdev, qp, iobuf, rc );
} else if ( rc != 0 ) {
/* Dump queue state (for debugging) */
hermon_dump_qpctx ( hermon, qp );
/* Hand off to completion handler */
ib_complete_recv ( ibdev, qp, NULL, NULL, iobuf, rc );
} else {
/* Set received length */
len = MLX_GET ( &cqe->normal, byte_cnt );
@ -1831,7 +1855,7 @@ static int hermon_complete ( struct ib_device *ibdev,
assert ( len <= iob_tailroom ( iobuf ) );
iob_put ( iobuf, len );
/* Hand off to completion handler */
ib_complete_recv ( ibdev, qp, &recv_dest, source, iobuf, rc );
ib_complete_recv ( ibdev, qp, &recv_dest, source, iobuf, 0 );
}
return rc;
@ -1898,6 +1922,11 @@ hermon_dump_eqctx ( struct hermon *hermon,
struct hermonprm_eqc eqctx;
int rc;
/* Do nothing unless debugging is enabled */
if ( ! DBG_LOG )
return 0;
/* Dump event queue context */
memset ( &eqctx, 0, sizeof ( eqctx ) );
if ( ( rc = hermon_cmd_query_eq ( hermon, hermon_eq->eqn,
&eqctx ) ) != 0 ) {
@ -1930,6 +1959,11 @@ hermon_dump_eqes ( struct hermon *hermon,
unsigned int idx;
int rc;
/* Do nothing unless debugging is enabled */
if ( ! DBG_LOG )
return 0;
/* Dump event queue entries */
memset ( &eqctx, 0, sizeof ( eqctx ) );
if ( ( rc = hermon_cmd_query_eq ( hermon, hermon_eq->eqn,
&eqctx ) ) != 0 ) {
@ -4198,6 +4232,10 @@ static struct pci_device_id hermon_nics[] = {
PCI_ROM ( 0x15b3, 0x675a, "mt26458", "MT26458 HCA driver", 0 ),
PCI_ROM ( 0x15b3, 0x6764, "mt26468", "MT26468 HCA driver", 0 ),
PCI_ROM ( 0x15b3, 0x676e, "mt26478", "MT26478 HCA driver", 0 ),
/* Mellanox ConnectX-3 VPI (ethernet + infiniband) */
PCI_ROM ( 0x15b3, 0x1003, "mt4099", "ConnectX-3 HCA driver", 0 ),
PCI_ROM ( 0x15b3, 0x1007, "mt4103", "ConnectX-3 Pro HCA driver", 0 ),
};
struct pci_driver hermon_driver __pci_driver = {

View File

@ -416,6 +416,7 @@ ath5k_eeprom_read_turbo_modes(struct ath5k_hw *ah,
if (ee->ee_version < AR5K_EEPROM_VERSION_5_0)
return 0;
AR5K_EEPROM_READ(o++, val);
switch (mode){
case AR5K_EEPROM_MODE_11A:
ee->ee_switch_settling_turbo[mode] = (val >> 6) & 0x7f;

View File

@ -65,35 +65,59 @@ static const char * ena_direction ( unsigned int direction ) {
*/
/**
* Reset hardware
* Wait for reset operation to be acknowledged
*
* @v ena ENA device
* @v expected Expected reset state
* @ret rc Return status code
*/
static int ena_reset ( struct ena_nic *ena ) {
static int ena_reset_wait ( struct ena_nic *ena, uint32_t expected ) {
uint32_t stat;
unsigned int i;
/* Trigger reset */
writel ( ENA_CTRL_RESET, ( ena->regs + ENA_CTRL ) );
/* Wait for reset to complete */
for ( i = 0 ; i < ENA_RESET_MAX_WAIT_MS ; i++ ) {
/* Check if device is ready */
stat = readl ( ena->regs + ENA_STAT );
if ( stat & ENA_STAT_READY )
if ( ( stat & ENA_STAT_RESET ) == expected )
return 0;
/* Delay */
mdelay ( 1 );
}
DBGC ( ena, "ENA %p timed out waiting for reset (status %#08x)\n",
ena, stat );
DBGC ( ena, "ENA %p timed out waiting for reset status %#08x "
"(got %#08x)\n", ena, expected, stat );
return -ETIMEDOUT;
}
/**
* Reset hardware
*
* @v ena ENA device
* @ret rc Return status code
*/
static int ena_reset ( struct ena_nic *ena ) {
int rc;
/* Trigger reset */
writel ( ENA_CTRL_RESET, ( ena->regs + ENA_CTRL ) );
/* Wait for reset to take effect */
if ( ( rc = ena_reset_wait ( ena, ENA_STAT_RESET ) ) != 0 )
return rc;
/* Clear reset */
writel ( 0, ( ena->regs + ENA_CTRL ) );
/* Wait for reset to clear */
if ( ( rc = ena_reset_wait ( ena, 0 ) ) != 0 )
return rc;
return 0;
}
/******************************************************************************
*
* Admin queue

View File

@ -66,7 +66,7 @@ FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
/** Device status register */
#define ENA_STAT 0x58
#define ENA_STAT_READY 0x00000001UL /**< Ready */
#define ENA_STAT_RESET 0x00000008UL /**< Reset in progress */
/** Admin queue entry header */
struct ena_aq_header {

View File

@ -259,7 +259,7 @@ static inline void eplatform_discard ( int dummy __unused, ... ) {}
*/
#define __einfo_error( einfo ) ( { \
__asm__ ( ".section \".einfo\", \"\", " PROGBITS_OPS "\n\t" \
".align 8\n\t" \
".balign 8\n\t" \
"\n1:\n\t" \
".long ( 4f - 1b )\n\t" \
".long %c0\n\t" \
@ -268,7 +268,7 @@ static inline void eplatform_discard ( int dummy __unused, ... ) {}
".long %c1\n\t" \
"\n2:\t.asciz \"" __einfo_desc ( einfo ) "\"\n\t" \
"\n3:\t.asciz \"" __FILE__ "\"\n\t" \
".align 8\n\t" \
".balign 8\n\t" \
"\n4:\n\t" \
".previous\n\t" : : \
"i" ( __einfo_errno ( einfo ) ), \

View File

@ -0,0 +1,17 @@
#ifndef _IPXE_CACHEDHCP_H
#define _IPXE_CACHEDHCP_H
/** @file
*
* Cached DHCP packet
*
*/
FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
#include <stddef.h>
#include <ipxe/uaccess.h>
extern int cachedhcp_record ( userptr_t data, size_t max_len );
#endif /* _IPXE_CACHEDHCP_H */

View File

@ -29,11 +29,6 @@ FILE_LICENCE ( GPL2_OR_LATER );
/* EFI headers redefine ARRAY_SIZE */
#undef ARRAY_SIZE
/* EFI headers expect ICC to define __GNUC__ */
#if defined ( __ICC ) && ! defined ( __GNUC__ )
#define __GNUC__ 1
#endif
/* EFI headers think your compiler uses the MS ABI by default on X64 */
#if __x86_64__
#define EFIAPI __attribute__((ms_abi))

View File

@ -9,6 +9,8 @@
FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
extern void efi_set_autoboot ( void );
#include <ipxe/efi/efi.h>
extern int efi_set_autoboot_ll_addr ( EFI_HANDLE device );
#endif /* _IPXE_EFI_AUTOBOOT_H */

View File

@ -0,0 +1,16 @@
#ifndef _IPXE_EFI_AUTOEXEC_H
#define _IPXE_EFI_AUTOEXEC_H
/** @file
*
* EFI autoexec script
*
*/
FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
#include <ipxe/efi/efi.h>
extern int efi_autoexec_load ( EFI_HANDLE device );
#endif /* _IPXE_EFI_AUTOEXEC_H */

View File

@ -0,0 +1,16 @@
#ifndef _IPXE_EFI_CACHEDHCP_H
#define _IPXE_EFI_CACHEDHCP_H
/** @file
*
* EFI cached DHCP packet
*
*/
FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
#include <ipxe/efi/efi.h>
extern int efi_cachedhcp_record ( EFI_HANDLE device );
#endif /* _IPXE_EFI_CACHEDHCP_H */

View File

@ -76,6 +76,7 @@ FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
#define ERRFILE_dummy_sanboot ( ERRFILE_CORE | 0x00240000 )
#define ERRFILE_fdt ( ERRFILE_CORE | 0x00250000 )
#define ERRFILE_dma ( ERRFILE_CORE | 0x00260000 )
#define ERRFILE_cachedhcp ( ERRFILE_CORE | 0x00270000 )
#define ERRFILE_eisa ( ERRFILE_DRIVER | 0x00000000 )
#define ERRFILE_isa ( ERRFILE_DRIVER | 0x00010000 )
@ -384,6 +385,8 @@ FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
#define ERRFILE_ntlm ( ERRFILE_OTHER | 0x00510000 )
#define ERRFILE_efi_veto ( ERRFILE_OTHER | 0x00520000 )
#define ERRFILE_efi_autoboot ( ERRFILE_OTHER | 0x00530000 )
#define ERRFILE_efi_autoexec ( ERRFILE_OTHER | 0x00540000 )
#define ERRFILE_efi_cachedhcp ( ERRFILE_OTHER | 0x00550000 )
/** @} */

View File

@ -444,75 +444,4 @@ FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
pointer >= table_start ( table ) ; \
pointer-- )
/******************************************************************************
*
* Intel's C compiler chokes on several of the constructs used in this
* file. The workarounds are ugly, so we use them only for an icc
* build.
*
*/
#define ICC_ALIGN_HACK_FACTOR 128
#ifdef __ICC
/*
* icc miscompiles zero-length arrays by inserting padding to a length
* of two array elements. We therefore have to generate the
* __table_entries() symbols by hand in asm.
*
*/
#undef __table_entries
#define __table_entries( table, idx ) ( { \
extern __table_type ( table ) \
__table_temp_sym ( idx, __LINE__ ) [] \
__table_entry ( table, idx ) \
asm ( __table_entries_sym ( table, idx ) ); \
__asm__ ( ".ifndef %c0\n\t" \
".section " __table_section ( table, idx ) "\n\t" \
".align %c1\n\t" \
"\n%c0:\n\t" \
".previous\n\t" \
".endif\n\t" \
: : "i" ( __table_temp_sym ( idx, __LINE__ ) ), \
"i" ( __table_alignment ( table ) ) ); \
__table_temp_sym ( idx, __LINE__ ); } )
#define __table_entries_sym( table, idx ) \
"__tbl_" __table_name ( table ) "_" #idx
#define __table_temp_sym( a, b ) \
___table_temp_sym( __table_, a, _, b )
#define ___table_temp_sym( a, b, c, d ) a ## b ## c ## d
/*
* icc ignores __attribute__ (( aligned (x) )) when it is used to
* decrease the compiler's default choice of alignment (which may be
* higher than the alignment actually required by the structure). We
* work around this by forcing the alignment to a large multiple of
* the required value (so that we are never attempting to decrease the
* default alignment) and then postprocessing the object file to
* reduce the alignment back down to the "real" value.
*
*/
#undef __table_alignment
#define __table_alignment( table ) \
( ICC_ALIGN_HACK_FACTOR * __alignof__ ( __table_type ( table ) ) )
/*
* Because of the alignment hack, we must ensure that the compiler
* never tries to place multiple objects within the same section,
* otherwise the assembler will insert padding to the (incorrect)
* alignment boundary. Do this by appending the line number to table
* section names.
*
* Note that we don't need to worry about padding between array
* elements, since the alignment is declared on the variable (i.e. the
* whole array) rather than on the type (i.e. on all individual array
* elements).
*/
#undef __table_section
#define __table_section( table, idx ) \
".tbl." __table_name ( table ) "." __table_str ( idx ) \
"." __table_xstr ( __LINE__ )
#define __table_xstr( x ) __table_str ( x )
#endif /* __ICC */
#endif /* _IPXE_TABLES_H */

View File

@ -25,40 +25,24 @@ FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
#include <string.h>
#include <errno.h>
#include <ipxe/image.h>
#include <ipxe/init.h>
#include <ipxe/efi/efi.h>
#include <ipxe/efi/efi_autoboot.h>
#include <ipxe/efi/Protocol/SimpleNetwork.h>
#include <ipxe/efi/Protocol/SimpleFileSystem.h>
#include <ipxe/efi/Guid/FileInfo.h>
#include <usr/autoboot.h>
/** @file
*
* EFI automatic booting
* EFI autoboot device
*
*/
/** Autoexec script filename */
#define AUTOEXEC_FILENAME L"autoexec.ipxe"
/** Autoexec script image name */
#define AUTOEXEC_NAME "autoexec.ipxe"
/** Autoexec script (if any) */
static void *efi_autoexec;
/** Autoexec script length */
static size_t efi_autoexec_len;
/**
* Identify autoboot device
*
* @v device Device handle
* @ret rc Return status code
*/
static int efi_set_autoboot_ll_addr ( EFI_HANDLE device ) {
int efi_set_autoboot_ll_addr ( EFI_HANDLE device ) {
EFI_BOOT_SERVICES *bs = efi_systab->BootServices;
union {
EFI_SIMPLE_NETWORK_PROTOCOL *snp;
@ -93,172 +77,3 @@ static int efi_set_autoboot_ll_addr ( EFI_HANDLE device ) {
return 0;
}
/**
* Load autoexec script
*
* @v device Device handle
* @ret rc Return status code
*/
static int efi_load_autoexec ( EFI_HANDLE device ) {
EFI_BOOT_SERVICES *bs = efi_systab->BootServices;
static wchar_t name[] = AUTOEXEC_FILENAME;
union {
void *interface;
EFI_SIMPLE_FILE_SYSTEM_PROTOCOL *fs;
} u;
struct {
EFI_FILE_INFO info;
CHAR16 name[ sizeof ( name ) / sizeof ( name[0] ) ];
} info;
EFI_FILE_PROTOCOL *root;
EFI_FILE_PROTOCOL *file;
UINTN size;
VOID *data;
EFI_STATUS efirc;
int rc;
/* Sanity check */
assert ( efi_autoexec == UNULL );
assert ( efi_autoexec_len == 0 );
/* Open simple file system protocol */
if ( ( efirc = bs->OpenProtocol ( device,
&efi_simple_file_system_protocol_guid,
&u.interface, efi_image_handle,
device,
EFI_OPEN_PROTOCOL_GET_PROTOCOL ))!=0){
rc = -EEFI ( efirc );
DBGC ( device, "EFI %s has no filesystem instance: %s\n",
efi_handle_name ( device ), strerror ( rc ) );
goto err_filesystem;
}
/* Open root directory */
if ( ( efirc = u.fs->OpenVolume ( u.fs, &root ) ) != 0 ) {
rc = -EEFI ( efirc );
DBGC ( device, "EFI %s could not open volume: %s\n",
efi_handle_name ( device ), strerror ( rc ) );
goto err_volume;
}
/* Open autoexec script */
if ( ( efirc = root->Open ( root, &file, name,
EFI_FILE_MODE_READ, 0 ) ) != 0 ) {
rc = -EEFI ( efirc );
DBGC ( device, "EFI %s has no %ls: %s\n",
efi_handle_name ( device ), name, strerror ( rc ) );
goto err_open;
}
/* Get file information */
size = sizeof ( info );
if ( ( efirc = file->GetInfo ( file, &efi_file_info_id, &size,
&info ) ) != 0 ) {
rc = -EEFI ( efirc );
DBGC ( device, "EFI %s could not get %ls info: %s\n",
efi_handle_name ( device ), name, strerror ( rc ) );
goto err_getinfo;
}
size = info.info.FileSize;
/* Ignore zero-length files */
if ( ! size ) {
rc = -EINVAL;
DBGC ( device, "EFI %s has zero-length %ls\n",
efi_handle_name ( device ), name );
goto err_empty;
}
/* Allocate temporary copy */
if ( ( efirc = bs->AllocatePool ( EfiBootServicesData, size,
&data ) ) != 0 ) {
rc = -EEFI ( efirc );
DBGC ( device, "EFI %s could not allocate %ls: %s\n",
efi_handle_name ( device ), name, strerror ( rc ) );
goto err_alloc;
}
/* Read file */
if ( ( efirc = file->Read ( file, &size, data ) ) != 0 ) {
rc = -EEFI ( efirc );
DBGC ( device, "EFI %s could not read %ls: %s\n",
efi_handle_name ( device ), name, strerror ( rc ) );
goto err_read;
}
/* Record autoexec script */
efi_autoexec = data;
efi_autoexec_len = size;
data = NULL;
DBGC ( device, "EFI %s found %ls\n",
efi_handle_name ( device ), name );
/* Success */
rc = 0;
err_read:
if ( data )
bs->FreePool ( data );
err_alloc:
err_empty:
err_getinfo:
file->Close ( file );
err_open:
root->Close ( root );
err_volume:
bs->CloseProtocol ( device, &efi_simple_file_system_protocol_guid,
efi_image_handle, device );
err_filesystem:
return rc;
}
/**
* Configure automatic booting
*
*/
void efi_set_autoboot ( void ) {
EFI_HANDLE device = efi_loaded_image->DeviceHandle;
/* Identify autoboot device, if any */
efi_set_autoboot_ll_addr ( device );
/* Load autoexec script, if any */
efi_load_autoexec ( device );
}
/**
* Register automatic boot image
*
*/
static void efi_autoboot_startup ( void ) {
EFI_BOOT_SERVICES *bs = efi_systab->BootServices;
EFI_HANDLE device = efi_loaded_image->DeviceHandle;
const char *name = AUTOEXEC_NAME;
struct image *image;
/* Do nothing if we have no autoexec script */
if ( ! efi_autoexec )
return;
/* Create autoexec image */
image = image_memory ( name, virt_to_user ( efi_autoexec ),
efi_autoexec_len );
if ( ! image ) {
DBGC ( device, "EFI %s could not create %s\n",
efi_handle_name ( device ), name );
return;
}
DBGC ( device, "EFI %s registered %s\n",
efi_handle_name ( device ), name );
/* Free temporary copy */
bs->FreePool ( efi_autoexec );
efi_autoexec = NULL;
}
/** Automatic boot startup function */
struct startup_fn efi_autoboot_startup_fn __startup_fn ( STARTUP_NORMAL ) = {
.name = "efi_autoboot",
.startup = efi_autoboot_startup,
};

View File

@ -0,0 +1,206 @@
/*
* Copyright (C) 2021 Michael Brown <mbrown@fensystems.co.uk>.
*
* 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 of the
* License, or any later version.
*
* This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
* 02110-1301, USA.
*
* You can also choose to distribute this program under the terms of
* the Unmodified Binary Distribution Licence (as given in the file
* COPYING.UBDL), provided that you have satisfied its requirements.
*/
FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
#include <string.h>
#include <errno.h>
#include <ipxe/image.h>
#include <ipxe/init.h>
#include <ipxe/efi/efi.h>
#include <ipxe/efi/efi_autoexec.h>
#include <ipxe/efi/Protocol/SimpleFileSystem.h>
#include <ipxe/efi/Guid/FileInfo.h>
/** @file
*
* EFI autoexec script
*
*/
/** Autoexec script filename */
#define AUTOEXEC_FILENAME L"autoexec.ipxe"
/** Autoexec script image name */
#define AUTOEXEC_NAME "autoexec.ipxe"
/** Autoexec script (if any) */
static void *efi_autoexec;
/** Autoexec script length */
static size_t efi_autoexec_len;
/**
* Load autoexec script
*
* @v device Device handle
* @ret rc Return status code
*/
int efi_autoexec_load ( EFI_HANDLE device ) {
EFI_BOOT_SERVICES *bs = efi_systab->BootServices;
static wchar_t name[] = AUTOEXEC_FILENAME;
union {
void *interface;
EFI_SIMPLE_FILE_SYSTEM_PROTOCOL *fs;
} u;
struct {
EFI_FILE_INFO info;
CHAR16 name[ sizeof ( name ) / sizeof ( name[0] ) ];
} info;
EFI_FILE_PROTOCOL *root;
EFI_FILE_PROTOCOL *file;
UINTN size;
VOID *data;
EFI_STATUS efirc;
int rc;
/* Sanity check */
assert ( efi_autoexec == NULL );
assert ( efi_autoexec_len == 0 );
/* Open simple file system protocol */
if ( ( efirc = bs->OpenProtocol ( device,
&efi_simple_file_system_protocol_guid,
&u.interface, efi_image_handle,
device,
EFI_OPEN_PROTOCOL_GET_PROTOCOL ))!=0){
rc = -EEFI ( efirc );
DBGC ( device, "EFI %s has no filesystem instance: %s\n",
efi_handle_name ( device ), strerror ( rc ) );
goto err_filesystem;
}
/* Open root directory */
if ( ( efirc = u.fs->OpenVolume ( u.fs, &root ) ) != 0 ) {
rc = -EEFI ( efirc );
DBGC ( device, "EFI %s could not open volume: %s\n",
efi_handle_name ( device ), strerror ( rc ) );
goto err_volume;
}
/* Open autoexec script */
if ( ( efirc = root->Open ( root, &file, name,
EFI_FILE_MODE_READ, 0 ) ) != 0 ) {
rc = -EEFI ( efirc );
DBGC ( device, "EFI %s has no %ls: %s\n",
efi_handle_name ( device ), name, strerror ( rc ) );
goto err_open;
}
/* Get file information */
size = sizeof ( info );
if ( ( efirc = file->GetInfo ( file, &efi_file_info_id, &size,
&info ) ) != 0 ) {
rc = -EEFI ( efirc );
DBGC ( device, "EFI %s could not get %ls info: %s\n",
efi_handle_name ( device ), name, strerror ( rc ) );
goto err_getinfo;
}
size = info.info.FileSize;
/* Ignore zero-length files */
if ( ! size ) {
rc = -EINVAL;
DBGC ( device, "EFI %s has zero-length %ls\n",
efi_handle_name ( device ), name );
goto err_empty;
}
/* Allocate temporary copy */
if ( ( efirc = bs->AllocatePool ( EfiBootServicesData, size,
&data ) ) != 0 ) {
rc = -EEFI ( efirc );
DBGC ( device, "EFI %s could not allocate %ls: %s\n",
efi_handle_name ( device ), name, strerror ( rc ) );
goto err_alloc;
}
/* Read file */
if ( ( efirc = file->Read ( file, &size, data ) ) != 0 ) {
rc = -EEFI ( efirc );
DBGC ( device, "EFI %s could not read %ls: %s\n",
efi_handle_name ( device ), name, strerror ( rc ) );
goto err_read;
}
/* Record autoexec script */
efi_autoexec = data;
efi_autoexec_len = size;
data = NULL;
DBGC ( device, "EFI %s found %ls\n",
efi_handle_name ( device ), name );
/* Success */
rc = 0;
err_read:
if ( data )
bs->FreePool ( data );
err_alloc:
err_empty:
err_getinfo:
file->Close ( file );
err_open:
root->Close ( root );
err_volume:
bs->CloseProtocol ( device, &efi_simple_file_system_protocol_guid,
efi_image_handle, device );
err_filesystem:
return rc;
}
/**
* Register autoexec script
*
*/
static void efi_autoexec_startup ( void ) {
EFI_BOOT_SERVICES *bs = efi_systab->BootServices;
EFI_HANDLE device = efi_loaded_image->DeviceHandle;
const char *name = AUTOEXEC_NAME;
struct image *image;
/* Do nothing if we have no autoexec script */
if ( ! efi_autoexec )
return;
/* Create autoexec image */
image = image_memory ( name, virt_to_user ( efi_autoexec ),
efi_autoexec_len );
if ( ! image ) {
DBGC ( device, "EFI %s could not create %s\n",
efi_handle_name ( device ), name );
return;
}
DBGC ( device, "EFI %s registered %s\n",
efi_handle_name ( device ), name );
/* Free temporary copy */
bs->FreePool ( efi_autoexec );
efi_autoexec = NULL;
}
/** Autoexec script startup function */
struct startup_fn efi_autoexec_startup_fn __startup_fn ( STARTUP_NORMAL ) = {
.name = "efi_autoexec",
.startup = efi_autoexec_startup,
};

View File

@ -0,0 +1,94 @@
/*
* Copyright (C) 2021 Michael Brown <mbrown@fensystems.co.uk>.
*
* 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 of the
* License, or any later version.
*
* This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
* 02110-1301, USA.
*
* You can also choose to distribute this program under the terms of
* the Unmodified Binary Distribution Licence (as given in the file
* COPYING.UBDL), provided that you have satisfied its requirements.
*/
FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
#include <string.h>
#include <errno.h>
#include <ipxe/cachedhcp.h>
#include <ipxe/efi/efi.h>
#include <ipxe/efi/efi_cachedhcp.h>
#include <ipxe/efi/Protocol/PxeBaseCode.h>
/** @file
*
* EFI cached DHCP packet
*
*/
/**
* Record cached DHCP packet
*
* @v device Device handle
* @ret rc Return status code
*/
int efi_cachedhcp_record ( EFI_HANDLE device ) {
EFI_BOOT_SERVICES *bs = efi_systab->BootServices;
union {
EFI_PXE_BASE_CODE_PROTOCOL *pxe;
void *interface;
} pxe;
EFI_PXE_BASE_CODE_MODE *mode;
EFI_STATUS efirc;
int rc;
/* Look for a PXE base code instance on the image's device handle */
if ( ( efirc = bs->OpenProtocol ( device,
&efi_pxe_base_code_protocol_guid,
&pxe.interface, efi_image_handle,
NULL,
EFI_OPEN_PROTOCOL_GET_PROTOCOL ))!=0){
rc = -EEFI ( efirc );
DBGC ( device, "EFI %s has no PXE base code instance: %s\n",
efi_handle_name ( device ), strerror ( rc ) );
goto err_open;
}
/* Do not attempt to cache IPv6 packets */
mode = pxe.pxe->Mode;
if ( mode->UsingIpv6 ) {
rc = -ENOTSUP;
DBGC ( device, "EFI %s has IPv6 PXE base code\n",
efi_handle_name ( device ) );
goto err_ipv6;
}
/* Record DHCPACK, if present */
if ( mode->DhcpAckReceived &&
( ( rc = cachedhcp_record ( virt_to_user ( &mode->DhcpAck ),
sizeof ( mode->DhcpAck ) ) ) != 0 ) ) {
DBGC ( device, "EFI %s could not record DHCPACK: %s\n",
efi_handle_name ( device ), strerror ( rc ) );
goto err_record;
}
/* Success */
rc = 0;
err_record:
err_ipv6:
bs->CloseProtocol ( device, &efi_pxe_base_code_protocol_guid,
efi_image_handle, NULL );
err_open:
return rc;
}

View File

@ -22,10 +22,13 @@ FILE_LICENCE ( GPL2_OR_LATER );
#include <stdlib.h>
#include <errno.h>
#include <ipxe/device.h>
#include <ipxe/init.h>
#include <ipxe/efi/efi.h>
#include <ipxe/efi/efi_driver.h>
#include <ipxe/efi/efi_snp.h>
#include <ipxe/efi/efi_autoboot.h>
#include <ipxe/efi/efi_autoexec.h>
#include <ipxe/efi/efi_cachedhcp.h>
#include <ipxe/efi/efi_watchdog.h>
#include <ipxe/efi/efi_veto.h>
@ -48,9 +51,6 @@ EFI_STATUS EFIAPI _efi_start ( EFI_HANDLE image_handle,
if ( ( efirc = efi_init ( image_handle, systab ) ) != 0 )
goto err_init;
/* Record autoboot device (if any) */
efi_set_autoboot();
/* Claim SNP devices for use by iPXE */
efi_snp_claim();
@ -72,6 +72,28 @@ EFI_STATUS EFIAPI _efi_start ( EFI_HANDLE image_handle,
return efirc;
}
/**
* Initialise EFI application
*
*/
static void efi_init_application ( void ) {
EFI_HANDLE device = efi_loaded_image->DeviceHandle;
/* Identify autoboot device, if any */
efi_set_autoboot_ll_addr ( device );
/* Store cached DHCP packet, if any */
efi_cachedhcp_record ( device );
/* Load autoexec script, if any */
efi_autoexec_load ( device );
}
/** EFI application initialisation function */
struct init_fn efi_init_application_fn __init_fn ( INIT_NORMAL ) = {
.initialise = efi_init_application,
};
/**
* Probe EFI root bus
*

View File

@ -210,18 +210,19 @@ int uriboot ( struct uri *filename, struct uri **root_paths,
}
/**
* Close all open net devices
* Close all but one network device
*
* Called before a fresh boot attempt in order to free up memory. We
* don't just close the device immediately after the boot fails,
* because there may still be TCP connections in the process of
* closing.
*/
static void close_all_netdevs ( void ) {
struct net_device *netdev;
static void close_other_netdevs ( struct net_device *netdev ) {
struct net_device *other;
for_each_netdev ( netdev ) {
ifclose ( netdev );
for_each_netdev ( other ) {
if ( other != netdev )
ifclose ( other );
}
}
@ -388,7 +389,7 @@ int netboot ( struct net_device *netdev ) {
int rc;
/* Close all other network devices */
close_all_netdevs();
close_other_netdevs ( netdev );
/* Open device and display device status */
if ( ( rc = ifopen ( netdev ) ) != 0 )

1
src/util/.gitignore vendored
View File

@ -6,5 +6,4 @@ elf2efi32
elf2efi64
efirom
efifatbin
iccfix
einfo

View File

@ -268,13 +268,27 @@ fi
#
if [ -n "${ISOIMG}" ] ; then
MKISOFS=
MKISOFS_MISSING=
MKISOFS_NOTSUP=
for CMD in genisoimage mkisofs xorrisofs ; do
if "${CMD}" ${ISOARGS} --version "${ISODIR}" >/dev/null 2>&1 ; then
MKISOFS="${CMD}"
break
if ! "${CMD}" --version >/dev/null 2>&1 ; then
MKISOFS_MISSING="${MKISOFS_MISSING} ${CMD}"
continue
fi
if ! "${CMD}" ${ISOARGS} --version "${ISODIR}" >/dev/null 2>&1 ; then
MKISOFS_NOTSUP="${MKISOFS_NOTSUP} ${CMD}"
continue
fi
MKISOFS="${CMD}"
break
done
if [ -z "${MKISOFS}" ] ; then
if [ -n "${MKISOFS_MISSING}" ] ; then
echo "${0}:${MKISOFS_MISSING}: not installed" >&2
fi
if [ -n "${MKISOFS_NOTSUP}" ] ; then
echo "${0}:${MKISOFS_NOTSUP}: cannot handle ${ISOARGS}" >&2
fi
echo "${0}: cannot find a suitable mkisofs or equivalent" >&2
exit 1
fi

View File

@ -1,157 +0,0 @@
#include <stdint.h>
#include <stddef.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <fcntl.h>
#include <errno.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <sys/mman.h>
#include <elf.h>
#include <ipxe/tables.h>
#define DEBUG 0
#define eprintf(...) fprintf ( stderr, __VA_ARGS__ )
#define dprintf(...) do { \
if ( DEBUG ) \
fprintf ( stderr, __VA_ARGS__ ); \
} while ( 0 )
#ifdef SELF_INCLUDED
/**
* Fix up ICC alignments
*
* @v elf ELF header
* @ret rc Return status code
*
* See comments in tables.h for an explanation of why this monstrosity
* is necessary.
*/
static int ICCFIX ( void *elf ) {
ELF_EHDR *ehdr = elf;
ELF_SHDR *shdr = ( elf + ehdr->e_shoff );
size_t shentsize = ehdr->e_shentsize;
unsigned int shnum = ehdr->e_shnum;
ELF_SHDR *strtab = ( ( ( void * ) shdr ) +
( ehdr->e_shstrndx * shentsize ) );
char *strings = ( elf + strtab->sh_offset );
for ( ; shnum-- ; shdr = ( ( ( void * ) shdr ) + shentsize ) ) {
char *name = ( strings + shdr->sh_name );
unsigned long align = shdr->sh_addralign;
unsigned long new_align;
if ( ( strncmp ( name, ".tbl.", 5 ) == 0 ) &&
( align >= ICC_ALIGN_HACK_FACTOR ) ) {
new_align = ( align / ICC_ALIGN_HACK_FACTOR );
shdr->sh_addralign = new_align;
dprintf ( "Section \"%s\": alignment %ld->%ld\n",
name, align, new_align );
}
}
return 0;
}
#else /* SELF_INCLUDED */
#define SELF_INCLUDED
/* Include iccfix32() function */
#define ELF_EHDR Elf32_Ehdr
#define ELF_SHDR Elf32_Shdr
#define ICCFIX iccfix32
#include "iccfix.c"
#undef ELF_EHDR
#undef ELF_SHDR
#undef ICCFIX
/* Include iccfix64() function */
#define ELF_EHDR Elf64_Ehdr
#define ELF_SHDR Elf64_Shdr
#define ICCFIX iccfix64
#include "iccfix.c"
#undef ELF_EHDR
#undef ELF_SHDR
#undef ICCFIX
static int iccfix ( const char *filename ) {
int fd;
struct stat stat;
void *elf;
unsigned char *eident;
int rc;
/* Open and mmap file */
fd = open ( filename, O_RDWR );
if ( fd < 0 ) {
eprintf ( "Could not open %s: %s\n",
filename, strerror ( errno ) );
rc = -1;
goto err_open;
}
if ( fstat ( fd, &stat ) < 0 ) {
eprintf ( "Could not determine size of %s: %s\n",
filename, strerror ( errno ) );
rc = -1;
goto err_fstat;
}
elf = mmap ( NULL, stat.st_size, ( PROT_READ | PROT_WRITE ),
MAP_SHARED, fd, 0 );
if ( elf == MAP_FAILED ) {
eprintf ( "Could not map %s: %s\n",
filename, strerror ( errno ) );
rc = -1;
goto err_mmap;
}
/* Perform fixups */
eident = elf;
switch ( eident[EI_CLASS] ) {
case ELFCLASS32:
rc = iccfix32 ( elf );
break;
case ELFCLASS64:
rc = iccfix64 ( elf );
break;
default:
eprintf ( "Unknown ELF class %d in %s\n",
eident[EI_CLASS], filename );
rc = -1;
break;
}
munmap ( elf, stat.st_size );
err_mmap:
err_fstat:
close ( fd );
err_open:
return rc;
}
int main ( int argc, char **argv ) {
int i;
int rc;
/* Parse command line */
if ( argc < 2 ) {
eprintf ( "Syntax: %s <object_file>...\n", argv[0] );
exit ( 1 );
}
/* Process each object in turn */
for ( i = 1 ; i < argc ; i++ ) {
if ( ( rc = iccfix ( argv[i] ) ) != 0 ) {
eprintf ( "Could not fix up %s\n", argv[i] );
exit ( 1 );
}
}
return 0;
}
#endif /* SELF_INCLUDED */