mirror of https://github.com/ipxe/ipxe.git
[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.pull/1/head
parent
54c024e0af
commit
81d92c6d34
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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.
|
||||
|
|
|
@ -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 $< $@
|
|
@ -8,5 +8,6 @@
|
|||
*/
|
||||
|
||||
#include <gpxe/bios_nap.h>
|
||||
#include <gpxe/efi/efix86_nap.h>
|
||||
|
||||
#endif /* _BITS_MAP_H */
|
||||
|
|
|
@ -0,0 +1,16 @@
|
|||
#ifndef _GPXE_EFIX86_NAP_H
|
||||
#define _GPXE_EFIX86_NAP_H
|
||||
|
||||
/** @file
|
||||
*
|
||||
* EFI CPU sleeping
|
||||
*
|
||||
*/
|
||||
|
||||
#ifdef NAP_EFIX86
|
||||
#define NAP_PREFIX_efix86
|
||||
#else
|
||||
#define NAP_PREFIX_efix86 __efix86_
|
||||
#endif
|
||||
|
||||
#endif /* _GPXE_EFIX86_NAP_H */
|
|
@ -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 );
|
|
@ -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
|
|
@ -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 );
|
||||
}
|
|
@ -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 */
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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,
|
||||
};
|
|
@ -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
|
|
@ -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
|
|
@ -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
|
|
@ -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
|
|
@ -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
|
|
@ -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 */
|
||||
|
|
|
@ -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 */
|
|
@ -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 */
|
|
@ -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 */
|
|
@ -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 */
|
|
@ -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 */
|
|
@ -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 )
|
||||
|
||||
/** @} */
|
||||
|
||||
|
|
|
@ -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 */
|
||||
|
||||
/** @} */
|
||||
|
||||
|
|
|
@ -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>
|
||||
|
|
|
@ -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>
|
||||
|
|
|
@ -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>
|
||||
|
|
|
@ -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>
|
||||
|
|
|
@ -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>
|
||||
|
|
|
@ -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,
|
||||
};
|
|
@ -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 () );
|
||||
}
|
|
@ -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 );
|
|
@ -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 );
|
|
@ -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 );
|
|
@ -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 );
|
|
@ -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 );
|
|
@ -2,3 +2,4 @@ nrv2b
|
|||
zbin
|
||||
hijack
|
||||
prototester
|
||||
efilink
|
||||
|
|
|
@ -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;
|
||||
}
|
Loading…
Reference in New Issue