Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Browse files
Browse the repository at this point in the history
[efi] Allow for interception of boot services calls by loaded image
When building with DEBUG=efi_wrap, print details of calls made by the loaded image to selected boot services functions. Signed-off-by: Michael Brown <mcb30@ipxe.org>
- Loading branch information
Showing
3 changed files
with
257 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,16 @@ | ||
#ifndef _IPXE_EFI_WRAP_H | ||
#define _IPXE_EFI_WRAP_H | ||
|
||
/** @file | ||
* | ||
* EFI driver interface | ||
*/ | ||
|
||
FILE_LICENCE ( GPL2_OR_LATER ); | ||
|
||
#include <ipxe/efi/efi.h> | ||
#include <ipxe/efi/Protocol/LoadedImage.h> | ||
|
||
extern void efi_wrap ( EFI_HANDLE handle, EFI_LOADED_IMAGE_PROTOCOL *loaded ); | ||
|
||
#endif /* _IPXE_EFI_WRAP_H */ |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,237 @@ | ||
/* | ||
* Copyright (C) 2014 Michael Brown <mbrown@fensystems.co.uk>. | ||
* | ||
* This program is free software; you can redistribute it and/or | ||
* modify it under the terms of the GNU General Public License as | ||
* published by the Free Software Foundation; either version 2 of the | ||
* License, or any later version. | ||
* | ||
* This program is distributed in the hope that it will be useful, but | ||
* WITHOUT ANY WARRANTY; without even the implied warranty of | ||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | ||
* General Public License for more details. | ||
* | ||
* You should have received a copy of the GNU General Public License | ||
* along with this program; if not, write to the Free Software | ||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA | ||
* 02110-1301, USA. | ||
*/ | ||
|
||
FILE_LICENCE ( GPL2_OR_LATER ); | ||
|
||
/** | ||
* @file | ||
* | ||
* EFI image wrapping | ||
* | ||
*/ | ||
|
||
#include <string.h> | ||
#include <stdio.h> | ||
#include <ipxe/efi/efi.h> | ||
#include <ipxe/efi/Protocol/LoadedImage.h> | ||
#include <ipxe/efi/efi_wrap.h> | ||
|
||
/** EFI system table wrapper */ | ||
static EFI_SYSTEM_TABLE efi_systab_wrapper; | ||
|
||
/** EFI boot services table wrapper */ | ||
static EFI_BOOT_SERVICES efi_bs_wrapper; | ||
|
||
/** Colour for debug messages */ | ||
#define colour &efi_systab_wrapper | ||
|
||
/** | ||
* Convert EFI status code to text | ||
* | ||
* @v efirc EFI status code | ||
* @ret text EFI status code text | ||
*/ | ||
static const char * efi_status ( EFI_STATUS efirc ) { | ||
static char buf[ 19 /* "0xXXXXXXXXXXXXXXXX" + NUL */ ]; | ||
|
||
switch ( efirc ) { | ||
case EFI_SUCCESS : return "0"; | ||
case EFI_LOAD_ERROR : return "LOAD_ERROR"; | ||
case EFI_INVALID_PARAMETER : return "INVALID_PARAMETER"; | ||
case EFI_UNSUPPORTED : return "UNSUPPORTED"; | ||
case EFI_BAD_BUFFER_SIZE : return "BAD_BUFFER_SIZE"; | ||
case EFI_BUFFER_TOO_SMALL : return "BUFFER_TOO_SMALL"; | ||
case EFI_NOT_READY : return "NOT_READY"; | ||
case EFI_DEVICE_ERROR : return "DEVICE_ERROR"; | ||
case EFI_WRITE_PROTECTED : return "WRITE_PROTECTED"; | ||
case EFI_OUT_OF_RESOURCES : return "OUT_OF_RESOURCES"; | ||
case EFI_VOLUME_CORRUPTED : return "VOLUME_CORRUPTED"; | ||
case EFI_VOLUME_FULL : return "VOLUME_FULL"; | ||
case EFI_NO_MEDIA : return "NO_MEDIA"; | ||
case EFI_MEDIA_CHANGED : return "MEDIA_CHANGED"; | ||
case EFI_NOT_FOUND : return "NOT_FOUND"; | ||
case EFI_ACCESS_DENIED : return "ACCESS_DENIED"; | ||
case EFI_NO_RESPONSE : return "NO_RESPONSE"; | ||
case EFI_NO_MAPPING : return "NO_MAPPING"; | ||
case EFI_TIMEOUT : return "TIMEOUT"; | ||
case EFI_NOT_STARTED : return "NOT_STARTED"; | ||
case EFI_ALREADY_STARTED : return "ALREADY_STARTED"; | ||
case EFI_ABORTED : return "ABORTED"; | ||
case EFI_ICMP_ERROR : return "ICMP_ERROR"; | ||
case EFI_TFTP_ERROR : return "TFTP_ERROR"; | ||
case EFI_PROTOCOL_ERROR : return "PROTOCOL_ERROR"; | ||
case EFI_INCOMPATIBLE_VERSION : return "INCOMPATIBLE_VERSION"; | ||
case EFI_SECURITY_VIOLATION : return "SECURITY_VIOLATION"; | ||
case EFI_CRC_ERROR : return "CRC_ERROR"; | ||
case EFI_END_OF_MEDIA : return "END_OF_MEDIA"; | ||
case EFI_END_OF_FILE : return "END_OF_FILE"; | ||
case EFI_INVALID_LANGUAGE : return "INVALID_LANGUAGE"; | ||
case EFI_COMPROMISED_DATA : return "COMPROMISED_DATA"; | ||
case EFI_WARN_UNKNOWN_GLYPH : return "WARN_UNKNOWN_GLYPH"; | ||
case EFI_WARN_DELETE_FAILURE : return "WARN_DELETE_FAILURE"; | ||
case EFI_WARN_WRITE_FAILURE : return "WARN_WRITE_FAILURE"; | ||
case EFI_WARN_BUFFER_TOO_SMALL : return "WARN_BUFFER_TOO_SMALL"; | ||
case EFI_WARN_STALE_DATA : return "WARN_STALE_DATA"; | ||
default: | ||
snprintf ( buf, sizeof ( buf ), "%#lx", | ||
( unsigned long ) efirc ); | ||
return buf; | ||
} | ||
} | ||
|
||
/** | ||
* Wrap HandleProtocol() | ||
* | ||
*/ | ||
static EFI_STATUS EFIAPI | ||
efi_handle_protocol_wrapper ( EFI_HANDLE handle, EFI_GUID *protocol, | ||
VOID **interface ) { | ||
EFI_BOOT_SERVICES *bs = efi_systab->BootServices; | ||
void *retaddr = __builtin_return_address ( 0 ); | ||
EFI_STATUS efirc; | ||
|
||
DBGC ( colour, "HandleProtocol ( %p %s, %s, ... ) ", handle, | ||
efi_handle_devpath_text ( handle ), efi_guid_ntoa ( protocol ) ); | ||
efirc = bs->HandleProtocol ( handle, protocol, interface ); | ||
DBGC ( colour, "= %s ( %p ) -> %p\n", | ||
efi_status ( efirc ), *interface, retaddr ); | ||
return efirc; | ||
} | ||
|
||
/** | ||
* Wrap LocateHandle() | ||
* | ||
*/ | ||
static EFI_STATUS EFIAPI | ||
efi_locate_handle_wrapper ( EFI_LOCATE_SEARCH_TYPE search_type, | ||
EFI_GUID *protocol, VOID *search_key, | ||
UINTN *buffer_size, EFI_HANDLE *buffer ) { | ||
EFI_BOOT_SERVICES *bs = efi_systab->BootServices; | ||
void *retaddr = __builtin_return_address ( 0 ); | ||
EFI_STATUS efirc; | ||
|
||
DBGC ( colour, "LocateHandle ( %d, %s, ..., %zd, ... ) ", search_type, | ||
efi_guid_ntoa ( protocol ), ( ( size_t ) *buffer_size ) ); | ||
efirc = bs->LocateHandle ( search_type, protocol, search_key, | ||
buffer_size, buffer ); | ||
DBGC ( colour, "= %s ( %zd ) -> %p\n", | ||
efi_status ( efirc ), ( ( size_t ) *buffer_size ), retaddr ); | ||
return efirc; | ||
} | ||
|
||
/** | ||
* Wrap LocateDevicePath() | ||
* | ||
*/ | ||
static EFI_STATUS EFIAPI | ||
efi_locate_device_path_wrapper ( EFI_GUID *protocol, | ||
EFI_DEVICE_PATH_PROTOCOL **device_path, | ||
EFI_HANDLE *device ) { | ||
EFI_BOOT_SERVICES *bs = efi_systab->BootServices; | ||
void *retaddr = __builtin_return_address ( 0 ); | ||
EFI_STATUS efirc; | ||
|
||
DBGC ( colour, "LocateDevicePath ( %s, %s, ... ) ", | ||
efi_guid_ntoa ( protocol ), efi_devpath_text ( *device_path ) ); | ||
efirc = bs->LocateDevicePath ( protocol, device_path, device ); | ||
DBGC ( colour, "= %s ( %p, ", | ||
efi_status ( efirc ), efi_devpath_text ( *device_path ) ); | ||
DBGC ( colour, "%p %s ) -> %p\n", | ||
*device, efi_handle_devpath_text ( *device ), retaddr ); | ||
return efirc; | ||
} | ||
|
||
/** | ||
* Wrap OpenProtocol() | ||
* | ||
*/ | ||
static EFI_STATUS EFIAPI | ||
efi_open_protocol_wrapper ( EFI_HANDLE handle, EFI_GUID *protocol, | ||
VOID **interface, EFI_HANDLE agent_handle, | ||
EFI_HANDLE controller_handle, UINT32 attributes ) { | ||
EFI_BOOT_SERVICES *bs = efi_systab->BootServices; | ||
void *retaddr = __builtin_return_address ( 0 ); | ||
EFI_STATUS efirc; | ||
|
||
DBGC ( colour, "OpenProtocol ( %p %s, %s, ..., ", handle, | ||
efi_handle_devpath_text ( handle ), efi_guid_ntoa ( protocol ) ); | ||
DBGC ( colour, "%p %s, ", agent_handle, | ||
efi_handle_devpath_text ( agent_handle ) ); | ||
DBGC ( colour, "%p %s, %#x ) ", controller_handle, | ||
efi_handle_devpath_text ( controller_handle ), attributes ); | ||
efirc = bs->OpenProtocol ( handle, protocol, interface, agent_handle, | ||
controller_handle, attributes ); | ||
DBGC ( colour, "= %s ( %p ) -> %p\n", | ||
efi_status ( efirc ), *interface, retaddr ); | ||
return efirc; | ||
} | ||
|
||
/** | ||
* Wrap LocateProtocol() | ||
* | ||
*/ | ||
static EFI_STATUS EFIAPI | ||
efi_locate_protocol_wrapper ( EFI_GUID *protocol, VOID *registration, | ||
VOID **interface ) { | ||
EFI_BOOT_SERVICES *bs = efi_systab->BootServices; | ||
void *retaddr = __builtin_return_address ( 0 ); | ||
EFI_STATUS efirc; | ||
|
||
DBGC ( colour, "LocateProtocol ( %s, %p, ... ) ", | ||
efi_guid_ntoa ( protocol ), registration ); | ||
efirc = bs->LocateProtocol ( protocol, registration, interface ); | ||
DBGC ( colour, "= %s ( %p ) -> %p\n", | ||
efi_status ( efirc ), *interface, retaddr ); | ||
return efirc; | ||
} | ||
|
||
/** | ||
* Wrap the calls made by a loaded image | ||
* | ||
* @v handle Image handle | ||
* @v loaded Loaded image protocol | ||
*/ | ||
void efi_wrap ( EFI_HANDLE handle, EFI_LOADED_IMAGE_PROTOCOL *loaded ) { | ||
EFI_BOOT_SERVICES *bs = efi_systab->BootServices; | ||
|
||
/* Do nothing unless debugging is enabled */ | ||
if ( ! DBG_LOG ) | ||
return; | ||
|
||
/* Populate table wrappers */ | ||
memcpy ( &efi_systab_wrapper, efi_systab, | ||
sizeof ( efi_systab_wrapper ) ); | ||
memcpy ( &efi_bs_wrapper, bs, sizeof ( efi_bs_wrapper ) ); | ||
efi_systab_wrapper.BootServices = &efi_bs_wrapper; | ||
efi_bs_wrapper.HandleProtocol = efi_handle_protocol_wrapper; | ||
efi_bs_wrapper.LocateHandle = efi_locate_handle_wrapper; | ||
efi_bs_wrapper.LocateDevicePath = efi_locate_device_path_wrapper; | ||
efi_bs_wrapper.OpenProtocol = efi_open_protocol_wrapper; | ||
efi_bs_wrapper.LocateProtocol = efi_locate_protocol_wrapper; | ||
|
||
/* Provide system table wrapper to image */ | ||
loaded->SystemTable = &efi_systab_wrapper; | ||
DBGC ( colour, "Wrapped image %p %s at base %p\n", handle, | ||
efi_handle_devpath_text ( handle ), loaded->ImageBase ); | ||
DBGC ( colour, "Parent image %p %s\n", loaded->ParentHandle, | ||
efi_handle_devpath_text ( loaded->ParentHandle ) ); | ||
DBGC ( colour, "Device %p %s ", loaded->DeviceHandle, | ||
efi_handle_devpath_text ( loaded->DeviceHandle ) ); | ||
DBGC ( colour, "file %s\n", efi_devpath_text ( loaded->FilePath ) ); | ||
} |