david/ipxe
david
/
ipxe
Archived
1
0
Fork 0

[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.
This commit is contained in:
Michael Brown 2008-10-12 01:55:55 +01:00
parent 54c024e0af
commit 81d92c6d34
40 changed files with 4781 additions and 1 deletions

View File

@ -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

View File

@ -693,6 +693,15 @@ $(ZBIN) : util/zbin.c util/nrv2b.c $(MAKEDEPS)
$(Q)$(HOST_CC) -O2 -o $@ $<
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

View File

@ -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.

View File

@ -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 $< $@

View File

@ -8,5 +8,6 @@
*/
#include <gpxe/bios_nap.h>
#include <gpxe/efi/efix86_nap.h>
#endif /* _BITS_MAP_H */

View File

@ -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 */

View File

@ -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 );

View File

@ -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

View File

@ -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 );
}

20
src/config/defaults/efi.h Normal file
View File

@ -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 */

View File

@ -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

View File

@ -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

106
src/image/efi_image.c Normal file
View File

@ -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,
};

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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 */

View File

@ -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 */

View File

@ -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 */

View File

@ -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 */

View File

@ -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 */

View File

@ -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 */

View File

@ -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 )
/** @} */

View File

@ -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 */
/** @} */

View File

@ -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>

View File

@ -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>

View File

@ -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>

View File

@ -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>

View File

@ -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>

View File

@ -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,
};

View File

@ -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 () );
}

201
src/interface/efi/efi_io.c Normal file
View File

@ -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 );

View File

@ -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 );

View File

@ -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 );

View File

@ -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 );

View File

@ -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 );

1
src/util/.gitignore vendored
View File

@ -2,3 +2,4 @@ nrv2b
zbin
hijack
prototester
efilink

507
src/util/efilink.c Normal file
View File

@ -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;
}