summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorMichael Brown2008-10-12 02:55:55 +0200
committerMichael Brown2008-10-13 11:24:14 +0200
commit81d92c6d34f9ce68f7c2bbd5b92352b3a631bcd0 (patch)
tree7bb6912503c83076ef9cad54a0503abc7aa19907
parent[sanboot] Quick and dirty hack to make SAN boot protocols selectable (diff)
downloadipxe-81d92c6d34f9ce68f7c2bbd5b92352b3a631bcd0.tar.gz
ipxe-81d92c6d34f9ce68f7c2bbd5b92352b3a631bcd0.tar.xz
ipxe-81d92c6d34f9ce68f7c2bbd5b92352b3a631bcd0.zip
[efi] Add EFI image format and basic runtime environment
We have EFI APIs for CPU I/O, PCI I/O, timers, console I/O, user access and user memory allocation. EFI executables are created using the vanilla GNU toolchain, with the EXE header handcrafted in assembly and relocations generated by a custom efilink utility.
-rw-r--r--src/Makefile3
-rw-r--r--src/Makefile.housekeeping9
-rw-r--r--src/arch/i386/Makefile1
-rw-r--r--src/arch/i386/Makefile.efi24
-rw-r--r--src/arch/i386/include/bits/nap.h1
-rw-r--r--src/arch/i386/include/gpxe/efi/efix86_nap.h16
-rw-r--r--src/arch/i386/interface/efi/efix86_nap.c46
-rw-r--r--src/arch/i386/prefix/efiprefix.S175
-rw-r--r--src/arch/i386/scripts/efi.lds174
-rw-r--r--src/config/defaults/efi.h20
-rw-r--r--src/config/general.h1
-rw-r--r--src/core/config.c6
-rw-r--r--src/image/efi_image.c106
-rw-r--r--src/include/gpxe/efi/IndustryStandard/PeImage.h742
-rw-r--r--src/include/gpxe/efi/Protocol/Cpu.h326
-rw-r--r--src/include/gpxe/efi/Protocol/CpuIo.h128
-rw-r--r--src/include/gpxe/efi/Protocol/DebugSupport.h656
-rw-r--r--src/include/gpxe/efi/Protocol/PciRootBridgeIo.h450
-rw-r--r--src/include/gpxe/efi/efi.h52
-rw-r--r--src/include/gpxe/efi/efi_io.h178
-rw-r--r--src/include/gpxe/efi/efi_pci.h146
-rw-r--r--src/include/gpxe/efi/efi_timer.h16
-rw-r--r--src/include/gpxe/efi/efi_uaccess.h88
-rw-r--r--src/include/gpxe/efi/efi_umalloc.h16
-rw-r--r--src/include/gpxe/errfile.h2
-rw-r--r--src/include/gpxe/features.h1
-rw-r--r--src/include/gpxe/io.h1
-rw-r--r--src/include/gpxe/pci_io.h1
-rw-r--r--src/include/gpxe/timer.h1
-rw-r--r--src/include/gpxe/uaccess.h1
-rw-r--r--src/include/gpxe/umalloc.h1
-rw-r--r--src/interface/efi/efi_console.c273
-rw-r--r--src/interface/efi/efi_entry.c83
-rw-r--r--src/interface/efi/efi_io.c201
-rw-r--r--src/interface/efi/efi_pci.c81
-rw-r--r--src/interface/efi/efi_timer.c115
-rw-r--r--src/interface/efi/efi_uaccess.c37
-rw-r--r--src/interface/efi/efi_umalloc.c96
-rw-r--r--src/util/.gitignore1
-rw-r--r--src/util/efilink.c507
40 files changed, 4781 insertions, 1 deletions
diff --git a/src/Makefile b/src/Makefile
index 89f43577..01048aae 100644
--- a/src/Makefile
+++ b/src/Makefile
@@ -37,6 +37,7 @@ SYMCHECK := $(PERL) ./util/symcheck.pl
SORTOBJDUMP := $(PERL) ./util/sortobjdump.pl
NRV2B := ./util/nrv2b
ZBIN := ./util/zbin
+EFILINK := ./util/efilink
DOXYGEN := doxygen
###############################################################################
@@ -57,7 +58,7 @@ SRCDIRS += drivers/block
SRCDIRS += drivers/nvs
SRCDIRS += drivers/bitbash
SRCDIRS += drivers/infiniband
-SRCDIRS += interface/pxe
+SRCDIRS += interface/pxe interface/efi
SRCDIRS += tests
SRCDIRS += crypto crypto/axtls crypto/matrixssl
SRCDIRS += hci hci/commands hci/tui
diff --git a/src/Makefile.housekeeping b/src/Makefile.housekeeping
index 14d07fb0..7054cdcf 100644
--- a/src/Makefile.housekeeping
+++ b/src/Makefile.housekeeping
@@ -695,6 +695,15 @@ CLEANUP += $(ZBIN)
###############################################################################
#
+# The EFI custom linker
+#
+$(EFILINK) : util/efilink.c $(MAKEDEPS)
+ $(QM)$(ECHO) " [HOSTCC] $@"
+ $(Q)$(HOST_CC) -O2 -o $@ $< -lbfd
+CLEANUP += $(EFILINK)
+
+###############################################################################
+#
# Auto-incrementing build serial number. Append "bs" to your list of
# build targets to get a serial number printed at the end of the
# build. Enable -DBUILD_SERIAL in order to see it when the code runs.
diff --git a/src/arch/i386/Makefile b/src/arch/i386/Makefile
index 1959fbfd..dac53493 100644
--- a/src/arch/i386/Makefile
+++ b/src/arch/i386/Makefile
@@ -64,6 +64,7 @@ SRCDIRS += arch/i386/drivers/net
SRCDIRS += arch/i386/interface/pcbios
SRCDIRS += arch/i386/interface/pxe
SRCDIRS += arch/i386/interface/syslinux
+SRCDIRS += arch/i386/interface/efi
# The various xxx_loader.c files are #included into core/loader.c and
# should not be compiled directly.
diff --git a/src/arch/i386/Makefile.efi b/src/arch/i386/Makefile.efi
new file mode 100644
index 00000000..f1eb6fdf
--- /dev/null
+++ b/src/arch/i386/Makefile.efi
@@ -0,0 +1,24 @@
+# -*- makefile -*- : Force emacs to use Makefile mode
+
+# The EFI linker script
+#
+LDSCRIPT = arch/i386/scripts/efi.lds
+
+# Use a relocatable link; we perform final relocations in the efilink utility.
+#
+LDFLAGS += -r -d -S
+
+# Media types.
+#
+NON_AUTO_MEDIA += efi
+
+# Rule for building EFI files
+#
+$(BIN)/%.efi.tmp-reloc : $(BIN)/%.efi.tmp $(EFILINK)
+ $(QM)$(ECHO) " [EFILINK] $@"
+ $(Q)$(LD) -e 0 -o /dev/null $< # Check for unresolved symbols
+ $(Q)$(EFILINK) $< $@
+
+$(BIN)/%.efi : $(BIN)/%.efi.tmp-reloc
+ $(QM)$(ECHO) " [FINISH] $@"
+ $(Q)$(OBJCOPY) -Obinary $< $@
diff --git a/src/arch/i386/include/bits/nap.h b/src/arch/i386/include/bits/nap.h
index 2c85444a..f8ba7a7c 100644
--- a/src/arch/i386/include/bits/nap.h
+++ b/src/arch/i386/include/bits/nap.h
@@ -8,5 +8,6 @@
*/
#include <gpxe/bios_nap.h>
+#include <gpxe/efi/efix86_nap.h>
#endif /* _BITS_MAP_H */
diff --git a/src/arch/i386/include/gpxe/efi/efix86_nap.h b/src/arch/i386/include/gpxe/efi/efix86_nap.h
new file mode 100644
index 00000000..91424c54
--- /dev/null
+++ b/src/arch/i386/include/gpxe/efi/efix86_nap.h
@@ -0,0 +1,16 @@
+#ifndef _GPXE_EFIX86_NAP_H
+#define _GPXE_EFIX86_NAP_H
+
+/** @file
+ *
+ * EFI CPU sleeping
+ *
+ */
+
+#ifdef NAP_EFIX86
+#define NAP_PREFIX_efix86
+#else
+#define NAP_PREFIX_efix86 __efix86_
+#endif
+
+#endif /* _GPXE_EFIX86_NAP_H */
diff --git a/src/arch/i386/interface/efi/efix86_nap.c b/src/arch/i386/interface/efi/efix86_nap.c
new file mode 100644
index 00000000..45e99a68
--- /dev/null
+++ b/src/arch/i386/interface/efi/efix86_nap.c
@@ -0,0 +1,46 @@
+/*
+ * Copyright (C) 2008 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., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#include <gpxe/nap.h>
+#include <gpxe/efi/efi.h>
+
+/** @file
+ *
+ * gPXE CPU sleeping API for EFI
+ *
+ */
+
+/**
+ * Sleep until next interrupt
+ *
+ */
+static void efix86_cpu_nap ( void ) {
+ /*
+ * I can't find any EFI API that allows us to put the CPU to
+ * sleep. The CpuSleep() function is defined in CpuLib.h, but
+ * isn't part of any exposed protocol so we have no way to
+ * call it.
+ *
+ * The EFI shell doesn't seem to bother sleeping the CPU; it
+ * just sits there idly burning power.
+ *
+ */
+ __asm__ __volatile__ ( "hlt" );
+}
+
+PROVIDE_NAP ( efix86, cpu_nap, efix86_cpu_nap );
diff --git a/src/arch/i386/prefix/efiprefix.S b/src/arch/i386/prefix/efiprefix.S
new file mode 100644
index 00000000..c4cf68e4
--- /dev/null
+++ b/src/arch/i386/prefix/efiprefix.S
@@ -0,0 +1,175 @@
+ .text
+ .code32
+ .arch i386
+ .section ".prefix", "a", @progbits
+ .org 0x00
+
+ /* DOS (.com) header
+ *
+ * EFI executables seem to leave most of this empty
+ */
+mzhdr:
+ .ascii "MZ" /* Magic number */
+ .word 0 /* Bytes on last page of file */
+ .word 0 /* Pages in file */
+ .word 0 /* Relocations */
+ .word 0 /* Size of header in paragraphs */
+ .word 0 /* Minimum extra paragraphs needed */
+ .word 0 /* Maximum extra paragraphs needed */
+ .word 0 /* Initial (relative) SS value */
+ .word 0 /* Initial SP value */
+ .word 0 /* "Checksum" */
+ .word 0 /* Initial IP value */
+ .word 0 /* Initial (relative) CS value */
+ .word 0 /* File address of relocation table */
+ .word 0 /* Ovesrlay number */
+ .word 0, 0, 0, 0 /* Reserved words */
+ .word 0 /* OEM identifier (for e_oeminfo) */
+ .word 0 /* OEM information; e_oemid specific */
+ .word 0, 0, 0, 0, 0 /* Reserved words */
+ .word 0, 0, 0, 0, 0 /* Reserved words */
+ .long pehdr_lma /* File address of new exe header */
+ .size mzhdr, . - mzhdr
+
+ /* PE header */
+ .org 0xc0 /* For compatibility with MS toolchain */
+pehdr:
+ .ascii "PE\0\0" /* Magic number */
+ .word 0x014c /* CPU architecture: i386 */
+ .word num_pe_sections /* Number of sections */
+ .long 0x10d1a884 /* Timestamp */
+ .long 0 /* Symbol table */
+ .long 0 /* Number of symbols */
+ .word opthdr_size /* Size of optional header */
+ .word 0x2102 /* Characteristics */
+ .size pehdr, . - pehdr
+ .equ pehdr_lma, pehdr - mzhdr
+
+ /* "Optional" header */
+opthdr:
+ .word 0x010b /* Magic number */
+ .byte 0 /* Linker major version number */
+ .byte 0 /* Linker minor version number */
+ .long _text_filesz /* Size of text section */
+ .long _data_filesz /* Size of data section */
+ .long _bss_filesz /* Size of bss section */
+ .long efi_entry_lma /* Entry point */
+ .long _text_lma /* Text section start RVA */
+ .long _data_lma /* Data section start RVA */
+ .long 0 /* Image base address */
+ .long _max_align /* Section alignment */
+ .long _max_align /* File alignment */
+ .word 0 /* Operating system major version number */
+ .word 0 /* Operating system minor version number */
+ .word 0 /* Image major version number */
+ .word 0 /* Image minor version number */
+ .word 0 /* Subsystem major version number */
+ .word 0 /* Subsystem minor version number */
+ .long 0 /* Reserved */
+ .long _filesz /* Total image size */
+ .long _prefix_filesz /* Total header size */
+ .long 0 /* "Checksum" */
+ .word 0x0a /* Subsystem: EFI */
+ .word 0 /* DLL characteristics */
+ .long 0 /* Size of stack reserve */
+ .long 0 /* Size of stack commit */
+ .long 0 /* Size of heap reserve */
+ .long 0 /* Size of heap commit */
+ .long 0 /* Loader flags */
+ .long 16 /* Number of data directory entries */
+ .long 0, 0 /* Export directory */
+ .long 0, 0 /* Import directory */
+ .long 0, 0 /* Resource directory */
+ .long 0, 0 /* Exception directory */
+ .long 0, 0 /* Security directory */
+ .long _reloc_lma, _reloc_filesz /* Base relocation directory */
+ .long debugdir_lma, debugdir_size /* Debug directory */
+ .long 0, 0 /* Description directory */
+ .long 0, 0 /* Special directory */
+ .long 0, 0 /* Thread storage directory */
+ .long 0, 0 /* Load configuration directory */
+ .long 0, 0 /* Bound import directory */
+ .long 0, 0 /* Import address table directory */
+ .long 0, 0 /* Delay import directory */
+ .long 0, 0 /* Reserved */
+ .long 0, 0 /* Reserved */
+ .size opthdr, . - opthdr
+ .equ opthdr_size, . - opthdr
+
+ /* PE sections */
+pe_sections:
+text_section:
+ .asciz ".text" /* Section name */
+ .align 8
+ .long _text_filesz /* Section size */
+ .long _text_lma /* Relative Virtual Address */
+ .long _text_filesz /* Section size (rounded up) */
+ .long _text_lma /* Pointer to raw data */
+ .long 0 /* Link-time relocations */
+ .long 0 /* Line numbers */
+ .word 0 /* Number of link-time relocations */
+ .word 0 /* Number of line numbers */
+ .long 0x68000020 /* Characteristics */
+rodata_section:
+ .asciz ".rodata" /* Section name */
+ .align 8
+ .long _rodata_filesz /* Section size */
+ .long _rodata_lma /* Relative Virtual Address */
+ .long _rodata_filesz /* Section size (rounded up) */
+ .long _rodata_lma /* Pointer to raw data */
+ .long 0 /* Link-time relocations */
+ .long 0 /* Line numbers */
+ .word 0 /* Number of link-time relocations */
+ .word 0 /* Number of line numbers */
+ .long 0x48000040 /* Characteristics */
+data_section:
+ .asciz ".data" /* Section name */
+ .align 8
+ .long _data_filesz /* Section size */
+ .long _data_lma /* Relative Virtual Address */
+ .long _data_filesz /* Section size (rounded up) */
+ .long _data_lma /* Pointer to raw data */
+ .long 0 /* Link-time relocations */
+ .long 0 /* Line numbers */
+ .word 0 /* Number of link-time relocations */
+ .word 0 /* Number of line numbers */
+ .long 0xc8000040 /* Characteristics */
+reloc_section:
+ .asciz ".reloc" /* Section name */
+ .align 8
+ .long _reloc_filesz /* Section size */
+ .long _reloc_lma /* Relative Virtual Address */
+ .long _reloc_filesz /* Section size (rounded up) */
+ .long _reloc_lma /* Pointer to raw data */
+ .long 0 /* Link-time relocations */
+ .long 0 /* Line numbers */
+ .word 0 /* Number of link-time relocations */
+ .word 0 /* Number of line numbers */
+ .long 0x42000040 /* Characteristics */
+
+pe_sections_end:
+ .size pe_sections, . - pe_sections
+ .equ num_pe_sections, ( ( . - pe_sections ) / 0x28 )
+
+ /* Debug directory */
+ .section ".rodata"
+ .globl debugdir
+debugdir:
+ .long 0 /* Characteristics */
+ .long 0x10d1a884 /* Timestamp */
+ .word 0 /* Major version */
+ .word 0 /* Minor version */
+ .long 0x02 /* RSDS? */
+ .long codeview_rsds_size /* Size of data */
+ .long codeview_rsds_lma /* RVA */
+ .long codeview_rsds_lma /* File offset */
+ .size debugdir, . - debugdir
+ .equ debugdir_size, . - debugdir
+ /* Codeview structure */
+ .globl codeview_rsds
+codeview_rsds:
+ .ascii "RSDS" /* Magic number */
+ .long 0, 0, 0, 0, 0 /* Unused by EFI */
+ .asciz "efiprefix.pdb"
+ .size codeview_rsds, . - codeview_rsds
+ .equ codeview_rsds_size, . - codeview_rsds
diff --git a/src/arch/i386/scripts/efi.lds b/src/arch/i386/scripts/efi.lds
new file mode 100644
index 00000000..8d9ecd77
--- /dev/null
+++ b/src/arch/i386/scripts/efi.lds
@@ -0,0 +1,174 @@
+/* -*- sh -*- */
+
+/*
+ * Linker script for EFI images
+ *
+ */
+
+EXTERN ( efi_entry )
+
+SECTIONS {
+
+ /* The file starts at a virtual address of zero, and sections are
+ * contiguous. Each section is aligned to at least _max_align,
+ * which defaults to 32. Load addresses are equal to virtual
+ * addresses.
+ */
+
+ . = 0;
+ PROVIDE ( _max_align = 32 );
+
+ /*
+ * The prefix
+ *
+ */
+
+ .prefix : AT ( _prefix_lma ) {
+ _prefix = .;
+ *(.prefix)
+ *(.prefix.*)
+ _mprefix = .;
+ } .prefix_bss (NOLOAD) : {
+ _eprefix = .;
+ }
+ _prefix_filesz = ABSOLUTE ( _mprefix - _prefix );
+ _prefix_memsz = ABSOLUTE ( _eprefix - _prefix );
+
+ /*
+ * The text section
+ *
+ */
+
+ . = ALIGN ( _max_align );
+ .text : AT ( _text_lma ) {
+ _text = .;
+ *(.text)
+ *(.text.*)
+ _mtext = .;
+ } .text_bss (NOLOAD) : {
+ _etext = .;
+ }
+ _text_filesz = ABSOLUTE ( _mtext - _text );
+ _text_memsz = ABSOLUTE ( _etext - _text );
+
+ /*
+ * The rodata section
+ *
+ */
+
+ . = ALIGN ( _max_align );
+ .rodata : AT ( _rodata_lma ) {
+ _rodata = .;
+ *(.rodata)
+ *(.rodata.*)
+ _mrodata = .;
+ } .rodata_bss (NOLOAD) : {
+ _erodata = .;
+ }
+ _rodata_filesz = ABSOLUTE ( _mrodata - _rodata );
+ _rodata_memsz = ABSOLUTE ( _erodata - _rodata );
+
+ /*
+ * The data section
+ *
+ */
+
+ . = ALIGN ( _max_align );
+ .data : AT ( _data_lma ) {
+ _data = .;
+ *(.data)
+ *(.data.*)
+ *(SORT(.tbl.*)) /* Various tables. See include/tables.h */
+ /* EFI seems to not support proper bss sections */
+ *(.bss)
+ *(.bss.*)
+ *(COMMON)
+ *(.stack)
+ *(.stack.*)
+ _mdata = .;
+ } .data_bss (NOLOAD) : {
+ _edata = .;
+ }
+ _data_filesz = ABSOLUTE ( _mdata - _data );
+ _data_memsz = ABSOLUTE ( _edata - _data );
+
+ /*
+ * The bss section
+ *
+ */
+
+ . = ALIGN ( _max_align );
+ .bss : AT ( _bss_lma ) {
+ _bss = .;
+ /* EFI seems to not support proper bss sections */
+ _mbss = .;
+ } .bss_bss (NOLOAD) : {
+ _ebss = .;
+ }
+ _bss_filesz = ABSOLUTE ( _mbss - _bss );
+ _bss_memsz = ABSOLUTE ( _ebss - _bss );
+
+ /*
+ * The reloc section
+ *
+ */
+
+ . = ALIGN ( _max_align );
+ .reloc : AT ( _reloc_lma ) {
+ _reloc = .;
+ /* Provide some dummy contents to force ld to include this
+ * section. It will be created by the efilink utility.
+ */
+ . += 1;
+ _mreloc = .;
+ } .reloc_bss (NOLOAD) : {
+ _ereloc = .;
+ }
+ _reloc_filesz = ABSOLUTE ( _mreloc - _reloc );
+ _reloc_memsz = ABSOLUTE ( _ereloc - _reloc );
+
+ _filesz = ABSOLUTE ( . );
+
+ /*
+ * Weak symbols that need zero values if not otherwise defined
+ *
+ */
+
+ .weak 0x0 : {
+ _weak = .;
+ *(.weak)
+ _eweak = .;
+ }
+ _assert = ASSERT ( ( _weak == _eweak ), ".weak is non-zero length" );
+
+ /*
+ * Dispose of the comment and note sections to make the link map
+ * easier to read
+ *
+ */
+
+ /DISCARD/ : {
+ *(.comment)
+ *(.note)
+ }
+
+ /*
+ * Load address calculations.
+ *
+ */
+
+ _prefix_lma = ABSOLUTE ( _prefix );
+ _text_lma = ABSOLUTE ( _text );
+ _rodata_lma = ABSOLUTE ( _rodata );
+ _data_lma = ABSOLUTE ( _data );
+ _bss_lma = ABSOLUTE ( _bss );
+ _reloc_lma = ABSOLUTE ( _reloc );
+
+ /*
+ * Load addresses required by the prefix
+ *
+ */
+ efi_entry_lma = ABSOLUTE ( efi_entry );
+ debugdir_lma = ABSOLUTE ( debugdir );
+ codeview_rsds_lma = ABSOLUTE ( codeview_rsds );
+}
diff --git a/src/config/defaults/efi.h b/src/config/defaults/efi.h
new file mode 100644
index 00000000..d980136a
--- /dev/null
+++ b/src/config/defaults/efi.h
@@ -0,0 +1,20 @@
+#ifndef CONFIG_DEFAULTS_EFI_H
+#define CONFIG_DEFAULTS_EFI_H
+
+/** @file
+ *
+ * Configuration defaults for EFI
+ *
+ */
+
+#define UACCESS_EFI
+#define IOAPI_EFI
+#define PCIAPI_EFI
+#define CONSOLE_EFI
+#define TIMER_EFI
+#define NAP_EFIX86
+#define UMALLOC_EFI
+
+#define IMAGE_EFI /* EFI image support */
+
+#endif /* CONFIG_DEFAULTS_EFI_H */
diff --git a/src/config/general.h b/src/config/general.h
index d18c9cca..3d9663b9 100644
--- a/src/config/general.h
+++ b/src/config/general.h
@@ -70,6 +70,7 @@
//#define IMAGE_SCRIPT /* gPXE script image support */
//#define IMAGE_BZIMAGE /* Linux bzImage image support */
//#define IMAGE_COMBOOT /* SYSLINUX COMBOOT image support */
+//#define IMAGE_EFI /* EFI image support */
/*
* Command-line commands to include
diff --git a/src/core/config.c b/src/core/config.c
index ee16b9c1..b14d25a8 100644
--- a/src/core/config.c
+++ b/src/core/config.c
@@ -59,6 +59,9 @@ REQUIRE_OBJECT ( pc_kbd );
#ifdef CONSOLE_SYSLOG
REQUIRE_OBJECT ( syslog );
#endif
+#ifdef CONSOLE_EFI
+REQUIRE_OBJECT ( efi_console );
+#endif
/*
* Drag in all requested network protocols
@@ -158,6 +161,9 @@ REQUIRE_OBJECT ( com32_call );
REQUIRE_OBJECT ( com32_wrapper );
REQUIRE_OBJECT ( comboot_resolv );
#endif
+#ifdef IMAGE_EFI
+REQUIRE_OBJECT ( efi_image );
+#endif
/*
* Drag in all requested commands
diff --git a/src/image/efi_image.c b/src/image/efi_image.c
new file mode 100644
index 00000000..c80cd264
--- /dev/null
+++ b/src/image/efi_image.c
@@ -0,0 +1,106 @@
+/*
+ * Copyright (C) 2008 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., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#include <errno.h>
+#include <gpxe/efi/efi.h>
+#include <gpxe/image.h>
+#include <gpxe/features.h>
+
+FEATURE ( FEATURE_IMAGE, "EFI", DHCP_EB_FEATURE_EFI, 1 );
+
+struct image_type efi_image_type __image_type ( PROBE_NORMAL );
+
+/**
+ * Execute EFI image
+ *
+ * @v image EFI image
+ * @ret rc Return status code
+ */
+static int efi_image_exec ( struct image *image ) {
+ EFI_BOOT_SERVICES *bs = efi_systab->BootServices;
+ EFI_HANDLE handle;
+ UINTN exit_data_size;
+ CHAR16 *exit_data;
+ EFI_STATUS efirc;
+
+ /* Attempt loading image */
+ if ( ( efirc = bs->LoadImage ( FALSE, efi_image_handle, NULL,
+ user_to_virt ( image->data, 0 ),
+ image->len, &handle ) ) != 0 ) {
+ /* Not an EFI image */
+ DBGC ( image, "EFIIMAGE %p could not load: %lx\n",
+ image, efirc );
+ return -ENOEXEC;
+ }
+
+ /* Start the image */
+ if ( ( efirc = bs->StartImage ( handle, &exit_data_size,
+ &exit_data ) ) != 0 ) {
+ DBGC ( image, "EFIIMAGE %p returned with status %lx\n",
+ image, efirc );
+ goto done;
+ }
+
+ done:
+ /* Unload the image. We can't leave it loaded, because we
+ * have no "unload" operation.
+ */
+ bs->UnloadImage ( handle );
+
+ return EFIRC_TO_RC ( efirc );
+}
+
+/**
+ * Load EFI image into memory
+ *
+ * @v image EFI file
+ * @ret rc Return status code
+ */
+static int efi_image_load ( struct image *image ) {
+ EFI_BOOT_SERVICES *bs = efi_systab->BootServices;
+ EFI_HANDLE handle;
+ EFI_STATUS efirc;
+
+ /* Attempt loading image */
+ if ( ( efirc = bs->LoadImage ( FALSE, efi_image_handle, NULL,
+ user_to_virt ( image->data, 0 ),
+ image->len, &handle ) ) != 0 ) {
+ /* Not an EFI image */
+ DBGC ( image, "EFIIMAGE %p could not load: %lx\n",
+ image, efirc );
+ return -ENOEXEC;
+ }
+
+ /* This is an EFI image */
+ if ( ! image->type )
+ image->type = &efi_image_type;
+
+ /* Unload the image. We can't leave it loaded, because we
+ * have no "unload" operation.
+ */
+ bs->UnloadImage ( handle );
+
+ return 0;
+}
+
+/** EFI image type */
+struct image_type efi_image_type __image_type ( PROBE_NORMAL ) = {
+ .name = "EFI",
+ .load = efi_image_load,
+ .exec = efi_image_exec,
+};
diff --git a/src/include/gpxe/efi/IndustryStandard/PeImage.h b/src/include/gpxe/efi/IndustryStandard/PeImage.h
new file mode 100644
index 00000000..666d4ec3
--- /dev/null
+++ b/src/include/gpxe/efi/IndustryStandard/PeImage.h
@@ -0,0 +1,742 @@
+/** @file
+ EFI image format for PE32 and PE32+. Please note some data structures are
+ different for PE32 and PE32+. EFI_IMAGE_NT_HEADERS32 is for PE32 and
+ EFI_IMAGE_NT_HEADERS64 is for PE32+.
+
+ This file is coded to the Visual Studio, Microsoft Portable Executable and
+ Common Object File Format Specification, Revision 8.0 - May 16, 2006.
+
+ Copyright (c) 2006 - 2007, Intel Corporation
+ All rights reserved. This program and the accompanying materials
+ are licensed and made available under the terms and conditions of the BSD License
+ which accompanies this distribution. The full text of the license may be found at
+ http://opensource.org/licenses/bsd-license.php
+
+ THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+ WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+
+**/
+
+#ifndef __EFI_IMAGE_H__
+#define __EFI_IMAGE_H__
+
+//
+// PE32+ Subsystem type for EFI images
+//
+#define EFI_IMAGE_SUBSYSTEM_EFI_APPLICATION 10
+#define EFI_IMAGE_SUBSYSTEM_EFI_BOOT_SERVICE_DRIVER 11
+#define EFI_IMAGE_SUBSYSTEM_EFI_RUNTIME_DRIVER 12
+#define EFI_IMAGE_SUBSYSTEM_EFI_EFI_ROM 13
+
+#define EFI_IMAGE_SUBSYSTEM_SAL_RUNTIME_DRIVER 13
+
+
+//
+// PE32+ Machine type for EFI images
+//
+#define IMAGE_FILE_MACHINE_I386 0x014c
+#define IMAGE_FILE_MACHINE_IA64 0x0200
+#define IMAGE_FILE_MACHINE_EBC 0x0EBC
+#define IMAGE_FILE_MACHINE_X64 0x8664
+//
+// Support old names for backward compatible
+//
+#define EFI_IMAGE_MACHINE_IA32 IMAGE_FILE_MACHINE_I386
+#define EFI_IMAGE_MACHINE_IA64 IMAGE_FILE_MACHINE_IA64
+#define EFI_IMAGE_MACHINE_IPF IMAGE_FILE_MACHINE_IA64
+#define EFI_IMAGE_MACHINE_EBC IMAGE_FILE_MACHINE_EBC
+#define EFI_IMAGE_MACHINE_X64 IMAGE_FILE_MACHINE_X64
+
+#define EFI_IMAGE_DOS_SIGNATURE 0x5A4D // MZ
+#define EFI_IMAGE_OS2_SIGNATURE 0x454E // NE
+#define EFI_IMAGE_OS2_SIGNATURE_LE 0x454C // LE
+#define EFI_IMAGE_NT_SIGNATURE 0x00004550 // PE00
+
+///
+/// PE images can start with an optional DOS header, so if an image is run
+/// under DOS it can print an error message.
+///
+typedef struct {
+ UINT16 e_magic; // Magic number
+ UINT16 e_cblp; // Bytes on last page of file
+ UINT16 e_cp; // Pages in file
+ UINT16 e_crlc; // Relocations
+ UINT16 e_cparhdr; // Size of header in paragraphs
+ UINT16 e_minalloc; // Minimum extra paragraphs needed
+ UINT16 e_maxalloc; // Maximum extra paragraphs needed
+ UINT16 e_ss; // Initial (relative) SS value
+ UINT16 e_sp; // Initial SP value
+ UINT16 e_csum; // Checksum
+ UINT16 e_ip; // Initial IP value
+ UINT16 e_cs; // Initial (relative) CS value
+ UINT16 e_lfarlc; // File address of relocation table
+ UINT16 e_ovno; // Overlay number
+ UINT16 e_res[4]; // Reserved words
+ UINT16 e_oemid; // OEM identifier (for e_oeminfo)
+ UINT16 e_oeminfo; // OEM information; e_oemid specific
+ UINT16 e_res2[10]; // Reserved words
+ UINT32 e_lfanew; // File address of new exe header
+} EFI_IMAGE_DOS_HEADER;
+
+///
+/// File header format.
+///
+typedef struct {
+ UINT16 Machine;
+ UINT16 NumberOfSections;
+ UINT32 TimeDateStamp;
+ UINT32 PointerToSymbolTable;
+ UINT32 NumberOfSymbols;
+ UINT16 SizeOfOptionalHeader;
+ UINT16 Characteristics;
+} EFI_IMAGE_FILE_HEADER;
+
+#define EFI_IMAGE_SIZEOF_FILE_HEADER 20
+
+#define EFI_IMAGE_FILE_RELOCS_STRIPPED 0x0001 // Relocation info stripped from file.
+#define EFI_IMAGE_FILE_EXECUTABLE_IMAGE 0x0002 // File is executable (i.e. no unresolved externel references).
+#define EFI_IMAGE_FILE_LINE_NUMS_STRIPPED 0x0004 // Line nunbers stripped from file.
+#define EFI_IMAGE_FILE_LOCAL_SYMS_STRIPPED 0x0008 // Local symbols stripped from file.
+#define EFI_IMAGE_FILE_BYTES_REVERSED_LO 0x0080 // Bytes of machine word are reversed.
+#define EFI_IMAGE_FILE_32BIT_MACHINE 0x0100 // 32 bit word machine.
+#define EFI_IMAGE_FILE_DEBUG_STRIPPED 0x0200 // Debugging info stripped from file in .DBG file
+#define EFI_IMAGE_FILE_SYSTEM 0x1000 // System File.
+#define EFI_IMAGE_FILE_DLL 0x2000 // File is a DLL.
+#define EFI_IMAGE_FILE_BYTES_REVERSED_HI 0x8000 // Bytes of machine word are reversed.
+#define EFI_IMAGE_FILE_MACHINE_UNKNOWN 0
+#define EFI_IMAGE_FILE_MACHINE_I386 0x14c // Intel 386.
+#define EFI_IMAGE_FILE_MACHINE_R3000 0x162 // MIPS* little-endian, 0540 big-endian
+#define EFI_IMAGE_FILE_MACHINE_R4000 0x166 // MIPS* little-endian
+#define EFI_IMAGE_FILE_MACHINE_ALPHA 0x184 // Alpha_AXP*
+#define EFI_IMAGE_FILE_MACHINE_POWERPC 0x1F0 // IBM* PowerPC Little-Endian
+#define EFI_IMAGE_FILE_MACHINE_TAHOE 0x7cc // Intel EM machine
+//
+// * Other names and brands may be claimed as the property of others.
+//
+
+///
+/// Directory format.
+///
+typedef struct {
+ UINT32 VirtualAddress;
+ UINT32 Size;
+} EFI_IMAGE_DATA_DIRECTORY;
+
+#define EFI_IMAGE_NUMBER_OF_DIRECTORY_ENTRIES 16
+
+typedef struct {
+ UINT16 Magic;
+ UINT8 MajorLinkerVersion;
+ UINT8 MinorLinkerVersion;
+ UINT32 SizeOfCode;
+ UINT32 SizeOfInitializedData;
+ UINT32 SizeOfUninitializedData;
+ UINT32 AddressOfEntryPoint;
+ UINT32 BaseOfCode;
+ UINT32 BaseOfData;
+ UINT32 BaseOfBss;
+ UINT32 GprMask;
+ UINT32 CprMask[4];
+ UINT32 GpValue;
+} EFI_IMAGE_ROM_OPTIONAL_HEADER;
+
+#define EFI_IMAGE_ROM_OPTIONAL_HDR_MAGIC 0x107
+#define EFI_IMAGE_SIZEOF_ROM_OPTIONAL_HEADER sizeof (EFI_IMAGE_ROM_OPTIONAL_HEADER)
+
+typedef struct {
+ EFI_IMAGE_FILE_HEADER FileHeader;
+ EFI_IMAGE_ROM_OPTIONAL_HEADER OptionalHeader;
+} EFI_IMAGE_ROM_HEADERS;
+
+///
+/// @attention
+/// EFI_IMAGE_NT_OPTIONAL_HDR32_MAGIC means PE32 and
+/// EFI_IMAGE_OPTIONAL_HEADER32 must be used. The data structures only vary
+/// after NT additional fields.
+///
+#define EFI_IMAGE_NT_OPTIONAL_HDR32_MAGIC 0x10b
+
+typedef struct {
+ ///
+ /// Standard fields.
+ ///
+ UINT16 Magic;
+ UINT8 MajorLinkerVersion;
+ UINT8 MinorLinkerVersion;
+ UINT32 SizeOfCode;
+ UINT32 SizeOfInitializedData;
+ UINT32 SizeOfUninitializedData;
+ UINT32 AddressOfEntryPoint;
+ UINT32 BaseOfCode;
+ UINT32 BaseOfData;
+ ///
+ /// NT additional fields.
+ ///
+ UINT32 ImageBase;
+ UINT32 SectionAlignment;
+ UINT32 FileAlignment;
+ UINT16 MajorOperatingSystemVersion;
+ UINT16 MinorOperatingSystemVersion;
+ UINT16 MajorImageVersion;
+ UINT16 MinorImageVersion;
+ UINT16 MajorSubsystemVersion;
+ UINT16 MinorSubsystemVersion;
+ UINT32 Win32VersionValue;
+ UINT32 SizeOfImage;
+ UINT32 SizeOfHeaders;
+ UINT32 CheckSum;
+ UINT16 Subsystem;
+ UINT16 DllCharacteristics;
+ UINT32 SizeOfStackReserve;
+ UINT32 SizeOfStackCommit;
+ UINT32 SizeOfHeapReserve;
+ UINT32 SizeOfHeapCommit;
+ UINT32 LoaderFlags;
+ UINT32 NumberOfRvaAndSizes;
+ EFI_IMAGE_DATA_DIRECTORY DataDirectory[EFI_IMAGE_NUMBER_OF_DIRECTORY_ENTRIES];
+} EFI_IMAGE_OPTIONAL_HEADER32;
+
+///
+/// @attention
+/// EFI_IMAGE_NT_OPTIONAL_HDR64_MAGIC means PE32+ and
+/// EFI_IMAGE_OPTIONAL_HEADER64 must be used. The data structures only vary
+/// after NT additional fields.
+///
+#define EFI_IMAGE_NT_OPTIONAL_HDR64_MAGIC 0x20b
+
+typedef struct {
+ //
+ // Standard fields.
+ //
+ UINT16 Magic;
+ UINT8 MajorLinkerVersion;
+ UINT8 MinorLinkerVersion;
+ UINT32 SizeOfCode;
+ UINT32 SizeOfInitializedData;
+ UINT32 SizeOfUninitializedData;
+ UINT32 AddressOfEntryPoint;
+ UINT32 BaseOfCode;
+ //
+ // NT additional fields.
+ //
+ UINT64 ImageBase;
+ UINT32 SectionAlignment;
+ UINT32 FileAlignment;
+ UINT16 MajorOperatingSystemVersion;
+ UINT16 MinorOperatingSystemVersion;
+ UINT16 MajorImageVersion;
+ UINT16 MinorImageVersion;
+ UINT16 MajorSubsystemVersion;
+ UINT16 MinorSubsystemVersion;
+ UINT32 Win32VersionValue;
+ UINT32 SizeOfImage;
+ UINT32 SizeOfHeaders;
+ UINT32 CheckSum;
+ UINT16 Subsystem;
+ UINT16 DllCharacteristics;
+ UINT64 SizeOfStackReserve;
+ UINT64 SizeOfStackCommit;
+ UINT64 SizeOfHeapReserve;
+ UINT64 SizeOfHeapCommit;
+ UINT32 LoaderFlags;
+ UINT32 NumberOfRvaAndSizes;
+ EFI_IMAGE_DATA_DIRECTORY DataDirectory[EFI_IMAGE_NUMBER_OF_DIRECTORY_ENTRIES];
+} EFI_IMAGE_OPTIONAL_HEADER64;
+
+
+///
+/// @attention
+/// EFI_IMAGE_NT_HEADERS32 and EFI_IMAGE_HEADERS64 are for use ONLY
+/// by tools. All proper EFI code MUST use EFI_IMAGE_NT_HEADERS ONLY!!!
+///
+typedef struct {
+ UINT32 Signature;
+ EFI_IMAGE_FILE_HEADER FileHeader;
+ EFI_IMAGE_OPTIONAL_HEADER32 OptionalHeader;
+} EFI_IMAGE_NT_HEADERS32;
+
+#define EFI_IMAGE_SIZEOF_NT_OPTIONAL32_HEADER sizeof (EFI_IMAGE_NT_HEADERS32)
+
+typedef struct {
+ UINT32 Signature;
+ EFI_IMAGE_FILE_HEADER FileHeader;
+ EFI_IMAGE_OPTIONAL_HEADER64 OptionalHeader;
+} EFI_IMAGE_NT_HEADERS64;
+
+#define EFI_IMAGE_SIZEOF_NT_OPTIONAL64_HEADER sizeof (EFI_IMAGE_NT_HEADERS64)
+
+
+//
+// Processor specific definition of EFI_IMAGE_OPTIONAL_HEADER so the
+// type name EFI_IMAGE_OPTIONAL_HEADER is appropriate to the build. Same for
+// EFI_IMAGE_NT_HEADERS. These definitions MUST be used by ALL EFI code.
+//
+#if defined (MDE_CPU_IA32)
+
+#define EFI_IMAGE_MACHINE_TYPE_SUPPORTED(Machine) \
+ (((Machine) == EFI_IMAGE_MACHINE_IA32) || ((Machine) == EFI_IMAGE_MACHINE_EBC))
+
+#define EFI_IMAGE_MACHINE_CROSS_TYPE_SUPPORTED(Machine) ((Machine) == EFI_IMAGE_MACHINE_X64)
+
+//
+// @bug - Remove me when other package updated.
+//
+typedef EFI_IMAGE_NT_HEADERS32 EFI_IMAGE_NT_HEADERS;
+
+#elif defined (MDE_CPU_IPF)
+
+#define EFI_IMAGE_MACHINE_TYPE_SUPPORTED(Machine) \
+ (((Machine) == EFI_IMAGE_MACHINE_IPF) || ((Machine) == EFI_IMAGE_MACHINE_EBC))
+
+#define EFI_IMAGE_MACHINE_CROSS_TYPE_SUPPORTED(Machine) (FALSE)
+
+//
+// @bug - Remove me when other package updated.
+//
+typedef EFI_IMAGE_NT_HEADERS64 EFI_IMAGE_NT_HEADERS;
+
+#elif defined (MDE_CPU_X64)
+
+#define EFI_IMAGE_MACHINE_TYPE_SUPPORTED(Machine) \
+ (((Machine) == EFI_IMAGE_MACHINE_X64) || ((Machine) == EFI_IMAGE_MACHINE_EBC))
+
+#define EFI_IMAGE_MACHINE_CROSS_TYPE_SUPPORTED(Machine) ((Machine) == EFI_IMAGE_MACHINE_IA32)
+
+//
+// @bug - Remove me when other package updated.
+//
+typedef EFI_IMAGE_NT_HEADERS64 EFI_IMAGE_NT_HEADERS;
+
+#elif defined (MDE_CPU_EBC)
+
+///
+/// This is just to make sure you can cross compile with the EBC compiiler.
+/// It does not make sense to have a PE loader coded in EBC. You need to
+/// understand the basic
+///
+#define EFI_IMAGE_MACHINE_TYPE_SUPPORTED(Machine) ((Machine) == EFI_IMAGE_MACHINE_EBC)
+
+#define EFI_IMAGE_MACHINE_CROSS_TYPE_SUPPORTED(Machine) (FALSE)
+
+//
+// @bug - Remove me when other package updated.
+//
+typedef EFI_IMAGE_NT_HEADERS64 EFI_IMAGE_NT_HEADERS;
+
+#else
+#error Unknown Processor Type
+#endif
+
+
+#define EFI_IMAGE_FIRST_SECTION(ntheader) \
+ ( \
+ (EFI_IMAGE_SECTION_HEADER *) \
+ ( \
+ (UINT32) ntheader + \
+ FIELD_OFFSET (EFI_IMAGE_NT_HEADERS, OptionalHeader) + \
+ ((EFI_IMAGE_NT_HEADERS *) (ntheader))->FileHeader.SizeOfOptionalHeader \
+ ) \
+ )
+
+//
+// Subsystem Values
+//
+#define EFI_IMAGE_SUBSYSTEM_UNKNOWN 0
+#define EFI_IMAGE_SUBSYSTEM_NATIVE 1
+#define EFI_IMAGE_SUBSYSTEM_WINDOWS_GUI 2
+#define EFI_IMAGE_SUBSYSTEM_WINDOWS_CUI 3.
+#define EFI_IMAGE_SUBSYSTEM_OS2_CUI 5
+#define EFI_IMAGE_SUBSYSTEM_POSIX_CUI 7
+
+//
+// Directory Entries
+//
+#define EFI_IMAGE_DIRECTORY_ENTRY_EXPORT 0
+#define EFI_IMAGE_DIRECTORY_ENTRY_IMPORT 1
+#define EFI_IMAGE_DIRECTORY_ENTRY_RESOURCE 2
+#define EFI_IMAGE_DIRECTORY_ENTRY_EXCEPTION 3
+#define EFI_IMAGE_DIRECTORY_ENTRY_SECURITY 4
+#define EFI_IMAGE_DIRECTORY_ENTRY_BASERELOC 5
+#define EFI_IMAGE_DIRECTORY_ENTRY_DEBUG 6
+#define EFI_IMAGE_DIRECTORY_ENTRY_COPYRIGHT 7
+#define EFI_IMAGE_DIRECTORY_ENTRY_GLOBALPTR 8
+#define EFI_IMAGE_DIRECTORY_ENTRY_TLS 9
+#define EFI_IMAGE_DIRECTORY_ENTRY_LOAD_CONFIG 10
+
+//
+// Section header format.
+//
+#define EFI_IMAGE_SIZEOF_SHORT_NAME 8
+
+typedef struct {
+ UINT8 Name[EFI_IMAGE_SIZEOF_SHORT_NAME];
+ union {
+ UINT32 PhysicalAddress;
+ UINT32 VirtualSize;
+ } Misc;
+ UINT32 VirtualAddress;
+ UINT32 SizeOfRawData;
+ UINT32 PointerToRawData;
+ UINT32 PointerToRelocations;
+ UINT32 PointerToLinenumbers;
+ UINT16 NumberOfRelocations;
+ UINT16 NumberOfLinenumbers;
+ UINT32 Characteristics;
+} EFI_IMAGE_SECTION_HEADER;
+
+#define EFI_IMAGE_SIZEOF_SECTION_HEADER 40
+
+#define EFI_IMAGE_SCN_TYPE_NO_PAD 0x00000008 // Reserved.
+#define EFI_IMAGE_SCN_CNT_CODE 0x00000020
+#define EFI_IMAGE_SCN_CNT_INITIALIZED_DATA 0x00000040
+#define EFI_IMAGE_SCN_CNT_UNINITIALIZED_DATA 0x00000080
+
+#define EFI_IMAGE_SCN_LNK_OTHER 0x00000100 // Reserved.
+#define EFI_IMAGE_SCN_LNK_INFO 0x00000200 // Section contains comments or some other type of information.
+#define EFI_IMAGE_SCN_LNK_REMOVE 0x00000800 // Section contents will not become part of image.
+#define EFI_IMAGE_SCN_LNK_COMDAT 0x00001000
+
+#define EFI_IMAGE_SCN_ALIGN_1BYTES 0x00100000
+#define EFI_IMAGE_SCN_ALIGN_2BYTES 0x00200000
+#define EFI_IMAGE_SCN_ALIGN_4BYTES 0x00300000
+#define EFI_IMAGE_SCN_ALIGN_8BYTES 0x00400000
+#define EFI_IMAGE_SCN_ALIGN_16BYTES 0x00500000
+#define EFI_IMAGE_SCN_ALIGN_32BYTES 0x00600000
+#define EFI_IMAGE_SCN_ALIGN_64BYTES 0x00700000
+
+#define EFI_IMAGE_SCN_MEM_DISCARDABLE 0x02000000
+#define EFI_IMAGE_SCN_MEM_NOT_CACHED 0x04000000
+#define EFI_IMAGE_SCN_MEM_NOT_PAGED 0x08000000
+#define EFI_IMAGE_SCN_MEM_SHARED 0x10000000
+#define EFI_IMAGE_SCN_MEM_EXECUTE 0x20000000
+#define EFI_IMAGE_SCN_MEM_READ 0x40000000
+#define EFI_IMAGE_SCN_MEM_WRITE 0x80000000
+
+///
+/// Symbol format.
+///
+#define EFI_IMAGE_SIZEOF_SYMBOL 18
+
+//
+// Section values.
+//
+// Symbols have a section number of the section in which they are
+// defined. Otherwise, section numbers have the following meanings:
+//
+#define EFI_IMAGE_SYM_UNDEFINED (UINT16) 0 // Symbol is undefined or is common.
+#define EFI_IMAGE_SYM_ABSOLUTE (UINT16) -1 // Symbol is an absolute value.
+#define EFI_IMAGE_SYM_DEBUG (UINT16) -2 // Symbol is a special debug item.
+//
+// Type (fundamental) values.
+//
+#define EFI_IMAGE_SYM_TYPE_NULL 0 // no type.
+#define EFI_IMAGE_SYM_TYPE_VOID 1 //
+#define EFI_IMAGE_SYM_TYPE_CHAR 2 // type character.
+#define EFI_IMAGE_SYM_TYPE_SHORT 3 // type short integer.
+#define EFI_IMAGE_SYM_TYPE_INT 4
+#define EFI_IMAGE_SYM_TYPE_LONG 5
+#define EFI_IMAGE_SYM_TYPE_FLOAT 6
+#define EFI_IMAGE_SYM_TYPE_DOUBLE 7
+#define EFI_IMAGE_SYM_TYPE_STRUCT 8
+#define EFI_IMAGE_SYM_TYPE_UNION 9
+#define EFI_IMAGE_SYM_TYPE_ENUM 10 // enumeration.
+#define EFI_IMAGE_SYM_TYPE_MOE 11 // member of enumeration.
+#define EFI_IMAGE_SYM_TYPE_BYTE 12
+#define EFI_IMAGE_SYM_TYPE_WORD 13
+#define EFI_IMAGE_SYM_TYPE_UINT 14
+#define EFI_IMAGE_SYM_TYPE_DWORD 15
+
+//
+// Type (derived) values.
+//
+#define EFI_IMAGE_SYM_DTYPE_NULL 0 // no derived type.
+#define EFI_IMAGE_SYM_DTYPE_POINTER 1
+#define EFI_IMAGE_SYM_DTYPE_FUNCTION 2
+#define EFI_IMAGE_SYM_DTYPE_ARRAY 3
+
+//
+// Storage classes.
+//
+#define EFI_IMAGE_SYM_CLASS_END_OF_FUNCTION (UINT8) -1
+#define EFI_IMAGE_SYM_CLASS_NULL 0
+#define EFI_IMAGE_SYM_CLASS_AUTOMATIC 1
+#define EFI_IMAGE_SYM_CLASS_EXTERNAL 2
+#define EFI_IMAGE_SYM_CLASS_STATIC 3
+#define EFI_IMAGE_SYM_CLASS_REGISTER 4
+#define EFI_IMAGE_SYM_CLASS_EXTERNAL_DEF 5
+#define EFI_IMAGE_SYM_CLASS_LABEL 6
+#define EFI_IMAGE_SYM_CLASS_UNDEFINED_LABEL 7
+#define EFI_IMAGE_SYM_CLASS_MEMBER_OF_STRUCT 8
+#define EFI_IMAGE_SYM_CLASS_ARGUMENT 9
+#define EFI_IMAGE_SYM_CLASS_STRUCT_TAG 10
+#define EFI_IMAGE_SYM_CLASS_MEMBER_OF_UNION 11
+#define EFI_IMAGE_SYM_CLASS_UNION_TAG 12
+#define EFI_IMAGE_SYM_CLASS_TYPE_DEFINITION 13
+#define EFI_IMAGE_SYM_CLASS_UNDEFINED_STATIC 14
+#define EFI_IMAGE_SYM_CLASS_ENUM_TAG 15
+#define EFI_IMAGE_SYM_CLASS_MEMBER_OF_ENUM 16
+#define EFI_IMAGE_SYM_CLASS_REGISTER_PARAM 17
+#define EFI_IMAGE_SYM_CLASS_BIT_FIELD 18
+#define EFI_IMAGE_SYM_CLASS_BLOCK 100
+#define EFI_IMAGE_SYM_CLASS_FUNCTION 101
+#define EFI_IMAGE_SYM_CLASS_END_OF_STRUCT 102
+#define EFI_IMAGE_SYM_CLASS_FILE 103
+#define EFI_IMAGE_SYM_CLASS_SECTION 104
+#define EFI_IMAGE_SYM_CLASS_WEAK_EXTERNAL 105
+
+//
+// type packing constants
+//
+#define EFI_IMAGE_N_BTMASK 017
+#define EFI_IMAGE_N_TMASK 060
+#define EFI_IMAGE_N_TMASK1 0300
+#define EFI_IMAGE_N_TMASK2 0360
+#define EFI_IMAGE_N_BTSHFT 4
+#define EFI_IMAGE_N_TSHIFT 2
+
+//
+// Communal selection types.
+//
+#define EFI_IMAGE_COMDAT_SELECT_NODUPLICATES 1
+#define EFI_IMAGE_COMDAT_SELECT_ANY 2
+#define EFI_IMAGE_COMDAT_SELECT_SAME_SIZE 3
+#define EFI_IMAGE_COMDAT_SELECT_EXACT_MATCH 4
+#define EFI_IMAGE_COMDAT_SELECT_ASSOCIATIVE 5
+
+#define EFI_IMAGE_WEAK_EXTERN_SEARCH_NOLIBRARY 1
+#define EFI_IMAGE_WEAK_EXTERN_SEARCH_LIBRARY 2
+#define EFI_IMAGE_WEAK_EXTERN_SEARCH_ALIAS 3
+
+///
+/// Relocation format.
+///
+typedef struct {
+ UINT32 VirtualAddress;
+ UINT32 SymbolTableIndex;
+ UINT16 Type;
+} EFI_IMAGE_RELOCATION;
+
+#define EFI_IMAGE_SIZEOF_RELOCATION 10
+
+//
+// I386 relocation types.
+//
+#define EFI_IMAGE_REL_I386_ABSOLUTE 0x0000 // Reference is absolute, no relocation is necessary
+#define EFI_IMAGE_REL_I386_DIR16 0x0001 // Direct 16-bit reference to the symbols virtual address
+#define EFI_IMAGE_REL_I386_REL16 0x0002 // PC-relative 16-bit reference to the symbols virtual address
+#define EFI_IMAGE_REL_I386_DIR32 0x0006 // Direct 32-bit reference to the symbols virtual address
+#define EFI_IMAGE_REL_I386_DIR32NB 0x0007 // Direct 32-bit reference to the symbols virtual address, base not included
+#define EFI_IMAGE_REL_I386_SEG12 0x0009 // Direct 16-bit reference to the segment-selector bits of a 32-bit virtual address
+#define EFI_IMAGE_REL_I386_SECTION 0x001a
+#define EFI_IMAGE_REL_I386_SECREL 0x000b
+#define EFI_IMAGE_REL_I386_REL32 0x0014 // PC-relative 32-bit reference to the symbols virtual address
+
+//
+// x64 processor relocation types.
+//
+#define IMAGE_REL_AMD64_ABSOLUTE 0x0000
+#define IMAGE_REL_AMD64_ADDR64 0x0001
+#define IMAGE_REL_AMD64_ADDR32 0x0002
+#define IMAGE_REL_AMD64_ADDR32NB 0x0003
+#define IMAGE_REL_AMD64_REL32 0x0004
+#define IMAGE_REL_AMD64_REL32_1 0x0005
+#define IMAGE_REL_AMD64_REL32_2 0x0006
+#define IMAGE_REL_AMD64_REL32_3 0x0007
+#define IMAGE_REL_AMD64_REL32_4 0x0008
+#define IMAGE_REL_AMD64_REL32_5 0x0009
+#define IMAGE_REL_AMD64_SECTION 0x000A
+#define IMAGE_REL_AMD64_SECREL 0x000B
+#define IMAGE_REL_AMD64_SECREL7 0x000C
+#define IMAGE_REL_AMD64_TOKEN 0x000D
+#define IMAGE_REL_AMD64_SREL32 0x000E
+#define IMAGE_REL_AMD64_PAIR 0x000F
+#define IMAGE_REL_AMD64_SSPAN32 0x0010
+
+///
+/// Based relocation format.
+///
+typedef struct {
+ UINT32 VirtualAddress;
+ UINT32 SizeOfBlock;
+} EFI_IMAGE_BASE_RELOCATION;
+
+#define EFI_IMAGE_SIZEOF_BASE_RELOCATION 8
+
+//
+// Based relocation types.
+//
+#define EFI_IMAGE_REL_BASED_ABSOLUTE 0
+#define EFI_IMAGE_REL_BASED_HIGH 1
+#define EFI_IMAGE_REL_BASED_LOW 2
+#define EFI_IMAGE_REL_BASED_HIGHLOW 3
+#define EFI_IMAGE_REL_BASED_HIGHADJ 4
+#define EFI_IMAGE_REL_BASED_MIPS_JMPADDR 5
+#define EFI_IMAGE_REL_BASED_IA64_IMM64 9
+#define EFI_IMAGE_REL_BASED_DIR64 10
+
+///
+/// Line number format.
+///
+typedef struct {
+ union {
+ UINT32 SymbolTableIndex; // Symbol table index of function name if Linenumber is 0.
+ UINT32 VirtualAddress; // Virtual address of line number.
+ } Type;
+ UINT16 Linenumber; // Line number.
+} EFI_IMAGE_LINENUMBER;
+
+#define EFI_IMAGE_SIZEOF_LINENUMBER 6
+
+//
+// Archive format.
+//
+#define EFI_IMAGE_ARCHIVE_START_SIZE 8
+#define EFI_IMAGE_ARCHIVE_START "!<arch>\n"
+#define EFI_IMAGE_ARCHIVE_END "`\n"
+#define EFI_IMAGE_ARCHIVE_PAD "\n"
+#define EFI_IMAGE_ARCHIVE_LINKER_MEMBER "/ "
+#define EFI_IMAGE_ARCHIVE_LONGNAMES_MEMBER "// "
+
+typedef struct {
+ UINT8 Name[16]; // File member name - `/' terminated.
+ UINT8 Date[12]; // File member date - decimal.
+ UINT8 UserID[6]; // File member user id - decimal.
+ UINT8 GroupID[6]; // File member group id - decimal.
+ UINT8 Mode[8]; // File member mode - octal.
+ UINT8 Size[10]; // File member size - decimal.
+ UINT8 EndHeader[2]; // String to end header.
+} EFI_IMAGE_ARCHIVE_MEMBER_HEADER;
+
+#define EFI_IMAGE_SIZEOF_ARCHIVE_MEMBER_HDR 60
+
+//
+// DLL support.
+//
+
+///
+/// DLL Export Format
+///
+typedef struct {
+ UINT32 Characteristics;
+ UINT32 TimeDateStamp;
+ UINT16 MajorVersion;
+ UINT16 MinorVersion;
+ UINT32 Name;
+ UINT32 Base;
+ UINT32 NumberOfFunctions;
+ UINT32 NumberOfNames;
+ UINT32 AddressOfFunctions;
+ UINT32 AddressOfNames;
+ UINT32 AddressOfNameOrdinals;
+} EFI_IMAGE_EXPORT_DIRECTORY;
+
+///
+/// DLL support.
+/// Import Format
+///
+typedef struct {
+ UINT16 Hint;
+ UINT8 Name[1];
+} EFI_IMAGE_IMPORT_BY_NAME;
+
+typedef struct {
+ union {
+ UINT32 Function;
+ UINT32 Ordinal;
+ EFI_IMAGE_IMPORT_BY_NAME *AddressOfData;
+ } u1;
+} EFI_IMAGE_THUNK_DATA;
+
+#define EFI_IMAGE_ORDINAL_FLAG 0x80000000
+#define EFI_IMAGE_SNAP_BY_ORDINAL(Ordinal) ((Ordinal & EFI_IMAGE_ORDINAL_FLAG) != 0)
+#define EFI_IMAGE_ORDINAL(Ordinal) (Ordinal & 0xffff)
+
+typedef struct {
+ UINT32 Characteristics;
+ UINT32 TimeDateStamp;
+ UINT32 ForwarderChain;
+ UINT32 Name;
+ EFI_IMAGE_THUNK_DATA *FirstThunk;
+} EFI_IMAGE_IMPORT_DESCRIPTOR;
+
+///
+/// Debug Format
+///
+#define EFI_IMAGE_DEBUG_TYPE_CODEVIEW 2
+
+typedef struct {
+ UINT32 Characteristics;
+ UINT32 TimeDateStamp;
+ UINT16 MajorVersion;
+ UINT16 MinorVersion;
+ UINT32 Type;
+ UINT32 SizeOfData;
+ UINT32 RVA;
+ UINT32 FileOffset;
+} EFI_IMAGE_DEBUG_DIRECTORY_ENTRY;
+
+#define CODEVIEW_SIGNATURE_NB10 0x3031424E // "NB10"
+typedef struct {
+ UINT32 Signature; // "NB10"
+ UINT32 Unknown;
+ UINT32 Unknown2;
+ UINT32 Unknown3;
+ //
+ // Filename of .PDB goes here
+ //
+} EFI_IMAGE_DEBUG_CODEVIEW_NB10_ENTRY;
+
+#define CODEVIEW_SIGNATURE_RSDS 0x53445352 // "RSDS"
+typedef struct {
+ UINT32 Signature; // "RSDS"
+ UINT32 Unknown;
+ UINT32 Unknown2;
+ UINT32 Unknown3;
+ UINT32 Unknown4;
+ UINT32 Unknown5;
+ //
+ // Filename of .PDB goes here
+ //
+} EFI_IMAGE_DEBUG_CODEVIEW_RSDS_ENTRY;
+
+///
+/// Header format for TE images
+///
+typedef struct {
+ UINT16 Signature; // signature for TE format = "VZ"
+ UINT16 Machine; // from the original file header
+ UINT8 NumberOfSections; // from the original file header
+ UINT8 Subsystem; // from original optional header
+ UINT16 StrippedSize; // how many bytes we removed from the header
+ UINT32 AddressOfEntryPoint; // offset to entry point -- from original optional header
+ UINT32 BaseOfCode; // from original image -- required for ITP debug
+ UINT64 ImageBase; // from original file header
+ EFI_IMAGE_DATA_DIRECTORY DataDirectory[2]; // only base relocation and debug directory
+} EFI_TE_IMAGE_HEADER;
+
+#define EFI_TE_IMAGE_HEADER_SIGNATURE 0x5A56 // "VZ"
+
+//
+// Data directory indexes in our TE image header
+//
+#define EFI_TE_IMAGE_DIRECTORY_ENTRY_BASERELOC 0
+#define EFI_TE_IMAGE_DIRECTORY_ENTRY_DEBUG 1
+
+
+///
+/// Union of PE32, PE32+, and TE headers
+///
+typedef union {
+ EFI_IMAGE_NT_HEADERS32 Pe32;
+ EFI_IMAGE_NT_HEADERS64 Pe32Plus;
+ EFI_TE_IMAGE_HEADER Te;
+} EFI_IMAGE_OPTIONAL_HEADER_UNION;
+
+typedef union {
+ EFI_IMAGE_NT_HEADERS32 *Pe32;
+ EFI_IMAGE_NT_HEADERS64 *Pe32Plus;
+ EFI_TE_IMAGE_HEADER *Te;
+ EFI_IMAGE_OPTIONAL_HEADER_UNION *Union;
+} EFI_IMAGE_OPTIONAL_HEADER_PTR_UNION;
+
+#endif
diff --git a/src/include/gpxe/efi/Protocol/Cpu.h b/src/include/gpxe/efi/Protocol/Cpu.h
new file mode 100644
index 00000000..6052a34f
--- /dev/null
+++ b/src/include/gpxe/efi/Protocol/Cpu.h
@@ -0,0 +1,326 @@
+/** @file
+ CPU Architectural Protocol as defined in PI spec Volume 2 DXE
+
+ This code abstracts the DXE core from processor implementation details.
+
+ Copyright (c) 2006 - 2008, Intel Corporation
+ All rights reserved. This program and the accompanying materials
+ are licensed and made available under the terms and conditions of the BSD License
+ which accompanies this distribution. The full text of the license may be found at
+ http://opensource.org/licenses/bsd-license.php
+
+ THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+ WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+
+**/
+
+#ifndef __ARCH_PROTOCOL_CPU_H__
+#define __ARCH_PROTOCOL_CPU_H__
+
+#include <gpxe/efi/Protocol/DebugSupport.h>
+
+#define EFI_CPU_ARCH_PROTOCOL_GUID \
+ { 0x26baccb1, 0x6f42, 0x11d4, {0xbc, 0xe7, 0x0, 0x80, 0xc7, 0x3c, 0x88, 0x81 } }
+
+typedef struct _EFI_CPU_ARCH_PROTOCOL EFI_CPU_ARCH_PROTOCOL;
+
+typedef enum {
+ EfiCpuFlushTypeWriteBackInvalidate,
+ EfiCpuFlushTypeWriteBack,
+ EfiCpuFlushTypeInvalidate,
+ EfiCpuMaxFlushType
+} EFI_CPU_FLUSH_TYPE;
+
+typedef enum {
+ EfiCpuInit,
+ EfiCpuMaxInitType
+} EFI_CPU_INIT_TYPE;
+
+/**
+ EFI_CPU_INTERRUPT_HANDLER that is called when a processor interrupt occurs.
+
+ @param InterruptType Defines the type of interrupt or exception that
+ occurred on the processor.This parameter is processor architecture specific.
+ @param SystemContext A pointer to the processor context when
+ the interrupt occurred on the processor.
+
+ @return None
+
+**/
+typedef
+VOID
+(EFIAPI *EFI_CPU_INTERRUPT_HANDLER)(
+ IN CONST EFI_EXCEPTION_TYPE InterruptType,
+ IN CONST EFI_SYSTEM_CONTEXT SystemContext
+ );
+
+/**
+ This function flushes the range of addresses from Start to Start+Length
+ from the processor's data cache. If Start is not aligned to a cache line
+ boundary, then the bytes before Start to the preceding cache line boundary
+ are also flushed. If Start+Length is not aligned to a cache line boundary,
+ then the bytes past Start+Length to the end of the next cache line boundary
+ are also flushed. The FlushType of EfiCpuFlushTypeWriteBackInvalidate must be
+ supported. If the data cache is fully coherent with all DMA operations, then
+ this function can just return EFI_SUCCESS. If the processor does not support
+ flushing a range of the data cache, then the entire data cache can be flushed.
+
+ @param This The EFI_CPU_ARCH_PROTOCOL instance.
+ @param Start The beginning physical address to flush from the processor's data
+ cache.
+ @param Length The number of bytes to flush from the processor's data cache. This
+ function may flush more bytes than Length specifies depending upon
+ the granularity of the flush operation that the processor supports.
+ @param FlushType Specifies the type of flush operation to perform.
+
+ @retval EFI_SUCCESS The address range from Start to Start+Length was flushed from
+ the processor's data cache.
+ @retval EFI_UNSUPPORTEDT The processor does not support the cache flush type specified
+ by FlushType.
+ @retval EFI_DEVICE_ERROR The address range from Start to Start+Length could not be flushed
+ from the processor's data cache.
+
+**/
+typedef
+EFI_STATUS
+(EFIAPI *EFI_CPU_FLUSH_DATA_CACHE)(
+ IN EFI_CPU_ARCH_PROTOCOL *This,
+ IN EFI_PHYSICAL_ADDRESS Start,
+ IN UINT64 Length,
+ IN EFI_CPU_FLUSH_TYPE FlushType
+ );
+
+
+/**
+ This function enables interrupt processing by the processor.
+
+ @param This The EFI_CPU_ARCH_PROTOCOL instance.
+
+ @retval EFI_SUCCESS Interrupts are enabled on the processor.
+ @retval EFI_DEVICE_ERROR Interrupts could not be enabled on the processor.
+
+**/
+typedef
+EFI_STATUS
+(EFIAPI *EFI_CPU_ENABLE_INTERRUPT)(
+ IN EFI_CPU_ARCH_PROTOCOL *This
+ );
+
+
+/**
+ This function disables interrupt processing by the processor.
+
+ @param This The EFI_CPU_ARCH_PROTOCOL instance.
+
+ @retval EFI_SUCCESS Interrupts are disabled on the processor.
+ @retval EFI_DEVICE_ERROR Interrupts could not be disabled on the processor.
+
+**/
+typedef
+EFI_STATUS
+(EFIAPI *EFI_CPU_DISABLE_INTERRUPT)(
+ IN EFI_CPU_ARCH_PROTOCOL *This
+ );
+
+
+/**
+ This function retrieves the processor's current interrupt state a returns it in
+ State. If interrupts are currently enabled, then TRUE is returned. If interrupts
+ are currently disabled, then FALSE is returned.
+
+ @param This The EFI_CPU_ARCH_PROTOCOL instance.
+ @param State A pointer to the processor's current interrupt state. Set to TRUE if
+ interrupts are enabled and FALSE if interrupts are disabled.
+
+ @retval EFI_SUCCESS The processor's current interrupt state was returned in State.
+ @retval EFI_INVALID_PARAMETER State is NULL.
+
+**/
+typedef
+EFI_STATUS
+(EFIAPI *EFI_CPU_GET_INTERRUPT_STATE)(
+ IN EFI_CPU_ARCH_PROTOCOL *This,
+ OUT BOOLEAN *State
+ );
+
+
+/**
+ This function generates an INIT on the processor. If this function succeeds, then the
+ processor will be reset, and control will not be returned to the caller. If InitType is
+ not supported by this processor, or the processor cannot programmatically generate an
+ INIT without help from external hardware, then EFI_UNSUPPORTED is returned. If an error
+ occurs attempting to generate an INIT, then EFI_DEVICE_ERROR is returned.
+
+ @param This The EFI_CPU_ARCH_PROTOCOL instance.
+ @param InitType The type of processor INIT to perform.
+
+ @retval EFI_SUCCESS The processor INIT was performed. This return code should never be seen.
+ @retval EFI_UNSUPPORTED The processor INIT operation specified by InitType is not supported
+ by this processor.
+ @retval EFI_DEVICE_ERROR The processor INIT failed.
+
+**/
+typedef
+EFI_STATUS
+(EFIAPI *EFI_CPU_INIT)(
+ IN EFI_CPU_ARCH_PROTOCOL *This,
+ IN EFI_CPU_INIT_TYPE InitType
+ );
+
+
+/**
+ This function registers and enables the handler specified by InterruptHandler for a processor
+ interrupt or exception type specified by InterruptType. If InterruptHandler is NULL, then the
+ handler for the processor interrupt or exception type specified by InterruptType is uninstalled.
+ The installed handler is called once for each processor interrupt or exception.
+
+ @param This The EFI_CPU_ARCH_PROTOCOL instance.
+ @param InterruptType A pointer to the processor's current interrupt state. Set to TRUE if interrupts
+ are enabled and FALSE if interrupts are disabled.
+ @param InterruptHandler A pointer to a function of type EFI_CPU_INTERRUPT_HANDLER that is called
+ when a processor interrupt occurs. If this parameter is NULL, then the handler
+ will be uninstalled.
+
+ @retval EFI_SUCCESS The handler for the processor interrupt was successfully installed or uninstalled.
+ @retval EFI_ALREADY_STARTED InterruptHandler is not NULL, and a handler for InterruptType was
+ previously installed.
+ @retval EFI_INVALID_PARAMETER InterruptHandler is NULL, and a handler for InterruptType was not
+ previously installed.
+ @retval EFI_UNSUPPORTED The interrupt specified by InterruptType is not supported.
+
+**/
+typedef
+EFI_STATUS
+(EFIAPI *EFI_CPU_REGISTER_INTERRUPT_HANDLER)(
+ IN EFI_CPU_ARCH_PROTOCOL *This,
+ IN EFI_EXCEPTION_TYPE InterruptType,
+ IN EFI_CPU_INTERRUPT_HANDLER InterruptHandler
+ );
+
+
+/**
+ This function reads the processor timer specified by TimerIndex and returns it in TimerValue.
+
+ @param This The EFI_CPU_ARCH_PROTOCOL instance.
+ @param TimerIndex Specifies which processor timer is to be returned in TimerValue. This parameter
+ must be between 0 and NumberOfTimers-1.
+ @param TimerValue Pointer to the returned timer value.
+ @param TimerPeriod A pointer to the amount of time that passes in femtoseconds for each increment
+ of TimerValue.
+
+ @retval EFI_SUCCESS The processor timer value specified by TimerIndex was returned in TimerValue.
+ @retval EFI_DEVICE_ERROR An error occurred attempting to read one of the processor's timers.
+ @retval EFI_INVALID_PARAMETER TimerValue is NULL or TimerIndex is not valid.
+ @retval EFI_UNSUPPORTED The processor does not have any readable timers.
+
+**/
+typedef
+EFI_STATUS
+(EFIAPI *EFI_CPU_GET_TIMER_VALUE)(
+ IN EFI_CPU_ARCH_PROTOCOL *This,
+ IN UINT32 TimerIndex,
+ OUT UINT64 *TimerValue,
+ OUT UINT64 *TimerPeriod OPTIONAL
+ );
+
+
+/**
+ This function modifies the attributes for the memory region specified by BaseAddress and
+ Length from their current attributes to the attributes specified by Attributes.
+
+ @param This The EFI_CPU_ARCH_PROTOCOL instance.
+ @param BaseAddress The physical address that is the start address of a memory region.
+ @param Length The size in bytes of the memory region.
+ @param Attributes The bit mask of attributes to set for the memory region.
+
+ @retval EFI_SUCCESS The attributes were set for the memory region.
+ @retval EFI_ACCESS_DENIED The attributes for the memory resource range specified by
+ BaseAddress and Length cannot be modified.
+ @retval EFI_INVALID_PARAMETER Length is zero.
+ @retval EFI_OUT_OF_RESOURCES There are not enough system resources to modify the attributes of
+ the memory resource range.
+ @retval EFI_UNSUPPORTED The processor does not support one or more bytes of the memory
+ resource range specified by BaseAddress and Length.
+ The bit mask of attributes is not support for the memory resource
+ range specified by BaseAddress and Length.
+
+**/
+typedef
+EFI_STATUS
+(EFIAPI *EFI_CPU_SET_MEMORY_ATTRIBUTES)(
+ IN EFI_CPU_ARCH_PROTOCOL *This,
+ IN EFI_PHYSICAL_ADDRESS BaseAddress,
+ IN UINT64 Length,
+ IN UINT64 Attributes
+ );
+
+
+/**
+ @par Protocol Description:
+ The EFI_CPU_ARCH_PROTOCOL is used to abstract processor-specific functions from the DXE
+ Foundation. This includes flushing caches, enabling and disabling interrupts, hooking interrupt
+ vectors and exception vectors, reading internal processor timers, resetting the processor, and
+ determining the processor frequency.
+
+ @param FlushDataCache
+ Flushes a range of the processor's data cache. If the processor does
+ not contain a data cache, or the data cache is fully coherent, then this
+ function can just return EFI_SUCCESS. If the processor does not support
+ flushing a range of addresses from the data cache, then the entire data
+ cache must be flushed.
+
+ @param EnableInterrupt
+ Enables interrupt processing by the processor.
+
+ @param DisableInterrupt
+ Disables interrupt processing by the processor.
+
+ @param GetInterruptState
+ Retrieves the processor's current interrupt state.
+
+ @param Init
+ Generates an INIT on the processor. If a processor cannot programmatically
+ generate an INIT without help from external hardware, then this function
+ returns EFI_UNSUPPORTED.
+
+ @param RegisterInterruptHandler
+ Associates an interrupt service routine with one of the processor's interrupt
+ vectors. This function is typically used by the EFI_TIMER_ARCH_PROTOCOL to
+ hook the timer interrupt in a system. It can also be used by the debugger to
+ hook exception vectors.
+
+ @param GetTimerValue
+ Returns the value of one of the processor's internal timers.
+
+ @param SetMemoryAttributes
+ Attempts to set the attributes of a memory region.
+
+ @param NumberOfTimers
+ The number of timers that are available in a processor. The value in this
+ field is a constant that must not be modified after the CPU Architectural
+ Protocol is installed. All consumers must treat this as a read-only field.
+
+ @param DmaBufferAlignment
+ The size, in bytes, of the alignment required for DMA buffer allocations.
+ This is typically the size of the largest data cache line in the platform.
+ The value in this field is a constant that must not be modified after the
+ CPU Architectural Protocol is installed. All consumers must treat this as
+ a read-only field.
+
+**/
+struct _EFI_CPU_ARCH_PROTOCOL {
+ EFI_CPU_FLUSH_DATA_CACHE FlushDataCache;
+ EFI_CPU_ENABLE_INTERRUPT EnableInterrupt;
+ EFI_CPU_DISABLE_INTERRUPT DisableInterrupt;
+ EFI_CPU_GET_INTERRUPT_STATE GetInterruptState;
+ EFI_CPU_INIT Init;
+ EFI_CPU_REGISTER_INTERRUPT_HANDLER RegisterInterruptHandler;
+ EFI_CPU_GET_TIMER_VALUE GetTimerValue;
+ EFI_CPU_SET_MEMORY_ATTRIBUTES SetMemoryAttributes;
+ UINT32 NumberOfTimers;
+ UINT32 DmaBufferAlignment;
+};
+
+extern EFI_GUID gEfiCpuArchProtocolGuid;
+
+#endif
diff --git a/src/include/gpxe/efi/Protocol/CpuIo.h b/src/include/gpxe/efi/Protocol/CpuIo.h
new file mode 100644
index 00000000..8d35c6cd
--- /dev/null
+++ b/src/include/gpxe/efi/Protocol/CpuIo.h
@@ -0,0 +1,128 @@
+/** @file
+ This code abstracts the CPU IO Protocol which installed by some platform or chipset-specific
+ PEIM that abstracts the processor-visible I/O operations.
+
+ Copyright (c) 2007, Intel Corporation
+ All rights reserved. This program and the accompanying materials
+ are licensed and made available under the terms and conditions of the BSD License
+ which accompanies this distribution. The full text of the license may be found at
+ http://opensource.org/licenses/bsd-license.php
+
+ THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+ WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+
+ Module Name: CpuIO.h
+
+ @par Revision Reference:
+ CPU IO Protocol is defined in Framework of EFI CPU IO Protocol Spec
+ Version 0.9
+
+**/
+
+#ifndef _CPUIO_H_
+#define _CPUIO_H_
+
+#include <gpxe/efi/PiDxe.h>
+
+#define EFI_CPU_IO_PROTOCOL_GUID \
+ { \
+ 0xB0732526, 0x38C8, 0x4b40, {0x88, 0x77, 0x61, 0xC7, 0xB0, 0x6A, 0xAC, 0x45 } \
+ }
+
+typedef struct _EFI_CPU_IO_PROTOCOL EFI_CPU_IO_PROTOCOL;
+
+//
+// *******************************************************
+// EFI_CPU_IO_PROTOCOL_WIDTH
+// *******************************************************
+//
+typedef enum {
+ EfiCpuIoWidthUint8,
+ EfiCpuIoWidthUint16,
+ EfiCpuIoWidthUint32,
+ EfiCpuIoWidthUint64,
+ EfiCpuIoWidthFifoUint8,
+ EfiCpuIoWidthFifoUint16,
+ EfiCpuIoWidthFifoUint32,
+ EfiCpuIoWidthFifoUint64,
+ EfiCpuIoWidthFillUint8,
+ EfiCpuIoWidthFillUint16,
+ EfiCpuIoWidthFillUint32,
+ EfiCpuIoWidthFillUint64,
+ EfiCpuIoWidthMaximum
+} EFI_CPU_IO_PROTOCOL_WIDTH;
+
+//
+// *******************************************************
+// EFI_CPU_IO_PROTOCOL_IO_MEM
+// *******************************************************
+//
+/**
+ Enables a driver to access memory-mapped registers in the EFI system memory space.
+ Or, Enables a driver to access registers in the EFI CPU I/O space.
+
+ @param This A pointer to the EFI_CPU_IO_PROTOCOL instance.
+ @param Width Signifies the width of the I/O or Memory operation.
+ @param Address The base address of the I/O or Memoryoperation.
+ @param Count The number of I/O or Memory operations to perform.
+ The number of bytes moved is Width size * Count, starting at Address.
+ @param Buffer For read operations, the destination buffer to store the results.
+ For write operations, the source buffer from which to write data.
+
+ @retval EFI_SUCCESS The data was read from or written to the EFI system.
+ @retval EFI_INVALID_PARAMETER Width is invalid for this EFI system.Or Buffer is NULL.
+ @retval EFI_UNSUPPORTED The Buffer is not aligned for the given Width.
+ Or,The address range specified by Address, Width, and Count is not valid for this EFI system.
+
+**/
+typedef
+EFI_STATUS
+(EFIAPI *EFI_CPU_IO_PROTOCOL_IO_MEM)(
+ IN EFI_CPU_IO_PROTOCOL *This,
+ IN EFI_CPU_IO_PROTOCOL_WIDTH Width,
+ IN UINT64 Address,
+ IN UINTN Count,
+ IN OUT VOID *Buffer
+ );
+
+//
+// *******************************************************
+// EFI_CPU_IO_PROTOCOL_ACCESS
+// *******************************************************
+//
+typedef struct {
+ EFI_CPU_IO_PROTOCOL_IO_MEM Read;
+ EFI_CPU_IO_PROTOCOL_IO_MEM Write;
+} EFI_CPU_IO_PROTOCOL_ACCESS;
+
+//
+// *******************************************************
+// EFI_CPU_IO_PROTOCOL
+// *******************************************************
+//
+/**
+ @par Protocol Description:
+ Provides the basic memory and I/O interfaces that are used to abstract
+ accesses to devices in a system.
+
+ @param Mem.Read
+ Allows reads from memory-mapped I/O space.
+
+ @param Mem.Write
+ Allows writes to memory-mapped I/O space.
+
+ @param Io.Read
+ Allows reads from I/O space.
+
+ @param Io.Write
+ Allows writes to I/O space.
+
+**/
+struct _EFI_CPU_IO_PROTOCOL {
+ EFI_CPU_IO_PROTOCOL_ACCESS Mem;
+ EFI_CPU_IO_PROTOCOL_ACCESS Io;
+};
+
+extern EFI_GUID gEfiCpuIoProtocolGuid;
+
+#endif
diff --git a/src/include/gpxe/efi/Protocol/DebugSupport.h b/src/include/gpxe/efi/Protocol/DebugSupport.h
new file mode 100644
index 00000000..6f785a17
--- /dev/null
+++ b/src/include/gpxe/efi/Protocol/DebugSupport.h
@@ -0,0 +1,656 @@
+/** @file
+ DebugSupport protocol and supporting definitions as defined in the UEFI2.0
+ specification.
+
+ The DebugSupport protocol is used by source level debuggers to abstract the
+ processor and handle context save and restore operations.
+
+ Copyright (c) 2006 - 2008, Intel Corporation
+ All rights reserved. This program and the accompanying materials
+ are licensed and made available under the terms and conditions of the BSD License
+ which accompanies this distribution. The full text of the license may be found at
+ http://opensource.org/licenses/bsd-license.php
+
+ THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+ WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+
+**/
+
+#ifndef __DEBUG_SUPPORT_H__
+#define __DEBUG_SUPPORT_H__
+
+#include <gpxe/efi/ProcessorBind.h>
+#include <gpxe/efi/IndustryStandard/PeImage.h>
+
+typedef struct _EFI_DEBUG_SUPPORT_PROTOCOL EFI_DEBUG_SUPPORT_PROTOCOL;
+
+///
+/// Debug Support protocol {2755590C-6F3C-42FA-9EA4-A3BA543CDA25}
+///
+#define EFI_DEBUG_SUPPORT_PROTOCOL_GUID \
+ { \
+ 0x2755590C, 0x6F3C, 0x42FA, {0x9E, 0xA4, 0xA3, 0xBA, 0x54, 0x3C, 0xDA, 0x25 } \
+ }
+
+///
+/// Debug Support definitions
+///
+typedef INTN EFI_EXCEPTION_TYPE;
+
+//
+// IA-32 processor exception types
+//
+#define EXCEPT_IA32_DIVIDE_ERROR 0
+#define EXCEPT_IA32_DEBUG 1
+#define EXCEPT_IA32_NMI 2
+#define EXCEPT_IA32_BREAKPOINT 3
+#define EXCEPT_IA32_OVERFLOW 4
+#define EXCEPT_IA32_BOUND 5
+#define EXCEPT_IA32_INVALID_OPCODE 6
+#define EXCEPT_IA32_DOUBLE_FAULT 8
+#define EXCEPT_IA32_INVALID_TSS 10
+#define EXCEPT_IA32_SEG_NOT_PRESENT 11
+#define EXCEPT_IA32_STACK_FAULT 12
+#define EXCEPT_IA32_GP_FAULT 13
+#define EXCEPT_IA32_PAGE_FAULT 14
+#define EXCEPT_IA32_FP_ERROR 16
+#define EXCEPT_IA32_ALIGNMENT_CHECK 17
+#define EXCEPT_IA32_MACHINE_CHECK 18
+#define EXCEPT_IA32_SIMD 19
+
+//
+// IA-32 processor context definition
+//
+//
+// FXSAVE_STATE
+// FP / MMX / XMM registers (see fxrstor instruction definition)
+//
+typedef struct {
+ UINT16 Fcw;
+ UINT16 Fsw;
+ UINT16 Ftw;
+ UINT16 Opcode;
+ UINT32 Eip;
+ UINT16 Cs;
+ UINT16 Reserved1;
+ UINT32 DataOffset;
+ UINT16 Ds;
+ UINT8 Reserved2[10];
+ UINT8 St0Mm0[10], Reserved3[6];
+ UINT8 St1Mm1[10], Reserved4[6];
+ UINT8 St2Mm2[10], Reserved5[6];
+ UINT8 St3Mm3[10], Reserved6[6];
+ UINT8 St4Mm4[10], Reserved7[6];
+ UINT8 St5Mm5[10], Reserved8[6];
+ UINT8 St6Mm6[10], Reserved9[6];
+ UINT8 St7Mm7[10], Reserved10[6];
+ UINT8 Xmm0[16];
+ UINT8 Xmm1[16];
+ UINT8 Xmm2[16];
+ UINT8 Xmm3[16];
+ UINT8 Xmm4[16];
+ UINT8 Xmm5[16];
+ UINT8 Xmm6[16];
+ UINT8 Xmm7[16];
+ UINT8 Reserved11[14 * 16];
+} EFI_FX_SAVE_STATE_IA32;
+
+typedef struct {
+ UINT32 ExceptionData;
+ EFI_FX_SAVE_STATE_IA32 FxSaveState;
+ UINT32 Dr0;
+ UINT32 Dr1;
+ UINT32 Dr2;
+ UINT32 Dr3;
+ UINT32 Dr6;
+ UINT32 Dr7;
+ UINT32 Cr0;
+ UINT32 Cr1; /* Reserved */
+ UINT32 Cr2;
+ UINT32 Cr3;
+ UINT32 Cr4;
+ UINT32 Eflags;
+ UINT32 Ldtr;
+ UINT32 Tr;
+ UINT32 Gdtr[2];
+ UINT32 Idtr[2];
+ UINT32 Eip;
+ UINT32 Gs;
+ UINT32 Fs;
+ UINT32 Es;
+ UINT32 Ds;
+ UINT32 Cs;
+ UINT32 Ss;
+ UINT32 Edi;
+ UINT32 Esi;
+ UINT32 Ebp;
+ UINT32 Esp;
+ UINT32 Ebx;
+ UINT32 Edx;
+ UINT32 Ecx;
+ UINT32 Eax;
+} EFI_SYSTEM_CONTEXT_IA32;
+
+//
+// X64 processor exception types
+//
+#define EXCEPT_X64_DIVIDE_ERROR 0
+#define EXCEPT_X64_DEBUG 1
+#define EXCEPT_X64_NMI 2
+#define EXCEPT_X64_BREAKPOINT 3
+#define EXCEPT_X64_OVERFLOW 4
+#define EXCEPT_X64_BOUND 5
+#define EXCEPT_X64_INVALID_OPCODE 6
+#define EXCEPT_X64_DOUBLE_FAULT 8
+#define EXCEPT_X64_INVALID_TSS 10
+#define EXCEPT_X64_SEG_NOT_PRESENT 11
+#define EXCEPT_X64_STACK_FAULT 12
+#define EXCEPT_X64_GP_FAULT 13
+#define EXCEPT_X64_PAGE_FAULT 14
+#define EXCEPT_X64_FP_ERROR 16
+#define EXCEPT_X64_ALIGNMENT_CHECK 17
+#define EXCEPT_X64_MACHINE_CHECK 18
+#define EXCEPT_X64_SIMD 19
+
+//
+// X64 processor context definition
+//
+// FXSAVE_STATE
+// FP / MMX / XMM registers (see fxrstor instruction definition)
+//
+typedef struct {
+ UINT16 Fcw;
+ UINT16 Fsw;
+ UINT16 Ftw;
+ UINT16 Opcode;
+ UINT64 Rip;
+ UINT64 DataOffset;
+ UINT8 Reserved1[8];
+ UINT8 St0Mm0[10], Reserved2[6];
+ UINT8 St1Mm1[10], Reserved3[6];
+ UINT8 St2Mm2[10], Reserved4[6];
+ UINT8 St3Mm3[10], Reserved5[6];
+ UINT8 St4Mm4[10], Reserved6[6];
+ UINT8 St5Mm5[10], Reserved7[6];
+ UINT8 St6Mm6[10], Reserved8[6];
+ UINT8 St7Mm7[10], Reserved9[6];
+ UINT8 Xmm0[16];
+ UINT8 Xmm1[16];
+ UINT8 Xmm2[16];
+ UINT8 Xmm3[16];
+ UINT8 Xmm4[16];
+ UINT8 Xmm5[16];
+ UINT8 Xmm6[16];
+ UINT8 Xmm7[16];
+ //
+ // NOTE: UEFI 2.0 spec definition as follows.
+ //
+ UINT8 Reserved11[14 * 16];
+} EFI_FX_SAVE_STATE_X64;
+
+typedef struct {
+ UINT64 ExceptionData;
+ EFI_FX_SAVE_STATE_X64 FxSaveState;
+ UINT64 Dr0;
+ UINT64 Dr1;
+ UINT64 Dr2;
+ UINT64 Dr3;
+ UINT64 Dr6;
+ UINT64 Dr7;
+ UINT64 Cr0;
+ UINT64 Cr1; /* Reserved */
+ UINT64 Cr2;
+ UINT64 Cr3;
+ UINT64 Cr4;
+ UINT64 Cr8;
+ UINT64 Rflags;
+ UINT64 Ldtr;
+ UINT64 Tr;
+ UINT64 Gdtr[2];
+ UINT64 Idtr[2];
+ UINT64 Rip;
+ UINT64 Gs;
+ UINT64 Fs;
+ UINT64 Es;
+ UINT64 Ds;
+ UINT64 Cs;
+ UINT64 Ss;
+ UINT64 Rdi;
+ UINT64 Rsi;
+ UINT64 Rbp;
+ UINT64 Rsp;
+ UINT64 Rbx;
+ UINT64 Rdx;
+ UINT64 Rcx;
+ UINT64 Rax;
+ UINT64 R8;
+ UINT64 R9;
+ UINT64 R10;
+ UINT64 R11;
+ UINT64 R12;
+ UINT64 R13;
+ UINT64 R14;
+ UINT64 R15;
+} EFI_SYSTEM_CONTEXT_X64;
+
+//
+// IPF processor exception types
+//
+#define EXCEPT_IPF_VHTP_TRANSLATION 0
+#define EXCEPT_IPF_INSTRUCTION_TLB 1
+#define EXCEPT_IPF_DATA_TLB 2
+#define EXCEPT_IPF_ALT_INSTRUCTION_TLB 3
+#define EXCEPT_IPF_ALT_DATA_TLB 4
+#define EXCEPT_IPF_DATA_NESTED_TLB 5
+#define EXCEPT_IPF_INSTRUCTION_KEY_MISSED 6
+#define EXCEPT_IPF_DATA_KEY_MISSED 7
+#define EXCEPT_IPF_DIRTY_BIT 8
+#define EXCEPT_IPF_INSTRUCTION_ACCESS_BIT 9
+#define EXCEPT_IPF_DATA_ACCESS_BIT 10
+#define EXCEPT_IPF_BREAKPOINT 11
+#define EXCEPT_IPF_EXTERNAL_INTERRUPT 12
+//
+// 13 - 19 reserved
+//
+#define EXCEPT_IPF_PAGE_NOT_PRESENT 20
+#define EXCEPT_IPF_KEY_PERMISSION 21
+#define EXCEPT_IPF_INSTRUCTION_ACCESS_RIGHTS 22
+#define EXCEPT_IPF_DATA_ACCESS_RIGHTS 23
+#define EXCEPT_IPF_GENERAL_EXCEPTION 24
+#define EXCEPT_IPF_DISABLED_FP_REGISTER 25
+#define EXCEPT_IPF_NAT_CONSUMPTION 26
+#define EXCEPT_IPF_SPECULATION 27
+//
+// 28 reserved
+//
+#define EXCEPT_IPF_DEBUG 29
+#define EXCEPT_IPF_UNALIGNED_REFERENCE 30
+#define EXCEPT_IPF_UNSUPPORTED_DATA_REFERENCE 31
+#define EXCEPT_IPF_FP_FAULT 32
+#define EXCEPT_IPF_FP_TRAP 33
+#define EXCEPT_IPF_LOWER_PRIVILEGE_TRANSFER_TRAP 34
+#define EXCEPT_IPF_TAKEN_BRANCH 35
+#define EXCEPT_IPF_SINGLE_STEP 36
+//
+// 37 - 44 reserved
+//
+#define EXCEPT_IPF_IA32_EXCEPTION 45
+#define EXCEPT_IPF_IA32_INTERCEPT 46
+#define EXCEPT_IPF_IA32_INTERRUPT 47
+
+//
+// IPF processor context definition
+//
+typedef struct {
+ //
+ // The first reserved field is necessary to preserve alignment for the correct
+ // bits in UNAT and to insure F2 is 16 byte aligned..
+ //
+ UINT64 Reserved;
+ UINT64 R1;
+ UINT64 R2;
+ UINT64 R3;
+ UINT64 R4;
+ UINT64 R5;
+ UINT64 R6;
+ UINT64 R7;
+ UINT64 R8;
+ UINT64 R9;
+ UINT64 R10;
+ UINT64 R11;
+ UINT64 R12;
+ UINT64 R13;
+ UINT64 R14;
+ UINT64 R15;
+ UINT64 R16;
+ UINT64 R17;
+ UINT64 R18;
+ UINT64 R19;
+ UINT64 R20;
+ UINT64 R21;
+ UINT64 R22;
+ UINT64 R23;
+ UINT64 R24;
+ UINT64 R25;
+ UINT64 R26;
+ UINT64 R27;
+ UINT64 R28;
+ UINT64 R29;
+ UINT64 R30;
+ UINT64 R31;
+
+ UINT64 F2[2];
+ UINT64 F3[2];
+ UINT64 F4[2];
+ UINT64 F5[2];
+ UINT64 F6[2];
+ UINT64 F7[2];
+ UINT64 F8[2];
+ UINT64 F9[2];
+ UINT64 F10[2];
+ UINT64 F11[2];
+ UINT64 F12[2];
+ UINT64 F13[2];
+ UINT64 F14[2];
+ UINT64 F15[2];
+ UINT64 F16[2];
+ UINT64 F17[2];
+ UINT64 F18[2];
+ UINT64 F19[2];
+ UINT64 F20[2];
+ UINT64 F21[2];
+ UINT64 F22[2];
+ UINT64 F23[2];
+ UINT64 F24[2];
+ UINT64 F25[2];
+ UINT64 F26[2];
+ UINT64 F27[2];
+ UINT64 F28[2];
+ UINT64 F29[2];
+ UINT64 F30[2];
+ UINT64 F31[2];
+
+ UINT64 Pr;
+
+ UINT64 B0;
+ UINT64 B1;
+ UINT64 B2;
+ UINT64 B3;
+ UINT64 B4;
+ UINT64 B5;
+ UINT64 B6;
+ UINT64 B7;
+
+ //
+ // application registers
+ //
+ UINT64 ArRsc;
+ UINT64 ArBsp;
+ UINT64 ArBspstore;
+ UINT64 ArRnat;
+
+ UINT64 ArFcr;
+
+ UINT64 ArEflag;
+ UINT64 ArCsd;
+ UINT64 ArSsd;
+ UINT64 ArCflg;
+ UINT64 ArFsr;
+ UINT64 ArFir;
+ UINT64 ArFdr;
+
+ UINT64 ArCcv;
+
+ UINT64 ArUnat;
+
+ UINT64 ArFpsr;
+
+ UINT64 ArPfs;
+ UINT64 ArLc;
+ UINT64 ArEc;
+
+ //
+ // control registers
+ //
+ UINT64 CrDcr;
+ UINT64 CrItm;
+ UINT64 CrIva;
+ UINT64 CrPta;
+ UINT64 CrIpsr;
+ UINT64 CrIsr;
+ UINT64 CrIip;
+ UINT64 CrIfa;
+ UINT64 CrItir;
+ UINT64 CrIipa;
+ UINT64 CrIfs;
+ UINT64 CrIim;
+ UINT64 CrIha;
+
+ //
+ // debug registers
+ //
+ UINT64 Dbr0;
+ UINT64 Dbr1;
+ UINT64 Dbr2;
+ UINT64 Dbr3;
+ UINT64 Dbr4;
+ UINT64 Dbr5;
+ UINT64 Dbr6;
+ UINT64 Dbr7;
+
+ UINT64 Ibr0;
+ UINT64 Ibr1;
+ UINT64 Ibr2;
+ UINT64 Ibr3;
+ UINT64 Ibr4;
+ UINT64 Ibr5;
+ UINT64 Ibr6;
+ UINT64 Ibr7;
+
+ //
+ // virtual registers - nat bits for R1-R31
+ //
+ UINT64 IntNat;
+
+} EFI_SYSTEM_CONTEXT_IPF;
+
+//
+// EBC processor exception types
+//
+#define EXCEPT_EBC_UNDEFINED 0
+#define EXCEPT_EBC_DIVIDE_ERROR 1
+#define EXCEPT_EBC_DEBUG 2
+#define EXCEPT_EBC_BREAKPOINT 3
+#define EXCEPT_EBC_OVERFLOW 4
+#define EXCEPT_EBC_INVALID_OPCODE 5 // opcode out of range
+#define EXCEPT_EBC_STACK_FAULT 6
+#define EXCEPT_EBC_ALIGNMENT_CHECK 7
+#define EXCEPT_EBC_INSTRUCTION_ENCODING 8 // malformed instruction
+#define EXCEPT_EBC_BAD_BREAK 9 // BREAK 0 or undefined BREAK
+#define EXCEPT_EBC_STEP 10 // to support debug stepping
+///
+/// For coding convenience, define the maximum valid EBC exception.
+///
+#define MAX_EBC_EXCEPTION EXCEPT_EBC_STEP
+
+///
+/// EBC processor context definition
+///
+typedef struct {
+ UINT64 R0;
+ UINT64 R1;
+ UINT64 R2;
+ UINT64 R3;
+ UINT64 R4;
+ UINT64 R5;
+ UINT64 R6;
+ UINT64 R7;
+ UINT64 Flags;
+ UINT64 ControlFlags;
+ UINT64 Ip;
+} EFI_SYSTEM_CONTEXT_EBC;
+
+///
+/// Universal EFI_SYSTEM_CONTEXT definition
+///
+typedef union {
+ EFI_SYSTEM_CONTEXT_EBC *SystemContextEbc;
+ EFI_SYSTEM_CONTEXT_IA32 *SystemContextIa32;
+ EFI_SYSTEM_CONTEXT_X64 *SystemContextX64;
+ EFI_SYSTEM_CONTEXT_IPF *SystemContextIpf;
+} EFI_SYSTEM_CONTEXT;
+
+//
+// DebugSupport callback function prototypes
+//
+
+/**
+ Registers and enables an exception callback function for the specified exception.
+
+ @param ExceptionType Exception types in EBC, IA-32, X64, or IPF
+ @param SystemContext Exception content.
+
+**/
+typedef
+VOID
+(*EFI_EXCEPTION_CALLBACK)(
+ IN EFI_EXCEPTION_TYPE ExceptionType,
+ IN OUT EFI_SYSTEM_CONTEXT SystemContext
+ );
+
+/**
+ Registers and enables the on-target debug agent's periodic entry point.
+
+ @param SystemContext Exception content.
+
+**/
+typedef
+VOID
+(*EFI_PERIODIC_CALLBACK)(
+ IN OUT EFI_SYSTEM_CONTEXT SystemContext
+ );
+
+//
+// Machine type definition
+//
+typedef enum {
+ IsaIa32 = IMAGE_FILE_MACHINE_I386, // 0x014C
+ IsaX64 = IMAGE_FILE_MACHINE_X64, // 0x8664
+ IsaIpf = IMAGE_FILE_MACHINE_IA64, // 0x0200
+ IsaEbc = IMAGE_FILE_MACHINE_EBC // 0x0EBC
+} EFI_INSTRUCTION_SET_ARCHITECTURE;
+
+
+//
+// DebugSupport member function definitions
+//
+
+/**
+ Returns the maximum value that may be used for the ProcessorIndex parameter in
+ RegisterPeriodicCallback() and RegisterExceptionCallback().
+
+ @param This A pointer to the EFI_DEBUG_SUPPORT_PROTOCOL instance.
+ @param MaxProcessorIndex Pointer to a caller-allocated UINTN in which the maximum supported
+ processor index is returned.
+
+ @retval EFI_SUCCESS The function completed successfully.
+
+**/
+typedef
+EFI_STATUS
+(EFIAPI *EFI_GET_MAXIMUM_PROCESSOR_INDEX)(
+ IN EFI_DEBUG_SUPPORT_PROTOCOL *This,
+ OUT UINTN *MaxProcessorIndex
+ );
+
+/**
+ Registers a function to be called back periodically in interrupt context.
+
+ @param This A pointer to the EFI_DEBUG_SUPPORT_PROTOCOL instance.
+ @param ProcessorIndex Specifies which processor the callback function applies to.
+ @param PeriodicCallback A pointer to a function of type PERIODIC_CALLBACK that is the main
+ periodic entry point of the debug agent.
+
+ @retval EFI_SUCCESS The function completed successfully.
+ @retval EFI_ALREADY_STARTED Non-NULL PeriodicCallback parameter when a callback
+ function was previously registered.
+ @retval EFI_OUT_OF_RESOURCES System has insufficient memory resources to register new callback
+ function.
+
+**/
+typedef
+EFI_STATUS
+(EFIAPI *EFI_REGISTER_PERIODIC_CALLBACK)(
+ IN EFI_DEBUG_SUPPORT_PROTOCOL *This,
+ IN UINTN ProcessorIndex,
+ IN EFI_PERIODIC_CALLBACK PeriodicCallback
+ );
+
+/**
+ Registers a function to be called when a given processor exception occurs.
+
+ @param This A pointer to the EFI_DEBUG_SUPPORT_PROTOCOL instance.
+ @param ProcessorIndex Specifies which processor the callback function applies to.
+ @param PeriodicCallback A pointer to a function of type EXCEPTION_CALLBACK that is called
+ when the processor exception specified by ExceptionType occurs.
+ @param ExceptionType Specifies which processor exception to hook.
+
+ @retval EFI_SUCCESS The function completed successfully.
+ @retval EFI_ALREADY_STARTED Non-NULL PeriodicCallback parameter when a callback
+ function was previously registered.
+ @retval EFI_OUT_OF_RESOURCES System has insufficient memory resources to register new callback
+ function.
+
+**/
+typedef
+EFI_STATUS
+(EFIAPI *EFI_REGISTER_EXCEPTION_CALLBACK)(
+ IN EFI_DEBUG_SUPPORT_PROTOCOL *This,
+ IN UINTN ProcessorIndex,
+ IN EFI_EXCEPTION_CALLBACK ExceptionCallback,
+ IN EFI_EXCEPTION_TYPE ExceptionType
+ );
+
+/**
+ Invalidates processor instruction cache for a memory range. Subsequent execution in this range
+ causes a fresh memory fetch to retrieve code to be executed.
+
+ @param This A pointer to the EFI_DEBUG_SUPPORT_PROTOCOL instance.
+ @param ProcessorIndex Specifies which processor's instruction cache is to be invalidated.
+ @param Start Specifies the physical base of the memory range to be invalidated.
+ @param Length Specifies the minimum number of bytes in the processor's instruction
+ cache to invalidate.
+
+ @retval EFI_SUCCESS The function completed successfully.
+
+**/
+typedef
+EFI_STATUS
+(EFIAPI *EFI_INVALIDATE_INSTRUCTION_CACHE)(
+ IN EFI_DEBUG_SUPPORT_PROTOCOL *This,
+ IN UINTN ProcessorIndex,
+ IN VOID *Start,
+ IN UINT64 Length
+ );
+
+//
+// DebugSupport protocol definition
+//
+/**
+ @par Protocol Description:
+ This protocol provides the services to allow the debug agent to register
+ callback functions that are called either periodically or when specific
+ processor exceptions occur.
+
+ @param Isa
+ Declares the processor architecture for this instance of the EFI
+ Debug Support protocol.
+
+ @param GetMaximumProcessorIndex
+ Returns the maximum processor index value that may be used.
+
+ @param RegisterPeriodicCallback
+ Registers a callback function that will be invoked periodically
+ and asynchronously to the execution of EFI.
+
+ @param RegisterExceptionCallback
+ Registers a callback function that will be called each time the
+ specified processor exception occurs.
+
+ @param InvalidateInstructionCache
+ Invalidate the instruction cache of the processor. This is required
+ by processor architectures where instruction and data caches are
+ not coherent when instructions in the code under debug has been
+ modified by the debug agent.
+**/
+struct _EFI_DEBUG_SUPPORT_PROTOCOL {
+ EFI_INSTRUCTION_SET_ARCHITECTURE Isa;
+ EFI_GET_MAXIMUM_PROCESSOR_INDEX GetMaximumProcessorIndex;
+ EFI_REGISTER_PERIODIC_CALLBACK RegisterPeriodicCallback;
+ EFI_REGISTER_EXCEPTION_CALLBACK RegisterExceptionCallback;
+ EFI_INVALIDATE_INSTRUCTION_CACHE InvalidateInstructionCache;
+};
+
+extern EFI_GUID gEfiDebugSupportProtocolGuid;
+
+#endif
diff --git a/src/include/gpxe/efi/Protocol/PciRootBridgeIo.h b/src/include/gpxe/efi/Protocol/PciRootBridgeIo.h
new file mode 100644
index 00000000..c15c72f7
--- /dev/null
+++ b/src/include/gpxe/efi/Protocol/PciRootBridgeIo.h
@@ -0,0 +1,450 @@
+/** @file
+ PCI Root Bridge I/O protocol as defined in the UEFI 2.0 specification.
+
+ PCI Root Bridge I/O protocol is used by PCI Bus Driver to perform PCI Memory, PCI I/O,
+ and PCI Configuration cycles on a PCI Root Bridge. It also provides services to perform
+ defferent types of bus mastering DMA
+
+ Copyright (c) 2006 - 2008, Intel Corporation
+ All rights reserved. This program and the accompanying materials
+ are licensed and made available under the terms and conditions of the BSD License
+ which accompanies this distribution. The full text of the license may be found at
+ http://opensource.org/licenses/bsd-license.php
+
+ THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+ WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+
+**/
+
+#ifndef __PCI_ROOT_BRIDGE_IO_H__
+#define __PCI_ROOT_BRIDGE_IO_H__
+
+#include <gpxe/efi/PiDxe.h>
+
+#define EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL_GUID \
+ { \
+ 0x2f707ebb, 0x4a1a, 0x11d4, {0x9a, 0x38, 0x00, 0x90, 0x27, 0x3f, 0xc1, 0x4d } \
+ }
+
+typedef struct _EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL;
+
+typedef enum {
+ EfiPciWidthUint8,
+ EfiPciWidthUint16,
+ EfiPciWidthUint32,
+ EfiPciWidthUint64,
+ EfiPciWidthFifoUint8,
+ EfiPciWidthFifoUint16,
+ EfiPciWidthFifoUint32,
+ EfiPciWidthFifoUint64,
+ EfiPciWidthFillUint8,
+ EfiPciWidthFillUint16,
+ EfiPciWidthFillUint32,
+ EfiPciWidthFillUint64,
+ EfiPciWidthMaximum
+} EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL_WIDTH;
+
+typedef enum {
+ EfiPciOperationBusMasterRead,
+ EfiPciOperationBusMasterWrite,
+ EfiPciOperationBusMasterCommonBuffer,
+ EfiPciOperationBusMasterRead64,
+ EfiPciOperationBusMasterWrite64,
+ EfiPciOperationBusMasterCommonBuffer64,
+ EfiPciOperationMaximum
+} EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL_OPERATION;
+
+#define EFI_PCI_ATTRIBUTE_ISA_MOTHERBOARD_IO 0x0001
+#define EFI_PCI_ATTRIBUTE_ISA_IO 0x0002
+#define EFI_PCI_ATTRIBUTE_VGA_PALETTE_IO 0x0004
+#define EFI_PCI_ATTRIBUTE_VGA_MEMORY 0x0008
+#define EFI_PCI_ATTRIBUTE_VGA_IO 0x0010
+#define EFI_PCI_ATTRIBUTE_IDE_PRIMARY_IO 0x0020
+#define EFI_PCI_ATTRIBUTE_IDE_SECONDARY_IO 0x0040
+#define EFI_PCI_ATTRIBUTE_MEMORY_WRITE_COMBINE 0x0080
+#define EFI_PCI_ATTRIBUTE_MEMORY_CACHED 0x0800
+#define EFI_PCI_ATTRIBUTE_MEMORY_DISABLE 0x1000
+#define EFI_PCI_ATTRIBUTE_DUAL_ADDRESS_CYCLE 0x8000
+
+#define EFI_PCI_ATTRIBUTE_VALID_FOR_ALLOCATE_BUFFER (EFI_PCI_ATTRIBUTE_MEMORY_WRITE_COMBINE | EFI_PCI_ATTRIBUTE_MEMORY_CACHED | EFI_PCI_ATTRIBUTE_DUAL_ADDRESS_CYCLE)
+
+#define EFI_PCI_ATTRIBUTE_INVALID_FOR_ALLOCATE_BUFFER (~EFI_PCI_ATTRIBUTE_VALID_FOR_ALLOCATE_BUFFER)
+
+#define EFI_PCI_ADDRESS(bus, dev, func, reg) \
+ ((UINT64) ((((UINTN) bus) << 24) + (((UINTN) dev) << 16) + (((UINTN) func) << 8) + ((UINTN) reg)))
+
+typedef struct {
+ UINT8 Register;
+ UINT8 Function;
+ UINT8 Device;
+ UINT8 Bus;
+ UINT32 ExtendedRegister;
+} EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL_PCI_ADDRESS;
+
+/**
+ Reads from the I/O space of a PCI Root Bridge. Returns when either the polling exit criteria is
+ satisfied or after a defined duration.
+
+ @param This A pointer to the EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL.
+ @param Width Signifies the width of the memory or I/O operations.
+ @param Address The base address of the memory or I/O operations.
+ @param Mask Mask used for the polling criteria.
+ @param Value The comparison value used for the polling exit criteria.
+ @param Delay The number of 100 ns units to poll.
+ @param Result Pointer to the last value read from the memory location.
+
+ @retval EFI_SUCCESS The last data returned from the access matched the poll exit criteria.
+ @retval EFI_TIMEOUT Delay expired before a match occurred.
+ @retval EFI_OUT_OF_RESOURCES The request could not be completed due to a lack of resources.
+ @retval EFI_INVALID_PARAMETER One or more parameters are invalid.
+
+**/
+typedef
+EFI_STATUS
+(EFIAPI *EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL_POLL_IO_MEM)(
+ IN EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL *This,
+ IN EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL_WIDTH Width,
+ IN UINT64 Address,
+ IN UINT64 Mask,
+ IN UINT64 Value,
+ IN UINT64 Delay,
+ OUT UINT64 *Result
+ );
+
+/**
+ Enables a PCI driver to access PCI controller registers in the PCI root bridge memory space.
+
+ @param This A pointer to the EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL.
+ @param Width Signifies the width of the memory operations.
+ @param Address The base address of the memory operations.
+ @param Count The number of memory operations to perform.
+ @param Buffer For read operations, the destination buffer to store the results. For write
+ operations, the source buffer to write data from.
+
+ @retval EFI_SUCCESS The data was read from or written to the PCI root bridge.
+ @retval EFI_OUT_OF_RESOURCES The request could not be completed due to a lack of resources.
+ @retval EFI_INVALID_PARAMETER One or more parameters are invalid.
+
+**/
+typedef
+EFI_STATUS
+(EFIAPI *EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL_IO_MEM)(
+ IN EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL *This,
+ IN EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL_WIDTH Width,
+ IN UINT64 Address,
+ IN UINTN Count,
+ IN OUT VOID *Buffer
+ );
+
+typedef struct {
+ EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL_IO_MEM Read;
+ EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL_IO_MEM Write;
+} EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL_ACCESS;
+
+/**
+ Enables a PCI driver to copy one region of PCI root bridge memory space to another region of PCI
+ root bridge memory space.
+
+ @param This A pointer to the EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL instance.
+ @param Width Signifies the width of the memory operations.
+ @param DestAddress The destination address of the memory operation.
+ @param SrcAddress The source address of the memory operation.
+ @param Count The number of memory operations to perform.
+
+ @retval EFI_SUCCESS The data was copied from one memory region to another memory region.
+ @retval EFI_INVALID_PARAMETER Width is invalid for this PCI root bridge.
+ @retval EFI_OUT_OF_RESOURCES The request could not be completed due to a lack of resources.
+
+**/
+typedef
+EFI_STATUS
+(EFIAPI *EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL_COPY_MEM)(
+ IN EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL *This,
+ IN EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL_WIDTH Width,
+ IN UINT64 DestAddress,
+ IN UINT64 SrcAddress,
+ IN UINTN Count
+ );
+
+/**
+ Provides the PCI controller-Cspecific addresses required to access system memory from a
+ DMA bus master.
+
+ @param This A pointer to the EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL.
+ @param Operation Indicates if the bus master is going to read or write to system memory.
+ @param HostAddress The system memory address to map to the PCI controller.
+ @param NumberOfBytes On input the number of bytes to map. On output the number of bytes
+ that were mapped.
+ @param DeviceAddress The resulting map address for the bus master PCI controller to use to
+ access the hosts HostAddress.
+ @param Mapping A resulting value to pass to Unmap().
+
+ @retval EFI_SUCCESS The range was mapped for the returned NumberOfBytes.
+ @retval EFI_UNSUPPORTED The HostAddress cannot be mapped as a common buffer.
+ @retval EFI_INVALID_PARAMETER One or more parameters are invalid.
+ @retval EFI_OUT_OF_RESOURCES The request could not be completed due to a lack of resources.
+ @retval EFI_DEVICE_ERROR The system hardware could not map the requested address.
+
+**/
+typedef
+EFI_STATUS
+(EFIAPI *EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL_MAP)(
+ IN EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL *This,
+ IN EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL_OPERATION Operation,
+ IN VOID *HostAddress,
+ IN OUT UINTN *NumberOfBytes,
+ OUT EFI_PHYSICAL_ADDRESS *DeviceAddress,
+ OUT VOID **Mapping
+ );
+
+/**
+ Completes the Map() operation and releases any corresponding resources.
+
+ @param This A pointer to the EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL.
+ @param Mapping The mapping value returned from Map().
+
+ @retval EFI_SUCCESS The range was unmapped.
+ @retval EFI_INVALID_PARAMETER Mapping is not a value that was returned by Map().
+ @retval EFI_DEVICE_ERROR The data was not committed to the target system memory.
+
+**/
+typedef
+EFI_STATUS
+(EFIAPI *EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL_UNMAP)(
+ IN EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL *This,
+ IN VOID *Mapping
+ );
+
+/**
+ Allocates pages that are suitable for an EfiPciOperationBusMasterCommonBuffer or
+ EfiPciOperationBusMasterCommonBuffer64 mapping.
+
+ @param This A pointer to the EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL.
+ @param Type This parameter is not used and must be ignored.
+ @param MemoryType The type of memory to allocate, EfiBootServicesData or
+ EfiRuntimeServicesData.
+ @param Pages The number of pages to allocate.
+ @param HostAddress A pointer to store the base system memory address of the
+ allocated range.
+ @param Attributes The requested bit mask of attributes for the allocated range.
+
+ @retval EFI_SUCCESS The requested memory pages were allocated.
+ @retval EFI_UNSUPPORTED Attributes is unsupported. The only legal attribute bits are
+ MEMORY_WRITE_COMBINE and MEMORY_CACHED.
+ @retval EFI_INVALID_PARAMETER One or more parameters are invalid.
+ @retval EFI_OUT_OF_RESOURCES The memory pages could not be allocated.
+
+**/
+typedef
+EFI_STATUS
+(EFIAPI *EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL_ALLOCATE_BUFFER)(
+ IN EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL *This,
+ IN EFI_ALLOCATE_TYPE Type,
+ IN EFI_MEMORY_TYPE MemoryType,
+ IN UINTN Pages,
+ IN OUT VOID **HostAddress,
+ IN UINT64 Attributes
+ );
+
+/**
+ Frees memory that was allocated with AllocateBuffer().
+
+ @param This A pointer to the EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL.
+ @param Pages The number of pages to free.
+ @param HostAddress The base system memory address of the allocated range.
+
+ @retval EFI_SUCCESS The requested memory pages were freed.
+ @retval EFI_INVALID_PARAMETER The memory range specified by HostAddress and Pages
+ was not allocated with AllocateBuffer().
+
+**/
+typedef
+EFI_STATUS
+(EFIAPI *EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL_FREE_BUFFER)(
+ IN EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL *This,
+ IN UINTN Pages,
+ IN VOID *HostAddress
+ );
+
+/**
+ Flushes all PCI posted write transactions from a PCI host bridge to system memory.
+
+ @param This A pointer to the EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL.
+
+ @retval EFI_SUCCESS The PCI posted write transactions were flushed from the PCI host
+ bridge to system memory.
+ @retval EFI_DEVICE_ERROR The PCI posted write transactions were not flushed from the PCI
+ host bridge due to a hardware error.
+
+**/
+typedef
+EFI_STATUS
+(EFIAPI *EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL_FLUSH)(
+ IN EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL *This
+ );
+
+/**
+ Gets the attributes that a PCI root bridge supports setting with SetAttributes(), and the
+ attributes that a PCI root bridge is currently using.
+
+ @param This A pointer to the EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL.
+ @param Supports A pointer to the mask of attributes that this PCI root bridge supports
+ setting with SetAttributes().
+ @param Attributes A pointer to the mask of attributes that this PCI root bridge is currently
+ using.
+
+ @retval EFI_SUCCESS If Supports is not NULL, then the attributes that the PCI root
+ bridge supports is returned in Supports. If Attributes is
+ not NULL, then the attributes that the PCI root bridge is currently
+ using is returned in Attributes.
+ @retval EFI_INVALID_PARAMETER Both Supports and Attributes are NULL.
+
+
+**/
+typedef
+EFI_STATUS
+(EFIAPI *EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL_GET_ATTRIBUTES)(
+ IN EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL *This,
+ OUT UINT64 *Supports,
+ OUT UINT64 *Attributes
+ );
+
+/**
+ Sets attributes for a resource range on a PCI root bridge.
+
+ @param This A pointer to the EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL.
+ @param Attributes The mask of attributes to set.
+ @param ResourceBase A pointer to the base address of the resource range to be modified by the
+ attributes specified by Attributes.
+ @param ResourceLength A pointer to the length of the resource range to be modified by the
+ attributes specified by Attributes.
+
+ @retval EFI_SUCCESS The set of attributes specified by Attributes for the resource
+ range specified by ResourceBase and ResourceLength
+ were set on the PCI root bridge, and the actual resource range is
+ returned in ResuourceBase and ResourceLength.
+ @retval EFI_UNSUPPORTED A bit is set in Attributes that is not supported by the PCI Root
+ Bridge.
+ @retval EFI_OUT_OF_RESOURCES There are not enough resources to set the attributes on the
+ resource range specified by BaseAddress and Length.
+ @retval EFI_INVALID_PARAMETER One or more parameters are invalid.
+
+**/
+typedef
+EFI_STATUS
+(EFIAPI *EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL_SET_ATTRIBUTES)(
+ IN EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL *This,
+ IN UINT64 Attributes,
+ IN OUT UINT64 *ResourceBase,
+ IN OUT UINT64 *ResourceLength
+ );
+
+/**
+ Retrieves the current resource settings of this PCI root bridge in the form of a set of ACPI 2.0
+ resource descriptors.
+
+ @param This A pointer to the EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL.
+ @param Resources A pointer to the ACPI 2.0 resource descriptors that describe the current
+ configuration of this PCI root bridge.
+
+ @retval EFI_SUCCESS The current configuration of this PCI root bridge was returned in
+ Resources.
+ @retval EFI_UNSUPPORTED The current configuration of this PCI root bridge could not be
+ retrieved.
+
+**/
+typedef
+EFI_STATUS
+(EFIAPI *EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL_CONFIGURATION)(
+ IN EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL *This,
+ OUT VOID **Resources
+ );
+
+/**
+ @par Protocol Description:
+ Provides the basic Memory, I/O, PCI configuration, and DMA interfaces that are
+ used to abstract accesses to PCI controllers behind a PCI Root Bridge Controller.
+
+ @param ParentHandle
+ The EFI_HANDLE of the PCI Host Bridge of which this PCI Root Bridge is a member.
+
+ @param PollMem
+ Polls an address in memory mapped I/O space until an exit condition is met,
+ or a timeout occurs.
+
+ @param PollIo
+ Polls an address in I/O space until an exit condition is met, or a timeout occurs.
+
+ @param Mem.Read
+ Allows reads from memory mapped I/O space.
+
+ @param Mem.Write
+ Allows writes to memory mapped I/O space.
+
+ @param Io.Read
+ Allows reads from I/O space.
+
+ @param Io.Write
+ Allows writes to I/O space.
+
+ @param Pci.Read
+ Allows reads from PCI configuration space.
+
+ @param Pci.Write
+ Allows writes to PCI configuration space.
+
+ @param CopyMem
+ Allows one region of PCI root bridge memory space to be copied to another
+ region of PCI root bridge memory space.
+
+ @param Map
+ Provides the PCI controller's specific addresses needed to access system memory for DMA.
+
+ @param Unmap
+ Releases any resources allocated by Map().
+
+ @param AllocateBuffer
+ Allocates pages that are suitable for a common buffer mapping.
+
+ @param FreeBuffer
+ Free pages that were allocated with AllocateBuffer().
+
+ @param Flush
+ Flushes all PCI posted write transactions to system memory.
+
+ @param GetAttributes
+ Gets the attributes that a PCI root bridge supports setting with SetAttributes(),
+ and the attributes that a PCI root bridge is currently using.
+
+ @param SetAttributes
+ Sets attributes for a resource range on a PCI root bridge.
+
+ @param Configuration
+ Gets the current resource settings for this PCI root bridge.
+
+ @param SegmentNumber
+ The segment number that this PCI root bridge resides.
+
+**/
+struct _EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL {
+ EFI_HANDLE ParentHandle;
+ EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL_POLL_IO_MEM PollMem;
+ EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL_POLL_IO_MEM PollIo;
+ EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL_ACCESS Mem;
+ EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL_ACCESS Io;
+ EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL_ACCESS Pci;
+ EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL_COPY_MEM CopyMem;
+ EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL_MAP Map;
+ EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL_UNMAP Unmap;
+ EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL_ALLOCATE_BUFFER AllocateBuffer;
+ EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL_FREE_BUFFER FreeBuffer;
+ EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL_FLUSH Flush;
+ EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL_GET_ATTRIBUTES GetAttributes;
+ EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL_SET_ATTRIBUTES SetAttributes;
+ EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL_CONFIGURATION Configuration;
+ UINT32 SegmentNumber;
+};
+
+extern EFI_GUID gEfiPciRootBridgeIoProtocolGuid;
+
+#endif
diff --git a/src/include/gpxe/efi/efi.h b/src/include/gpxe/efi/efi.h
index 36aab5eb..0643066f 100644
--- a/src/include/gpxe/efi/efi.h
+++ b/src/include/gpxe/efi/efi.h
@@ -34,4 +34,56 @@
/* Reset any trailing #pragma pack directives */
#pragma pack()
+#include <gpxe/tables.h>
+#include <gpxe/uuid.h>
+
+/** An EFI protocol used by gPXE */
+struct efi_protocol {
+ union {
+ /** EFI protocol GUID */
+ EFI_GUID guid;
+ /** UUID structure understood by gPXE */
+ union uuid uuid;
+ } u;
+ /** Variable containing pointer to protocol structure */
+ void **protocol;
+};
+
+/** Declare an EFI protocol used by gPXE */
+#define __efi_protocol \
+ __table ( struct efi_protocol, efi_protocols, 01 )
+
+/** Declare an EFI protocol to be required by gPXE
+ *
+ * @v _protocol EFI protocol name
+ * @v _ptr Pointer to protocol instance
+ */
+#define EFI_REQUIRE_PROTOCOL( _protocol, _ptr ) \
+ struct efi_protocol __ ## _protocol __efi_protocol = { \
+ .u.guid = _protocol ## _GUID, \
+ .protocol = ( ( void ** ) ( void * ) \
+ ( ( (_ptr) == ( ( _protocol ** ) NULL ) ) ? \
+ (_ptr) : (_ptr) ) ), \
+ }
+
+/** Convert a gPXE status code to an EFI status code
+ *
+ * FIXME: actually perform some kind of conversion. gPXE error codes
+ * will be detected as EFI error codes; both have the top bit set, and
+ * the success return code is zero for both. Anything that just
+ * reports a numerical error will be OK, anything attempting to
+ * interpret the value or to display a text equivalent will be
+ * screwed.
+ */
+#define RC_TO_EFIRC( rc ) (rc)
+
+/** Convert an EFI status code to a gPXE status code
+ *
+ * FIXME: as above
+ */
+#define EFIRC_TO_RC( efirc ) (efirc)
+
+extern EFI_HANDLE efi_image_handle;
+extern EFI_SYSTEM_TABLE *efi_systab;
+
#endif /* _EFI_H */
diff --git a/src/include/gpxe/efi/efi_io.h b/src/include/gpxe/efi/efi_io.h
new file mode 100644
index 00000000..93f559db
--- /dev/null
+++ b/src/include/gpxe/efi/efi_io.h
@@ -0,0 +1,178 @@
+#ifndef _GPXE_EFI_IO_H
+#define _GPXE_EFI_IO_H
+
+/** @file
+ *
+ * gPXE I/O API for EFI
+ *
+ * EFI runs with flat physical addressing, so the various mappings
+ * between virtual addresses, I/O addresses and bus addresses are all
+ * no-ops. I/O is handled using the EFI_CPU_IO_PROTOCOL.
+ */
+
+#ifdef IOAPI_EFI
+#define IOAPI_PREFIX_efi
+#else
+#define IOAPI_PREFIX_efi __efi_
+#endif
+
+extern unsigned long long efi_ioread ( volatile void *io_addr,
+ size_t size );
+extern void efi_iowrite ( unsigned long long data, volatile void *io_addr,
+ size_t size );
+extern void efi_ioreads ( volatile void *io_addr, void *data,
+ size_t size, unsigned int count );
+extern void efi_iowrites ( volatile void *io_addr, const void *data,
+ size_t size, unsigned int count );
+
+/*
+ * Physical<->Bus and Bus<->I/O address mappings
+ *
+ * EFI runs with flat physical addressing, so these are all no-ops.
+ *
+ */
+
+static inline __always_inline unsigned long
+IOAPI_INLINE ( efi, phys_to_bus ) ( unsigned long phys_addr ) {
+ return phys_addr;
+}
+
+static inline __always_inline unsigned long
+IOAPI_INLINE ( efi, bus_to_phys ) ( unsigned long bus_addr ) {
+ return bus_addr;
+}
+
+static inline __always_inline void *
+IOAPI_INLINE ( efi, ioremap ) ( unsigned long bus_addr, size_t len __unused ) {
+ return ( ( void * ) bus_addr );
+}
+
+static inline __always_inline void
+IOAPI_INLINE ( efi, iounmap ) ( volatile const void *io_addr __unused ) {
+ /* Nothing to do */
+}
+
+static inline __always_inline unsigned long
+IOAPI_INLINE ( efi, io_to_bus ) ( volatile const void *io_addr ) {
+ return ( ( unsigned long ) io_addr );
+}
+
+/*
+ * I/O functions
+ *
+ */
+
+static inline __always_inline uint8_t
+IOAPI_INLINE ( efi, readb ) ( volatile uint8_t *io_addr ) {
+ return efi_ioread ( io_addr, sizeof ( *io_addr ) );
+}
+
+static inline __always_inline uint16_t
+IOAPI_INLINE ( efi, readw ) ( volatile uint16_t *io_addr ) {
+ return efi_ioread ( io_addr, sizeof ( *io_addr ) );
+}
+
+static inline __always_inline uint32_t
+IOAPI_INLINE ( efi, readl ) ( volatile uint32_t *io_addr ) {
+ return efi_ioread ( io_addr, sizeof ( *io_addr ) );
+}
+
+static inline __always_inline uint64_t
+IOAPI_INLINE ( efi, readq ) ( volatile uint64_t *io_addr ) {
+ return efi_ioread ( io_addr, sizeof ( *io_addr ) );
+}
+
+static inline __always_inline void
+IOAPI_INLINE ( efi, writeb ) ( uint8_t data, volatile uint8_t *io_addr ) {
+ efi_iowrite ( data, io_addr, sizeof ( *io_addr ) );
+}
+
+static inline __always_inline void
+IOAPI_INLINE ( efi, writew ) ( uint16_t data, volatile uint16_t *io_addr ) {
+ efi_iowrite ( data, io_addr, sizeof ( *io_addr ) );
+}
+
+static inline __always_inline void
+IOAPI_INLINE ( efi, writel ) ( uint32_t data, volatile uint32_t *io_addr ) {
+ efi_iowrite ( data, io_addr, sizeof ( *io_addr ) );
+}
+
+static inline __always_inline void
+IOAPI_INLINE ( efi, writeq ) ( uint64_t data, volatile uint64_t *io_addr ) {
+ efi_iowrite ( data, io_addr, sizeof ( *io_addr ) );
+}
+
+static inline __always_inline uint8_t
+IOAPI_INLINE ( efi, inb ) ( volatile uint8_t *io_addr ) {
+ return efi_ioread ( io_addr, sizeof ( *io_addr ) );
+}
+
+static inline __always_inline uint16_t
+IOAPI_INLINE ( efi, inw ) ( volatile uint16_t *io_addr ) {
+ return efi_ioread ( io_addr, sizeof ( *io_addr ) );
+}
+
+static inline __always_inline uint32_t
+IOAPI_INLINE ( efi, inl ) ( volatile uint32_t *io_addr ) {
+ return efi_ioread ( io_addr, sizeof ( *io_addr ) );
+}
+
+static inline __always_inline void
+IOAPI_INLINE ( efi, outb ) ( uint8_t data, volatile uint8_t *io_addr ) {
+ efi_iowrite ( data, io_addr, sizeof ( *io_addr ) );
+}
+
+static inline __always_inline void
+IOAPI_INLINE ( efi, outw ) ( uint16_t data, volatile uint16_t *io_addr ) {
+ efi_iowrite ( data, io_addr, sizeof ( *io_addr ) );
+}
+
+static inline __always_inline void
+IOAPI_INLINE ( efi, outl ) ( uint32_t data, volatile uint32_t *io_addr ) {
+ efi_iowrite ( data, io_addr, sizeof ( *io_addr ) );
+}
+
+static inline __always_inline void
+IOAPI_INLINE ( efi, insb ) ( volatile uint8_t *io_addr, uint8_t *data,
+ unsigned int count ) {
+ efi_ioreads ( io_addr, data, sizeof ( *io_addr ), count );
+}
+
+static inline __always_inline void
+IOAPI_INLINE ( efi, insw ) ( volatile uint16_t *io_addr, uint16_t *data,
+ unsigned int count ) {
+ efi_ioreads ( io_addr, data, sizeof ( *io_addr ), count );
+}
+
+static inline __always_inline void
+IOAPI_INLINE ( efi, insl ) ( volatile uint32_t *io_addr, uint32_t *data,
+ unsigned int count ) {
+ efi_ioreads ( io_addr, data, sizeof ( *io_addr ), count );
+}
+
+static inline __always_inline void
+IOAPI_INLINE ( efi, outsb ) ( volatile uint8_t *io_addr, const uint8_t *data,
+ unsigned int count ) {
+ efi_iowrites ( io_addr, data, sizeof ( *io_addr ), count );
+}
+
+static inline __always_inline void
+IOAPI_INLINE ( efi, outsw ) ( volatile uint16_t *io_addr, const uint16_t *data,
+ unsigned int count ) {
+ efi_iowrites ( io_addr, data, sizeof ( *io_addr ), count );
+}
+
+static inline __always_inline void
+IOAPI_INLINE ( efi, outsl ) ( volatile uint32_t *io_addr, const uint32_t *data,
+ unsigned int count ) {
+ efi_iowrites ( io_addr, data, sizeof ( *io_addr ), count );
+}
+
+static inline __always_inline void
+IOAPI_INLINE ( efi, mb ) ( void ) {
+ /* Do nothing; EFI readl()/writel() calls already act as
+ * memory barriers.
+ */
+}
+
+#endif /* _GPXE_EFI_IO_H */
diff --git a/src/include/gpxe/efi/efi_pci.h b/src/include/gpxe/efi/efi_pci.h
new file mode 100644
index 00000000..8be331ab
--- /dev/null
+++ b/src/include/gpxe/efi/efi_pci.h
@@ -0,0 +1,146 @@
+#ifndef _GPXE_EFI_PCI_H
+#define _GPXE_EFI_PCI_H
+
+/** @file
+ *
+ * gPXE PCI I/O API for EFI
+ *
+ */
+
+#ifdef PCIAPI_EFI
+#define PCIAPI_PREFIX_efi
+#else
+#define PCIAPI_PREFIX_efi __efi_
+#endif
+
+/* EFI PCI width codes defined by EFI spec */
+#define EFIPCI_WIDTH_BYTE 0
+#define EFIPCI_WIDTH_WORD 1
+#define EFIPCI_WIDTH_DWORD 2
+
+#define EFIPCI_LOCATION( _offset, _width ) \
+ ( (_offset) | ( (_width) << 16 ) )
+#define EFIPCI_OFFSET( _location ) ( (_location) & 0xffff )
+#define EFIPCI_WIDTH( _location ) ( (_location) >> 16 )
+
+struct pci_device;
+
+extern int efipci_read ( struct pci_device *pci, unsigned long location,
+ void *value );
+extern int efipci_write ( struct pci_device *pci, unsigned long location,
+ unsigned long value );
+
+/**
+ * Determine maximum PCI bus number within system
+ *
+ * @ret max_bus Maximum bus number
+ */
+static inline __always_inline int
+PCIAPI_INLINE ( efi, pci_max_bus ) ( void ) {
+ /* No way to work this out via EFI */
+ return 0xff;
+}
+
+/**
+ * Read byte from PCI configuration space via EFI
+ *
+ * @v pci PCI device
+ * @v where Location within PCI configuration space
+ * @v value Value read
+ * @ret rc Return status code
+ */
+static inline __always_inline int
+PCIAPI_INLINE ( efi, pci_read_config_byte ) ( struct pci_device *pci,
+ unsigned int where,
+ uint8_t *value ) {
+ return efipci_read ( pci,
+ EFIPCI_LOCATION ( where, EFIPCI_WIDTH_BYTE ),
+ value );
+}
+
+/**
+ * Read word from PCI configuration space via EFI
+ *
+ * @v pci PCI device
+ * @v where Location within PCI configuration space
+ * @v value Value read
+ * @ret rc Return status code
+ */
+static inline __always_inline int
+PCIAPI_INLINE ( efi, pci_read_config_word ) ( struct pci_device *pci,
+ unsigned int where,
+ uint16_t *value ) {
+ return efipci_read ( pci,
+ EFIPCI_LOCATION ( where, EFIPCI_WIDTH_WORD ),
+ value );
+}
+
+/**
+ * Read dword from PCI configuration space via EFI
+ *
+ * @v pci PCI device
+ * @v where Location within PCI configuration space
+ * @v value Value read
+ * @ret rc Return status code
+ */
+static inline __always_inline int
+PCIAPI_INLINE ( efi, pci_read_config_dword ) ( struct pci_device *pci,
+ unsigned int where,
+ uint32_t *value ) {
+ return efipci_read ( pci,
+ EFIPCI_LOCATION ( where, EFIPCI_WIDTH_DWORD ),
+ value );
+}
+
+/**
+ * Write byte to PCI configuration space via EFI
+ *
+ * @v pci PCI device
+ * @v where Location within PCI configuration space
+ * @v value Value to be written
+ * @ret rc Return status code
+ */
+static inline __always_inline int
+PCIAPI_INLINE ( efi, pci_write_config_byte ) ( struct pci_device *pci,
+ unsigned int where,
+ uint8_t value ) {
+ return efipci_write ( pci,
+ EFIPCI_LOCATION ( where, EFIPCI_WIDTH_BYTE ),
+ value );
+}
+
+/**
+ * Write word to PCI configuration space via EFI
+ *
+ * @v pci PCI device
+ * @v where Location within PCI configuration space
+ * @v value Value to be written
+ * @ret rc Return status code
+ */
+static inline __always_inline int
+PCIAPI_INLINE ( efi, pci_write_config_word ) ( struct pci_device *pci,
+ unsigned int where,
+ uint16_t value ) {
+ return efipci_write ( pci,
+ EFIPCI_LOCATION ( where, EFIPCI_WIDTH_WORD ),
+ value );
+}
+
+/**
+ * Write dword to PCI configuration space via EFI
+ *
+ * @v pci PCI device
+ * @v where Location within PCI configuration space
+ * @v value Value to be written
+ * @ret rc Return status code
+ */
+static inline __always_inline int
+PCIAPI_INLINE ( efi, pci_write_config_dword ) ( struct pci_device *pci,
+ unsigned int where,
+ uint32_t value ) {
+ return efipci_write ( pci,
+ EFIPCI_LOCATION ( where, EFIPCI_WIDTH_DWORD ),
+ value );
+}
+
+#endif /* _GPXE_EFI_PCI_H */
diff --git a/src/include/gpxe/efi/efi_timer.h b/src/include/gpxe/efi/efi_timer.h
new file mode 100644
index 00000000..c332c9d6
--- /dev/null
+++ b/src/include/gpxe/efi/efi_timer.h
@@ -0,0 +1,16 @@
+#ifndef _GPXE_EFI_TIMER_H
+#define _GPXE_EFI_TIMER_H
+
+/** @file
+ *
+ * gPXE timer API for EFI
+ *
+ */
+
+#ifdef TIMER_EFI
+#define TIMER_PREFIX_efi
+#else
+#define TIMER_PREFIX_efi __efi_
+#endif
+
+#endif /* _GPXE_EFI_TIMER_H */
diff --git a/src/include/gpxe/efi/efi_uaccess.h b/src/include/gpxe/efi/efi_uaccess.h
new file mode 100644
index 00000000..bae5fb41
--- /dev/null
+++ b/src/include/gpxe/efi/efi_uaccess.h
@@ -0,0 +1,88 @@
+#ifndef _GPXE_EFI_UACCESS_H
+#define _GPXE_EFI_UACCESS_H
+
+/** @file
+ *
+ * gPXE user access API for EFI
+ *
+ * EFI runs with flat physical addressing, so the various mappings
+ * between virtual addresses, I/O addresses and bus addresses are all
+ * no-ops.
+ */
+
+#ifdef UACCESS_EFI
+#define UACCESS_PREFIX_efi
+#else
+#define UACCESS_PREFIX_efi __efi_
+#endif
+
+/**
+ * Convert physical address to user pointer
+ *
+ * @v phys_addr Physical address
+ * @ret userptr User pointer
+ */
+static inline __always_inline userptr_t
+UACCESS_INLINE ( efi, phys_to_user ) ( unsigned long phys_addr ) {
+ return phys_addr;
+}
+
+/**
+ * Convert user buffer to physical address
+ *
+ * @v userptr User pointer
+ * @v offset Offset from user pointer
+ * @ret phys_addr Physical address
+ */
+static inline __always_inline unsigned long
+UACCESS_INLINE ( efi, user_to_phys ) ( userptr_t userptr, off_t offset ) {
+ return ( userptr + offset );
+}
+
+static inline __always_inline userptr_t
+UACCESS_INLINE ( efi, virt_to_user ) ( volatile const void *addr ) {
+ return trivial_virt_to_user ( addr );
+}
+
+static inline __always_inline void *
+UACCESS_INLINE ( efi, user_to_virt ) ( userptr_t userptr, off_t offset ) {
+ return trivial_user_to_virt ( userptr, offset );
+}
+
+static inline __always_inline userptr_t
+UACCESS_INLINE ( efi, userptr_add ) ( userptr_t userptr, off_t offset ) {
+ return trivial_userptr_add ( userptr, offset );
+}
+
+static inline __always_inline void
+UACCESS_INLINE ( efi, memcpy_user ) ( userptr_t dest, off_t dest_off,
+ userptr_t src, off_t src_off,
+ size_t len ) {
+ trivial_memcpy_user ( dest, dest_off, src, src_off, len );
+}
+
+static inline __always_inline void
+UACCESS_INLINE ( efi, memmove_user ) ( userptr_t dest, off_t dest_off,
+ userptr_t src, off_t src_off,
+ size_t len ) {
+ trivial_memmove_user ( dest, dest_off, src, src_off, len );
+}
+
+static inline __always_inline void
+UACCESS_INLINE ( efi, memset_user ) ( userptr_t buffer, off_t offset,
+ int c, size_t len ) {
+ trivial_memset_user ( buffer, offset, c, len );
+}
+
+static inline __always_inline size_t
+UACCESS_INLINE ( efi, strlen_user ) ( userptr_t buffer, off_t offset ) {
+ return trivial_strlen_user ( buffer, offset );
+}
+
+static inline __always_inline off_t
+UACCESS_INLINE ( efi, memchr_user ) ( userptr_t buffer, off_t offset,
+ int c, size_t len ) {
+ return trivial_memchr_user ( buffer, offset, c, len );
+}
+
+#endif /* _GPXE_EFI_UACCESS_H */
diff --git a/src/include/gpxe/efi/efi_umalloc.h b/src/include/gpxe/efi/efi_umalloc.h
new file mode 100644
index 00000000..def17b2d
--- /dev/null
+++ b/src/include/gpxe/efi/efi_umalloc.h
@@ -0,0 +1,16 @@
+#ifndef _GPXE_EFI_UMALLOC_H
+#define _GPXE_EFI_UMALLOC_H
+
+/** @file
+ *
+ * gPXE user memory allocation API for EFI
+ *
+ */
+
+#ifdef UMALLOC_EFI
+#define UMALLOC_PREFIX_efi
+#else
+#define UMALLOC_PREFIX_efi __efi_
+#endif
+
+#endif /* _GPXE_EFI_UMALLOC_H */
diff --git a/src/include/gpxe/errfile.h b/src/include/gpxe/errfile.h
index ca0abebf..609500cd 100644
--- a/src/include/gpxe/errfile.h
+++ b/src/include/gpxe/errfile.h
@@ -139,6 +139,7 @@
#define ERRFILE_elf ( ERRFILE_IMAGE | 0x00010000 )
#define ERRFILE_script ( ERRFILE_IMAGE | 0x00020000 )
#define ERRFILE_segment ( ERRFILE_IMAGE | 0x00030000 )
+#define ERRFILE_efi_image ( ERRFILE_IMAGE | 0x00040000 )
#define ERRFILE_asn1 ( ERRFILE_OTHER | 0x00000000 )
#define ERRFILE_chap ( ERRFILE_OTHER | 0x00010000 )
@@ -156,6 +157,7 @@
#define ERRFILE_tls ( ERRFILE_OTHER | 0x000d0000 )
#define ERRFILE_ifmgmt ( ERRFILE_OTHER | 0x000e0000 )
#define ERRFILE_iscsiboot ( ERRFILE_OTHER | 0x000f0000 )
+#define ERRFILE_efi_pci ( ERRFILE_OTHER | 0x00100000 )
/** @} */
diff --git a/src/include/gpxe/features.h b/src/include/gpxe/features.h
index 107ff085..e4d29213 100644
--- a/src/include/gpxe/features.h
+++ b/src/include/gpxe/features.h
@@ -46,6 +46,7 @@
#define DHCP_EB_FEATURE_PXE 0x21 /**< PXE format */
#define DHCP_EB_FEATURE_ELF 0x22 /**< ELF format */
#define DHCP_EB_FEATURE_COMBOOT 0x23 /**< COMBOOT format */
+#define DHCP_EB_FEATURE_EFI 0x24 /**< EFI format */
/** @} */
diff --git a/src/include/gpxe/io.h b/src/include/gpxe/io.h
index 0fc7c74e..ebb8ba30 100644
--- a/src/include/gpxe/io.h
+++ b/src/include/gpxe/io.h
@@ -51,6 +51,7 @@
PROVIDE_SINGLE_API_INLINE ( IOAPI_PREFIX_ ## _subsys, _api_func )
/* Include all architecture-independent I/O API headers */
+#include <gpxe/efi/efi_io.h>
/* Include all architecture-dependent I/O API headers */
#include <bits/io.h>
diff --git a/src/include/gpxe/pci_io.h b/src/include/gpxe/pci_io.h
index db50939d..365166c8 100644
--- a/src/include/gpxe/pci_io.h
+++ b/src/include/gpxe/pci_io.h
@@ -41,6 +41,7 @@
PROVIDE_SINGLE_API_INLINE ( PCIAPI_PREFIX_ ## _subsys, _api_func )
/* Include all architecture-independent I/O API headers */
+#include <gpxe/efi/efi_pci.h>
/* Include all architecture-dependent I/O API headers */
#include <bits/pci_io.h>
diff --git a/src/include/gpxe/timer.h b/src/include/gpxe/timer.h
index e62007ae..862d87b3 100644
--- a/src/include/gpxe/timer.h
+++ b/src/include/gpxe/timer.h
@@ -42,6 +42,7 @@
PROVIDE_SINGLE_API_INLINE ( TIMER_PREFIX_ ## _subsys, _api_func )
/* Include all architecture-independent I/O API headers */
+#include <gpxe/efi/efi_timer.h>
/* Include all architecture-dependent I/O API headers */
#include <bits/timer.h>
diff --git a/src/include/gpxe/uaccess.h b/src/include/gpxe/uaccess.h
index f677b7fd..33aaed18 100644
--- a/src/include/gpxe/uaccess.h
+++ b/src/include/gpxe/uaccess.h
@@ -186,6 +186,7 @@ trivial_memchr_user ( userptr_t buffer, off_t offset, int c, size_t len ) {
PROVIDE_SINGLE_API_INLINE ( UACCESS_PREFIX_ ## _subsys, _api_func )
/* Include all architecture-independent user access API headers */
+#include <gpxe/efi/efi_uaccess.h>
/* Include all architecture-dependent user access API headers */
#include <bits/uaccess.h>
diff --git a/src/include/gpxe/umalloc.h b/src/include/gpxe/umalloc.h
index ffa0c0c4..e6fc7bf0 100644
--- a/src/include/gpxe/umalloc.h
+++ b/src/include/gpxe/umalloc.h
@@ -23,6 +23,7 @@
PROVIDE_SINGLE_API ( UMALLOC_PREFIX_ ## _subsys, _api_func, _func )
/* Include all architecture-independent I/O API headers */
+#include <gpxe/efi/efi_umalloc.h>
/* Include all architecture-dependent I/O API headers */
#include <bits/umalloc.h>
diff --git a/src/interface/efi/efi_console.c b/src/interface/efi/efi_console.c
new file mode 100644
index 00000000..b6e0dafd
--- /dev/null
+++ b/src/interface/efi/efi_console.c
@@ -0,0 +1,273 @@
+/*
+ * Copyright (C) 2008 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., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#include <stddef.h>
+#include <assert.h>
+#include <gpxe/efi/efi.h>
+#include <gpxe/ansiesc.h>
+#include <console.h>
+
+#define ATTR_BOLD 0x08
+
+#define ATTR_FCOL_MASK 0x07
+#define ATTR_FCOL_BLACK 0x00
+#define ATTR_FCOL_BLUE 0x01
+#define ATTR_FCOL_GREEN 0x02
+#define ATTR_FCOL_CYAN 0x03
+#define ATTR_FCOL_RED 0x04
+#define ATTR_FCOL_MAGENTA 0x05
+#define ATTR_FCOL_YELLOW 0x06
+#define ATTR_FCOL_WHITE 0x07
+
+#define ATTR_BCOL_MASK 0x70
+#define ATTR_BCOL_BLACK 0x00
+#define ATTR_BCOL_BLUE 0x10
+#define ATTR_BCOL_GREEN 0x20
+#define ATTR_BCOL_CYAN 0x30
+#define ATTR_BCOL_RED 0x40
+#define ATTR_BCOL_MAGENTA 0x50
+#define ATTR_BCOL_YELLOW 0x60
+#define ATTR_BCOL_WHITE 0x70
+
+#define ATTR_DEFAULT ATTR_FCOL_WHITE
+
+/** Current character attribute */
+static unsigned int efi_attr = ATTR_DEFAULT;
+
+/**
+ * Handle ANSI CUP (cursor position)
+ *
+ * @v count Parameter count
+ * @v params[0] Row (1 is top)
+ * @v params[1] Column (1 is left)
+ */
+static void efi_handle_cup ( unsigned int count __unused, int params[] ) {
+ EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL *conout = efi_systab->ConOut;
+ int cx = ( params[1] - 1 );
+ int cy = ( params[0] - 1 );
+
+ if ( cx < 0 )
+ cx = 0;
+ if ( cy < 0 )
+ cy = 0;
+
+ conout->SetCursorPosition ( conout, cx, cy );
+}
+
+/**
+ * Handle ANSI ED (erase in page)
+ *
+ * @v count Parameter count
+ * @v params[0] Region to erase
+ */
+static void efi_handle_ed ( unsigned int count __unused,
+ int params[] __unused ) {
+ EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL *conout = efi_systab->ConOut;
+
+ /* We assume that we always clear the whole screen */
+ assert ( params[0] == ANSIESC_ED_ALL );
+
+ conout->ClearScreen ( conout );
+}
+
+/**
+ * Handle ANSI SGR (set graphics rendition)
+ *
+ * @v count Parameter count
+ * @v params List of graphic rendition aspects
+ */
+static void efi_handle_sgr ( unsigned int count, int params[] ) {
+ EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL *conout = efi_systab->ConOut;
+ static const uint8_t efi_attr_fcols[10] = {
+ ATTR_FCOL_BLACK, ATTR_FCOL_RED, ATTR_FCOL_GREEN,
+ ATTR_FCOL_YELLOW, ATTR_FCOL_BLUE, ATTR_FCOL_MAGENTA,
+ ATTR_FCOL_CYAN, ATTR_FCOL_WHITE,
+ ATTR_FCOL_WHITE, ATTR_FCOL_WHITE /* defaults */
+ };
+ static const uint8_t efi_attr_bcols[10] = {
+ ATTR_BCOL_BLACK, ATTR_BCOL_RED, ATTR_BCOL_GREEN,
+ ATTR_BCOL_YELLOW, ATTR_BCOL_BLUE, ATTR_BCOL_MAGENTA,
+ ATTR_BCOL_CYAN, ATTR_BCOL_WHITE,
+ ATTR_BCOL_BLACK, ATTR_BCOL_BLACK /* defaults */
+ };
+ unsigned int i;
+ int aspect;
+
+ for ( i = 0 ; i < count ; i++ ) {
+ aspect = params[i];
+ if ( aspect == 0 ) {
+ efi_attr = ATTR_DEFAULT;
+ } else if ( aspect == 1 ) {
+ efi_attr |= ATTR_BOLD;
+ } else if ( aspect == 22 ) {
+ efi_attr &= ~ATTR_BOLD;
+ } else if ( ( aspect >= 30 ) && ( aspect <= 39 ) ) {
+ efi_attr &= ~ATTR_FCOL_MASK;
+ efi_attr |= efi_attr_fcols[ aspect - 30 ];
+ } else if ( ( aspect >= 40 ) && ( aspect <= 49 ) ) {
+ efi_attr &= ~ATTR_BCOL_MASK;
+ efi_attr |= efi_attr_bcols[ aspect - 40 ];
+ }
+ }
+
+ conout->SetAttribute ( conout, efi_attr );
+}
+
+/** EFI console ANSI escape sequence handlers */
+static struct ansiesc_handler efi_ansiesc_handlers[] = {
+ { ANSIESC_CUP, efi_handle_cup },
+ { ANSIESC_ED, efi_handle_ed },
+ { ANSIESC_SGR, efi_handle_sgr },
+ { 0, NULL }
+};
+
+/** EFI console ANSI escape sequence context */
+static struct ansiesc_context efi_ansiesc_ctx = {
+ .handlers = efi_ansiesc_handlers,
+};
+
+/**
+ * Print a character to EFI console
+ *
+ * @v character Character to be printed
+ */
+static void efi_putchar ( int character ) {
+ EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL *conout = efi_systab->ConOut;
+ wchar_t wstr[] = { character, 0 };
+
+ /* Intercept ANSI escape sequences */
+ character = ansiesc_process ( &efi_ansiesc_ctx, character );
+ if ( character < 0 )
+ return;
+
+ conout->OutputString ( conout, wstr );
+}
+
+/**
+ * Pointer to current ANSI output sequence
+ *
+ * While we are in the middle of returning an ANSI sequence for a
+ * special key, this will point to the next character to return. When
+ * not in the middle of such a sequence, this will point to a NUL
+ * (note: not "will be NULL").
+ */
+static const char *ansi_input = "";
+
+/** Mapping from EFI scan codes to ANSI escape sequences */
+static const char *ansi_sequences[] = {
+ [SCAN_UP] = "[A",
+ [SCAN_DOWN] = "[B",
+ [SCAN_RIGHT] = "[C",
+ [SCAN_LEFT] = "[D",
+ [SCAN_HOME] = "[H",
+ [SCAN_END] = "[F",
+ [SCAN_INSERT] = "[2~",
+ /* EFI translates an incoming backspace via the serial console
+ * into a SCAN_DELETE. There's not much we can do about this.
+ */
+ [SCAN_DELETE] = "[3~",
+ [SCAN_PAGE_UP] = "[5~",
+ [SCAN_PAGE_DOWN] = "[6~",
+ /* EFI translates some (but not all) incoming escape sequences
+ * via the serial console into equivalent scancodes. When it
+ * doesn't recognise a sequence, it helpfully(!) translates
+ * the initial ESC and passes the remainder through verbatim.
+ * Treating SCAN_ESC as equivalent to an empty escape sequence
+ * works around this bug.
+ */
+ [SCAN_ESC] = "",
+};
+
+/**
+ * Get ANSI escape sequence corresponding to EFI scancode
+ *
+ * @v scancode EFI scancode
+ * @ret ansi_seq ANSI escape sequence, if any, otherwise NULL
+ */
+static const char * scancode_to_ansi_seq ( unsigned int scancode ) {
+ if ( scancode < ( sizeof ( ansi_sequences ) /
+ sizeof ( ansi_sequences[0] ) ) ) {
+ return ansi_sequences[scancode];
+ }
+ return NULL;
+}
+
+/**
+ * Get character from EFI console
+ *
+ * @ret character Character read from console
+ */
+static int efi_getchar ( void ) {
+ EFI_SIMPLE_TEXT_INPUT_PROTOCOL *conin = efi_systab->ConIn;
+ const char *ansi_seq;
+ EFI_INPUT_KEY key;
+ EFI_STATUS efirc;
+
+ /* If we are mid-sequence, pass out the next byte */
+ if ( *ansi_input )
+ return *(ansi_input++);
+
+ /* Read key from real EFI console */
+ if ( ( efirc = conin->ReadKeyStroke ( conin, &key ) ) != 0 ) {
+ DBG ( "EFI could not read keystroke: %lx\n", efirc );
+ return 0;
+ }
+ DBG2 ( "EFI read key stroke with unicode %04x scancode %04x\n",
+ key.UnicodeChar, key.ScanCode );
+
+ /* If key has a Unicode representation, return it */
+ if ( key.UnicodeChar )
+ return key.UnicodeChar;
+
+ /* Otherwise, check for a special key that we know about */
+ if ( ( ansi_seq = scancode_to_ansi_seq ( key.ScanCode ) ) ) {
+ /* Start of escape sequence: return ESC (0x1b) */
+ ansi_input = ansi_seq;
+ return 0x1b;
+ }
+
+ return 0;
+}
+
+/**
+ * Check for character ready to read from EFI console
+ *
+ * @ret True Character available to read
+ * @ret False No character available to read
+ */
+static int efi_iskey ( void ) {
+ EFI_BOOT_SERVICES *bs = efi_systab->BootServices;
+ EFI_SIMPLE_TEXT_INPUT_PROTOCOL *conin = efi_systab->ConIn;
+ EFI_STATUS efirc;
+
+ /* If we are mid-sequence, we are always ready */
+ if ( *ansi_input )
+ return 1;
+
+ /* Check to see if the WaitForKey event has fired */
+ if ( ( efirc = bs->CheckEvent ( conin->WaitForKey ) ) == 0 )
+ return 1;
+
+ return 0;
+}
+
+struct console_driver efi_console __console_driver = {
+ .putchar = efi_putchar,
+ .getchar = efi_getchar,
+ .iskey = efi_iskey,
+};
diff --git a/src/interface/efi/efi_entry.c b/src/interface/efi/efi_entry.c
new file mode 100644
index 00000000..b00828ad
--- /dev/null
+++ b/src/interface/efi/efi_entry.c
@@ -0,0 +1,83 @@
+/*
+ * Copyright (C) 2008 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., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#include <stdlib.h>
+#include <gpxe/efi/efi.h>
+#include <gpxe/uuid.h>
+
+/** Image handle passed to entry point */
+EFI_HANDLE efi_image_handle;
+
+/** System table passed to entry point */
+EFI_SYSTEM_TABLE *efi_systab;
+
+/** Declared used EFI protocols */
+static struct efi_protocol efi_protocols[0] \
+ __table_start ( struct efi_protocol, efi_protocols );
+static struct efi_protocol efi_protocols_end[0] \
+ __table_end ( struct efi_protocol, efi_protocols );
+
+/**
+ * EFI entry point
+ *
+ * @v image_handle Image handle
+ * @v systab System table
+ * @ret efirc EFI return status code
+ */
+EFI_STATUS EFIAPI efi_entry ( EFI_HANDLE image_handle,
+ EFI_SYSTEM_TABLE *systab ) {
+ EFI_BOOT_SERVICES *bs;
+ struct efi_protocol *prot;
+ EFI_STATUS efirc;
+
+ /* Store image handle and system table pointer for future use */
+ efi_image_handle = image_handle;
+ efi_systab = systab;
+
+ /* Sanity checks */
+ if ( ! systab )
+ return EFI_NOT_AVAILABLE_YET;
+ if ( ! systab->ConOut )
+ return EFI_NOT_AVAILABLE_YET;
+ if ( ! systab->BootServices ) {
+ DBGC ( systab, "EFI provided no BootServices entry point\n" );
+ return EFI_NOT_AVAILABLE_YET;
+ }
+ if ( ! systab->RuntimeServices ) {
+ DBGC ( systab, "EFI provided no RuntimeServices entry "
+ "point\n" );
+ return EFI_NOT_AVAILABLE_YET;
+ }
+ DBGC ( systab, "EFI handle %p systab %p\n", image_handle, systab );
+
+ /* Look up required protocols */
+ bs = systab->BootServices;
+ for ( prot = efi_protocols ; prot < efi_protocols_end ; prot++ ) {
+ if ( ( efirc = bs->LocateProtocol ( &prot->u.guid, NULL,
+ prot->protocol ) ) != 0 ) {
+ DBGC ( systab, "EFI does not provide protocol %s\n",
+ uuid_ntoa ( &prot->u.uuid ) );
+ return efirc;
+ }
+ DBGC ( systab, "EFI protocol %s is at %p\n",
+ uuid_ntoa ( &prot->u.uuid ), *(prot->protocol) );
+ }
+
+ /* Call to main() */
+ return RC_TO_EFIRC ( main () );
+}
diff --git a/src/interface/efi/efi_io.c b/src/interface/efi/efi_io.c
new file mode 100644
index 00000000..1d4537ab
--- /dev/null
+++ b/src/interface/efi/efi_io.c
@@ -0,0 +1,201 @@
+/*
+ * Copyright (C) 2008 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., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#include <assert.h>
+#include <gpxe/io.h>
+#include <gpxe/efi/efi.h>
+#include <gpxe/efi/Protocol/CpuIo.h>
+#include <gpxe/efi/efi_io.h>
+
+/** @file
+ *
+ * gPXE I/O API for EFI
+ *
+ */
+
+/** CPU I/O protocol */
+static EFI_CPU_IO_PROTOCOL *cpu_io;
+EFI_REQUIRE_PROTOCOL ( EFI_CPU_IO_PROTOCOL, &cpu_io );
+
+/** Maximum address that can be used for port I/O */
+#define MAX_PORT_ADDRESS 0xffff
+
+/**
+ * Determine whether or not address is a port I/O address
+ *
+ * @v io_addr I/O address
+ * @v is_port I/O address is a port I/O address
+ */
+#define IS_PORT_ADDRESS(io_addr) \
+ ( ( ( intptr_t ) (io_addr) ) <= MAX_PORT_ADDRESS )
+
+/**
+ * Determine EFI CPU I/O width code
+ *
+ * @v size Size of value
+ * @ret width EFI width code
+ *
+ * Someone at Intel clearly gets paid by the number of lines of code
+ * they write. No-one should ever be able to make I/O this
+ * convoluted. The EFI_CPU_IO_PROTOCOL_WIDTH enum is my favourite
+ * idiocy.
+ */
+static EFI_CPU_IO_PROTOCOL_WIDTH efi_width ( size_t size ) {
+ switch ( size ) {
+ case 1 : return EfiCpuIoWidthFifoUint8;
+ case 2 : return EfiCpuIoWidthFifoUint16;
+ case 4 : return EfiCpuIoWidthFifoUint32;
+ case 8 : return EfiCpuIoWidthFifoUint64;
+ default :
+ assert ( 0 );
+ /* I wonder what this will actually do... */
+ return EfiCpuIoWidthMaximum;
+ }
+}
+
+/**
+ * Read from device
+ *
+ * @v io_addr I/O address
+ * @v size Size of value
+ * @ret data Value read
+ */
+unsigned long long efi_ioread ( volatile void *io_addr, size_t size ) {
+ EFI_CPU_IO_PROTOCOL_IO_MEM read;
+ unsigned long long data = 0;
+ EFI_STATUS efirc;
+
+ read = ( IS_PORT_ADDRESS ( io_addr ) ?
+ cpu_io->Io.Read : cpu_io->Mem.Read );
+
+ if ( ( efirc = read ( cpu_io, efi_width ( size ),
+ ( intptr_t ) io_addr, 1,
+ ( void * ) &data ) ) != 0 ) {
+ DBG ( "EFI I/O read at %p failed: %lx\n", io_addr, efirc );
+ return -1ULL;
+ }
+
+ return data;
+}
+
+/**
+ * Write to device
+ *
+ * @v data Value to write
+ * @v io_addr I/O address
+ * @v size Size of value
+ */
+void efi_iowrite ( unsigned long long data, volatile void *io_addr,
+ size_t size ) {
+ EFI_CPU_IO_PROTOCOL_IO_MEM write;
+ EFI_STATUS efirc;
+
+ write = ( IS_PORT_ADDRESS ( io_addr ) ?
+ cpu_io->Io.Write : cpu_io->Mem.Write );
+
+ if ( ( efirc = write ( cpu_io, efi_width ( size ),
+ ( intptr_t ) io_addr, 1,
+ ( void * ) &data ) ) != 0 ) {
+ DBG ( "EFI I/O write at %p failed: %lx\n", io_addr, efirc );
+ }
+}
+
+/**
+ * String read from device
+ *
+ * @v io_addr I/O address
+ * @v data Data buffer
+ * @v size Size of values
+ * @v count Number of values to read
+ */
+void efi_ioreads ( volatile void *io_addr, void *data,
+ size_t size, unsigned int count ) {
+ EFI_CPU_IO_PROTOCOL_IO_MEM read;
+ EFI_STATUS efirc;
+
+ read = ( IS_PORT_ADDRESS ( io_addr ) ?
+ cpu_io->Io.Read : cpu_io->Mem.Read );
+
+ if ( ( efirc = read ( cpu_io, efi_width ( size ),
+ ( intptr_t ) io_addr, count,
+ ( void * ) data ) ) != 0 ) {
+ DBG ( "EFI I/O string read at %p failed: %lx\n",
+ io_addr, efirc );
+ }
+}
+
+/**
+ * String write to device
+ *
+ * @v io_addr I/O address
+ * @v data Data buffer
+ * @v size Size of values
+ * @v count Number of values to write
+ */
+void efi_iowrites ( volatile void *io_addr, const void *data,
+ size_t size, unsigned int count ) {
+ EFI_CPU_IO_PROTOCOL_IO_MEM write;
+ EFI_STATUS efirc;
+
+ write = ( IS_PORT_ADDRESS ( io_addr ) ?
+ cpu_io->Io.Write : cpu_io->Mem.Write );
+
+ if ( ( efirc = write ( cpu_io, efi_width ( size ),
+ ( intptr_t ) io_addr, count,
+ ( void * ) data ) ) != 0 ) {
+ DBG ( "EFI I/O write at %p failed: %lx\n",
+ io_addr, efirc );
+ }
+}
+
+/**
+ * Wait for I/O-mapped operation to complete
+ *
+ */
+static void efi_iodelay ( void ) {
+ /* Write to non-existent port. Probably x86-only. */
+ outb ( 0, 0x80 );
+}
+
+PROVIDE_IOAPI_INLINE ( efi, phys_to_bus );
+PROVIDE_IOAPI_INLINE ( efi, bus_to_phys );
+PROVIDE_IOAPI_INLINE ( efi, ioremap );
+PROVIDE_IOAPI_INLINE ( efi, iounmap );
+PROVIDE_IOAPI_INLINE ( efi, io_to_bus );
+PROVIDE_IOAPI_INLINE ( efi, readb );
+PROVIDE_IOAPI_INLINE ( efi, readw );
+PROVIDE_IOAPI_INLINE ( efi, readl );
+PROVIDE_IOAPI_INLINE ( efi, readq );
+PROVIDE_IOAPI_INLINE ( efi, writeb );
+PROVIDE_IOAPI_INLINE ( efi, writew );
+PROVIDE_IOAPI_INLINE ( efi, writel );
+PROVIDE_IOAPI_INLINE ( efi, writeq );
+PROVIDE_IOAPI_INLINE ( efi, inb );
+PROVIDE_IOAPI_INLINE ( efi, inw );
+PROVIDE_IOAPI_INLINE ( efi, inl );
+PROVIDE_IOAPI_INLINE ( efi, outb );
+PROVIDE_IOAPI_INLINE ( efi, outw );
+PROVIDE_IOAPI_INLINE ( efi, outl );
+PROVIDE_IOAPI_INLINE ( efi, insb );
+PROVIDE_IOAPI_INLINE ( efi, insw );
+PROVIDE_IOAPI_INLINE ( efi, insl );
+PROVIDE_IOAPI_INLINE ( efi, outsb );
+PROVIDE_IOAPI_INLINE ( efi, outsw );
+PROVIDE_IOAPI_INLINE ( efi, outsl );
+PROVIDE_IOAPI ( efi, iodelay, efi_iodelay );
+PROVIDE_IOAPI_INLINE ( efi, mb );
diff --git a/src/interface/efi/efi_pci.c b/src/interface/efi/efi_pci.c
new file mode 100644
index 00000000..93408165
--- /dev/null
+++ b/src/interface/efi/efi_pci.c
@@ -0,0 +1,81 @@
+/*
+ * Copyright (C) 2008 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., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#include <errno.h>
+#include <gpxe/pci.h>
+#include <gpxe/efi/efi.h>
+#include <gpxe/efi/Protocol/PciRootBridgeIo.h>
+
+/** @file
+ *
+ * gPXE PCI I/O API for EFI
+ *
+ */
+
+/** PCI root bridge I/O protocol */
+static EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL *efipci;
+EFI_REQUIRE_PROTOCOL ( EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL, &efipci );
+
+static unsigned long efipci_address ( struct pci_device *pci,
+ unsigned long location ) {
+ return EFI_PCI_ADDRESS ( pci->bus, PCI_SLOT ( pci->devfn ),
+ PCI_FUNC ( pci->devfn ),
+ EFIPCI_OFFSET ( location ) );
+}
+
+int efipci_read ( struct pci_device *pci, unsigned long location,
+ void *value ) {
+ EFI_STATUS efirc;
+
+ if ( ( efirc = efipci->Pci.Read ( efipci, EFIPCI_WIDTH ( location ),
+ efipci_address ( pci, location ), 1,
+ value ) ) != 0 ) {
+ DBG ( "EFIPCI config read from %02x:%02x.%x offset %02lx "
+ "failed: %lx\n", pci->bus, PCI_SLOT ( pci->devfn ),
+ PCI_FUNC ( pci->devfn ), EFIPCI_OFFSET ( location ),
+ efirc );
+ return -EIO;
+ }
+
+ return 0;
+}
+
+int efipci_write ( struct pci_device *pci, unsigned long location,
+ unsigned long value ) {
+ EFI_STATUS efirc;
+
+ if ( ( efirc = efipci->Pci.Write ( efipci, EFIPCI_WIDTH ( location ),
+ efipci_address ( pci, location ), 1,
+ &value ) ) != 0 ) {
+ DBG ( "EFIPCI config write to %02x:%02x.%x offset %02lx "
+ "failed: %lx\n", pci->bus, PCI_SLOT ( pci->devfn ),
+ PCI_FUNC ( pci->devfn ), EFIPCI_OFFSET ( location ),
+ efirc );
+ return -EIO;
+ }
+
+ return 0;
+}
+
+PROVIDE_PCIAPI_INLINE ( efi, pci_max_bus );
+PROVIDE_PCIAPI_INLINE ( efi, pci_read_config_byte );
+PROVIDE_PCIAPI_INLINE ( efi, pci_read_config_word );
+PROVIDE_PCIAPI_INLINE ( efi, pci_read_config_dword );
+PROVIDE_PCIAPI_INLINE ( efi, pci_write_config_byte );
+PROVIDE_PCIAPI_INLINE ( efi, pci_write_config_word );
+PROVIDE_PCIAPI_INLINE ( efi, pci_write_config_dword );
diff --git a/src/interface/efi/efi_timer.c b/src/interface/efi/efi_timer.c
new file mode 100644
index 00000000..b4e54a65
--- /dev/null
+++ b/src/interface/efi/efi_timer.c
@@ -0,0 +1,115 @@
+/*
+ * Copyright (C) 2008 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., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#include <limits.h>
+#include <assert.h>
+#include <unistd.h>
+#include <gpxe/timer.h>
+#include <gpxe/efi/efi.h>
+#include <gpxe/efi/Protocol/Cpu.h>
+
+/** @file
+ *
+ * gPXE timer API for EFI
+ *
+ */
+
+/** Scale factor to apply to CPU timer 0
+ *
+ * The timer is scaled down in order to ensure that reasonable values
+ * for "number of ticks" don't exceed the size of an unsigned long.
+ */
+#define EFI_TIMER0_SHIFT 12
+
+/** Calibration time */
+#define EFI_CALIBRATE_DELAY_MS 1
+
+/** CPU protocol */
+static EFI_CPU_ARCH_PROTOCOL *cpu_arch;
+EFI_REQUIRE_PROTOCOL ( EFI_CPU_ARCH_PROTOCOL, &cpu_arch );
+
+/**
+ * Delay for a fixed number of microseconds
+ *
+ * @v usecs Number of microseconds for which to delay
+ */
+static void efi_udelay ( unsigned long usecs ) {
+ EFI_BOOT_SERVICES *bs = efi_systab->BootServices;
+ EFI_STATUS efirc;
+
+ if ( ( efirc = bs->Stall ( usecs ) ) != 0 ) {
+ DBG ( "EFI could not delay for %ldus: %lx\n",
+ usecs, efirc );
+ /* Probably screwed */
+ }
+}
+
+/**
+ * Get current system time in ticks
+ *
+ * @ret ticks Current time, in ticks
+ */
+static unsigned long efi_currticks ( void ) {
+ UINT64 time;
+ EFI_STATUS efirc;
+
+ /* Read CPU timer 0 (TSC) */
+ if ( ( efirc = cpu_arch->GetTimerValue ( cpu_arch, 0, &time,
+ NULL ) ) != 0 ) {
+ DBG ( "EFI could not read CPU timer: %lx\n", efirc );
+ /* Probably screwed */
+ return -1UL;
+ }
+
+ return ( time >> EFI_TIMER0_SHIFT );
+}
+
+/**
+ * Get number of ticks per second
+ *
+ * @ret ticks_per_sec Number of ticks per second
+ */
+static unsigned long efi_ticks_per_sec ( void ) {
+ static unsigned long ticks_per_sec = 0;
+
+ /* Calibrate timer, if necessary. EFI does nominally provide
+ * the timer speed via the (optional) TimerPeriod parameter to
+ * the GetTimerValue() call, but it gets the speed slightly
+ * wrong. By up to three orders of magnitude. Not helpful.
+ */
+ if ( ! ticks_per_sec ) {
+ unsigned long start;
+ unsigned long elapsed;
+
+ DBG ( "Calibrating EFI timer with a %d ms delay\n",
+ EFI_CALIBRATE_DELAY_MS );
+ start = currticks();
+ mdelay ( EFI_CALIBRATE_DELAY_MS );
+ elapsed = ( currticks() - start );
+ ticks_per_sec = ( elapsed * ( 1000 / EFI_CALIBRATE_DELAY_MS ));
+ DBG ( "EFI CPU timer calibrated at %ld ticks in %d ms (%ld "
+ "ticks/sec)\n", elapsed, EFI_CALIBRATE_DELAY_MS,
+ ticks_per_sec );
+ }
+
+ return ticks_per_sec;
+}
+
+PROVIDE_TIMER ( efi, udelay, efi_udelay );
+PROVIDE_TIMER ( efi, currticks, efi_currticks );
+PROVIDE_TIMER ( efi, ticks_per_sec, efi_ticks_per_sec );
diff --git a/src/interface/efi/efi_uaccess.c b/src/interface/efi/efi_uaccess.c
new file mode 100644
index 00000000..1c54c031
--- /dev/null
+++ b/src/interface/efi/efi_uaccess.c
@@ -0,0 +1,37 @@
+/*
+ * Copyright (C) 2008 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., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#include <gpxe/uaccess.h>
+#include <gpxe/efi/efi.h>
+
+/** @file
+ *
+ * gPXE user access API for EFI
+ *
+ */
+
+PROVIDE_UACCESS_INLINE ( efi, phys_to_user );
+PROVIDE_UACCESS_INLINE ( efi, user_to_phys );
+PROVIDE_UACCESS_INLINE ( efi, virt_to_user );
+PROVIDE_UACCESS_INLINE ( efi, user_to_virt );
+PROVIDE_UACCESS_INLINE ( efi, userptr_add );
+PROVIDE_UACCESS_INLINE ( efi, memcpy_user );
+PROVIDE_UACCESS_INLINE ( efi, memmove_user );
+PROVIDE_UACCESS_INLINE ( efi, memset_user );
+PROVIDE_UACCESS_INLINE ( efi, strlen_user );
+PROVIDE_UACCESS_INLINE ( efi, memchr_user );
diff --git a/src/interface/efi/efi_umalloc.c b/src/interface/efi/efi_umalloc.c
new file mode 100644
index 00000000..d7357a1d
--- /dev/null
+++ b/src/interface/efi/efi_umalloc.c
@@ -0,0 +1,96 @@
+/*
+ * Copyright (C) 2008 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., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#include <assert.h>
+#include <gpxe/umalloc.h>
+#include <gpxe/efi/efi.h>
+
+/** @file
+ *
+ * gPXE user memory allocation API for EFI
+ *
+ */
+
+/** Equivalent of NOWHERE for user pointers */
+#define UNOWHERE ( ~UNULL )
+
+/**
+ * Reallocate external memory
+ *
+ * @v old_ptr Memory previously allocated by umalloc(), or UNULL
+ * @v new_size Requested size
+ * @ret new_ptr Allocated memory, or UNULL
+ *
+ * Calling realloc() with a new size of zero is a valid way to free a
+ * memory block.
+ */
+static userptr_t efi_urealloc ( userptr_t old_ptr, size_t new_size ) {
+ EFI_BOOT_SERVICES *bs = efi_systab->BootServices;
+ EFI_PHYSICAL_ADDRESS phys_addr;
+ unsigned int new_pages, old_pages;
+ userptr_t new_ptr = UNOWHERE;
+ size_t old_size;
+ EFI_STATUS efirc;
+
+ /* Allocate new memory if necessary. If allocation fails,
+ * return without touching the old block.
+ */
+ if ( new_size ) {
+ new_pages = ( EFI_SIZE_TO_PAGES ( new_size ) + 1 );
+ if ( ( efirc = bs->AllocatePages ( AllocateAnyPages,
+ EfiBootServicesData,
+ new_pages,
+ &phys_addr ) ) != 0 ) {
+ DBG ( "EFI could not allocate %d pages: %lx\n",
+ new_pages, efirc );
+ return UNULL;
+ }
+ assert ( phys_addr != 0 );
+ new_ptr = phys_to_user ( phys_addr + EFI_PAGE_SIZE );
+ copy_to_user ( new_ptr, -EFI_PAGE_SIZE,
+ &new_size, sizeof ( new_size ) );
+ DBG ( "EFI allocated %d pages at %llx\n",
+ new_pages, phys_addr );
+ }
+
+ /* Copy across relevant part of the old data region (if any),
+ * then free it. Note that at this point either (a) new_ptr
+ * is valid, or (b) new_size is 0; either way, the memcpy() is
+ * valid.
+ */
+ if ( old_ptr && ( old_ptr != UNOWHERE ) ) {
+ copy_from_user ( &old_size, old_ptr, -EFI_PAGE_SIZE,
+ sizeof ( old_size ) );
+ memcpy_user ( new_ptr, 0, old_ptr, 0,
+ ( (old_size < new_size) ? old_size : new_size ));
+ old_pages = ( EFI_SIZE_TO_PAGES ( old_size ) + 1 );
+ phys_addr = user_to_phys ( old_ptr, -EFI_PAGE_SIZE );
+ if ( ( efirc = bs->FreePages ( phys_addr, old_pages ) ) != 0 ){
+ DBG ( "EFI could not free %d pages at %llx: %lx\n",
+ old_pages, phys_addr, efirc );
+ /* Not fatal; we have leaked memory but successfully
+ * allocated (if asked to do so).
+ */
+ }
+ DBG ( "EFI freed %d pages at %llx\n", old_pages, phys_addr );
+ }
+
+ return new_ptr;
+}
+
+PROVIDE_UMALLOC ( efi, urealloc, efi_urealloc );
diff --git a/src/util/.gitignore b/src/util/.gitignore
index 98adc2df..7f9d7557 100644
--- a/src/util/.gitignore
+++ b/src/util/.gitignore
@@ -2,3 +2,4 @@ nrv2b
zbin
hijack
prototester
+efilink
diff --git a/src/util/efilink.c b/src/util/efilink.c
new file mode 100644
index 00000000..e21f4a90
--- /dev/null
+++ b/src/util/efilink.c
@@ -0,0 +1,507 @@
+#include <stdint.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include <errno.h>
+#include <bfd.h>
+
+struct bfd_file {
+ bfd *bfd;
+ asymbol **symtab;
+ long symcount;
+};
+
+struct pe_relocs {
+ struct pe_relocs *next;
+ unsigned long start_rva;
+ unsigned int used_relocs;
+ unsigned int total_relocs;
+ uint16_t *relocs;
+};
+
+/**
+ * Allocate memory
+ *
+ * @v len Length of memory to allocate
+ * @ret ptr Pointer to allocated memory
+ */
+static void * xmalloc ( size_t len ) {
+ void *ptr;
+
+ ptr = malloc ( len );
+ if ( ! ptr ) {
+ fprintf ( stderr, "Could not allocate %zd bytes\n", len );
+ exit ( 1 );
+ }
+
+ return ptr;
+}
+
+/**
+ * Generate entry in PE relocation table
+ *
+ * @v pe_reltab PE relocation table
+ * @v rva RVA
+ * @v size Size of relocation entry
+ */
+static void generate_pe_reloc ( struct pe_relocs **pe_reltab,
+ unsigned long rva, size_t size ) {
+ unsigned long start_rva;
+ uint16_t reloc;
+ struct pe_relocs *pe_rel;
+ uint16_t *relocs;
+
+ /* Construct */
+ start_rva = ( rva & ~0xfff );
+ reloc = ( rva & 0xfff );
+ switch ( size ) {
+ case 4:
+ reloc |= 0x3000;
+ break;
+ case 2:
+ reloc |= 0x2000;
+ break;
+ default:
+ fprintf ( stderr, "Unsupported relocation size %zd\n", size );
+ exit ( 1 );
+ }
+
+ /* Locate or create PE relocation table */
+ for ( pe_rel = *pe_reltab ; pe_rel ; pe_rel = pe_rel->next ) {
+ if ( pe_rel->start_rva == start_rva )
+ break;
+ }
+ if ( ! pe_rel ) {
+ pe_rel = xmalloc ( sizeof ( *pe_rel ) );
+ memset ( pe_rel, 0, sizeof ( *pe_rel ) );
+ pe_rel->next = *pe_reltab;
+ *pe_reltab = pe_rel;
+ pe_rel->start_rva = start_rva;
+ }
+
+ /* Expand relocation list if necessary */
+ if ( pe_rel->used_relocs < pe_rel->total_relocs ) {
+ relocs = pe_rel->relocs;
+ } else {
+ pe_rel->total_relocs = ( pe_rel->total_relocs ?
+ ( pe_rel->total_relocs * 2 ) : 256 );
+ relocs = xmalloc ( pe_rel->total_relocs *
+ sizeof ( pe_rel->relocs[0] ) );
+ memset ( relocs, 0,
+ pe_rel->total_relocs * sizeof ( pe_rel->relocs[0] ) );
+ memcpy ( relocs, pe_rel->relocs,
+ pe_rel->used_relocs * sizeof ( pe_rel->relocs[0] ) );
+ free ( pe_rel->relocs );
+ pe_rel->relocs = relocs;
+ }
+
+ /* Store relocation */
+ pe_rel->relocs[ pe_rel->used_relocs++ ] = reloc;
+}
+
+/**
+ * Calculate size of binary PE relocation table
+ *
+ * @v pe_reltab PE relocation table
+ * @v buffer Buffer to contain binary table, or NULL
+ * @ret size Size of binary table
+ */
+static size_t output_pe_reltab ( struct pe_relocs *pe_reltab,
+ void *buffer ) {
+ struct pe_relocs *pe_rel;
+ unsigned int num_relocs;
+ size_t size;
+ size_t total_size = 0;
+
+ for ( pe_rel = pe_reltab ; pe_rel ; pe_rel = pe_rel->next ) {
+ num_relocs = ( ( pe_rel->used_relocs + 1 ) & ~1 );
+ size = ( sizeof ( uint32_t ) /* VirtualAddress */ +
+ sizeof ( uint32_t ) /* SizeOfBlock */ +
+ ( num_relocs * sizeof ( uint16_t ) ) );
+ if ( buffer ) {
+ *( (uint32_t *) ( buffer + total_size + 0 ) )
+ = pe_rel->start_rva;
+ *( (uint32_t *) ( buffer + total_size + 4 ) ) = size;
+ memcpy ( ( buffer + total_size + 8 ), pe_rel->relocs,
+ ( num_relocs * sizeof ( uint16_t ) ) );
+ }
+ total_size += size;
+ }
+
+ return total_size;
+}
+
+/**
+ * Read symbol table
+ *
+ * @v bfd BFD file
+ */
+static void read_symtab ( struct bfd_file *bfd ) {
+ long symtab_size;
+
+ /* Get symbol table size */
+ symtab_size = bfd_get_symtab_upper_bound ( bfd->bfd );
+ if ( symtab_size < 0 ) {
+ bfd_perror ( "Could not get symbol table upper bound" );
+ exit ( 1 );
+ }
+
+ /* Allocate and read symbol table */
+ bfd->symtab = xmalloc ( symtab_size );
+ bfd->symcount = bfd_canonicalize_symtab ( bfd->bfd, bfd->symtab );
+ if ( bfd->symcount < 0 ) {
+ bfd_perror ( "Cannot read symbol table" );
+ exit ( 1 );
+ }
+}
+
+/**
+ * Read relocation table
+ *
+ * @v bfd BFD file
+ * @v section Section
+ * @v symtab Symbol table
+ * @ret reltab Relocation table
+ */
+static arelent ** read_reltab ( struct bfd_file *bfd, asection *section ) {
+ long reltab_size;
+ arelent **reltab;
+ long numrels;
+
+ /* Get relocation table size */
+ reltab_size = bfd_get_reloc_upper_bound ( bfd->bfd, section );
+ if ( reltab_size < 0 ) {
+ bfd_perror ( "Could not get relocation table upper bound" );
+ exit ( 1 );
+ }
+
+ /* Allocate and read relocation table */
+ reltab = xmalloc ( reltab_size );
+ numrels = bfd_canonicalize_reloc ( bfd->bfd, section, reltab,
+ bfd->symtab );
+ if ( numrels < 0 ) {
+ bfd_perror ( "Cannot read relocation table" );
+ exit ( 1 );
+ }
+
+ return reltab;
+}
+
+
+/**
+ * Open input BFD file
+ *
+ * @v filename File name
+ * @ret ibfd BFD file
+ */
+static struct bfd_file * open_input_bfd ( const char *filename ) {
+ struct bfd_file *ibfd;
+
+ /* Create BFD file */
+ ibfd = xmalloc ( sizeof ( *ibfd ) );
+ memset ( ibfd, 0, sizeof ( *ibfd ) );
+
+ /* Open the file */
+ ibfd->bfd = bfd_openr ( filename, NULL );
+ if ( ! ibfd->bfd ) {
+ fprintf ( stderr, "Cannot open %s: ", filename );
+ bfd_perror ( NULL );
+ exit ( 1 );
+ }
+
+ /* The call to bfd_check_format() must be present, otherwise
+ * we get a segfault from later BFD calls.
+ */
+ if ( bfd_check_format ( ibfd->bfd, bfd_object ) < 0 ) {
+ fprintf ( stderr, "%s is not an object file\n", filename );
+ exit ( 1 );
+ }
+
+ /* Read symbols and relocation entries */
+ read_symtab ( ibfd );
+
+ return ibfd;
+}
+
+/**
+ * Open output BFD file
+ *
+ * @v filename File name
+ * @v ibfd Input BFD file
+ * @ret obfd BFD file
+ */
+static struct bfd_file * open_output_bfd ( const char *filename,
+ struct bfd_file *ibfd ) {
+ struct bfd_file *obfd;
+ asection *isection;
+ asection *osection;
+
+ /*
+ * Most of this code is based on what objcopy.c does.
+ *
+ */
+
+ /* Create BFD file */
+ obfd = xmalloc ( sizeof ( *obfd ) );
+ memset ( obfd, 0, sizeof ( *obfd ) );
+
+ /* Open the file */
+ obfd->bfd = bfd_openw ( filename, ibfd->bfd->xvec->name );
+ if ( ! obfd->bfd ) {
+ fprintf ( stderr, "Cannot open %s: ", filename );
+ bfd_perror ( NULL );
+ exit ( 1 );
+ }
+
+ /* Copy per-file data */
+ if ( ! bfd_set_arch_mach ( obfd->bfd, bfd_get_arch ( ibfd->bfd ),
+ bfd_get_mach ( ibfd->bfd ) ) ) {
+ bfd_perror ( "Cannot copy architecture" );
+ exit ( 1 );
+ }
+ if ( ! bfd_set_format ( obfd->bfd, bfd_get_format ( ibfd->bfd ) ) ) {
+ bfd_perror ( "Cannot copy format" );
+ exit ( 1 );
+ }
+ if ( ! bfd_copy_private_header_data ( ibfd->bfd, obfd->bfd ) ) {
+ bfd_perror ( "Cannot copy private header data" );
+ exit ( 1 );
+ }
+
+ /* Create sections */
+ for ( isection = ibfd->bfd->sections ; isection ;
+ isection = isection->next ) {
+ osection = bfd_make_section_anyway ( obfd->bfd,
+ isection->name );
+ if ( ! osection ) {
+ bfd_perror ( "Cannot create section" );
+ exit ( 1 );
+ }
+ if ( ! bfd_set_section_flags ( obfd->bfd, osection,
+ isection->flags ) ) {
+ bfd_perror ( "Cannot copy section flags" );
+ exit ( 1 );
+ }
+ if ( ! bfd_set_section_size ( obfd->bfd, osection,
+ bfd_section_size ( ibfd->bfd, isection ) ) ) {
+ bfd_perror ( "Cannot copy section size" );
+ exit ( 1 );
+ }
+ if ( ! bfd_set_section_vma ( obfd->bfd, osection,
+ bfd_section_vma ( ibfd->bfd, isection ) ) ) {
+ bfd_perror ( "Cannot copy section VMA" );
+ exit ( 1 );
+ }
+ osection->lma = bfd_section_lma ( ibfd->bfd, isection );
+ if ( ! bfd_set_section_alignment ( obfd->bfd, osection,
+ bfd_section_alignment ( ibfd->bfd, isection ) ) ) {
+ bfd_perror ( "Cannot copy section alignment" );
+ exit ( 1 );
+ }
+ osection->entsize = isection->entsize;
+ isection->output_section = osection;
+ isection->output_offset = 0;
+ if ( ! bfd_copy_private_section_data ( ibfd->bfd, isection,
+ obfd->bfd, osection ) ){
+ bfd_perror ( "Cannot copy section private data" );
+ exit ( 1 );
+ }
+ }
+
+ /* Copy symbol table */
+ bfd_set_symtab ( obfd->bfd, ibfd->symtab, ibfd->symcount );
+ obfd->symtab = ibfd->symtab;
+
+ return obfd;
+}
+
+/**
+ * Copy section from input BFD file to output BFD file
+ *
+ * @v obfd Output BFD file
+ * @v ibfd Input BFD file
+ * @v section Section
+ */
+static void copy_bfd_section ( struct bfd_file *obfd, struct bfd_file *ibfd,
+ asection *isection ) {
+ size_t size;
+ void *buf;
+ arelent **reltab;
+ arelent **rel;
+ char *errmsg;
+
+ /* Read in original section */
+ size = bfd_section_size ( ibfd->bfd, isection );
+ if ( ! size )
+ return;
+ buf = xmalloc ( size );
+ if ( ( ! bfd_get_section_contents ( ibfd->bfd, isection,
+ buf, 0, size ) ) ) {
+ fprintf ( stderr, "Cannot read section %s: ", isection->name );
+ bfd_perror ( NULL );
+ exit ( 1 );
+ }
+
+ /* Perform relocations. We do this here, rather than letting
+ * ld do it for us when creating the input ELF file, so that
+ * we can change symbol values as a result of having created
+ * the .reloc section.
+ */
+ reltab = read_reltab ( ibfd, isection );
+ for ( rel = reltab ; *rel ; rel++ ) {
+ bfd_perform_relocation ( ibfd->bfd, *rel, buf, isection,
+ NULL, &errmsg );
+ }
+ free ( reltab );
+
+ /* Write out modified section */
+ if ( ( ! bfd_set_section_contents ( obfd->bfd,
+ isection->output_section,
+ buf, 0, size ) ) ) {
+ fprintf ( stderr, "Cannot write section %s: ",
+ isection->output_section->name );
+ bfd_perror ( NULL );
+ exit ( 1 );
+ }
+
+ free ( buf );
+}
+
+/**
+ * Process relocation record
+ *
+ * @v section Section
+ * @v rel Relocation entry
+ * @v pe_reltab PE relocation table to fill in
+ */
+static void process_reloc ( asection *section, arelent *rel,
+ struct pe_relocs **pe_reltab ) {
+ reloc_howto_type *howto = rel->howto;
+ asymbol *sym = *(rel->sym_ptr_ptr);
+ unsigned long offset = ( section->lma + rel->address );
+
+ if ( bfd_is_abs_section ( sym->section ) ) {
+ /* Skip absolute symbols; the symbol value won't
+ * change when the object is loaded.
+ */
+ } else if ( strcmp ( howto->name, "R_386_32" ) == 0 ) {
+ /* Generate a 4-byte PE relocation */
+ generate_pe_reloc ( pe_reltab, offset, 4 );
+ } else if ( strcmp ( howto->name, "R_386_16" ) == 0 ) {
+ /* Generate a 2-byte PE relocation */
+ generate_pe_reloc ( pe_reltab, offset, 2 );
+ } else if ( strcmp ( howto->name, "R_386_PC32" ) == 0 ) {
+ /* Skip PC-relative relocations; all relative offsets
+ * remain unaltered when the object is loaded.
+ */
+ } else {
+ fprintf ( stderr, "Unrecognised relocation type %s\n",
+ howto->name );
+ exit ( 1 );
+ }
+}
+
+/**
+ * Create .reloc section
+ *
+ * obfd Output BFD file
+ * section .reloc section in output file
+ * pe_reltab PE relocation table
+ */
+static void create_reloc_section ( struct bfd_file *obfd, asection *section,
+ struct pe_relocs *pe_reltab ) {
+ size_t raw_size;
+ size_t size;
+ size_t old_size;
+ void *buf;
+ asymbol **sym;
+
+ /* Build binary PE relocation table */
+ raw_size = output_pe_reltab ( pe_reltab, NULL );
+ size = ( ( raw_size + 31 ) & ~31 );
+ buf = xmalloc ( size );
+ memset ( buf, 0, size );
+ output_pe_reltab ( pe_reltab, buf );
+
+ /* Write .reloc section */
+ old_size = bfd_section_size ( obfd->bfd, section );
+ if ( ! bfd_set_section_size ( obfd->bfd, section, size ) ) {
+ bfd_perror ( "Cannot resize .reloc section" );
+ exit ( 1 );
+ }
+ if ( ! bfd_set_section_contents ( obfd->bfd, section,
+ buf, 0, size ) ) {
+ bfd_perror ( "Cannot set .reloc section contents" );
+ exit ( 1 );
+ }
+
+ /* Update symbols pertaining to the relocation directory */
+ for ( sym = obfd->symtab ; *sym ; sym++ ) {
+ if ( strcmp ( (*sym)->name, "_reloc_memsz" ) == 0 ) {
+ (*sym)->value = size;
+ } else if ( strcmp ( (*sym)->name, "_reloc_filesz" ) == 0 ){
+ (*sym)->value = raw_size;
+ } else if ( strcmp ( (*sym)->name, "_filesz" ) == 0 ) {
+ (*sym)->value += ( size - old_size );
+ }
+ }
+}
+
+int main ( int argc, const char *argv[] ) {
+ const char *iname;
+ const char *oname;
+ struct bfd_file *ibfd;
+ struct bfd_file *obfd;
+ asection *section;
+ arelent **reltab;
+ arelent **rel;
+ struct pe_relocs *pe_reltab = NULL;
+ asection *reloc_section;
+
+ /* Initialise libbfd */
+ bfd_init();
+
+ /* Identify intput and output files */
+ if ( argc != 3 ) {
+ fprintf ( stderr, "Syntax: %s infile outfile\n", argv[0] );
+ exit ( 1 );
+ }
+ iname = argv[1];
+ oname = argv[2];
+
+ /* Open BFD files */
+ ibfd = open_input_bfd ( iname );
+ obfd = open_output_bfd ( oname, ibfd );
+
+ /* Process relocations in all sections */
+ for ( section = ibfd->bfd->sections ; section ;
+ section = section->next ) {
+ reltab = read_reltab ( ibfd, section );
+ for ( rel = reltab ; *rel ; rel++ ) {
+ process_reloc ( section, *rel, &pe_reltab );
+ }
+ free ( reltab );
+ }
+
+ /* Create modified .reloc section */
+ reloc_section = bfd_get_section_by_name ( obfd->bfd, ".reloc" );
+ if ( ! reloc_section ) {
+ fprintf ( stderr, "Cannot find .reloc section\n" );
+ exit ( 1 );
+ }
+ create_reloc_section ( obfd, reloc_section, pe_reltab );
+
+ /* Copy other section contents */
+ for ( section = ibfd->bfd->sections ; section ;
+ section = section->next ) {
+ if ( section->output_section != reloc_section )
+ copy_bfd_section ( obfd, ibfd, section );
+ }
+
+ /* Write out files and clean up */
+ bfd_close ( obfd->bfd );
+ bfd_close ( ibfd->bfd );
+
+ return 0;
+}