edkII update in preparation of upgrade OC to 0.9.7.
This commit is contained in:
parent
f6fcfeccbd
commit
3fd62f2756
|
@ -28,9 +28,11 @@
|
|||
FLASH_DEFINITION = Clover.fdf
|
||||
!endif
|
||||
|
||||
!ifndef OPENSSL_VERSION
|
||||
DEFINE OPENSSL_VERSION = 1.0.1e
|
||||
!endif
|
||||
!ifndef OPENSSL_VERSION
|
||||
DEFINE OPENSSL_VERSION = 1.0.1e
|
||||
!endif
|
||||
|
||||
!include MdePkg/MdeLibs.dsc.inc
|
||||
|
||||
################################################################################
|
||||
#
|
||||
|
|
|
@ -1294,15 +1294,15 @@ AtaPassThruPassThru (
|
|||
Instance = ATA_PASS_THRU_PRIVATE_DATA_FROM_THIS (This);
|
||||
|
||||
// DBG(L"This->Mode->IoAlign=%d Packet=%x Packet->InDataBuffer=%x\n", This->Mode->IoAlign, (UINTN)Packet, (UINTN)Packet->InDataBuffer);
|
||||
if ((This->Mode->IoAlign > 1) && !IS_ALIGNED(Packet->InDataBuffer, This->Mode->IoAlign)) {
|
||||
if ((This->Mode->IoAlign > 1) && !IS_ALIGNED((UINTN)Packet->InDataBuffer, This->Mode->IoAlign)) {
|
||||
return EFI_INVALID_PARAMETER;
|
||||
}
|
||||
|
||||
if ((This->Mode->IoAlign > 1) && !IS_ALIGNED(Packet->OutDataBuffer, This->Mode->IoAlign)) {
|
||||
if ((This->Mode->IoAlign > 1) && !IS_ALIGNED((UINTN)Packet->OutDataBuffer, This->Mode->IoAlign)) {
|
||||
return EFI_INVALID_PARAMETER;
|
||||
}
|
||||
|
||||
if ((This->Mode->IoAlign > 1) && !IS_ALIGNED(Packet->Asb, This->Mode->IoAlign)) {
|
||||
if ((This->Mode->IoAlign > 1) && !IS_ALIGNED((UINTN)Packet->Asb, This->Mode->IoAlign)) {
|
||||
return EFI_INVALID_PARAMETER;
|
||||
}
|
||||
|
||||
|
@ -2011,17 +2011,17 @@ ExtScsiPassThruPassThru (
|
|||
return EFI_INVALID_PARAMETER;
|
||||
}
|
||||
|
||||
if ((This->Mode->IoAlign > 1) && !IS_ALIGNED(Packet->InDataBuffer, This->Mode->IoAlign)) {
|
||||
if ((This->Mode->IoAlign > 1) && !IS_ALIGNED((UINTN)Packet->InDataBuffer, This->Mode->IoAlign)) {
|
||||
// DBG(L"IN not aligned\n");
|
||||
return EFI_INVALID_PARAMETER;
|
||||
}
|
||||
|
||||
if ((This->Mode->IoAlign > 1) && !IS_ALIGNED(Packet->OutDataBuffer, This->Mode->IoAlign)) {
|
||||
if ((This->Mode->IoAlign > 1) && !IS_ALIGNED((UINTN)Packet->OutDataBuffer, This->Mode->IoAlign)) {
|
||||
// DBG(L"OUT not aligned\n");
|
||||
return EFI_INVALID_PARAMETER;
|
||||
}
|
||||
|
||||
if ((This->Mode->IoAlign > 1) && !IS_ALIGNED(Packet->SenseData, This->Mode->IoAlign)) {
|
||||
if ((This->Mode->IoAlign > 1) && !IS_ALIGNED((UINTN)Packet->SenseData, This->Mode->IoAlign)) {
|
||||
// DBG(L"SenseData not aligned\n");
|
||||
return EFI_INVALID_PARAMETER;
|
||||
}
|
||||
|
|
|
@ -149,7 +149,7 @@ struct _ATA_NONBLOCK_TASK {
|
|||
//
|
||||
#define ATA_ATAPI_TIMEOUT EFI_TIMER_PERIOD_SECONDS(3)
|
||||
|
||||
#define IS_ALIGNED(addr, size) (((UINTN) (addr) & (size - 1)) == 0)
|
||||
//#define IS_ALIGNED(addr, size) (((UINTN) (addr) & (size - 1)) == 0)
|
||||
|
||||
#define ATA_PASS_THRU_PRIVATE_DATA_FROM_THIS(a) \
|
||||
CR (a, \
|
||||
|
|
|
@ -84,7 +84,7 @@
|
|||
#define ATA_TASK_SIGNATURE SIGNATURE_32 ('A', 'T', 'S', 'K')
|
||||
#define ATA_DEVICE_SIGNATURE SIGNATURE_32 ('A', 'B', 'I', 'D')
|
||||
#define ATA_SUB_TASK_SIGNATURE SIGNATURE_32 ('A', 'S', 'T', 'S')
|
||||
#define IS_ALIGNED(addr, size) (((UINTN) (addr) & (size - 1)) == 0)
|
||||
//#define IS_ALIGNED(addr, size) (((UINTN) (addr) & (size - 1)) == 0)
|
||||
|
||||
#define ROUNDUP512(x) (((x) % 512 == 0) ? (x) : ((x) / 512 + 1) * 512)
|
||||
|
||||
|
|
|
@ -1000,7 +1000,7 @@ TrustTransferAtaDevice (
|
|||
// Check the alignment of the incoming buffer prior to invoking underlying ATA PassThru
|
||||
//
|
||||
AtaPassThru = AtaDevice->AtaBusDriverData->AtaPassThru;
|
||||
if ((AtaPassThru->Mode->IoAlign > 1) && !IS_ALIGNED (Buffer, AtaPassThru->Mode->IoAlign)) {
|
||||
if ((AtaPassThru->Mode->IoAlign > 1) && !IS_ALIGNED ((UINTN)Buffer, AtaPassThru->Mode->IoAlign)) {
|
||||
NewBuffer = AllocateAlignedBuffer (AtaDevice, TransferLength);
|
||||
if (NewBuffer == NULL) {
|
||||
return EFI_OUT_OF_RESOURCES;
|
||||
|
|
|
@ -0,0 +1,16 @@
|
|||
## @file
|
||||
# Ext4 DSC include file for Platform DSC
|
||||
#
|
||||
# SPDX-FileCopyrightText: Copyright (c) 2022 NVIDIA CORPORATION & AFFILIATES. All rights reserved.
|
||||
# SPDX-License-Identifier: BSD-2-Clause-Patent
|
||||
#
|
||||
##
|
||||
|
||||
[Defines]
|
||||
!include Ext4Pkg/Ext4Defines.dsc.inc
|
||||
|
||||
[LibraryClasses]
|
||||
!include Ext4Pkg/Ext4Libs.dsc.inc
|
||||
|
||||
[Components.common]
|
||||
!include Ext4Pkg/Ext4Components.dsc.inc
|
|
@ -0,0 +1,11 @@
|
|||
## @file
|
||||
# Ext4 FDF include file for All Architectures.
|
||||
#
|
||||
# SPDX-FileCopyrightText: Copyright (c) 2022 NVIDIA CORPORATION & AFFILIATES. All rights reserved.
|
||||
# SPDX-License-Identifier: BSD-2-Clause-Patent
|
||||
#
|
||||
##
|
||||
|
||||
!if $(EXT4_ENABLE) == TRUE
|
||||
INF Ext4Pkg/Ext4Dxe/Ext4Dxe.inf
|
||||
!endif
|
|
@ -0,0 +1,14 @@
|
|||
## @file
|
||||
# Ext4 DSC include file for [Components] section of all Architectures.
|
||||
#
|
||||
# SPDX-FileCopyrightText: Copyright (c) 2022 NVIDIA CORPORATION & AFFILIATES. All rights reserved.
|
||||
# SPDX-License-Identifier: BSD-2-Clause-Patent
|
||||
#
|
||||
##
|
||||
|
||||
!if $(EXT4_ENABLE) == TRUE
|
||||
Ext4Pkg/Ext4Dxe/Ext4Dxe.inf {
|
||||
<PcdsFixedAtBuild>
|
||||
gEfiMdePkgTokenSpaceGuid.PcdDebugPrintErrorLevel|0x80000007
|
||||
}
|
||||
!endif
|
|
@ -0,0 +1,14 @@
|
|||
## @file
|
||||
# Ext4 DSC include file for [Defines] section of all Architectures.
|
||||
#
|
||||
# SPDX-FileCopyrightText: Copyright (c) 2022 NVIDIA CORPORATION & AFFILIATES. All rights reserved.
|
||||
# SPDX-License-Identifier: BSD-2-Clause-Patent
|
||||
#
|
||||
##
|
||||
|
||||
!ifndef EXT4_ENABLE
|
||||
#
|
||||
# This flag is to enable or disable the ext4 feature.
|
||||
#
|
||||
DEFINE EXT4_ENABLE = TRUE
|
||||
!endif
|
|
@ -0,0 +1,229 @@
|
|||
/** @file
|
||||
Block group related routines
|
||||
|
||||
Copyright (c) 2021 Pedro Falcato All rights reserved.
|
||||
Copyright (c) 2007 - 2018, Intel Corporation. All rights reserved.<BR>
|
||||
|
||||
SPDX-License-Identifier: BSD-2-Clause-Patent
|
||||
**/
|
||||
|
||||
#include "Ext4Dxe.h"
|
||||
|
||||
/**
|
||||
Retrieves a block group descriptor of the ext4 filesystem.
|
||||
|
||||
@param[in] Partition Pointer to the opened ext4 partition.
|
||||
@param[in] BlockGroup Block group number.
|
||||
|
||||
@return A pointer to the block group descriptor.
|
||||
**/
|
||||
EXT4_BLOCK_GROUP_DESC *
|
||||
Ext4GetBlockGroupDesc (
|
||||
IN EXT4_PARTITION *Partition,
|
||||
IN UINT32 BlockGroup
|
||||
)
|
||||
{
|
||||
// Maybe assert that the block group nr isn't a nonsense number?
|
||||
return (EXT4_BLOCK_GROUP_DESC *)((CHAR8 *)Partition->BlockGroups + BlockGroup * Partition->DescSize);
|
||||
}
|
||||
|
||||
/**
|
||||
Reads an inode from disk.
|
||||
|
||||
@param[in] Partition Pointer to the opened partition.
|
||||
@param[in] InodeNum Number of the desired Inode
|
||||
@param[out] OutIno Pointer to where it will be stored a pointer to the read inode.
|
||||
|
||||
@return Status of the inode read.
|
||||
**/
|
||||
EFI_STATUS
|
||||
Ext4ReadInode (
|
||||
IN EXT4_PARTITION *Partition,
|
||||
IN EXT4_INO_NR InodeNum,
|
||||
OUT EXT4_INODE **OutIno
|
||||
)
|
||||
{
|
||||
UINT64 InodeOffset;
|
||||
UINT32 BlockGroupNumber;
|
||||
EXT4_INODE *Inode;
|
||||
EXT4_BLOCK_GROUP_DESC *BlockGroup;
|
||||
EXT4_BLOCK_NR InodeTableStart;
|
||||
EFI_STATUS Status;
|
||||
|
||||
if (!EXT4_IS_VALID_INODE_NR (Partition, InodeNum)) {
|
||||
DEBUG ((DEBUG_ERROR, "[ext4] Error reading inode: inode number %lu isn't valid\n", InodeNum));
|
||||
return EFI_VOLUME_CORRUPTED;
|
||||
}
|
||||
|
||||
BlockGroupNumber = (UINT32)DivU64x64Remainder (
|
||||
InodeNum - 1,
|
||||
Partition->SuperBlock.s_inodes_per_group,
|
||||
&InodeOffset
|
||||
);
|
||||
|
||||
// Check for the block group number's correctness
|
||||
if (BlockGroupNumber >= Partition->NumberBlockGroups) {
|
||||
return EFI_VOLUME_CORRUPTED;
|
||||
}
|
||||
|
||||
Inode = Ext4AllocateInode (Partition);
|
||||
|
||||
if (Inode == NULL) {
|
||||
return EFI_OUT_OF_RESOURCES;
|
||||
}
|
||||
|
||||
BlockGroup = Ext4GetBlockGroupDesc (Partition, BlockGroupNumber);
|
||||
|
||||
// Note: We'll need to check INODE_UNINIT and friends when/if we add write support
|
||||
|
||||
InodeTableStart = EXT4_BLOCK_NR_FROM_HALFS (
|
||||
Partition,
|
||||
BlockGroup->bg_inode_table_lo,
|
||||
BlockGroup->bg_inode_table_hi
|
||||
);
|
||||
|
||||
Status = Ext4ReadDiskIo (
|
||||
Partition,
|
||||
Inode,
|
||||
Partition->InodeSize,
|
||||
EXT4_BLOCK_TO_BYTES (Partition, InodeTableStart) + MultU64x32 (InodeOffset, Partition->InodeSize)
|
||||
);
|
||||
|
||||
if (EFI_ERROR (Status)) {
|
||||
DEBUG ((
|
||||
DEBUG_ERROR,
|
||||
"[ext4] Error reading inode: status %x; inode offset %lx"
|
||||
" inode table start %lu block group %lu\n",
|
||||
Status,
|
||||
InodeOffset,
|
||||
InodeTableStart,
|
||||
BlockGroupNumber
|
||||
));
|
||||
FreePool (Inode);
|
||||
return Status;
|
||||
}
|
||||
|
||||
if (!Ext4CheckInodeChecksum (Partition, Inode, InodeNum)) {
|
||||
DEBUG ((
|
||||
DEBUG_ERROR,
|
||||
"[ext4] Inode %llu has invalid checksum (calculated %x)\n",
|
||||
InodeNum,
|
||||
Ext4CalculateInodeChecksum (Partition, Inode, InodeNum)
|
||||
));
|
||||
FreePool (Inode);
|
||||
return EFI_VOLUME_CORRUPTED;
|
||||
}
|
||||
|
||||
*OutIno = Inode;
|
||||
return EFI_SUCCESS;
|
||||
}
|
||||
|
||||
/**
|
||||
Calculates the checksum of the block group descriptor for METADATA_CSUM enabled filesystems.
|
||||
@param[in] Partition Pointer to the opened EXT4 partition.
|
||||
@param[in] BlockGroupDesc Pointer to the block group descriptor.
|
||||
@param[in] BlockGroupNum Number of the block group.
|
||||
|
||||
@return The checksum.
|
||||
**/
|
||||
STATIC
|
||||
UINT16
|
||||
Ext4CalculateBlockGroupDescChecksumMetadataCsum (
|
||||
IN CONST EXT4_PARTITION *Partition,
|
||||
IN CONST EXT4_BLOCK_GROUP_DESC *BlockGroupDesc,
|
||||
IN UINT32 BlockGroupNum
|
||||
)
|
||||
{
|
||||
UINT32 Csum;
|
||||
UINT16 Dummy;
|
||||
|
||||
Dummy = 0;
|
||||
|
||||
Csum = Ext4CalculateChecksum (Partition, &BlockGroupNum, sizeof (BlockGroupNum), Partition->InitialSeed);
|
||||
Csum = Ext4CalculateChecksum (Partition, BlockGroupDesc, OFFSET_OF (EXT4_BLOCK_GROUP_DESC, bg_checksum), Csum);
|
||||
Csum = Ext4CalculateChecksum (Partition, &Dummy, sizeof (Dummy), Csum);
|
||||
Csum =
|
||||
Ext4CalculateChecksum (
|
||||
Partition,
|
||||
&BlockGroupDesc->bg_block_bitmap_hi,
|
||||
Partition->DescSize - OFFSET_OF (EXT4_BLOCK_GROUP_DESC, bg_block_bitmap_hi),
|
||||
Csum
|
||||
);
|
||||
return (UINT16)Csum;
|
||||
}
|
||||
|
||||
/**
|
||||
Calculates the checksum of the block group descriptor for GDT_CSUM enabled filesystems.
|
||||
@param[in] Partition Pointer to the opened EXT4 partition.
|
||||
@param[in] BlockGroupDesc Pointer to the block group descriptor.
|
||||
@param[in] BlockGroupNum Number of the block group.
|
||||
|
||||
@return The checksum.
|
||||
**/
|
||||
STATIC
|
||||
UINT16
|
||||
Ext4CalculateBlockGroupDescChecksumGdtCsum (
|
||||
IN CONST EXT4_PARTITION *Partition,
|
||||
IN CONST EXT4_BLOCK_GROUP_DESC *BlockGroupDesc,
|
||||
IN UINT32 BlockGroupNum
|
||||
)
|
||||
{
|
||||
UINT16 Csum;
|
||||
|
||||
Csum = CalculateCrc16Ansi (Partition->SuperBlock.s_uuid, sizeof (Partition->SuperBlock.s_uuid), 0xFFFF);
|
||||
Csum = CalculateCrc16Ansi (&BlockGroupNum, sizeof (BlockGroupNum), Csum);
|
||||
Csum = CalculateCrc16Ansi (BlockGroupDesc, OFFSET_OF (EXT4_BLOCK_GROUP_DESC, bg_checksum), Csum);
|
||||
Csum =
|
||||
CalculateCrc16Ansi (
|
||||
&BlockGroupDesc->bg_block_bitmap_hi,
|
||||
Partition->DescSize - OFFSET_OF (EXT4_BLOCK_GROUP_DESC, bg_block_bitmap_hi),
|
||||
Csum
|
||||
);
|
||||
return Csum;
|
||||
}
|
||||
|
||||
/**
|
||||
Checks if the checksum of the block group descriptor is correct.
|
||||
@param[in] Partition Pointer to the opened EXT4 partition.
|
||||
@param[in] BlockGroupDesc Pointer to the block group descriptor.
|
||||
@param[in] BlockGroupNum Number of the block group.
|
||||
|
||||
@return TRUE if checksum is correct, FALSE if there is corruption.
|
||||
**/
|
||||
BOOLEAN
|
||||
Ext4VerifyBlockGroupDescChecksum (
|
||||
IN CONST EXT4_PARTITION *Partition,
|
||||
IN CONST EXT4_BLOCK_GROUP_DESC *BlockGroupDesc,
|
||||
IN UINT32 BlockGroupNum
|
||||
)
|
||||
{
|
||||
if (!EXT4_HAS_METADATA_CSUM (Partition) && !EXT4_HAS_GDT_CSUM (Partition)) {
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
return Ext4CalculateBlockGroupDescChecksum (Partition, BlockGroupDesc, BlockGroupNum) == BlockGroupDesc->bg_checksum;
|
||||
}
|
||||
|
||||
/**
|
||||
Calculates the checksum of the block group descriptor.
|
||||
@param[in] Partition Pointer to the opened EXT4 partition.
|
||||
@param[in] BlockGroupDesc Pointer to the block group descriptor.
|
||||
@param[in] BlockGroupNum Number of the block group.
|
||||
|
||||
@return The checksum.
|
||||
**/
|
||||
UINT16
|
||||
Ext4CalculateBlockGroupDescChecksum (
|
||||
IN CONST EXT4_PARTITION *Partition,
|
||||
IN CONST EXT4_BLOCK_GROUP_DESC *BlockGroupDesc,
|
||||
IN UINT32 BlockGroupNum
|
||||
)
|
||||
{
|
||||
if (EXT4_HAS_METADATA_CSUM (Partition)) {
|
||||
return Ext4CalculateBlockGroupDescChecksumMetadataCsum (Partition, BlockGroupDesc, BlockGroupNum);
|
||||
} else if (EXT4_HAS_GDT_CSUM (Partition)) {
|
||||
return Ext4CalculateBlockGroupDescChecksumGdtCsum (Partition, BlockGroupDesc, BlockGroupNum);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
|
@ -0,0 +1,285 @@
|
|||
/** @file
|
||||
Implementation of routines that deal with ext2/3 block maps.
|
||||
|
||||
Copyright (c) 2022 Pedro Falcato All rights reserved.
|
||||
SPDX-License-Identifier: BSD-2-Clause-Patent
|
||||
**/
|
||||
|
||||
#include <Ext4Dxe.h>
|
||||
|
||||
// Note: The largest path we can take uses up 4 indices
|
||||
#define EXT4_MAX_BLOCK_PATH 4
|
||||
|
||||
typedef enum ext4_logical_block_type {
|
||||
EXT4_TYPE_DIRECT_BLOCK = 0,
|
||||
EXT4_TYPE_SINGLY_BLOCK,
|
||||
EXT4_TYPE_DOUBLY_BLOCK,
|
||||
EXT4_TYPE_TREBLY_BLOCK,
|
||||
EXT4_TYPE_BAD_BLOCK
|
||||
} EXT4_LOGICAL_BLOCK_TYPE;
|
||||
|
||||
/**
|
||||
@brief Detect the type of path the logical block will follow
|
||||
|
||||
@param[in] LogicalBlock The logical block
|
||||
@param[in] Partition Pointer to an EXT4_PARTITION
|
||||
@return The type of path the logical block will need to follow
|
||||
*/
|
||||
STATIC
|
||||
EXT4_LOGICAL_BLOCK_TYPE
|
||||
Ext4DetectBlockType (
|
||||
IN UINT32 LogicalBlock,
|
||||
IN CONST EXT4_PARTITION *Partition
|
||||
)
|
||||
{
|
||||
UINT32 Entries;
|
||||
UINT32 MinSinglyBlock;
|
||||
UINT32 MinDoublyBlock;
|
||||
UINT32 MinTreblyBlock;
|
||||
UINT32 MinQuadBlock;
|
||||
|
||||
Entries = (Partition->BlockSize / sizeof (UINT32));
|
||||
MinSinglyBlock = EXT4_DBLOCKS;
|
||||
MinDoublyBlock = Entries + MinSinglyBlock;
|
||||
MinTreblyBlock = Entries * Entries + MinDoublyBlock;
|
||||
MinQuadBlock = Entries * Entries * Entries + MinTreblyBlock; // Doesn't actually exist
|
||||
|
||||
if (LogicalBlock < MinSinglyBlock) {
|
||||
return EXT4_TYPE_DIRECT_BLOCK;
|
||||
} else if ((LogicalBlock >= MinSinglyBlock) && (LogicalBlock < MinDoublyBlock)) {
|
||||
return EXT4_TYPE_SINGLY_BLOCK;
|
||||
} else if ((LogicalBlock >= MinDoublyBlock) && (LogicalBlock < MinTreblyBlock)) {
|
||||
return EXT4_TYPE_DOUBLY_BLOCK;
|
||||
} else if (((LogicalBlock >= MinTreblyBlock) && (LogicalBlock < MinQuadBlock))) {
|
||||
return EXT4_TYPE_TREBLY_BLOCK;
|
||||
} else {
|
||||
return EXT4_TYPE_BAD_BLOCK;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
@brief Get a block's path in indices
|
||||
|
||||
@param[in] Partition Pointer to an EXT4_PARTITION
|
||||
@param[in] LogicalBlock Logical block
|
||||
@param[out] BlockPath Pointer to an array of EXT4_MAX_BLOCK_PATH elements, where the
|
||||
indices we'll need to read are inserted.
|
||||
@return The number of path elements that are required (and were inserted in BlockPath)
|
||||
*/
|
||||
UINTN
|
||||
Ext4GetBlockPath (
|
||||
IN CONST EXT4_PARTITION *Partition,
|
||||
IN UINT32 LogicalBlock,
|
||||
OUT EXT2_BLOCK_NR BlockPath[EXT4_MAX_BLOCK_PATH]
|
||||
)
|
||||
{
|
||||
// The logic behind the block map is very much like a page table
|
||||
// Let's think of blocks with 512 entries (exactly like a page table on x64).
|
||||
// On doubly indirect block paths, we subtract the min doubly blocks from the logical block.
|
||||
// The top 9 bits of the result are the index inside the dind block, the bottom 9 bits are the
|
||||
// index inside the ind block. Since Entries is always a power of 2, entries - 1 will give us
|
||||
// a mask of the BlockMapBits.
|
||||
// Note that all this math could be done with ands and shifts (similar implementations exist
|
||||
// in a bunch of other places), but I'm doing it a simplified way with divs and modulus,
|
||||
// since it's not going to be a bottleneck anyway.
|
||||
|
||||
UINT32 Entries;
|
||||
UINT32 EntriesEntries;
|
||||
UINT32 MinSinglyBlock;
|
||||
UINT32 MinDoublyBlock;
|
||||
UINT32 MinTreblyBlock;
|
||||
|
||||
EXT4_LOGICAL_BLOCK_TYPE Type;
|
||||
|
||||
Entries = (Partition->BlockSize / sizeof (UINT32));
|
||||
EntriesEntries = Entries * Entries;
|
||||
|
||||
MinSinglyBlock = EXT4_DBLOCKS;
|
||||
MinDoublyBlock = Entries + MinSinglyBlock;
|
||||
MinTreblyBlock = EntriesEntries + MinDoublyBlock;
|
||||
|
||||
Type = Ext4DetectBlockType (LogicalBlock, Partition);
|
||||
|
||||
switch (Type) {
|
||||
case EXT4_TYPE_DIRECT_BLOCK:
|
||||
BlockPath[0] = LogicalBlock;
|
||||
break;
|
||||
case EXT4_TYPE_SINGLY_BLOCK:
|
||||
BlockPath[0] = EXT4_IND_BLOCK;
|
||||
BlockPath[1] = LogicalBlock - EXT4_DBLOCKS;
|
||||
break;
|
||||
case EXT4_TYPE_DOUBLY_BLOCK:
|
||||
BlockPath[0] = EXT4_DIND_BLOCK;
|
||||
LogicalBlock -= MinDoublyBlock;
|
||||
BlockPath[1] = LogicalBlock / Entries;
|
||||
BlockPath[2] = LogicalBlock % Entries;
|
||||
break;
|
||||
case EXT4_TYPE_TREBLY_BLOCK:
|
||||
BlockPath[0] = EXT4_DIND_BLOCK;
|
||||
LogicalBlock -= MinTreblyBlock;
|
||||
BlockPath[1] = LogicalBlock / EntriesEntries;
|
||||
BlockPath[2] = (LogicalBlock % EntriesEntries) / Entries;
|
||||
BlockPath[3] = (LogicalBlock % EntriesEntries) % Entries;
|
||||
break;
|
||||
default:
|
||||
// EXT4_TYPE_BAD_BLOCK
|
||||
break;
|
||||
}
|
||||
|
||||
return Type + 1;
|
||||
}
|
||||
|
||||
/**
|
||||
@brief Get an extent from a block map
|
||||
Note: Also parses file holes and creates uninitialized extents from them.
|
||||
|
||||
@param[in] Buffer Buffer of block pointers
|
||||
@param[in] IndEntries Number of entries in this block pointer table
|
||||
@param[in] StartIndex The start index from which we want to find a contiguous extent
|
||||
@param[out] Extent Pointer to the resulting EXT4_EXTENT
|
||||
*/
|
||||
VOID
|
||||
Ext4GetExtentInBlockMap (
|
||||
IN CONST UINT32 *Buffer,
|
||||
IN CONST UINT32 IndEntries,
|
||||
IN UINT32 StartIndex,
|
||||
OUT EXT4_EXTENT *Extent
|
||||
)
|
||||
{
|
||||
UINT32 Index;
|
||||
UINT32 FirstBlock;
|
||||
UINT32 LastBlock;
|
||||
UINT16 Count;
|
||||
|
||||
Count = 1;
|
||||
LastBlock = Buffer[StartIndex];
|
||||
FirstBlock = LastBlock;
|
||||
|
||||
if (FirstBlock == EXT4_BLOCK_FILE_HOLE) {
|
||||
// File hole, let's see how many blocks this hole spans
|
||||
Extent->ee_start_hi = 0;
|
||||
Extent->ee_start_lo = 0;
|
||||
|
||||
for (Index = StartIndex + 1; Index < IndEntries; Index++) {
|
||||
if (Count == EXT4_EXTENT_MAX_INITIALIZED - 1) {
|
||||
// We've reached the max size of an uninit extent, break
|
||||
break;
|
||||
}
|
||||
|
||||
if (Buffer[Index] == EXT4_BLOCK_FILE_HOLE) {
|
||||
Count++;
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// We mark the extent as uninitialized, although there's a difference between uninit
|
||||
// extents and file holes.
|
||||
Extent->ee_len = EXT4_EXTENT_MAX_INITIALIZED + Count;
|
||||
return;
|
||||
}
|
||||
|
||||
for (Index = StartIndex + 1; Index < IndEntries; Index++) {
|
||||
if (Count == EXT4_EXTENT_MAX_INITIALIZED) {
|
||||
// We've reached the max size of an extent, break
|
||||
break;
|
||||
}
|
||||
|
||||
if ((Buffer[Index] == LastBlock + 1) && (Buffer[Index] != EXT4_BLOCK_FILE_HOLE)) {
|
||||
Count++;
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
|
||||
LastBlock = Buffer[Index];
|
||||
}
|
||||
|
||||
Extent->ee_start_lo = FirstBlock;
|
||||
Extent->ee_start_hi = 0;
|
||||
Extent->ee_len = Count;
|
||||
}
|
||||
|
||||
/**
|
||||
Retrieves an extent from an EXT2/3 inode (with a blockmap).
|
||||
@param[in] Partition Pointer to the opened EXT4 partition.
|
||||
@param[in] File Pointer to the opened file.
|
||||
@param[in] LogicalBlock Block number which the returned extent must cover.
|
||||
@param[out] Extent Pointer to the output buffer, where the extent will be copied to.
|
||||
|
||||
@retval EFI_SUCCESS Retrieval was successful.
|
||||
@retval EFI_NO_MAPPING Block has no mapping.
|
||||
**/
|
||||
EFI_STATUS
|
||||
Ext4GetBlocks (
|
||||
IN EXT4_PARTITION *Partition,
|
||||
IN EXT4_FILE *File,
|
||||
IN EXT2_BLOCK_NR LogicalBlock,
|
||||
OUT EXT4_EXTENT *Extent
|
||||
)
|
||||
{
|
||||
EXT4_INODE *Inode;
|
||||
EXT2_BLOCK_NR BlockPath[EXT4_MAX_BLOCK_PATH];
|
||||
UINTN BlockPathLength;
|
||||
UINTN Index;
|
||||
UINT32 *Buffer;
|
||||
EFI_STATUS Status;
|
||||
UINT32 Block;
|
||||
UINT32 BlockIndex;
|
||||
|
||||
Inode = File->Inode;
|
||||
|
||||
BlockPathLength = Ext4GetBlockPath (Partition, LogicalBlock, BlockPath);
|
||||
|
||||
if (BlockPathLength - 1 == EXT4_TYPE_BAD_BLOCK) {
|
||||
// Bad logical block (out of range)
|
||||
return EFI_NO_MAPPING;
|
||||
}
|
||||
|
||||
Extent->ee_block = LogicalBlock;
|
||||
|
||||
if (BlockPathLength == 1) {
|
||||
// Fast path for blocks 0 - 12 that skips allocations
|
||||
Ext4GetExtentInBlockMap (Inode->i_data, EXT4_DBLOCKS, BlockPath[0], Extent);
|
||||
|
||||
return EFI_SUCCESS;
|
||||
}
|
||||
|
||||
Buffer = AllocatePool (Partition->BlockSize);
|
||||
if (Buffer == NULL) {
|
||||
return EFI_OUT_OF_RESOURCES;
|
||||
}
|
||||
|
||||
// Note the BlockPathLength - 1 so we don't end up reading the final block
|
||||
for (Index = 0; Index < BlockPathLength - 1; Index++) {
|
||||
BlockIndex = BlockPath[Index];
|
||||
|
||||
if (Index == 0) {
|
||||
Block = Inode->i_data[BlockIndex];
|
||||
} else {
|
||||
Block = Buffer[BlockIndex];
|
||||
}
|
||||
|
||||
if (Block == EXT4_BLOCK_FILE_HOLE) {
|
||||
FreePool (Buffer);
|
||||
return EFI_NO_MAPPING;
|
||||
}
|
||||
|
||||
Status = Ext4ReadBlocks (Partition, Buffer, 1, Block);
|
||||
|
||||
if (EFI_ERROR (Status)) {
|
||||
FreePool (Buffer);
|
||||
return Status;
|
||||
}
|
||||
}
|
||||
|
||||
Ext4GetExtentInBlockMap (
|
||||
Buffer,
|
||||
Partition->BlockSize / sizeof (UINT32),
|
||||
BlockPath[BlockPathLength - 1],
|
||||
Extent
|
||||
);
|
||||
|
||||
FreePool (Buffer);
|
||||
|
||||
return EFI_SUCCESS;
|
||||
}
|
|
@ -0,0 +1,195 @@
|
|||
/** @file
|
||||
Unicode collation routines
|
||||
|
||||
Copyright (c) 2021 - 2023 Pedro Falcato All rights reserved.
|
||||
Copyright (c) 2005 - 2017, Intel Corporation. All rights reserved.
|
||||
|
||||
SPDX-License-Identifier: BSD-2-Clause-Patent
|
||||
**/
|
||||
|
||||
#include <Uefi.h>
|
||||
|
||||
#include <Library/DebugLib.h>
|
||||
#include <Library/UefiLib.h>
|
||||
#include <Library/UefiBootServicesTableLib.h>
|
||||
#include <Library/MemoryAllocationLib.h>
|
||||
|
||||
#include <Protocol/UnicodeCollation.h>
|
||||
|
||||
STATIC EFI_UNICODE_COLLATION_PROTOCOL *gUnicodeCollationInterface = NULL;
|
||||
|
||||
/*
|
||||
* Note: This code is heavily based on FatPkg's Unicode collation, since they seem to know what
|
||||
* they're doing.
|
||||
* PS: Maybe all this code could be put in a library? It looks heavily shareable.
|
||||
**/
|
||||
|
||||
/**
|
||||
Check if unicode collation is initialized
|
||||
|
||||
@retval TRUE if Ext4InitialiseUnicodeCollation() was already called successfully
|
||||
@retval FALSE if Ext4InitialiseUnicodeCollation() was not yet called successfully
|
||||
**/
|
||||
STATIC
|
||||
BOOLEAN
|
||||
Ext4IsCollationInitialized (
|
||||
VOID
|
||||
)
|
||||
{
|
||||
return gUnicodeCollationInterface != NULL;
|
||||
}
|
||||
|
||||
/**
|
||||
Worker function to initialize Unicode Collation support.
|
||||
|
||||
It tries to locate Unicode Collation (2) protocol and matches it with current
|
||||
platform language code.
|
||||
|
||||
@param[in] DriverHandle The handle used to open Unicode Collation (2) protocol.
|
||||
@param[in] ProtocolGuid The pointer to Unicode Collation (2) protocol GUID.
|
||||
@param[in] VariableName The name of the RFC 4646 or ISO 639-2 language variable.
|
||||
@param[in] DefaultLanguage The default language in case the RFC 4646 or ISO 639-2 language is absent.
|
||||
|
||||
@retval EFI_SUCCESS The Unicode Collation (2) protocol has been successfully located.
|
||||
@retval Others The Unicode Collation (2) protocol has not been located.
|
||||
|
||||
**/
|
||||
STATIC
|
||||
EFI_STATUS
|
||||
Ext4InitialiseUnicodeCollationInternal (
|
||||
IN EFI_HANDLE DriverHandle,
|
||||
IN EFI_GUID *ProtocolGuid,
|
||||
IN CONST CHAR16 *VariableName,
|
||||
IN CONST CHAR8 *DefaultLanguage
|
||||
)
|
||||
{
|
||||
UINTN NumHandles;
|
||||
EFI_HANDLE *Handles;
|
||||
EFI_UNICODE_COLLATION_PROTOCOL *Uci;
|
||||
BOOLEAN Iso639Language;
|
||||
CHAR8 *Language;
|
||||
EFI_STATUS RetStatus;
|
||||
EFI_STATUS Status;
|
||||
UINTN Idx;
|
||||
CHAR8 *BestLanguage;
|
||||
|
||||
Iso639Language = (BOOLEAN)(ProtocolGuid == &gEfiUnicodeCollationProtocolGuid);
|
||||
RetStatus = EFI_UNSUPPORTED;
|
||||
GetEfiGlobalVariable2 (VariableName, (VOID **)&Language, NULL);
|
||||
|
||||
Status = gBS->LocateHandleBuffer (
|
||||
ByProtocol,
|
||||
ProtocolGuid,
|
||||
NULL,
|
||||
&NumHandles,
|
||||
&Handles
|
||||
);
|
||||
if (EFI_ERROR (Status)) {
|
||||
return Status;
|
||||
}
|
||||
|
||||
for (Idx = 0; Idx < NumHandles; Idx++) {
|
||||
Status = gBS->OpenProtocol (
|
||||
Handles[Idx],
|
||||
ProtocolGuid,
|
||||
(VOID **)&Uci,
|
||||
DriverHandle,
|
||||
NULL,
|
||||
EFI_OPEN_PROTOCOL_GET_PROTOCOL
|
||||
);
|
||||
|
||||
if (EFI_ERROR (Status)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
BestLanguage = GetBestLanguage (
|
||||
Uci->SupportedLanguages,
|
||||
Iso639Language,
|
||||
(Language == NULL) ? "" : Language,
|
||||
DefaultLanguage,
|
||||
NULL
|
||||
);
|
||||
if (BestLanguage != NULL) {
|
||||
FreePool (BestLanguage);
|
||||
gUnicodeCollationInterface = Uci;
|
||||
RetStatus = EFI_SUCCESS;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (Language != NULL) {
|
||||
FreePool (Language);
|
||||
}
|
||||
|
||||
FreePool (Handles);
|
||||
return RetStatus;
|
||||
}
|
||||
|
||||
/**
|
||||
Initialises Unicode collation, which is needed for case-insensitive string comparisons
|
||||
within the driver (a good example of an application of this is filename comparison).
|
||||
|
||||
@param[in] DriverHandle Handle to the driver image.
|
||||
|
||||
@retval EFI_SUCCESS Unicode collation was successfully initialised.
|
||||
@retval !EFI_SUCCESS Failure.
|
||||
**/
|
||||
EFI_STATUS
|
||||
Ext4InitialiseUnicodeCollation (
|
||||
EFI_HANDLE DriverHandle
|
||||
)
|
||||
{
|
||||
EFI_STATUS Status;
|
||||
|
||||
Status = EFI_UNSUPPORTED;
|
||||
|
||||
// If already done, just return success.
|
||||
if (Ext4IsCollationInitialized ()) {
|
||||
return EFI_SUCCESS;
|
||||
}
|
||||
|
||||
//
|
||||
// First try to use RFC 4646 Unicode Collation 2 Protocol.
|
||||
//
|
||||
Status = Ext4InitialiseUnicodeCollationInternal (
|
||||
DriverHandle,
|
||||
&gEfiUnicodeCollation2ProtocolGuid,
|
||||
L"PlatformLang",
|
||||
(CONST CHAR8 *)PcdGetPtr (PcdUefiVariableDefaultPlatformLang)
|
||||
);
|
||||
//
|
||||
// If the attempt to use Unicode Collation 2 Protocol fails, then we fall back
|
||||
// on the ISO 639-2 Unicode Collation Protocol.
|
||||
//
|
||||
if (EFI_ERROR (Status)) {
|
||||
Status = Ext4InitialiseUnicodeCollationInternal (
|
||||
DriverHandle,
|
||||
&gEfiUnicodeCollationProtocolGuid,
|
||||
L"Lang",
|
||||
(CONST CHAR8 *)PcdGetPtr (PcdUefiVariableDefaultLang)
|
||||
);
|
||||
}
|
||||
|
||||
return Status;
|
||||
}
|
||||
|
||||
/**
|
||||
Does a case-insensitive string comparison. Refer to EFI_UNICODE_COLLATION_PROTOCOL's StriColl
|
||||
for more details.
|
||||
|
||||
@param[in] Str1 Pointer to a null terminated string.
|
||||
@param[in] Str2 Pointer to a null terminated string.
|
||||
|
||||
@retval 0 Str1 is equivalent to Str2.
|
||||
@retval >0 Str1 is lexically greater than Str2.
|
||||
@retval <0 Str1 is lexically less than Str2.
|
||||
**/
|
||||
INTN
|
||||
Ext4StrCmpInsensitive (
|
||||
IN CHAR16 *Str1,
|
||||
IN CHAR16 *Str2
|
||||
)
|
||||
{
|
||||
ASSERT (gUnicodeCollationInterface != NULL);
|
||||
return gUnicodeCollationInterface->StriColl (gUnicodeCollationInterface, Str1, Str2);
|
||||
}
|
|
@ -0,0 +1,708 @@
|
|||
/** @file
|
||||
Directory related routines
|
||||
|
||||
Copyright (c) 2021 - 2023 Pedro Falcato All rights reserved.
|
||||
|
||||
SPDX-License-Identifier: BSD-2-Clause-Patent
|
||||
**/
|
||||
|
||||
#include "Ext4Dxe.h"
|
||||
|
||||
#include <Library/BaseUcs2Utf8Lib.h>
|
||||
|
||||
/**
|
||||
Retrieves the filename of the directory entry and converts it to UTF-16/UCS-2
|
||||
|
||||
@param[in] Entry Pointer to a EXT4_DIR_ENTRY.
|
||||
@param[out] Ucs2FileName Pointer to an array of CHAR16's, of size EXT4_NAME_MAX + 1.
|
||||
|
||||
@retval EFI_SUCCESS The filename was successfully retrieved and converted to UCS2.
|
||||
@retval EFI_INVALID_PARAMETER The filename is not valid UTF-8.
|
||||
@retval !EFI_SUCCESS Failure.
|
||||
**/
|
||||
EFI_STATUS
|
||||
Ext4GetUcs2DirentName (
|
||||
IN EXT4_DIR_ENTRY *Entry,
|
||||
OUT CHAR16 Ucs2FileName[EXT4_NAME_MAX + 1]
|
||||
)
|
||||
{
|
||||
CHAR8 Utf8NameBuf[EXT4_NAME_MAX + 1];
|
||||
UINT16 *Str;
|
||||
UINT8 Index;
|
||||
EFI_STATUS Status;
|
||||
|
||||
for (Index = 0; Index < Entry->name_len; ++Index) {
|
||||
if (Entry->name[Index] == '\0') {
|
||||
return EFI_INVALID_PARAMETER;
|
||||
}
|
||||
|
||||
Utf8NameBuf[Index] = Entry->name[Index];
|
||||
}
|
||||
|
||||
Utf8NameBuf[Entry->name_len] = '\0';
|
||||
|
||||
// Unfortunately, BaseUcs2Utf8Lib doesn't have a convert-buffer-to-buffer-like
|
||||
// function. Therefore, we need to allocate from the pool (inside UTF8StrToUCS2),
|
||||
// copy it to our out buffer (Ucs2FileName) and free.
|
||||
|
||||
Status = UTF8StrToUCS2 (Utf8NameBuf, &Str);
|
||||
|
||||
if (EFI_ERROR (Status)) {
|
||||
return Status;
|
||||
}
|
||||
|
||||
Status = StrCpyS (Ucs2FileName, EXT4_NAME_MAX + 1, Str);
|
||||
|
||||
FreePool (Str);
|
||||
|
||||
return Status;
|
||||
}
|
||||
|
||||
/**
|
||||
Validates a directory entry.
|
||||
|
||||
@param[in] Dirent Pointer to the directory entry.
|
||||
|
||||
@retval TRUE Valid directory entry.
|
||||
FALSE Invalid directory entry.
|
||||
**/
|
||||
STATIC
|
||||
BOOLEAN
|
||||
Ext4ValidDirent (
|
||||
IN CONST EXT4_DIR_ENTRY *Dirent
|
||||
)
|
||||
{
|
||||
UINTN RequiredSize;
|
||||
|
||||
RequiredSize = Dirent->name_len + EXT4_MIN_DIR_ENTRY_LEN;
|
||||
|
||||
if (Dirent->rec_len < RequiredSize) {
|
||||
DEBUG ((DEBUG_ERROR, "[ext4] dirent size %lu too small (compared to %lu)\n", Dirent->rec_len, RequiredSize));
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
// Dirent sizes need to be 4 byte aligned
|
||||
if ((Dirent->rec_len % 4) != 0) {
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
/**
|
||||
Retrieves a directory entry.
|
||||
|
||||
@param[in] Directory Pointer to the opened directory.
|
||||
@param[in] NameUnicode Pointer to the UCS-2 formatted filename.
|
||||
@param[in] Partition Pointer to the ext4 partition.
|
||||
@param[out] Result Pointer to the destination directory entry.
|
||||
|
||||
@return The result of the operation.
|
||||
**/
|
||||
EFI_STATUS
|
||||
Ext4RetrieveDirent (
|
||||
IN EXT4_FILE *Directory,
|
||||
IN CONST CHAR16 *Name,
|
||||
IN EXT4_PARTITION *Partition,
|
||||
OUT EXT4_DIR_ENTRY *Result
|
||||
)
|
||||
{
|
||||
EFI_STATUS Status;
|
||||
CHAR8 *Buf;
|
||||
UINT64 Off;
|
||||
EXT4_INODE *Inode;
|
||||
UINT64 DirInoSize;
|
||||
UINT32 BlockRemainder;
|
||||
UINTN Length;
|
||||
EXT4_DIR_ENTRY *Entry;
|
||||
UINTN RemainingBlock;
|
||||
CHAR16 DirentUcs2Name[EXT4_NAME_MAX + 1];
|
||||
UINTN ToCopy;
|
||||
UINTN BlockOffset;
|
||||
|
||||
Buf = AllocatePool (Partition->BlockSize);
|
||||
|
||||
if (Buf == NULL) {
|
||||
return EFI_OUT_OF_RESOURCES;
|
||||
}
|
||||
|
||||
Off = 0;
|
||||
|
||||
Inode = Directory->Inode;
|
||||
DirInoSize = EXT4_INODE_SIZE (Inode);
|
||||
|
||||
DivU64x32Remainder (DirInoSize, Partition->BlockSize, &BlockRemainder);
|
||||
if (BlockRemainder != 0) {
|
||||
// Directory inodes need to have block aligned sizes
|
||||
Status = EFI_VOLUME_CORRUPTED;
|
||||
goto Out;
|
||||
}
|
||||
|
||||
while (Off < DirInoSize) {
|
||||
Length = Partition->BlockSize;
|
||||
|
||||
Status = Ext4Read (Partition, Directory, Buf, Off, &Length);
|
||||
|
||||
if (Status != EFI_SUCCESS) {
|
||||
goto Out;
|
||||
}
|
||||
|
||||
for (BlockOffset = 0; BlockOffset < Partition->BlockSize; ) {
|
||||
Entry = (EXT4_DIR_ENTRY *)(Buf + BlockOffset);
|
||||
RemainingBlock = Partition->BlockSize - BlockOffset;
|
||||
// Check if the minimum directory entry fits inside [BlockOffset, EndOfBlock]
|
||||
if (RemainingBlock < EXT4_MIN_DIR_ENTRY_LEN) {
|
||||
Status = EFI_VOLUME_CORRUPTED;
|
||||
goto Out;
|
||||
}
|
||||
|
||||
if (!Ext4ValidDirent (Entry)) {
|
||||
Status = EFI_VOLUME_CORRUPTED;
|
||||
goto Out;
|
||||
}
|
||||
|
||||
if ((Entry->name_len > RemainingBlock) || (Entry->rec_len > RemainingBlock)) {
|
||||
// Corrupted filesystem
|
||||
Status = EFI_VOLUME_CORRUPTED;
|
||||
goto Out;
|
||||
}
|
||||
|
||||
// Unused entry
|
||||
if (Entry->inode == 0) {
|
||||
BlockOffset += Entry->rec_len;
|
||||
continue;
|
||||
}
|
||||
|
||||
Status = Ext4GetUcs2DirentName (Entry, DirentUcs2Name);
|
||||
|
||||
/* In theory, this should never fail.
|
||||
* In reality, it's quite possible that it can fail, considering filenames in
|
||||
* Linux (and probably other nixes) are just null-terminated bags of bytes, and don't
|
||||
* need to form valid ASCII/UTF-8 sequences.
|
||||
*/
|
||||
if (EFI_ERROR (Status)) {
|
||||
if (Status == EFI_INVALID_PARAMETER) {
|
||||
// If we error out due to a bad UTF-8 sequence (see Ext4GetUcs2DirentName), skip this entry.
|
||||
// I'm not sure if this is correct behaviour, but I don't think there's a precedent here.
|
||||
BlockOffset += Entry->rec_len;
|
||||
continue;
|
||||
}
|
||||
|
||||
// Other sorts of errors should just error out.
|
||||
FreePool (Buf);
|
||||
return Status;
|
||||
}
|
||||
|
||||
if ((Entry->name_len == StrLen (Name)) &&
|
||||
!Ext4StrCmpInsensitive (DirentUcs2Name, (CHAR16 *)Name))
|
||||
{
|
||||
ToCopy = MIN (Entry->rec_len, sizeof (EXT4_DIR_ENTRY));
|
||||
|
||||
CopyMem (Result, Entry, ToCopy);
|
||||
Status = EFI_SUCCESS;
|
||||
goto Out;
|
||||
}
|
||||
|
||||
BlockOffset += Entry->rec_len;
|
||||
}
|
||||
|
||||
Off += Partition->BlockSize;
|
||||
}
|
||||
|
||||
Status = EFI_NOT_FOUND;
|
||||
|
||||
Out:
|
||||
FreePool (Buf);
|
||||
return Status;
|
||||
}
|
||||
|
||||
/**
|
||||
Opens a file using a directory entry.
|
||||
|
||||
@param[in] Partition Pointer to the ext4 partition.
|
||||
@param[in] OpenMode Mode in which the file is supposed to be open.
|
||||
@param[out] OutFile Pointer to the newly opened file.
|
||||
@param[in] Entry Directory entry to be used.
|
||||
@param[in] Directory Pointer to the opened directory.
|
||||
|
||||
@retval EFI_STATUS Result of the operation
|
||||
**/
|
||||
EFI_STATUS
|
||||
Ext4OpenDirent (
|
||||
IN EXT4_PARTITION *Partition,
|
||||
IN UINT64 OpenMode,
|
||||
OUT EXT4_FILE **OutFile,
|
||||
IN EXT4_DIR_ENTRY *Entry,
|
||||
IN EXT4_FILE *Directory
|
||||
)
|
||||
{
|
||||
EFI_STATUS Status;
|
||||
CHAR16 FileName[EXT4_NAME_MAX + 1];
|
||||
EXT4_FILE *File;
|
||||
|
||||
File = AllocateZeroPool (sizeof (EXT4_FILE));
|
||||
|
||||
if (File == NULL) {
|
||||
Status = EFI_OUT_OF_RESOURCES;
|
||||
goto Error;
|
||||
}
|
||||
|
||||
Status = Ext4GetUcs2DirentName (Entry, FileName);
|
||||
|
||||
if (EFI_ERROR (Status)) {
|
||||
goto Error;
|
||||
}
|
||||
|
||||
if (StrCmp (FileName, L".") == 0) {
|
||||
// We're using the parent directory's dentry
|
||||
File->Dentry = Directory->Dentry;
|
||||
|
||||
ASSERT (File->Dentry != NULL);
|
||||
|
||||
Ext4RefDentry (File->Dentry);
|
||||
} else if (StrCmp (FileName, L"..") == 0) {
|
||||
// Using the parent's parent's dentry
|
||||
File->Dentry = Directory->Dentry->Parent;
|
||||
|
||||
if (!File->Dentry) {
|
||||
// Someone tried .. on root, so direct them to /
|
||||
// This is an illegal EFI Open() but is possible to hit from a variety of internal code
|
||||
File->Dentry = Directory->Dentry;
|
||||
}
|
||||
|
||||
Ext4RefDentry (File->Dentry);
|
||||
} else {
|
||||
File->Dentry = Ext4CreateDentry (FileName, Directory->Dentry);
|
||||
|
||||
if (File->Dentry == NULL) {
|
||||
Status = EFI_OUT_OF_RESOURCES;
|
||||
goto Error;
|
||||
}
|
||||
}
|
||||
|
||||
Status = Ext4InitExtentsMap (File);
|
||||
|
||||
if (EFI_ERROR (Status)) {
|
||||
goto Error;
|
||||
}
|
||||
|
||||
File->InodeNum = Entry->inode;
|
||||
|
||||
Ext4SetupFile (File, Partition);
|
||||
|
||||
Status = Ext4ReadInode (Partition, Entry->inode, &File->Inode);
|
||||
|
||||
if (EFI_ERROR (Status)) {
|
||||
goto Error;
|
||||
}
|
||||
|
||||
*OutFile = File;
|
||||
|
||||
InsertTailList (&Partition->OpenFiles, &File->OpenFilesListNode);
|
||||
|
||||
return EFI_SUCCESS;
|
||||
|
||||
Error:
|
||||
if (File != NULL) {
|
||||
if (File->Dentry != NULL) {
|
||||
Ext4UnrefDentry (File->Dentry);
|
||||
}
|
||||
|
||||
if (File->ExtentsMap != NULL) {
|
||||
OrderedCollectionUninit (File->ExtentsMap);
|
||||
}
|
||||
|
||||
FreePool (File);
|
||||
}
|
||||
|
||||
return Status;
|
||||
}
|
||||
|
||||
/**
|
||||
Opens a file.
|
||||
|
||||
@param[in] Directory Pointer to the opened directory.
|
||||
@param[in] Name Pointer to the UCS-2 formatted filename.
|
||||
@param[in] Partition Pointer to the ext4 partition.
|
||||
@param[in] OpenMode Mode in which the file is supposed to be open.
|
||||
@param[out] OutFile Pointer to the newly opened file.
|
||||
|
||||
@return Result of the operation.
|
||||
**/
|
||||
EFI_STATUS
|
||||
Ext4OpenFile (
|
||||
IN EXT4_FILE *Directory,
|
||||
IN CONST CHAR16 *Name,
|
||||
IN EXT4_PARTITION *Partition,
|
||||
IN UINT64 OpenMode,
|
||||
OUT EXT4_FILE **OutFile
|
||||
)
|
||||
{
|
||||
EXT4_DIR_ENTRY Entry;
|
||||
EFI_STATUS Status;
|
||||
|
||||
Status = Ext4RetrieveDirent (Directory, Name, Partition, &Entry);
|
||||
|
||||
if (EFI_ERROR (Status)) {
|
||||
return Status;
|
||||
}
|
||||
|
||||
// EFI requires us to error out on ".." opens for the root directory
|
||||
if (Entry.inode == Directory->InodeNum) {
|
||||
return EFI_NOT_FOUND;
|
||||
}
|
||||
|
||||
return Ext4OpenDirent (Partition, OpenMode, OutFile, &Entry, Directory);
|
||||
}
|
||||
|
||||
/**
|
||||
Open the root directory on a volume.
|
||||
|
||||
@param[in] This A pointer to the volume to open the root directory.
|
||||
@param[out] Root A pointer to the location to return the opened file handle for the
|
||||
root directory.
|
||||
|
||||
@retval EFI_SUCCESS The device was opened.
|
||||
@retval EFI_UNSUPPORTED This volume does not support the requested file system type.
|
||||
@retval EFI_NO_MEDIA The device has no medium.
|
||||
@retval EFI_DEVICE_ERROR The device reported an error.
|
||||
@retval EFI_VOLUME_CORRUPTED The file system structures are corrupted.
|
||||
@retval EFI_ACCESS_DENIED The service denied access to the file.
|
||||
@retval EFI_OUT_OF_RESOURCES The volume was not opened due to lack of resources.
|
||||
@retval EFI_MEDIA_CHANGED The device has a different medium in it or the medium is no
|
||||
longer supported. Any existing file handles for this volume are
|
||||
no longer valid. To access the files on the new medium, the
|
||||
volume must be reopened with OpenVolume().
|
||||
|
||||
**/
|
||||
EFI_STATUS
|
||||
EFIAPI
|
||||
Ext4OpenVolume (
|
||||
IN EFI_SIMPLE_FILE_SYSTEM_PROTOCOL *This,
|
||||
OUT EFI_FILE_PROTOCOL **Root
|
||||
)
|
||||
{
|
||||
EXT4_INODE *RootInode;
|
||||
EFI_STATUS Status;
|
||||
EXT4_FILE *RootDir;
|
||||
EXT4_PARTITION *Partition;
|
||||
|
||||
Partition = (EXT4_PARTITION *)This;
|
||||
|
||||
Status = Ext4ReadInode (Partition, EXT4_ROOT_INODE_NR, &RootInode);
|
||||
|
||||
if (EFI_ERROR (Status)) {
|
||||
DEBUG ((DEBUG_ERROR, "[ext4] Could not open root inode - error %r\n", Status));
|
||||
return Status;
|
||||
}
|
||||
|
||||
RootDir = AllocateZeroPool (sizeof (EXT4_FILE));
|
||||
|
||||
if (RootDir == NULL) {
|
||||
FreePool (RootInode);
|
||||
return EFI_OUT_OF_RESOURCES;
|
||||
}
|
||||
|
||||
RootDir->Inode = RootInode;
|
||||
RootDir->InodeNum = EXT4_ROOT_INODE_NR;
|
||||
|
||||
Status = Ext4InitExtentsMap (RootDir);
|
||||
|
||||
if (EFI_ERROR (Status)) {
|
||||
FreePool (RootInode);
|
||||
FreePool (RootDir);
|
||||
return EFI_OUT_OF_RESOURCES;
|
||||
}
|
||||
|
||||
Ext4SetupFile (RootDir, Partition);
|
||||
*Root = &RootDir->Protocol;
|
||||
|
||||
InsertTailList (&Partition->OpenFiles, &RootDir->OpenFilesListNode);
|
||||
|
||||
ASSERT (Partition->RootDentry != NULL);
|
||||
RootDir->Dentry = Partition->RootDentry;
|
||||
|
||||
Ext4RefDentry (RootDir->Dentry);
|
||||
|
||||
return EFI_SUCCESS;
|
||||
}
|
||||
|
||||
/**
|
||||
Reads a directory entry.
|
||||
|
||||
@param[in] Partition Pointer to the ext4 partition.
|
||||
@param[in] File Pointer to the open directory.
|
||||
@param[out] Buffer Pointer to the output buffer.
|
||||
@param[in] Offset Initial directory position.
|
||||
@param[in out] OutLength Pointer to a UINTN that contains the length of the buffer,
|
||||
and the length of the actual EFI_FILE_INFO after the call.
|
||||
|
||||
@return Result of the operation.
|
||||
**/
|
||||
EFI_STATUS
|
||||
Ext4ReadDir (
|
||||
IN EXT4_PARTITION *Partition,
|
||||
IN EXT4_FILE *File,
|
||||
OUT VOID *Buffer,
|
||||
IN UINT64 Offset,
|
||||
IN OUT UINTN *OutLength
|
||||
)
|
||||
{
|
||||
EXT4_INODE *DirIno;
|
||||
EFI_STATUS Status;
|
||||
UINT64 DirInoSize;
|
||||
UINTN Len;
|
||||
UINT32 BlockRemainder;
|
||||
EXT4_DIR_ENTRY Entry;
|
||||
EXT4_FILE *TempFile;
|
||||
BOOLEAN ShouldSkip;
|
||||
BOOLEAN IsDotOrDotDot;
|
||||
CHAR16 DirentUcs2Name[EXT4_NAME_MAX + 1];
|
||||
|
||||
DirIno = File->Inode;
|
||||
Status = EFI_SUCCESS;
|
||||
DirInoSize = EXT4_INODE_SIZE (DirIno);
|
||||
|
||||
DivU64x32Remainder (DirInoSize, Partition->BlockSize, &BlockRemainder);
|
||||
if (BlockRemainder != 0) {
|
||||
// Directory inodes need to have block aligned sizes
|
||||
return EFI_VOLUME_CORRUPTED;
|
||||
}
|
||||
|
||||
while (TRUE) {
|
||||
TempFile = NULL;
|
||||
|
||||
// We (try to) read the maximum size of a directory entry at a time
|
||||
// Note that we don't need to read any padding that may exist after it.
|
||||
Len = sizeof (Entry);
|
||||
Status = Ext4Read (Partition, File, &Entry, Offset, &Len);
|
||||
|
||||
if (EFI_ERROR (Status)) {
|
||||
goto Out;
|
||||
}
|
||||
|
||||
if (Len == 0) {
|
||||
*OutLength = 0;
|
||||
Status = EFI_SUCCESS;
|
||||
goto Out;
|
||||
}
|
||||
|
||||
if (Len < EXT4_MIN_DIR_ENTRY_LEN) {
|
||||
Status = EFI_VOLUME_CORRUPTED;
|
||||
goto Out;
|
||||
}
|
||||
|
||||
// Invalid directory entry length
|
||||
if (!Ext4ValidDirent (&Entry)) {
|
||||
DEBUG ((DEBUG_ERROR, "[ext4] Invalid dirent at offset %lu\n", Offset));
|
||||
Status = EFI_VOLUME_CORRUPTED;
|
||||
goto Out;
|
||||
}
|
||||
|
||||
// Check if the entire dir entry length fits in Len
|
||||
if (Len < (UINTN)(EXT4_MIN_DIR_ENTRY_LEN + Entry.name_len)) {
|
||||
Status = EFI_VOLUME_CORRUPTED;
|
||||
goto Out;
|
||||
}
|
||||
|
||||
// We don't care about passing . or .. entries to the caller of ReadDir(),
|
||||
// since they're generally useless entries *and* may break things if too
|
||||
// many callers assume FAT32.
|
||||
|
||||
// Entry.name_len may be 0 if it's a nameless entry, like an unused entry
|
||||
// or a checksum at the end of the directory block.
|
||||
// memcmp (and CompareMem) return 0 when the passed length is 0.
|
||||
|
||||
// We must bound name_len as > 0 and <= 2 to avoid any out-of-bounds accesses or bad detection of
|
||||
// "." and "..".
|
||||
IsDotOrDotDot = Entry.name_len > 0 && Entry.name_len <= 2 &&
|
||||
CompareMem (Entry.name, "..", Entry.name_len) == 0;
|
||||
|
||||
// When inode = 0, it's unused. When name_len == 0, it's a nameless entry
|
||||
// (which we should not expose to ReadDir).
|
||||
ShouldSkip = Entry.inode == 0 || Entry.name_len == 0 || IsDotOrDotDot;
|
||||
|
||||
if (ShouldSkip) {
|
||||
Offset += Entry.rec_len;
|
||||
continue;
|
||||
}
|
||||
|
||||
// Test if the dirent is valid utf-8. This is already done inside Ext4OpenDirent but EFI_INVALID_PARAMETER
|
||||
// has the danger of its meaning being overloaded in many places, so we can't skip according to that.
|
||||
// So test outside of it, explicitly.
|
||||
Status = Ext4GetUcs2DirentName (&Entry, DirentUcs2Name);
|
||||
|
||||
if (EFI_ERROR (Status)) {
|
||||
if (Status == EFI_INVALID_PARAMETER) {
|
||||
// Bad UTF-8, skip.
|
||||
Offset += Entry.rec_len;
|
||||
continue;
|
||||
}
|
||||
|
||||
goto Out;
|
||||
}
|
||||
|
||||
Status = Ext4OpenDirent (Partition, EFI_FILE_MODE_READ, &TempFile, &Entry, File);
|
||||
|
||||
if (EFI_ERROR (Status)) {
|
||||
goto Out;
|
||||
}
|
||||
|
||||
Status = Ext4GetFileInfo (TempFile, Buffer, OutLength);
|
||||
if (!EFI_ERROR (Status)) {
|
||||
File->Position = Offset + Entry.rec_len;
|
||||
}
|
||||
|
||||
Ext4CloseInternal (TempFile);
|
||||
|
||||
goto Out;
|
||||
}
|
||||
|
||||
Status = EFI_SUCCESS;
|
||||
Out:
|
||||
return Status;
|
||||
}
|
||||
|
||||
/**
|
||||
Removes a dentry from the other's list.
|
||||
|
||||
@param[in out] Parent Pointer to the parent EXT4_DENTRY.
|
||||
@param[in out] ToBeRemoved Pointer to the child EXT4_DENTRY.
|
||||
**/
|
||||
STATIC
|
||||
VOID
|
||||
Ext4RemoveDentry (
|
||||
IN OUT EXT4_DENTRY *Parent,
|
||||
IN OUT EXT4_DENTRY *ToBeRemoved
|
||||
)
|
||||
{
|
||||
ASSERT (IsNodeInList (&ToBeRemoved->ListNode, &Parent->Children));
|
||||
RemoveEntryList (&ToBeRemoved->ListNode);
|
||||
}
|
||||
|
||||
/**
|
||||
Adds a dentry to the other's list.
|
||||
|
||||
The dentry that is added to the other one's list gets ->Parent set to Parent,
|
||||
and the parent gets its reference count incremented.
|
||||
|
||||
@param[in out] Parent Pointer to the parent EXT4_DENTRY.
|
||||
@param[in out] ToBeAdded Pointer to the child EXT4_DENTRY.
|
||||
**/
|
||||
STATIC
|
||||
VOID
|
||||
Ext4AddDentry (
|
||||
IN OUT EXT4_DENTRY *Parent,
|
||||
IN OUT EXT4_DENTRY *ToBeAdded
|
||||
)
|
||||
{
|
||||
ToBeAdded->Parent = Parent;
|
||||
InsertTailList (&Parent->Children, &ToBeAdded->ListNode);
|
||||
Ext4RefDentry (Parent);
|
||||
}
|
||||
|
||||
/**
|
||||
Creates a new dentry object.
|
||||
|
||||
@param[in] Name Name of the dentry.
|
||||
@param[in out opt] Parent Parent dentry, if it's not NULL.
|
||||
|
||||
@return The new allocated and initialised dentry.
|
||||
The ref count will be set to 1.
|
||||
**/
|
||||
EXT4_DENTRY *
|
||||
Ext4CreateDentry (
|
||||
IN CONST CHAR16 *Name,
|
||||
IN OUT EXT4_DENTRY *Parent OPTIONAL
|
||||
)
|
||||
{
|
||||
EXT4_DENTRY *Dentry;
|
||||
EFI_STATUS Status;
|
||||
|
||||
Dentry = AllocateZeroPool (sizeof (EXT4_DENTRY));
|
||||
|
||||
if (Dentry == NULL) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
Dentry->RefCount = 1;
|
||||
|
||||
// This StrCpyS should not fail.
|
||||
Status = StrCpyS (Dentry->Name, ARRAY_SIZE (Dentry->Name), Name);
|
||||
|
||||
ASSERT_EFI_ERROR (Status);
|
||||
|
||||
InitializeListHead (&Dentry->Children);
|
||||
|
||||
if (Parent != NULL) {
|
||||
Ext4AddDentry (Parent, Dentry);
|
||||
}
|
||||
|
||||
DEBUG ((DEBUG_FS, "[ext4] Created dentry %s\n", Name));
|
||||
|
||||
return Dentry;
|
||||
}
|
||||
|
||||
/**
|
||||
Increments the ref count of the dentry.
|
||||
|
||||
@param[in out] Dentry Pointer to a valid EXT4_DENTRY.
|
||||
**/
|
||||
VOID
|
||||
Ext4RefDentry (
|
||||
IN OUT EXT4_DENTRY *Dentry
|
||||
)
|
||||
{
|
||||
UINTN OldRef;
|
||||
|
||||
OldRef = Dentry->RefCount;
|
||||
|
||||
Dentry->RefCount++;
|
||||
|
||||
// I'm not sure if this (Refcount overflow) is a valid concern,
|
||||
// but it's better to be safe than sorry.
|
||||
ASSERT (OldRef < Dentry->RefCount);
|
||||
}
|
||||
|
||||
/**
|
||||
Deletes the dentry.
|
||||
|
||||
@param[in out] Dentry Pointer to a valid EXT4_DENTRY.
|
||||
**/
|
||||
STATIC
|
||||
VOID
|
||||
Ext4DeleteDentry (
|
||||
IN OUT EXT4_DENTRY *Dentry
|
||||
)
|
||||
{
|
||||
if (Dentry->Parent) {
|
||||
Ext4RemoveDentry (Dentry->Parent, Dentry);
|
||||
Ext4UnrefDentry (Dentry->Parent);
|
||||
}
|
||||
|
||||
DEBUG ((DEBUG_FS, "[ext4] Deleted dentry %s\n", Dentry->Name));
|
||||
FreePool (Dentry);
|
||||
}
|
||||
|
||||
/**
|
||||
Decrements the ref count of the dentry.
|
||||
If the ref count is 0, it's destroyed.
|
||||
|
||||
@param[in out] Dentry Pointer to a valid EXT4_DENTRY.
|
||||
|
||||
@retval True if it was destroyed, false if it's alive.
|
||||
**/
|
||||
BOOLEAN
|
||||
Ext4UnrefDentry (
|
||||
IN OUT EXT4_DENTRY *Dentry
|
||||
)
|
||||
{
|
||||
Dentry->RefCount--;
|
||||
|
||||
if (Dentry->RefCount == 0) {
|
||||
Ext4DeleteDentry (Dentry);
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
return FALSE;
|
||||
}
|
|
@ -0,0 +1,123 @@
|
|||
/** @file
|
||||
Disk utilities
|
||||
|
||||
Copyright (c) 2021 Pedro Falcato All rights reserved.
|
||||
SPDX-License-Identifier: BSD-2-Clause-Patent
|
||||
**/
|
||||
#include "Ext4Dxe.h"
|
||||
|
||||
/**
|
||||
Reads from the partition's disk using the DISK_IO protocol.
|
||||
|
||||
@param[in] Partition Pointer to the opened ext4 partition.
|
||||
@param[out] Buffer Pointer to a destination buffer.
|
||||
@param[in] Length Length of the destination buffer.
|
||||
@param[in] Offset Offset, in bytes, of the location to read.
|
||||
|
||||
@return Success status of the disk read.
|
||||
**/
|
||||
EFI_STATUS
|
||||
Ext4ReadDiskIo (
|
||||
IN EXT4_PARTITION *Partition,
|
||||
OUT VOID *Buffer,
|
||||
IN UINTN Length,
|
||||
IN UINT64 Offset
|
||||
)
|
||||
{
|
||||
return EXT4_DISK_IO (Partition)->ReadDisk (
|
||||
EXT4_DISK_IO (Partition),
|
||||
EXT4_MEDIA_ID (Partition),
|
||||
Offset,
|
||||
Length,
|
||||
Buffer
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
Reads blocks from the partition's disk using the DISK_IO protocol.
|
||||
|
||||
@param[in] Partition Pointer to the opened ext4 partition.
|
||||
@param[out] Buffer Pointer to a destination buffer.
|
||||
@param[in] NumberBlocks Length of the read, in filesystem blocks.
|
||||
@param[in] BlockNumber Starting block number.
|
||||
|
||||
@return Success status of the read.
|
||||
**/
|
||||
EFI_STATUS
|
||||
Ext4ReadBlocks (
|
||||
IN EXT4_PARTITION *Partition,
|
||||
OUT VOID *Buffer,
|
||||
IN UINTN NumberBlocks,
|
||||
IN EXT4_BLOCK_NR BlockNumber
|
||||
)
|
||||
{
|
||||
UINT64 Offset;
|
||||
UINTN Length;
|
||||
|
||||
ASSERT (NumberBlocks != 0);
|
||||
ASSERT (BlockNumber != EXT4_BLOCK_FILE_HOLE);
|
||||
|
||||
Offset = MultU64x32 (BlockNumber, Partition->BlockSize);
|
||||
Length = NumberBlocks * Partition->BlockSize;
|
||||
|
||||
// Check for overflow on the block -> byte conversions.
|
||||
// Partition->BlockSize is never 0, so we don't need to check for that.
|
||||
|
||||
if (DivU64x64Remainder (Offset, BlockNumber, NULL) != Partition->BlockSize) {
|
||||
return EFI_INVALID_PARAMETER;
|
||||
}
|
||||
|
||||
if (Length / NumberBlocks != Partition->BlockSize) {
|
||||
return EFI_INVALID_PARAMETER;
|
||||
}
|
||||
|
||||
return Ext4ReadDiskIo (Partition, Buffer, Length, Offset);
|
||||
}
|
||||
|
||||
/**
|
||||
Allocates a buffer and reads blocks from the partition's disk using the DISK_IO protocol.
|
||||
This function is deprecated and will be removed in the future.
|
||||
|
||||
@param[in] Partition Pointer to the opened ext4 partition.
|
||||
@param[in] NumberBlocks Length of the read, in filesystem blocks.
|
||||
@param[in] BlockNumber Starting block number.
|
||||
|
||||
@return Buffer allocated by AllocatePool, or NULL if some part of the process
|
||||
failed.
|
||||
**/
|
||||
VOID *
|
||||
Ext4AllocAndReadBlocks (
|
||||
IN EXT4_PARTITION *Partition,
|
||||
IN UINTN NumberBlocks,
|
||||
IN EXT4_BLOCK_NR BlockNumber
|
||||
)
|
||||
{
|
||||
VOID *Buf;
|
||||
UINTN Length;
|
||||
|
||||
// Check that number of blocks isn't empty, because
|
||||
// this is incorrect condition for opened partition,
|
||||
// so we just early-exit
|
||||
if ((NumberBlocks == 0) || (BlockNumber == EXT4_BLOCK_FILE_HOLE)) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
Length = NumberBlocks * Partition->BlockSize;
|
||||
|
||||
// Check for integer overflow
|
||||
if (Length / NumberBlocks != Partition->BlockSize) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
Buf = AllocatePool (Length);
|
||||
if (Buf == NULL) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (Ext4ReadBlocks (Partition, Buf, NumberBlocks, BlockNumber) != EFI_SUCCESS) {
|
||||
FreePool (Buf);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return Buf;
|
||||
}
|
|
@ -0,0 +1,501 @@
|
|||
/** @file
|
||||
Raw filesystem data structures
|
||||
|
||||
Copyright (c) 2021 - 2023 Pedro Falcato All rights reserved.
|
||||
SPDX-License-Identifier: BSD-2-Clause-Patent
|
||||
|
||||
Layout of an EXT2/3/4 filesystem:
|
||||
(note: this driver has been developed using
|
||||
https://www.kernel.org/doc/html/latest/filesystems/ext4/index.html as
|
||||
documentation).
|
||||
|
||||
An ext2/3/4 filesystem (here on out referred to as simply an ext4 filesystem,
|
||||
due to the similarities) is composed of various concepts:
|
||||
|
||||
1) Superblock
|
||||
The superblock is the structure near (1024 bytes offset from the start)
|
||||
the start of the partition, and describes the filesystem in general.
|
||||
Here, we get to know the size of the filesystem's blocks, which features
|
||||
it supports or not, whether it's been cleanly unmounted, how many blocks
|
||||
we have, etc.
|
||||
|
||||
2) Block groups
|
||||
EXT4 filesystems are divided into block groups, and each block group covers
|
||||
s_blocks_per_group(8 * Block Size) blocks. Each block group has an
|
||||
associated block group descriptor; these are present directly after the
|
||||
superblock. Each block group descriptor contains the location of the
|
||||
inode table, and the inode and block bitmaps (note these bitmaps are only
|
||||
a block long, which gets us the 8 * Block Size formula covered previously).
|
||||
|
||||
3) Blocks
|
||||
The ext4 filesystem is divided in blocks, of size s_log_block_size ^ 1024.
|
||||
Blocks can be allocated using individual block groups's bitmaps. Note
|
||||
that block 0 is invalid and its presence on extents/block tables means
|
||||
it's part of a file hole, and that particular location must be read as
|
||||
a block full of zeros.
|
||||
|
||||
4) Inodes
|
||||
The ext4 filesystem divides files/directories into inodes (originally
|
||||
index nodes). Each file/socket/symlink/directory/etc (here on out referred
|
||||
to as a file, since there is no distinction under the ext4 filesystem) is
|
||||
stored as a /nameless/ inode, that is stored in some block group's inode
|
||||
table. Each inode has s_inode_size size (or GOOD_OLD_INODE_SIZE if it's
|
||||
an old filesystem), and holds various metadata about the file. Since the
|
||||
largest inode structure right now is ~160 bytes, the rest of the inode
|
||||
contains inline extended attributes. Inodes' data is stored using either
|
||||
data blocks (under ext2/3) or extents (under ext4).
|
||||
|
||||
5) Extents
|
||||
Ext4 inodes store data in extents. These let N contiguous logical blocks
|
||||
that are represented by N contiguous physical blocks be represented by a
|
||||
single extent structure, which minimizes filesystem metadata bloat and
|
||||
speeds up block mapping (particularly due to the fact that high-quality
|
||||
ext4 implementations like linux's try /really/ hard to make the file
|
||||
contiguous, so it's common to have files with almost 0 fragmentation).
|
||||
Inodes that use extents store them in a tree, and the top of the tree
|
||||
is stored on i_data. The tree's leaves always start with an
|
||||
EXT4_EXTENT_HEADER and contain EXT4_EXTENT_INDEX on eh_depth != 0 and
|
||||
EXT4_EXTENT on eh_depth = 0; these entries are always sorted by logical
|
||||
block.
|
||||
|
||||
6) Directories
|
||||
Ext4 directories are files that store name -> inode mappings for the
|
||||
logical directory; this is where files get their names, which means ext4
|
||||
inodes do not themselves have names, since they can be linked (present)
|
||||
multiple times with different names. Directories can store entries in two
|
||||
different ways:
|
||||
1) Classical linear directories: They store entries as a mostly-linked
|
||||
mostly-list of EXT4_DIR_ENTRY.
|
||||
2) Hash tree directories: These are used for larger directories, with
|
||||
hundreds of entries, and are designed in a backwards compatible way.
|
||||
These are not yet implemented in the Ext4Dxe driver.
|
||||
|
||||
7) Journal
|
||||
Ext3/4 filesystems have a journal to help protect the filesystem against
|
||||
system crashes. This is not yet implemented in Ext4Dxe but is described
|
||||
in detail in the Linux kernel's documentation.
|
||||
**/
|
||||
|
||||
#ifndef EXT4_DISK_H_
|
||||
#define EXT4_DISK_H_
|
||||
|
||||
#include <Uefi.h>
|
||||
|
||||
#define EXT4_SUPERBLOCK_OFFSET 1024U
|
||||
|
||||
#define EXT4_SIGNATURE 0xEF53U
|
||||
|
||||
#define EXT4_FS_STATE_UNMOUNTED 0x1
|
||||
#define EXT4_FS_STATE_ERRORS_DETECTED 0x2
|
||||
#define EXT4_FS_STATE_RECOVERING_ORPHANS 0x4
|
||||
|
||||
#define EXT4_ERRORS_CONTINUE 1
|
||||
#define EXT4_ERRORS_RO 2
|
||||
#define EXT4_ERRORS_PANIC 3
|
||||
|
||||
#define EXT4_LINUX_ID 0
|
||||
#define EXT4_GNU_HURD_ID 1
|
||||
#define EXT4_MASIX_ID 2
|
||||
#define EXT4_FREEBSD_ID 3
|
||||
#define EXT4_LITES_ID 4
|
||||
|
||||
#define EXT4_GOOD_OLD_REV 0
|
||||
#define EXT4_DYNAMIC_REV 1
|
||||
|
||||
#define EXT4_CHECKSUM_CRC32C 0x1
|
||||
|
||||
#define EXT4_FEATURE_COMPAT_DIR_PREALLOC 0x01
|
||||
#define EXT4_FEATURE_COMPAT_IMAGIC_INODES 0x02
|
||||
#define EXT3_FEATURE_COMPAT_HAS_JOURNAL 0x04
|
||||
#define EXT4_FEATURE_COMPAT_EXT_ATTR 0x08
|
||||
#define EXT4_FEATURE_COMPAT_RESIZE_INO 0x10
|
||||
#define EXT4_FEATURE_COMPAT_DIR_INDEX 0x20
|
||||
|
||||
#define EXT4_FEATURE_INCOMPAT_COMPRESSION 0x00001
|
||||
#define EXT4_FEATURE_INCOMPAT_FILETYPE 0x00002
|
||||
#define EXT4_FEATURE_INCOMPAT_RECOVER 0x00004
|
||||
#define EXT4_FEATURE_INCOMPAT_JOURNAL_DEV 0x00008
|
||||
#define EXT4_FEATURE_INCOMPAT_META_BG 0x00010
|
||||
#define EXT4_FEATURE_INCOMPAT_EXTENTS 0x00040
|
||||
#define EXT4_FEATURE_INCOMPAT_64BIT 0x00080
|
||||
#define EXT4_FEATURE_INCOMPAT_MMP 0x00100
|
||||
#define EXT4_FEATURE_INCOMPAT_FLEX_BG 0x00200
|
||||
#define EXT4_FEATURE_INCOMPAT_EA_INODE 0x00400
|
||||
// It's not clear whether or not this feature (below) is used right now
|
||||
#define EXT4_FEATURE_INCOMPAT_DIRDATA 0x01000
|
||||
#define EXT4_FEATURE_INCOMPAT_CSUM_SEED 0x02000
|
||||
#define EXT4_FEATURE_INCOMPAT_LARGEDIR 0x04000
|
||||
#define EXT4_FEATURE_INCOMPAT_INLINE_DATA 0x08000
|
||||
#define EXT4_FEATURE_INCOMPAT_ENCRYPT 0x10000
|
||||
|
||||
#define EXT4_FEATURE_RO_COMPAT_SPARSE_SUPER 0x0001
|
||||
#define EXT4_FEATURE_RO_COMPAT_LARGE_FILE 0x0002
|
||||
#define EXT4_FEATURE_RO_COMPAT_BTREE_DIR 0x0004// Unused
|
||||
#define EXT4_FEATURE_RO_COMPAT_HUGE_FILE 0x0008
|
||||
#define EXT4_FEATURE_RO_COMPAT_GDT_CSUM 0x0010
|
||||
#define EXT4_FEATURE_RO_COMPAT_DIR_NLINK 0x0020
|
||||
#define EXT4_FEATURE_RO_COMPAT_EXTRA_ISIZE 0x0040
|
||||
#define EXT4_FEATURE_RO_COMPAT_HAS_SNAPSHOT 0x0080// Not implemented in ext4
|
||||
#define EXT4_FEATURE_RO_COMPAT_QUOTA 0x0100
|
||||
#define EXT4_FEATURE_RO_COMPAT_BIGALLOC 0x0200
|
||||
#define EXT4_FEATURE_RO_COMPAT_METADATA_CSUM 0x0400
|
||||
#define EXT4_FEATURE_RO_COMPAT_REPLICA 0x0800// Not used
|
||||
|
||||
// We explicitly don't recognise this, so we get read only.
|
||||
#define EXT4_FEATURE_RO_COMPAT_READONLY 0x1000
|
||||
#define EXT4_FEATURE_RO_COMPAT_PROJECT 0x2000
|
||||
|
||||
/* Important notes about the features
|
||||
* Absolutely needed features:
|
||||
* 1) Every incompat, because we might want to mount root filesystems
|
||||
* 2) Relevant RO_COMPATs(I'm not sure of what to do wrt quota, project)
|
||||
**/
|
||||
|
||||
#define EXT4_INO_TYPE_FIFO 0x1000
|
||||
#define EXT4_INO_TYPE_CHARDEV 0x2000
|
||||
#define EXT4_INO_TYPE_DIR 0x4000
|
||||
#define EXT4_INO_TYPE_BLOCKDEV 0x6000
|
||||
#define EXT4_INO_TYPE_REGFILE 0x8000
|
||||
#define EXT4_INO_TYPE_SYMLINK 0xA000
|
||||
#define EXT4_INO_TYPE_UNIX_SOCK 0xC000
|
||||
|
||||
/* Inode flags */
|
||||
#define EXT4_SECRM_FL 0x00000001
|
||||
#define EXT4_UNRM_FL 0x00000002
|
||||
#define EXT4_COMPR_FL 0x00000004
|
||||
#define EXT4_SYNC_FL 0x00000008
|
||||
#define EXT4_IMMUTABLE_FL 0x00000010
|
||||
#define EXT4_APPEND_FL 0x00000020
|
||||
#define EXT4_NODUMP_FL 0x00000040
|
||||
#define EXT4_NOATIME_FL 0x00000080
|
||||
#define EXT4_DIRTY_FL 0x00000100
|
||||
#define EXT4_COMPRBLK_FL 0x00000200
|
||||
#define EXT4_NOCOMPR_FL 0x00000400
|
||||
#define EXT4_ENCRYPT_FL 0x00000800
|
||||
#define EXT4_BTREE_FL 0x00001000
|
||||
#define EXT4_INDEX_FL 0x00002000
|
||||
#define EXT4_JOURNAL_DATA_FL 0x00004000
|
||||
#define EXT4_NOTAIL_FL 0x00008000
|
||||
#define EXT4_DIRSYNC_FL 0x00010000
|
||||
#define EXT4_TOPDIR_FL 0x00020000
|
||||
#define EXT4_HUGE_FILE_FL 0x00040000
|
||||
#define EXT4_EXTENTS_FL 0x00080000
|
||||
#define EXT4_VERITY_FL 0x00100000
|
||||
#define EXT4_EA_INODE_FL 0x00200000
|
||||
#define EXT4_RESERVED_FL 0x80000000
|
||||
|
||||
/* File type flags that are stored in the directory entries */
|
||||
#define EXT4_FT_UNKNOWN 0
|
||||
#define EXT4_FT_REG_FILE 1
|
||||
#define EXT4_FT_DIR 2
|
||||
#define EXT4_FT_CHRDEV 3
|
||||
#define EXT4_FT_BLKDEV 4
|
||||
#define EXT4_FT_FIFO 5
|
||||
#define EXT4_FT_SOCK 6
|
||||
#define EXT4_FT_SYMLINK 7
|
||||
|
||||
typedef struct {
|
||||
UINT32 s_inodes_count;
|
||||
UINT32 s_blocks_count;
|
||||
UINT32 s_r_blocks_count;
|
||||
UINT32 s_free_blocks_count;
|
||||
UINT32 s_free_inodes_count;
|
||||
UINT32 s_first_data_block;
|
||||
UINT32 s_log_block_size;
|
||||
UINT32 s_log_frag_size;
|
||||
UINT32 s_blocks_per_group;
|
||||
UINT32 s_frags_per_group;
|
||||
UINT32 s_inodes_per_group;
|
||||
UINT32 s_mtime;
|
||||
UINT32 s_wtime;
|
||||
UINT16 s_mnt_count;
|
||||
UINT16 s_max_mnt_count;
|
||||
UINT16 s_magic;
|
||||
UINT16 s_state;
|
||||
UINT16 s_errors;
|
||||
UINT16 s_minor_rev_level;
|
||||
UINT32 s_lastcheck;
|
||||
UINT32 s_check_interval;
|
||||
UINT32 s_creator_os;
|
||||
UINT32 s_rev_level;
|
||||
UINT16 s_def_resuid;
|
||||
UINT16 s_def_resgid;
|
||||
|
||||
/* Every field after this comment is revision >= 1 */
|
||||
|
||||
UINT32 s_first_ino;
|
||||
UINT16 s_inode_size;
|
||||
UINT16 s_block_group_nr;
|
||||
UINT32 s_feature_compat;
|
||||
UINT32 s_feature_incompat;
|
||||
UINT32 s_feature_ro_compat;
|
||||
UINT8 s_uuid[16];
|
||||
UINT8 s_volume_name[16];
|
||||
UINT8 s_last_mounted[64];
|
||||
UINT32 s_algo_bitmap;
|
||||
UINT8 s_prealloc_blocks;
|
||||
UINT8 s_prealloc_dir_blocks;
|
||||
UINT16 unused;
|
||||
UINT8 s_journal_uuid[16];
|
||||
UINT32 s_journal_inum;
|
||||
UINT32 s_journal_dev;
|
||||
UINT32 s_last_orphan;
|
||||
UINT32 s_hash_seed[4];
|
||||
UINT8 s_def_hash_version;
|
||||
UINT8 s_jnl_backup_type;
|
||||
UINT16 s_desc_size;
|
||||
UINT32 s_default_mount_options;
|
||||
UINT32 s_first_meta_bg;
|
||||
UINT32 s_mkfs_time;
|
||||
UINT32 s_jnl_blocks[17];
|
||||
UINT32 s_blocks_count_hi;
|
||||
UINT32 s_r_blocks_count_hi;
|
||||
UINT32 s_free_blocks_count_hi;
|
||||
UINT16 s_min_extra_isize;
|
||||
UINT16 s_want_extra_isize;
|
||||
UINT32 s_flags;
|
||||
UINT16 s_raid_stride;
|
||||
UINT16 s_mmp_interval;
|
||||
UINT64 s_mmp_block;
|
||||
UINT32 s_raid_stride_width;
|
||||
UINT8 s_log_groups_per_flex;
|
||||
UINT8 s_checksum_type; // Only valid value is 1 - CRC32C
|
||||
UINT16 s_reserved_pad;
|
||||
UINT64 s_kbytes_written;
|
||||
|
||||
// Snapshot stuff isn't used in Linux and isn't implemented here
|
||||
UINT32 s_snapshot_inum;
|
||||
UINT32 s_snapshot_id;
|
||||
UINT64 s_snapshot_r_blocks_count;
|
||||
UINT32 s_snapshot_list;
|
||||
UINT32 s_error_count;
|
||||
UINT32 s_first_error_time;
|
||||
UINT32 s_first_error_ino;
|
||||
UINT64 s_first_error_block;
|
||||
UINT8 s_first_error_func[32];
|
||||
UINT32 s_first_error_line;
|
||||
UINT32 s_last_error_time;
|
||||
UINT32 s_last_error_ino;
|
||||
UINT32 s_last_error_line;
|
||||
UINT64 s_last_error_block;
|
||||
UINT8 s_last_error_func[32];
|
||||
UINT8 s_mount_opts[64];
|
||||
UINT32 s_usr_quota_inum;
|
||||
UINT32 s_grp_quota_inum;
|
||||
UINT32 s_overhead_blocks;
|
||||
UINT32 s_backup_bgs[2]; // sparse_super2
|
||||
UINT8 s_encrypt_algos[4];
|
||||
UINT8 s_encrypt_pw_salt[16];
|
||||
UINT32 s_lpf_ino;
|
||||
UINT32 s_prj_quota_inum;
|
||||
UINT32 s_checksum_seed;
|
||||
UINT32 s_reserved[98];
|
||||
UINT32 s_checksum;
|
||||
} EXT4_SUPERBLOCK;
|
||||
|
||||
STATIC_ASSERT (
|
||||
sizeof (EXT4_SUPERBLOCK) == 1024,
|
||||
"ext4 superblock struct has incorrect size"
|
||||
);
|
||||
|
||||
typedef struct {
|
||||
UINT32 bg_block_bitmap_lo;
|
||||
UINT32 bg_inode_bitmap_lo;
|
||||
UINT32 bg_inode_table_lo;
|
||||
UINT16 bg_free_blocks_count_lo;
|
||||
UINT16 bg_free_inodes_count_lo;
|
||||
UINT16 bg_used_dirs_count_lo;
|
||||
UINT16 bg_flags;
|
||||
UINT32 bg_exclude_bitmap_lo;
|
||||
UINT16 bg_block_bitmap_csum_lo;
|
||||
UINT16 bg_inode_bitmap_csum_lo;
|
||||
UINT16 bg_itable_unused_lo;
|
||||
UINT16 bg_checksum;
|
||||
UINT32 bg_block_bitmap_hi;
|
||||
UINT32 bg_inode_bitmap_hi;
|
||||
UINT32 bg_inode_table_hi;
|
||||
UINT16 bg_free_blocks_count_hi;
|
||||
UINT16 bg_free_inodes_count_hi;
|
||||
UINT16 bg_used_dirs_count_hi;
|
||||
UINT16 bg_itable_unused_hi;
|
||||
UINT32 bg_exclude_bitmap_hi;
|
||||
UINT16 bg_block_bitmap_csum_hi;
|
||||
UINT16 bg_inode_bitmap_csum_hi;
|
||||
UINT32 bg_reserved;
|
||||
} EXT4_BLOCK_GROUP_DESC;
|
||||
|
||||
#define EXT4_OLD_BLOCK_DESC_SIZE 32
|
||||
#define EXT4_64BIT_BLOCK_DESC_SIZE 64
|
||||
|
||||
STATIC_ASSERT (
|
||||
sizeof (EXT4_BLOCK_GROUP_DESC) == EXT4_64BIT_BLOCK_DESC_SIZE,
|
||||
"ext4 block group descriptor struct has incorrect size"
|
||||
);
|
||||
|
||||
#define EXT4_DBLOCKS 12
|
||||
#define EXT4_IND_BLOCK 12
|
||||
#define EXT4_DIND_BLOCK 13
|
||||
#define EXT4_TIND_BLOCK 14
|
||||
#define EXT4_NR_BLOCKS 15
|
||||
#define EXT4_FAST_SYMLINK_MAX_SIZE EXT4_NR_BLOCKS * sizeof(UINT32)
|
||||
|
||||
#define EXT4_GOOD_OLD_INODE_SIZE 128U
|
||||
|
||||
typedef struct _Ext4_I_OSD2_Linux {
|
||||
UINT16 l_i_blocks_high;
|
||||
UINT16 l_i_file_acl_high;
|
||||
UINT16 l_i_uid_high;
|
||||
UINT16 l_i_gid_high;
|
||||
UINT16 l_i_checksum_lo;
|
||||
UINT16 l_i_reserved;
|
||||
} EXT4_OSD2_LINUX;
|
||||
|
||||
typedef struct _Ext4_I_OSD2_Hurd {
|
||||
UINT16 h_i_reserved1;
|
||||
UINT16 h_i_mode_high;
|
||||
UINT16 h_i_uid_high;
|
||||
UINT16 h_i_gid_high;
|
||||
UINT32 h_i_author;
|
||||
} EXT4_OSD2_HURD;
|
||||
|
||||
typedef union {
|
||||
// Note: Toolchain-specific defines (such as "linux") stops us from using
|
||||
// simpler names down here.
|
||||
EXT4_OSD2_LINUX data_linux;
|
||||
EXT4_OSD2_HURD data_hurd;
|
||||
} EXT4_OSD2;
|
||||
|
||||
typedef struct _Ext4Inode {
|
||||
UINT16 i_mode;
|
||||
UINT16 i_uid;
|
||||
UINT32 i_size_lo;
|
||||
UINT32 i_atime;
|
||||
UINT32 i_ctime;
|
||||
UINT32 i_mtime;
|
||||
UINT32 i_dtime;
|
||||
UINT16 i_gid;
|
||||
UINT16 i_links;
|
||||
UINT32 i_blocks;
|
||||
UINT32 i_flags;
|
||||
UINT32 i_os_spec;
|
||||
UINT32 i_data[EXT4_NR_BLOCKS];
|
||||
UINT32 i_generation;
|
||||
UINT32 i_file_acl;
|
||||
UINT32 i_size_hi;
|
||||
UINT32 i_faddr;
|
||||
|
||||
EXT4_OSD2 i_osd2;
|
||||
|
||||
UINT16 i_extra_isize;
|
||||
UINT16 i_checksum_hi;
|
||||
UINT32 i_ctime_extra;
|
||||
UINT32 i_mtime_extra;
|
||||
UINT32 i_atime_extra;
|
||||
UINT32 i_crtime;
|
||||
UINT32 i_crtime_extra;
|
||||
UINT32 i_version_hi;
|
||||
UINT32 i_projid;
|
||||
} EXT4_INODE;
|
||||
|
||||
#define EXT4_NAME_MAX 255
|
||||
|
||||
typedef struct {
|
||||
// offset 0x0: inode number (if 0, unused entry, should skip.)
|
||||
UINT32 inode;
|
||||
// offset 0x4: Directory entry's length.
|
||||
// Note: rec_len >= name_len + EXT4_MIN_DIR_ENTRY_LEN and rec_len % 4 == 0.
|
||||
UINT16 rec_len;
|
||||
// offset 0x6: Directory entry's name's length
|
||||
UINT8 name_len;
|
||||
// offset 0x7: Directory entry's file type indicator
|
||||
UINT8 file_type;
|
||||
// offset 0x8: name[name_len]: Variable length character array; not null-terminated.
|
||||
CHAR8 name[EXT4_NAME_MAX];
|
||||
// Further notes on names:
|
||||
// 1) We use EXT4_NAME_MAX here instead of flexible arrays for ease of use around the driver.
|
||||
//
|
||||
// 2) ext4 directories are defined, as the documentation puts it, as:
|
||||
// "a directory is more or less a flat file that maps an arbitrary byte string
|
||||
// (usually ASCII) to an inode number on the filesystem". So, they are not
|
||||
// necessarily encoded with ASCII, UTF-8, or any of the sort. We must treat it
|
||||
// as a bag of bytes. When interacting with EFI interfaces themselves (which expect UCS-2)
|
||||
// we skip any directory entry that is not valid UTF-8.
|
||||
} EXT4_DIR_ENTRY;
|
||||
|
||||
#define EXT4_MIN_DIR_ENTRY_LEN 8
|
||||
|
||||
// This on-disk structure is present at the bottom of the extent tree
|
||||
typedef struct {
|
||||
// First logical block
|
||||
UINT32 ee_block;
|
||||
// Length of the extent, in blocks
|
||||
UINT16 ee_len;
|
||||
// The physical (filesystem-relative) block is split between the high 16 bits
|
||||
// and the low 32 bits - this forms a 48-bit block number
|
||||
UINT16 ee_start_hi;
|
||||
UINT32 ee_start_lo;
|
||||
} EXT4_EXTENT;
|
||||
|
||||
// This on-disk structure is present at all levels except the bottom
|
||||
typedef struct {
|
||||
// This index covers logical blocks from 'ei_block'
|
||||
UINT32 ei_block;
|
||||
// Block of the next level of the extent tree, similarly split in a high and
|
||||
// low portion.
|
||||
UINT32 ei_leaf_lo;
|
||||
UINT16 ei_leaf_hi;
|
||||
|
||||
UINT16 ei_unused;
|
||||
} EXT4_EXTENT_INDEX;
|
||||
|
||||
typedef struct {
|
||||
// Needs to be EXT4_EXTENT_HEADER_MAGIC
|
||||
UINT16 eh_magic;
|
||||
// Number of entries
|
||||
UINT16 eh_entries;
|
||||
// Maximum number of entries that could follow this header
|
||||
UINT16 eh_max;
|
||||
// Depth of this node in the tree - the tree can be at most 5 levels deep
|
||||
UINT16 eh_depth;
|
||||
// Unused by standard ext4
|
||||
UINT32 eh_generation;
|
||||
} EXT4_EXTENT_HEADER;
|
||||
|
||||
#define EXT4_EXTENT_HEADER_MAGIC 0xF30A
|
||||
|
||||
// Specified by ext4 docs and backed by a bunch of math
|
||||
#define EXT4_EXTENT_TREE_MAX_DEPTH 5
|
||||
|
||||
typedef struct {
|
||||
// CRC32C of UUID + inode number + igeneration + extent block
|
||||
UINT32 eb_checksum;
|
||||
} EXT4_EXTENT_TAIL;
|
||||
|
||||
/**
|
||||
* EXT4 has this feature called uninitialized extents:
|
||||
* An extent has a maximum of 32768 blocks (2^15 or 1 << 15).
|
||||
* When we find an extent with > 32768 blocks, this extent is called
|
||||
* uninitialized. Long story short, it's an extent that behaves as a file hole
|
||||
* but has blocks already allocated.
|
||||
*/
|
||||
#define EXT4_EXTENT_MAX_INITIALIZED (1 << 15)
|
||||
|
||||
typedef UINT64 EXT4_BLOCK_NR;
|
||||
typedef UINT32 EXT2_BLOCK_NR;
|
||||
typedef UINT32 EXT4_INO_NR;
|
||||
|
||||
/* Special inode numbers */
|
||||
#define EXT4_ROOT_INODE_NR 2
|
||||
#define EXT4_USR_QUOTA_INODE_NR 3
|
||||
#define EXT4_GRP_QUOTA_INODE_NR 4
|
||||
#define EXT4_BOOT_LOADER_INODE_NR 5
|
||||
#define EXT4_UNDEL_DIR_INODE_NR 6
|
||||
#define EXT4_RESIZE_INODE_NR 7
|
||||
#define EXT4_JOURNAL_INODE_NR 8
|
||||
|
||||
/* First non-reserved inode for old ext4 filesystems */
|
||||
#define EXT4_GOOD_OLD_FIRST_INODE_NR 11
|
||||
|
||||
#define EXT4_BLOCK_FILE_HOLE 0
|
||||
|
||||
#endif
|
|
@ -0,0 +1,847 @@
|
|||
/** @file
|
||||
Driver entry point
|
||||
|
||||
Copyright (c) 2021 - 2023 Pedro Falcato All rights reserved.
|
||||
SPDX-License-Identifier: BSD-2-Clause-Patent
|
||||
**/
|
||||
|
||||
#include "Ext4Dxe.h"
|
||||
|
||||
GLOBAL_REMOVE_IF_UNREFERENCED EFI_UNICODE_STRING_TABLE mExt4DriverNameTable[] = {
|
||||
{
|
||||
"eng;en",
|
||||
L"Ext4 File System Driver"
|
||||
},
|
||||
{
|
||||
NULL,
|
||||
NULL
|
||||
}
|
||||
};
|
||||
|
||||
GLOBAL_REMOVE_IF_UNREFERENCED EFI_UNICODE_STRING_TABLE mExt4ControllerNameTable[] = {
|
||||
{
|
||||
"eng;en",
|
||||
L"Ext4 File System"
|
||||
},
|
||||
{
|
||||
NULL,
|
||||
NULL
|
||||
}
|
||||
};
|
||||
|
||||
// Needed by gExt4ComponentName*
|
||||
|
||||
/**
|
||||
Retrieves a Unicode string that is the user-readable name of the EFI Driver.
|
||||
|
||||
@param[in] This A pointer to the EFI_COMPONENT_NAME_PROTOCOL instance.
|
||||
@param[in] Language A pointer to a three-character ISO 639-2 language identifier.
|
||||
This is the language of the driver name that that the caller
|
||||
is requesting, and it must match one of the languages specified
|
||||
in SupportedLanguages. The number of languages supported by a
|
||||
driver is up to the driver writer.
|
||||
@param[out] DriverName A pointer to the Unicode string to return. This Unicode string
|
||||
is the name of the driver specified by This in the language
|
||||
specified by Language.
|
||||
|
||||
@retval EFI_SUCCESS The Unicode string for the Driver specified by This
|
||||
and the language specified by Language was returned
|
||||
in DriverName.
|
||||
@retval EFI_INVALID_PARAMETER Language is NULL.
|
||||
@retval EFI_INVALID_PARAMETER DriverName is NULL.
|
||||
@retval EFI_UNSUPPORTED The driver specified by This does not support the
|
||||
language specified by Language.
|
||||
|
||||
**/
|
||||
EFI_STATUS
|
||||
EFIAPI
|
||||
Ext4ComponentNameGetDriverName (
|
||||
IN EFI_COMPONENT_NAME_PROTOCOL *This,
|
||||
IN CHAR8 *Language,
|
||||
OUT CHAR16 **DriverName
|
||||
);
|
||||
|
||||
/**
|
||||
Retrieves a Unicode string that is the user readable name of the controller
|
||||
that is being managed by an EFI Driver.
|
||||
|
||||
@param[in] This A pointer to the EFI_COMPONENT_NAME_PROTOCOL instance.
|
||||
@param[in] ControllerHandle The handle of a controller that the driver specified by
|
||||
This is managing. This handle specifies the controller
|
||||
whose name is to be returned.
|
||||
@param[in] ChildHandle The handle of the child controller to retrieve the name
|
||||
of. This is an optional parameter that may be NULL. It
|
||||
will be NULL for device drivers. It will also be NULL
|
||||
for a bus drivers that wish to retrieve the name of the
|
||||
bus controller. It will not be NULL for a bus driver
|
||||
that wishes to retrieve the name of a child controller.
|
||||
@param[in] Language A pointer to a three character ISO 639-2 language
|
||||
identifier. This is the language of the controller name
|
||||
that the caller is requesting, and it must match one
|
||||
of the languages specified in SupportedLanguages. The
|
||||
number of languages supported by a driver is up to the
|
||||
driver writer.
|
||||
@param[out] ControllerName A pointer to the Unicode string to return. This Unicode
|
||||
string is the name of the controller specified by
|
||||
ControllerHandle and ChildHandle in the language specified
|
||||
by Language, from the point of view of the driver specified
|
||||
by This.
|
||||
|
||||
@retval EFI_SUCCESS The Unicode string for the user-readable name in the
|
||||
language specified by Language for the driver
|
||||
specified by This was returned in DriverName.
|
||||
@retval EFI_INVALID_PARAMETER ControllerHandle is NULL.
|
||||
@retval EFI_INVALID_PARAMETER ChildHandle is not NULL and it is not a valid EFI_HANDLE.
|
||||
@retval EFI_INVALID_PARAMETER Language is NULL.
|
||||
@retval EFI_INVALID_PARAMETER ControllerName is NULL.
|
||||
@retval EFI_UNSUPPORTED The driver specified by This is not currently managing
|
||||
the controller specified by ControllerHandle and
|
||||
ChildHandle.
|
||||
@retval EFI_UNSUPPORTED The driver specified by This does not support the
|
||||
language specified by Language.
|
||||
|
||||
**/
|
||||
EFI_STATUS
|
||||
EFIAPI
|
||||
Ext4ComponentNameGetControllerName (
|
||||
IN EFI_COMPONENT_NAME_PROTOCOL *This,
|
||||
IN EFI_HANDLE ControllerHandle,
|
||||
IN EFI_HANDLE ChildHandle OPTIONAL,
|
||||
IN CHAR8 *Language,
|
||||
OUT CHAR16 **ControllerName
|
||||
);
|
||||
|
||||
extern EFI_COMPONENT_NAME_PROTOCOL gExt4ComponentName;
|
||||
|
||||
GLOBAL_REMOVE_IF_UNREFERENCED EFI_COMPONENT_NAME_PROTOCOL gExt4ComponentName = {
|
||||
Ext4ComponentNameGetDriverName,
|
||||
Ext4ComponentNameGetControllerName,
|
||||
"eng"
|
||||
};
|
||||
|
||||
//
|
||||
// EFI Component Name 2 Protocol
|
||||
//
|
||||
GLOBAL_REMOVE_IF_UNREFERENCED EFI_COMPONENT_NAME2_PROTOCOL gExt4ComponentName2 = {
|
||||
(EFI_COMPONENT_NAME2_GET_DRIVER_NAME)Ext4ComponentNameGetDriverName,
|
||||
(EFI_COMPONENT_NAME2_GET_CONTROLLER_NAME)Ext4ComponentNameGetControllerName,
|
||||
"en"
|
||||
};
|
||||
|
||||
// Needed by gExt4BindingProtocol
|
||||
|
||||
/**
|
||||
Tests to see if this driver supports a given controller. If a child device is provided,
|
||||
it further tests to see if this driver supports creating a handle for the specified child device.
|
||||
|
||||
This function checks to see if the driver specified by This supports the device specified by
|
||||
ControllerHandle. Drivers will typically use the device path attached to
|
||||
ControllerHandle and/or the services from the bus I/O abstraction attached to
|
||||
ControllerHandle to determine if the driver supports ControllerHandle. This function
|
||||
may be called many times during platform initialization. In order to reduce boot times, the tests
|
||||
performed by this function must be very small, and take as little time as possible to execute. This
|
||||
function must not change the state of any hardware devices, and this function must be aware that the
|
||||
device specified by ControllerHandle may already be managed by the same driver or a
|
||||
different driver. This function must match its calls to AllocatePages() with FreePages(),
|
||||
AllocatePool() with FreePool(), and OpenProtocol() with CloseProtocol().
|
||||
Because ControllerHandle may have been previously started by the same driver, if a protocol is
|
||||
already in the opened state, then it must not be closed with CloseProtocol(). This is required
|
||||
to guarantee the state of ControllerHandle is not modified by this function.
|
||||
|
||||
@param[in] This A pointer to the EFI_DRIVER_BINDING_PROTOCOL instance.
|
||||
@param[in] ControllerHandle The handle of the controller to test. This handle
|
||||
must support a protocol interface that supplies
|
||||
an I/O abstraction to the driver.
|
||||
@param[in] RemainingDevicePath A pointer to the remaining portion of a device path. This
|
||||
parameter is ignored by device drivers, and is optional for bus
|
||||
drivers. For bus drivers, if this parameter is not NULL, then
|
||||
the bus driver must determine if the bus controller specified
|
||||
by ControllerHandle and the child controller specified
|
||||
by RemainingDevicePath are both supported by this
|
||||
bus driver.
|
||||
|
||||
@retval EFI_SUCCESS The device specified by ControllerHandle and
|
||||
RemainingDevicePath is supported by the driver specified by This.
|
||||
@retval EFI_ALREADY_STARTED The device specified by ControllerHandle and
|
||||
RemainingDevicePath is already being managed by the driver
|
||||
specified by This.
|
||||
@retval EFI_ACCESS_DENIED The device specified by ControllerHandle and
|
||||
RemainingDevicePath is already being managed by a different
|
||||
driver or an application that requires exclusive access.
|
||||
Currently not implemented.
|
||||
@retval EFI_UNSUPPORTED The device specified by ControllerHandle and
|
||||
RemainingDevicePath is not supported by the driver specified by This.
|
||||
**/
|
||||
EFI_STATUS
|
||||
EFIAPI
|
||||
Ext4IsBindingSupported (
|
||||
IN EFI_DRIVER_BINDING_PROTOCOL *BindingProtocol,
|
||||
IN EFI_HANDLE ControllerHandle,
|
||||
IN EFI_DEVICE_PATH *RemainingDevicePath OPTIONAL
|
||||
);
|
||||
|
||||
/**
|
||||
Starts a device controller or a bus controller.
|
||||
|
||||
The Start() function is designed to be invoked from the EFI boot service ConnectController().
|
||||
As a result, much of the error checking on the parameters to Start() has been moved into this
|
||||
common boot service. It is legal to call Start() from other locations,
|
||||
but the following calling restrictions must be followed, or the system behavior will not be deterministic.
|
||||
1. ControllerHandle must be a valid EFI_HANDLE.
|
||||
2. If RemainingDevicePath is not NULL, then it must be a pointer to a naturally aligned
|
||||
EFI_DEVICE_PATH_PROTOCOL.
|
||||
3. Prior to calling Start(), the Supported() function for the driver specified by This must
|
||||
have been called with the same calling parameters, and Supported() must have returned EFI_SUCCESS.
|
||||
|
||||
@param[in] This A pointer to the EFI_DRIVER_BINDING_PROTOCOL instance.
|
||||
@param[in] ControllerHandle The handle of the controller to start. This handle
|
||||
must support a protocol interface that supplies
|
||||
an I/O abstraction to the driver.
|
||||
@param[in] RemainingDevicePath A pointer to the remaining portion of a device path. This
|
||||
parameter is ignored by device drivers, and is optional for bus
|
||||
drivers. For a bus driver, if this parameter is NULL, then handles
|
||||
for all the children of Controller are created by this driver.
|
||||
If this parameter is not NULL and the first Device Path Node is
|
||||
not the End of Device Path Node, then only the handle for the
|
||||
child device specified by the first Device Path Node of
|
||||
RemainingDevicePath is created by this driver.
|
||||
If the first Device Path Node of RemainingDevicePath is
|
||||
the End of Device Path Node, no child handle is created by this
|
||||
driver.
|
||||
|
||||
@retval EFI_SUCCESS The device was started.
|
||||
@retval EFI_DEVICE_ERROR The device could not be started due to a device error.Currently not implemented.
|
||||
@retval EFI_OUT_OF_RESOURCES The request could not be completed due to a lack of resources.
|
||||
@retval Others The driver failded to start the device.
|
||||
|
||||
**/
|
||||
EFI_STATUS
|
||||
EFIAPI
|
||||
Ext4Bind (
|
||||
IN EFI_DRIVER_BINDING_PROTOCOL *BindingProtocol,
|
||||
IN EFI_HANDLE ControllerHandle,
|
||||
IN EFI_DEVICE_PATH *RemainingDevicePath OPTIONAL
|
||||
);
|
||||
|
||||
/**
|
||||
Stops a device controller or a bus controller.
|
||||
|
||||
The Stop() function is designed to be invoked from the EFI boot service DisconnectController().
|
||||
As a result, much of the error checking on the parameters to Stop() has been moved
|
||||
into this common boot service. It is legal to call Stop() from other locations,
|
||||
but the following calling restrictions must be followed, or the system behavior will not be deterministic.
|
||||
1. ControllerHandle must be a valid EFI_HANDLE that was used on a previous call to this
|
||||
same driver's Start() function.
|
||||
2. The first NumberOfChildren handles of ChildHandleBuffer must all be a valid
|
||||
EFI_HANDLE. In addition, all of these handles must have been created in this driver's
|
||||
Start() function, and the Start() function must have called OpenProtocol() on
|
||||
ControllerHandle with an Attribute of EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER.
|
||||
|
||||
@param[in] This A pointer to the EFI_DRIVER_BINDING_PROTOCOL instance.
|
||||
@param[in] ControllerHandle A handle to the device being stopped. The handle must
|
||||
support a bus specific I/O protocol for the driver
|
||||
to use to stop the device.
|
||||
@param[in] NumberOfChildren The number of child device handles in ChildHandleBuffer.
|
||||
@param[in] ChildHandleBuffer An array of child handles to be freed. May be NULL
|
||||
if NumberOfChildren is 0.
|
||||
|
||||
@retval EFI_SUCCESS The device was stopped.
|
||||
@retval EFI_DEVICE_ERROR The device could not be stopped due to a device error.
|
||||
|
||||
**/
|
||||
EFI_STATUS
|
||||
EFIAPI
|
||||
Ext4Stop (
|
||||
IN EFI_DRIVER_BINDING_PROTOCOL *This,
|
||||
IN EFI_HANDLE ControllerHandle,
|
||||
IN UINTN NumberOfChildren,
|
||||
IN EFI_HANDLE *ChildHandleBuffer OPTIONAL
|
||||
);
|
||||
|
||||
EFI_DRIVER_BINDING_PROTOCOL gExt4BindingProtocol =
|
||||
{
|
||||
.Supported = Ext4IsBindingSupported,
|
||||
.Start = Ext4Bind,
|
||||
.Stop = Ext4Stop,
|
||||
.Version = EXT4_DRIVER_VERSION,
|
||||
.ImageHandle = NULL,
|
||||
.DriverBindingHandle = NULL
|
||||
};
|
||||
|
||||
/**
|
||||
Retrieves a Unicode string that is the user readable name of the controller
|
||||
that is being managed by an EFI Driver.
|
||||
|
||||
@param[in] This A pointer to the EFI_COMPONENT_NAME_PROTOCOL instance.
|
||||
@param[in] ControllerHandle The handle of a controller that the driver specified by
|
||||
This is managing. This handle specifies the controller
|
||||
whose name is to be returned.
|
||||
@param[in] ChildHandle The handle of the child controller to retrieve the name
|
||||
of. This is an optional parameter that may be NULL. It
|
||||
will be NULL for device drivers. It will also be NULL
|
||||
for a bus drivers that wish to retrieve the name of the
|
||||
bus controller. It will not be NULL for a bus driver
|
||||
that wishes to retrieve the name of a child controller.
|
||||
@param[in] Language A pointer to a three character ISO 639-2 language
|
||||
identifier. This is the language of the controller name
|
||||
that the caller is requesting, and it must match one
|
||||
of the languages specified in SupportedLanguages. The
|
||||
number of languages supported by a driver is up to the
|
||||
driver writer.
|
||||
@param[out] ControllerName A pointer to the Unicode string to return. This Unicode
|
||||
string is the name of the controller specified by
|
||||
ControllerHandle and ChildHandle in the language specified
|
||||
by Language, from the point of view of the driver specified
|
||||
by This.
|
||||
|
||||
@retval EFI_SUCCESS The Unicode string for the user-readable name in the
|
||||
language specified by Language for the driver
|
||||
specified by This was returned in DriverName.
|
||||
@retval EFI_INVALID_PARAMETER ControllerHandle is NULL.
|
||||
@retval EFI_INVALID_PARAMETER ChildHandle is not NULL and it is not a valid EFI_HANDLE.
|
||||
@retval EFI_INVALID_PARAMETER Language is NULL.
|
||||
@retval EFI_INVALID_PARAMETER ControllerName is NULL.
|
||||
@retval EFI_UNSUPPORTED The driver specified by This is not currently managing
|
||||
the controller specified by ControllerHandle and
|
||||
ChildHandle.
|
||||
@retval EFI_UNSUPPORTED The driver specified by This does not support the
|
||||
language specified by Language.
|
||||
|
||||
**/
|
||||
EFI_STATUS
|
||||
EFIAPI
|
||||
Ext4ComponentNameGetControllerName (
|
||||
IN EFI_COMPONENT_NAME_PROTOCOL *This,
|
||||
IN EFI_HANDLE ControllerHandle,
|
||||
IN EFI_HANDLE ChildHandle OPTIONAL,
|
||||
IN CHAR8 *Language,
|
||||
OUT CHAR16 **ControllerName
|
||||
)
|
||||
{
|
||||
EFI_STATUS Status;
|
||||
|
||||
if (ChildHandle != NULL) {
|
||||
return EFI_UNSUPPORTED;
|
||||
}
|
||||
|
||||
// Test if the driver manages ControllHandle
|
||||
Status = EfiTestManagedDevice (
|
||||
ControllerHandle,
|
||||
gExt4BindingProtocol.DriverBindingHandle,
|
||||
&gEfiDiskIoProtocolGuid
|
||||
);
|
||||
|
||||
if (EFI_ERROR (Status)) {
|
||||
return Status;
|
||||
}
|
||||
|
||||
return LookupUnicodeString2 (
|
||||
Language,
|
||||
This->SupportedLanguages,
|
||||
mExt4ControllerNameTable,
|
||||
ControllerName,
|
||||
(BOOLEAN)(This == &gExt4ComponentName)
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
Retrieves a Unicode string that is the user-readable name of the EFI Driver.
|
||||
|
||||
@param[in] This A pointer to the EFI_COMPONENT_NAME_PROTOCOL instance.
|
||||
@param[in] Language A pointer to a three-character ISO 639-2 language identifier.
|
||||
This is the language of the driver name that that the caller
|
||||
is requesting, and it must match one of the languages specified
|
||||
in SupportedLanguages. The number of languages supported by a
|
||||
driver is up to the driver writer.
|
||||
@param[out] DriverName A pointer to the Unicode string to return. This Unicode string
|
||||
is the name of the driver specified by This in the language
|
||||
specified by Language.
|
||||
|
||||
@retval EFI_SUCCESS The Unicode string for the Driver specified by This
|
||||
and the language specified by Language was returned
|
||||
in DriverName.
|
||||
@retval EFI_INVALID_PARAMETER Language is NULL.
|
||||
@retval EFI_INVALID_PARAMETER DriverName is NULL.
|
||||
@retval EFI_UNSUPPORTED The driver specified by This does not support the
|
||||
language specified by Language.
|
||||
|
||||
**/
|
||||
EFI_STATUS
|
||||
EFIAPI
|
||||
Ext4ComponentNameGetDriverName (
|
||||
IN EFI_COMPONENT_NAME_PROTOCOL *This,
|
||||
IN CHAR8 *Language,
|
||||
OUT CHAR16 **DriverName
|
||||
)
|
||||
{
|
||||
return LookupUnicodeString2 (
|
||||
Language,
|
||||
This->SupportedLanguages,
|
||||
mExt4DriverNameTable,
|
||||
DriverName,
|
||||
(BOOLEAN)(This == &gExt4ComponentName)
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
Stops a device controller or a bus controller.
|
||||
|
||||
The Stop() function is designed to be invoked from the EFI boot service DisconnectController().
|
||||
As a result, much of the error checking on the parameters to Stop() has been moved
|
||||
into this common boot service. It is legal to call Stop() from other locations,
|
||||
but the following calling restrictions must be followed, or the system behavior will not be deterministic.
|
||||
1. ControllerHandle must be a valid EFI_HANDLE that was used on a previous call to this
|
||||
same driver's Start() function.
|
||||
2. The first NumberOfChildren handles of ChildHandleBuffer must all be a valid
|
||||
EFI_HANDLE. In addition, all of these handles must have been created in this driver's
|
||||
Start() function, and the Start() function must have called OpenProtocol() on
|
||||
ControllerHandle with an Attribute of EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER.
|
||||
|
||||
@param[in] This A pointer to the EFI_DRIVER_BINDING_PROTOCOL instance.
|
||||
@param[in] ControllerHandle A handle to the device being stopped. The handle must
|
||||
support a bus specific I/O protocol for the driver
|
||||
to use to stop the device.
|
||||
@param[in] NumberOfChildren The number of child device handles in ChildHandleBuffer.
|
||||
@param[in] ChildHandleBuffer An array of child handles to be freed. May be NULL
|
||||
if NumberOfChildren is 0.
|
||||
|
||||
@retval EFI_SUCCESS The device was stopped.
|
||||
@retval EFI_DEVICE_ERROR The device could not be stopped due to a device error.
|
||||
|
||||
**/
|
||||
EFI_STATUS
|
||||
EFIAPI
|
||||
Ext4Stop (
|
||||
IN EFI_DRIVER_BINDING_PROTOCOL *This,
|
||||
IN EFI_HANDLE ControllerHandle,
|
||||
IN UINTN NumberOfChildren,
|
||||
IN EFI_HANDLE *ChildHandleBuffer OPTIONAL
|
||||
)
|
||||
{
|
||||
EFI_STATUS Status;
|
||||
EFI_SIMPLE_FILE_SYSTEM_PROTOCOL *Sfs;
|
||||
EXT4_PARTITION *Partition;
|
||||
BOOLEAN HasDiskIo2;
|
||||
|
||||
Status = gBS->OpenProtocol (
|
||||
ControllerHandle,
|
||||
&gEfiSimpleFileSystemProtocolGuid,
|
||||
(VOID **)&Sfs,
|
||||
This->DriverBindingHandle,
|
||||
ControllerHandle,
|
||||
EFI_OPEN_PROTOCOL_GET_PROTOCOL
|
||||
);
|
||||
|
||||
if (EFI_ERROR (Status)) {
|
||||
return Status;
|
||||
}
|
||||
|
||||
Partition = (EXT4_PARTITION *)Sfs;
|
||||
|
||||
HasDiskIo2 = EXT4_DISK_IO2 (Partition) != NULL;
|
||||
|
||||
Status = Ext4UnmountAndFreePartition (Partition);
|
||||
|
||||
if (EFI_ERROR (Status)) {
|
||||
return Status;
|
||||
}
|
||||
|
||||
Status = gBS->UninstallMultipleProtocolInterfaces (
|
||||
ControllerHandle,
|
||||
&gEfiSimpleFileSystemProtocolGuid,
|
||||
&Partition->Interface,
|
||||
NULL
|
||||
);
|
||||
|
||||
if (EFI_ERROR (Status)) {
|
||||
return Status;
|
||||
}
|
||||
|
||||
// Close all open protocols (DiskIo, DiskIo2, BlockIo)
|
||||
|
||||
Status = gBS->CloseProtocol (
|
||||
ControllerHandle,
|
||||
&gEfiDiskIoProtocolGuid,
|
||||
This->DriverBindingHandle,
|
||||
ControllerHandle
|
||||
);
|
||||
|
||||
if (EFI_ERROR (Status)) {
|
||||
return Status;
|
||||
}
|
||||
|
||||
Status = gBS->CloseProtocol (
|
||||
ControllerHandle,
|
||||
&gEfiBlockIoProtocolGuid,
|
||||
This->DriverBindingHandle,
|
||||
ControllerHandle
|
||||
);
|
||||
|
||||
if (EFI_ERROR (Status)) {
|
||||
return Status;
|
||||
}
|
||||
|
||||
if (HasDiskIo2) {
|
||||
Status = gBS->CloseProtocol (
|
||||
ControllerHandle,
|
||||
&gEfiDiskIo2ProtocolGuid,
|
||||
This->DriverBindingHandle,
|
||||
ControllerHandle
|
||||
);
|
||||
|
||||
if (EFI_ERROR (Status)) {
|
||||
return Status;
|
||||
}
|
||||
}
|
||||
|
||||
return Status;
|
||||
}
|
||||
|
||||
/**
|
||||
Ext4Dxe Driver's entry point.
|
||||
|
||||
Called at load time.
|
||||
|
||||
@param[in] ImageHandle Handle to the image.
|
||||
@param[in] SystemTable Pointer to the EFI_SYSTEM_TABLE.
|
||||
@return Result of the load.
|
||||
**/
|
||||
EFI_STATUS
|
||||
EFIAPI
|
||||
Ext4EntryPoint (
|
||||
IN EFI_HANDLE ImageHandle,
|
||||
IN EFI_SYSTEM_TABLE *SystemTable
|
||||
)
|
||||
{
|
||||
return EfiLibInstallAllDriverProtocols2 (
|
||||
ImageHandle,
|
||||
SystemTable,
|
||||
&gExt4BindingProtocol,
|
||||
ImageHandle,
|
||||
&gExt4ComponentName,
|
||||
&gExt4ComponentName2,
|
||||
NULL,
|
||||
NULL,
|
||||
NULL,
|
||||
NULL
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
Ext4Dxe Driver's unload callback.
|
||||
|
||||
Called at unload time.
|
||||
|
||||
@param[in] ImageHandle Handle to the image.
|
||||
@return Result of the unload.
|
||||
**/
|
||||
EFI_STATUS
|
||||
EFIAPI
|
||||
Ext4Unload (
|
||||
IN EFI_HANDLE ImageHandle
|
||||
)
|
||||
{
|
||||
EFI_STATUS Status;
|
||||
EFI_HANDLE *DeviceHandleBuffer;
|
||||
UINTN DeviceHandleCount;
|
||||
UINTN Index;
|
||||
EFI_HANDLE Handle;
|
||||
|
||||
Status = gBS->LocateHandleBuffer (
|
||||
AllHandles,
|
||||
NULL,
|
||||
NULL,
|
||||
&DeviceHandleCount,
|
||||
&DeviceHandleBuffer
|
||||
);
|
||||
if (EFI_ERROR (Status)) {
|
||||
return Status;
|
||||
}
|
||||
|
||||
for (Index = 0; Index < DeviceHandleCount; Index++) {
|
||||
Handle = DeviceHandleBuffer[Index];
|
||||
|
||||
Status = EfiTestManagedDevice (Handle, ImageHandle, &gEfiDiskIoProtocolGuid);
|
||||
|
||||
if (Status == EFI_SUCCESS) {
|
||||
Status = gBS->DisconnectController (Handle, ImageHandle, NULL);
|
||||
|
||||
if (EFI_ERROR (Status)) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
FreePool (DeviceHandleBuffer);
|
||||
|
||||
Status = EfiLibUninstallAllDriverProtocols2 (
|
||||
&gExt4BindingProtocol,
|
||||
&gExt4ComponentName,
|
||||
&gExt4ComponentName2,
|
||||
NULL,
|
||||
NULL,
|
||||
NULL,
|
||||
NULL
|
||||
);
|
||||
|
||||
return Status;
|
||||
}
|
||||
|
||||
/**
|
||||
Tests to see if this driver supports a given controller. If a child device is provided,
|
||||
it further tests to see if this driver supports creating a handle for the specified child device.
|
||||
|
||||
This function checks to see if the driver specified by This supports the device specified by
|
||||
ControllerHandle. Drivers will typically use the device path attached to
|
||||
ControllerHandle and/or the services from the bus I/O abstraction attached to
|
||||
ControllerHandle to determine if the driver supports ControllerHandle. This function
|
||||
may be called many times during platform initialization. In order to reduce boot times, the tests
|
||||
performed by this function must be very small, and take as little time as possible to execute. This
|
||||
function must not change the state of any hardware devices, and this function must be aware that the
|
||||
device specified by ControllerHandle may already be managed by the same driver or a
|
||||
different driver. This function must match its calls to AllocatePages() with FreePages(),
|
||||
AllocatePool() with FreePool(), and OpenProtocol() with CloseProtocol().
|
||||
Because ControllerHandle may have been previously started by the same driver, if a protocol is
|
||||
already in the opened state, then it must not be closed with CloseProtocol(). This is required
|
||||
to guarantee the state of ControllerHandle is not modified by this function.
|
||||
|
||||
@param[in] This A pointer to the EFI_DRIVER_BINDING_PROTOCOL instance.
|
||||
@param[in] ControllerHandle The handle of the controller to test. This handle
|
||||
must support a protocol interface that supplies
|
||||
an I/O abstraction to the driver.
|
||||
@param[in] RemainingDevicePath A pointer to the remaining portion of a device path. This
|
||||
parameter is ignored by device drivers, and is optional for bus
|
||||
drivers. For bus drivers, if this parameter is not NULL, then
|
||||
the bus driver must determine if the bus controller specified
|
||||
by ControllerHandle and the child controller specified
|
||||
by RemainingDevicePath are both supported by this
|
||||
bus driver.
|
||||
|
||||
@retval EFI_SUCCESS The device specified by ControllerHandle and
|
||||
RemainingDevicePath is supported by the driver specified by This.
|
||||
@retval EFI_ALREADY_STARTED The device specified by ControllerHandle and
|
||||
RemainingDevicePath is already being managed by the driver
|
||||
specified by This.
|
||||
@retval EFI_ACCESS_DENIED The device specified by ControllerHandle and
|
||||
RemainingDevicePath is already being managed by a different
|
||||
driver or an application that requires exclusive access.
|
||||
@retval EFI_UNSUPPORTED The device specified by ControllerHandle and
|
||||
RemainingDevicePath is not supported by the driver specified by This.
|
||||
**/
|
||||
EFI_STATUS
|
||||
EFIAPI
|
||||
Ext4IsBindingSupported (
|
||||
IN EFI_DRIVER_BINDING_PROTOCOL *BindingProtocol,
|
||||
IN EFI_HANDLE ControllerHandle,
|
||||
IN EFI_DEVICE_PATH *RemainingDevicePath OPTIONAL
|
||||
)
|
||||
{
|
||||
EFI_STATUS Status;
|
||||
EFI_DISK_IO_PROTOCOL *DiskIo;
|
||||
EFI_BLOCK_IO_PROTOCOL *BlockIo;
|
||||
|
||||
DiskIo = NULL;
|
||||
BlockIo = NULL;
|
||||
|
||||
//
|
||||
// Open the IO Abstraction(s) needed to perform the supported test
|
||||
//
|
||||
Status = gBS->OpenProtocol (
|
||||
ControllerHandle,
|
||||
&gEfiDiskIoProtocolGuid,
|
||||
(VOID **)&DiskIo,
|
||||
BindingProtocol->DriverBindingHandle,
|
||||
ControllerHandle,
|
||||
EFI_OPEN_PROTOCOL_BY_DRIVER
|
||||
);
|
||||
|
||||
if (EFI_ERROR (Status)) {
|
||||
return Status;
|
||||
}
|
||||
|
||||
//
|
||||
// Open the IO Abstraction(s) needed to perform the supported test
|
||||
//
|
||||
Status = gBS->OpenProtocol (
|
||||
ControllerHandle,
|
||||
&gEfiBlockIoProtocolGuid,
|
||||
(VOID **)&BlockIo,
|
||||
BindingProtocol->DriverBindingHandle,
|
||||
ControllerHandle,
|
||||
EFI_OPEN_PROTOCOL_GET_PROTOCOL
|
||||
);
|
||||
|
||||
if (!EFI_ERROR (Status)) {
|
||||
if (!Ext4SuperblockCheckMagic (DiskIo, BlockIo)) {
|
||||
Status = EFI_UNSUPPORTED;
|
||||
}
|
||||
}
|
||||
|
||||
//
|
||||
// Close the I/O Abstraction(s) used to perform the supported test
|
||||
//
|
||||
if (DiskIo != NULL) {
|
||||
gBS->CloseProtocol (
|
||||
ControllerHandle,
|
||||
&gEfiDiskIoProtocolGuid,
|
||||
BindingProtocol->DriverBindingHandle,
|
||||
ControllerHandle
|
||||
);
|
||||
}
|
||||
|
||||
if (BlockIo != NULL) {
|
||||
gBS->CloseProtocol (
|
||||
ControllerHandle,
|
||||
&gEfiBlockIoProtocolGuid,
|
||||
BindingProtocol->DriverBindingHandle,
|
||||
ControllerHandle
|
||||
);
|
||||
}
|
||||
|
||||
return Status;
|
||||
}
|
||||
|
||||
/**
|
||||
Starts a device controller or a bus controller.
|
||||
|
||||
The Start() function is designed to be invoked from the EFI boot service ConnectController().
|
||||
As a result, much of the error checking on the parameters to Start() has been moved into this
|
||||
common boot service. It is legal to call Start() from other locations,
|
||||
but the following calling restrictions must be followed, or the system behavior will not be deterministic.
|
||||
1. ControllerHandle must be a valid EFI_HANDLE.
|
||||
2. If RemainingDevicePath is not NULL, then it must be a pointer to a naturally aligned
|
||||
EFI_DEVICE_PATH_PROTOCOL.
|
||||
3. Prior to calling Start(), the Supported() function for the driver specified by This must
|
||||
have been called with the same calling parameters, and Supported() must have returned EFI_SUCCESS.
|
||||
|
||||
@param[in] This A pointer to the EFI_DRIVER_BINDING_PROTOCOL instance.
|
||||
@param[in] ControllerHandle The handle of the controller to start. This handle
|
||||
must support a protocol interface that supplies
|
||||
an I/O abstraction to the driver.
|
||||
@param[in] RemainingDevicePath A pointer to the remaining portion of a device path. This
|
||||
parameter is ignored by device drivers, and is optional for bus
|
||||
drivers. For a bus driver, if this parameter is NULL, then handles
|
||||
for all the children of Controller are created by this driver.
|
||||
If this parameter is not NULL and the first Device Path Node is
|
||||
not the End of Device Path Node, then only the handle for the
|
||||
child device specified by the first Device Path Node of
|
||||
RemainingDevicePath is created by this driver.
|
||||
If the first Device Path Node of RemainingDevicePath is
|
||||
the End of Device Path Node, no child handle is created by this
|
||||
driver.
|
||||
|
||||
@retval EFI_SUCCESS The device was started.
|
||||
@retval EFI_DEVICE_ERROR The device could not be started due to a device error.Currently not implemented.
|
||||
@retval EFI_OUT_OF_RESOURCES The request could not be completed due to a lack of resources.
|
||||
@retval Others The driver failded to start the device.
|
||||
|
||||
**/
|
||||
EFI_STATUS
|
||||
EFIAPI
|
||||
Ext4Bind (
|
||||
IN EFI_DRIVER_BINDING_PROTOCOL *BindingProtocol,
|
||||
IN EFI_HANDLE ControllerHandle,
|
||||
IN EFI_DEVICE_PATH *RemainingDevicePath OPTIONAL
|
||||
)
|
||||
{
|
||||
EFI_DISK_IO_PROTOCOL *DiskIo;
|
||||
EFI_DISK_IO2_PROTOCOL *DiskIo2;
|
||||
EFI_BLOCK_IO_PROTOCOL *BlockIo;
|
||||
EFI_STATUS Status;
|
||||
|
||||
DiskIo2 = NULL;
|
||||
BlockIo = NULL;
|
||||
DiskIo = NULL;
|
||||
|
||||
// Note: We initialize collation here since this is called in BDS, when we are likely
|
||||
// to have the Unicode Collation protocols available.
|
||||
Status = Ext4InitialiseUnicodeCollation (BindingProtocol->ImageHandle);
|
||||
if (EFI_ERROR (Status)) {
|
||||
// Lets throw a loud error into the log
|
||||
// It is very unlikely something like this may fire out of the blue. Chances are either
|
||||
// the platform configuration is wrong, or we are.
|
||||
DEBUG ((DEBUG_ERROR, "[ext4] Error: Unicode Collation not available - failure to Start() - error %r\n", Status));
|
||||
goto Error;
|
||||
}
|
||||
|
||||
Status = gBS->OpenProtocol (
|
||||
ControllerHandle,
|
||||
&gEfiDiskIoProtocolGuid,
|
||||
(VOID **)&DiskIo,
|
||||
BindingProtocol->ImageHandle,
|
||||
ControllerHandle,
|
||||
EFI_OPEN_PROTOCOL_BY_DRIVER
|
||||
);
|
||||
|
||||
if (EFI_ERROR (Status)) {
|
||||
goto Error;
|
||||
}
|
||||
|
||||
DEBUG ((DEBUG_INFO, "[ext4] Controller supports DISK_IO\n"));
|
||||
|
||||
Status = gBS->OpenProtocol (
|
||||
ControllerHandle,
|
||||
&gEfiDiskIo2ProtocolGuid,
|
||||
(VOID **)&DiskIo2,
|
||||
BindingProtocol->ImageHandle,
|
||||
ControllerHandle,
|
||||
EFI_OPEN_PROTOCOL_BY_DRIVER
|
||||
);
|
||||
// It's okay to not support DISK_IO2
|
||||
|
||||
if (DiskIo2 != NULL) {
|
||||
DEBUG ((DEBUG_INFO, "[ext4] Controller supports DISK_IO2\n"));
|
||||
}
|
||||
|
||||
Status = gBS->OpenProtocol (
|
||||
ControllerHandle,
|
||||
&gEfiBlockIoProtocolGuid,
|
||||
(VOID **)&BlockIo,
|
||||
BindingProtocol->ImageHandle,
|
||||
ControllerHandle,
|
||||
EFI_OPEN_PROTOCOL_GET_PROTOCOL
|
||||
);
|
||||
|
||||
if (EFI_ERROR (Status)) {
|
||||
goto Error;
|
||||
}
|
||||
|
||||
Status = Ext4OpenPartition (ControllerHandle, DiskIo, DiskIo2, BlockIo);
|
||||
|
||||
if (EFI_ERROR (Status)) {
|
||||
DEBUG ((DEBUG_ERROR, "[ext4] Error mounting: %r\n", Status));
|
||||
// Falls through to Error
|
||||
} else {
|
||||
return Status;
|
||||
}
|
||||
|
||||
Error:
|
||||
if (DiskIo) {
|
||||
gBS->CloseProtocol (
|
||||
ControllerHandle,
|
||||
&gEfiDiskIoProtocolGuid,
|
||||
BindingProtocol->ImageHandle,
|
||||
ControllerHandle
|
||||
);
|
||||
}
|
||||
|
||||
if (DiskIo2) {
|
||||
gBS->CloseProtocol (
|
||||
ControllerHandle,
|
||||
&gEfiDiskIo2ProtocolGuid,
|
||||
BindingProtocol->ImageHandle,
|
||||
ControllerHandle
|
||||
);
|
||||
}
|
||||
|
||||
if (BlockIo) {
|
||||
gBS->CloseProtocol (
|
||||
ControllerHandle,
|
||||
&gEfiBlockIoProtocolGuid,
|
||||
BindingProtocol->ImageHandle,
|
||||
ControllerHandle
|
||||
);
|
||||
}
|
||||
|
||||
return Status;
|
||||
}
|
File diff suppressed because it is too large
Load Diff
|
@ -0,0 +1,149 @@
|
|||
## @file
|
||||
# Ext4 Package
|
||||
#
|
||||
# UEFI Driver that produces the Simple File System Protocol for a partition that is formatted
|
||||
# with the EXT4 file system.
|
||||
# More details are available at: https://www.kernel.org/doc/html/v5.4/filesystems/ext4/index.html
|
||||
#
|
||||
# Copyright (c) 2021 Pedro Falcato
|
||||
# SPDX-License-Identifier: BSD-2-Clause-Patent
|
||||
#
|
||||
# Layout of an EXT2/3/4 filesystem:
|
||||
# (note: this driver has been developed using
|
||||
# https://www.kernel.org/doc/html/latest/filesystems/ext4/index.html as
|
||||
# documentation).
|
||||
#
|
||||
# An ext2/3/4 filesystem (here on out referred to as simply an ext4 filesystem,
|
||||
# due to the similarities) is composed of various concepts:
|
||||
#
|
||||
# 1) Superblock
|
||||
# The superblock is the structure near (1024 bytes offset from the start)
|
||||
# the start of the partition, and describes the filesystem in general.
|
||||
# Here, we get to know the size of the filesystem's blocks, which features
|
||||
# it supports or not, whether it's been cleanly unmounted, how many blocks
|
||||
# we have, etc.
|
||||
#
|
||||
# 2) Block groups
|
||||
# EXT4 filesystems are divided into block groups, and each block group covers
|
||||
# s_blocks_per_group(8 * Block Size) blocks. Each block group has an
|
||||
# associated block group descriptor; these are present directly after the
|
||||
# superblock. Each block group descriptor contains the location of the
|
||||
# inode table, and the inode and block bitmaps (note these bitmaps are only
|
||||
# a block long, which gets us the 8 * Block Size formula covered previously).
|
||||
#
|
||||
# 3) Blocks
|
||||
# The ext4 filesystem is divided in blocks, of size s_log_block_size ^ 1024.
|
||||
# Blocks can be allocated using individual block groups's bitmaps. Note
|
||||
# that block 0 is invalid and its presence on extents/block tables means
|
||||
# it's part of a file hole, and that particular location must be read as
|
||||
# a block full of zeros.
|
||||
#
|
||||
# 4) Inodes
|
||||
# The ext4 filesystem divides files/directories into inodes (originally
|
||||
# index nodes). Each file/socket/symlink/directory/etc (here on out referred
|
||||
# to as a file, since there is no distinction under the ext4 filesystem) is
|
||||
# stored as a /nameless/ inode, that is stored in some block group's inode
|
||||
# table. Each inode has s_inode_size size (or GOOD_OLD_INODE_SIZE if it's
|
||||
# an old filesystem), and holds various metadata about the file. Since the
|
||||
# largest inode structure right now is ~160 bytes, the rest of the inode
|
||||
# contains inline extended attributes. Inodes' data is stored using either
|
||||
# data blocks (under ext2/3) or extents (under ext4).
|
||||
#
|
||||
# 5) Extents
|
||||
# Ext4 inodes store data in extents. These let N contiguous logical blocks
|
||||
# that are represented by N contiguous physical blocks be represented by a
|
||||
# single extent structure, which minimizes filesystem metadata bloat and
|
||||
# speeds up block mapping (particularly due to the fact that high-quality
|
||||
# ext4 implementations like linux's try /really/ hard to make the file
|
||||
# contiguous, so it's common to have files with almost 0 fragmentation).
|
||||
# Inodes that use extents store them in a tree, and the top of the tree
|
||||
# is stored on i_data. The tree's leaves always start with an
|
||||
# EXT4_EXTENT_HEADER and contain EXT4_EXTENT_INDEX on eh_depth != 0 and
|
||||
# EXT4_EXTENT on eh_depth = 0; these entries are always sorted by logical
|
||||
# block.
|
||||
#
|
||||
# 6) Directories
|
||||
# Ext4 directories are files that store name -> inode mappings for the
|
||||
# logical directory; this is where files get their names, which means ext4
|
||||
# inodes do not themselves have names, since they can be linked (present)
|
||||
# multiple times with different names. Directories can store entries in two
|
||||
# different ways:
|
||||
# 1) Classical linear directories: They store entries as a mostly-linked
|
||||
# mostly-list of EXT4_DIR_ENTRY.
|
||||
# 2) Hash tree directories: These are used for larger directories, with
|
||||
# hundreds of entries, and are designed in a backwards compatible way.
|
||||
# These are not yet implemented in the Ext4Dxe driver.
|
||||
#
|
||||
# 7) Journal
|
||||
# Ext3/4 filesystems have a journal to help protect the filesystem against
|
||||
# system crashes. This is not yet implemented in Ext4Dxe but is described
|
||||
# in detail in the Linux kernel's documentation.
|
||||
##
|
||||
|
||||
|
||||
[Defines]
|
||||
INF_VERSION = 0x00010005
|
||||
BASE_NAME = Ext4Dxe
|
||||
MODULE_UNI_FILE = Ext4Dxe.uni
|
||||
FILE_GUID = 75F2B676-D73B-45CB-B7C1-303C7F4E6FD6
|
||||
MODULE_TYPE = UEFI_DRIVER
|
||||
VERSION_STRING = 1.0
|
||||
|
||||
ENTRY_POINT = Ext4EntryPoint
|
||||
UNLOAD_IMAGE = Ext4Unload
|
||||
|
||||
#
|
||||
# The following information is for reference only and not required by the build tools.
|
||||
#
|
||||
# VALID_ARCHITECTURES = IA32 X64 EBC
|
||||
#
|
||||
|
||||
[Sources]
|
||||
Ext4Dxe.c
|
||||
Partition.c
|
||||
DiskUtil.c
|
||||
Superblock.c
|
||||
BlockGroup.c
|
||||
Inode.c
|
||||
Directory.c
|
||||
Extents.c
|
||||
File.c
|
||||
Symlink.c
|
||||
Collation.c
|
||||
Ext4Disk.h
|
||||
Ext4Dxe.h
|
||||
BlockMap.c
|
||||
|
||||
[Packages]
|
||||
MdePkg/MdePkg.dec
|
||||
RedfishPkg/RedfishPkg.dec
|
||||
|
||||
[LibraryClasses]
|
||||
UefiRuntimeServicesTableLib
|
||||
UefiBootServicesTableLib
|
||||
MemoryAllocationLib
|
||||
BaseMemoryLib
|
||||
BaseLib
|
||||
UefiLib
|
||||
UefiDriverEntryPoint
|
||||
DebugLib
|
||||
PcdLib
|
||||
OrderedCollectionLib
|
||||
BaseUcs2Utf8Lib
|
||||
|
||||
[Guids]
|
||||
gEfiFileInfoGuid ## SOMETIMES_CONSUMES ## UNDEFINED
|
||||
gEfiFileSystemInfoGuid ## SOMETIMES_CONSUMES ## UNDEFINED
|
||||
gEfiFileSystemVolumeLabelInfoIdGuid ## SOMETIMES_CONSUMES ## UNDEFINED
|
||||
|
||||
[Protocols]
|
||||
gEfiDiskIoProtocolGuid ## TO_START
|
||||
gEfiDiskIo2ProtocolGuid ## TO_START
|
||||
gEfiBlockIoProtocolGuid ## TO_START
|
||||
gEfiSimpleFileSystemProtocolGuid ## BY_START
|
||||
gEfiUnicodeCollationProtocolGuid ## TO_START
|
||||
gEfiUnicodeCollation2ProtocolGuid ## TO_START
|
||||
|
||||
[Pcd]
|
||||
gEfiMdePkgTokenSpaceGuid.PcdUefiVariableDefaultLang ## SOMETIMES_CONSUMES
|
||||
gEfiMdePkgTokenSpaceGuid.PcdUefiVariableDefaultPlatformLang ## SOMETIMES_CONSUMES
|
|
@ -0,0 +1,15 @@
|
|||
## @file
|
||||
# Ext4 Package
|
||||
#
|
||||
# UEFI Driver that produces the Simple File System Protocol for a partition that is formatted
|
||||
# with the EXT4 file system.
|
||||
# More details are available at: https://www.kernel.org/doc/html/v5.4/filesystems/ext4/index.html
|
||||
#
|
||||
# Copyright (c) 2021 Pedro Falcato
|
||||
# SPDX-License-Identifier: BSD-2-Clause-Patent
|
||||
#
|
||||
##
|
||||
|
||||
#string STR_MODULE_ABSTRACT #language en-US "UEFI driver for the EXT4 file system."
|
||||
|
||||
#string STR_MODULE_DESCRIPTION #language en-US "Produces the EFI Simple File System protocol."
|
|
@ -0,0 +1,685 @@
|
|||
/** @file
|
||||
Extent related routines
|
||||
|
||||
Copyright (c) 2021 - 2023 Pedro Falcato All rights reserved.
|
||||
SPDX-License-Identifier: BSD-2-Clause-Patent
|
||||
**/
|
||||
|
||||
#include "Ext4Dxe.h"
|
||||
|
||||
/**
|
||||
Checks if the checksum of the extent data block is correct.
|
||||
@param[in] ExtHeader Pointer to the EXT4_EXTENT_HEADER.
|
||||
@param[in] File Pointer to the file.
|
||||
|
||||
@return TRUE if the checksum is correct, FALSE if there is corruption.
|
||||
**/
|
||||
BOOLEAN
|
||||
Ext4CheckExtentChecksum (
|
||||
IN CONST EXT4_EXTENT_HEADER *ExtHeader,
|
||||
IN CONST EXT4_FILE *File
|
||||
);
|
||||
|
||||
/**
|
||||
Calculates the checksum of the extent data block.
|
||||
@param[in] ExtHeader Pointer to the EXT4_EXTENT_HEADER.
|
||||
@param[in] File Pointer to the file.
|
||||
|
||||
@return The checksum.
|
||||
**/
|
||||
UINT32
|
||||
Ext4CalculateExtentChecksum (
|
||||
IN CONST EXT4_EXTENT_HEADER *ExtHeader,
|
||||
IN CONST EXT4_FILE *File
|
||||
);
|
||||
|
||||
/**
|
||||
Caches a range of extents, by allocating pool memory for each extent and adding it to the tree.
|
||||
|
||||
@param[in] File Pointer to the open file.
|
||||
@param[in] Extents Pointer to an array of extents.
|
||||
@param[in] NumberExtents Length of the array.
|
||||
|
||||
@return Result of the caching
|
||||
**/
|
||||
STATIC
|
||||
EFI_STATUS
|
||||
Ext4CacheExtents (
|
||||
IN EXT4_FILE *File,
|
||||
IN CONST EXT4_EXTENT *Extents,
|
||||
IN UINT16 NumberExtents
|
||||
);
|
||||
|
||||
/**
|
||||
Gets an extent from the extents cache of the file.
|
||||
|
||||
@param[in] File Pointer to the open file.
|
||||
@param[in] Block Block we want to grab.
|
||||
|
||||
@return Pointer to the extent, or NULL if it was not found.
|
||||
**/
|
||||
EXT4_EXTENT *
|
||||
Ext4GetExtentFromMap (
|
||||
IN EXT4_FILE *File,
|
||||
IN UINT32 Block
|
||||
);
|
||||
|
||||
/**
|
||||
Retrieves the pointer to the top of the extent tree.
|
||||
@param[in] Inode Pointer to the inode structure.
|
||||
|
||||
@return Pointer to an EXT4_EXTENT_HEADER. This pointer is inside
|
||||
the inode and must not be freed.
|
||||
**/
|
||||
STATIC
|
||||
EXT4_EXTENT_HEADER *
|
||||
Ext4GetInoExtentHeader (
|
||||
IN EXT4_INODE *Inode
|
||||
)
|
||||
{
|
||||
return (EXT4_EXTENT_HEADER *)Inode->i_data;
|
||||
}
|
||||
|
||||
/**
|
||||
Checks if an extent header is valid.
|
||||
@param[in] Header Pointer to the EXT4_EXTENT_HEADER structure.
|
||||
@param[in] MaxEntries Maximum number of entries possible for this tree node.
|
||||
|
||||
@return TRUE if valid, FALSE if not.
|
||||
**/
|
||||
STATIC
|
||||
BOOLEAN
|
||||
Ext4ExtentHeaderValid (
|
||||
IN CONST EXT4_EXTENT_HEADER *Header,
|
||||
IN UINT16 MaxEntries
|
||||
)
|
||||
{
|
||||
if (Header->eh_depth > EXT4_EXTENT_TREE_MAX_DEPTH) {
|
||||
DEBUG ((DEBUG_ERROR, "[ext4] Invalid extent header depth %u\n", Header->eh_depth));
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
if (Header->eh_magic != EXT4_EXTENT_HEADER_MAGIC) {
|
||||
DEBUG ((DEBUG_ERROR, "[ext4] Invalid extent header magic %x\n", Header->eh_magic));
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
// Note: We do not need to check eh_entries here, as the next branch makes sure max >= entries
|
||||
if (Header->eh_max > MaxEntries) {
|
||||
DEBUG ((
|
||||
DEBUG_ERROR,
|
||||
"[ext4] Invalid extent header max entries (%u eh_max, "
|
||||
"theoretical max is %u) (larger than permitted)\n",
|
||||
Header->eh_max,
|
||||
MaxEntries
|
||||
));
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
if (Header->eh_max < Header->eh_entries) {
|
||||
DEBUG ((
|
||||
DEBUG_ERROR,
|
||||
"[ext4] Invalid extent header num entries %u max entries %u\n",
|
||||
Header->eh_entries,
|
||||
Header->eh_max
|
||||
));
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
/**
|
||||
Performs a binary search for a EXT4_EXTENT_INDEX that corresponds to a
|
||||
logical block in a given extent tree node.
|
||||
|
||||
@param[in] Header Pointer to the EXT4_EXTENT_HEADER structure.
|
||||
@param[in] LogicalBlock Block that will be searched
|
||||
|
||||
@return Pointer to the found EXT4_EXTENT_INDEX.
|
||||
**/
|
||||
STATIC
|
||||
EXT4_EXTENT_INDEX *
|
||||
Ext4BinsearchExtentIndex (
|
||||
IN EXT4_EXTENT_HEADER *Header,
|
||||
IN EXT4_BLOCK_NR LogicalBlock
|
||||
)
|
||||
{
|
||||
EXT4_EXTENT_INDEX *l;
|
||||
EXT4_EXTENT_INDEX *r;
|
||||
EXT4_EXTENT_INDEX *m;
|
||||
|
||||
l = ((EXT4_EXTENT_INDEX *)(Header + 1)) + 1;
|
||||
r = ((EXT4_EXTENT_INDEX *)(Header + 1)) + Header->eh_entries - 1;
|
||||
|
||||
// Perform a mostly-standard binary search on the array
|
||||
// This works very nicely because the extents arrays are always sorted.
|
||||
|
||||
while (l <= r) {
|
||||
m = l + (r - l) / 2;
|
||||
|
||||
if (LogicalBlock < m->ei_block) {
|
||||
r = m - 1;
|
||||
} else {
|
||||
l = m + 1;
|
||||
}
|
||||
}
|
||||
|
||||
return l - 1;
|
||||
}
|
||||
|
||||
/**
|
||||
Performs a binary search for a EXT4_EXTENT that corresponds to a
|
||||
logical block in a given extent tree node.
|
||||
|
||||
@param[in] Header Pointer to the EXT4_EXTENT_HEADER structure.
|
||||
@param[in] LogicalBlock Block that will be searched
|
||||
|
||||
@return Pointer to the found EXT4_EXTENT_INDEX, else NULL if the array is empty.
|
||||
Note: The caller must check if the logical block
|
||||
is actually mapped under the given extent.
|
||||
**/
|
||||
STATIC
|
||||
EXT4_EXTENT *
|
||||
Ext4BinsearchExtentExt (
|
||||
IN EXT4_EXTENT_HEADER *Header,
|
||||
IN EXT4_BLOCK_NR LogicalBlock
|
||||
)
|
||||
{
|
||||
EXT4_EXTENT *l;
|
||||
EXT4_EXTENT *r;
|
||||
EXT4_EXTENT *m;
|
||||
|
||||
l = ((EXT4_EXTENT *)(Header + 1)) + 1;
|
||||
r = ((EXT4_EXTENT *)(Header + 1)) + Header->eh_entries - 1;
|
||||
// Perform a mostly-standard binary search on the array
|
||||
// This works very nicely because the extents arrays are always sorted.
|
||||
|
||||
// Empty array
|
||||
if (Header->eh_entries == 0) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
while (l <= r) {
|
||||
m = l + (r - l) / 2;
|
||||
|
||||
if (LogicalBlock < m->ee_block) {
|
||||
r = m - 1;
|
||||
} else {
|
||||
l = m + 1;
|
||||
}
|
||||
}
|
||||
|
||||
return l - 1;
|
||||
}
|
||||
|
||||
/**
|
||||
Retrieves the leaf block from an EXT4_EXTENT_INDEX.
|
||||
|
||||
@param[in] Index Pointer to the EXT4_EXTENT_INDEX structure.
|
||||
|
||||
@return Block number of the leaf node.
|
||||
**/
|
||||
STATIC
|
||||
EXT4_BLOCK_NR
|
||||
Ext4ExtentIdxLeafBlock (
|
||||
IN EXT4_EXTENT_INDEX *Index
|
||||
)
|
||||
{
|
||||
return LShiftU64 (Index->ei_leaf_hi, 32) | Index->ei_leaf_lo;
|
||||
}
|
||||
|
||||
// Results of sizeof(i_data) / sizeof(extent) - 1 = 4
|
||||
#define EXT4_NR_INLINE_EXTENTS 4
|
||||
|
||||
/**
|
||||
Retrieves an extent from an EXT4 inode.
|
||||
@param[in] Partition Pointer to the opened EXT4 partition.
|
||||
@param[in] File Pointer to the opened file.
|
||||
@param[in] LogicalBlock Block number which the returned extent must cover.
|
||||
@param[out] Extent Pointer to the output buffer, where the extent will be copied to.
|
||||
|
||||
@retval EFI_SUCCESS Retrieval was successful.
|
||||
@retval EFI_NO_MAPPING Block has no mapping.
|
||||
**/
|
||||
EFI_STATUS
|
||||
Ext4GetExtent (
|
||||
IN EXT4_PARTITION *Partition,
|
||||
IN EXT4_FILE *File,
|
||||
IN EXT4_BLOCK_NR LogicalBlock,
|
||||
OUT EXT4_EXTENT *Extent
|
||||
)
|
||||
{
|
||||
EXT4_INODE *Inode;
|
||||
VOID *Buffer;
|
||||
EXT4_EXTENT *Ext;
|
||||
UINT32 CurrentDepth;
|
||||
EXT4_EXTENT_HEADER *ExtHeader;
|
||||
EXT4_EXTENT_INDEX *Index;
|
||||
EFI_STATUS Status;
|
||||
UINT16 MaxExtentsPerNode;
|
||||
EXT4_BLOCK_NR BlockNumber;
|
||||
|
||||
Inode = File->Inode;
|
||||
Ext = NULL;
|
||||
Buffer = NULL;
|
||||
|
||||
DEBUG ((DEBUG_FS, "[ext4] Looking up extent for block %lu\n", LogicalBlock));
|
||||
|
||||
// ext4 does not have support for logical block numbers bigger than UINT32_MAX
|
||||
if (LogicalBlock > (UINT32)-1) {
|
||||
return EFI_NO_MAPPING;
|
||||
}
|
||||
|
||||
// Note: Right now, holes are the single biggest reason for cache misses
|
||||
// We should find a way to get (or cache) holes
|
||||
if ((Ext = Ext4GetExtentFromMap (File, (UINT32)LogicalBlock)) != NULL) {
|
||||
*Extent = *Ext;
|
||||
|
||||
return EFI_SUCCESS;
|
||||
}
|
||||
|
||||
if ((Inode->i_flags & EXT4_EXTENTS_FL) == 0) {
|
||||
// If this is an older ext2/ext3 filesystem, emulate Ext4GetExtent using the block map
|
||||
// By specification files using block maps are limited to 2^32 blocks,
|
||||
// so we can safely cast LogicalBlock to uint32
|
||||
Status = Ext4GetBlocks (Partition, File, (UINT32)LogicalBlock, Extent);
|
||||
|
||||
if (!EFI_ERROR (Status)) {
|
||||
Status = Ext4CacheExtents (File, Extent, 1);
|
||||
|
||||
if (EFI_ERROR (Status) && (Status != EFI_OUT_OF_RESOURCES)) {
|
||||
return Status;
|
||||
}
|
||||
|
||||
Status = EFI_SUCCESS;
|
||||
}
|
||||
|
||||
return Status;
|
||||
}
|
||||
|
||||
// Slow path, we'll need to read from disk and (try to) cache those extents.
|
||||
|
||||
ExtHeader = Ext4GetInoExtentHeader (Inode);
|
||||
|
||||
if (!Ext4ExtentHeaderValid (ExtHeader, EXT4_NR_INLINE_EXTENTS)) {
|
||||
return EFI_VOLUME_CORRUPTED;
|
||||
}
|
||||
|
||||
CurrentDepth = ExtHeader->eh_depth;
|
||||
|
||||
// A single node fits into a single block, so we can only have (BlockSize / sizeof(EXT4_EXTENT)) - 1
|
||||
// extents in a single node. Note the -1, because both leaf and internal node headers are 12 bytes,
|
||||
// and so are individual entries.
|
||||
MaxExtentsPerNode = (UINT16)((Partition->BlockSize / sizeof (EXT4_EXTENT)) - 1);
|
||||
|
||||
while (ExtHeader->eh_depth != 0) {
|
||||
CurrentDepth--;
|
||||
// While depth != 0, we're traversing the tree itself and not any leaves
|
||||
// As such, every entry is an EXT4_EXTENT_INDEX entry
|
||||
// Note: Entries after the extent header, either index or actual extent, are always sorted.
|
||||
// Therefore, we can use binary search, and it's actually the standard for doing so
|
||||
// (see FreeBSD).
|
||||
|
||||
Index = Ext4BinsearchExtentIndex (ExtHeader, LogicalBlock);
|
||||
BlockNumber = Ext4ExtentIdxLeafBlock (Index);
|
||||
|
||||
// Check that block isn't file hole
|
||||
if (BlockNumber == EXT4_BLOCK_FILE_HOLE) {
|
||||
if (Buffer != NULL) {
|
||||
FreePool (Buffer);
|
||||
}
|
||||
|
||||
return EFI_VOLUME_CORRUPTED;
|
||||
}
|
||||
|
||||
if (Buffer == NULL) {
|
||||
Buffer = AllocatePool (Partition->BlockSize);
|
||||
if (Buffer == NULL) {
|
||||
return EFI_OUT_OF_RESOURCES;
|
||||
}
|
||||
}
|
||||
|
||||
// Read the leaf block onto the previously-allocated buffer.
|
||||
|
||||
Status = Ext4ReadBlocks (Partition, Buffer, 1, BlockNumber);
|
||||
if (EFI_ERROR (Status)) {
|
||||
FreePool (Buffer);
|
||||
return Status;
|
||||
}
|
||||
|
||||
ExtHeader = Buffer;
|
||||
|
||||
if (!Ext4ExtentHeaderValid (ExtHeader, MaxExtentsPerNode)) {
|
||||
FreePool (Buffer);
|
||||
return EFI_VOLUME_CORRUPTED;
|
||||
}
|
||||
|
||||
if (!Ext4CheckExtentChecksum (ExtHeader, File)) {
|
||||
DEBUG ((DEBUG_ERROR, "[ext4] Invalid extent checksum\n"));
|
||||
FreePool (Buffer);
|
||||
return EFI_VOLUME_CORRUPTED;
|
||||
}
|
||||
|
||||
if (ExtHeader->eh_depth != CurrentDepth) {
|
||||
FreePool (Buffer);
|
||||
return EFI_VOLUME_CORRUPTED;
|
||||
}
|
||||
}
|
||||
|
||||
/* We try to cache every extent under a single leaf, since it's quite likely that we
|
||||
* may need to access things sequentially. Furthermore, ext4 block allocation as done
|
||||
* by linux (and possibly other systems) is quite fancy and usually it results in a small number of extents.
|
||||
* Therefore, we shouldn't have any memory issues.
|
||||
**/
|
||||
Status = Ext4CacheExtents (File, (EXT4_EXTENT *)(ExtHeader + 1), ExtHeader->eh_entries);
|
||||
|
||||
if (EFI_ERROR (Status) && (Status != EFI_OUT_OF_RESOURCES)) {
|
||||
if (Buffer != NULL) {
|
||||
FreePool (Buffer);
|
||||
}
|
||||
|
||||
return Status;
|
||||
}
|
||||
|
||||
Ext = Ext4BinsearchExtentExt (ExtHeader, LogicalBlock);
|
||||
|
||||
if (!Ext) {
|
||||
if (Buffer != NULL) {
|
||||
FreePool (Buffer);
|
||||
}
|
||||
|
||||
return EFI_NO_MAPPING;
|
||||
}
|
||||
|
||||
if (!((LogicalBlock >= Ext->ee_block) && (Ext->ee_block + Ext4GetExtentLength (Ext) > LogicalBlock))) {
|
||||
// This extent does not cover the block
|
||||
if (Buffer != NULL) {
|
||||
FreePool (Buffer);
|
||||
}
|
||||
|
||||
return EFI_NO_MAPPING;
|
||||
}
|
||||
|
||||
*Extent = *Ext;
|
||||
|
||||
if (Buffer != NULL) {
|
||||
FreePool (Buffer);
|
||||
}
|
||||
|
||||
return EFI_SUCCESS;
|
||||
}
|
||||
|
||||
/**
|
||||
Compare two EXT4_EXTENT structs.
|
||||
Used in the extent map's ORDERED_COLLECTION.
|
||||
|
||||
@param[in] UserStruct1 Pointer to the first user structure.
|
||||
|
||||
@param[in] UserStruct2 Pointer to the second user structure.
|
||||
|
||||
@retval <0 If UserStruct1 compares less than UserStruct2.
|
||||
|
||||
@retval 0 If UserStruct1 compares equal to UserStruct2.
|
||||
|
||||
@retval >0 If UserStruct1 compares greater than UserStruct2.
|
||||
**/
|
||||
STATIC
|
||||
INTN
|
||||
EFIAPI
|
||||
Ext4ExtentsMapStructCompare (
|
||||
IN CONST VOID *UserStruct1,
|
||||
IN CONST VOID *UserStruct2
|
||||
)
|
||||
{
|
||||
CONST EXT4_EXTENT *Extent1;
|
||||
CONST EXT4_EXTENT *Extent2;
|
||||
|
||||
Extent1 = UserStruct1;
|
||||
Extent2 = UserStruct2;
|
||||
|
||||
return Extent1->ee_block < Extent2->ee_block ? -1 :
|
||||
Extent1->ee_block > Extent2->ee_block ? 1 : 0;
|
||||
}
|
||||
|
||||
/**
|
||||
Compare a standalone key against a EXT4_EXTENT containing an embedded key.
|
||||
Used in the extent map's ORDERED_COLLECTION.
|
||||
|
||||
@param[in] StandaloneKey Pointer to the bare key.
|
||||
|
||||
@param[in] UserStruct Pointer to the user structure with the embedded
|
||||
key.
|
||||
|
||||
@retval <0 If StandaloneKey compares less than UserStruct's key.
|
||||
|
||||
@retval 0 If StandaloneKey compares equal to UserStruct's key.
|
||||
|
||||
@retval >0 If StandaloneKey compares greater than UserStruct's key.
|
||||
**/
|
||||
STATIC
|
||||
INTN
|
||||
EFIAPI
|
||||
Ext4ExtentsMapKeyCompare (
|
||||
IN CONST VOID *StandaloneKey,
|
||||
IN CONST VOID *UserStruct
|
||||
)
|
||||
{
|
||||
CONST EXT4_EXTENT *Extent;
|
||||
UINT32 Block;
|
||||
|
||||
// Note that logical blocks are 32-bits in size so no truncation can happen here
|
||||
// with regards to 32-bit architectures.
|
||||
Extent = UserStruct;
|
||||
Block = (UINT32)(UINTN)StandaloneKey;
|
||||
|
||||
if ((Block >= Extent->ee_block) && (Block - Extent->ee_block < Ext4GetExtentLength (Extent))) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
return Block < Extent->ee_block ? -1 :
|
||||
Block > Extent->ee_block ? 1 : 0;
|
||||
}
|
||||
|
||||
/**
|
||||
Initialises the (empty) extents map, that will work as a cache of extents.
|
||||
|
||||
@param[in] File Pointer to the open file.
|
||||
|
||||
@return Result of the operation.
|
||||
**/
|
||||
EFI_STATUS
|
||||
Ext4InitExtentsMap (
|
||||
IN EXT4_FILE *File
|
||||
)
|
||||
{
|
||||
File->ExtentsMap = OrderedCollectionInit (Ext4ExtentsMapStructCompare, Ext4ExtentsMapKeyCompare);
|
||||
if (!File->ExtentsMap) {
|
||||
return EFI_OUT_OF_RESOURCES;
|
||||
}
|
||||
|
||||
return EFI_SUCCESS;
|
||||
}
|
||||
|
||||
/**
|
||||
Frees the extents map, deleting every extent stored.
|
||||
|
||||
@param[in] File Pointer to the open file.
|
||||
**/
|
||||
VOID
|
||||
Ext4FreeExtentsMap (
|
||||
IN EXT4_FILE *File
|
||||
)
|
||||
{
|
||||
// Keep calling Min(), so we get an arbitrary node we can delete.
|
||||
// If Min() returns NULL, it's empty.
|
||||
|
||||
ORDERED_COLLECTION_ENTRY *MinEntry;
|
||||
EXT4_EXTENT *Ext;
|
||||
|
||||
MinEntry = NULL;
|
||||
|
||||
while ((MinEntry = OrderedCollectionMin (File->ExtentsMap)) != NULL) {
|
||||
OrderedCollectionDelete (File->ExtentsMap, MinEntry, (VOID **)&Ext);
|
||||
FreePool (Ext);
|
||||
}
|
||||
|
||||
ASSERT (OrderedCollectionIsEmpty (File->ExtentsMap));
|
||||
|
||||
OrderedCollectionUninit (File->ExtentsMap);
|
||||
File->ExtentsMap = NULL;
|
||||
}
|
||||
|
||||
/**
|
||||
Caches a range of extents, by allocating pool memory for each extent and adding it to the tree.
|
||||
|
||||
@param[in] File Pointer to the open file.
|
||||
@param[in] Extents Pointer to an array of extents.
|
||||
@param[in] NumberExtents Length of the array.
|
||||
|
||||
@return Result of the caching
|
||||
**/
|
||||
STATIC
|
||||
EFI_STATUS
|
||||
Ext4CacheExtents (
|
||||
IN EXT4_FILE *File,
|
||||
IN CONST EXT4_EXTENT *Extents,
|
||||
IN UINT16 NumberExtents
|
||||
)
|
||||
{
|
||||
UINT16 Idx;
|
||||
EXT4_EXTENT *Extent;
|
||||
EFI_STATUS Status;
|
||||
|
||||
/* Note that any out of memory condition might mean we don't get to cache a whole leaf of extents
|
||||
* in which case, future insertions might fail.
|
||||
*/
|
||||
|
||||
for (Idx = 0; Idx < NumberExtents; Idx++, Extents++) {
|
||||
if (Extents->ee_len == 0) {
|
||||
// 0-sized extent, must be corruption
|
||||
return EFI_VOLUME_CORRUPTED;
|
||||
}
|
||||
|
||||
Extent = AllocatePool (sizeof (EXT4_EXTENT));
|
||||
|
||||
if (Extent == NULL) {
|
||||
return EFI_OUT_OF_RESOURCES;
|
||||
}
|
||||
|
||||
CopyMem (Extent, Extents, sizeof (EXT4_EXTENT));
|
||||
Status = OrderedCollectionInsert (File->ExtentsMap, NULL, Extent);
|
||||
|
||||
// EFI_ALREADY_STARTED = already exists in the tree.
|
||||
if (EFI_ERROR (Status)) {
|
||||
FreePool (Extent);
|
||||
|
||||
if (Status == EFI_ALREADY_STARTED) {
|
||||
continue;
|
||||
}
|
||||
|
||||
return EFI_SUCCESS;
|
||||
}
|
||||
}
|
||||
|
||||
return EFI_SUCCESS;
|
||||
}
|
||||
|
||||
/**
|
||||
Gets an extent from the extents cache of the file.
|
||||
|
||||
@param[in] File Pointer to the open file.
|
||||
@param[in] Block Block we want to grab.
|
||||
|
||||
@return Pointer to the extent, or NULL if it was not found.
|
||||
**/
|
||||
EXT4_EXTENT *
|
||||
Ext4GetExtentFromMap (
|
||||
IN EXT4_FILE *File,
|
||||
IN UINT32 Block
|
||||
)
|
||||
{
|
||||
ORDERED_COLLECTION_ENTRY *Entry;
|
||||
|
||||
Entry = OrderedCollectionFind (File->ExtentsMap, (CONST VOID *)(UINTN)Block);
|
||||
|
||||
if (Entry == NULL) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return OrderedCollectionUserStruct (Entry);
|
||||
}
|
||||
|
||||
/**
|
||||
Calculates the checksum of the extent data block.
|
||||
@param[in] ExtHeader Pointer to the EXT4_EXTENT_HEADER.
|
||||
@param[in] File Pointer to the file.
|
||||
|
||||
@return The checksum.
|
||||
**/
|
||||
UINT32
|
||||
Ext4CalculateExtentChecksum (
|
||||
IN CONST EXT4_EXTENT_HEADER *ExtHeader,
|
||||
IN CONST EXT4_FILE *File
|
||||
)
|
||||
{
|
||||
UINT32 Csum;
|
||||
EXT4_PARTITION *Partition;
|
||||
EXT4_INODE *Inode;
|
||||
|
||||
Partition = File->Partition;
|
||||
Inode = File->Inode;
|
||||
|
||||
Csum = Ext4CalculateChecksum (Partition, &File->InodeNum, sizeof (EXT4_INO_NR), Partition->InitialSeed);
|
||||
Csum = Ext4CalculateChecksum (Partition, &Inode->i_generation, sizeof (Inode->i_generation), Csum);
|
||||
Csum = Ext4CalculateChecksum (Partition, ExtHeader, Partition->BlockSize - sizeof (EXT4_EXTENT_TAIL), Csum);
|
||||
|
||||
return Csum;
|
||||
}
|
||||
|
||||
/**
|
||||
Checks if the checksum of the extent data block is correct.
|
||||
@param[in] ExtHeader Pointer to the EXT4_EXTENT_HEADER.
|
||||
@param[in] File Pointer to the file.
|
||||
|
||||
@return TRUE if the checksum is correct, FALSE if there is corruption.
|
||||
**/
|
||||
BOOLEAN
|
||||
Ext4CheckExtentChecksum (
|
||||
IN CONST EXT4_EXTENT_HEADER *ExtHeader,
|
||||
IN CONST EXT4_FILE *File
|
||||
)
|
||||
{
|
||||
EXT4_PARTITION *Partition;
|
||||
EXT4_EXTENT_TAIL *Tail;
|
||||
|
||||
Partition = File->Partition;
|
||||
|
||||
if (!EXT4_HAS_METADATA_CSUM (Partition)) {
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
Tail = (EXT4_EXTENT_TAIL *)((CONST CHAR8 *)ExtHeader + (Partition->BlockSize - 4));
|
||||
|
||||
return Tail->eb_checksum == Ext4CalculateExtentChecksum (ExtHeader, File);
|
||||
}
|
||||
|
||||
/**
|
||||
Retrieves the extent's length, dealing with uninitialized extents in the process.
|
||||
|
||||
@param[in] Extent Pointer to the EXT4_EXTENT
|
||||
|
||||
@returns Extent's length, in filesystem blocks.
|
||||
**/
|
||||
EXT4_BLOCK_NR
|
||||
Ext4GetExtentLength (
|
||||
IN CONST EXT4_EXTENT *Extent
|
||||
)
|
||||
{
|
||||
// If it's an uninitialized extent, the true length is ee_len - 2^15
|
||||
if (EXT4_EXTENT_IS_UNINITIALIZED (Extent)) {
|
||||
return Extent->ee_len - EXT4_EXTENT_MAX_INITIALIZED;
|
||||
}
|
||||
|
||||
return Extent->ee_len;
|
||||
}
|
File diff suppressed because it is too large
Load Diff
|
@ -0,0 +1,490 @@
|
|||
/** @file
|
||||
Inode related routines
|
||||
|
||||
Copyright (c) 2021 - 2022 Pedro Falcato All rights reserved.
|
||||
SPDX-License-Identifier: BSD-2-Clause-Patent
|
||||
|
||||
EpochToEfiTime copied from EmbeddedPkg/Library/TimeBaseLib.c
|
||||
Copyright (c) 2016, Hisilicon Limited. All rights reserved.
|
||||
Copyright (c) 2016-2019, Linaro Limited. All rights reserved.
|
||||
Copyright (c) 2021, Ampere Computing LLC. All rights reserved.
|
||||
**/
|
||||
|
||||
#include "Ext4Dxe.h"
|
||||
|
||||
/**
|
||||
Calculates the checksum of the given inode.
|
||||
@param[in] Partition Pointer to the opened EXT4 partition.
|
||||
@param[in] Inode Pointer to the inode.
|
||||
@param[in] InodeNum Inode number.
|
||||
|
||||
@return The checksum.
|
||||
**/
|
||||
UINT32
|
||||
Ext4CalculateInodeChecksum (
|
||||
IN CONST EXT4_PARTITION *Partition,
|
||||
IN CONST EXT4_INODE *Inode,
|
||||
IN EXT4_INO_NR InodeNum
|
||||
)
|
||||
{
|
||||
UINT32 Crc;
|
||||
UINT16 Dummy;
|
||||
BOOLEAN HasSecondChecksumField;
|
||||
CONST VOID *RestOfInode;
|
||||
UINTN RestOfInodeLength;
|
||||
UINTN Length;
|
||||
|
||||
HasSecondChecksumField = EXT4_INODE_HAS_FIELD (Inode, i_checksum_hi);
|
||||
|
||||
Dummy = 0;
|
||||
|
||||
Crc = Ext4CalculateChecksum (Partition, &InodeNum, sizeof (InodeNum), Partition->InitialSeed);
|
||||
Crc = Ext4CalculateChecksum (Partition, &Inode->i_generation, sizeof (Inode->i_generation), Crc);
|
||||
|
||||
Crc = Ext4CalculateChecksum (
|
||||
Partition,
|
||||
Inode,
|
||||
OFFSET_OF (EXT4_INODE, i_osd2.data_linux.l_i_checksum_lo),
|
||||
Crc
|
||||
);
|
||||
|
||||
Crc = Ext4CalculateChecksum (Partition, &Dummy, sizeof (Dummy), Crc);
|
||||
|
||||
RestOfInode = &Inode->i_osd2.data_linux.l_i_reserved;
|
||||
RestOfInodeLength = Partition->InodeSize - OFFSET_OF (EXT4_INODE, i_osd2.data_linux.l_i_reserved);
|
||||
|
||||
if (HasSecondChecksumField) {
|
||||
Length = OFFSET_OF (EXT4_INODE, i_checksum_hi) - OFFSET_OF (EXT4_INODE, i_osd2.data_linux.l_i_reserved);
|
||||
|
||||
Crc = Ext4CalculateChecksum (Partition, &Inode->i_osd2.data_linux.l_i_reserved, Length, Crc);
|
||||
Crc = Ext4CalculateChecksum (Partition, &Dummy, sizeof (Dummy), Crc);
|
||||
|
||||
// 4 is the size of the i_extra_size field + the size of i_checksum_hi
|
||||
RestOfInodeLength = Partition->InodeSize - EXT4_GOOD_OLD_INODE_SIZE - 4;
|
||||
RestOfInode = &Inode->i_ctime_extra;
|
||||
}
|
||||
|
||||
Crc = Ext4CalculateChecksum (Partition, RestOfInode, RestOfInodeLength, Crc);
|
||||
|
||||
return Crc;
|
||||
}
|
||||
|
||||
/**
|
||||
Reads from an EXT4 inode.
|
||||
@param[in] Partition Pointer to the opened EXT4 partition.
|
||||
@param[in] File Pointer to the opened file.
|
||||
@param[out] Buffer Pointer to the buffer.
|
||||
@param[in] Offset Offset of the read.
|
||||
@param[in out] Length Pointer to the length of the buffer, in bytes.
|
||||
After a successful read, it's updated to the number of read bytes.
|
||||
|
||||
@return Status of the read operation.
|
||||
**/
|
||||
EFI_STATUS
|
||||
Ext4Read (
|
||||
IN EXT4_PARTITION *Partition,
|
||||
IN EXT4_FILE *File,
|
||||
OUT VOID *Buffer,
|
||||
IN UINT64 Offset,
|
||||
IN OUT UINTN *Length
|
||||
)
|
||||
{
|
||||
EXT4_INODE *Inode;
|
||||
UINT64 InodeSize;
|
||||
UINT64 CurrentSeek;
|
||||
UINTN RemainingRead;
|
||||
UINTN BeenRead;
|
||||
UINTN WasRead;
|
||||
EXT4_EXTENT Extent;
|
||||
UINT32 BlockOff;
|
||||
EFI_STATUS Status;
|
||||
BOOLEAN HasBackingExtent;
|
||||
UINT32 HoleOff;
|
||||
UINT64 HoleLen;
|
||||
UINT64 ExtentStartBytes;
|
||||
UINT64 ExtentLengthBytes;
|
||||
UINT64 ExtentLogicalBytes;
|
||||
|
||||
// Our extent offset is the difference between CurrentSeek and ExtentLogicalBytes
|
||||
UINT64 ExtentOffset;
|
||||
UINTN ExtentMayRead;
|
||||
|
||||
Inode = File->Inode;
|
||||
InodeSize = EXT4_INODE_SIZE (Inode);
|
||||
CurrentSeek = Offset;
|
||||
RemainingRead = *Length;
|
||||
BeenRead = 0;
|
||||
|
||||
DEBUG ((DEBUG_FS, "[ext4] Ext4Read(%s, Offset %lu, Length %lu)\n", File->Dentry->Name, Offset, *Length));
|
||||
|
||||
if (Offset > InodeSize) {
|
||||
return EFI_DEVICE_ERROR;
|
||||
}
|
||||
|
||||
if (RemainingRead > InodeSize - Offset) {
|
||||
RemainingRead = (UINTN)(InodeSize - Offset);
|
||||
}
|
||||
|
||||
while (RemainingRead != 0) {
|
||||
WasRead = 0;
|
||||
|
||||
// The algorithm here is to get the extent corresponding to the current block
|
||||
// and then read as much as we can from the current extent.
|
||||
|
||||
Status = Ext4GetExtent (
|
||||
Partition,
|
||||
File,
|
||||
DivU64x32Remainder (CurrentSeek, Partition->BlockSize, &BlockOff),
|
||||
&Extent
|
||||
);
|
||||
|
||||
if ((Status != EFI_SUCCESS) && (Status != EFI_NO_MAPPING)) {
|
||||
return Status;
|
||||
}
|
||||
|
||||
HasBackingExtent = Status != EFI_NO_MAPPING;
|
||||
|
||||
if (!HasBackingExtent || EXT4_EXTENT_IS_UNINITIALIZED (&Extent)) {
|
||||
HoleOff = BlockOff;
|
||||
|
||||
if (!HasBackingExtent) {
|
||||
HoleLen = Partition->BlockSize - HoleOff;
|
||||
} else {
|
||||
// Uninitialized extents behave exactly the same as file holes, except they have
|
||||
// blocks already allocated to them.
|
||||
HoleLen = MultU64x32 (Ext4GetExtentLength (&Extent), Partition->BlockSize) - HoleOff;
|
||||
}
|
||||
|
||||
WasRead = HoleLen > RemainingRead ? RemainingRead : (UINTN)HoleLen;
|
||||
// Potential improvement: In the future, we could get the file hole's total
|
||||
// size and memset all that
|
||||
ZeroMem (Buffer, WasRead);
|
||||
} else {
|
||||
ExtentStartBytes = MultU64x32 (
|
||||
LShiftU64 (Extent.ee_start_hi, 32) |
|
||||
Extent.ee_start_lo,
|
||||
Partition->BlockSize
|
||||
);
|
||||
ExtentLengthBytes = Extent.ee_len * Partition->BlockSize;
|
||||
ExtentLogicalBytes = MultU64x32 ((UINT64)Extent.ee_block, Partition->BlockSize);
|
||||
ExtentOffset = CurrentSeek - ExtentLogicalBytes;
|
||||
ExtentMayRead = (UINTN)(ExtentLengthBytes - ExtentOffset);
|
||||
|
||||
WasRead = ExtentMayRead > RemainingRead ? RemainingRead : ExtentMayRead;
|
||||
|
||||
Status = Ext4ReadDiskIo (Partition, Buffer, WasRead, ExtentStartBytes + ExtentOffset);
|
||||
|
||||
if (EFI_ERROR (Status)) {
|
||||
DEBUG ((
|
||||
DEBUG_ERROR,
|
||||
"[ext4] Error %r reading [%lu, %lu]\n",
|
||||
Status,
|
||||
ExtentStartBytes + ExtentOffset,
|
||||
ExtentStartBytes + ExtentOffset + WasRead - 1
|
||||
));
|
||||
return Status;
|
||||
}
|
||||
}
|
||||
|
||||
RemainingRead -= WasRead;
|
||||
Buffer = (VOID *)((CHAR8 *)Buffer + WasRead);
|
||||
BeenRead += WasRead;
|
||||
CurrentSeek += WasRead;
|
||||
}
|
||||
|
||||
*Length = BeenRead;
|
||||
|
||||
return EFI_SUCCESS;
|
||||
}
|
||||
|
||||
/**
|
||||
Allocates a zeroed inode structure.
|
||||
@param[in] Partition Pointer to the opened EXT4 partition.
|
||||
|
||||
@return Pointer to the allocated structure, from the pool,
|
||||
with size Partition->InodeSize.
|
||||
**/
|
||||
EXT4_INODE *
|
||||
Ext4AllocateInode (
|
||||
IN EXT4_PARTITION *Partition
|
||||
)
|
||||
{
|
||||
BOOLEAN NeedsToZeroRest;
|
||||
UINT32 InodeSize;
|
||||
EXT4_INODE *Inode;
|
||||
|
||||
NeedsToZeroRest = FALSE;
|
||||
InodeSize = Partition->InodeSize;
|
||||
|
||||
// We allocate a structure of at least sizeof(EXT4_INODE), but in the future, when
|
||||
// write support is added and we need to flush inodes to disk, we could have a bit better
|
||||
// distinction between the on-disk inode and a separate, nicer to work with inode struct.
|
||||
// It's important to note that EXT4_INODE includes fields that may not exist in an actual
|
||||
// filesystem (the minimum inode size is 128 byte and at the moment the size of EXT4_INODE
|
||||
// is 160 bytes).
|
||||
|
||||
if (InodeSize < sizeof (EXT4_INODE)) {
|
||||
InodeSize = sizeof (EXT4_INODE);
|
||||
NeedsToZeroRest = TRUE;
|
||||
}
|
||||
|
||||
Inode = AllocateZeroPool (InodeSize);
|
||||
|
||||
if (Inode == NULL) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (NeedsToZeroRest) {
|
||||
Inode->i_extra_isize = 0;
|
||||
}
|
||||
|
||||
return Inode;
|
||||
}
|
||||
|
||||
/**
|
||||
Checks if a file is a directory.
|
||||
@param[in] File Pointer to the opened file.
|
||||
|
||||
@return TRUE if file is a directory.
|
||||
**/
|
||||
BOOLEAN
|
||||
Ext4FileIsDir (
|
||||
IN CONST EXT4_FILE *File
|
||||
)
|
||||
{
|
||||
return (File->Inode->i_mode & EXT4_INO_TYPE_DIR) == EXT4_INO_TYPE_DIR;
|
||||
}
|
||||
|
||||
/**
|
||||
Checks if a file is a symlink.
|
||||
|
||||
@param[in] File Pointer to the opened file.
|
||||
|
||||
@return BOOLEAN Whether file is a symlink
|
||||
**/
|
||||
BOOLEAN
|
||||
Ext4FileIsSymlink (
|
||||
IN CONST EXT4_FILE *File
|
||||
)
|
||||
{
|
||||
return (File->Inode->i_mode & EXT4_INO_TYPE_SYMLINK) == EXT4_INO_TYPE_SYMLINK;
|
||||
}
|
||||
|
||||
/**
|
||||
Checks if a file is a regular file.
|
||||
@param[in] File Pointer to the opened file.
|
||||
|
||||
@return BOOLEAN TRUE if file is a regular file.
|
||||
**/
|
||||
BOOLEAN
|
||||
Ext4FileIsReg (
|
||||
IN CONST EXT4_FILE *File
|
||||
)
|
||||
{
|
||||
return (File->Inode->i_mode & EXT4_INO_TYPE_REGFILE) == EXT4_INO_TYPE_REGFILE;
|
||||
}
|
||||
|
||||
/**
|
||||
Calculates the physical space used by a file.
|
||||
@param[in] File Pointer to the opened file.
|
||||
|
||||
@return Physical space used by a file, in bytes.
|
||||
**/
|
||||
UINT64
|
||||
Ext4FilePhysicalSpace (
|
||||
IN EXT4_FILE *File
|
||||
)
|
||||
{
|
||||
BOOLEAN HugeFile;
|
||||
UINT64 Blocks;
|
||||
|
||||
HugeFile = EXT4_HAS_RO_COMPAT (File->Partition, EXT4_FEATURE_RO_COMPAT_HUGE_FILE);
|
||||
Blocks = File->Inode->i_blocks;
|
||||
|
||||
if (HugeFile) {
|
||||
Blocks |= LShiftU64 (File->Inode->i_osd2.data_linux.l_i_blocks_high, 32);
|
||||
|
||||
// If HUGE_FILE is enabled and EXT4_HUGE_FILE_FL is set in the inode's flags, each unit
|
||||
// in i_blocks corresponds to an actual filesystem block
|
||||
if ((File->Inode->i_flags & EXT4_HUGE_FILE_FL) != 0) {
|
||||
return MultU64x32 (Blocks, File->Partition->BlockSize);
|
||||
}
|
||||
}
|
||||
|
||||
// Else, each i_blocks unit corresponds to 512 bytes
|
||||
return MultU64x32 (Blocks, 512);
|
||||
}
|
||||
|
||||
// Copied from EmbeddedPkg at my mentor's request.
|
||||
// The lack of comments and good variable names is frightening...
|
||||
|
||||
/**
|
||||
Converts Epoch seconds (elapsed since 1970 JANUARY 01, 00:00:00 UTC) to EFI_TIME.
|
||||
|
||||
@param[in] EpochSeconds Epoch seconds.
|
||||
@param[out] Time The time converted to UEFI format.
|
||||
|
||||
**/
|
||||
STATIC
|
||||
VOID
|
||||
EFIAPI
|
||||
EpochToEfiTime (
|
||||
IN UINTN EpochSeconds,
|
||||
OUT EFI_TIME *Time
|
||||
)
|
||||
{
|
||||
UINTN a;
|
||||
UINTN b;
|
||||
UINTN c;
|
||||
UINTN d;
|
||||
UINTN g;
|
||||
UINTN j;
|
||||
UINTN m;
|
||||
UINTN y;
|
||||
UINTN da;
|
||||
UINTN db;
|
||||
UINTN dc;
|
||||
UINTN dg;
|
||||
UINTN hh;
|
||||
UINTN mm;
|
||||
UINTN ss;
|
||||
UINTN J;
|
||||
|
||||
J = (EpochSeconds / 86400) + 2440588;
|
||||
j = J + 32044;
|
||||
g = j / 146097;
|
||||
dg = j % 146097;
|
||||
c = (((dg / 36524) + 1) * 3) / 4;
|
||||
dc = dg - (c * 36524);
|
||||
b = dc / 1461;
|
||||
db = dc % 1461;
|
||||
a = (((db / 365) + 1) * 3) / 4;
|
||||
da = db - (a * 365);
|
||||
y = (g * 400) + (c * 100) + (b * 4) + a;
|
||||
m = (((da * 5) + 308) / 153) - 2;
|
||||
d = da - (((m + 4) * 153) / 5) + 122;
|
||||
|
||||
Time->Year = (UINT16)(y - 4800 + ((m + 2) / 12));
|
||||
Time->Month = ((m + 2) % 12) + 1;
|
||||
Time->Day = (UINT8)(d + 1);
|
||||
|
||||
ss = EpochSeconds % 60;
|
||||
a = (EpochSeconds - ss) / 60;
|
||||
mm = a % 60;
|
||||
b = (a - mm) / 60;
|
||||
hh = b % 24;
|
||||
|
||||
Time->Hour = (UINT8)hh;
|
||||
Time->Minute = (UINT8)mm;
|
||||
Time->Second = (UINT8)ss;
|
||||
Time->Nanosecond = 0;
|
||||
}
|
||||
|
||||
// The time format used to (de/en)code timestamp and timestamp_extra is documented on
|
||||
// the ext4 docs page in kernel.org
|
||||
#define EXT4_EXTRA_TIMESTAMP_MASK ((1 << 2) - 1)
|
||||
|
||||
#define EXT4_FILE_GET_TIME_GENERIC(Name, Field) \
|
||||
VOID \
|
||||
Ext4File ## Name (IN EXT4_FILE *File, OUT EFI_TIME *Time) \
|
||||
{ \
|
||||
EXT4_INODE *Inode = File->Inode; \
|
||||
UINT64 SecondsEpoch = Inode->Field; \
|
||||
UINT32 Nanoseconds = 0; \
|
||||
\
|
||||
if (EXT4_INODE_HAS_FIELD (Inode, Field ## _extra)) { \
|
||||
SecondsEpoch |= LShiftU64 ((UINT64)(Inode->Field ## _extra & EXT4_EXTRA_TIMESTAMP_MASK), 32); \
|
||||
Nanoseconds = Inode->Field ## _extra >> 2; \
|
||||
} \
|
||||
EpochToEfiTime ((UINTN)SecondsEpoch, Time); \
|
||||
Time->Nanosecond = Nanoseconds; \
|
||||
}
|
||||
|
||||
// Note: EpochToEfiTime should be adjusted to take in a UINT64 instead of a UINTN, in order to avoid Y2038
|
||||
// on 32-bit systems.
|
||||
|
||||
/**
|
||||
Gets the file's last access time.
|
||||
@param[in] File Pointer to the opened file.
|
||||
@param[out] Time Pointer to an EFI_TIME structure.
|
||||
**/
|
||||
EXT4_FILE_GET_TIME_GENERIC (ATime, i_atime);
|
||||
|
||||
/**
|
||||
Gets the file's last (data) modification time.
|
||||
@param[in] File Pointer to the opened file.
|
||||
@param[out] Time Pointer to an EFI_TIME structure.
|
||||
**/
|
||||
EXT4_FILE_GET_TIME_GENERIC (MTime, i_mtime);
|
||||
|
||||
/**
|
||||
Gets the file's creation time.
|
||||
@param[in] File Pointer to the opened file.
|
||||
@param[out] Time Pointer to an EFI_TIME structure.
|
||||
**/
|
||||
STATIC
|
||||
EXT4_FILE_GET_TIME_GENERIC (
|
||||
CrTime,
|
||||
i_crtime
|
||||
);
|
||||
|
||||
/**
|
||||
Gets the file's creation time, if possible.
|
||||
@param[in] File Pointer to the opened file.
|
||||
@param[out] Time Pointer to an EFI_TIME structure.
|
||||
In the case where the the creation time isn't recorded,
|
||||
Time is zeroed.
|
||||
**/
|
||||
VOID
|
||||
Ext4FileCreateTime (
|
||||
IN EXT4_FILE *File,
|
||||
OUT EFI_TIME *Time
|
||||
)
|
||||
{
|
||||
EXT4_INODE *Inode;
|
||||
|
||||
Inode = File->Inode;
|
||||
|
||||
if (!EXT4_INODE_HAS_FIELD (Inode, i_crtime)) {
|
||||
ZeroMem (Time, sizeof (EFI_TIME));
|
||||
return;
|
||||
}
|
||||
|
||||
Ext4FileCrTime (File, Time);
|
||||
}
|
||||
|
||||
/**
|
||||
Checks if the checksum of the inode is correct.
|
||||
@param[in] Partition Pointer to the opened EXT4 partition.
|
||||
@param[in] Inode Pointer to the inode.
|
||||
@param[in] InodeNum Inode number.
|
||||
|
||||
@return TRUE if checksum is correct, FALSE if there is corruption.
|
||||
**/
|
||||
BOOLEAN
|
||||
Ext4CheckInodeChecksum (
|
||||
IN CONST EXT4_PARTITION *Partition,
|
||||
IN CONST EXT4_INODE *Inode,
|
||||
IN EXT4_INO_NR InodeNum
|
||||
)
|
||||
{
|
||||
UINT32 Csum;
|
||||
UINT32 DiskCsum;
|
||||
|
||||
if (!EXT4_HAS_METADATA_CSUM (Partition)) {
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
Csum = Ext4CalculateInodeChecksum (Partition, Inode, InodeNum);
|
||||
|
||||
DiskCsum = Inode->i_osd2.data_linux.l_i_checksum_lo;
|
||||
|
||||
if (EXT4_INODE_HAS_FIELD (Inode, i_checksum_hi)) {
|
||||
DiskCsum |= ((UINT32)Inode->i_checksum_hi) << 16;
|
||||
} else {
|
||||
// Only keep the lower bits for the comparison if the checksum is 16 bits.
|
||||
Csum &= 0xffff;
|
||||
}
|
||||
|
||||
return Csum == DiskCsum;
|
||||
}
|
|
@ -0,0 +1,132 @@
|
|||
/** @file
|
||||
Driver entry point
|
||||
|
||||
Copyright (c) 2021 Pedro Falcato All rights reserved.
|
||||
SPDX-License-Identifier: BSD-2-Clause-Patent
|
||||
**/
|
||||
|
||||
#include "Ext4Dxe.h"
|
||||
|
||||
/**
|
||||
Opens an ext4 partition and installs the Simple File System protocol.
|
||||
|
||||
@param[in] DeviceHandle Handle to the block device.
|
||||
@param[in] DiskIo Pointer to an EFI_DISK_IO_PROTOCOL.
|
||||
@param[in opt] DiskIo2 Pointer to an EFI_DISK_IO2_PROTOCOL, if supported.
|
||||
@param[in] BlockIo Pointer to an EFI_BLOCK_IO_PROTOCOL.
|
||||
|
||||
@retval EFI_SUCCESS The opening was successful.
|
||||
!EFI_SUCCESS Opening failed.
|
||||
**/
|
||||
EFI_STATUS
|
||||
Ext4OpenPartition (
|
||||
IN EFI_HANDLE DeviceHandle,
|
||||
IN EFI_DISK_IO_PROTOCOL *DiskIo,
|
||||
IN OPTIONAL EFI_DISK_IO2_PROTOCOL *DiskIo2,
|
||||
IN EFI_BLOCK_IO_PROTOCOL *BlockIo
|
||||
)
|
||||
{
|
||||
EXT4_PARTITION *Part;
|
||||
EFI_STATUS Status;
|
||||
|
||||
Part = AllocateZeroPool (sizeof (*Part));
|
||||
|
||||
if (Part == NULL) {
|
||||
return EFI_OUT_OF_RESOURCES;
|
||||
}
|
||||
|
||||
InitializeListHead (&Part->OpenFiles);
|
||||
|
||||
Part->BlockIo = BlockIo;
|
||||
Part->DiskIo = DiskIo;
|
||||
Part->DiskIo2 = DiskIo2;
|
||||
|
||||
Status = Ext4OpenSuperblock (Part);
|
||||
|
||||
if (EFI_ERROR (Status)) {
|
||||
FreePool (Part);
|
||||
return Status;
|
||||
}
|
||||
|
||||
Part->Interface.Revision = EFI_SIMPLE_FILE_SYSTEM_PROTOCOL_REVISION;
|
||||
Part->Interface.OpenVolume = Ext4OpenVolume;
|
||||
Status = gBS->InstallMultipleProtocolInterfaces (
|
||||
&DeviceHandle,
|
||||
&gEfiSimpleFileSystemProtocolGuid,
|
||||
&Part->Interface,
|
||||
NULL
|
||||
);
|
||||
|
||||
if (EFI_ERROR (Status)) {
|
||||
FreePool (Part);
|
||||
return Status;
|
||||
}
|
||||
|
||||
return EFI_SUCCESS;
|
||||
}
|
||||
|
||||
/**
|
||||
Sets up the protocol and metadata of a file that is being opened.
|
||||
|
||||
@param[in out] File Pointer to the file.
|
||||
@param[in] Partition Pointer to the opened partition.
|
||||
**/
|
||||
VOID
|
||||
Ext4SetupFile (
|
||||
IN OUT EXT4_FILE *File,
|
||||
IN EXT4_PARTITION *Partition
|
||||
)
|
||||
{
|
||||
// Note: We don't yet support revision 2 of the file protocol
|
||||
// (needs DISK_IO2 + asynchronous IO)
|
||||
File->Protocol.Revision = EFI_FILE_PROTOCOL_REVISION;
|
||||
File->Protocol.Open = Ext4Open;
|
||||
File->Protocol.Close = Ext4Close;
|
||||
File->Protocol.Delete = Ext4Delete;
|
||||
File->Protocol.Read = Ext4ReadFile;
|
||||
File->Protocol.Write = Ext4WriteFile;
|
||||
File->Protocol.SetPosition = Ext4SetPosition;
|
||||
File->Protocol.GetPosition = Ext4GetPosition;
|
||||
File->Protocol.GetInfo = Ext4GetInfo;
|
||||
File->Protocol.SetInfo = Ext4SetInfo;
|
||||
|
||||
File->Partition = Partition;
|
||||
}
|
||||
|
||||
/**
|
||||
Unmounts and frees an ext4 partition.
|
||||
|
||||
@param[in] Partition Pointer to the opened partition.
|
||||
|
||||
@retval Status of the unmount.
|
||||
**/
|
||||
EFI_STATUS
|
||||
Ext4UnmountAndFreePartition (
|
||||
IN EXT4_PARTITION *Partition
|
||||
)
|
||||
{
|
||||
LIST_ENTRY *Entry;
|
||||
LIST_ENTRY *NextEntry;
|
||||
EXT4_FILE *File;
|
||||
BOOLEAN DeletedRootDentry;
|
||||
|
||||
Partition->Unmounting = TRUE;
|
||||
Ext4CloseInternal (Partition->Root);
|
||||
|
||||
BASE_LIST_FOR_EACH_SAFE (Entry, NextEntry, &Partition->OpenFiles) {
|
||||
File = EXT4_FILE_FROM_OPEN_FILES_NODE (Entry);
|
||||
|
||||
Ext4CloseInternal (File);
|
||||
}
|
||||
|
||||
DeletedRootDentry = Ext4UnrefDentry (Partition->RootDentry);
|
||||
|
||||
if (!DeletedRootDentry) {
|
||||
DEBUG ((DEBUG_ERROR, "[ext4] Failed to delete root dentry - resource leak present.\n"));
|
||||
}
|
||||
|
||||
FreePool (Partition->BlockGroups);
|
||||
FreePool (Partition);
|
||||
|
||||
return EFI_SUCCESS;
|
||||
}
|
|
@ -0,0 +1,363 @@
|
|||
/** @file
|
||||
Superblock managing routines
|
||||
|
||||
Copyright (c) 2021 - 2023 Pedro Falcato All rights reserved.
|
||||
SPDX-License-Identifier: BSD-2-Clause-Patent
|
||||
**/
|
||||
|
||||
#include "Ext4Dxe.h"
|
||||
|
||||
STATIC CONST UINT32 gSupportedCompatFeat = EXT4_FEATURE_COMPAT_EXT_ATTR;
|
||||
|
||||
STATIC CONST UINT32 gSupportedRoCompatFeat =
|
||||
EXT4_FEATURE_RO_COMPAT_DIR_NLINK | EXT4_FEATURE_RO_COMPAT_EXTRA_ISIZE |
|
||||
EXT4_FEATURE_RO_COMPAT_HUGE_FILE | EXT4_FEATURE_RO_COMPAT_LARGE_FILE |
|
||||
EXT4_FEATURE_RO_COMPAT_GDT_CSUM | EXT4_FEATURE_RO_COMPAT_METADATA_CSUM | EXT4_FEATURE_RO_COMPAT_SPARSE_SUPER;
|
||||
|
||||
STATIC CONST UINT32 gSupportedIncompatFeat =
|
||||
EXT4_FEATURE_INCOMPAT_64BIT | EXT4_FEATURE_INCOMPAT_DIRDATA |
|
||||
EXT4_FEATURE_INCOMPAT_FLEX_BG | EXT4_FEATURE_INCOMPAT_FILETYPE |
|
||||
EXT4_FEATURE_INCOMPAT_EXTENTS | EXT4_FEATURE_INCOMPAT_LARGEDIR |
|
||||
EXT4_FEATURE_INCOMPAT_MMP | EXT4_FEATURE_INCOMPAT_RECOVER | EXT4_FEATURE_INCOMPAT_CSUM_SEED;
|
||||
|
||||
// Future features that may be nice additions in the future:
|
||||
// 1) Btree support: Required for write support and would speed up lookups in large directories.
|
||||
// 2) meta_bg: Required to mount meta_bg-enabled partitions.
|
||||
|
||||
// Note: We ignore MMP because it's impossible that it's mapped elsewhere,
|
||||
// I think (unless there's some sort of network setup where we're accessing a remote partition).
|
||||
|
||||
// Note on corruption signaling:
|
||||
// We (Ext4Dxe) could signal corruption by setting s_state to |= EXT4_FS_STATE_ERRORS_DETECTED.
|
||||
// I've decided against that, because right now the driver is read-only, and
|
||||
// that would mean we would need to writeback the superblock. If something like
|
||||
// this is desired, it's fairly trivial to look for EFI_VOLUME_CORRUPTED
|
||||
// references and add some Ext4SignalCorruption function + function call.
|
||||
|
||||
/**
|
||||
Checks the superblock's magic value.
|
||||
|
||||
@param[in] DiskIo Pointer to the DiskIo.
|
||||
@param[in] BlockIo Pointer to the BlockIo.
|
||||
|
||||
@returns Whether the partition has a valid EXT4 superblock magic value.
|
||||
**/
|
||||
BOOLEAN
|
||||
Ext4SuperblockCheckMagic (
|
||||
IN EFI_DISK_IO_PROTOCOL *DiskIo,
|
||||
IN EFI_BLOCK_IO_PROTOCOL *BlockIo
|
||||
)
|
||||
{
|
||||
UINT16 Magic;
|
||||
EFI_STATUS Status;
|
||||
|
||||
Status = DiskIo->ReadDisk (
|
||||
DiskIo,
|
||||
BlockIo->Media->MediaId,
|
||||
EXT4_SUPERBLOCK_OFFSET + OFFSET_OF (EXT4_SUPERBLOCK, s_magic),
|
||||
sizeof (Magic),
|
||||
&Magic
|
||||
);
|
||||
if (EFI_ERROR (Status)) {
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
if (Magic != EXT4_SIGNATURE) {
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
/**
|
||||
Does brief validation of the ext4 superblock.
|
||||
|
||||
@param[in] Sb Pointer to the read superblock.
|
||||
|
||||
@return TRUE if a valid ext4 superblock, else FALSE.
|
||||
**/
|
||||
BOOLEAN
|
||||
Ext4SuperblockValidate (
|
||||
CONST EXT4_SUPERBLOCK *Sb
|
||||
)
|
||||
{
|
||||
if (Sb->s_magic != EXT4_SIGNATURE) {
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
if ((Sb->s_rev_level != EXT4_DYNAMIC_REV) && (Sb->s_rev_level != EXT4_GOOD_OLD_REV)) {
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
if ((Sb->s_state & EXT4_FS_STATE_UNMOUNTED) == 0) {
|
||||
DEBUG ((DEBUG_WARN, "[ext4] Filesystem was not unmounted cleanly\n"));
|
||||
}
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
/**
|
||||
Calculates the superblock's checksum.
|
||||
|
||||
@param[in] Partition Pointer to the opened partition.
|
||||
@param[in] Sb Pointer to the superblock.
|
||||
|
||||
@return The superblock's checksum.
|
||||
**/
|
||||
STATIC
|
||||
UINT32
|
||||
Ext4CalculateSuperblockChecksum (
|
||||
EXT4_PARTITION *Partition,
|
||||
CONST EXT4_SUPERBLOCK *Sb
|
||||
)
|
||||
{
|
||||
// Most checksums require us to go through a dummy 0 as part of the requirement
|
||||
// that the checksum is done over a structure with its checksum field = 0.
|
||||
UINT32 Checksum;
|
||||
|
||||
Checksum = Ext4CalculateChecksum (
|
||||
Partition,
|
||||
Sb,
|
||||
OFFSET_OF (EXT4_SUPERBLOCK, s_checksum),
|
||||
~0U
|
||||
);
|
||||
|
||||
return Checksum;
|
||||
}
|
||||
|
||||
/**
|
||||
Verifies that the superblock's checksum is valid.
|
||||
|
||||
@param[in] Partition Pointer to the opened partition.
|
||||
@param[in] Sb Pointer to the superblock.
|
||||
|
||||
@return The superblock's checksum.
|
||||
**/
|
||||
STATIC
|
||||
BOOLEAN
|
||||
Ext4VerifySuperblockChecksum (
|
||||
EXT4_PARTITION *Partition,
|
||||
CONST EXT4_SUPERBLOCK *Sb
|
||||
)
|
||||
{
|
||||
if (!EXT4_HAS_METADATA_CSUM (Partition)) {
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
return Sb->s_checksum == Ext4CalculateSuperblockChecksum (Partition, Sb);
|
||||
}
|
||||
|
||||
/**
|
||||
Opens and parses the superblock.
|
||||
|
||||
@param[out] Partition Partition structure to fill with filesystem details.
|
||||
@retval EFI_SUCCESS Parsing was successful and the partition is a
|
||||
valid ext4 partition.
|
||||
**/
|
||||
EFI_STATUS
|
||||
Ext4OpenSuperblock (
|
||||
OUT EXT4_PARTITION *Partition
|
||||
)
|
||||
{
|
||||
UINT32 Index;
|
||||
EFI_STATUS Status;
|
||||
EXT4_SUPERBLOCK *Sb;
|
||||
UINT32 NrBlocksRem;
|
||||
UINTN NrBlocks;
|
||||
UINT32 UnsupportedRoCompat;
|
||||
EXT4_BLOCK_GROUP_DESC *Desc;
|
||||
|
||||
Status = Ext4ReadDiskIo (
|
||||
Partition,
|
||||
&Partition->SuperBlock,
|
||||
sizeof (EXT4_SUPERBLOCK),
|
||||
EXT4_SUPERBLOCK_OFFSET
|
||||
);
|
||||
|
||||
if (EFI_ERROR (Status)) {
|
||||
return Status;
|
||||
}
|
||||
|
||||
Sb = &Partition->SuperBlock;
|
||||
|
||||
if (!Ext4SuperblockValidate (Sb)) {
|
||||
return EFI_VOLUME_CORRUPTED;
|
||||
}
|
||||
|
||||
if (Sb->s_rev_level == EXT4_DYNAMIC_REV) {
|
||||
Partition->FeaturesCompat = Sb->s_feature_compat;
|
||||
Partition->FeaturesIncompat = Sb->s_feature_incompat;
|
||||
Partition->FeaturesRoCompat = Sb->s_feature_ro_compat;
|
||||
Partition->InodeSize = Sb->s_inode_size;
|
||||
|
||||
// Check for proper alignment of InodeSize and that InodeSize is indeed larger than
|
||||
// the minimum size, 128 bytes.
|
||||
if (((Partition->InodeSize % 4) != 0) || (Partition->InodeSize < EXT4_GOOD_OLD_INODE_SIZE)) {
|
||||
return EFI_VOLUME_CORRUPTED;
|
||||
}
|
||||
} else {
|
||||
// GOOD_OLD_REV
|
||||
Partition->FeaturesCompat = Partition->FeaturesIncompat = Partition->FeaturesRoCompat = 0;
|
||||
Partition->InodeSize = EXT4_GOOD_OLD_INODE_SIZE;
|
||||
}
|
||||
|
||||
// Now, check for the feature set of the filesystem
|
||||
// It's essential to check for this to avoid filesystem corruption and to avoid
|
||||
// accidentally opening an ext2/3/4 filesystem we don't understand, which would be disastrous.
|
||||
|
||||
if (Partition->FeaturesIncompat & ~gSupportedIncompatFeat) {
|
||||
DEBUG ((
|
||||
DEBUG_ERROR,
|
||||
"[ext4] Unsupported features %lx\n",
|
||||
Partition->FeaturesIncompat & ~gSupportedIncompatFeat
|
||||
));
|
||||
return EFI_UNSUPPORTED;
|
||||
}
|
||||
|
||||
if (EXT4_HAS_INCOMPAT (Partition, EXT4_FEATURE_INCOMPAT_RECOVER)) {
|
||||
DEBUG ((DEBUG_WARN, "[ext4] Needs journal recovery, mounting read-only\n"));
|
||||
Partition->ReadOnly = TRUE;
|
||||
}
|
||||
|
||||
// At the time of writing, it's the only supported checksum.
|
||||
if (EXT4_HAS_METADATA_CSUM (Partition) && (Sb->s_checksum_type != EXT4_CHECKSUM_CRC32C)) {
|
||||
return EFI_UNSUPPORTED;
|
||||
}
|
||||
|
||||
if (EXT4_HAS_INCOMPAT (Partition, EXT4_FEATURE_INCOMPAT_CSUM_SEED)) {
|
||||
Partition->InitialSeed = Sb->s_checksum_seed;
|
||||
} else {
|
||||
Partition->InitialSeed = Ext4CalculateChecksum (Partition, Sb->s_uuid, 16, ~0U);
|
||||
}
|
||||
|
||||
UnsupportedRoCompat = Partition->FeaturesRoCompat & ~gSupportedRoCompatFeat;
|
||||
|
||||
if (UnsupportedRoCompat != 0) {
|
||||
DEBUG ((DEBUG_WARN, "[ext4] Unsupported ro compat %x\n", UnsupportedRoCompat));
|
||||
Partition->ReadOnly = TRUE;
|
||||
}
|
||||
|
||||
// gSupportedCompatFeat is documentation-only since we never need to access it.
|
||||
// The line below avoids unused variable warnings.
|
||||
(VOID)gSupportedCompatFeat;
|
||||
|
||||
DEBUG ((DEBUG_FS, "Read only = %u\n", Partition->ReadOnly));
|
||||
|
||||
if (Sb->s_inodes_per_group == 0) {
|
||||
DEBUG ((DEBUG_ERROR, "[ext4] Inodes per group can not be zero\n"));
|
||||
return EFI_VOLUME_CORRUPTED;
|
||||
}
|
||||
|
||||
if (Sb->s_log_block_size > EXT4_LOG_BLOCK_SIZE_MAX) {
|
||||
DEBUG ((DEBUG_ERROR, "[ext4] SuperBlock s_log_block_size %lu is too big\n", Sb->s_log_block_size));
|
||||
return EFI_UNSUPPORTED;
|
||||
}
|
||||
|
||||
Partition->BlockSize = (UINT32)LShiftU64 (1024, Sb->s_log_block_size);
|
||||
|
||||
// The size of a block group can also be calculated as 8 * Partition->BlockSize
|
||||
if (Sb->s_blocks_per_group != 8 * Partition->BlockSize) {
|
||||
return EFI_UNSUPPORTED;
|
||||
}
|
||||
|
||||
Partition->NumberBlocks = EXT4_BLOCK_NR_FROM_HALFS (Partition, Sb->s_blocks_count, Sb->s_blocks_count_hi);
|
||||
Partition->NumberBlockGroups = DivU64x32 (Partition->NumberBlocks, Sb->s_blocks_per_group);
|
||||
|
||||
DEBUG ((
|
||||
DEBUG_FS,
|
||||
"[ext4] Number of blocks = %lu\n[ext4] Number of block groups: %lu\n",
|
||||
Partition->NumberBlocks,
|
||||
Partition->NumberBlockGroups
|
||||
));
|
||||
|
||||
if (EXT4_IS_64_BIT (Partition)) {
|
||||
// s_desc_size should be 4 byte aligned and
|
||||
// 64 bit filesystems need DescSize to be 64 bytes
|
||||
if (((Sb->s_desc_size % 4) != 0) || (Sb->s_desc_size < EXT4_64BIT_BLOCK_DESC_SIZE)) {
|
||||
return EFI_VOLUME_CORRUPTED;
|
||||
}
|
||||
|
||||
Partition->DescSize = Sb->s_desc_size;
|
||||
} else {
|
||||
Partition->DescSize = EXT4_OLD_BLOCK_DESC_SIZE;
|
||||
}
|
||||
|
||||
if (!Ext4VerifySuperblockChecksum (Partition, Sb)) {
|
||||
DEBUG ((DEBUG_ERROR, "[ext4] Bad superblock checksum %lx\n", Ext4CalculateSuperblockChecksum (Partition, Sb)));
|
||||
return EFI_VOLUME_CORRUPTED;
|
||||
}
|
||||
|
||||
NrBlocks = (UINTN)DivU64x32Remainder (
|
||||
MultU64x32 (Partition->NumberBlockGroups, Partition->DescSize),
|
||||
Partition->BlockSize,
|
||||
&NrBlocksRem
|
||||
);
|
||||
|
||||
if (NrBlocksRem != 0) {
|
||||
NrBlocks++;
|
||||
}
|
||||
|
||||
Partition->BlockGroups = Ext4AllocAndReadBlocks (Partition, NrBlocks, Partition->BlockSize == 1024 ? 2 : 1);
|
||||
|
||||
if (Partition->BlockGroups == NULL) {
|
||||
return EFI_OUT_OF_RESOURCES;
|
||||
}
|
||||
|
||||
for (Index = 0; Index < Partition->NumberBlockGroups; Index++) {
|
||||
Desc = Ext4GetBlockGroupDesc (Partition, Index);
|
||||
if (!Ext4VerifyBlockGroupDescChecksum (Partition, Desc, Index)) {
|
||||
DEBUG ((DEBUG_ERROR, "[ext4] Block group descriptor %u has an invalid checksum\n", Index));
|
||||
FreePool (Partition->BlockGroups);
|
||||
return EFI_VOLUME_CORRUPTED;
|
||||
}
|
||||
}
|
||||
|
||||
// RootDentry will serve as the basis of our directory entry tree.
|
||||
Partition->RootDentry = Ext4CreateDentry (L"\\", NULL);
|
||||
|
||||
if (Partition->RootDentry == NULL) {
|
||||
FreePool (Partition->BlockGroups);
|
||||
return EFI_OUT_OF_RESOURCES;
|
||||
}
|
||||
|
||||
// Note that the cast below is completely safe, because EXT4_FILE is a specialization of EFI_FILE_PROTOCOL
|
||||
Status = Ext4OpenVolume (&Partition->Interface, (EFI_FILE_PROTOCOL **)&Partition->Root);
|
||||
|
||||
if (EFI_ERROR (Status)) {
|
||||
Ext4UnrefDentry (Partition->RootDentry);
|
||||
FreePool (Partition->BlockGroups);
|
||||
}
|
||||
|
||||
return Status;
|
||||
}
|
||||
|
||||
/**
|
||||
Calculates the checksum of the given buffer.
|
||||
@param[in] Partition Pointer to the opened EXT4 partition.
|
||||
@param[in] Buffer Pointer to the buffer.
|
||||
@param[in] Length Length of the buffer, in bytes.
|
||||
@param[in] InitialValue Initial value of the CRC.
|
||||
|
||||
@return The checksum.
|
||||
**/
|
||||
UINT32
|
||||
Ext4CalculateChecksum (
|
||||
IN CONST EXT4_PARTITION *Partition,
|
||||
IN CONST VOID *Buffer,
|
||||
IN UINTN Length,
|
||||
IN UINT32 InitialValue
|
||||
)
|
||||
{
|
||||
if (!EXT4_HAS_METADATA_CSUM (Partition)) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
switch (Partition->SuperBlock.s_checksum_type) {
|
||||
case EXT4_CHECKSUM_CRC32C:
|
||||
// For some reason, EXT4 really likes non-inverted CRC32C checksums, so we stick to that here.
|
||||
return ~CalculateCrc32c(Buffer, Length, ~InitialValue);
|
||||
default:
|
||||
ASSERT (FALSE);
|
||||
return 0;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,261 @@
|
|||
/** @file
|
||||
Symbolic links routines
|
||||
|
||||
Copyright (c) 2022-2023 Savva Mitrofanov All rights reserved.
|
||||
SPDX-License-Identifier: BSD-2-Clause-Patent
|
||||
**/
|
||||
|
||||
#include "Ext4Dxe.h"
|
||||
|
||||
/**
|
||||
Detects if a symlink is a fast symlink.
|
||||
|
||||
@param[in] File Pointer to the opened file.
|
||||
|
||||
@return BOOLEAN Whether symlink is a fast symlink
|
||||
**/
|
||||
STATIC
|
||||
BOOLEAN
|
||||
Ext4SymlinkIsFastSymlink (
|
||||
IN CONST EXT4_FILE *File
|
||||
)
|
||||
{
|
||||
//
|
||||
// Detection logic of the fast-symlink splits into two behaviors - old and new.
|
||||
// The old behavior is based on comparing the extended attribute blocks
|
||||
// with the inode's i_blocks, and if it's zero we know the inode isn't storing
|
||||
// the link in filesystem blocks, so we look to the inode->i_data.
|
||||
// The new behavior is apparently needed only with the large EA inode feature.
|
||||
// In this case we check that inode size less than maximum fast symlink size.
|
||||
// So, we revert to the old behavior if the large EA inode feature is not set.
|
||||
//
|
||||
UINT32 FileAcl;
|
||||
UINT32 ExtAttrBlocks;
|
||||
|
||||
if ((File->Inode->i_flags & EXT4_EA_INODE_FL) == 0) {
|
||||
FileAcl = File->Inode->i_file_acl;
|
||||
if (EXT4_IS_64_BIT (File->Partition)) {
|
||||
//
|
||||
// We don't care about final value, we are just checking for any bit is set
|
||||
// so, thats why we neglect LShiftU64(.., 32)
|
||||
//
|
||||
FileAcl |= File->Inode->i_osd2.data_linux.l_i_file_acl_high;
|
||||
}
|
||||
|
||||
ExtAttrBlocks = FileAcl != 0 ? (File->Partition->BlockSize >> 9) : 0;
|
||||
|
||||
return File->Inode->i_blocks == ExtAttrBlocks;
|
||||
}
|
||||
|
||||
return EXT4_INODE_SIZE (File->Inode) <= EXT4_FAST_SYMLINK_MAX_SIZE;
|
||||
}
|
||||
|
||||
/**
|
||||
Reads a fast symlink file.
|
||||
|
||||
@param[in] Partition Pointer to the ext4 partition.
|
||||
@param[in] File Pointer to the open symlink file.
|
||||
@param[out] AsciiSymlink Pointer to the output ascii symlink string.
|
||||
@param[out] AsciiSymlinkSize Pointer to the output ascii symlink string length.
|
||||
|
||||
@retval EFI_SUCCESS Fast symlink was read.
|
||||
@retval EFI_OUT_OF_RESOURCES Memory allocation error.
|
||||
**/
|
||||
STATIC
|
||||
EFI_STATUS
|
||||
Ext4ReadFastSymlink (
|
||||
IN EXT4_PARTITION *Partition,
|
||||
IN EXT4_FILE *File,
|
||||
OUT CHAR8 **AsciiSymlink,
|
||||
OUT UINT32 *AsciiSymlinkSize
|
||||
)
|
||||
{
|
||||
UINT32 SymlinkSize;
|
||||
CHAR8 *AsciiSymlinkTmp;
|
||||
|
||||
//
|
||||
// Fast-symlink's EXT4_INODE_SIZE is not necessarily validated when we checked it in
|
||||
// Ext4SymlinkIsFastSymlink(), so truncate if necessary.
|
||||
//
|
||||
SymlinkSize = (UINT32)MIN (EXT4_INODE_SIZE (File->Inode), EXT4_FAST_SYMLINK_MAX_SIZE);
|
||||
|
||||
AsciiSymlinkTmp = AllocatePool (SymlinkSize + 1);
|
||||
if (AsciiSymlinkTmp == NULL) {
|
||||
DEBUG ((DEBUG_ERROR, "[ext4] Failed to allocate symlink ascii string buffer\n"));
|
||||
return EFI_OUT_OF_RESOURCES;
|
||||
}
|
||||
|
||||
CopyMem (AsciiSymlinkTmp, File->Inode->i_data, SymlinkSize);
|
||||
|
||||
//
|
||||
// Add null-terminator
|
||||
//
|
||||
AsciiSymlinkTmp[SymlinkSize] = '\0';
|
||||
|
||||
*AsciiSymlink = AsciiSymlinkTmp;
|
||||
*AsciiSymlinkSize = SymlinkSize + 1;
|
||||
|
||||
return EFI_SUCCESS;
|
||||
}
|
||||
|
||||
/**
|
||||
Reads a slow symlink file.
|
||||
|
||||
@param[in] Partition Pointer to the ext4 partition.
|
||||
@param[in] File Pointer to the open symlink file.
|
||||
@param[out] AsciiSymlink Pointer to the output ascii symlink string.
|
||||
@param[out] AsciiSymlinkSize Pointer to the output ascii symlink string length.
|
||||
|
||||
@retval EFI_SUCCESS Slow symlink was read.
|
||||
@retval EFI_OUT_OF_RESOURCES Memory allocation error.
|
||||
@retval EFI_INVALID_PARAMETER Slow symlink path has incorrect length
|
||||
@retval EFI_VOLUME_CORRUPTED Symlink read block size differ from inode value
|
||||
**/
|
||||
STATIC
|
||||
EFI_STATUS
|
||||
Ext4ReadSlowSymlink (
|
||||
IN EXT4_PARTITION *Partition,
|
||||
IN EXT4_FILE *File,
|
||||
OUT CHAR8 **AsciiSymlink,
|
||||
OUT UINT32 *AsciiSymlinkSize
|
||||
)
|
||||
{
|
||||
EFI_STATUS Status;
|
||||
CHAR8 *SymlinkTmp;
|
||||
UINT64 SymlinkSizeTmp;
|
||||
UINT32 SymlinkAllocateSize;
|
||||
UINTN ReadSize;
|
||||
|
||||
SymlinkSizeTmp = EXT4_INODE_SIZE (File->Inode);
|
||||
|
||||
//
|
||||
// Allocate EXT4_INODE_SIZE + 1
|
||||
//
|
||||
if (SymlinkSizeTmp >= EXT4_EFI_PATH_MAX) {
|
||||
DEBUG ((
|
||||
DEBUG_WARN,
|
||||
"[ext4] Warn: symlink path maximum length was hit!\n"
|
||||
));
|
||||
return EFI_INVALID_PARAMETER;
|
||||
}
|
||||
|
||||
SymlinkAllocateSize = (UINT32)SymlinkSizeTmp + 1;
|
||||
|
||||
SymlinkTmp = AllocatePool (SymlinkAllocateSize);
|
||||
if (SymlinkTmp == NULL) {
|
||||
DEBUG ((DEBUG_FS, "[ext4] Failed to allocate symlink ascii string buffer\n"));
|
||||
return EFI_OUT_OF_RESOURCES;
|
||||
}
|
||||
|
||||
ReadSize = (UINTN)SymlinkSizeTmp;
|
||||
Status = Ext4Read (Partition, File, SymlinkTmp, File->Position, &ReadSize);
|
||||
if (EFI_ERROR (Status)) {
|
||||
DEBUG ((DEBUG_FS, "[ext4] Failed to read symlink from blocks with status %r\n", Status));
|
||||
FreePool (SymlinkTmp);
|
||||
return Status;
|
||||
}
|
||||
|
||||
if (SymlinkSizeTmp != ReadSize) {
|
||||
DEBUG ((
|
||||
DEBUG_FS,
|
||||
"[ext4] Error! The size of the read block doesn't match the value from the inode!\n"
|
||||
));
|
||||
FreePool (SymlinkTmp);
|
||||
return EFI_VOLUME_CORRUPTED;
|
||||
}
|
||||
|
||||
//
|
||||
// Add null-terminator
|
||||
//
|
||||
SymlinkTmp[ReadSize] = '\0';
|
||||
|
||||
*AsciiSymlinkSize = SymlinkAllocateSize;
|
||||
*AsciiSymlink = SymlinkTmp;
|
||||
|
||||
return EFI_SUCCESS;
|
||||
}
|
||||
|
||||
/**
|
||||
Reads a symlink file.
|
||||
|
||||
@param[in] Partition Pointer to the ext4 partition.
|
||||
@param[in] File Pointer to the open symlink file.
|
||||
@param[out] Symlink Pointer to the output unicode symlink string.
|
||||
|
||||
@retval EFI_SUCCESS Symlink was read.
|
||||
@retval EFI_ACCESS_DENIED Symlink is encrypted.
|
||||
@retval EFI_OUT_OF_RESOURCES Memory allocation error.
|
||||
@retval EFI_INVALID_PARAMETER Symlink path has incorrect length
|
||||
@retval EFI_VOLUME_CORRUPTED Symlink read block size differ from inode value
|
||||
**/
|
||||
EFI_STATUS
|
||||
Ext4ReadSymlink (
|
||||
IN EXT4_PARTITION *Partition,
|
||||
IN EXT4_FILE *File,
|
||||
OUT CHAR16 **Symlink
|
||||
)
|
||||
{
|
||||
EFI_STATUS Status;
|
||||
CHAR8 *SymlinkTmp;
|
||||
UINT32 SymlinkSize;
|
||||
CHAR16 *Symlink16Tmp;
|
||||
CHAR16 *Needle;
|
||||
|
||||
//
|
||||
// Assume that we already read Inode via Ext4ReadInode
|
||||
// Skip reading, just check encryption flag
|
||||
//
|
||||
if ((File->Inode->i_flags & EXT4_ENCRYPT_FL) != 0) {
|
||||
DEBUG ((DEBUG_WARN, "[ext4] Warn: symlink is encrypted\n"));
|
||||
return EFI_ACCESS_DENIED;
|
||||
}
|
||||
|
||||
if (Ext4SymlinkIsFastSymlink (File)) {
|
||||
Status = Ext4ReadFastSymlink (Partition, File, &SymlinkTmp, &SymlinkSize);
|
||||
} else {
|
||||
Status = Ext4ReadSlowSymlink (Partition, File, &SymlinkTmp, &SymlinkSize);
|
||||
}
|
||||
|
||||
if (EFI_ERROR (Status)) {
|
||||
DEBUG ((DEBUG_FS, "[ext4] Symlink read error with Status %r\n", Status));
|
||||
return Status;
|
||||
}
|
||||
|
||||
Symlink16Tmp = AllocatePool (SymlinkSize * sizeof (CHAR16));
|
||||
if (Symlink16Tmp == NULL) {
|
||||
DEBUG ((DEBUG_FS, "[ext4] Failed to allocate symlink unicode string buffer\n"));
|
||||
FreePool (SymlinkTmp);
|
||||
return EFI_OUT_OF_RESOURCES;
|
||||
}
|
||||
|
||||
Status = AsciiStrToUnicodeStrS (
|
||||
SymlinkTmp,
|
||||
Symlink16Tmp,
|
||||
SymlinkSize
|
||||
);
|
||||
|
||||
FreePool (SymlinkTmp);
|
||||
|
||||
if (EFI_ERROR (Status)) {
|
||||
DEBUG ((
|
||||
DEBUG_FS,
|
||||
"[ext4] Failed to convert ascii symlink to unicode with Status %r\n",
|
||||
Status
|
||||
));
|
||||
FreePool (Symlink16Tmp);
|
||||
return Status;
|
||||
}
|
||||
|
||||
//
|
||||
// Convert to UEFI slashes
|
||||
//
|
||||
for (Needle = Symlink16Tmp; *Needle != L'\0'; Needle++) {
|
||||
if (*Needle == L'/') {
|
||||
*Needle = L'\\';
|
||||
}
|
||||
}
|
||||
|
||||
*Symlink = Symlink16Tmp;
|
||||
|
||||
return Status;
|
||||
}
|
|
@ -0,0 +1,11 @@
|
|||
## @file
|
||||
# Ext4 DSC include file for [LibraryClasses] section of all Architectures.
|
||||
#
|
||||
# SPDX-FileCopyrightText: Copyright (c) 2022 NVIDIA CORPORATION & AFFILIATES. All rights reserved.
|
||||
# SPDX-License-Identifier: BSD-2-Clause-Patent
|
||||
#
|
||||
##
|
||||
|
||||
!if $(EXT4_ENABLE) == TRUE
|
||||
BaseUcs2Utf8Lib|RedfishPkg/Library/BaseUcs2Utf8Lib/BaseUcs2Utf8Lib.inf
|
||||
!endif
|
|
@ -0,0 +1,65 @@
|
|||
## @file
|
||||
# CI configuration for Ext4Pkg
|
||||
#
|
||||
# Copyright (c) Microsoft Corporation
|
||||
# Copyright (c) 2020, Intel Corporation. All rights reserved.<BR>
|
||||
# SPDX-License-Identifier: BSD-2-Clause-Patent
|
||||
##
|
||||
{
|
||||
"LicenseCheck": {
|
||||
"IgnoreFiles": []
|
||||
},
|
||||
"EccCheck": {
|
||||
## Exception sample looks like below:
|
||||
## "ExceptionList": [
|
||||
## "<ErrorID>", "<KeyWord>"
|
||||
## ]
|
||||
"ExceptionList": [
|
||||
],
|
||||
## Both file path and directory path are accepted.
|
||||
"IgnoreFiles": [
|
||||
]
|
||||
},
|
||||
"CompilerPlugin": {
|
||||
"DscPath": "Ext4Pkg.dsc"
|
||||
},
|
||||
"CharEncodingCheck": {
|
||||
"IgnoreFiles": []
|
||||
},
|
||||
"DependencyCheck": {
|
||||
"AcceptableDependencies": [
|
||||
"MdePkg/MdePkg.dec",
|
||||
"MdeModulePkg/MdeModulePkg.dec",
|
||||
],
|
||||
# For host based unit tests
|
||||
"AcceptableDependencies-HOST_APPLICATION":[],
|
||||
# For UEFI shell based apps
|
||||
"AcceptableDependencies-UEFI_APPLICATION":[],
|
||||
"IgnoreInf": []
|
||||
},
|
||||
"DscCompleteCheck": {
|
||||
"IgnoreInf": [],
|
||||
"DscPath": "Ext4Pkg.dsc"
|
||||
},
|
||||
"GuidCheck": {
|
||||
"IgnoreGuidName": [],
|
||||
"IgnoreGuidValue": [],
|
||||
"IgnoreFoldersAndFiles": []
|
||||
},
|
||||
"LibraryClassCheck": {
|
||||
"IgnoreHeaderFile": []
|
||||
},
|
||||
"SpellCheck": {
|
||||
"ExtendWords": [
|
||||
"ELTORITO",
|
||||
"FHAND",
|
||||
"IFILE",
|
||||
"OFILE",
|
||||
"FDISKed",
|
||||
"Lfnbuffer",
|
||||
"FFFFFFFFL",
|
||||
"CDVOL",
|
||||
"DMDEPKG"
|
||||
]
|
||||
}
|
||||
}
|
|
@ -0,0 +1,17 @@
|
|||
## @file
|
||||
# Ext4 Package
|
||||
#
|
||||
# This package provides libraries and drivers related to the ext4 filesystem implementation.
|
||||
# More details are available at: https://www.kernel.org/doc/html/v5.4/filesystems/ext4/index.html
|
||||
#
|
||||
# Copyright (c) 2021 Pedro Falcato
|
||||
# SPDX-License-Identifier: BSD-2-Clause-Patent
|
||||
#
|
||||
##
|
||||
|
||||
[Defines]
|
||||
DEC_SPECIFICATION = 0x00010005
|
||||
PACKAGE_NAME = Ext4Pkg
|
||||
PACKAGE_UNI_FILE = Ext4Pkg.uni
|
||||
PACKAGE_GUID = 6B4BF998-668B-46D3-BCFA-971F99F8708C
|
||||
PACKAGE_VERSION = 0.1
|
|
@ -0,0 +1,75 @@
|
|||
## @file
|
||||
# Ext4 Package
|
||||
#
|
||||
# This package provides libraries and drivers related to the ext4 filesystem implementation.
|
||||
# More details are available at: https://www.kernel.org/doc/html/v5.4/filesystems/ext4/index.html
|
||||
#
|
||||
# Copyright (c) 2021 Pedro Falcato
|
||||
# SPDX-License-Identifier: BSD-2-Clause-Patent
|
||||
#
|
||||
##
|
||||
|
||||
|
||||
[Defines]
|
||||
PLATFORM_NAME = Ext4
|
||||
PLATFORM_GUID = 6B4BF998-668B-46D3-BCFA-971F99F8708C
|
||||
PLATFORM_VERSION = 0.1
|
||||
DSC_SPECIFICATION = 0x00010005
|
||||
SUPPORTED_ARCHITECTURES = IA32|X64|EBC|ARM|AARCH64|RISCV64
|
||||
OUTPUT_DIRECTORY = Build/Ext4Pkg
|
||||
BUILD_TARGETS = DEBUG|RELEASE|NOOPT
|
||||
SKUID_IDENTIFIER = DEFAULT
|
||||
|
||||
!include MdePkg/MdeLibs.dsc.inc
|
||||
|
||||
[BuildOptions]
|
||||
*_*_*_CC_FLAGS = -D DISABLE_NEW_DEPRECATED_INTERFACES
|
||||
|
||||
[LibraryClasses]
|
||||
#
|
||||
# Entry Point Libraries
|
||||
#
|
||||
UefiDriverEntryPoint|MdePkg/Library/UefiDriverEntryPoint/UefiDriverEntryPoint.inf
|
||||
#
|
||||
# Common Libraries
|
||||
#
|
||||
BaseLib|MdePkg/Library/BaseLib/BaseLib.inf
|
||||
BaseMemoryLib|MdePkg/Library/BaseMemoryLib/BaseMemoryLib.inf
|
||||
UefiLib|MdePkg/Library/UefiLib/UefiLib.inf
|
||||
PrintLib|MdePkg/Library/BasePrintLib/BasePrintLib.inf
|
||||
PcdLib|MdePkg/Library/BasePcdLibNull/BasePcdLibNull.inf
|
||||
MemoryAllocationLib|MdePkg/Library/UefiMemoryAllocationLib/UefiMemoryAllocationLib.inf
|
||||
UefiBootServicesTableLib|MdePkg/Library/UefiBootServicesTableLib/UefiBootServicesTableLib.inf
|
||||
UefiRuntimeServicesTableLib|MdePkg/Library/UefiRuntimeServicesTableLib/UefiRuntimeServicesTableLib.inf
|
||||
DebugLib|MdePkg/Library/BaseDebugLibNull/BaseDebugLibNull.inf
|
||||
DebugPrintErrorLevelLib|MdePkg/Library/BaseDebugPrintErrorLevelLib/BaseDebugPrintErrorLevelLib.inf
|
||||
DevicePathLib|MdePkg/Library/UefiDevicePathLib/UefiDevicePathLib.inf
|
||||
OrderedCollectionLib|MdePkg/Library/BaseOrderedCollectionRedBlackTreeLib/BaseOrderedCollectionRedBlackTreeLib.inf
|
||||
BaseUcs2Utf8Lib|RedfishPkg/Library/BaseUcs2Utf8Lib/BaseUcs2Utf8Lib.inf
|
||||
|
||||
#
|
||||
# Required for stack protector support
|
||||
#
|
||||
NULL|MdePkg/Library/BaseStackCheckLib/BaseStackCheckLib.inf
|
||||
|
||||
###################################################################################################
|
||||
#
|
||||
# Components Section - list of the modules and components that will be processed by compilation
|
||||
# tools and the EDK II tools to generate PE32/PE32+/Coff image files.
|
||||
#
|
||||
# Note: The EDK II DSC file is not used to specify how compiled binary images get placed
|
||||
# into firmware volume images. This section is just a list of modules to compile from
|
||||
# source into UEFI-compliant binaries.
|
||||
# It is the FDF file that contains information on combining binary files into firmware
|
||||
# volume images, whose concept is beyond UEFI and is described in PI specification.
|
||||
# Binary modules do not need to be listed in this section, as they should be
|
||||
# specified in the FDF file. For example: Shell binary (Shell_Full.efi), FAT binary (Fat.efi),
|
||||
# Logo (Logo.bmp), and etc.
|
||||
# There may also be modules listed in this section that are not required in the FDF file,
|
||||
# When a module listed here is excluded from FDF file, then UEFI-compliant binary will be
|
||||
# generated for it, but the binary will not be put into any firmware volume.
|
||||
#
|
||||
###################################################################################################
|
||||
|
||||
[Components]
|
||||
Ext4Pkg/Ext4Dxe/Ext4Dxe.inf
|
|
@ -0,0 +1,14 @@
|
|||
## @file
|
||||
# Ext4 Package
|
||||
#
|
||||
# This package provides libraries and drivers related to the ext4 filesystem implementation.
|
||||
# More details are available at: https://www.kernel.org/doc/html/v5.4/filesystems/ext4/index.html
|
||||
#
|
||||
# Copyright (c) 2021 Pedro Falcato
|
||||
# SPDX-License-Identifier: BSD-2-Clause-Patent
|
||||
#
|
||||
##
|
||||
|
||||
#string STR_PACKAGE_ABSTRACT #language en-US "Module implementations for the EXT4 file system"
|
||||
|
||||
#string STR_PACKAGE_DESCRIPTION #language en-US "This package contains UEFI drivers and libraries for the EXT4 file system."
|
|
@ -0,0 +1,68 @@
|
|||
/** @file
|
||||
Variable Flash Information Library
|
||||
|
||||
Copyright (c) Microsoft Corporation<BR>
|
||||
SPDX-License-Identifier: BSD-2-Clause-Patent
|
||||
|
||||
**/
|
||||
|
||||
#ifndef VARIABLE_FLASH_INFO_LIB_H_
|
||||
#define VARIABLE_FLASH_INFO_LIB_H_
|
||||
|
||||
/**
|
||||
Get the base address and size for the NV storage area used for UEFI variable storage.
|
||||
|
||||
@param[out] BaseAddress The NV storage base address.
|
||||
@param[out] Length The NV storage length in bytes.
|
||||
|
||||
@retval EFI_SUCCESS NV storage information was found successfully.
|
||||
@retval EFI_INVALID_PARAMETER A required pointer parameter is NULL.
|
||||
@retval EFI_NOT_FOUND NV storage information could not be found.
|
||||
|
||||
**/
|
||||
EFI_STATUS
|
||||
EFIAPI
|
||||
GetVariableFlashNvStorageInfo (
|
||||
OUT EFI_PHYSICAL_ADDRESS *BaseAddress,
|
||||
OUT UINT64 *Length
|
||||
);
|
||||
|
||||
/**
|
||||
Get the base address and size for the fault tolerant write (FTW) spare
|
||||
area used for UEFI variable storage.
|
||||
|
||||
@param[out] BaseAddress The FTW spare base address.
|
||||
@param[out] Length The FTW spare length in bytes.
|
||||
|
||||
@retval EFI_SUCCESS FTW spare information was found successfully.
|
||||
@retval EFI_INVALID_PARAMETER A required pointer parameter is NULL.
|
||||
@retval EFI_NOT_FOUND FTW spare information could not be found.
|
||||
|
||||
**/
|
||||
EFI_STATUS
|
||||
EFIAPI
|
||||
GetVariableFlashFtwSpareInfo (
|
||||
OUT EFI_PHYSICAL_ADDRESS *BaseAddress,
|
||||
OUT UINT64 *Length
|
||||
);
|
||||
|
||||
/**
|
||||
Get the base address and size for the fault tolerant write (FTW) working
|
||||
area used for UEFI variable storage.
|
||||
|
||||
@param[out] BaseAddress The FTW working area base address.
|
||||
@param[out] Length The FTW working area length in bytes.
|
||||
|
||||
@retval EFI_SUCCESS FTW working information was found successfully.
|
||||
@retval EFI_INVALID_PARAMETER A required pointer parameter is NULL.
|
||||
@retval EFI_NOT_FOUND FTW working information could not be found.
|
||||
|
||||
**/
|
||||
EFI_STATUS
|
||||
EFIAPI
|
||||
GetVariableFlashFtwWorkingInfo (
|
||||
OUT EFI_PHYSICAL_ADDRESS *BaseAddress,
|
||||
OUT UINT64 *Length
|
||||
);
|
||||
|
||||
#endif
|
|
@ -0,0 +1,161 @@
|
|||
/** @file -- VariablePolicyHelperLib.h
|
||||
This library contains helper functions for marshalling and registering
|
||||
new policies with the VariablePolicy infrastructure.
|
||||
|
||||
Copyright (c) Microsoft Corporation.
|
||||
SPDX-License-Identifier: BSD-2-Clause-Patent
|
||||
|
||||
**/
|
||||
|
||||
#ifndef _EDKII_VARIABLE_POLICY_HELPER_LIB_H_
|
||||
#define _EDKII_VARIABLE_POLICY_HELPER_LIB_H_
|
||||
|
||||
#include <Protocol/VariablePolicy.h>
|
||||
|
||||
/**
|
||||
This helper function will allocate and populate a new VariablePolicy
|
||||
structure for a policy that does not contain any sub-structures (such as
|
||||
VARIABLE_LOCK_ON_VAR_STATE_POLICY).
|
||||
|
||||
NOTE: Caller will need to free structure once finished.
|
||||
|
||||
@param[in] Namespace Pointer to an EFI_GUID for the target variable namespace that this policy will protect.
|
||||
@param[in] Name [Optional] If provided, a pointer to the CHAR16 array for the target variable name.
|
||||
Otherwise, will create a policy that targets an entire namespace.
|
||||
@param[in] MinSize MinSize for the VariablePolicy.
|
||||
@param[in] MaxSize MaxSize for the VariablePolicy.
|
||||
@param[in] AttributesMustHave AttributesMustHave for the VariablePolicy.
|
||||
@param[in] AttributesCantHave AttributesCantHave for the VariablePolicy.
|
||||
@param[in] LockPolicyType LockPolicyType for the VariablePolicy.
|
||||
@param[out] NewEntry If successful, will be set to a pointer to the allocated buffer containing the
|
||||
new policy.
|
||||
|
||||
@retval EFI_SUCCESS Operation completed successfully and structure is populated.
|
||||
@retval EFI_INVALID_PARAMETER Namespace is NULL.
|
||||
@retval EFI_INVALID_PARAMETER LockPolicyType is invalid for a basic structure.
|
||||
@retval EFI_BUFFER_TOO_SMALL Finished structure would not fit in UINT16 size.
|
||||
@retval EFI_OUT_OF_RESOURCES Could not allocate sufficient space for structure.
|
||||
|
||||
**/
|
||||
EFI_STATUS
|
||||
EFIAPI
|
||||
CreateBasicVariablePolicy (
|
||||
IN CONST EFI_GUID *Namespace,
|
||||
IN CONST CHAR16 *Name OPTIONAL,
|
||||
IN UINT32 MinSize,
|
||||
IN UINT32 MaxSize,
|
||||
IN UINT32 AttributesMustHave,
|
||||
IN UINT32 AttributesCantHave,
|
||||
IN UINT8 LockPolicyType,
|
||||
OUT VARIABLE_POLICY_ENTRY **NewEntry
|
||||
);
|
||||
|
||||
/**
|
||||
This helper function will allocate and populate a new VariablePolicy
|
||||
structure for a policy with a lock type of VARIABLE_POLICY_TYPE_LOCK_ON_VAR_STATE.
|
||||
|
||||
NOTE: Caller will need to free structure once finished.
|
||||
|
||||
@param[in] Namespace Pointer to an EFI_GUID for the target variable namespace that this policy will protect.
|
||||
@param[in] Name [Optional] If provided, a pointer to the CHAR16 array for the target variable name.
|
||||
Otherwise, will create a policy that targets an entire namespace.
|
||||
@param[in] MinSize MinSize for the VariablePolicy.
|
||||
@param[in] MaxSize MaxSize for the VariablePolicy.
|
||||
@param[in] AttributesMustHave AttributesMustHave for the VariablePolicy.
|
||||
@param[in] AttributesCantHave AttributesCantHave for the VariablePolicy.
|
||||
@param[in] VarStateNamespace Pointer to the EFI_GUID for the VARIABLE_LOCK_ON_VAR_STATE_POLICY.Namespace.
|
||||
@param[in] VarStateValue Value for the VARIABLE_LOCK_ON_VAR_STATE_POLICY.Value.
|
||||
@param[in] VarStateName Pointer to the CHAR16 array for the VARIABLE_LOCK_ON_VAR_STATE_POLICY.Name.
|
||||
@param[out] NewEntry If successful, will be set to a pointer to the allocated buffer containing the
|
||||
new policy.
|
||||
|
||||
@retval EFI_SUCCESS Operation completed successfully and structure is populated.
|
||||
@retval EFI_INVALID_PARAMETER Namespace, VarStateNamespace, VarStateName is NULL.
|
||||
@retval EFI_BUFFER_TOO_SMALL Finished structure would not fit in UINT16 size.
|
||||
@retval EFI_OUT_OF_RESOURCES Could not allocate sufficient space for structure.
|
||||
|
||||
**/
|
||||
EFI_STATUS
|
||||
EFIAPI
|
||||
CreateVarStateVariablePolicy (
|
||||
IN CONST EFI_GUID *Namespace,
|
||||
IN CONST CHAR16 *Name OPTIONAL,
|
||||
IN UINT32 MinSize,
|
||||
IN UINT32 MaxSize,
|
||||
IN UINT32 AttributesMustHave,
|
||||
IN UINT32 AttributesCantHave,
|
||||
IN CONST EFI_GUID *VarStateNamespace,
|
||||
IN UINT8 VarStateValue,
|
||||
IN CONST CHAR16 *VarStateName,
|
||||
OUT VARIABLE_POLICY_ENTRY **NewEntry
|
||||
);
|
||||
|
||||
/**
|
||||
This helper function does everything that CreateBasicVariablePolicy() does, but also
|
||||
uses the passed in protocol to register the policy with the infrastructure.
|
||||
Does not return a buffer, does not require the caller to free anything.
|
||||
|
||||
@param[in] VariablePolicy Pointer to a valid instance of the VariablePolicy protocol.
|
||||
@param[in] Namespace Pointer to an EFI_GUID for the target variable namespace that this policy will protect.
|
||||
@param[in] Name [Optional] If provided, a pointer to the CHAR16 array for the target variable name.
|
||||
Otherwise, will create a policy that targets an entire namespace.
|
||||
@param[in] MinSize MinSize for the VariablePolicy.
|
||||
@param[in] MaxSize MaxSize for the VariablePolicy.
|
||||
@param[in] AttributesMustHave AttributesMustHave for the VariablePolicy.
|
||||
@param[in] AttributesCantHave AttributesCantHave for the VariablePolicy.
|
||||
@param[in] LockPolicyType LockPolicyType for the VariablePolicy.
|
||||
|
||||
@retval EFI_INVALID_PARAMETER VariablePolicy pointer is NULL.
|
||||
@retval EFI_STATUS Status returned by CreateBasicVariablePolicy() or RegisterVariablePolicy().
|
||||
|
||||
**/
|
||||
EFI_STATUS
|
||||
EFIAPI
|
||||
RegisterBasicVariablePolicy (
|
||||
IN EDKII_VARIABLE_POLICY_PROTOCOL *VariablePolicy,
|
||||
IN CONST EFI_GUID *Namespace,
|
||||
IN CONST CHAR16 *Name OPTIONAL,
|
||||
IN UINT32 MinSize,
|
||||
IN UINT32 MaxSize,
|
||||
IN UINT32 AttributesMustHave,
|
||||
IN UINT32 AttributesCantHave,
|
||||
IN UINT8 LockPolicyType
|
||||
);
|
||||
|
||||
/**
|
||||
This helper function does everything that CreateBasicVariablePolicy() does, but also
|
||||
uses the passed in protocol to register the policy with the infrastructure.
|
||||
Does not return a buffer, does not require the caller to free anything.
|
||||
|
||||
@param[in] VariablePolicy Pointer to a valid instance of the VariablePolicy protocol.
|
||||
@param[in] Namespace Pointer to an EFI_GUID for the target variable namespace that this policy will protect.
|
||||
@param[in] Name [Optional] If provided, a pointer to the CHAR16 array for the target variable name.
|
||||
Otherwise, will create a policy that targets an entire namespace.
|
||||
@param[in] MinSize MinSize for the VariablePolicy.
|
||||
@param[in] MaxSize MaxSize for the VariablePolicy.
|
||||
@param[in] AttributesMustHave AttributesMustHave for the VariablePolicy.
|
||||
@param[in] AttributesCantHave AttributesCantHave for the VariablePolicy.
|
||||
@param[in] VarStateNamespace Pointer to the EFI_GUID for the VARIABLE_LOCK_ON_VAR_STATE_POLICY.Namespace.
|
||||
@param[in] VarStateName Pointer to the CHAR16 array for the VARIABLE_LOCK_ON_VAR_STATE_POLICY.Name.
|
||||
@param[in] VarStateValue Value for the VARIABLE_LOCK_ON_VAR_STATE_POLICY.Value.
|
||||
|
||||
@retval EFI_INVALID_PARAMETER VariablePolicy pointer is NULL.
|
||||
@retval EFI_STATUS Status returned by CreateBasicVariablePolicy() or RegisterVariablePolicy().
|
||||
|
||||
**/
|
||||
EFI_STATUS
|
||||
EFIAPI
|
||||
RegisterVarStateVariablePolicy (
|
||||
IN EDKII_VARIABLE_POLICY_PROTOCOL *VariablePolicy,
|
||||
IN CONST EFI_GUID *Namespace,
|
||||
IN CONST CHAR16 *Name OPTIONAL,
|
||||
IN UINT32 MinSize,
|
||||
IN UINT32 MaxSize,
|
||||
IN UINT32 AttributesMustHave,
|
||||
IN UINT32 AttributesCantHave,
|
||||
IN CONST EFI_GUID *VarStateNamespace,
|
||||
IN CONST CHAR16 *VarStateName,
|
||||
IN UINT8 VarStateValue
|
||||
);
|
||||
|
||||
#endif // _EDKII_VARIABLE_POLICY_HELPER_LIB_H_
|
|
@ -0,0 +1,304 @@
|
|||
/** @file -- VariablePolicyLib.h
|
||||
Business logic for Variable Policy enforcement.
|
||||
|
||||
Copyright (c) Microsoft Corporation.
|
||||
SPDX-License-Identifier: BSD-2-Clause-Patent
|
||||
|
||||
**/
|
||||
|
||||
#ifndef _VARIABLE_POLICY_LIB_H_
|
||||
#define _VARIABLE_POLICY_LIB_H_
|
||||
|
||||
#include <Protocol/VariablePolicy.h>
|
||||
|
||||
/**
|
||||
This API function validates and registers a new policy with
|
||||
the policy enforcement engine.
|
||||
|
||||
@param[in] NewPolicy Pointer to the incoming policy structure.
|
||||
|
||||
@retval EFI_SUCCESS
|
||||
@retval EFI_INVALID_PARAMETER NewPolicy is NULL or is internally inconsistent.
|
||||
@retval EFI_ALREADY_STARTED An identical matching policy already exists.
|
||||
@retval EFI_WRITE_PROTECTED The interface has been locked until the next reboot.
|
||||
@retval EFI_UNSUPPORTED Policy enforcement has been disabled. No reason to add more policies.
|
||||
@retval EFI_ABORTED A calculation error has prevented this function from completing.
|
||||
@retval EFI_OUT_OF_RESOURCES Cannot grow the table to hold any more policies.
|
||||
@retval EFI_NOT_READY Library has not yet been initialized.
|
||||
|
||||
**/
|
||||
EFI_STATUS
|
||||
EFIAPI
|
||||
RegisterVariablePolicy (
|
||||
IN CONST VARIABLE_POLICY_ENTRY *NewPolicy
|
||||
);
|
||||
|
||||
/**
|
||||
This API function checks to see whether the parameters to SetVariable would
|
||||
be allowed according to the current variable policies.
|
||||
|
||||
@param[in] VariableName Same as EFI_SET_VARIABLE.
|
||||
@param[in] VendorGuid Same as EFI_SET_VARIABLE.
|
||||
@param[in] Attributes Same as EFI_SET_VARIABLE.
|
||||
@param[in] DataSize Same as EFI_SET_VARIABLE.
|
||||
@param[in] Data Same as EFI_SET_VARIABLE.
|
||||
|
||||
@retval EFI_SUCCESS A matching policy allows this update.
|
||||
@retval EFI_SUCCESS There are currently no policies that restrict this update.
|
||||
@retval EFI_SUCCESS The protections have been disable until the next reboot.
|
||||
@retval EFI_WRITE_PROTECTED Variable is currently locked.
|
||||
@retval EFI_INVALID_PARAMETER Attributes or size are invalid.
|
||||
@retval EFI_ABORTED A lock policy exists, but an error prevented evaluation.
|
||||
@retval EFI_NOT_READY Library has not been initialized.
|
||||
|
||||
**/
|
||||
EFI_STATUS
|
||||
EFIAPI
|
||||
ValidateSetVariable (
|
||||
IN CHAR16 *VariableName,
|
||||
IN EFI_GUID *VendorGuid,
|
||||
IN UINT32 Attributes,
|
||||
IN UINTN DataSize,
|
||||
IN VOID *Data
|
||||
);
|
||||
|
||||
/**
|
||||
This API function disables the variable policy enforcement. If it's
|
||||
already been called once, will return EFI_ALREADY_STARTED.
|
||||
|
||||
@retval EFI_SUCCESS
|
||||
@retval EFI_ALREADY_STARTED Has already been called once this boot.
|
||||
@retval EFI_WRITE_PROTECTED Interface has been locked until reboot.
|
||||
@retval EFI_WRITE_PROTECTED Interface option is disabled by platform PCD.
|
||||
@retval EFI_NOT_READY Library has not yet been initialized.
|
||||
|
||||
**/
|
||||
EFI_STATUS
|
||||
EFIAPI
|
||||
DisableVariablePolicy (
|
||||
VOID
|
||||
);
|
||||
|
||||
/**
|
||||
This API function will dump the entire contents of the variable policy table.
|
||||
|
||||
Similar to GetVariable, the first call can be made with a 0 size and it will return
|
||||
the size of the buffer required to hold the entire table.
|
||||
|
||||
@param[out] Policy Pointer to the policy buffer. Can be NULL if Size is 0.
|
||||
@param[in,out] Size On input, the size of the output buffer. On output, the size
|
||||
of the data returned.
|
||||
|
||||
@retval EFI_SUCCESS Policy data is in the output buffer and Size has been updated.
|
||||
@retval EFI_INVALID_PARAMETER Size is NULL, or Size is non-zero and Policy is NULL.
|
||||
@retval EFI_BUFFER_TOO_SMALL Size is insufficient to hold policy. Size updated with required size.
|
||||
@retval EFI_NOT_READY Library has not yet been initialized.
|
||||
|
||||
**/
|
||||
EFI_STATUS
|
||||
EFIAPI
|
||||
DumpVariablePolicy (
|
||||
OUT UINT8 *Policy,
|
||||
IN OUT UINT32 *Size
|
||||
);
|
||||
|
||||
/**
|
||||
This function will return variable policy information for a UEFI variable with a
|
||||
registered variable policy.
|
||||
|
||||
@param[in] VariableName The name of the variable to use for the policy search.
|
||||
@param[in] VendorGuid The vendor GUID of the variable to use for the policy search.
|
||||
@param[in,out] VariablePolicyVariableNameBufferSize On input, the size, in bytes, of the VariablePolicyVariableName
|
||||
buffer.
|
||||
|
||||
On output, the size, in bytes, needed to store the variable
|
||||
policy variable name.
|
||||
|
||||
If testing for the VariablePolicyVariableName buffer size
|
||||
needed, set this value to zero so EFI_BUFFER_TOO_SMALL is
|
||||
guaranteed to be returned if the variable policy variable name
|
||||
is found.
|
||||
@param[out] VariablePolicy Pointer to a buffer where the policy entry will be written
|
||||
if found.
|
||||
@param[out] VariablePolicyVariableName Pointer to a buffer where the variable name used for the
|
||||
variable policy will be written if a variable name is
|
||||
registered.
|
||||
|
||||
If the variable policy is not associated with a variable name
|
||||
(e.g. applied to variable vendor namespace) and this parameter
|
||||
is given, this parameter will not be modified and
|
||||
VariablePolicyVariableNameBufferSize will be set to zero to
|
||||
indicate a name was not present.
|
||||
|
||||
If the pointer given is not NULL,
|
||||
VariablePolicyVariableNameBufferSize must be non-NULL.
|
||||
|
||||
@retval EFI_SUCCESS A variable policy entry was found and returned successfully.
|
||||
@retval EFI_BAD_BUFFER_SIZE An internal buffer size caused a calculation error.
|
||||
@retval EFI_BUFFER_TOO_SMALL The VariablePolicyVariableName buffer value is too small for the size needed.
|
||||
The buffer should now point to the size needed.
|
||||
@retval EFI_NOT_READY Variable policy has not yet been initialized.
|
||||
@retval EFI_INVALID_PARAMETER A required pointer argument passed is NULL. This will be returned if
|
||||
VariablePolicyVariableName is non-NULL and VariablePolicyVariableNameBufferSize
|
||||
is NULL.
|
||||
@retval EFI_NOT_FOUND A variable policy was not found for the given UEFI variable name and vendor GUID.
|
||||
|
||||
**/
|
||||
EFI_STATUS
|
||||
EFIAPI
|
||||
GetVariablePolicyInfo (
|
||||
IN CONST CHAR16 *VariableName,
|
||||
IN CONST EFI_GUID *VendorGuid,
|
||||
IN OUT UINTN *VariablePolicyVariableNameBufferSize OPTIONAL,
|
||||
OUT VARIABLE_POLICY_ENTRY *VariablePolicy,
|
||||
OUT CHAR16 *VariablePolicyVariableName OPTIONAL
|
||||
);
|
||||
|
||||
/**
|
||||
This function will return the Lock on Variable State policy information for the policy
|
||||
associated with the given UEFI variable.
|
||||
|
||||
@param[in] VariableName The name of the variable to use for the policy search.
|
||||
@param[in] VendorGuid The vendor GUID of the variable to use for the policy
|
||||
search.
|
||||
@param[in,out] VariableLockPolicyVariableNameBufferSize On input, the size, in bytes, of the
|
||||
VariableLockPolicyVariableName buffer.
|
||||
|
||||
On output, the size, in bytes, needed to store the variable
|
||||
policy variable name.
|
||||
|
||||
If testing for the VariableLockPolicyVariableName buffer
|
||||
size needed, set this value to zero so EFI_BUFFER_TOO_SMALL
|
||||
is guaranteed to be returned if the variable policy variable
|
||||
name is found.
|
||||
@param[out] VariablePolicy Pointer to a buffer where the policy entry will be written
|
||||
if found.
|
||||
@param[out] VariableLockPolicyVariableName Pointer to a buffer where the variable name used for the
|
||||
variable lock on variable state policy will be written if
|
||||
a variable name is registered.
|
||||
|
||||
If the lock on variable policy is not associated with a
|
||||
variable name (e.g. applied to variable vendor namespace)
|
||||
and this parameter is given, this parameter will not be
|
||||
modified and VariableLockPolicyVariableNameBufferSize will
|
||||
be set to zero to indicate a name was not present.
|
||||
|
||||
If the pointer given is not NULL,
|
||||
VariableLockPolicyVariableNameBufferSize must be non-NULL.
|
||||
|
||||
@retval EFI_SUCCESS A Lock on Variable State variable policy entry was found and returned
|
||||
successfully.
|
||||
@retval EFI_BAD_BUFFER_SIZE An internal buffer size caused a calculation error.
|
||||
@retval EFI_BUFFER_TOO_SMALL The VariableLockPolicyVariableName buffer is too small for the size needed.
|
||||
The buffer should now point to the size needed.
|
||||
@retval EFI_NOT_READY Variable policy has not yet been initialized.
|
||||
@retval EFI_INVALID_PARAMETER A required pointer argument passed is NULL. This will be returned if
|
||||
VariableLockPolicyVariableName is non-NULL and
|
||||
VariableLockPolicyVariableNameBufferSize is NULL.
|
||||
@retval EFI_NOT_FOUND A Lock on Variable State variable policy was not found for the given UEFI
|
||||
variable name and vendor GUID.
|
||||
|
||||
**/
|
||||
EFI_STATUS
|
||||
EFIAPI
|
||||
GetLockOnVariableStateVariablePolicyInfo (
|
||||
IN CONST CHAR16 *VariableName,
|
||||
IN CONST EFI_GUID *VendorGuid,
|
||||
IN OUT UINTN *VariableLockPolicyVariableNameBufferSize OPTIONAL,
|
||||
OUT VARIABLE_LOCK_ON_VAR_STATE_POLICY *VariablePolicy,
|
||||
OUT CHAR16 *VariableLockPolicyVariableName OPTIONAL
|
||||
);
|
||||
|
||||
/**
|
||||
This API function returns whether or not the policy engine is
|
||||
currently being enforced.
|
||||
|
||||
@retval TRUE
|
||||
@retval FALSE
|
||||
@retval FALSE Library has not yet been initialized.
|
||||
|
||||
**/
|
||||
BOOLEAN
|
||||
EFIAPI
|
||||
IsVariablePolicyEnabled (
|
||||
VOID
|
||||
);
|
||||
|
||||
/**
|
||||
This API function locks the interface so that no more policy updates
|
||||
can be performed or changes made to the enforcement until the next boot.
|
||||
|
||||
@retval EFI_SUCCESS
|
||||
@retval EFI_NOT_READY Library has not yet been initialized.
|
||||
|
||||
**/
|
||||
EFI_STATUS
|
||||
EFIAPI
|
||||
LockVariablePolicy (
|
||||
VOID
|
||||
);
|
||||
|
||||
/**
|
||||
This API function returns whether or not the policy interface is locked
|
||||
for the remainder of the boot.
|
||||
|
||||
@retval TRUE
|
||||
@retval FALSE
|
||||
@retval FALSE Library has not yet been initialized.
|
||||
|
||||
**/
|
||||
BOOLEAN
|
||||
EFIAPI
|
||||
IsVariablePolicyInterfaceLocked (
|
||||
VOID
|
||||
);
|
||||
|
||||
/**
|
||||
This helper function initializes the library and sets
|
||||
up any required internal structures or handlers.
|
||||
|
||||
Also registers the internal pointer for the GetVariable helper.
|
||||
|
||||
@param[in] GetVariableHelper A function pointer matching the EFI_GET_VARIABLE prototype that will be used to
|
||||
check policy criteria that involve the existence of other variables.
|
||||
|
||||
@retval EFI_SUCCESS
|
||||
@retval EFI_ALREADY_STARTED The initialize function has been called more than once without a call to
|
||||
deinitialize.
|
||||
|
||||
**/
|
||||
EFI_STATUS
|
||||
EFIAPI
|
||||
InitVariablePolicyLib (
|
||||
IN EFI_GET_VARIABLE GetVariableHelper
|
||||
);
|
||||
|
||||
/**
|
||||
This helper function returns whether or not the library is currently initialized.
|
||||
|
||||
@retval TRUE
|
||||
@retval FALSE
|
||||
|
||||
**/
|
||||
BOOLEAN
|
||||
EFIAPI
|
||||
IsVariablePolicyLibInitialized (
|
||||
VOID
|
||||
);
|
||||
|
||||
/**
|
||||
This helper function tears down the library.
|
||||
|
||||
Should generally only be used for test harnesses.
|
||||
|
||||
@retval EFI_SUCCESS
|
||||
@retval EFI_NOT_READY Deinitialize was called without first calling initialize.
|
||||
|
||||
**/
|
||||
EFI_STATUS
|
||||
EFIAPI
|
||||
DeinitVariablePolicyLib (
|
||||
VOID
|
||||
);
|
||||
|
||||
#endif // _VARIABLE_POLICY_LIB_H_
|
|
@ -0,0 +1,276 @@
|
|||
/** @file -- VariablePolicy.h
|
||||
|
||||
This protocol allows communication with Variable Policy Engine.
|
||||
|
||||
Copyright (c) Microsoft Corporation.
|
||||
SPDX-License-Identifier: BSD-2-Clause-Patent
|
||||
**/
|
||||
|
||||
#ifndef __EDKII_VARIABLE_POLICY_PROTOCOL__
|
||||
#define __EDKII_VARIABLE_POLICY_PROTOCOL__
|
||||
|
||||
#define EDKII_VARIABLE_POLICY_PROTOCOL_REVISION 0x0000000000020000
|
||||
|
||||
/*
|
||||
Rev 0x0000000000010000:
|
||||
- Initial protocol definition
|
||||
|
||||
Rev 0x0000000000020000:
|
||||
- Add GetVariablePolicyInfo() API
|
||||
- Add GetLockOnVariableStateVariablePolicyInfo() API
|
||||
|
||||
*/
|
||||
|
||||
#define EDKII_VARIABLE_POLICY_PROTOCOL_GUID \
|
||||
{ \
|
||||
0x81D1675C, 0x86F6, 0x48DF, { 0xBD, 0x95, 0x9A, 0x6E, 0x4F, 0x09, 0x25, 0xC3 } \
|
||||
}
|
||||
|
||||
#define VARIABLE_POLICY_ENTRY_REVISION 0x00010000
|
||||
|
||||
#pragma pack(push, 1)
|
||||
typedef struct {
|
||||
UINT32 Version;
|
||||
UINT16 Size;
|
||||
UINT16 OffsetToName;
|
||||
EFI_GUID Namespace;
|
||||
UINT32 MinSize;
|
||||
UINT32 MaxSize;
|
||||
UINT32 AttributesMustHave;
|
||||
UINT32 AttributesCantHave;
|
||||
UINT8 LockPolicyType;
|
||||
UINT8 Padding[3];
|
||||
// UINT8 LockPolicy[]; // Variable Length Field
|
||||
// CHAR16 Name[] // Variable Length Field
|
||||
} VARIABLE_POLICY_ENTRY;
|
||||
|
||||
#define VARIABLE_POLICY_NO_MIN_SIZE 0
|
||||
#define VARIABLE_POLICY_NO_MAX_SIZE MAX_UINT32
|
||||
#define VARIABLE_POLICY_NO_MUST_ATTR 0
|
||||
#define VARIABLE_POLICY_NO_CANT_ATTR 0
|
||||
|
||||
#define VARIABLE_POLICY_TYPE_NO_LOCK 0
|
||||
#define VARIABLE_POLICY_TYPE_LOCK_NOW 1
|
||||
#define VARIABLE_POLICY_TYPE_LOCK_ON_CREATE 2
|
||||
#define VARIABLE_POLICY_TYPE_LOCK_ON_VAR_STATE 3
|
||||
|
||||
typedef struct {
|
||||
EFI_GUID Namespace;
|
||||
UINT8 Value;
|
||||
UINT8 Padding;
|
||||
// CHAR16 Name[]; // Variable Length Field
|
||||
} VARIABLE_LOCK_ON_VAR_STATE_POLICY;
|
||||
#pragma pack(pop)
|
||||
|
||||
/**
|
||||
This API function disables the variable policy enforcement. If it's
|
||||
already been called once, will return EFI_ALREADY_STARTED.
|
||||
|
||||
@retval EFI_SUCCESS
|
||||
@retval EFI_ALREADY_STARTED Has already been called once this boot.
|
||||
@retval EFI_WRITE_PROTECTED Interface has been locked until reboot.
|
||||
@retval EFI_WRITE_PROTECTED Interface option is disabled by platform PCD.
|
||||
|
||||
**/
|
||||
typedef
|
||||
EFI_STATUS
|
||||
(EFIAPI *DISABLE_VARIABLE_POLICY)(
|
||||
VOID
|
||||
);
|
||||
|
||||
/**
|
||||
This API function returns whether or not the policy engine is
|
||||
currently being enforced.
|
||||
|
||||
@param[out] State Pointer to a return value for whether the policy enforcement
|
||||
is currently enabled.
|
||||
|
||||
@retval EFI_SUCCESS
|
||||
@retval Others An error has prevented this command from completing.
|
||||
|
||||
**/
|
||||
typedef
|
||||
EFI_STATUS
|
||||
(EFIAPI *IS_VARIABLE_POLICY_ENABLED)(
|
||||
OUT BOOLEAN *State
|
||||
);
|
||||
|
||||
/**
|
||||
This API function validates and registers a new policy with
|
||||
the policy enforcement engine.
|
||||
|
||||
@param[in] NewPolicy Pointer to the incoming policy structure.
|
||||
|
||||
@retval EFI_SUCCESS
|
||||
@retval EFI_INVALID_PARAMETER NewPolicy is NULL or is internally inconsistent.
|
||||
@retval EFI_ALREADY_STARTED An identical matching policy already exists.
|
||||
@retval EFI_WRITE_PROTECTED The interface has been locked until the next reboot.
|
||||
@retval EFI_ABORTED A calculation error has prevented this function from completing.
|
||||
@retval EFI_OUT_OF_RESOURCES Cannot grow the table to hold any more policies.
|
||||
|
||||
**/
|
||||
typedef
|
||||
EFI_STATUS
|
||||
(EFIAPI *REGISTER_VARIABLE_POLICY)(
|
||||
IN CONST VARIABLE_POLICY_ENTRY *PolicyEntry
|
||||
);
|
||||
|
||||
/**
|
||||
This API function will dump the entire contents of the variable policy table.
|
||||
|
||||
Similar to GetVariable, the first call can be made with a 0 size and it will return
|
||||
the size of the buffer required to hold the entire table.
|
||||
|
||||
@param[out] Policy Pointer to the policy buffer. Can be NULL if Size is 0.
|
||||
@param[in,out] Size On input, the size of the output buffer. On output, the size
|
||||
of the data returned.
|
||||
|
||||
@retval EFI_SUCCESS Policy data is in the output buffer and Size has been updated.
|
||||
@retval EFI_INVALID_PARAMETER Size is NULL, or Size is non-zero and Policy is NULL.
|
||||
@retval EFI_BUFFER_TOO_SMALL Size is insufficient to hold policy. Size updated with required size.
|
||||
|
||||
**/
|
||||
typedef
|
||||
EFI_STATUS
|
||||
(EFIAPI *DUMP_VARIABLE_POLICY)(
|
||||
IN OUT UINT8 *Policy,
|
||||
IN OUT UINT32 *Size
|
||||
);
|
||||
|
||||
/**
|
||||
This API function locks the interface so that no more policy updates
|
||||
can be performed or changes made to the enforcement until the next boot.
|
||||
|
||||
@retval EFI_SUCCESS
|
||||
@retval Others An error has prevented this command from completing.
|
||||
|
||||
**/
|
||||
typedef
|
||||
EFI_STATUS
|
||||
(EFIAPI *LOCK_VARIABLE_POLICY)(
|
||||
VOID
|
||||
);
|
||||
|
||||
/**
|
||||
This function will return variable policy information for a UEFI variable with a
|
||||
registered variable policy.
|
||||
|
||||
@param[in] VariableName The name of the variable to use for the policy search.
|
||||
@param[in] VendorGuid The vendor GUID of the variable to use for the policy search.
|
||||
@param[in,out] VariablePolicyVariableNameBufferSize On input, the size, in bytes, of the VariablePolicyVariableName
|
||||
buffer.
|
||||
|
||||
On output, the size, in bytes, needed to store the variable
|
||||
policy variable name.
|
||||
|
||||
If testing for the VariablePolicyVariableName buffer size
|
||||
needed, set this value to zero so EFI_BUFFER_TOO_SMALL is
|
||||
guaranteed to be returned if the variable policy variable name
|
||||
is found.
|
||||
@param[out] VariablePolicy Pointer to a buffer where the policy entry will be written
|
||||
if found.
|
||||
@param[out] VariablePolicyVariableName Pointer to a buffer where the variable name used for the
|
||||
variable policy will be written if a variable name is
|
||||
registered.
|
||||
|
||||
If the variable policy is not associated with a variable name
|
||||
(e.g. applied to variable vendor namespace) and this parameter
|
||||
is given, this parameter will not be modified and
|
||||
VariablePolicyVariableNameBufferSize will be set to zero to
|
||||
indicate a name was not present.
|
||||
|
||||
If the pointer given is not NULL,
|
||||
VariablePolicyVariableNameBufferSize must be non-NULL.
|
||||
|
||||
@retval EFI_SUCCESS A variable policy entry was found and returned successfully.
|
||||
@retval EFI_BAD_BUFFER_SIZE An internal buffer size caused a calculation error.
|
||||
@retval EFI_BUFFER_TOO_SMALL The VariablePolicyVariableName buffer value is too small for the size needed.
|
||||
The buffer should now point to the size needed.
|
||||
@retval EFI_NOT_READY Variable policy has not yet been initialized.
|
||||
@retval EFI_INVALID_PARAMETER A required pointer argument passed is NULL. This will be returned if
|
||||
VariablePolicyVariableName is non-NULL and VariablePolicyVariableNameBufferSize
|
||||
is NULL.
|
||||
@retval EFI_NOT_FOUND A variable policy was not found for the given UEFI variable name and vendor GUID.
|
||||
|
||||
**/
|
||||
typedef
|
||||
EFI_STATUS
|
||||
(EFIAPI *GET_VARIABLE_POLICY_INFO)(
|
||||
IN CONST CHAR16 *VariableName,
|
||||
IN CONST EFI_GUID *VendorGuid,
|
||||
IN OUT UINTN *VariablePolicyVariableNameBufferSize OPTIONAL,
|
||||
OUT VARIABLE_POLICY_ENTRY *VariablePolicy,
|
||||
OUT CHAR16 *VariablePolicyVariableName OPTIONAL
|
||||
);
|
||||
|
||||
/**
|
||||
This function will return the Lock on Variable State policy information for the policy
|
||||
associated with the given UEFI variable.
|
||||
|
||||
@param[in] VariableName The name of the variable to use for the policy search.
|
||||
@param[in] VendorGuid The vendor GUID of the variable to use for the policy
|
||||
search.
|
||||
@param[in,out] VariableLockPolicyVariableNameBufferSize On input, the size, in bytes, of the
|
||||
VariableLockPolicyVariableName buffer.
|
||||
|
||||
On output, the size, in bytes, needed to store the variable
|
||||
policy variable name.
|
||||
|
||||
If testing for the VariableLockPolicyVariableName buffer
|
||||
size needed, set this value to zero so EFI_BUFFER_TOO_SMALL
|
||||
is guaranteed to be returned if the variable policy variable
|
||||
name is found.
|
||||
@param[out] VariablePolicy Pointer to a buffer where the policy entry will be written
|
||||
if found.
|
||||
@param[out] VariableLockPolicyVariableName Pointer to a buffer where the variable name used for the
|
||||
variable lock on variable state policy will be written if
|
||||
a variable name is registered.
|
||||
|
||||
If the lock on variable policy is not associated with a
|
||||
variable name (e.g. applied to variable vendor namespace)
|
||||
and this parameter is given, this parameter will not be
|
||||
modified and VariableLockPolicyVariableNameBufferSize will
|
||||
be set to zero to indicate a name was not present.
|
||||
|
||||
If the pointer given is not NULL,
|
||||
VariableLockPolicyVariableNameBufferSize must be non-NULL.
|
||||
|
||||
@retval EFI_SUCCESS A Lock on Variable State variable policy entry was found and returned
|
||||
successfully.
|
||||
@retval EFI_BAD_BUFFER_SIZE An internal buffer size caused a calculation error.
|
||||
@retval EFI_BUFFER_TOO_SMALL The VariableLockPolicyVariableName buffer is too small for the size needed.
|
||||
The buffer should now point to the size needed.
|
||||
@retval EFI_NOT_READY Variable policy has not yet been initialized.
|
||||
@retval EFI_INVALID_PARAMETER A required pointer argument passed is NULL. This will be returned if
|
||||
VariableLockPolicyVariableName is non-NULL and
|
||||
VariableLockPolicyVariableNameBufferSize is NULL.
|
||||
@retval EFI_NOT_FOUND A Lock on Variable State variable policy was not found for the given UEFI
|
||||
variable name and vendor GUID.
|
||||
|
||||
**/
|
||||
typedef
|
||||
EFI_STATUS
|
||||
(EFIAPI *GET_LOCK_ON_VARIABLE_STATE_VARIABLE_POLICY_INFO)(
|
||||
IN CONST CHAR16 *VariableName,
|
||||
IN CONST EFI_GUID *VendorGuid,
|
||||
IN OUT UINTN *VariableLockPolicyVariableNameBufferSize OPTIONAL,
|
||||
OUT VARIABLE_LOCK_ON_VAR_STATE_POLICY *VariablePolicy,
|
||||
OUT CHAR16 *VariableLockPolicyVariableName OPTIONAL
|
||||
);
|
||||
|
||||
typedef struct {
|
||||
UINT64 Revision;
|
||||
DISABLE_VARIABLE_POLICY DisableVariablePolicy;
|
||||
IS_VARIABLE_POLICY_ENABLED IsVariablePolicyEnabled;
|
||||
REGISTER_VARIABLE_POLICY RegisterVariablePolicy;
|
||||
DUMP_VARIABLE_POLICY DumpVariablePolicy;
|
||||
LOCK_VARIABLE_POLICY LockVariablePolicy;
|
||||
GET_VARIABLE_POLICY_INFO GetVariablePolicyInfo;
|
||||
GET_LOCK_ON_VARIABLE_STATE_VARIABLE_POLICY_INFO GetLockOnVariableStateVariablePolicyInfo;
|
||||
} _EDKII_VARIABLE_POLICY_PROTOCOL;
|
||||
|
||||
typedef _EDKII_VARIABLE_POLICY_PROTOCOL EDKII_VARIABLE_POLICY_PROTOCOL;
|
||||
|
||||
extern EFI_GUID gEdkiiVariablePolicyProtocolGuid;
|
||||
|
||||
#endif
|
|
@ -31,3 +31,4 @@
|
|||
|
||||
[LibraryClasses]
|
||||
DebugLib
|
||||
CommonMemoryAllocationLib
|
||||
|
|
|
@ -1,13 +1,12 @@
|
|||
/** @file
|
||||
Null routines for memory profile for DxeCore.
|
||||
Null routines for memory profile.
|
||||
|
||||
Copyright (c) 2016 - 2018, Intel Corporation. All rights reserved.<BR>
|
||||
SPDX-License-Identifier: BSD-2-Clause-Patent
|
||||
|
||||
**/
|
||||
|
||||
|
||||
#include <PiDxe.h>
|
||||
#include <Uefi.h>
|
||||
|
||||
#include <Guid/MemoryProfile.h>
|
||||
|
||||
|
@ -36,14 +35,13 @@
|
|||
EFI_STATUS
|
||||
EFIAPI
|
||||
MemoryProfileLibRecord (
|
||||
IN PHYSICAL_ADDRESS CallerAddress,
|
||||
IN MEMORY_PROFILE_ACTION Action,
|
||||
IN EFI_MEMORY_TYPE MemoryType,
|
||||
IN VOID *Buffer,
|
||||
IN UINTN Size,
|
||||
IN CHAR8 *ActionString OPTIONAL
|
||||
IN PHYSICAL_ADDRESS CallerAddress,
|
||||
IN MEMORY_PROFILE_ACTION Action,
|
||||
IN EFI_MEMORY_TYPE MemoryType,
|
||||
IN VOID *Buffer,
|
||||
IN UINTN Size,
|
||||
IN CHAR8 *ActionString OPTIONAL
|
||||
)
|
||||
{
|
||||
return EFI_UNSUPPORTED;
|
||||
}
|
||||
|
|
@ -0,0 +1,32 @@
|
|||
## @file
|
||||
# Memory Profile Library Null instance.
|
||||
#
|
||||
# Copyright (c) 2008 - 2018, Intel Corporation. All rights reserved.<BR>
|
||||
#
|
||||
# SPDX-License-Identifier: BSD-2-Clause-Patent
|
||||
#
|
||||
#
|
||||
##
|
||||
|
||||
[Defines]
|
||||
INF_VERSION = 0x00010005
|
||||
BASE_NAME = BaseMemoryProfileLibNull
|
||||
MODULE_UNI_FILE = BaseMemoryProfileLibNull.uni
|
||||
FILE_GUID = 888809d7-e5c5-4848-b8b9-f920a7b89ce1
|
||||
MODULE_TYPE = BASE
|
||||
VERSION_STRING = 1.0
|
||||
LIBRARY_CLASS = MemoryProfileLib
|
||||
|
||||
#
|
||||
# The following information is for reference only and not required by the build tools.
|
||||
#
|
||||
# VALID_ARCHITECTURES = IA32 X64 EBC
|
||||
#
|
||||
|
||||
[Sources]
|
||||
BaseMemoryProfileLibNull.c
|
||||
|
||||
[Packages]
|
||||
MdePkg/MdePkg.dec
|
||||
MdeModulePkg/MdeModulePkg.dec
|
||||
|
|
@ -0,0 +1,14 @@
|
|||
// /** @file
|
||||
// Memory Profile Library Null instance.
|
||||
//
|
||||
// Copyright (c) 2008 - 2016, Intel Corporation. All rights reserved.<BR>
|
||||
//
|
||||
// SPDX-License-Identifier: BSD-2-Clause-Patent
|
||||
//
|
||||
// **/
|
||||
|
||||
|
||||
#string STR_MODULE_ABSTRACT #language en-US "Memory Profile Library Null instance"
|
||||
|
||||
#string STR_MODULE_DESCRIPTION #language en-US "Memory Profile Library Null instance."
|
||||
|
|
@ -0,0 +1,179 @@
|
|||
/** @file
|
||||
Variable Flash Information Library
|
||||
|
||||
Copyright (c) Microsoft Corporation<BR>
|
||||
|
||||
SPDX-License-Identifier: BSD-2-Clause-Patent
|
||||
|
||||
**/
|
||||
|
||||
#include <Uefi.h>
|
||||
#include <Pi/PiMultiPhase.h>
|
||||
#include <Guid/VariableFlashInfo.h>
|
||||
#include <Library/DebugLib.h>
|
||||
#include <Library/HobLib.h>
|
||||
#include <Library/VariableFlashInfoLib.h>
|
||||
|
||||
/**
|
||||
Get the HOB that contains variable flash information.
|
||||
|
||||
@param[out] VariableFlashInfo Pointer to a pointer to set to the variable flash information structure.
|
||||
|
||||
@retval EFI_SUCCESS Variable flash information was found successfully.
|
||||
@retval EFI_INVALID_PARAMETER The VariableFlashInfo pointer given is NULL.
|
||||
@retval EFI_NOT_FOUND Variable flash information could not be found.
|
||||
|
||||
**/
|
||||
STATIC
|
||||
EFI_STATUS
|
||||
GetVariableFlashInfoFromHob (
|
||||
OUT VARIABLE_FLASH_INFO **VariableFlashInfo
|
||||
)
|
||||
{
|
||||
EFI_HOB_GUID_TYPE *GuidHob;
|
||||
|
||||
if (VariableFlashInfo == NULL) {
|
||||
return EFI_INVALID_PARAMETER;
|
||||
}
|
||||
|
||||
GuidHob = GetFirstGuidHob (&gVariableFlashInfoHobGuid);
|
||||
if (GuidHob == NULL) {
|
||||
return EFI_NOT_FOUND;
|
||||
}
|
||||
|
||||
*VariableFlashInfo = GET_GUID_HOB_DATA (GuidHob);
|
||||
|
||||
//
|
||||
// Assert if more than one variable flash information HOB is present.
|
||||
//
|
||||
DEBUG_CODE (
|
||||
if ((GetNextGuidHob (&gVariableFlashInfoHobGuid, GET_NEXT_HOB (GuidHob)) != NULL)) {
|
||||
DEBUG ((DEBUG_ERROR, "ERROR: Found two variable flash information HOBs\n"));
|
||||
ASSERT (FALSE);
|
||||
}
|
||||
|
||||
);
|
||||
|
||||
return EFI_SUCCESS;
|
||||
}
|
||||
|
||||
/**
|
||||
Get the base address and size for the NV storage area used for UEFI variable storage.
|
||||
|
||||
@param[out] BaseAddress The NV storage base address.
|
||||
@param[out] Length The NV storage length in bytes.
|
||||
|
||||
@retval EFI_SUCCESS NV storage information was found successfully.
|
||||
@retval EFI_INVALID_PARAMETER A required pointer parameter is NULL.
|
||||
|
||||
**/
|
||||
EFI_STATUS
|
||||
EFIAPI
|
||||
GetVariableFlashNvStorageInfo (
|
||||
OUT EFI_PHYSICAL_ADDRESS *BaseAddress,
|
||||
OUT UINT64 *Length
|
||||
)
|
||||
{
|
||||
EFI_STATUS Status;
|
||||
VARIABLE_FLASH_INFO *VariableFlashInfo;
|
||||
|
||||
if ((BaseAddress == NULL) || (Length == NULL)) {
|
||||
return EFI_INVALID_PARAMETER;
|
||||
}
|
||||
|
||||
Status = GetVariableFlashInfoFromHob (&VariableFlashInfo);
|
||||
if (!EFI_ERROR (Status)) {
|
||||
*BaseAddress = VariableFlashInfo->NvVariableBaseAddress;
|
||||
*Length = VariableFlashInfo->NvVariableLength;
|
||||
} else {
|
||||
*BaseAddress = (EFI_PHYSICAL_ADDRESS)(PcdGet64 (PcdFlashNvStorageVariableBase64) != 0 ?
|
||||
PcdGet64 (PcdFlashNvStorageVariableBase64) :
|
||||
PcdGet32 (PcdFlashNvStorageVariableBase)
|
||||
);
|
||||
*Length = (UINT64)PcdGet32 (PcdFlashNvStorageVariableSize);
|
||||
}
|
||||
|
||||
return EFI_SUCCESS;
|
||||
}
|
||||
|
||||
/**
|
||||
Get the base address and size for the fault tolerant write (FTW) spare
|
||||
area used for UEFI variable storage.
|
||||
|
||||
@param[out] BaseAddress The FTW spare base address.
|
||||
@param[out] Length The FTW spare length in bytes.
|
||||
|
||||
@retval EFI_SUCCESS FTW spare information was found successfully.
|
||||
@retval EFI_INVALID_PARAMETER A required pointer parameter is NULL.
|
||||
@retval EFI_NOT_FOUND FTW spare information could not be found.
|
||||
|
||||
**/
|
||||
EFI_STATUS
|
||||
EFIAPI
|
||||
GetVariableFlashFtwSpareInfo (
|
||||
OUT EFI_PHYSICAL_ADDRESS *BaseAddress,
|
||||
OUT UINT64 *Length
|
||||
)
|
||||
{
|
||||
EFI_STATUS Status;
|
||||
VARIABLE_FLASH_INFO *VariableFlashInfo;
|
||||
|
||||
if ((BaseAddress == NULL) || (Length == NULL)) {
|
||||
return EFI_INVALID_PARAMETER;
|
||||
}
|
||||
|
||||
Status = GetVariableFlashInfoFromHob (&VariableFlashInfo);
|
||||
if (!EFI_ERROR (Status)) {
|
||||
*BaseAddress = VariableFlashInfo->FtwSpareBaseAddress;
|
||||
*Length = VariableFlashInfo->FtwSpareLength;
|
||||
} else {
|
||||
*BaseAddress = (EFI_PHYSICAL_ADDRESS)(PcdGet64 (PcdFlashNvStorageFtwSpareBase64) != 0 ?
|
||||
PcdGet64 (PcdFlashNvStorageFtwSpareBase64) :
|
||||
PcdGet32 (PcdFlashNvStorageFtwSpareBase)
|
||||
);
|
||||
*Length = (UINT64)PcdGet32 (PcdFlashNvStorageFtwSpareSize);
|
||||
}
|
||||
|
||||
return EFI_SUCCESS;
|
||||
}
|
||||
|
||||
/**
|
||||
Get the base address and size for the fault tolerant write (FTW) working
|
||||
area used for UEFI variable storage.
|
||||
|
||||
@param[out] BaseAddress The FTW working area base address.
|
||||
@param[out] Length The FTW working area length in bytes.
|
||||
|
||||
@retval EFI_SUCCESS FTW working information was found successfully.
|
||||
@retval EFI_INVALID_PARAMETER A required pointer parameter is NULL.
|
||||
@retval EFI_NOT_FOUND FTW working information could not be found.
|
||||
|
||||
**/
|
||||
EFI_STATUS
|
||||
EFIAPI
|
||||
GetVariableFlashFtwWorkingInfo (
|
||||
OUT EFI_PHYSICAL_ADDRESS *BaseAddress,
|
||||
OUT UINT64 *Length
|
||||
)
|
||||
{
|
||||
EFI_STATUS Status;
|
||||
VARIABLE_FLASH_INFO *VariableFlashInfo;
|
||||
|
||||
if ((BaseAddress == NULL) || (Length == NULL)) {
|
||||
return EFI_INVALID_PARAMETER;
|
||||
}
|
||||
|
||||
Status = GetVariableFlashInfoFromHob (&VariableFlashInfo);
|
||||
if (!EFI_ERROR (Status)) {
|
||||
*BaseAddress = VariableFlashInfo->FtwWorkingBaseAddress;
|
||||
*Length = VariableFlashInfo->FtwWorkingLength;
|
||||
} else {
|
||||
*BaseAddress = (EFI_PHYSICAL_ADDRESS)(PcdGet64 (PcdFlashNvStorageFtwWorkingBase64) != 0 ?
|
||||
PcdGet64 (PcdFlashNvStorageFtwWorkingBase64) :
|
||||
PcdGet32 (PcdFlashNvStorageFtwWorkingBase)
|
||||
);
|
||||
*Length = (UINT64)PcdGet32 (PcdFlashNvStorageFtwWorkingSize);
|
||||
}
|
||||
|
||||
return EFI_SUCCESS;
|
||||
}
|
|
@ -0,0 +1,48 @@
|
|||
## @file
|
||||
# Variable Flash Information Library
|
||||
#
|
||||
# Provides services to access UEFI variable flash information.
|
||||
#
|
||||
# Copyright (c) Microsoft Corporation<BR>
|
||||
# SPDX-License-Identifier: BSD-2-Clause-Patent
|
||||
##
|
||||
|
||||
[Defines]
|
||||
INF_VERSION = 0x00010005
|
||||
BASE_NAME = BaseVariableFlashInfoLib
|
||||
MODULE_UNI_FILE = BaseVariableFlashInfoLib.uni
|
||||
FILE_GUID = DEC426C9-C92E-4BAD-8E93-3F61C261118B
|
||||
MODULE_TYPE = BASE
|
||||
VERSION_STRING = 1.0
|
||||
LIBRARY_CLASS = VariableFlashInfoLib
|
||||
|
||||
#
|
||||
# The following information is for reference only and not required by the build tools.
|
||||
#
|
||||
# VALID_ARCHITECTURES = ANY
|
||||
#
|
||||
|
||||
[Sources]
|
||||
BaseVariableFlashInfoLib.c
|
||||
|
||||
[Packages]
|
||||
MdePkg/MdePkg.dec
|
||||
MdeModulePkg/MdeModulePkg.dec
|
||||
|
||||
[LibraryClasses]
|
||||
DebugLib
|
||||
HobLib
|
||||
|
||||
[Guids]
|
||||
gVariableFlashInfoHobGuid ## CONSUMES ## HOB
|
||||
|
||||
[Pcd]
|
||||
gEfiMdeModulePkgTokenSpaceGuid.PcdFlashNvStorageVariableBase ## SOMETIMES_CONSUMES
|
||||
gEfiMdeModulePkgTokenSpaceGuid.PcdFlashNvStorageVariableBase64 ## SOMETIMES_CONSUMES
|
||||
gEfiMdeModulePkgTokenSpaceGuid.PcdFlashNvStorageVariableSize ## SOMETIMES_CONSUMES
|
||||
gEfiMdeModulePkgTokenSpaceGuid.PcdFlashNvStorageFtwSpareBase ## SOMETIMES_CONSUMES
|
||||
gEfiMdeModulePkgTokenSpaceGuid.PcdFlashNvStorageFtwSpareBase64 ## SOMETIMES_CONSUMES
|
||||
gEfiMdeModulePkgTokenSpaceGuid.PcdFlashNvStorageFtwSpareSize ## SOMETIMES_CONSUMES
|
||||
gEfiMdeModulePkgTokenSpaceGuid.PcdFlashNvStorageFtwWorkingBase ## SOMETIMES_CONSUMES
|
||||
gEfiMdeModulePkgTokenSpaceGuid.PcdFlashNvStorageFtwWorkingBase64 ## SOMETIMES_CONSUMES
|
||||
gEfiMdeModulePkgTokenSpaceGuid.PcdFlashNvStorageFtwWorkingSize ## SOMETIMES_CONSUMES
|
|
@ -0,0 +1,12 @@
|
|||
// /** @file
|
||||
// Variable Flash Information Library
|
||||
//
|
||||
// Copyright (c) Microsoft Corporation<BR>
|
||||
//
|
||||
// SPDX-License-Identifier: BSD-2-Clause-Patent
|
||||
//
|
||||
// **/
|
||||
|
||||
#string STR_MODULE_ABSTRACT #language en-US "UEFI variable flash information library"
|
||||
|
||||
#string STR_MODULE_DESCRIPTION #language en-US "Provides services to access UEFI variable flash information."
|
|
@ -0,0 +1,84 @@
|
|||
/** @file
|
||||
Common code for the Memory Allocation Library aligned page allocation code.
|
||||
|
||||
Copyright (c) 2006 - 2018, Intel Corporation. All rights reserved.<BR>
|
||||
SPDX-License-Identifier: BSD-2-Clause-Patent
|
||||
|
||||
**/
|
||||
|
||||
#include <Base.h>
|
||||
#include <Uefi/UefiBaseType.h>
|
||||
#include <Uefi/UefiSpec.h>
|
||||
|
||||
#include <Library/MemoryAllocationLib.h>
|
||||
#include <Library/MemoryAllocationLibEx.h>
|
||||
|
||||
#include "AlignedPages.h"
|
||||
|
||||
/**
|
||||
Allocates one or more 4KB pages of a certain memory type at a specified alignment.
|
||||
|
||||
Allocates the number of 4KB pages specified by Pages of a certain memory type with an alignment
|
||||
specified by Alignment. The allocated buffer is returned. If Pages is 0, then NULL is returned.
|
||||
If there is not enough memory at the specified alignment remaining to satisfy the request, then
|
||||
NULL is returned.
|
||||
If Alignment is not a power of two and Alignment is not zero, then ASSERT().
|
||||
If Pages plus EFI_SIZE_TO_PAGES (Alignment) overflows, then ASSERT().
|
||||
|
||||
@param MemoryType The type of memory to allocate.
|
||||
@param Pages The number of 4 KB pages to allocate.
|
||||
@param Alignment The requested alignment of the allocation. Must be a power of two.
|
||||
If Alignment is zero, then byte alignment is used.
|
||||
|
||||
@return A pointer to the allocated buffer or NULL if allocation fails.
|
||||
|
||||
**/
|
||||
VOID *
|
||||
InternalAllocateAlignedPages (
|
||||
IN EFI_MEMORY_TYPE MemoryType,
|
||||
IN UINTN Pages,
|
||||
IN UINTN Alignment
|
||||
)
|
||||
{
|
||||
EFI_STATUS Status;
|
||||
EFI_PHYSICAL_ADDRESS Memory;
|
||||
|
||||
Status = AllocateAlignedPagesEx (
|
||||
AllocateAnyPages,
|
||||
MemoryType,
|
||||
Pages,
|
||||
Alignment,
|
||||
&Memory
|
||||
);
|
||||
if (EFI_ERROR (Status)) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return (VOID *)(UINTN)Memory;
|
||||
}
|
||||
|
||||
/**
|
||||
Frees one or more 4KB pages that were previously allocated with one of the aligned page
|
||||
allocation functions in the Memory Allocation Library.
|
||||
|
||||
Frees the number of 4KB pages specified by Pages from the buffer specified by Buffer. Buffer
|
||||
must have been allocated on a previous call to the aligned page allocation services of the Memory
|
||||
Allocation Library. If it is not possible to free allocated pages, then this function will
|
||||
perform no actions.
|
||||
|
||||
If Buffer was not allocated with an aligned page allocation function in the Memory Allocation
|
||||
Library, then ASSERT().
|
||||
If Pages is zero, then ASSERT().
|
||||
|
||||
@param Buffer Pointer to the buffer of pages to free.
|
||||
@param Pages The number of 4 KB pages to free.
|
||||
|
||||
**/
|
||||
VOID
|
||||
InternalFreeAlignedPages (
|
||||
IN VOID *Buffer,
|
||||
IN UINTN Pages
|
||||
)
|
||||
{
|
||||
FreePages (Buffer, Pages);
|
||||
}
|
|
@ -0,0 +1,60 @@
|
|||
/** @file
|
||||
Common code for the Memory Allocation Library aligned page allocation code.
|
||||
|
||||
Copyright (c) 2006 - 2018, Intel Corporation. All rights reserved.<BR>
|
||||
SPDX-License-Identifier: BSD-2-Clause-Patent
|
||||
|
||||
**/
|
||||
|
||||
#ifndef ALIGNED_PAGES_H_
|
||||
#define ALIGNED_PAGES_H_
|
||||
|
||||
/**
|
||||
Allocates one or more 4KB pages of a certain memory type at a specified alignment.
|
||||
|
||||
Allocates the number of 4KB pages specified by Pages of a certain memory type with an alignment
|
||||
specified by Alignment. The allocated buffer is returned. If Pages is 0, then NULL is returned.
|
||||
If there is not enough memory at the specified alignment remaining to satisfy the request, then
|
||||
NULL is returned.
|
||||
If Alignment is not a power of two and Alignment is not zero, then ASSERT().
|
||||
If Pages plus EFI_SIZE_TO_PAGES (Alignment) overflows, then ASSERT().
|
||||
|
||||
@param MemoryType The type of memory to allocate.
|
||||
@param Pages The number of 4 KB pages to allocate.
|
||||
@param Alignment The requested alignment of the allocation. Must be a power of two.
|
||||
If Alignment is zero, then byte alignment is used.
|
||||
|
||||
@return A pointer to the allocated buffer or NULL if allocation fails.
|
||||
|
||||
**/
|
||||
VOID *
|
||||
InternalAllocateAlignedPages (
|
||||
IN EFI_MEMORY_TYPE MemoryType,
|
||||
IN UINTN Pages,
|
||||
IN UINTN Alignment
|
||||
);
|
||||
|
||||
/**
|
||||
Frees one or more 4KB pages that were previously allocated with one of the aligned page
|
||||
allocation functions in the Memory Allocation Library.
|
||||
|
||||
Frees the number of 4KB pages specified by Pages from the buffer specified by Buffer. Buffer
|
||||
must have been allocated on a previous call to the aligned page allocation services of the Memory
|
||||
Allocation Library. If it is not possible to free allocated pages, then this function will
|
||||
perform no actions.
|
||||
|
||||
If Buffer was not allocated with an aligned page allocation function in the Memory Allocation
|
||||
Library, then ASSERT().
|
||||
If Pages is zero, then ASSERT().
|
||||
|
||||
@param Buffer Pointer to the buffer of pages to free.
|
||||
@param Pages The number of 4 KB pages to free.
|
||||
|
||||
**/
|
||||
VOID
|
||||
InternalFreeAlignedPages (
|
||||
IN VOID *Buffer,
|
||||
IN UINTN Pages
|
||||
);
|
||||
|
||||
#endif // ALIGNED_PAGES_H_
|
|
@ -1,55 +1,25 @@
|
|||
/** @file
|
||||
Support routines for memory allocation routines based
|
||||
on boot services for Dxe phase drivers, with memory profile support.
|
||||
Common code for the Memory Allocation Library based on
|
||||
PhaseMemoryAllocationLib.
|
||||
|
||||
Copyright (c) 2006 - 2018, Intel Corporation. All rights reserved.<BR>
|
||||
SPDX-License-Identifier: BSD-2-Clause-Patent
|
||||
|
||||
**/
|
||||
|
||||
|
||||
#include <Uefi.h>
|
||||
|
||||
#include <Base.h>
|
||||
#include <Uefi/UefiBaseType.h>
|
||||
#include <Uefi/UefiSpec.h>
|
||||
|
||||
#include <Library/MemoryAllocationLib.h>
|
||||
#include <Library/UefiBootServicesTableLib.h>
|
||||
#include <Library/MemoryAllocationLibEx.h>
|
||||
#include <Library/PhaseMemoryAllocationLib.h>
|
||||
#include <Library/BaseMemoryLib.h>
|
||||
#include <Library/DebugLib.h>
|
||||
|
||||
#include <Library/MemoryProfileLib.h>
|
||||
|
||||
/**
|
||||
Allocates one or more 4KB pages of a certain memory type.
|
||||
|
||||
Allocates the number of 4KB pages of a certain memory type and returns a pointer to the allocated
|
||||
buffer. The buffer returned is aligned on a 4KB boundary. If Pages is 0, then NULL is returned.
|
||||
If there is not enough memory remaining to satisfy the request, then NULL is returned.
|
||||
|
||||
@param MemoryType The type of memory to allocate.
|
||||
@param Pages The number of 4 KB pages to allocate.
|
||||
|
||||
@return A pointer to the allocated buffer or NULL if allocation fails.
|
||||
|
||||
**/
|
||||
VOID *
|
||||
InternalAllocatePages (
|
||||
IN EFI_MEMORY_TYPE MemoryType,
|
||||
IN UINTN Pages
|
||||
)
|
||||
{
|
||||
EFI_STATUS Status;
|
||||
EFI_PHYSICAL_ADDRESS Memory;
|
||||
|
||||
if (Pages == 0) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
Status = gBS->AllocatePages (AllocateAnyPages, MemoryType, Pages, &Memory);
|
||||
if (EFI_ERROR(Status)) {
|
||||
return NULL;
|
||||
}
|
||||
return (VOID *) (UINTN) Memory;
|
||||
}
|
||||
#include "AlignedPages.h"
|
||||
|
||||
/**
|
||||
Allocates one or more 4KB pages of type EfiBootServicesData.
|
||||
|
@ -70,19 +40,26 @@ AllocatePages (
|
|||
IN UINTN Pages
|
||||
)
|
||||
{
|
||||
VOID *Buffer;
|
||||
EFI_STATUS Status;
|
||||
EFI_PHYSICAL_ADDRESS Memory;
|
||||
VOID *Buffer;
|
||||
|
||||
Buffer = InternalAllocatePages (EfiBootServicesData, Pages);
|
||||
if (Buffer != NULL) {
|
||||
MemoryProfileLibRecord (
|
||||
(PHYSICAL_ADDRESS) (UINTN) RETURN_ADDRESS(0),
|
||||
MEMORY_PROFILE_ACTION_LIB_ALLOCATE_PAGES,
|
||||
EfiBootServicesData,
|
||||
Buffer,
|
||||
EFI_PAGES_TO_SIZE (Pages),
|
||||
NULL
|
||||
);
|
||||
Status = PhaseAllocatePages (AllocateAnyPages, gPhaseDefaultDataType, Pages, &Memory);
|
||||
if (EFI_ERROR (Status)) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
Buffer = (VOID *)(UINTN)Memory;
|
||||
|
||||
MemoryProfileLibRecord (
|
||||
(PHYSICAL_ADDRESS)(UINTN)RETURN_ADDRESS (0),
|
||||
MEMORY_PROFILE_ACTION_LIB_ALLOCATE_PAGES,
|
||||
gPhaseDefaultDataType,
|
||||
Buffer,
|
||||
EFI_PAGES_TO_SIZE (Pages),
|
||||
NULL
|
||||
);
|
||||
|
||||
return Buffer;
|
||||
}
|
||||
|
||||
|
@ -105,19 +82,26 @@ AllocateRuntimePages (
|
|||
IN UINTN Pages
|
||||
)
|
||||
{
|
||||
VOID *Buffer;
|
||||
EFI_STATUS Status;
|
||||
EFI_PHYSICAL_ADDRESS Memory;
|
||||
VOID *Buffer;
|
||||
|
||||
Buffer = InternalAllocatePages (EfiRuntimeServicesData, Pages);
|
||||
if (Buffer != NULL) {
|
||||
MemoryProfileLibRecord (
|
||||
(PHYSICAL_ADDRESS) (UINTN) RETURN_ADDRESS(0),
|
||||
MEMORY_PROFILE_ACTION_LIB_ALLOCATE_RUNTIME_PAGES,
|
||||
EfiRuntimeServicesData,
|
||||
Buffer,
|
||||
EFI_PAGES_TO_SIZE (Pages),
|
||||
NULL
|
||||
);
|
||||
Status = PhaseAllocatePages (AllocateAnyPages, EfiRuntimeServicesData, Pages, &Memory);
|
||||
if (EFI_ERROR (Status)) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
Buffer = (VOID *)(UINTN)Memory;
|
||||
|
||||
MemoryProfileLibRecord (
|
||||
(PHYSICAL_ADDRESS)(UINTN)RETURN_ADDRESS (0),
|
||||
MEMORY_PROFILE_ACTION_LIB_ALLOCATE_RUNTIME_PAGES,
|
||||
EfiRuntimeServicesData,
|
||||
Buffer,
|
||||
EFI_PAGES_TO_SIZE (Pages),
|
||||
NULL
|
||||
);
|
||||
|
||||
return Buffer;
|
||||
}
|
||||
|
||||
|
@ -140,22 +124,59 @@ AllocateReservedPages (
|
|||
IN UINTN Pages
|
||||
)
|
||||
{
|
||||
VOID *Buffer;
|
||||
EFI_STATUS Status;
|
||||
EFI_PHYSICAL_ADDRESS Memory;
|
||||
VOID *Buffer;
|
||||
|
||||
Buffer = InternalAllocatePages (EfiReservedMemoryType, Pages);
|
||||
if (Buffer != NULL) {
|
||||
MemoryProfileLibRecord (
|
||||
(PHYSICAL_ADDRESS) (UINTN) RETURN_ADDRESS(0),
|
||||
MEMORY_PROFILE_ACTION_LIB_ALLOCATE_RESERVED_PAGES,
|
||||
EfiReservedMemoryType,
|
||||
Buffer,
|
||||
EFI_PAGES_TO_SIZE (Pages),
|
||||
NULL
|
||||
);
|
||||
Status = PhaseAllocatePages (AllocateAnyPages, EfiReservedMemoryType, Pages, &Memory);
|
||||
if (EFI_ERROR (Status)) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
Buffer = (VOID *)(UINTN)Memory;
|
||||
|
||||
MemoryProfileLibRecord (
|
||||
(PHYSICAL_ADDRESS)(UINTN)RETURN_ADDRESS (0),
|
||||
MEMORY_PROFILE_ACTION_LIB_ALLOCATE_RESERVED_PAGES,
|
||||
EfiReservedMemoryType,
|
||||
Buffer,
|
||||
EFI_PAGES_TO_SIZE (Pages),
|
||||
NULL
|
||||
);
|
||||
|
||||
return Buffer;
|
||||
}
|
||||
|
||||
/**
|
||||
Allocates one or more 4KB pages of type EfiBootServicesCode.
|
||||
|
||||
Allocates the number of 4KB pages of type EfiBootServicesCode and returns a pointer to the
|
||||
allocated buffer. The buffer returned is aligned on a 4KB boundary. If Pages is 0, then NULL
|
||||
is returned. If there is not enough memory remaining to satisfy the request, then NULL is
|
||||
returned.
|
||||
|
||||
@param Pages The number of 4 KB pages to allocate.
|
||||
|
||||
@return A pointer to the allocated buffer or NULL if allocation fails.
|
||||
|
||||
**/
|
||||
VOID *
|
||||
EFIAPI
|
||||
AllocateCodePages (
|
||||
IN UINTN Pages
|
||||
)
|
||||
{
|
||||
EFI_STATUS Status;
|
||||
EFI_PHYSICAL_ADDRESS Memory;
|
||||
|
||||
Status = PhaseAllocatePages (AllocateAnyPages, gPhaseDefaultCodeType, Pages, &Memory);
|
||||
if (EFI_ERROR (Status)) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return (VOID *)(UINTN)Memory;
|
||||
}
|
||||
|
||||
/**
|
||||
Frees one or more 4KB pages that were previously allocated with one of the page allocation
|
||||
functions in the Memory Allocation Library.
|
||||
|
@ -169,7 +190,7 @@ AllocateReservedPages (
|
|||
then ASSERT().
|
||||
If Pages is zero, then ASSERT().
|
||||
|
||||
@param Buffer The pointer to the buffer of pages to free.
|
||||
@param Buffer Pointer to the buffer of pages to free.
|
||||
@param Pages The number of 4 KB pages to free.
|
||||
|
||||
**/
|
||||
|
@ -180,97 +201,10 @@ FreePages (
|
|||
IN UINTN Pages
|
||||
)
|
||||
{
|
||||
EFI_STATUS Status;
|
||||
EFI_STATUS Status;
|
||||
|
||||
ASSERT (Pages != 0);
|
||||
Status = gBS->FreePages ((EFI_PHYSICAL_ADDRESS) (UINTN) Buffer, Pages);
|
||||
ASSERT_EFI_ERROR(Status);
|
||||
}
|
||||
|
||||
/**
|
||||
Allocates one or more 4KB pages of a certain memory type at a specified alignment.
|
||||
|
||||
Allocates the number of 4KB pages specified by Pages of a certain memory type with an alignment
|
||||
specified by Alignment. The allocated buffer is returned. If Pages is 0, then NULL is returned.
|
||||
If there is not enough memory at the specified alignment remaining to satisfy the request, then
|
||||
NULL is returned.
|
||||
If Alignment is not a power of two and Alignment is not zero, then ASSERT().
|
||||
If Pages plus EFI_SIZE_TO_PAGES (Alignment) overflows, then ASSERT().
|
||||
|
||||
@param MemoryType The type of memory to allocate.
|
||||
@param Pages The number of 4 KB pages to allocate.
|
||||
@param Alignment The requested alignment of the allocation. Must be a power of two.
|
||||
If Alignment is zero, then byte alignment is used.
|
||||
|
||||
@return A pointer to the allocated buffer or NULL if allocation fails.
|
||||
|
||||
**/
|
||||
VOID *
|
||||
InternalAllocateAlignedPages (
|
||||
IN EFI_MEMORY_TYPE MemoryType,
|
||||
IN UINTN Pages,
|
||||
IN UINTN Alignment
|
||||
)
|
||||
{
|
||||
EFI_STATUS Status;
|
||||
EFI_PHYSICAL_ADDRESS Memory;
|
||||
UINTN AlignedMemory;
|
||||
UINTN AlignmentMask;
|
||||
UINTN UnalignedPages;
|
||||
UINTN RealPages;
|
||||
|
||||
//
|
||||
// Alignment must be a power of two or zero.
|
||||
//
|
||||
ASSERT ((Alignment & (Alignment - 1)) == 0);
|
||||
|
||||
if (Pages == 0) {
|
||||
return NULL;
|
||||
}
|
||||
if (Alignment > EFI_PAGE_SIZE) {
|
||||
//
|
||||
// Calculate the total number of pages since alignment is larger than page size.
|
||||
//
|
||||
AlignmentMask = Alignment - 1;
|
||||
RealPages = Pages + EFI_SIZE_TO_PAGES (Alignment);
|
||||
//
|
||||
// Make sure that Pages plus EFI_SIZE_TO_PAGES (Alignment) does not overflow.
|
||||
//
|
||||
ASSERT (RealPages > Pages);
|
||||
|
||||
Status = gBS->AllocatePages (AllocateAnyPages, MemoryType, RealPages, &Memory);
|
||||
if (EFI_ERROR(Status)) {
|
||||
return NULL;
|
||||
}
|
||||
AlignedMemory = ((UINTN) Memory + AlignmentMask) & ~AlignmentMask;
|
||||
UnalignedPages = EFI_SIZE_TO_PAGES (AlignedMemory - (UINTN) Memory);
|
||||
if (UnalignedPages > 0) {
|
||||
//
|
||||
// Free first unaligned page(s).
|
||||
//
|
||||
Status = gBS->FreePages (Memory, UnalignedPages);
|
||||
ASSERT_EFI_ERROR(Status);
|
||||
}
|
||||
Memory = AlignedMemory + EFI_PAGES_TO_SIZE (Pages);
|
||||
UnalignedPages = RealPages - Pages - UnalignedPages;
|
||||
if (UnalignedPages > 0) {
|
||||
//
|
||||
// Free last unaligned page(s).
|
||||
//
|
||||
Status = gBS->FreePages (Memory, UnalignedPages);
|
||||
ASSERT_EFI_ERROR(Status);
|
||||
}
|
||||
} else {
|
||||
//
|
||||
// Do not over-allocate pages in this case.
|
||||
//
|
||||
Status = gBS->AllocatePages (AllocateAnyPages, MemoryType, Pages, &Memory);
|
||||
if (EFI_ERROR(Status)) {
|
||||
return NULL;
|
||||
}
|
||||
AlignedMemory = (UINTN) Memory;
|
||||
}
|
||||
return (VOID *) AlignedMemory;
|
||||
Status = PhaseFreePages ((UINTN)Buffer, Pages);
|
||||
ASSERT_EFI_ERROR (Status);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -300,17 +234,18 @@ AllocateAlignedPages (
|
|||
{
|
||||
VOID *Buffer;
|
||||
|
||||
Buffer = InternalAllocateAlignedPages (EfiBootServicesData, Pages, Alignment);
|
||||
Buffer = InternalAllocateAlignedPages (gPhaseDefaultDataType, Pages, Alignment);
|
||||
if (Buffer != NULL) {
|
||||
MemoryProfileLibRecord (
|
||||
(PHYSICAL_ADDRESS) (UINTN) RETURN_ADDRESS(0),
|
||||
(PHYSICAL_ADDRESS)(UINTN)RETURN_ADDRESS (0),
|
||||
MEMORY_PROFILE_ACTION_LIB_ALLOCATE_ALIGNED_PAGES,
|
||||
EfiBootServicesData,
|
||||
gPhaseDefaultDataType,
|
||||
Buffer,
|
||||
EFI_PAGES_TO_SIZE (Pages),
|
||||
NULL
|
||||
);
|
||||
}
|
||||
|
||||
return Buffer;
|
||||
}
|
||||
|
||||
|
@ -344,7 +279,7 @@ AllocateAlignedRuntimePages (
|
|||
Buffer = InternalAllocateAlignedPages (EfiRuntimeServicesData, Pages, Alignment);
|
||||
if (Buffer != NULL) {
|
||||
MemoryProfileLibRecord (
|
||||
(PHYSICAL_ADDRESS) (UINTN) RETURN_ADDRESS(0),
|
||||
(PHYSICAL_ADDRESS)(UINTN)RETURN_ADDRESS (0),
|
||||
MEMORY_PROFILE_ACTION_LIB_ALLOCATE_ALIGNED_RUNTIME_PAGES,
|
||||
EfiRuntimeServicesData,
|
||||
Buffer,
|
||||
|
@ -352,6 +287,7 @@ AllocateAlignedRuntimePages (
|
|||
NULL
|
||||
);
|
||||
}
|
||||
|
||||
return Buffer;
|
||||
}
|
||||
|
||||
|
@ -385,7 +321,7 @@ AllocateAlignedReservedPages (
|
|||
Buffer = InternalAllocateAlignedPages (EfiReservedMemoryType, Pages, Alignment);
|
||||
if (Buffer != NULL) {
|
||||
MemoryProfileLibRecord (
|
||||
(PHYSICAL_ADDRESS) (UINTN) RETURN_ADDRESS(0),
|
||||
(PHYSICAL_ADDRESS)(UINTN)RETURN_ADDRESS (0),
|
||||
MEMORY_PROFILE_ACTION_LIB_ALLOCATE_ALIGNED_RESERVED_PAGES,
|
||||
EfiReservedMemoryType,
|
||||
Buffer,
|
||||
|
@ -393,9 +329,20 @@ AllocateAlignedReservedPages (
|
|||
NULL
|
||||
);
|
||||
}
|
||||
|
||||
return Buffer;
|
||||
}
|
||||
|
||||
VOID *
|
||||
EFIAPI
|
||||
AllocateAlignedCodePages (
|
||||
IN UINTN Pages,
|
||||
IN UINTN Alignment
|
||||
)
|
||||
{
|
||||
return InternalAllocateAlignedPages (gPhaseDefaultCodeType, Pages, Alignment);
|
||||
}
|
||||
|
||||
/**
|
||||
Frees one or more 4KB pages that were previously allocated with one of the aligned page
|
||||
allocation functions in the Memory Allocation Library.
|
||||
|
@ -409,7 +356,7 @@ AllocateAlignedReservedPages (
|
|||
Library, then ASSERT().
|
||||
If Pages is zero, then ASSERT().
|
||||
|
||||
@param Buffer The pointer to the buffer of pages to free.
|
||||
@param Buffer Pointer to the buffer of pages to free.
|
||||
@param Pages The number of 4 KB pages to free.
|
||||
|
||||
**/
|
||||
|
@ -420,40 +367,7 @@ FreeAlignedPages (
|
|||
IN UINTN Pages
|
||||
)
|
||||
{
|
||||
EFI_STATUS Status;
|
||||
|
||||
ASSERT (Pages != 0);
|
||||
Status = gBS->FreePages ((EFI_PHYSICAL_ADDRESS) (UINTN) Buffer, Pages);
|
||||
ASSERT_EFI_ERROR(Status);
|
||||
}
|
||||
|
||||
/**
|
||||
Allocates a buffer of a certain pool type.
|
||||
|
||||
Allocates the number bytes specified by AllocationSize of a certain pool type and returns a
|
||||
pointer to the allocated buffer. If AllocationSize is 0, then a valid buffer of 0 size is
|
||||
returned. If there is not enough memory remaining to satisfy the request, then NULL is returned.
|
||||
|
||||
@param MemoryType The type of memory to allocate.
|
||||
@param AllocationSize The number of bytes to allocate.
|
||||
|
||||
@return A pointer to the allocated buffer or NULL if allocation fails.
|
||||
|
||||
**/
|
||||
VOID *
|
||||
InternalAllocatePool (
|
||||
IN EFI_MEMORY_TYPE MemoryType,
|
||||
IN UINTN AllocationSize
|
||||
)
|
||||
{
|
||||
EFI_STATUS Status;
|
||||
VOID *Memory;
|
||||
|
||||
Status = gBS->AllocatePool (MemoryType, AllocationSize, &Memory);
|
||||
if (EFI_ERROR(Status)) {
|
||||
Memory = NULL;
|
||||
}
|
||||
return Memory;
|
||||
InternalFreeAlignedPages (Buffer, Pages);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -476,17 +390,18 @@ AllocatePool (
|
|||
{
|
||||
VOID *Buffer;
|
||||
|
||||
Buffer = InternalAllocatePool (EfiBootServicesData, AllocationSize);
|
||||
Buffer = PhaseAllocatePool (gPhaseDefaultDataType, AllocationSize);
|
||||
if (Buffer != NULL) {
|
||||
MemoryProfileLibRecord (
|
||||
(PHYSICAL_ADDRESS) (UINTN) RETURN_ADDRESS(0),
|
||||
(PHYSICAL_ADDRESS)(UINTN)RETURN_ADDRESS (0),
|
||||
MEMORY_PROFILE_ACTION_LIB_ALLOCATE_POOL,
|
||||
EfiBootServicesData,
|
||||
gPhaseDefaultDataType,
|
||||
Buffer,
|
||||
AllocationSize,
|
||||
NULL
|
||||
);
|
||||
}
|
||||
|
||||
return Buffer;
|
||||
}
|
||||
|
||||
|
@ -510,10 +425,10 @@ AllocateRuntimePool (
|
|||
{
|
||||
VOID *Buffer;
|
||||
|
||||
Buffer = InternalAllocatePool (EfiRuntimeServicesData, AllocationSize);
|
||||
Buffer = PhaseAllocatePool (EfiRuntimeServicesData, AllocationSize);
|
||||
if (Buffer != NULL) {
|
||||
MemoryProfileLibRecord (
|
||||
(PHYSICAL_ADDRESS) (UINTN) RETURN_ADDRESS(0),
|
||||
(PHYSICAL_ADDRESS)(UINTN)RETURN_ADDRESS (0),
|
||||
MEMORY_PROFILE_ACTION_LIB_ALLOCATE_RUNTIME_POOL,
|
||||
EfiRuntimeServicesData,
|
||||
Buffer,
|
||||
|
@ -521,6 +436,7 @@ AllocateRuntimePool (
|
|||
NULL
|
||||
);
|
||||
}
|
||||
|
||||
return Buffer;
|
||||
}
|
||||
|
||||
|
@ -544,10 +460,10 @@ AllocateReservedPool (
|
|||
{
|
||||
VOID *Buffer;
|
||||
|
||||
Buffer = InternalAllocatePool (EfiReservedMemoryType, AllocationSize);
|
||||
Buffer = PhaseAllocatePool (EfiReservedMemoryType, AllocationSize);
|
||||
if (Buffer != NULL) {
|
||||
MemoryProfileLibRecord (
|
||||
(PHYSICAL_ADDRESS) (UINTN) RETURN_ADDRESS(0),
|
||||
(PHYSICAL_ADDRESS)(UINTN)RETURN_ADDRESS (0),
|
||||
MEMORY_PROFILE_ACTION_LIB_ALLOCATE_RESERVED_POOL,
|
||||
EfiReservedMemoryType,
|
||||
Buffer,
|
||||
|
@ -555,6 +471,7 @@ AllocateReservedPool (
|
|||
NULL
|
||||
);
|
||||
}
|
||||
|
||||
return Buffer;
|
||||
}
|
||||
|
||||
|
@ -572,18 +489,20 @@ AllocateReservedPool (
|
|||
@return A pointer to the allocated buffer or NULL if allocation fails.
|
||||
|
||||
**/
|
||||
STATIC
|
||||
VOID *
|
||||
InternalAllocateZeroPool(
|
||||
InternalAllocateZeroPool (
|
||||
IN EFI_MEMORY_TYPE PoolType,
|
||||
IN UINTN AllocationSize
|
||||
)
|
||||
{
|
||||
VOID *Memory;
|
||||
|
||||
Memory = InternalAllocatePool (PoolType, AllocationSize);
|
||||
Memory = PhaseAllocatePool (PoolType, AllocationSize);
|
||||
if (Memory != NULL) {
|
||||
Memory = ZeroMem (Memory, AllocationSize);
|
||||
}
|
||||
|
||||
return Memory;
|
||||
}
|
||||
|
||||
|
@ -602,23 +521,24 @@ InternalAllocateZeroPool(
|
|||
**/
|
||||
VOID *
|
||||
EFIAPI
|
||||
AllocateZeroPool(
|
||||
AllocateZeroPool (
|
||||
IN UINTN AllocationSize
|
||||
)
|
||||
{
|
||||
VOID *Buffer;
|
||||
|
||||
Buffer = InternalAllocateZeroPool(EfiBootServicesData, AllocationSize);
|
||||
Buffer = InternalAllocateZeroPool (gPhaseDefaultDataType, AllocationSize);
|
||||
if (Buffer != NULL) {
|
||||
MemoryProfileLibRecord (
|
||||
(PHYSICAL_ADDRESS) (UINTN) RETURN_ADDRESS(0),
|
||||
(PHYSICAL_ADDRESS)(UINTN)RETURN_ADDRESS (0),
|
||||
MEMORY_PROFILE_ACTION_LIB_ALLOCATE_ZERO_POOL,
|
||||
EfiBootServicesData,
|
||||
gPhaseDefaultDataType,
|
||||
Buffer,
|
||||
AllocationSize,
|
||||
NULL
|
||||
);
|
||||
}
|
||||
|
||||
return Buffer;
|
||||
}
|
||||
|
||||
|
@ -643,10 +563,10 @@ AllocateRuntimeZeroPool (
|
|||
{
|
||||
VOID *Buffer;
|
||||
|
||||
Buffer = InternalAllocateZeroPool(EfiRuntimeServicesData, AllocationSize);
|
||||
Buffer = InternalAllocateZeroPool (EfiRuntimeServicesData, AllocationSize);
|
||||
if (Buffer != NULL) {
|
||||
MemoryProfileLibRecord (
|
||||
(PHYSICAL_ADDRESS) (UINTN) RETURN_ADDRESS(0),
|
||||
(PHYSICAL_ADDRESS)(UINTN)RETURN_ADDRESS (0),
|
||||
MEMORY_PROFILE_ACTION_LIB_ALLOCATE_RUNTIME_ZERO_POOL,
|
||||
EfiRuntimeServicesData,
|
||||
Buffer,
|
||||
|
@ -654,6 +574,7 @@ AllocateRuntimeZeroPool (
|
|||
NULL
|
||||
);
|
||||
}
|
||||
|
||||
return Buffer;
|
||||
}
|
||||
|
||||
|
@ -678,10 +599,10 @@ AllocateReservedZeroPool (
|
|||
{
|
||||
VOID *Buffer;
|
||||
|
||||
Buffer = InternalAllocateZeroPool(EfiReservedMemoryType, AllocationSize);
|
||||
Buffer = InternalAllocateZeroPool (EfiReservedMemoryType, AllocationSize);
|
||||
if (Buffer != NULL) {
|
||||
MemoryProfileLibRecord (
|
||||
(PHYSICAL_ADDRESS) (UINTN) RETURN_ADDRESS(0),
|
||||
(PHYSICAL_ADDRESS)(UINTN)RETURN_ADDRESS (0),
|
||||
MEMORY_PROFILE_ACTION_LIB_ALLOCATE_RESERVED_ZERO_POOL,
|
||||
EfiReservedMemoryType,
|
||||
Buffer,
|
||||
|
@ -689,6 +610,7 @@ AllocateReservedZeroPool (
|
|||
NULL
|
||||
);
|
||||
}
|
||||
|
||||
return Buffer;
|
||||
}
|
||||
|
||||
|
@ -709,8 +631,9 @@ AllocateReservedZeroPool (
|
|||
@return A pointer to the allocated buffer or NULL if allocation fails.
|
||||
|
||||
**/
|
||||
STATIC
|
||||
VOID *
|
||||
InternalAllocateCopyPool(
|
||||
InternalAllocateCopyPool (
|
||||
IN EFI_MEMORY_TYPE PoolType,
|
||||
IN UINTN AllocationSize,
|
||||
IN CONST VOID *Buffer
|
||||
|
@ -719,12 +642,13 @@ InternalAllocateCopyPool(
|
|||
VOID *Memory;
|
||||
|
||||
ASSERT (Buffer != NULL);
|
||||
ASSERT (AllocationSize <= (MAX_ADDRESS - (UINTN) Buffer + 1));
|
||||
ASSERT (AllocationSize <= (MAX_ADDRESS - (UINTN)Buffer + 1));
|
||||
|
||||
Memory = InternalAllocatePool (PoolType, AllocationSize);
|
||||
Memory = PhaseAllocatePool (PoolType, AllocationSize);
|
||||
if (Memory != NULL) {
|
||||
Memory = CopyMem(Memory, Buffer, AllocationSize);
|
||||
Memory = CopyMem (Memory, Buffer, AllocationSize);
|
||||
}
|
||||
|
||||
return Memory;
|
||||
}
|
||||
|
||||
|
@ -747,24 +671,25 @@ InternalAllocateCopyPool(
|
|||
**/
|
||||
VOID *
|
||||
EFIAPI
|
||||
AllocateCopyPool(
|
||||
AllocateCopyPool (
|
||||
IN UINTN AllocationSize,
|
||||
IN CONST VOID *Buffer
|
||||
)
|
||||
{
|
||||
VOID *NewBuffer;
|
||||
|
||||
NewBuffer = InternalAllocateCopyPool(EfiBootServicesData, AllocationSize, Buffer);
|
||||
NewBuffer = InternalAllocateCopyPool (gPhaseDefaultDataType, AllocationSize, Buffer);
|
||||
if (NewBuffer != NULL) {
|
||||
MemoryProfileLibRecord (
|
||||
(PHYSICAL_ADDRESS) (UINTN) RETURN_ADDRESS(0),
|
||||
(PHYSICAL_ADDRESS)(UINTN)RETURN_ADDRESS (0),
|
||||
MEMORY_PROFILE_ACTION_LIB_ALLOCATE_COPY_POOL,
|
||||
EfiBootServicesData,
|
||||
gPhaseDefaultDataType,
|
||||
NewBuffer,
|
||||
AllocationSize,
|
||||
NULL
|
||||
);
|
||||
}
|
||||
|
||||
return NewBuffer;
|
||||
}
|
||||
|
||||
|
@ -794,10 +719,10 @@ AllocateRuntimeCopyPool (
|
|||
{
|
||||
VOID *NewBuffer;
|
||||
|
||||
NewBuffer = InternalAllocateCopyPool(EfiRuntimeServicesData, AllocationSize, Buffer);
|
||||
NewBuffer = InternalAllocateCopyPool (EfiRuntimeServicesData, AllocationSize, Buffer);
|
||||
if (NewBuffer != NULL) {
|
||||
MemoryProfileLibRecord (
|
||||
(PHYSICAL_ADDRESS) (UINTN) RETURN_ADDRESS(0),
|
||||
(PHYSICAL_ADDRESS)(UINTN)RETURN_ADDRESS (0),
|
||||
MEMORY_PROFILE_ACTION_LIB_ALLOCATE_RUNTIME_COPY_POOL,
|
||||
EfiRuntimeServicesData,
|
||||
NewBuffer,
|
||||
|
@ -805,6 +730,7 @@ AllocateRuntimeCopyPool (
|
|||
NULL
|
||||
);
|
||||
}
|
||||
|
||||
return NewBuffer;
|
||||
}
|
||||
|
||||
|
@ -834,10 +760,10 @@ AllocateReservedCopyPool (
|
|||
{
|
||||
VOID *NewBuffer;
|
||||
|
||||
NewBuffer = InternalAllocateCopyPool(EfiReservedMemoryType, AllocationSize, Buffer);
|
||||
NewBuffer = InternalAllocateCopyPool (EfiReservedMemoryType, AllocationSize, Buffer);
|
||||
if (NewBuffer != NULL) {
|
||||
MemoryProfileLibRecord (
|
||||
(PHYSICAL_ADDRESS) (UINTN) RETURN_ADDRESS(0),
|
||||
(PHYSICAL_ADDRESS)(UINTN)RETURN_ADDRESS (0),
|
||||
MEMORY_PROFILE_ACTION_LIB_ALLOCATE_RESERVED_COPY_POOL,
|
||||
EfiRuntimeServicesData,
|
||||
NewBuffer,
|
||||
|
@ -845,6 +771,7 @@ AllocateReservedCopyPool (
|
|||
NULL
|
||||
);
|
||||
}
|
||||
|
||||
return NewBuffer;
|
||||
}
|
||||
|
||||
|
@ -870,6 +797,7 @@ AllocateReservedCopyPool (
|
|||
@return A pointer to the allocated buffer or NULL if allocation fails.
|
||||
|
||||
**/
|
||||
STATIC
|
||||
VOID *
|
||||
InternalReallocatePool (
|
||||
IN EFI_MEMORY_TYPE PoolType,
|
||||
|
@ -880,11 +808,12 @@ InternalReallocatePool (
|
|||
{
|
||||
VOID *NewBuffer;
|
||||
|
||||
NewBuffer = InternalAllocateZeroPool(PoolType, NewSize);
|
||||
if (NewBuffer != NULL && OldBuffer != NULL) {
|
||||
CopyMem(NewBuffer, OldBuffer, MIN (OldSize, NewSize));
|
||||
FreePool(OldBuffer);
|
||||
NewBuffer = InternalAllocateZeroPool (PoolType, NewSize);
|
||||
if ((NewBuffer != NULL) && (OldBuffer != NULL)) {
|
||||
CopyMem (NewBuffer, OldBuffer, MIN (OldSize, NewSize));
|
||||
FreePool (OldBuffer);
|
||||
}
|
||||
|
||||
return NewBuffer;
|
||||
}
|
||||
|
||||
|
@ -919,17 +848,18 @@ ReallocatePool (
|
|||
{
|
||||
VOID *Buffer;
|
||||
|
||||
Buffer = InternalReallocatePool (EfiBootServicesData, OldSize, NewSize, OldBuffer);
|
||||
Buffer = InternalReallocatePool (gPhaseDefaultDataType, OldSize, NewSize, OldBuffer);
|
||||
if (Buffer != NULL) {
|
||||
MemoryProfileLibRecord (
|
||||
(PHYSICAL_ADDRESS) (UINTN) RETURN_ADDRESS(0),
|
||||
(PHYSICAL_ADDRESS)(UINTN)RETURN_ADDRESS (0),
|
||||
MEMORY_PROFILE_ACTION_LIB_REALLOCATE_POOL,
|
||||
EfiBootServicesData,
|
||||
gPhaseDefaultDataType,
|
||||
Buffer,
|
||||
NewSize,
|
||||
NULL
|
||||
);
|
||||
}
|
||||
|
||||
return Buffer;
|
||||
}
|
||||
|
||||
|
@ -967,7 +897,7 @@ ReallocateRuntimePool (
|
|||
Buffer = InternalReallocatePool (EfiRuntimeServicesData, OldSize, NewSize, OldBuffer);
|
||||
if (Buffer != NULL) {
|
||||
MemoryProfileLibRecord (
|
||||
(PHYSICAL_ADDRESS) (UINTN) RETURN_ADDRESS(0),
|
||||
(PHYSICAL_ADDRESS)(UINTN)RETURN_ADDRESS (0),
|
||||
MEMORY_PROFILE_ACTION_LIB_REALLOCATE_RUNTIME_POOL,
|
||||
EfiRuntimeServicesData,
|
||||
Buffer,
|
||||
|
@ -975,6 +905,7 @@ ReallocateRuntimePool (
|
|||
NULL
|
||||
);
|
||||
}
|
||||
|
||||
return Buffer;
|
||||
}
|
||||
|
||||
|
@ -1012,7 +943,7 @@ ReallocateReservedPool (
|
|||
Buffer = InternalReallocatePool (EfiReservedMemoryType, OldSize, NewSize, OldBuffer);
|
||||
if (Buffer != NULL) {
|
||||
MemoryProfileLibRecord (
|
||||
(PHYSICAL_ADDRESS) (UINTN) RETURN_ADDRESS(0),
|
||||
(PHYSICAL_ADDRESS)(UINTN)RETURN_ADDRESS (0),
|
||||
MEMORY_PROFILE_ACTION_LIB_REALLOCATE_RESERVED_POOL,
|
||||
EfiReservedMemoryType,
|
||||
Buffer,
|
||||
|
@ -1020,6 +951,7 @@ ReallocateReservedPool (
|
|||
NULL
|
||||
);
|
||||
}
|
||||
|
||||
return Buffer;
|
||||
}
|
||||
|
||||
|
@ -1034,18 +966,14 @@ ReallocateReservedPool (
|
|||
If Buffer was not allocated with a pool allocation function in the Memory Allocation Library,
|
||||
then ASSERT().
|
||||
|
||||
@param Buffer The pointer to the buffer to free.
|
||||
@param Buffer Pointer to the buffer to free.
|
||||
|
||||
**/
|
||||
VOID
|
||||
EFIAPI
|
||||
FreePool(
|
||||
IN VOID *Buffer
|
||||
FreePool (
|
||||
IN VOID *Buffer
|
||||
)
|
||||
{
|
||||
EFI_STATUS Status;
|
||||
|
||||
Status = gBS->FreePool(Buffer);
|
||||
ASSERT_EFI_ERROR(Status);
|
||||
PhaseFreePool (Buffer);
|
||||
}
|
||||
|
|
@ -0,0 +1,39 @@
|
|||
## @file
|
||||
# Common code for the Memory Allocation Library based on
|
||||
# PhaseMemoryAllocationLib.
|
||||
#
|
||||
# Copyright (c) 2007 - 2018, Intel Corporation. All rights reserved.<BR>
|
||||
#
|
||||
# SPDX-License-Identifier: BSD-2-Clause-Patent
|
||||
#
|
||||
#
|
||||
##
|
||||
|
||||
[Defines]
|
||||
INF_VERSION = 0x00010005
|
||||
BASE_NAME = CommonMemoryAllocationLib
|
||||
MODULE_UNI_FILE = CommonMemoryAllocationLib.uni
|
||||
FILE_GUID = 020172f8-f96d-479b-9f29-c4d2f204573d
|
||||
MODULE_TYPE = BASE
|
||||
VERSION_STRING = 1.0
|
||||
LIBRARY_CLASS = CommonMemoryAllocationLib
|
||||
|
||||
#
|
||||
# VALID_ARCHITECTURES = IA32 X64 EBC
|
||||
#
|
||||
|
||||
[Sources]
|
||||
AlignedPages.h
|
||||
AlignedPages.c
|
||||
CommonMemoryAllocationLib.c
|
||||
CommonMemoryAllocationLibEx.c
|
||||
|
||||
[Packages]
|
||||
MdePkg/MdePkg.dec
|
||||
MdeModulePkg/MdeModulePkg.dec
|
||||
|
||||
[LibraryClasses]
|
||||
DebugLib
|
||||
BaseMemoryLib
|
||||
MemoryProfileLib
|
||||
|
|
@ -0,0 +1,15 @@
|
|||
// /** @file
|
||||
// Common code for the Memory Allocation Library based on
|
||||
// PhaseMemoryAllocationLib.
|
||||
//
|
||||
// Copyright (c) 2007 - 2014, Intel Corporation. All rights reserved.<BR>
|
||||
//
|
||||
// SPDX-License-Identifier: BSD-2-Clause-Patent
|
||||
//
|
||||
// **/
|
||||
|
||||
|
||||
#string STR_MODULE_ABSTRACT #language en-US "Common code for the Memory Allocation Library based on PhaseMemoryAllocationLib"
|
||||
|
||||
#string STR_MODULE_DESCRIPTION #language en-US "Common code for the Memory Allocation Library based on PhaseMemoryAllocationLib."
|
||||
|
|
@ -0,0 +1,150 @@
|
|||
/** @file
|
||||
Implementation of MemoryAllocationLibEx based on PhaseMemoryAllocationLib.
|
||||
|
||||
Copyright (c) 2006 - 2018, Intel Corporation. All rights reserved.<BR>
|
||||
Copyright (c) 2023, Marvin Häuser. All rights reserved.<BR>
|
||||
SPDX-License-Identifier: BSD-2-Clause-Patent
|
||||
|
||||
**/
|
||||
|
||||
#include <PiDxe.h>
|
||||
|
||||
#include <Library/MemoryAllocationLibEx.h>
|
||||
#include <Library/PhaseMemoryAllocationLib.h>
|
||||
#include <Library/DebugLib.h>
|
||||
|
||||
/**
|
||||
Allocates one or more 4KB pages of a certain memory type.
|
||||
|
||||
Allocates the number of 4KB pages of a certain memory type and returns a pointer
|
||||
to the allocated buffer. The buffer returned is aligned on a 4KB boundary.
|
||||
|
||||
@param Type The type of allocation to perform.
|
||||
@param MemoryType The type of memory to allocate.
|
||||
@param Pages The number of 4 KB pages to allocate.
|
||||
@param Memory The pointer to a physical address. On input, the
|
||||
way in which the address is used depends on the
|
||||
value of Type.
|
||||
|
||||
@retval EFI_SUCCESS The requested pages were allocated.
|
||||
@retval EFI_OUT_OF_RESOURCES The pages could not be allocated.
|
||||
@retval EFI_NOT_FOUND The requested pages could not be found.
|
||||
|
||||
**/
|
||||
EFI_STATUS
|
||||
EFIAPI
|
||||
AllocatePagesEx (
|
||||
IN EFI_ALLOCATE_TYPE Type,
|
||||
IN EFI_MEMORY_TYPE MemoryType,
|
||||
IN UINTN Pages,
|
||||
IN OUT EFI_PHYSICAL_ADDRESS *Memory
|
||||
)
|
||||
{
|
||||
return PhaseAllocatePages (Type, MemoryType, Pages, Memory);
|
||||
}
|
||||
|
||||
/**
|
||||
Allocates one or more 4KB pages of a certain memory type at a specified alignment.
|
||||
|
||||
Allocates the number of 4KB pages specified by Pages of a certain memory type with an alignment
|
||||
specified by Alignment.
|
||||
If Alignment is not a power of two and Alignment is not zero, then ASSERT().
|
||||
If Pages plus EFI_SIZE_TO_PAGES (Alignment) overflows, then ASSERT().
|
||||
|
||||
@param Type The type of allocation to perform.
|
||||
@param MemoryType The type of memory to allocate.
|
||||
@param Pages The number of 4 KB pages to allocate.
|
||||
@param Alignment The requested alignment of the allocation. Must be a power of two.
|
||||
If Alignment is zero, then byte alignment is used.
|
||||
@param Memory The pointer to a physical address. On input, the
|
||||
way in which the address is used depends on the
|
||||
value of Type.
|
||||
|
||||
@retval EFI_SUCCESS The requested pages were allocated.
|
||||
@retval EFI_OUT_OF_RESOURCES The pages could not be allocated.
|
||||
@retval EFI_NOT_FOUND The requested pages could not be found.
|
||||
|
||||
**/
|
||||
EFI_STATUS
|
||||
EFIAPI
|
||||
AllocateAlignedPagesEx (
|
||||
IN EFI_ALLOCATE_TYPE Type,
|
||||
IN EFI_MEMORY_TYPE MemoryType,
|
||||
IN UINTN Pages,
|
||||
IN UINTN Alignment,
|
||||
IN OUT EFI_PHYSICAL_ADDRESS *Memory
|
||||
)
|
||||
{
|
||||
EFI_STATUS Status;
|
||||
EFI_PHYSICAL_ADDRESS Address;
|
||||
EFI_PHYSICAL_ADDRESS AlignedMemory;
|
||||
UINTN AlignmentMask;
|
||||
UINTN UnalignedPages;
|
||||
UINTN RealPages;
|
||||
|
||||
//
|
||||
// Alignment must be a power of two or zero.
|
||||
//
|
||||
ASSERT ((Alignment & (Alignment - 1)) == 0);
|
||||
|
||||
//
|
||||
// Reserving a specific address does not require guaranteeing alignment
|
||||
// constraints.
|
||||
//
|
||||
ASSERT (Type != AllocateAddress);
|
||||
|
||||
if (Pages == 0) {
|
||||
return EFI_INVALID_PARAMETER;
|
||||
}
|
||||
|
||||
if (Alignment > EFI_PAGE_SIZE) {
|
||||
//
|
||||
// Calculate the total number of pages since alignment is larger than page size.
|
||||
//
|
||||
AlignmentMask = Alignment - 1;
|
||||
RealPages = Pages + EFI_SIZE_TO_PAGES (Alignment);
|
||||
//
|
||||
// Make sure that Pages plus EFI_SIZE_TO_PAGES (Alignment) does not overflow.
|
||||
//
|
||||
ASSERT (RealPages > Pages);
|
||||
|
||||
Status = AllocatePagesEx (Type, MemoryType, RealPages, Memory);
|
||||
if (EFI_ERROR (Status)) {
|
||||
return Status;
|
||||
}
|
||||
|
||||
Address = *Memory;
|
||||
|
||||
AlignedMemory = (Address + AlignmentMask) & ~(EFI_PHYSICAL_ADDRESS)AlignmentMask;
|
||||
UnalignedPages = EFI_SIZE_TO_PAGES ((UINTN)(AlignedMemory - Address));
|
||||
if (UnalignedPages > 0) {
|
||||
//
|
||||
// Free first unaligned page(s).
|
||||
//
|
||||
Status = PhaseFreePages (Address, UnalignedPages);
|
||||
ASSERT_EFI_ERROR (Status);
|
||||
}
|
||||
|
||||
Address = AlignedMemory + EFI_PAGES_TO_SIZE (Pages);
|
||||
UnalignedPages = RealPages - Pages - UnalignedPages;
|
||||
if (UnalignedPages > 0) {
|
||||
//
|
||||
// Free last unaligned page(s).
|
||||
//
|
||||
Status = PhaseFreePages (Address, UnalignedPages);
|
||||
ASSERT_EFI_ERROR (Status);
|
||||
}
|
||||
|
||||
*Memory = AlignedMemory;
|
||||
} else {
|
||||
//
|
||||
// Do not over-allocate pages in this case.
|
||||
//
|
||||
Status = AllocatePagesEx (Type, MemoryType, Pages, Memory);
|
||||
if (EFI_ERROR (Status)) {
|
||||
return Status;
|
||||
}
|
||||
}
|
||||
|
||||
return EFI_SUCCESS;
|
||||
}
|
|
@ -29,7 +29,6 @@
|
|||
[Sources]
|
||||
MemoryAllocationLib.c
|
||||
DxeCoreMemoryAllocationServices.h
|
||||
DxeCoreMemoryProfileLibNull.c
|
||||
|
||||
[Packages]
|
||||
MdePkg/MdePkg.dec
|
||||
|
@ -38,3 +37,5 @@
|
|||
[LibraryClasses]
|
||||
DebugLib
|
||||
BaseMemoryLib
|
||||
MemoryProfileLib
|
||||
CommonMemoryAllocationLib
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
## @file
|
||||
# Memory Allocation/Profile Library instance dedicated to DXE Core.
|
||||
# The implementation borrows the DxeCore Memory Allocation/profile services as the primitive
|
||||
# for memory allocation/profile instead of using UEFI boot services or memory profile protocol in an indirect way.
|
||||
# Memory Profile Library instance dedicated to DXE Core.
|
||||
# The implementation borrows the DxeCore Memory profile services as the primitive
|
||||
# for memory profile instead of using UEFI boot services or memory profile protocol in an indirect way.
|
||||
# It is assumed that this library instance must be linked with DxeCore in this package.
|
||||
#
|
||||
# Copyright (c) 2008 - 2018, Intel Corporation. All rights reserved.<BR>
|
||||
|
@ -18,7 +18,6 @@
|
|||
FILE_GUID = 7ADD7147-74E8-4583-BE34-B6BC45353BB5
|
||||
MODULE_TYPE = DXE_CORE
|
||||
VERSION_STRING = 1.0
|
||||
LIBRARY_CLASS = MemoryAllocationLib|DXE_CORE
|
||||
LIBRARY_CLASS = MemoryProfileLib|DXE_CORE
|
||||
|
||||
#
|
||||
|
@ -28,8 +27,6 @@
|
|||
#
|
||||
|
||||
[Sources]
|
||||
MemoryAllocationLib.c
|
||||
DxeCoreMemoryAllocationServices.h
|
||||
DxeCoreMemoryProfileLib.c
|
||||
DxeCoreMemoryProfileServices.h
|
||||
|
||||
|
@ -37,7 +34,3 @@
|
|||
MdePkg/MdePkg.dec
|
||||
MdeModulePkg/MdeModulePkg.dec
|
||||
|
||||
[LibraryClasses]
|
||||
DebugLib
|
||||
BaseMemoryLib
|
||||
|
||||
|
|
|
@ -1,8 +1,8 @@
|
|||
// /** @file
|
||||
// Memory Allocation/Profile Library instance dedicated to DXE Core.
|
||||
// Memory Profile Library instance dedicated to DXE Core.
|
||||
//
|
||||
// The implementation borrows the DxeCore Memory Allocation/Profile services as the primitive
|
||||
// for memory allocation/profile instead of using UEFI boot services or memory profile protocol in an indirect way.
|
||||
// The implementation borrows the DxeCore Memory Profile services as the primitive
|
||||
// for memory profile instead of using UEFI boot services or memory profile protocol in an indirect way.
|
||||
// It is assumed that this library instance must be linked with DxeCore in this package.
|
||||
//
|
||||
// Copyright (c) 2008 - 2016, Intel Corporation. All rights reserved.<BR>
|
||||
|
@ -12,7 +12,7 @@
|
|||
// **/
|
||||
|
||||
|
||||
#string STR_MODULE_ABSTRACT #language en-US "Memory Allocation/Profile Library instance dedicated to DXE Core"
|
||||
#string STR_MODULE_ABSTRACT #language en-US "Memory Profile Library instance dedicated to DXE Core"
|
||||
|
||||
#string STR_MODULE_DESCRIPTION #language en-US "The implementation borrows the DxeCore Memory Allocation/Profile services as the primitive for memory allocation/profile instead of using UEFI boot services or memory profile protocol in an indirect way. It is assumed that this library instance must be linked with DxeCore in this package."
|
||||
#string STR_MODULE_DESCRIPTION #language en-US "The implementation borrows the DxeCore Memory Profile services as the primitive for memory profile instead of using UEFI boot services or memory profile protocol in an indirect way. It is assumed that this library instance must be linked with DxeCore in this package."
|
||||
|
||||
|
|
|
@ -12,7 +12,6 @@
|
|||
#ifndef _DXE_CORE_MEMORY_ALLOCATION_SERVICES_H_
|
||||
#define _DXE_CORE_MEMORY_ALLOCATION_SERVICES_H_
|
||||
|
||||
|
||||
/**
|
||||
Allocates pages from the memory map.
|
||||
|
||||
|
@ -34,14 +33,12 @@
|
|||
EFI_STATUS
|
||||
EFIAPI
|
||||
CoreAllocatePages (
|
||||
IN EFI_ALLOCATE_TYPE Type,
|
||||
IN EFI_MEMORY_TYPE MemoryType,
|
||||
IN UINTN NumberOfPages,
|
||||
IN EFI_ALLOCATE_TYPE Type,
|
||||
IN EFI_MEMORY_TYPE MemoryType,
|
||||
IN UINTN NumberOfPages,
|
||||
IN OUT EFI_PHYSICAL_ADDRESS *Memory
|
||||
);
|
||||
|
||||
|
||||
|
||||
/**
|
||||
Frees previous allocated pages.
|
||||
|
||||
|
@ -56,11 +53,10 @@ CoreAllocatePages (
|
|||
EFI_STATUS
|
||||
EFIAPI
|
||||
CoreFreePages (
|
||||
IN EFI_PHYSICAL_ADDRESS Memory,
|
||||
IN UINTN NumberOfPages
|
||||
IN EFI_PHYSICAL_ADDRESS Memory,
|
||||
IN UINTN NumberOfPages
|
||||
);
|
||||
|
||||
|
||||
/**
|
||||
Allocate pool of a particular type.
|
||||
|
||||
|
@ -93,8 +89,8 @@ CoreAllocatePool (
|
|||
**/
|
||||
EFI_STATUS
|
||||
EFIAPI
|
||||
CoreFreePool(
|
||||
IN VOID *Buffer
|
||||
CoreFreePool (
|
||||
IN VOID *Buffer
|
||||
);
|
||||
|
||||
#endif
|
||||
|
|
|
@ -6,7 +6,6 @@
|
|||
|
||||
**/
|
||||
|
||||
|
||||
#include <PiDxe.h>
|
||||
|
||||
#include <Guid/MemoryProfile.h>
|
||||
|
@ -38,14 +37,13 @@
|
|||
EFI_STATUS
|
||||
EFIAPI
|
||||
MemoryProfileLibRecord (
|
||||
IN PHYSICAL_ADDRESS CallerAddress,
|
||||
IN MEMORY_PROFILE_ACTION Action,
|
||||
IN EFI_MEMORY_TYPE MemoryType,
|
||||
IN VOID *Buffer,
|
||||
IN UINTN Size,
|
||||
IN CHAR8 *ActionString OPTIONAL
|
||||
IN PHYSICAL_ADDRESS CallerAddress,
|
||||
IN MEMORY_PROFILE_ACTION Action,
|
||||
IN EFI_MEMORY_TYPE MemoryType,
|
||||
IN VOID *Buffer,
|
||||
IN UINTN Size,
|
||||
IN CHAR8 *ActionString OPTIONAL
|
||||
)
|
||||
{
|
||||
return CoreUpdateProfile (CallerAddress, Action, MemoryType, Size, Buffer, ActionString);
|
||||
}
|
||||
|
||||
|
|
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
|
@ -1,42 +0,0 @@
|
|||
## @file
|
||||
# Memory Allocation Library instance dedicated to SMM Core.
|
||||
# The implementation borrows the SMM Core Memory Allocation services as the primitive
|
||||
# for memory allocation instead of using SMM System Table services in an indirect way.
|
||||
# It is assumed that this library instance must be linked with SMM Cre in this package.
|
||||
#
|
||||
# Copyright (c) 2010 - 2016, Intel Corporation. All rights reserved.<BR>
|
||||
#
|
||||
# SPDX-License-Identifier: BSD-2-Clause-Patent
|
||||
#
|
||||
##
|
||||
|
||||
[Defines]
|
||||
INF_VERSION = 0x00010005
|
||||
BASE_NAME = PiSmmCoreMemoryAllocationLib
|
||||
MODULE_UNI_FILE = PiSmmCoreMemoryAllocationLib.uni
|
||||
FILE_GUID = B618E089-9ABA-4d97-AE80-57B5BCCDA51D
|
||||
MODULE_TYPE = SMM_CORE
|
||||
VERSION_STRING = 1.0
|
||||
PI_SPECIFICATION_VERSION = 0x0001000A
|
||||
LIBRARY_CLASS = MemoryAllocationLib|SMM_CORE
|
||||
CONSTRUCTOR = PiSmmCoreMemoryAllocationLibConstructor
|
||||
|
||||
#
|
||||
# The following information is for reference only and not required by the build tools.
|
||||
#
|
||||
# VALID_ARCHITECTURES = IA32 X64
|
||||
#
|
||||
|
||||
[Sources]
|
||||
MemoryAllocationLib.c
|
||||
PiSmmCoreMemoryAllocationServices.h
|
||||
PiSmmCoreMemoryProfileLibNull.c
|
||||
|
||||
[Packages]
|
||||
MdePkg/MdePkg.dec
|
||||
MdeModulePkg/MdeModulePkg.dec
|
||||
|
||||
[LibraryClasses]
|
||||
DebugLib
|
||||
BaseMemoryLib
|
||||
UefiBootServicesTableLib
|
|
@ -1,18 +0,0 @@
|
|||
// /** @file
|
||||
// Memory Allocation Library instance dedicated to SMM Core.
|
||||
//
|
||||
// The implementation borrows the SMM Core Memory Allocation services as the primitive
|
||||
// for memory allocation instead of using SMM System Table services in an indirect way.
|
||||
// It is assumed that this library instance must be linked with SMM Cre in this package.
|
||||
//
|
||||
// Copyright (c) 2010 - 2016, Intel Corporation. All rights reserved.<BR>
|
||||
//
|
||||
// SPDX-License-Identifier: BSD-2-Clause-Patent
|
||||
//
|
||||
// **/
|
||||
|
||||
|
||||
#string STR_MODULE_ABSTRACT #language en-US "Memory Allocation Library instance dedicated to SMM Core"
|
||||
|
||||
#string STR_MODULE_DESCRIPTION #language en-US "The implementation borrows the SMM Core Memory Allocation services as the primitive for memory allocation instead of using SMM System Table services in an indirect way. This library is only intended to be linked with the SMM Core that resides in this same package."
|
||||
|
|
@ -1,49 +0,0 @@
|
|||
## @file
|
||||
# Memory Allocation/Profile Library instance dedicated to SMM Core.
|
||||
# The implementation borrows the SMM Core Memory Allocation/Profile services as the primitive
|
||||
# for memory allocation/profile instead of using SMM System Table servces or SMM memory profile protocol in an indirect way.
|
||||
# It is assumed that this library instance must be linked with SMM Cre in this package.
|
||||
#
|
||||
# Copyright (c) 2010 - 2016, Intel Corporation. All rights reserved.<BR>
|
||||
#
|
||||
# SPDX-License-Identifier: BSD-2-Clause-Patent
|
||||
#
|
||||
##
|
||||
|
||||
[Defines]
|
||||
INF_VERSION = 0x00010005
|
||||
BASE_NAME = PiSmmCoreMemoryAllocationProfileLib
|
||||
MODULE_UNI_FILE = PiSmmCoreMemoryAllocationProfileLib.uni
|
||||
FILE_GUID = D55E42AD-3E63-4536-8281-82C0F1098C5E
|
||||
MODULE_TYPE = SMM_CORE
|
||||
VERSION_STRING = 1.0
|
||||
PI_SPECIFICATION_VERSION = 0x0001000A
|
||||
LIBRARY_CLASS = MemoryAllocationLib|SMM_CORE
|
||||
CONSTRUCTOR = PiSmmCoreMemoryAllocationLibConstructor
|
||||
LIBRARY_CLASS = MemoryProfileLib|SMM_CORE
|
||||
CONSTRUCTOR = PiSmmCoreMemoryProfileLibConstructor
|
||||
|
||||
#
|
||||
# The following information is for reference only and not required by the build tools.
|
||||
#
|
||||
# VALID_ARCHITECTURES = IA32 X64
|
||||
#
|
||||
|
||||
[Sources]
|
||||
MemoryAllocationLib.c
|
||||
PiSmmCoreMemoryAllocationServices.h
|
||||
PiSmmCoreMemoryProfileLib.c
|
||||
PiSmmCoreMemoryProfileServices.h
|
||||
|
||||
[Packages]
|
||||
MdePkg/MdePkg.dec
|
||||
MdeModulePkg/MdeModulePkg.dec
|
||||
|
||||
[LibraryClasses]
|
||||
DebugLib
|
||||
BaseMemoryLib
|
||||
UefiBootServicesTableLib
|
||||
|
||||
[Guids]
|
||||
gEdkiiMemoryProfileGuid ## SOMETIMES_CONSUMES ## GUID # Locate protocol
|
||||
|
|
@ -1,18 +0,0 @@
|
|||
// /** @file
|
||||
// Memory Allocation/Profile Library instance dedicated to SMM Core.
|
||||
//
|
||||
// The implementation borrows the SMM Core Memory Allocation/Profile services as the primitive
|
||||
// for memory allocation/profile instead of using SMM System Table servces or SMM memory profile protocol in an indirect way.
|
||||
// It is assumed that this library instance must be linked with SMM Cre in this package.
|
||||
//
|
||||
// Copyright (c) 2010 - 2016, Intel Corporation. All rights reserved.<BR>
|
||||
//
|
||||
// SPDX-License-Identifier: BSD-2-Clause-Patent
|
||||
//
|
||||
// **/
|
||||
|
||||
|
||||
#string STR_MODULE_ABSTRACT #language en-US "Memory Allocation/Profile Library instance dedicated to SMM Core"
|
||||
|
||||
#string STR_MODULE_DESCRIPTION #language en-US "The implementation borrows the SMM Core Memory Allocation/Profile services as the primitive for memory allocation/profile instead of using SMM System Table services or SMM memory profile protocol in an indirect way. This library is only intended to be linked with the SMM Core that resides in this same package."
|
||||
|
|
@ -1,185 +0,0 @@
|
|||
/** @file
|
||||
Contains function prototypes for Memory Services in the SMM Core.
|
||||
|
||||
This header file borrows the PiSmmCore Memory Allocation services as the primitive
|
||||
for memory allocation.
|
||||
|
||||
Copyright (c) 2008 - 2018, Intel Corporation. All rights reserved.<BR>
|
||||
SPDX-License-Identifier: BSD-2-Clause-Patent
|
||||
|
||||
**/
|
||||
|
||||
#ifndef _PI_SMM_CORE_MEMORY_ALLOCATION_SERVICES_H_
|
||||
#define _PI_SMM_CORE_MEMORY_ALLOCATION_SERVICES_H_
|
||||
|
||||
//
|
||||
// It should be aligned with the definition in PiSmmCore.
|
||||
//
|
||||
typedef struct {
|
||||
UINTN Signature;
|
||||
|
||||
///
|
||||
/// The ImageHandle passed into the entry point of the SMM IPL. This ImageHandle
|
||||
/// is used by the SMM Core to fill in the ParentImageHandle field of the Loaded
|
||||
/// Image Protocol for each SMM Driver that is dispatched by the SMM Core.
|
||||
///
|
||||
EFI_HANDLE SmmIplImageHandle;
|
||||
|
||||
///
|
||||
/// The number of SMRAM ranges passed from the SMM IPL to the SMM Core. The SMM
|
||||
/// Core uses these ranges of SMRAM to initialize the SMM Core memory manager.
|
||||
///
|
||||
UINTN SmramRangeCount;
|
||||
|
||||
///
|
||||
/// A table of SMRAM ranges passed from the SMM IPL to the SMM Core. The SMM
|
||||
/// Core uses these ranges of SMRAM to initialize the SMM Core memory manager.
|
||||
///
|
||||
EFI_SMRAM_DESCRIPTOR *SmramRanges;
|
||||
|
||||
///
|
||||
/// The SMM Foundation Entry Point. The SMM Core fills in this field when the
|
||||
/// SMM Core is initialized. The SMM IPL is responsbile for registering this entry
|
||||
/// point with the SMM Configuration Protocol. The SMM Configuration Protocol may
|
||||
/// not be available at the time the SMM IPL and SMM Core are started, so the SMM IPL
|
||||
/// sets up a protocol notification on the SMM Configuration Protocol and registers
|
||||
/// the SMM Foundation Entry Point as soon as the SMM Configuration Protocol is
|
||||
/// available.
|
||||
///
|
||||
EFI_SMM_ENTRY_POINT SmmEntryPoint;
|
||||
|
||||
///
|
||||
/// Boolean flag set to TRUE while an SMI is being processed by the SMM Core.
|
||||
///
|
||||
BOOLEAN SmmEntryPointRegistered;
|
||||
|
||||
///
|
||||
/// Boolean flag set to TRUE while an SMI is being processed by the SMM Core.
|
||||
///
|
||||
BOOLEAN InSmm;
|
||||
|
||||
///
|
||||
/// This field is set by the SMM Core then the SMM Core is initialized. This field is
|
||||
/// used by the SMM Base 2 Protocol and SMM Communication Protocol implementations in
|
||||
/// the SMM IPL.
|
||||
///
|
||||
EFI_SMM_SYSTEM_TABLE2 *Smst;
|
||||
|
||||
///
|
||||
/// This field is used by the SMM Communicatioon Protocol to pass a buffer into
|
||||
/// a software SMI handler and for the software SMI handler to pass a buffer back to
|
||||
/// the caller of the SMM Communication Protocol.
|
||||
///
|
||||
VOID *CommunicationBuffer;
|
||||
|
||||
///
|
||||
/// This field is used by the SMM Communicatioon Protocol to pass the size of a buffer,
|
||||
/// in bytes, into a software SMI handler and for the software SMI handler to pass the
|
||||
/// size, in bytes, of a buffer back to the caller of the SMM Communication Protocol.
|
||||
///
|
||||
UINTN BufferSize;
|
||||
|
||||
///
|
||||
/// This field is used by the SMM Communication Protocol to pass the return status from
|
||||
/// a software SMI handler back to the caller of the SMM Communication Protocol.
|
||||
///
|
||||
EFI_STATUS ReturnStatus;
|
||||
|
||||
EFI_PHYSICAL_ADDRESS PiSmmCoreImageBase;
|
||||
UINT64 PiSmmCoreImageSize;
|
||||
EFI_PHYSICAL_ADDRESS PiSmmCoreEntryPoint;
|
||||
} SMM_CORE_PRIVATE_DATA;
|
||||
|
||||
/**
|
||||
Called to initialize the memory service.
|
||||
|
||||
@param SmramRangeCount Number of SMRAM Regions
|
||||
@param SmramRanges Pointer to SMRAM Descriptors
|
||||
|
||||
**/
|
||||
VOID
|
||||
SmmInitializeMemoryServices (
|
||||
IN UINTN SmramRangeCount,
|
||||
IN EFI_SMRAM_DESCRIPTOR *SmramRanges
|
||||
);
|
||||
|
||||
/**
|
||||
Allocates pages from the memory map.
|
||||
|
||||
@param Type The type of allocation to perform
|
||||
@param MemoryType The type of memory to turn the allocated pages
|
||||
into
|
||||
@param NumberOfPages The number of pages to allocate
|
||||
@param Memory A pointer to receive the base allocated memory
|
||||
address
|
||||
|
||||
@retval EFI_INVALID_PARAMETER Parameters violate checking rules defined in spec.
|
||||
@retval EFI_NOT_FOUND Could not allocate pages match the requirement.
|
||||
@retval EFI_OUT_OF_RESOURCES No enough pages to allocate.
|
||||
@retval EFI_SUCCESS Pages successfully allocated.
|
||||
|
||||
**/
|
||||
EFI_STATUS
|
||||
EFIAPI
|
||||
SmmAllocatePages (
|
||||
IN EFI_ALLOCATE_TYPE Type,
|
||||
IN EFI_MEMORY_TYPE MemoryType,
|
||||
IN UINTN NumberOfPages,
|
||||
OUT EFI_PHYSICAL_ADDRESS *Memory
|
||||
);
|
||||
|
||||
/**
|
||||
Frees previous allocated pages.
|
||||
|
||||
@param Memory Base address of memory being freed
|
||||
@param NumberOfPages The number of pages to free
|
||||
|
||||
@retval EFI_NOT_FOUND Could not find the entry that covers the range
|
||||
@retval EFI_INVALID_PARAMETER Address not aligned
|
||||
@return EFI_SUCCESS Pages successfully freed.
|
||||
|
||||
**/
|
||||
EFI_STATUS
|
||||
EFIAPI
|
||||
SmmFreePages (
|
||||
IN EFI_PHYSICAL_ADDRESS Memory,
|
||||
IN UINTN NumberOfPages
|
||||
);
|
||||
|
||||
/**
|
||||
Allocate pool of a particular type.
|
||||
|
||||
@param PoolType Type of pool to allocate
|
||||
@param Size The amount of pool to allocate
|
||||
@param Buffer The address to return a pointer to the allocated
|
||||
pool
|
||||
|
||||
@retval EFI_INVALID_PARAMETER PoolType not valid
|
||||
@retval EFI_OUT_OF_RESOURCES Size exceeds max pool size or allocation failed.
|
||||
@retval EFI_SUCCESS Pool successfully allocated.
|
||||
|
||||
**/
|
||||
EFI_STATUS
|
||||
EFIAPI
|
||||
SmmAllocatePool (
|
||||
IN EFI_MEMORY_TYPE PoolType,
|
||||
IN UINTN Size,
|
||||
OUT VOID **Buffer
|
||||
);
|
||||
|
||||
/**
|
||||
Frees pool.
|
||||
|
||||
@param Buffer The allocated pool entry to free
|
||||
|
||||
@retval EFI_INVALID_PARAMETER Buffer is not a valid value.
|
||||
@retval EFI_SUCCESS Pool successfully freed.
|
||||
|
||||
**/
|
||||
EFI_STATUS
|
||||
EFIAPI
|
||||
SmmFreePool(
|
||||
IN VOID *Buffer
|
||||
);
|
||||
|
||||
#endif
|
|
@ -1,117 +0,0 @@
|
|||
/** @file
|
||||
Support routines for memory profile for PiSmmCore.
|
||||
|
||||
Copyright (c) 2016 - 2018, Intel Corporation. All rights reserved.<BR>
|
||||
SPDX-License-Identifier: BSD-2-Clause-Patent
|
||||
|
||||
**/
|
||||
|
||||
#include <PiSmm.h>
|
||||
|
||||
#include <Library/UefiBootServicesTableLib.h>
|
||||
#include <Library/DebugLib.h>
|
||||
|
||||
#include <Guid/MemoryProfile.h>
|
||||
|
||||
#include "PiSmmCoreMemoryProfileServices.h"
|
||||
|
||||
EDKII_MEMORY_PROFILE_PROTOCOL *mLibProfileProtocol;
|
||||
|
||||
/**
|
||||
Check whether the start address of buffer is within any of the SMRAM ranges.
|
||||
|
||||
@param[in] Buffer The pointer to the buffer to be checked.
|
||||
|
||||
@retval TRUE The buffer is in SMRAM ranges.
|
||||
@retval FALSE The buffer is out of SMRAM ranges.
|
||||
**/
|
||||
BOOLEAN
|
||||
EFIAPI
|
||||
BufferInSmram (
|
||||
IN VOID *Buffer
|
||||
);
|
||||
|
||||
/**
|
||||
The constructor function initializes memory profile for SMM phase.
|
||||
|
||||
@param ImageHandle The firmware allocated handle for the EFI image.
|
||||
@param SystemTable A pointer to the EFI System Table.
|
||||
|
||||
@retval EFI_SUCCESS The constructor always returns EFI_SUCCESS.
|
||||
|
||||
**/
|
||||
EFI_STATUS
|
||||
EFIAPI
|
||||
PiSmmCoreMemoryProfileLibConstructor (
|
||||
IN EFI_HANDLE ImageHandle,
|
||||
IN EFI_SYSTEM_TABLE *SystemTable
|
||||
)
|
||||
{
|
||||
EFI_STATUS Status;
|
||||
|
||||
//
|
||||
// Locate Profile Protocol
|
||||
//
|
||||
Status = gBS->LocateProtocol (
|
||||
&gEdkiiMemoryProfileGuid,
|
||||
NULL,
|
||||
(VOID **)&mLibProfileProtocol
|
||||
);
|
||||
if (EFI_ERROR(Status)) {
|
||||
mLibProfileProtocol = NULL;
|
||||
}
|
||||
|
||||
return EFI_SUCCESS;
|
||||
}
|
||||
|
||||
/**
|
||||
Record memory profile of multilevel caller.
|
||||
|
||||
@param[in] CallerAddress Address of caller.
|
||||
@param[in] Action Memory profile action.
|
||||
@param[in] MemoryType Memory type.
|
||||
EfiMaxMemoryType means the MemoryType is unknown.
|
||||
@param[in] Buffer Buffer address.
|
||||
@param[in] Size Buffer size.
|
||||
@param[in] ActionString String for memory profile action.
|
||||
Only needed for user defined allocate action.
|
||||
|
||||
@return EFI_SUCCESS Memory profile is updated.
|
||||
@return EFI_UNSUPPORTED Memory profile is unsupported,
|
||||
or memory profile for the image is not required,
|
||||
or memory profile for the memory type is not required.
|
||||
@return EFI_ACCESS_DENIED It is during memory profile data getting.
|
||||
@return EFI_ABORTED Memory profile recording is not enabled.
|
||||
@return EFI_OUT_OF_RESOURCES No enough resource to update memory profile for allocate action.
|
||||
@return EFI_NOT_FOUND No matched allocate info found for free action.
|
||||
|
||||
**/
|
||||
EFI_STATUS
|
||||
EFIAPI
|
||||
MemoryProfileLibRecord (
|
||||
IN PHYSICAL_ADDRESS CallerAddress,
|
||||
IN MEMORY_PROFILE_ACTION Action,
|
||||
IN EFI_MEMORY_TYPE MemoryType,
|
||||
IN VOID *Buffer,
|
||||
IN UINTN Size,
|
||||
IN CHAR8 *ActionString OPTIONAL
|
||||
)
|
||||
{
|
||||
if (BufferInSmram (Buffer)) {
|
||||
return SmmCoreUpdateProfile (CallerAddress, Action, MemoryType, Size, Buffer, ActionString);
|
||||
} else {
|
||||
if (mLibProfileProtocol == NULL) {
|
||||
return EFI_UNSUPPORTED;
|
||||
}
|
||||
return mLibProfileProtocol->Record (
|
||||
mLibProfileProtocol,
|
||||
CallerAddress,
|
||||
Action,
|
||||
MemoryType,
|
||||
Buffer,
|
||||
Size,
|
||||
ActionString
|
||||
);
|
||||
}
|
||||
}
|
||||
|
|
@ -1,48 +0,0 @@
|
|||
/** @file
|
||||
Null routines for memory profile for PiSmmCore.
|
||||
|
||||
Copyright (c) 2016 - 2018, Intel Corporation. All rights reserved.<BR>
|
||||
SPDX-License-Identifier: BSD-2-Clause-Patent
|
||||
|
||||
**/
|
||||
|
||||
#include <PiSmm.h>
|
||||
|
||||
#include <Guid/MemoryProfile.h>
|
||||
|
||||
/**
|
||||
Record memory profile of multilevel caller.
|
||||
|
||||
@param[in] CallerAddress Address of caller.
|
||||
@param[in] Action Memory profile action.
|
||||
@param[in] MemoryType Memory type.
|
||||
EfiMaxMemoryType means the MemoryType is unknown.
|
||||
@param[in] Buffer Buffer address.
|
||||
@param[in] Size Buffer size.
|
||||
@param[in] ActionString String for memory profile action.
|
||||
Only needed for user defined allocate action.
|
||||
|
||||
@return EFI_SUCCESS Memory profile is updated.
|
||||
@return EFI_UNSUPPORTED Memory profile is unsupported,
|
||||
or memory profile for the image is not required,
|
||||
or memory profile for the memory type is not required.
|
||||
@return EFI_ACCESS_DENIED It is during memory profile data getting.
|
||||
@return EFI_ABORTED Memory profile recording is not enabled.
|
||||
@return EFI_OUT_OF_RESOURCES No enough resource to update memory profile for allocate action.
|
||||
@return EFI_NOT_FOUND No matched allocate info found for free action.
|
||||
|
||||
**/
|
||||
EFI_STATUS
|
||||
EFIAPI
|
||||
MemoryProfileLibRecord (
|
||||
IN PHYSICAL_ADDRESS CallerAddress,
|
||||
IN MEMORY_PROFILE_ACTION Action,
|
||||
IN EFI_MEMORY_TYPE MemoryType,
|
||||
IN VOID *Buffer,
|
||||
IN UINTN Size,
|
||||
IN CHAR8 *ActionString OPTIONAL
|
||||
)
|
||||
{
|
||||
return EFI_UNSUPPORTED;
|
||||
}
|
||||
|
|
@ -1,48 +0,0 @@
|
|||
/** @file
|
||||
Contains function prototypes for Memory Profile Services in the SMM Core.
|
||||
|
||||
This header file borrows the PiSmmCore Memory Profile services as the primitive
|
||||
for memory profile.
|
||||
|
||||
Copyright (c) 2016 - 2018, Intel Corporation. All rights reserved.<BR>
|
||||
SPDX-License-Identifier: BSD-2-Clause-Patent
|
||||
|
||||
**/
|
||||
|
||||
#ifndef _PI_SMM_CORE_MEMORY_PROFILE_SERVICES_H_
|
||||
#define _PI_SMM_CORE_MEMORY_PROFILE_SERVICES_H_
|
||||
|
||||
/**
|
||||
Update SMRAM profile information.
|
||||
|
||||
@param CallerAddress Address of caller who call Allocate or Free.
|
||||
@param Action This Allocate or Free action.
|
||||
@param MemoryType Memory type.
|
||||
EfiMaxMemoryType means the MemoryType is unknown.
|
||||
@param Size Buffer size.
|
||||
@param Buffer Buffer address.
|
||||
@param ActionString String for memory profile action.
|
||||
Only needed for user defined allocate action.
|
||||
|
||||
@return EFI_SUCCESS Memory profile is updated.
|
||||
@return EFI_UNSUPPORTED Memory profile is unsupported,
|
||||
or memory profile for the image is not required,
|
||||
or memory profile for the memory type is not required.
|
||||
@return EFI_ACCESS_DENIED It is during memory profile data getting.
|
||||
@return EFI_ABORTED Memory profile recording is not enabled.
|
||||
@return EFI_OUT_OF_RESOURCES No enough resource to update memory profile for allocate action.
|
||||
@return EFI_NOT_FOUND No matched allocate info found for free action.
|
||||
|
||||
**/
|
||||
EFI_STATUS
|
||||
EFIAPI
|
||||
SmmCoreUpdateProfile (
|
||||
IN PHYSICAL_ADDRESS CallerAddress,
|
||||
IN MEMORY_PROFILE_ACTION Action,
|
||||
IN EFI_MEMORY_TYPE MemoryType, // Valid for AllocatePages/AllocatePool
|
||||
IN UINTN Size, // Valid for AllocatePages/FreePages/AllocatePool
|
||||
IN VOID *Buffer,
|
||||
IN CHAR8 *ActionString OPTIONAL
|
||||
);
|
||||
|
||||
#endif
|
File diff suppressed because it is too large
Load Diff
|
@ -1,57 +0,0 @@
|
|||
## @file
|
||||
# Instance of Memory Allocation Library using SMM Services Table,
|
||||
# with memory profile support.
|
||||
#
|
||||
# Memory Allocation Library that uses services from the SMM Services Table to
|
||||
# allocate and free memory, with memory profile support.
|
||||
#
|
||||
# The implementation of this instance is copied from UefiMemoryAllocationLib
|
||||
# in MdePkg and updated to support both MemoryAllocationLib and MemoryProfileLib.
|
||||
#
|
||||
# Copyright (c) 2010 - 2018, Intel Corporation. All rights reserved.<BR>
|
||||
# SPDX-License-Identifier: BSD-2-Clause-Patent
|
||||
#
|
||||
##
|
||||
|
||||
[Defines]
|
||||
INF_VERSION = 0x00010005
|
||||
BASE_NAME = SmmMemoryAllocationProfileLib
|
||||
MODULE_UNI_FILE = SmmMemoryAllocationProfileLib.uni
|
||||
FILE_GUID = DC50729F-8633-47ab-8FD3-6939688CEE4C
|
||||
MODULE_TYPE = DXE_SMM_DRIVER
|
||||
VERSION_STRING = 1.0
|
||||
PI_SPECIFICATION_VERSION = 0x0001000A
|
||||
LIBRARY_CLASS = MemoryAllocationLib|DXE_SMM_DRIVER
|
||||
CONSTRUCTOR = SmmMemoryAllocationLibConstructor
|
||||
DESTRUCTOR = SmmMemoryAllocationLibDestructor
|
||||
LIBRARY_CLASS = MemoryProfileLib|DXE_SMM_DRIVER
|
||||
CONSTRUCTOR = SmmMemoryProfileLibConstructor
|
||||
|
||||
#
|
||||
# VALID_ARCHITECTURES = IA32 X64
|
||||
#
|
||||
|
||||
[Sources]
|
||||
MemoryAllocationLib.c
|
||||
SmmMemoryProfileLib.c
|
||||
|
||||
[Packages]
|
||||
MdePkg/MdePkg.dec
|
||||
MdeModulePkg/MdeModulePkg.dec
|
||||
|
||||
[LibraryClasses]
|
||||
DebugLib
|
||||
BaseMemoryLib
|
||||
SmmServicesTableLib
|
||||
UefiBootServicesTableLib
|
||||
|
||||
[Protocols]
|
||||
gEfiSmmAccess2ProtocolGuid ## CONSUMES
|
||||
|
||||
[Guids]
|
||||
gEdkiiMemoryProfileGuid ## SOMETIMES_CONSUMES ## GUID # Locate protocol
|
||||
gEdkiiSmmMemoryProfileGuid ## SOMETIMES_CONSUMES ## GUID # Locate protocol
|
||||
|
||||
[Depex]
|
||||
gEfiSmmAccess2ProtocolGuid
|
||||
|
|
@ -1,18 +0,0 @@
|
|||
// /** @file
|
||||
// Instance of Memory Allocation Library using SMM Services Table,
|
||||
// with memory profile support.
|
||||
//
|
||||
// Memory Allocation Library that uses services from the SMM Services Table to
|
||||
// allocate and free memory, with memory profile support.
|
||||
//
|
||||
// Copyright (c) 2010 - 2016, Intel Corporation. All rights reserved.<BR>
|
||||
//
|
||||
// SPDX-License-Identifier: BSD-2-Clause-Patent
|
||||
//
|
||||
// **/
|
||||
|
||||
|
||||
#string STR_MODULE_ABSTRACT #language en-US "Instance of Memory Allocation Library using SMM Services Table, with memory profile support"
|
||||
|
||||
#string STR_MODULE_DESCRIPTION #language en-US "This Memory Allocation Library uses services from the SMM Services Table to allocate and free memory, with memory profile support."
|
||||
|
|
@ -1,137 +0,0 @@
|
|||
/** @file
|
||||
Support routines for memory profile for Smm phase drivers.
|
||||
|
||||
Copyright (c) 2016 - 2018, Intel Corporation. All rights reserved.<BR>
|
||||
SPDX-License-Identifier: BSD-2-Clause-Patent
|
||||
|
||||
**/
|
||||
|
||||
#include <PiSmm.h>
|
||||
|
||||
#include <Library/UefiBootServicesTableLib.h>
|
||||
#include <Library/SmmServicesTableLib.h>
|
||||
#include <Library/DebugLib.h>
|
||||
|
||||
#include <Guid/MemoryProfile.h>
|
||||
|
||||
EDKII_MEMORY_PROFILE_PROTOCOL *mLibProfileProtocol;
|
||||
EDKII_SMM_MEMORY_PROFILE_PROTOCOL *mLibSmmProfileProtocol;
|
||||
|
||||
/**
|
||||
Check whether the start address of buffer is within any of the SMRAM ranges.
|
||||
|
||||
@param[in] Buffer The pointer to the buffer to be checked.
|
||||
|
||||
@retval TRUE The buffer is in SMRAM ranges.
|
||||
@retval FALSE The buffer is out of SMRAM ranges.
|
||||
**/
|
||||
BOOLEAN
|
||||
EFIAPI
|
||||
BufferInSmram (
|
||||
IN VOID *Buffer
|
||||
);
|
||||
|
||||
/**
|
||||
The constructor function initializes memory profile for SMM phase.
|
||||
|
||||
@param ImageHandle The firmware allocated handle for the EFI image.
|
||||
@param SystemTable A pointer to the EFI System Table.
|
||||
|
||||
@retval EFI_SUCCESS The constructor always returns EFI_SUCCESS.
|
||||
|
||||
**/
|
||||
EFI_STATUS
|
||||
EFIAPI
|
||||
SmmMemoryProfileLibConstructor (
|
||||
IN EFI_HANDLE ImageHandle,
|
||||
IN EFI_SYSTEM_TABLE *SystemTable
|
||||
)
|
||||
{
|
||||
EFI_STATUS Status;
|
||||
|
||||
//
|
||||
// Locate Profile Protocol
|
||||
//
|
||||
Status = gBS->LocateProtocol (
|
||||
&gEdkiiMemoryProfileGuid,
|
||||
NULL,
|
||||
(VOID **)&mLibProfileProtocol
|
||||
);
|
||||
if (EFI_ERROR(Status)) {
|
||||
mLibProfileProtocol = NULL;
|
||||
}
|
||||
|
||||
Status = gSmst->SmmLocateProtocol (
|
||||
&gEdkiiSmmMemoryProfileGuid,
|
||||
NULL,
|
||||
(VOID **)&mLibSmmProfileProtocol
|
||||
);
|
||||
if (EFI_ERROR(Status)) {
|
||||
mLibSmmProfileProtocol = NULL;
|
||||
}
|
||||
|
||||
return EFI_SUCCESS;
|
||||
}
|
||||
|
||||
/**
|
||||
Record memory profile of multilevel caller.
|
||||
|
||||
@param[in] CallerAddress Address of caller.
|
||||
@param[in] Action Memory profile action.
|
||||
@param[in] MemoryType Memory type.
|
||||
EfiMaxMemoryType means the MemoryType is unknown.
|
||||
@param[in] Buffer Buffer address.
|
||||
@param[in] Size Buffer size.
|
||||
@param[in] ActionString String for memory profile action.
|
||||
Only needed for user defined allocate action.
|
||||
|
||||
@return EFI_SUCCESS Memory profile is updated.
|
||||
@return EFI_UNSUPPORTED Memory profile is unsupported,
|
||||
or memory profile for the image is not required,
|
||||
or memory profile for the memory type is not required.
|
||||
@return EFI_ACCESS_DENIED It is during memory profile data getting.
|
||||
@return EFI_ABORTED Memory profile recording is not enabled.
|
||||
@return EFI_OUT_OF_RESOURCES No enough resource to update memory profile for allocate action.
|
||||
@return EFI_NOT_FOUND No matched allocate info found for free action.
|
||||
|
||||
**/
|
||||
EFI_STATUS
|
||||
EFIAPI
|
||||
MemoryProfileLibRecord (
|
||||
IN PHYSICAL_ADDRESS CallerAddress,
|
||||
IN MEMORY_PROFILE_ACTION Action,
|
||||
IN EFI_MEMORY_TYPE MemoryType,
|
||||
IN VOID *Buffer,
|
||||
IN UINTN Size,
|
||||
IN CHAR8 *ActionString OPTIONAL
|
||||
)
|
||||
{
|
||||
if (BufferInSmram (Buffer)) {
|
||||
if (mLibSmmProfileProtocol == NULL) {
|
||||
return EFI_UNSUPPORTED;
|
||||
}
|
||||
return mLibSmmProfileProtocol->Record (
|
||||
mLibSmmProfileProtocol,
|
||||
CallerAddress,
|
||||
Action,
|
||||
MemoryType,
|
||||
Buffer,
|
||||
Size,
|
||||
ActionString
|
||||
);
|
||||
} else {
|
||||
if (mLibProfileProtocol == NULL) {
|
||||
return EFI_UNSUPPORTED;
|
||||
}
|
||||
return mLibProfileProtocol->Record (
|
||||
mLibProfileProtocol,
|
||||
CallerAddress,
|
||||
Action,
|
||||
MemoryType,
|
||||
Buffer,
|
||||
Size,
|
||||
ActionString
|
||||
);
|
||||
}
|
||||
}
|
||||
|
|
@ -1,96 +0,0 @@
|
|||
/** @file
|
||||
Support routines for memory profile for Dxe phase drivers.
|
||||
|
||||
Copyright (c) 2016 - 2018, Intel Corporation. All rights reserved.<BR>
|
||||
SPDX-License-Identifier: BSD-2-Clause-Patent
|
||||
|
||||
**/
|
||||
|
||||
|
||||
#include <Uefi.h>
|
||||
|
||||
|
||||
#include <Library/UefiBootServicesTableLib.h>
|
||||
#include <Library/DebugLib.h>
|
||||
|
||||
#include <Guid/MemoryProfile.h>
|
||||
|
||||
EDKII_MEMORY_PROFILE_PROTOCOL *mLibProfileProtocol;
|
||||
|
||||
/**
|
||||
The constructor function initializes memory profile for DXE phase.
|
||||
|
||||
@param ImageHandle The firmware allocated handle for the EFI image.
|
||||
@param SystemTable A pointer to the EFI System Table.
|
||||
|
||||
@retval EFI_SUCCESS The constructor always returns EFI_SUCCESS.
|
||||
|
||||
**/
|
||||
EFI_STATUS
|
||||
EFIAPI
|
||||
MemoryProfileLibConstructor (
|
||||
IN EFI_HANDLE ImageHandle,
|
||||
IN EFI_SYSTEM_TABLE *SystemTable
|
||||
)
|
||||
{
|
||||
EFI_STATUS Status;
|
||||
|
||||
Status = gBS->LocateProtocol (
|
||||
&gEdkiiMemoryProfileGuid,
|
||||
NULL,
|
||||
(VOID **) &mLibProfileProtocol
|
||||
);
|
||||
if (EFI_ERROR(Status)) {
|
||||
mLibProfileProtocol = NULL;
|
||||
}
|
||||
|
||||
return EFI_SUCCESS;
|
||||
}
|
||||
|
||||
/**
|
||||
Record memory profile of multilevel caller.
|
||||
|
||||
@param[in] CallerAddress Address of caller.
|
||||
@param[in] Action Memory profile action.
|
||||
@param[in] MemoryType Memory type.
|
||||
EfiMaxMemoryType means the MemoryType is unknown.
|
||||
@param[in] Buffer Buffer address.
|
||||
@param[in] Size Buffer size.
|
||||
@param[in] ActionString String for memory profile action.
|
||||
Only needed for user defined allocate action.
|
||||
|
||||
@return EFI_SUCCESS Memory profile is updated.
|
||||
@return EFI_UNSUPPORTED Memory profile is unsupported,
|
||||
or memory profile for the image is not required,
|
||||
or memory profile for the memory type is not required.
|
||||
@return EFI_ACCESS_DENIED It is during memory profile data getting.
|
||||
@return EFI_ABORTED Memory profile recording is not enabled.
|
||||
@return EFI_OUT_OF_RESOURCES No enough resource to update memory profile for allocate action.
|
||||
@return EFI_NOT_FOUND No matched allocate info found for free action.
|
||||
|
||||
**/
|
||||
EFI_STATUS
|
||||
EFIAPI
|
||||
MemoryProfileLibRecord (
|
||||
IN PHYSICAL_ADDRESS CallerAddress,
|
||||
IN MEMORY_PROFILE_ACTION Action,
|
||||
IN EFI_MEMORY_TYPE MemoryType,
|
||||
IN VOID *Buffer,
|
||||
IN UINTN Size,
|
||||
IN CHAR8 *ActionString OPTIONAL
|
||||
)
|
||||
{
|
||||
if (mLibProfileProtocol == NULL) {
|
||||
return EFI_UNSUPPORTED;
|
||||
}
|
||||
return mLibProfileProtocol->Record (
|
||||
mLibProfileProtocol,
|
||||
CallerAddress,
|
||||
Action,
|
||||
MemoryType,
|
||||
Buffer,
|
||||
Size,
|
||||
ActionString
|
||||
);
|
||||
}
|
||||
|
|
@ -1,48 +0,0 @@
|
|||
## @file
|
||||
# Instance of Memory Allocation Library using EFI Boot Services,
|
||||
# with memory profile support.
|
||||
#
|
||||
# Memory Allocation Library that uses EFI Boot Services to allocate
|
||||
# and free memory, with memory profile support.
|
||||
#
|
||||
# The implementation of this instance is copied from UefiMemoryAllocationLib
|
||||
# in MdePkg and updated to support both MemoryAllocationLib and MemoryProfileLib.
|
||||
#
|
||||
# Copyright (c) 2007 - 2018, Intel Corporation. All rights reserved.<BR>
|
||||
#
|
||||
# SPDX-License-Identifier: BSD-2-Clause-Patent
|
||||
#
|
||||
#
|
||||
##
|
||||
|
||||
[Defines]
|
||||
INF_VERSION = 0x00010005
|
||||
BASE_NAME = UefiMemoryAllocationProfileLib
|
||||
MODULE_UNI_FILE = UefiMemoryAllocationProfileLib.uni
|
||||
FILE_GUID = 9E8A380A-231E-41E4-AD40-5E706196B853
|
||||
MODULE_TYPE = UEFI_DRIVER
|
||||
VERSION_STRING = 1.0
|
||||
LIBRARY_CLASS = MemoryAllocationLib|DXE_DRIVER DXE_RUNTIME_DRIVER DXE_SMM_DRIVER UEFI_APPLICATION UEFI_DRIVER
|
||||
LIBRARY_CLASS = MemoryProfileLib|DXE_DRIVER DXE_RUNTIME_DRIVER DXE_SMM_DRIVER UEFI_APPLICATION UEFI_DRIVER
|
||||
CONSTRUCTOR = MemoryProfileLibConstructor
|
||||
|
||||
#
|
||||
# VALID_ARCHITECTURES = IA32 X64 EBC
|
||||
#
|
||||
|
||||
[Sources]
|
||||
MemoryAllocationLib.c
|
||||
DxeMemoryProfileLib.c
|
||||
|
||||
[Packages]
|
||||
MdePkg/MdePkg.dec
|
||||
MdeModulePkg/MdeModulePkg.dec
|
||||
|
||||
[LibraryClasses]
|
||||
DebugLib
|
||||
BaseMemoryLib
|
||||
UefiBootServicesTableLib
|
||||
|
||||
[Guids]
|
||||
gEdkiiMemoryProfileGuid ## SOMETIMES_CONSUMES ## GUID # Locate protocol
|
||||
|
|
@ -1,18 +0,0 @@
|
|||
// /** @file
|
||||
// Instance of Memory Allocation Library using EFI Boot Services,
|
||||
// with memory profile support.
|
||||
//
|
||||
// Memory Allocation Library that uses EFI Boot Services to allocate
|
||||
// and free memory, with memory profile support.
|
||||
//
|
||||
// Copyright (c) 2007 - 2016, Intel Corporation. All rights reserved.<BR>
|
||||
//
|
||||
// SPDX-License-Identifier: BSD-2-Clause-Patent
|
||||
//
|
||||
// **/
|
||||
|
||||
|
||||
#string STR_MODULE_ABSTRACT #language en-US "Instance of Memory Allocation Library using EFI Boot Services, with memory profile support"
|
||||
|
||||
#string STR_MODULE_DESCRIPTION #language en-US "This Memory Allocation Library uses EFI Boot Services to allocate and free memory, with memory profile support."
|
||||
|
|
@ -0,0 +1,410 @@
|
|||
/** @file -- VariablePolicyHelperLib.c
|
||||
This library contains helper functions for marshalling and registering
|
||||
new policies with the VariablePolicy infrastructure.
|
||||
|
||||
This library is currently written against VariablePolicy revision 0x00010000.
|
||||
|
||||
Copyright (c) Microsoft Corporation.
|
||||
SPDX-License-Identifier: BSD-2-Clause-Patent
|
||||
|
||||
**/
|
||||
|
||||
#include <Uefi.h>
|
||||
|
||||
#include <Library/BaseLib.h>
|
||||
#include <Library/DebugLib.h>
|
||||
#include <Library/BaseMemoryLib.h>
|
||||
#include <Library/MemoryAllocationLib.h>
|
||||
|
||||
#include <Protocol/VariablePolicy.h>
|
||||
|
||||
/**
|
||||
This internal helper function populates the header structure,
|
||||
all common fields, and takes care of fix-ups.
|
||||
|
||||
NOTE: Only use this internally. Assumes correctly-sized buffers.
|
||||
|
||||
@param[out] EntPtr Pointer to the buffer to be populated.
|
||||
@param[in] Namespace Pointer to an EFI_GUID for the target variable namespace that this policy will protect.
|
||||
@param[in] MinSize MinSize for the VariablePolicy.
|
||||
@param[in] MaxSize MaxSize for the VariablePolicy.
|
||||
@param[in] AttributesMustHave AttributesMustHave for the VariablePolicy.
|
||||
@param[in] AttributesCantHave AttributesCantHave for the VariablePolicy.
|
||||
@param[in] LockPolicyType LockPolicyType for the VariablePolicy.
|
||||
|
||||
**/
|
||||
STATIC
|
||||
VOID
|
||||
PopulateCommonData (
|
||||
OUT VARIABLE_POLICY_ENTRY *EntPtr,
|
||||
IN CONST EFI_GUID *Namespace,
|
||||
IN UINT32 MinSize,
|
||||
IN UINT32 MaxSize,
|
||||
IN UINT32 AttributesMustHave,
|
||||
IN UINT32 AttributesCantHave,
|
||||
IN UINT8 LockPolicyType
|
||||
)
|
||||
{
|
||||
EntPtr->Version = VARIABLE_POLICY_ENTRY_REVISION;
|
||||
CopyGuid (&EntPtr->Namespace, Namespace);
|
||||
EntPtr->MinSize = MinSize;
|
||||
EntPtr->MaxSize = MaxSize;
|
||||
EntPtr->AttributesMustHave = AttributesMustHave;
|
||||
EntPtr->AttributesCantHave = AttributesCantHave;
|
||||
EntPtr->LockPolicyType = LockPolicyType;
|
||||
|
||||
// NOTE: As a heler, fix up MaxSize for compatibility with the old model.
|
||||
if (EntPtr->MaxSize == 0) {
|
||||
EntPtr->MaxSize = VARIABLE_POLICY_NO_MAX_SIZE;
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
/**
|
||||
This helper function will allocate and populate a new VariablePolicy
|
||||
structure for a policy that does not contain any sub-structures (such as
|
||||
VARIABLE_LOCK_ON_VAR_STATE_POLICY).
|
||||
|
||||
NOTE: Caller will need to free structure once finished.
|
||||
|
||||
@param[in] Namespace Pointer to an EFI_GUID for the target variable namespace that this policy will protect.
|
||||
@param[in] Name [Optional] If provided, a pointer to the CHAR16 array for the target variable name.
|
||||
Otherwise, will create a policy that targets an entire namespace.
|
||||
@param[in] MinSize MinSize for the VariablePolicy.
|
||||
@param[in] MaxSize MaxSize for the VariablePolicy.
|
||||
@param[in] AttributesMustHave AttributesMustHave for the VariablePolicy.
|
||||
@param[in] AttributesCantHave AttributesCantHave for the VariablePolicy.
|
||||
@param[in] LockPolicyType LockPolicyType for the VariablePolicy.
|
||||
@param[out] NewEntry If successful, will be set to a pointer to the allocated buffer containing the
|
||||
new policy.
|
||||
|
||||
@retval EFI_SUCCESS Operation completed successfully and structure is populated.
|
||||
@retval EFI_INVALID_PARAMETER Namespace is NULL.
|
||||
@retval EFI_INVALID_PARAMETER LockPolicyType is invalid for a basic structure.
|
||||
@retval EFI_BUFFER_TOO_SMALL Finished structure would not fit in UINT16 size.
|
||||
@retval EFI_OUT_OF_RESOURCES Could not allocate sufficient space for structure.
|
||||
|
||||
**/
|
||||
EFI_STATUS
|
||||
EFIAPI
|
||||
CreateBasicVariablePolicy (
|
||||
IN CONST EFI_GUID *Namespace,
|
||||
IN CONST CHAR16 *Name OPTIONAL,
|
||||
IN UINT32 MinSize,
|
||||
IN UINT32 MaxSize,
|
||||
IN UINT32 AttributesMustHave,
|
||||
IN UINT32 AttributesCantHave,
|
||||
IN UINT8 LockPolicyType,
|
||||
OUT VARIABLE_POLICY_ENTRY **NewEntry
|
||||
)
|
||||
{
|
||||
UINTN TotalSize;
|
||||
UINTN NameSize;
|
||||
VARIABLE_POLICY_ENTRY *EntPtr;
|
||||
CHAR16 *CopyName;
|
||||
|
||||
// Check some initial invalid parameters for this function.
|
||||
if ((Namespace == NULL) || (NewEntry == NULL)) {
|
||||
return EFI_INVALID_PARAMETER;
|
||||
}
|
||||
|
||||
if ((LockPolicyType != VARIABLE_POLICY_TYPE_NO_LOCK) &&
|
||||
(LockPolicyType != VARIABLE_POLICY_TYPE_LOCK_NOW) &&
|
||||
(LockPolicyType != VARIABLE_POLICY_TYPE_LOCK_ON_CREATE))
|
||||
{
|
||||
return EFI_INVALID_PARAMETER;
|
||||
}
|
||||
|
||||
//
|
||||
// Set NameSize to suppress incorrect compiler/analyzer warnings
|
||||
//
|
||||
NameSize = 0;
|
||||
|
||||
// Now we've gotta determine the total size of the buffer required for
|
||||
// the VariablePolicy structure.
|
||||
TotalSize = sizeof (VARIABLE_POLICY_ENTRY);
|
||||
if (Name != NULL) {
|
||||
NameSize = StrnSizeS (Name, MAX_UINT16);
|
||||
TotalSize += NameSize;
|
||||
}
|
||||
|
||||
// Make sure the size fits within a VARIABLE_POLICY_ENTRY.Size.
|
||||
ASSERT (TotalSize <= MAX_UINT16);
|
||||
if (TotalSize > MAX_UINT16) {
|
||||
return EFI_BUFFER_TOO_SMALL;
|
||||
}
|
||||
|
||||
// Allocate a buffer to hold all the data. We're on the home stretch.
|
||||
*NewEntry = AllocatePool (TotalSize);
|
||||
if (*NewEntry == NULL) {
|
||||
return EFI_OUT_OF_RESOURCES;
|
||||
}
|
||||
|
||||
// If we're still here, we're basically done.
|
||||
// Copy the data and GET... OUT....
|
||||
EntPtr = *NewEntry;
|
||||
PopulateCommonData (
|
||||
EntPtr,
|
||||
Namespace,
|
||||
MinSize,
|
||||
MaxSize,
|
||||
AttributesMustHave,
|
||||
AttributesCantHave,
|
||||
LockPolicyType
|
||||
);
|
||||
EntPtr->Size = (UINT16)TotalSize; // This is safe because we've already checked.
|
||||
EntPtr->OffsetToName = sizeof (VARIABLE_POLICY_ENTRY);
|
||||
if (Name != NULL) {
|
||||
CopyName = (CHAR16 *)((UINT8 *)EntPtr + EntPtr->OffsetToName);
|
||||
CopyMem (CopyName, Name, NameSize);
|
||||
}
|
||||
|
||||
return EFI_SUCCESS;
|
||||
}
|
||||
|
||||
/**
|
||||
This helper function will allocate and populate a new VariablePolicy
|
||||
structure for a policy with a lock type of VARIABLE_POLICY_TYPE_LOCK_ON_VAR_STATE.
|
||||
|
||||
NOTE: Caller will need to free structure once finished.
|
||||
|
||||
@param[in] Namespace Pointer to an EFI_GUID for the target variable namespace that this policy will protect.
|
||||
@param[in] Name [Optional] If provided, a pointer to the CHAR16 array for the target variable name.
|
||||
Otherwise, will create a policy that targets an entire namespace.
|
||||
@param[in] MinSize MinSize for the VariablePolicy.
|
||||
@param[in] MaxSize MaxSize for the VariablePolicy.
|
||||
@param[in] AttributesMustHave AttributesMustHave for the VariablePolicy.
|
||||
@param[in] AttributesCantHave AttributesCantHave for the VariablePolicy.
|
||||
@param[in] VarStateNamespace Pointer to the EFI_GUID for the VARIABLE_LOCK_ON_VAR_STATE_POLICY.Namespace.
|
||||
@param[in] VarStateValue Value for the VARIABLE_LOCK_ON_VAR_STATE_POLICY.Value.
|
||||
@param[in] VarStateName Pointer to the CHAR16 array for the VARIABLE_LOCK_ON_VAR_STATE_POLICY.Name.
|
||||
@param[out] NewEntry If successful, will be set to a pointer to the allocated buffer containing the
|
||||
new policy.
|
||||
|
||||
@retval EFI_SUCCESS Operation completed successfully and structure is populated.
|
||||
@retval EFI_INVALID_PARAMETER Namespace, VarStateNamespace, VarStateName is NULL.
|
||||
@retval EFI_BUFFER_TOO_SMALL Finished structure would not fit in UINT16 size.
|
||||
@retval EFI_OUT_OF_RESOURCES Could not allocate sufficient space for structure.
|
||||
|
||||
**/
|
||||
EFI_STATUS
|
||||
EFIAPI
|
||||
CreateVarStateVariablePolicy (
|
||||
IN CONST EFI_GUID *Namespace,
|
||||
IN CONST CHAR16 *Name OPTIONAL,
|
||||
IN UINT32 MinSize,
|
||||
IN UINT32 MaxSize,
|
||||
IN UINT32 AttributesMustHave,
|
||||
IN UINT32 AttributesCantHave,
|
||||
IN CONST EFI_GUID *VarStateNamespace,
|
||||
IN UINT8 VarStateValue,
|
||||
IN CONST CHAR16 *VarStateName,
|
||||
OUT VARIABLE_POLICY_ENTRY **NewEntry
|
||||
)
|
||||
{
|
||||
UINTN TotalSize;
|
||||
UINTN NameSize;
|
||||
UINTN VarStateNameSize;
|
||||
VARIABLE_POLICY_ENTRY *EntPtr;
|
||||
CHAR16 *CopyName;
|
||||
VARIABLE_LOCK_ON_VAR_STATE_POLICY *CopyPolicy;
|
||||
|
||||
// Check some initial invalid parameters for this function.
|
||||
if ((Namespace == NULL) || (VarStateNamespace == NULL) ||
|
||||
(VarStateName == NULL) || (NewEntry == NULL))
|
||||
{
|
||||
return EFI_INVALID_PARAMETER;
|
||||
}
|
||||
|
||||
// Now we've gotta determine the total size of the buffer required for
|
||||
// the VariablePolicy structure.
|
||||
VarStateNameSize = StrnSizeS (VarStateName, MAX_UINT16);
|
||||
TotalSize = sizeof (VARIABLE_POLICY_ENTRY) +
|
||||
sizeof (VARIABLE_LOCK_ON_VAR_STATE_POLICY) +
|
||||
VarStateNameSize;
|
||||
if (Name != NULL) {
|
||||
NameSize = StrnSizeS (Name, MAX_UINT16);
|
||||
TotalSize += NameSize;
|
||||
}
|
||||
|
||||
// Make sure the size fits within a VARIABLE_POLICY_ENTRY.Size.
|
||||
ASSERT (TotalSize <= MAX_UINT16);
|
||||
if (TotalSize > MAX_UINT16) {
|
||||
return EFI_BUFFER_TOO_SMALL;
|
||||
}
|
||||
|
||||
// Allocate a buffer to hold all the data. We're on the home stretch.
|
||||
*NewEntry = AllocatePool (TotalSize);
|
||||
if (*NewEntry == NULL) {
|
||||
return EFI_OUT_OF_RESOURCES;
|
||||
}
|
||||
|
||||
// If we're still here, we're basically done.
|
||||
// Copy the data and GET... OUT....
|
||||
EntPtr = *NewEntry;
|
||||
PopulateCommonData (
|
||||
EntPtr,
|
||||
Namespace,
|
||||
MinSize,
|
||||
MaxSize,
|
||||
AttributesMustHave,
|
||||
AttributesCantHave,
|
||||
VARIABLE_POLICY_TYPE_LOCK_ON_VAR_STATE
|
||||
);
|
||||
EntPtr->Size = (UINT16)TotalSize; // This is safe because we've already checked.
|
||||
EntPtr->OffsetToName = sizeof (VARIABLE_POLICY_ENTRY) +
|
||||
sizeof (VARIABLE_LOCK_ON_VAR_STATE_POLICY) +
|
||||
(UINT16)VarStateNameSize;
|
||||
|
||||
CopyPolicy = (VARIABLE_LOCK_ON_VAR_STATE_POLICY *)((UINT8 *)EntPtr + sizeof (VARIABLE_POLICY_ENTRY));
|
||||
CopyName = (CHAR16 *)((UINT8 *)CopyPolicy + sizeof (VARIABLE_LOCK_ON_VAR_STATE_POLICY));
|
||||
CopyGuid (&CopyPolicy->Namespace, VarStateNamespace);
|
||||
CopyPolicy->Value = VarStateValue;
|
||||
CopyMem (CopyName, VarStateName, VarStateNameSize);
|
||||
|
||||
if (Name != NULL) {
|
||||
CopyName = (CHAR16 *)((UINT8 *)EntPtr + EntPtr->OffsetToName);
|
||||
CopyMem (CopyName, Name, NameSize);
|
||||
}
|
||||
|
||||
return EFI_SUCCESS;
|
||||
}
|
||||
|
||||
/**
|
||||
This helper function does everything that CreateBasicVariablePolicy() does, but also
|
||||
uses the passed in protocol to register the policy with the infrastructure.
|
||||
Does not return a buffer, does not require the caller to free anything.
|
||||
|
||||
@param[in] VariablePolicy Pointer to a valid instance of the VariablePolicy protocol.
|
||||
@param[in] Namespace Pointer to an EFI_GUID for the target variable namespace that this policy will protect.
|
||||
@param[in] Name [Optional] If provided, a pointer to the CHAR16 array for the target variable name.
|
||||
Otherwise, will create a policy that targets an entire namespace.
|
||||
@param[in] MinSize MinSize for the VariablePolicy.
|
||||
@param[in] MaxSize MaxSize for the VariablePolicy.
|
||||
@param[in] AttributesMustHave AttributesMustHave for the VariablePolicy.
|
||||
@param[in] AttributesCantHave AttributesCantHave for the VariablePolicy.
|
||||
@param[in] LockPolicyType LockPolicyType for the VariablePolicy.
|
||||
|
||||
@retval EFI_INVALID_PARAMETER VariablePolicy pointer is NULL.
|
||||
@retval EFI_STATUS Status returned by CreateBasicVariablePolicy() or RegisterVariablePolicy().
|
||||
|
||||
**/
|
||||
EFI_STATUS
|
||||
EFIAPI
|
||||
RegisterBasicVariablePolicy (
|
||||
IN EDKII_VARIABLE_POLICY_PROTOCOL *VariablePolicy,
|
||||
IN CONST EFI_GUID *Namespace,
|
||||
IN CONST CHAR16 *Name OPTIONAL,
|
||||
IN UINT32 MinSize,
|
||||
IN UINT32 MaxSize,
|
||||
IN UINT32 AttributesMustHave,
|
||||
IN UINT32 AttributesCantHave,
|
||||
IN UINT8 LockPolicyType
|
||||
)
|
||||
{
|
||||
VARIABLE_POLICY_ENTRY *NewEntry;
|
||||
EFI_STATUS Status;
|
||||
|
||||
// Check the simple things.
|
||||
if (VariablePolicy == NULL) {
|
||||
return EFI_INVALID_PARAMETER;
|
||||
}
|
||||
|
||||
// Create the new entry and make sure that everything worked.
|
||||
NewEntry = NULL;
|
||||
Status = CreateBasicVariablePolicy (
|
||||
Namespace,
|
||||
Name,
|
||||
MinSize,
|
||||
MaxSize,
|
||||
AttributesMustHave,
|
||||
AttributesCantHave,
|
||||
LockPolicyType,
|
||||
&NewEntry
|
||||
);
|
||||
|
||||
// If that was successful, attempt to register the new policy.
|
||||
if (!EFI_ERROR (Status)) {
|
||||
Status = VariablePolicy->RegisterVariablePolicy (NewEntry);
|
||||
}
|
||||
|
||||
// If we allocated the buffer, free the buffer.
|
||||
if (NewEntry != NULL) {
|
||||
FreePool (NewEntry);
|
||||
}
|
||||
|
||||
return Status;
|
||||
}
|
||||
|
||||
/**
|
||||
This helper function does everything that CreateBasicVariablePolicy() does, but also
|
||||
uses the passed in protocol to register the policy with the infrastructure.
|
||||
Does not return a buffer, does not require the caller to free anything.
|
||||
|
||||
@param[in] VariablePolicy Pointer to a valid instance of the VariablePolicy protocol.
|
||||
@param[in] Namespace Pointer to an EFI_GUID for the target variable namespace that this policy will protect.
|
||||
@param[in] Name [Optional] If provided, a pointer to the CHAR16 array for the target variable name.
|
||||
Otherwise, will create a policy that targets an entire namespace.
|
||||
@param[in] MinSize MinSize for the VariablePolicy.
|
||||
@param[in] MaxSize MaxSize for the VariablePolicy.
|
||||
@param[in] AttributesMustHave AttributesMustHave for the VariablePolicy.
|
||||
@param[in] AttributesCantHave AttributesCantHave for the VariablePolicy.
|
||||
@param[in] VarStateNamespace Pointer to the EFI_GUID for the VARIABLE_LOCK_ON_VAR_STATE_POLICY.Namespace.
|
||||
@param[in] VarStateName Pointer to the CHAR16 array for the VARIABLE_LOCK_ON_VAR_STATE_POLICY.Name.
|
||||
@param[in] VarStateValue Value for the VARIABLE_LOCK_ON_VAR_STATE_POLICY.Value.
|
||||
|
||||
@retval EFI_INVALID_PARAMETER VariablePolicy pointer is NULL.
|
||||
@retval EFI_STATUS Status returned by CreateBasicVariablePolicy() or RegisterVariablePolicy().
|
||||
|
||||
**/
|
||||
EFI_STATUS
|
||||
EFIAPI
|
||||
RegisterVarStateVariablePolicy (
|
||||
IN EDKII_VARIABLE_POLICY_PROTOCOL *VariablePolicy,
|
||||
IN CONST EFI_GUID *Namespace,
|
||||
IN CONST CHAR16 *Name OPTIONAL,
|
||||
IN UINT32 MinSize,
|
||||
IN UINT32 MaxSize,
|
||||
IN UINT32 AttributesMustHave,
|
||||
IN UINT32 AttributesCantHave,
|
||||
IN CONST EFI_GUID *VarStateNamespace,
|
||||
IN CONST CHAR16 *VarStateName,
|
||||
IN UINT8 VarStateValue
|
||||
)
|
||||
{
|
||||
VARIABLE_POLICY_ENTRY *NewEntry;
|
||||
EFI_STATUS Status;
|
||||
|
||||
// Check the simple things.
|
||||
if (VariablePolicy == NULL) {
|
||||
return EFI_INVALID_PARAMETER;
|
||||
}
|
||||
|
||||
// Create the new entry and make sure that everything worked.
|
||||
NewEntry = NULL;
|
||||
Status = CreateVarStateVariablePolicy (
|
||||
Namespace,
|
||||
Name,
|
||||
MinSize,
|
||||
MaxSize,
|
||||
AttributesMustHave,
|
||||
AttributesCantHave,
|
||||
VarStateNamespace,
|
||||
VarStateValue,
|
||||
VarStateName,
|
||||
&NewEntry
|
||||
);
|
||||
|
||||
// If that was successful, attempt to register the new policy.
|
||||
if (!EFI_ERROR (Status)) {
|
||||
Status = VariablePolicy->RegisterVariablePolicy (NewEntry);
|
||||
}
|
||||
|
||||
// If we allocated the buffer, free the buffer.
|
||||
if (NewEntry != NULL) {
|
||||
FreePool (NewEntry);
|
||||
}
|
||||
|
||||
return Status;
|
||||
}
|
|
@ -0,0 +1,35 @@
|
|||
## @file VariablePolicyHelperLib.inf
|
||||
# This library contains helper functions for marshalling and registering
|
||||
# new policies with the VariablePolicy infrastructure.
|
||||
#
|
||||
# This library is currently written against VariablePolicy revision 0x00010000.
|
||||
#
|
||||
# Copyright (c) Microsoft Corporation.
|
||||
# SPDX-License-Identifier: BSD-2-Clause-Patent
|
||||
##
|
||||
|
||||
|
||||
[Defines]
|
||||
INF_VERSION = 0x00010017
|
||||
BASE_NAME = VariablePolicyHelperLib
|
||||
# MODULE_UNI_FILE = VariablePolicyHelperLib.uni
|
||||
FILE_GUID = B3C2206B-FDD1-4AED-8352-FC5EC34C5630
|
||||
VERSION_STRING = 1.0
|
||||
MODULE_TYPE = BASE
|
||||
LIBRARY_CLASS = VariablePolicyHelperLib
|
||||
|
||||
|
||||
[Sources]
|
||||
VariablePolicyHelperLib.c
|
||||
|
||||
|
||||
[Packages]
|
||||
MdePkg/MdePkg.dec
|
||||
MdeModulePkg/MdeModulePkg.dec
|
||||
|
||||
|
||||
[LibraryClasses]
|
||||
BaseLib
|
||||
DebugLib
|
||||
MemoryAllocationLib
|
||||
BaseMemoryLib
|
|
@ -0,0 +1,12 @@
|
|||
// /** @file
|
||||
// VariablePolicyHelperLib.uni
|
||||
//
|
||||
// Copyright (c) Microsoft Corporation.
|
||||
// SPDX-License-Identifier: BSD-2-Clause-Patent
|
||||
//
|
||||
// **/
|
||||
|
||||
|
||||
#string STR_MODULE_ABSTRACT #language en-US "Library containing helper functions for marshalling and registering new policies with the VariablePolicy infrastructure"
|
||||
|
||||
#string STR_MODULE_DESCRIPTION #language en-US "Library containing helper functions for marshalling and registering new policies with the VariablePolicy infrastructure"
|
|
@ -0,0 +1,406 @@
|
|||
---
|
||||
title: UEFI Variable Policy Whitepaper
|
||||
version: 1.0
|
||||
copyright: Copyright (c) Microsoft Corporation.
|
||||
---
|
||||
|
||||
# UEFI Variable Policy
|
||||
|
||||
## Summary
|
||||
|
||||
UEFI Variable Policy spec aims to describe the DXE protocol interface
|
||||
which allows enforcing certain rules on certain UEFI variables. The
|
||||
protocol allows communication with the Variable Policy Engine which
|
||||
performs the policy enforcement.
|
||||
|
||||
The Variable Policy is comprised of a set of policy entries which
|
||||
describe, per UEFI variable (identified by namespace GUID and variable
|
||||
name) the following rules:
|
||||
|
||||
- Required variable attributes
|
||||
- Prohibited variable attributes
|
||||
- Minimum variable size
|
||||
- Maximum variable size
|
||||
- Locking:
|
||||
- Locking "immediately"
|
||||
- Locking on creation
|
||||
- Locking based on a state of another variable
|
||||
|
||||
The spec assumes that the Variable Policy Engine runs in a trusted
|
||||
enclave, potentially off the main CPU that runs UEFI. For that reason,
|
||||
it is assumed that the Variable Policy Engine has no concept of UEFI
|
||||
events, and that the communication from the DXE driver to the trusted
|
||||
enclave is proprietary.
|
||||
|
||||
At power-on, the Variable Policy Engine is:
|
||||
|
||||
- Enabled -- present policy entries are evaluated on variable access
|
||||
calls.
|
||||
- Unlocked -- new policy entries can be registered.
|
||||
|
||||
Policy is expected to be clear on power-on. Policy is volatile and not
|
||||
preserved across system reset.
|
||||
|
||||
## DXE Protocol
|
||||
|
||||
```h
|
||||
typedef struct {
|
||||
UINT64 Revision;
|
||||
DISABLE_VARIABLE_POLICY DisableVariablePolicy;
|
||||
IS_VARIABLE_POLICY_ENABLED IsVariablePolicyEnabled;
|
||||
REGISTER_VARIABLE_POLICY RegisterVariablePolicy;
|
||||
DUMP_VARIABLE_POLICY DumpVariablePolicy;
|
||||
LOCK_VARIABLE_POLICY LockVariablePolicy;
|
||||
} _VARIABLE_POLICY_PROTOCOL;
|
||||
|
||||
typedef _VARIABLE_POLICY_PROTOCOL VARIABLE_POLICY_PROTOCOL;
|
||||
|
||||
extern EFI_GUID gVariablePolicyProtocolGuid;
|
||||
```
|
||||
|
||||
```text
|
||||
## Include/Protocol/VariablePolicy.h
|
||||
gVariablePolicyProtocolGuid = { 0x81D1675C, 0x86F6, 0x48DF, { 0xBD, 0x95, 0x9A, 0x6E, 0x4F, 0x09, 0x25, 0xC3 } }
|
||||
```
|
||||
|
||||
### DisableVariablePolicy
|
||||
|
||||
Function prototype:
|
||||
|
||||
```c
|
||||
EFI_STATUS
|
||||
EFIAPI
|
||||
DisableVariablePolicy (
|
||||
VOID
|
||||
);
|
||||
```
|
||||
|
||||
`DisableVariablePolicy` call disables the Variable Policy Engine, so
|
||||
that the present policy entries are no longer taken into account on
|
||||
variable access calls. This call effectively turns off the variable
|
||||
policy verification for this boot. This also disables UEFI
|
||||
Authenticated Variable protections including Secure Boot.
|
||||
`DisableVariablePolicy` can only be called once during boot. If called
|
||||
more than once, it will return `EFI_ALREADY_STARTED`. Note, this process
|
||||
is irreversible until the next system reset -- there is no
|
||||
"EnablePolicy" protocol function.
|
||||
|
||||
_IMPORTANT NOTE:_ It is strongly recommended that VariablePolicy *NEVER*
|
||||
be disabled in "normal, production boot conditions". It is expected to always
|
||||
be enforced. The most likely reasons to disable are for Manufacturing and
|
||||
Refurbishing scenarios. If in doubt, leave the `gEfiMdeModulePkgTokenSpaceGuid.PcdAllowVariablePolicyEnforcementDisable`
|
||||
PCD set to `FALSE` and VariablePolicy will always be enabled.
|
||||
|
||||
### IsVariablePolicyEnabled
|
||||
|
||||
Function prototype:
|
||||
|
||||
```c
|
||||
EFI_STATUS
|
||||
EFIAPI
|
||||
IsVariablePolicyEnabled (
|
||||
OUT BOOLEAN *State
|
||||
);
|
||||
```
|
||||
|
||||
`IsVariablePolicyEnabled` accepts a pointer to a Boolean in which it
|
||||
will store `TRUE` if Variable Policy Engine is enabled, or `FALSE` if
|
||||
Variable Policy Engine is disabled. The function returns `EFI_SUCCESS`.
|
||||
|
||||
### RegisterVariablePolicy
|
||||
|
||||
Function prototype:
|
||||
|
||||
```c
|
||||
EFI_STATUS
|
||||
EFIAPI
|
||||
RegisterVariablePolicy (
|
||||
IN CONST VARIABLE_POLICY_ENTRY *PolicyEntry
|
||||
);
|
||||
```
|
||||
|
||||
`RegisterVariablePolicy` call accepts a pointer to a policy entry
|
||||
structure and returns the status of policy registration. If the
|
||||
Variable Policy Engine is not locked and the policy structures are
|
||||
valid, the function will return `EFI_SUCCESS`. If the Variable Policy
|
||||
Engine is locked, `RegisterVariablePolicy` call will return
|
||||
`EFI_WRITE_PROTECTED` and will not register the policy entry. Bulk
|
||||
registration is not supported at this time due to the requirements
|
||||
around error handling on each policy registration.
|
||||
|
||||
Upon successful registration of a policy entry, Variable Policy Engine
|
||||
will then evaluate this entry on subsequent variable access calls (as
|
||||
long as Variable Policy Engine hasn't been disabled).
|
||||
|
||||
### DumpVariablePolicy
|
||||
|
||||
Function prototype:
|
||||
|
||||
```c
|
||||
EFI_STATUS
|
||||
EFIAPI
|
||||
DumpVariablePolicy (
|
||||
OUT UINT8 *Policy,
|
||||
IN OUT UINT32 *Size
|
||||
);
|
||||
```
|
||||
|
||||
`DumpVariablePolicy` call accepts a pointer to a buffer and a pointer to
|
||||
the size of the buffer as parameters and returns the status of placing
|
||||
the policy into the buffer. On first call to `DumpVariablePolicy` one
|
||||
should pass `NULL` as the buffer and a pointer to 0 as the `Size` variable
|
||||
and `DumpVariablePolicy` will return `EFI_BUFFER_TOO_SMALL` and will
|
||||
populate the `Size` parameter with the size of the needed buffer to
|
||||
store the policy. This way, the caller can allocate the buffer of
|
||||
correct size and call `DumpVariablePolicy` again. The function will
|
||||
populate the buffer with policy and return `EFI_SUCCESS`.
|
||||
|
||||
### LockVariablePolicy
|
||||
|
||||
Function prototype:
|
||||
|
||||
```c
|
||||
EFI_STATUS
|
||||
EFIAPI
|
||||
LockVariablePolicy (
|
||||
VOID
|
||||
);
|
||||
```
|
||||
|
||||
`LockVariablePolicy` locks the Variable Policy Engine, i.e. prevents any
|
||||
new policy entries from getting registered in this boot
|
||||
(`RegisterVariablePolicy` calls will fail with `EFI_WRITE_PROTECTED`
|
||||
status code returned).
|
||||
|
||||
## Policy Structure
|
||||
|
||||
The structure below is meant for the DXE protocol calling interface,
|
||||
when communicating to the Variable Policy Engine, thus the pragma pack
|
||||
directive. How these policies are stored in memory is up to the
|
||||
implementation.
|
||||
|
||||
```c
|
||||
#pragma pack(1)
|
||||
typedef struct {
|
||||
UINT32 Version;
|
||||
UINT16 Size;
|
||||
UINT16 OffsetToName;
|
||||
EFI_GUID Namespace;
|
||||
UINT32 MinSize;
|
||||
UINT32 MaxSize;
|
||||
UINT32 AttributesMustHave;
|
||||
UINT32 AttributesCantHave;
|
||||
UINT8 LockPolicyType;
|
||||
UINT8 Reserved[3];
|
||||
// UINT8 LockPolicy[]; // Variable Length Field
|
||||
// CHAR16 Name[]; // Variable Length Field
|
||||
} VARIABLE_POLICY_ENTRY;
|
||||
```
|
||||
|
||||
The struct `VARIABLE_POLICY_ENTRY` above describes the layout for a policy
|
||||
entry. The first element, `Size`, is the size of the policy entry, then
|
||||
followed by `OffsetToName` -- the number of bytes from the beginning of
|
||||
the struct to the name of the UEFI variable targeted by the policy
|
||||
entry. The name can contain wildcards to match more than one variable,
|
||||
more on this in the Wildcards section. The rest of the struct elements
|
||||
are self-explanatory.
|
||||
|
||||
```cpp
|
||||
#define VARIABLE_POLICY_TYPE_NO_LOCK 0
|
||||
#define VARIABLE_POLICY_TYPE_LOCK_NOW 1
|
||||
#define VARIABLE_POLICY_TYPE_LOCK_ON_CREATE 2
|
||||
#define VARIABLE_POLICY_TYPE_LOCK_ON_VAR_STATE 3
|
||||
```
|
||||
|
||||
`LockPolicyType` can have the following values:
|
||||
|
||||
- `VARIABLE_POLICY_TYPE_NO_LOCK` -- means that no variable locking is performed. However,
|
||||
the attribute and size constraints are still enforced. LockPolicy
|
||||
field is size 0.
|
||||
- `VARIABLE_POLICY_TYPE_LOCK_NOW` -- means that the variable starts being locked
|
||||
immediately after policy entry registration. If the variable doesn't
|
||||
exist at this point, being LockedNow means it cannot be created on
|
||||
this boot. LockPolicy field is size 0.
|
||||
- `VARIABLE_POLICY_TYPE_LOCK_ON_CREATE` -- means that the variable starts being locked
|
||||
after it is created. This allows for variable creation and
|
||||
protection after LockVariablePolicy() function has been called. The
|
||||
LockPolicy field is size 0.
|
||||
- `VARIABLE_POLICY_TYPE_LOCK_ON_VAR_STATE` -- means that the Variable Policy Engine will
|
||||
examine the state/contents of another variable to determine if the
|
||||
variable referenced in the policy entry is locked.
|
||||
|
||||
```c
|
||||
typedef struct {
|
||||
EFI_GUID Namespace;
|
||||
UINT8 Value;
|
||||
UINT8 Reserved;
|
||||
// CHAR16 Name[]; // Variable Length Field
|
||||
} VARIABLE_LOCK_ON_VAR_STATE_POLICY;
|
||||
```
|
||||
|
||||
If `LockPolicyType` is `VARIABLE_POLICY_TYPE_LOCK_ON_VAR_STATE`, then the final element in the
|
||||
policy entry struct is of type `VARIABLE_LOCK_ON_VAR_STATE_POLICY`, which
|
||||
lists the namespace GUID, name (no wildcards here), and value of the
|
||||
variable which state determines the locking of the variable referenced
|
||||
in the policy entry. The "locking" variable must be 1 byte in terms of
|
||||
payload size. If the Referenced variable contents match the Value of the
|
||||
`VARIABLE_LOCK_ON_VAR_STATE_POLICY` structure, the lock will be considered
|
||||
active and the target variable will be locked. If the Reference variable
|
||||
does not exist (ie. returns `EFI_NOT_FOUND`), this policy will be
|
||||
considered inactive.
|
||||
|
||||
## Variable Name Wildcards
|
||||
|
||||
Two types of wildcards can be used in the UEFI variable name field in a
|
||||
policy entry:
|
||||
|
||||
1. If the Name is a zero-length array (easily checked by comparing
|
||||
fields `Size` and `OffsetToName` -- if they're the same, then the
|
||||
`Name` is zero-length), then all variables in the namespace specified
|
||||
by the provided GUID are targeted by the policy entry.
|
||||
2. Character "#" in the `Name` corresponds to one numeric character
|
||||
(0-9, A-F, a-f). For example, string "Boot####" in the `Name`
|
||||
field of the policy entry will make it so that the policy entry will
|
||||
target variables named "Boot0001", "Boot0002", etc.
|
||||
|
||||
Given the above two types of wildcards, one variable can be targeted by
|
||||
more than one policy entry, thus there is a need to establish the
|
||||
precedence rule: a more specific match is applied. When a variable
|
||||
access operation is performed, Variable Policy Engine should first check
|
||||
the variable being accessed against the policy entries without
|
||||
wildcards, then with 1 wildcard, then with 2 wildcards, etc., followed
|
||||
in the end by policy entries that match the whole namespace. One can
|
||||
still imagine a situation where two policy entries with the same number
|
||||
of wildcards match the same variable -- for example, policy entries with
|
||||
Names "Boot00##" and "Boot##01" will both match variable "Boot0001".
|
||||
Such situation can (and should) be avoided by designing mutually
|
||||
exclusive Name strings with wildcards, however, if it occurs, then the
|
||||
policy entry that was registered first will be used. After the most
|
||||
specific match is selected, all other policies are ignored.
|
||||
|
||||
## Available Testing
|
||||
|
||||
This functionality is current supported by two kinds of tests: there is a host-based
|
||||
unit test for the core business logic (this test accompanies the `VariablePolicyLib`
|
||||
implementation that lives in `MdeModulePkg/Library`) and there is a functional test
|
||||
for the protocol and its interfaces (this test lives in the `MdeModulePkg/Test/ShellTest`
|
||||
directory).
|
||||
|
||||
### Host-Based Unit Test
|
||||
|
||||
There is a test that can be run as part of the Host-Based Unit Testing
|
||||
infrastructure provided by EDK2 PyTools (documented elsewhere). It will test
|
||||
all internal guarantees and is where you will find test cases for most of the
|
||||
policy matching and security of the Variable Policy Engine.
|
||||
|
||||
### Shell-Based Functional Test
|
||||
|
||||
This test -- [Variable Policy Functional Unit Test](https://github.com/microsoft/mu_plus/tree/release/202005/UefiTestingPkg/FunctionalSystemTests/VarPolicyUnitTestApp) -- can be built as a
|
||||
UEFI Shell application and run to validate that the Variable Policy Engine
|
||||
is correctly installed and enforcing policies on the target system.
|
||||
|
||||
NOTE: This test _must_ be run prior to calling `DisableVariablePolicy` for all
|
||||
test cases to pass. For this reason, it is recommended to run this on a test-built
|
||||
FW for complete results, and then again on a production-built FW for release
|
||||
results.
|
||||
|
||||
## Use Cases
|
||||
|
||||
The below examples are hypothetical scenarios based on real-world requirements
|
||||
that demonstrate how Variable Policies could be constructed to solve various
|
||||
problems.
|
||||
|
||||
### UEFI Setup Variables (Example 1)
|
||||
|
||||
Variables containing values of the setup options exposed via UEFI
|
||||
menu (setup variables). These would be locked based on a state of
|
||||
another variable, "ReadyToBoot", which would be set to 1 at the
|
||||
ReadyToBoot event. Thus, the policy for the setup variables would be
|
||||
of type `LockOnVarState`, with the "ReadyToBoot" listed as the name of
|
||||
the variable, appropriate GUID listed as the namespace, and 1 as
|
||||
value. Entry into the trusted UEFI menu app doesn't signal
|
||||
ReadyToBoot, but booting to any device does, and the setup variables
|
||||
are write-protected. The "ReadyToBoot" variable would need to be
|
||||
locked-on-create. *(THIS IS ESSENTIALLY LOCK ON EVENT, BUT SINCE THE
|
||||
POLICY ENGINE IS NOT IN THE UEFI ENVIRONMENT VARIABLES ARE USED)*
|
||||
|
||||
For example, "AllowPXEBoot" variable locked by "ReadyToBoot" variable.
|
||||
|
||||
(NOTE: In the below example, the emphasized fields ('Namespace', 'Value', and 'Name')
|
||||
are members of the `VARIABLE_LOCK_ON_VAR_STATE_POLICY` structure.)
|
||||
|
||||
Size | ...
|
||||
---- | ---
|
||||
OffsetToName | ...
|
||||
NameSpace | ...
|
||||
MinSize | ...
|
||||
MaxSize | ...
|
||||
AttributesMustHave | ...
|
||||
AttributesCantHave | ...
|
||||
LockPolicyType | `VARIABLE_POLICY_TYPE_LOCK_ON_VAR_STATE`
|
||||
_Namespace_ | ...
|
||||
_Value_ | 1
|
||||
_Name_ | "ReadyToBoot"
|
||||
//Name | "AllowPXEBoot"
|
||||
|
||||
### Manufacturing VPD (Example 2)
|
||||
|
||||
Manufacturing Variable Provisioning Data (VPD) is stored in
|
||||
variables and is created while in Manufacturing (MFG) Mode. In MFG
|
||||
Mode Variable Policy Engine is disabled, thus these VPD variables
|
||||
can be created. These variables are locked with lock policy type
|
||||
`LockNow`, so that these variables can't be tampered with in Customer
|
||||
Mode. To overwrite or clear VPD, the device would need to MFG mode,
|
||||
which is standard practice for refurbishing/remanufacturing
|
||||
scenarios.
|
||||
|
||||
Example: "DisplayPanelCalibration" variable...
|
||||
|
||||
Size | ...
|
||||
---- | ---
|
||||
OffsetToName | ...
|
||||
NameSpace | ...
|
||||
MinSize | ...
|
||||
MaxSize | ...
|
||||
AttributesMustHave | ...
|
||||
AttributesCantHave | ...
|
||||
LockPolicyType | `VARIABLE_POLICY_TYPE_LOCK_NOW`
|
||||
// Name | "DisplayPanelCalibration"
|
||||
|
||||
### 3rd Party Calibration Data (Example 3)
|
||||
|
||||
Bluetooth pre-pairing variables are locked-on-create because these
|
||||
get created by an OS application when Variable Policy is in effect.
|
||||
|
||||
Example: "KeyboardBTPairing" variable
|
||||
|
||||
Size | ...
|
||||
---- | ---
|
||||
OffsetToName | ...
|
||||
NameSpace | ...
|
||||
MinSize | ...
|
||||
MaxSize | ...
|
||||
AttributesMustHave | ...
|
||||
AttributesCantHave | ...
|
||||
LockPolicyType | `VARIABLE_POLICY_TYPE_LOCK_ON_CREATE`
|
||||
// Name | "KeyboardBTPairing"
|
||||
|
||||
### Software-based Variable Policy (Example 4)
|
||||
|
||||
Example: "Boot####" variables (a name string with wildcards that
|
||||
will match variables "Boot0000" to "BootFFFF") locked by "LockBootOrder"
|
||||
variable.
|
||||
|
||||
Size | ...
|
||||
---- | ---
|
||||
OffsetToName | ...
|
||||
NameSpace | ...
|
||||
MinSize | ...
|
||||
MaxSize | ...
|
||||
AttributesMustHave | ...
|
||||
AttributesCantHave | ...
|
||||
LockPolicyType | `VARIABLE_POLICY_TYPE_LOCK_ON_VAR_STATE`
|
||||
_Namespace_ | ...
|
||||
_Value_ | 1
|
||||
_Name_ | "LockBootOrder"
|
||||
//Name | "Boot####"
|
|
@ -0,0 +1,44 @@
|
|||
/** @file -- VariablePolicyExtraInitNull.c
|
||||
This file contains extra init and deinit routines that don't do anything
|
||||
extra.
|
||||
|
||||
Copyright (c) Microsoft Corporation.
|
||||
SPDX-License-Identifier: BSD-2-Clause-Patent
|
||||
|
||||
**/
|
||||
|
||||
#include <Library/UefiRuntimeServicesTableLib.h>
|
||||
|
||||
/**
|
||||
An extra init hook that enables the RuntimeDxe library instance to
|
||||
register VirtualAddress change callbacks. Among other things.
|
||||
|
||||
@retval EFI_SUCCESS Everything is good. Continue with init.
|
||||
@retval Others Uh... don't continue.
|
||||
|
||||
**/
|
||||
EFI_STATUS
|
||||
VariablePolicyExtraInit (
|
||||
VOID
|
||||
)
|
||||
{
|
||||
// NULL implementation.
|
||||
return EFI_SUCCESS;
|
||||
}
|
||||
|
||||
/**
|
||||
An extra deinit hook that enables the RuntimeDxe library instance to
|
||||
register VirtualAddress change callbacks. Among other things.
|
||||
|
||||
@retval EFI_SUCCESS Everything is good. Continue with deinit.
|
||||
@retval Others Uh... don't continue.
|
||||
|
||||
**/
|
||||
EFI_STATUS
|
||||
VariablePolicyExtraDeinit (
|
||||
VOID
|
||||
)
|
||||
{
|
||||
// NULL implementation.
|
||||
return EFI_SUCCESS;
|
||||
}
|
|
@ -0,0 +1,84 @@
|
|||
/** @file -- VariablePolicyExtraInitRuntimeDxe.c
|
||||
This file contains extra init and deinit routines that register and unregister
|
||||
VariableAddressChange callbacks.
|
||||
|
||||
Copyright (c) Microsoft Corporation.
|
||||
SPDX-License-Identifier: BSD-2-Clause-Patent
|
||||
|
||||
**/
|
||||
|
||||
#include <Library/UefiBootServicesTableLib.h>
|
||||
#include <Library/UefiRuntimeServicesTableLib.h>
|
||||
|
||||
extern EFI_GET_VARIABLE mGetVariableHelper;
|
||||
extern UINT8 *mPolicyTable;
|
||||
STATIC BOOLEAN mIsVirtualAddrConverted;
|
||||
STATIC EFI_EVENT mVariablePolicyLibVirtualAddressChangeEvent = NULL;
|
||||
|
||||
/**
|
||||
For the RuntimeDxe version of this lib, convert internal pointer addresses to virtual addresses.
|
||||
|
||||
@param[in] Event Event whose notification function is being invoked.
|
||||
@param[in] Context The pointer to the notification function's context, which
|
||||
is implementation-dependent.
|
||||
**/
|
||||
STATIC
|
||||
VOID
|
||||
EFIAPI
|
||||
VariablePolicyLibVirtualAddressCallback (
|
||||
IN EFI_EVENT Event,
|
||||
IN VOID *Context
|
||||
)
|
||||
{
|
||||
gRT->ConvertPointer (0, (VOID **)&mPolicyTable);
|
||||
gRT->ConvertPointer (0, (VOID **)&mGetVariableHelper);
|
||||
mIsVirtualAddrConverted = TRUE;
|
||||
}
|
||||
|
||||
/**
|
||||
An extra init hook that enables the RuntimeDxe library instance to
|
||||
register VirtualAddress change callbacks. Among other things.
|
||||
|
||||
@retval EFI_SUCCESS Everything is good. Continue with init.
|
||||
@retval Others Uh... don't continue.
|
||||
|
||||
**/
|
||||
EFI_STATUS
|
||||
VariablePolicyExtraInit (
|
||||
VOID
|
||||
)
|
||||
{
|
||||
return gBS->CreateEventEx (
|
||||
EVT_NOTIFY_SIGNAL,
|
||||
TPL_NOTIFY,
|
||||
VariablePolicyLibVirtualAddressCallback,
|
||||
NULL,
|
||||
&gEfiEventVirtualAddressChangeGuid,
|
||||
&mVariablePolicyLibVirtualAddressChangeEvent
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
An extra deinit hook that enables the RuntimeDxe library instance to
|
||||
register VirtualAddress change callbacks. Among other things.
|
||||
|
||||
@retval EFI_SUCCESS Everything is good. Continue with deinit.
|
||||
@retval Others Uh... don't continue.
|
||||
|
||||
**/
|
||||
EFI_STATUS
|
||||
VariablePolicyExtraDeinit (
|
||||
VOID
|
||||
)
|
||||
{
|
||||
EFI_STATUS Status;
|
||||
|
||||
Status = EFI_SUCCESS;
|
||||
if (mIsVirtualAddrConverted) {
|
||||
Status = gBS->CloseEvent (mVariablePolicyLibVirtualAddressChangeEvent);
|
||||
} else {
|
||||
Status = EFI_SUCCESS;
|
||||
}
|
||||
|
||||
return Status;
|
||||
}
|
File diff suppressed because it is too large
Load Diff
|
@ -0,0 +1,49 @@
|
|||
## @file VariablePolicyLib.inf
|
||||
# Business logic for Variable Policy enforcement.
|
||||
#
|
||||
# Copyright (c) Microsoft Corporation.
|
||||
# SPDX-License-Identifier: BSD-2-Clause-Patent
|
||||
##
|
||||
|
||||
|
||||
[Defines]
|
||||
INF_VERSION = 0x00010017
|
||||
BASE_NAME = VariablePolicyLib
|
||||
FILE_GUID = E9ECD342-159A-4F24-9FDF-65724027C594
|
||||
VERSION_STRING = 1.0
|
||||
MODULE_TYPE = DXE_DRIVER
|
||||
LIBRARY_CLASS = VariablePolicyLib|DXE_DRIVER DXE_SMM_DRIVER MM_STANDALONE
|
||||
|
||||
#
|
||||
# The following information is for reference only and not required by the build tools.
|
||||
#
|
||||
# VALID_ARCHITECTURES = ANY
|
||||
#
|
||||
|
||||
|
||||
[Sources]
|
||||
VariablePolicyLib.c
|
||||
VariablePolicyExtraInitNull.c
|
||||
|
||||
|
||||
[Packages]
|
||||
MdePkg/MdePkg.dec
|
||||
MdeModulePkg/MdeModulePkg.dec
|
||||
|
||||
|
||||
[LibraryClasses]
|
||||
BaseLib
|
||||
DebugLib
|
||||
BaseMemoryLib
|
||||
MemoryAllocationLib
|
||||
SafeIntLib
|
||||
PcdLib
|
||||
|
||||
|
||||
[Pcd]
|
||||
gEfiMdeModulePkgTokenSpaceGuid.PcdAllowVariablePolicyEnforcementDisable ## CONSUMES
|
||||
|
||||
|
||||
[BuildOptions]
|
||||
MSFT:NOOPT_*_*_CC_FLAGS = -DINTERNAL_UNIT_TEST
|
||||
GCC:NOOPT_*_*_CC_FLAGS = -DINTERNAL_UNIT_TEST
|
|
@ -0,0 +1,12 @@
|
|||
// /** @file
|
||||
// VariablePolicyLib.uni
|
||||
//
|
||||
// Copyright (c) Microsoft Corporation.
|
||||
// SPDX-License-Identifier: BSD-2-Clause-Patent
|
||||
//
|
||||
// **/
|
||||
|
||||
|
||||
#string STR_MODULE_ABSTRACT #language en-US "Library containing the business logic for the VariablePolicy engine"
|
||||
|
||||
#string STR_MODULE_DESCRIPTION #language en-US "Library containing the business logic for the VariablePolicy engine"
|
|
@ -0,0 +1,51 @@
|
|||
## @file VariablePolicyLibRuntimeDxe.inf
|
||||
# Business logic for Variable Policy enforcement.
|
||||
# This instance is specifically for RuntimeDxe and contains
|
||||
# extra routines to register for VirtualAddressChangeEvents.
|
||||
#
|
||||
# Copyright (c) Microsoft Corporation.
|
||||
# SPDX-License-Identifier: BSD-2-Clause-Patent
|
||||
##
|
||||
|
||||
|
||||
[Defines]
|
||||
INF_VERSION = 0x00010017
|
||||
BASE_NAME = VariablePolicyLibRuntimeDxe
|
||||
FILE_GUID = 205F7F0E-8EAC-4914-8390-1B90DD7E2A27
|
||||
VERSION_STRING = 1.0
|
||||
MODULE_TYPE = DXE_RUNTIME_DRIVER
|
||||
LIBRARY_CLASS = VariablePolicyLib|DXE_RUNTIME_DRIVER
|
||||
|
||||
#
|
||||
# The following information is for reference only and not required by the build tools.
|
||||
#
|
||||
# VALID_ARCHITECTURES = ANY
|
||||
#
|
||||
|
||||
|
||||
[Sources]
|
||||
VariablePolicyLib.c
|
||||
VariablePolicyExtraInitRuntimeDxe.c
|
||||
|
||||
|
||||
[Packages]
|
||||
MdePkg/MdePkg.dec
|
||||
MdeModulePkg/MdeModulePkg.dec
|
||||
|
||||
|
||||
[LibraryClasses]
|
||||
DebugLib
|
||||
BaseMemoryLib
|
||||
MemoryAllocationLib
|
||||
SafeIntLib
|
||||
UefiBootServicesTableLib
|
||||
UefiRuntimeServicesTableLib
|
||||
PcdLib
|
||||
|
||||
|
||||
[Pcd]
|
||||
gEfiMdeModulePkgTokenSpaceGuid.PcdAllowVariablePolicyEnforcementDisable ## CONSUMES
|
||||
|
||||
|
||||
[Guids]
|
||||
gEfiEventVirtualAddressChangeGuid
|
|
@ -620,6 +620,12 @@
|
|||
# 0x80000006 | Incorrect error code provided.
|
||||
#
|
||||
|
||||
## Include/Protocol/VariablePolicy.h
|
||||
gEdkiiVariablePolicyProtocolGuid = { 0x81D1675C, 0x86F6, 0x48DF, { 0xBD, 0x95, 0x9A, 0x6E, 0x4F, 0x09, 0x25, 0xC3 } }
|
||||
|
||||
## Include/Protocol/UsbEthernetProtocol.h
|
||||
gEdkIIUsbEthProtocolGuid = { 0x8d8969cc, 0xfeb0, 0x4303, { 0xb2, 0x1a, 0x1f, 0x11, 0x6f, 0x38, 0x56, 0x43 } }
|
||||
|
||||
[PcdsFeatureFlag]
|
||||
## Indicates if the platform can support update capsule across a system reset.<BR><BR>
|
||||
# TRUE - Supports update capsule across a system reset.<BR>
|
||||
|
@ -1116,6 +1122,15 @@
|
|||
# @Prompt Variable storage size.
|
||||
gEfiMdeModulePkgTokenSpaceGuid.PcdVariableStoreSize|0x10000|UINT32|0x30000005
|
||||
|
||||
## Toggle for whether the VariablePolicy engine should allow disabling.
|
||||
# The engine is enabled at power-on, but the interface allows the platform to
|
||||
# disable enforcement for servicing flexibility. If this PCD is disabled, it will block the ability to
|
||||
# disable the enforcement and VariablePolicy enforcement will always be ON.
|
||||
# TRUE - VariablePolicy can be disabled by request through the interface (until interface is locked)
|
||||
# FALSE - VariablePolicy interface will not accept requests to disable and is ALWAYS ON
|
||||
# @Prompt Allow VariablePolicy enforcement to be disabled.
|
||||
gEfiMdeModulePkgTokenSpaceGuid.PcdAllowVariablePolicyEnforcementDisable|FALSE|BOOLEAN|0x30000020
|
||||
|
||||
## FFS filename to find the ACPI tables.
|
||||
# @Prompt FFS name of ACPI tables storage.
|
||||
gEfiMdeModulePkgTokenSpaceGuid.PcdAcpiTableStorageFile|{ 0x25, 0x4e, 0x37, 0x7e, 0x01, 0x8e, 0xee, 0x4f, 0x87, 0xf2, 0x39, 0xc, 0x23, 0xc6, 0x6, 0xcd }|VOID*|0x30000016
|
||||
|
|
|
@ -803,6 +803,47 @@ typedef UINTN *BASE_LIST;
|
|||
#define OFFSET_OF(TYPE, Field) ((UINTN) &(((TYPE *)0)->Field))
|
||||
#endif
|
||||
|
||||
/**
|
||||
Returns the alignment requirement of a type.
|
||||
|
||||
@param TYPE The name of the type to retrieve the alignment requirement of.
|
||||
|
||||
@return Alignment requirement, in Bytes, of TYPE.
|
||||
**/
|
||||
#if defined(__cplusplus) && __cplusplus >= 201103L
|
||||
//
|
||||
// C++ 11 and later support the standard operator alignof.
|
||||
//
|
||||
#define ALIGNOF(TYPE) alignof (TYPE)
|
||||
#elif ((defined(__GNUC__) || (defined(_MSC_VER) && _MSC_VER >= 1900)) && !defined (__cplusplus)) || defined(__clang__)
|
||||
//
|
||||
// All supported versions of GCC and Clang, as well as MSVC 2015 and later,
|
||||
// support the standard operator _Alignof in C mode. GCC and MSVC do not
|
||||
// support it in C++ mode though.
|
||||
//
|
||||
#define ALIGNOF(TYPE) _Alignof (TYPE)
|
||||
#elif defined(__GNUC__)
|
||||
//
|
||||
// GCC does not support _Alignof in C++ mode, unlike Clang. The vendor-
|
||||
// extenstion is supported in both C and C++ mode.
|
||||
//
|
||||
#define ALIGNOF(TYPE) __alignof__ (TYPE)
|
||||
#elif defined(_MSC_EXTENSIONS)
|
||||
//
|
||||
// Earlier versions of MSVC, at least MSVC 2008 and later, as well as current
|
||||
// versions in C++ mode support the vendor-extension __alignof.
|
||||
//
|
||||
#define ALIGNOF(TYPE) __alignof (TYPE)
|
||||
#else
|
||||
//
|
||||
// For compilers that do not support inbuilt alignof operators, use OFFSET_OF.
|
||||
// CHAR8 is known to have both a size and an alignment requirement of 1 Byte.
|
||||
// As such, A must be located exactly at the offset equal to its alignment
|
||||
// requirement.
|
||||
//
|
||||
#define ALIGNOF(TYPE) OFFSET_OF (struct { CHAR8 C; TYPE A; }, A)
|
||||
#endif
|
||||
|
||||
/**
|
||||
Portable definition for compile time assertions.
|
||||
Equivalent to C11 static_assert macro from assert.h.
|
||||
|
@ -887,6 +928,60 @@ STATIC_ASSERT (sizeof (__VERIFY_UINT32_ENUM_SIZE) == 4, "Size of enum does not m
|
|||
**/
|
||||
#define BASE_CR(Record, TYPE, Field) ((TYPE *) ((CHAR8 *) (Record) - OFFSET_OF (TYPE, Field)))
|
||||
|
||||
/**
|
||||
Checks whether a value is a power of two.
|
||||
|
||||
@param Value The value to check.
|
||||
|
||||
@retval TRUE Value is a power of two.
|
||||
@retval FALSE Value is not a power of two.
|
||||
**/
|
||||
#define IS_POW2(Value) ((Value) != 0U && ((Value) & ((Value) - 1U)) == 0U)
|
||||
|
||||
/**
|
||||
Determines the subtrahend to subtract from a value to round it down to the
|
||||
previous boundary of a specified alignment.
|
||||
|
||||
@param Value The value to round down.
|
||||
@param Alignment The alignment boundary used to return the subtrahend.
|
||||
|
||||
@return Subtrahend to round Value down to alignment boundary Alignment.
|
||||
**/
|
||||
#define ALIGN_VALUE_SUBTRAHEND(Value, Alignment) ((Value) & ((Alignment) - 1U))
|
||||
|
||||
/**
|
||||
Checks whether a value is aligned by a specified alignment.
|
||||
|
||||
@param Value The value to check.
|
||||
@param Alignment The alignment boundary used to check against.
|
||||
|
||||
@retval TRUE Value is aligned by Alignment.
|
||||
@retval FALSE Value is not aligned by Alignment.
|
||||
**/
|
||||
#define IS_ALIGNED(Value, Alignment) (ALIGN_VALUE_SUBTRAHEND (Value, Alignment) == 0U)
|
||||
|
||||
/**
|
||||
Checks whether a pointer or address is aligned by a specified alignment.
|
||||
|
||||
@param Address The pointer or address to check.
|
||||
@param Alignment The alignment boundary used to check against.
|
||||
|
||||
@retval TRUE Address is aligned by Alignment.
|
||||
@retval FALSE Address is not aligned by Alignment.
|
||||
**/
|
||||
#define ADDRESS_IS_ALIGNED(Address, Alignment) IS_ALIGNED ((UINTN) (Address), Alignment)
|
||||
|
||||
/**
|
||||
Determines the addend to add to a value to round it up to the next boundary of
|
||||
a specified alignment.
|
||||
|
||||
@param Value The value to round up.
|
||||
@param Alignment The alignment boundary used to return the addend.
|
||||
|
||||
@return Addend to round Value up to alignment boundary Alignment.
|
||||
**/
|
||||
#define ALIGN_VALUE_ADDEND(Value, Alignment) (((Alignment) - (Value)) & ((Alignment) - 1U))
|
||||
|
||||
/**
|
||||
Rounds a value up to the next boundary using a specified alignment.
|
||||
|
||||
|
|
|
@ -56,12 +56,11 @@ typedef struct {
|
|||
/// WIN_CERTIFICATE_UEFI_GUID.CertData
|
||||
///
|
||||
typedef struct {
|
||||
EFI_GUID HashType;
|
||||
GUID HashType;
|
||||
UINT8 PublicKey[256];
|
||||
UINT8 Signature[256];
|
||||
} EFI_CERT_BLOCK_RSA_2048_SHA256;
|
||||
|
||||
|
||||
///
|
||||
/// Certificate which encapsulates a GUID-specific digital signature
|
||||
///
|
||||
|
@ -75,7 +74,7 @@ typedef struct {
|
|||
/// This is the unique id which determines the
|
||||
/// format of the CertData. .
|
||||
///
|
||||
EFI_GUID CertType;
|
||||
GUID CertType;
|
||||
///
|
||||
/// The following is the certificate data. The format of
|
||||
/// the data is determined by the CertType.
|
||||
|
@ -85,7 +84,6 @@ typedef struct {
|
|||
UINT8 CertData[1];
|
||||
} WIN_CERTIFICATE_UEFI_GUID;
|
||||
|
||||
|
||||
///
|
||||
/// Certificate which encapsulates the RSASSA_PKCS1-v1_5 digital signature.
|
||||
///
|
||||
|
@ -104,7 +102,7 @@ typedef struct {
|
|||
/// This is the hashing algorithm which was performed on the
|
||||
/// UEFI executable when creating the digital signature.
|
||||
///
|
||||
EFI_GUID HashAlgorithm;
|
||||
GUID HashAlgorithm;
|
||||
///
|
||||
/// The following is the actual digital signature. The
|
||||
/// size of the signature is the same size as the key
|
||||
|
@ -117,6 +115,6 @@ typedef struct {
|
|||
///
|
||||
} WIN_CERTIFICATE_EFI_PKCS1_15;
|
||||
|
||||
extern EFI_GUID gEfiCertTypeRsa2048Sha256Guid;
|
||||
extern GUID gEfiCertTypeRsa2048Sha256Guid;
|
||||
|
||||
#endif
|
||||
|
|
|
@ -51,7 +51,6 @@
|
|||
///
|
||||
#define HTTP_HEADER_ACCEPT "Accept"
|
||||
|
||||
|
||||
///
|
||||
/// Accept-Charset Request Header
|
||||
/// The Accept-Charset request-header field can be used to indicate what character sets
|
||||
|
@ -76,7 +75,6 @@
|
|||
///
|
||||
#define HTTP_HEADER_ACCEPT_RANGES "Accept-Ranges"
|
||||
|
||||
|
||||
///
|
||||
/// Accept-Encoding Request Header
|
||||
/// The Accept-Encoding request-header field is similar to Accept,
|
||||
|
@ -105,7 +103,6 @@
|
|||
#define HTTP_CONTENT_ENCODING_DEFLATE "deflate" /// The "zlib" format defined in RFC 1950 in combination with the "deflate"
|
||||
/// compression mechanism described in RFC 1951.
|
||||
|
||||
|
||||
///
|
||||
/// Content-Type Header
|
||||
/// The Content-Type entity-header field indicates the media type of the entity-body sent to
|
||||
|
@ -129,7 +126,6 @@
|
|||
#define HTTP_CONTENT_TYPE_IMAGE_PNG "image/png"
|
||||
#define HTTP_CONTENT_TYPE_IMAGE_SVG_XML "image/svg+xml"
|
||||
|
||||
|
||||
///
|
||||
/// Content-Length Header
|
||||
/// The Content-Length entity-header field indicates the size of the entity-body,
|
||||
|
@ -146,7 +142,11 @@
|
|||
/// is a property of the message, not of the entity.
|
||||
///
|
||||
#define HTTP_HEADER_TRANSFER_ENCODING "Transfer-Encoding"
|
||||
|
||||
#define HTTP_HEADER_TRANSFER_ENCODING_CHUNKED "chunked"
|
||||
#define CHUNKED_TRANSFER_CODING_CR '\r'
|
||||
#define CHUNKED_TRANSFER_CODING_LF '\n'
|
||||
#define CHUNKED_TRANSFER_CODING_LAST_CHUNK '0'
|
||||
#define CHUNKED_TRANSFER_CODING_EXTENSION_SEPARATOR ';'
|
||||
|
||||
///
|
||||
/// User Agent Request Header
|
||||
|
@ -193,7 +193,6 @@
|
|||
///
|
||||
#define HTTP_HEADER_IF_MATCH "If-Match"
|
||||
|
||||
|
||||
///
|
||||
/// The If-None-Match request-header field is used with a method to make it conditional.
|
||||
/// A client that has one or more entities previously obtained from the resource can verify
|
||||
|
@ -205,7 +204,13 @@
|
|||
///
|
||||
#define HTTP_HEADER_IF_NONE_MATCH "If-None-Match"
|
||||
|
||||
|
||||
///
|
||||
/// The WWW-Authenticate Response Header
|
||||
/// If a server receives a request for an access-protected object, and an
|
||||
/// acceptable Authorization header is not sent, the server responds with
|
||||
/// a "401 Unauthorized" status code, and a WWW-Authenticate header.
|
||||
///
|
||||
#define HTTP_HEADER_WWW_AUTHENTICATE "WWW-Authenticate"
|
||||
|
||||
///
|
||||
/// Authorization Request Header
|
||||
|
|
|
@ -0,0 +1,737 @@
|
|||
/** @file
|
||||
EFI image format for PE32, PE32+ and TE. 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.3 - February 6, 2013.
|
||||
This file also includes some definitions in PI Specification, Revision 1.0.
|
||||
|
||||
Copyright (c) 2020, Marvin Häuser. All rights reserved.<BR>
|
||||
Copyright (c) 2020, Vitaly Cheptsov. All rights reserved.<BR>
|
||||
Copyright (c) 2020, ISP RAS. All rights reserved.<BR>
|
||||
Portions copyright (c) 2006 - 2019, Intel Corporation. All rights reserved.<BR>
|
||||
Portions copyright (c) 2008 - 2010, Apple Inc. All rights reserved.<BR>
|
||||
Portions Copyright (c) 2020, Hewlett Packard Enterprise Development LP. All rights reserved.<BR>
|
||||
|
||||
SPDX-License-Identifier: BSD-3-Clause
|
||||
**/
|
||||
|
||||
#ifndef PE_COFF_IMAGE2_H_
|
||||
#define PE_COFF_IMAGE2_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_SAL_RUNTIME_DRIVER 13 ///< defined PI Specification, 1.0
|
||||
|
||||
|
||||
//
|
||||
// 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
|
||||
#define IMAGE_FILE_MACHINE_ARMTHUMB_MIXED 0x01c2
|
||||
#define IMAGE_FILE_MACHINE_ARM64 0xAA64
|
||||
#define IMAGE_FILE_MACHINE_RISCV32 0x5032
|
||||
#define IMAGE_FILE_MACHINE_RISCV64 0x5064
|
||||
#define IMAGE_FILE_MACHINE_RISCV128 0x5128
|
||||
#define IMAGE_FILE_MACHINE_LOONGARCH32 0x6232
|
||||
#define IMAGE_FILE_MACHINE_LOONGARCH64 0x6264
|
||||
|
||||
//
|
||||
// EXE file formats
|
||||
//
|
||||
#define EFI_IMAGE_DOS_SIGNATURE SIGNATURE_16('M', 'Z')
|
||||
#define EFI_IMAGE_OS2_SIGNATURE SIGNATURE_16('N', 'E')
|
||||
#define EFI_IMAGE_OS2_SIGNATURE_LE SIGNATURE_16('L', 'E')
|
||||
#define EFI_IMAGE_NT_SIGNATURE SIGNATURE_32('P', 'E', '\0', '\0')
|
||||
|
||||
///
|
||||
/// 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;
|
||||
|
||||
///
|
||||
/// COFF File Header (Object and Image).
|
||||
///
|
||||
typedef struct {
|
||||
UINT16 Machine;
|
||||
UINT16 NumberOfSections;
|
||||
UINT32 TimeDateStamp;
|
||||
UINT32 PointerToSymbolTable;
|
||||
UINT32 NumberOfSymbols;
|
||||
UINT16 SizeOfOptionalHeader;
|
||||
UINT16 Characteristics;
|
||||
} EFI_IMAGE_FILE_HEADER;
|
||||
|
||||
///
|
||||
/// Size of EFI_IMAGE_FILE_HEADER.
|
||||
///
|
||||
#define EFI_IMAGE_SIZEOF_FILE_HEADER 20
|
||||
|
||||
//
|
||||
// Characteristics
|
||||
//
|
||||
#define EFI_IMAGE_FILE_RELOCS_STRIPPED BIT0 ///< 0x0001 Relocation info stripped from file.
|
||||
#define EFI_IMAGE_FILE_EXECUTABLE_IMAGE BIT1 ///< 0x0002 File is executable (i.e. no unresolved externel references).
|
||||
#define EFI_IMAGE_FILE_LINE_NUMS_STRIPPED BIT2 ///< 0x0004 Line numbers stripped from file.
|
||||
#define EFI_IMAGE_FILE_LOCAL_SYMS_STRIPPED BIT3 ///< 0x0008 Local symbols stripped from file.
|
||||
#define EFI_IMAGE_FILE_LARGE_ADDRESS_AWARE BIT5 ///< 0x0020 Supports addresses > 2-GB
|
||||
#define EFI_IMAGE_FILE_BYTES_REVERSED_LO BIT7 ///< 0x0080 Bytes of machine word are reversed.
|
||||
#define EFI_IMAGE_FILE_32BIT_MACHINE BIT8 ///< 0x0100 32 bit word machine.
|
||||
#define EFI_IMAGE_FILE_DEBUG_STRIPPED BIT9 ///< 0x0200 Debugging info stripped from file in .DBG file.
|
||||
#define EFI_IMAGE_FILE_SYSTEM BIT12 ///< 0x1000 System File.
|
||||
#define EFI_IMAGE_FILE_DLL BIT13 ///< 0x2000 File is a DLL.
|
||||
#define EFI_IMAGE_FILE_BYTES_REVERSED_HI BIT15 ///< 0x8000 Bytes of machine word are reversed.
|
||||
|
||||
///
|
||||
/// Header Data Directories.
|
||||
///
|
||||
typedef struct {
|
||||
UINT32 VirtualAddress;
|
||||
UINT32 Size;
|
||||
} EFI_IMAGE_DATA_DIRECTORY;
|
||||
|
||||
//
|
||||
// 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
|
||||
|
||||
#define EFI_IMAGE_NUMBER_OF_DIRECTORY_ENTRIES 16
|
||||
|
||||
///
|
||||
/// @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
|
||||
|
||||
///
|
||||
/// @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
|
||||
|
||||
|
||||
///
|
||||
/// @attention
|
||||
/// EFI_IMAGE_NT_HEADERS32 is for use ONLY by tools.
|
||||
///
|
||||
typedef struct {
|
||||
UINT32 Signature;
|
||||
EFI_IMAGE_FILE_HEADER FileHeader;
|
||||
} EFI_IMAGE_NT_HEADERS_COMMON_HDR;
|
||||
|
||||
STATIC_ASSERT (
|
||||
sizeof (EFI_IMAGE_NT_HEADERS_COMMON_HDR) == sizeof (UINT32) + sizeof (EFI_IMAGE_FILE_HEADER),
|
||||
"Unsupported padding."
|
||||
);
|
||||
|
||||
///
|
||||
/// @attention
|
||||
/// EFI_IMAGE_NT_HEADERS32 is for use ONLY by tools.
|
||||
///
|
||||
typedef struct {
|
||||
EFI_IMAGE_NT_HEADERS_COMMON_HDR CommonHeader;
|
||||
///
|
||||
/// Standard fields.
|
||||
///
|
||||
UINT16 Magic;
|
||||
UINT8 MajorLinkerVersion;
|
||||
UINT8 MinorLinkerVersion;
|
||||
UINT32 SizeOfCode;
|
||||
UINT32 SizeOfInitializedData;
|
||||
UINT32 SizeOfUninitializedData;
|
||||
UINT32 AddressOfEntryPoint;
|
||||
UINT32 BaseOfCode;
|
||||
UINT32 BaseOfData; ///< PE32 contains this additional field, which is absent in PE32+.
|
||||
///
|
||||
/// Optional Header Windows-Specific 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_NT_HEADERS32;
|
||||
|
||||
///
|
||||
/// @attention
|
||||
/// EFI_IMAGE_HEADERS64 is for use ONLY by tools.
|
||||
///
|
||||
typedef struct {
|
||||
EFI_IMAGE_NT_HEADERS_COMMON_HDR CommonHeader;
|
||||
///
|
||||
/// Standard fields.
|
||||
///
|
||||
UINT16 Magic;
|
||||
UINT8 MajorLinkerVersion;
|
||||
UINT8 MinorLinkerVersion;
|
||||
UINT32 SizeOfCode;
|
||||
UINT32 SizeOfInitializedData;
|
||||
UINT32 SizeOfUninitializedData;
|
||||
UINT32 AddressOfEntryPoint;
|
||||
UINT32 BaseOfCode;
|
||||
///
|
||||
/// Optional Header Windows-Specific 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_NT_HEADERS64;
|
||||
|
||||
//
|
||||
// Other Windows 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
|
||||
|
||||
///
|
||||
/// Length of ShortName.
|
||||
///
|
||||
#define EFI_IMAGE_SIZEOF_SHORT_NAME 8
|
||||
|
||||
///
|
||||
/// Section Table. This table immediately follows the optional header.
|
||||
///
|
||||
typedef struct {
|
||||
UINT8 Name[EFI_IMAGE_SIZEOF_SHORT_NAME];
|
||||
UINT32 VirtualSize;
|
||||
UINT32 VirtualAddress;
|
||||
UINT32 SizeOfRawData;
|
||||
UINT32 PointerToRawData;
|
||||
UINT32 PointerToRelocations;
|
||||
UINT32 PointerToLinenumbers;
|
||||
UINT16 NumberOfRelocations;
|
||||
UINT16 NumberOfLinenumbers;
|
||||
UINT32 Characteristics;
|
||||
} EFI_IMAGE_SECTION_HEADER;
|
||||
|
||||
//
|
||||
// Section Flags Values
|
||||
//
|
||||
#define EFI_IMAGE_SCN_TYPE_NO_PAD BIT3 ///< 0x00000008 ///< Reserved.
|
||||
#define EFI_IMAGE_SCN_CNT_CODE BIT5 ///< 0x00000020
|
||||
#define EFI_IMAGE_SCN_CNT_INITIALIZED_DATA BIT6 ///< 0x00000040
|
||||
#define EFI_IMAGE_SCN_CNT_UNINITIALIZED_DATA BIT7 ///< 0x00000080
|
||||
|
||||
#define EFI_IMAGE_SCN_LNK_OTHER BIT8 ///< 0x00000100 ///< Reserved.
|
||||
#define EFI_IMAGE_SCN_LNK_INFO BIT9 ///< 0x00000200 ///< Section contains comments or some other type of information.
|
||||
#define EFI_IMAGE_SCN_LNK_REMOVE BIT11 ///< 0x00000800 ///< Section contents will not become part of image.
|
||||
#define EFI_IMAGE_SCN_LNK_COMDAT BIT12 ///< 0x00001000
|
||||
|
||||
#define EFI_IMAGE_SCN_ALIGN_1BYTES BIT20 ///< 0x00100000
|
||||
#define EFI_IMAGE_SCN_ALIGN_2BYTES BIT21 ///< 0x00200000
|
||||
#define EFI_IMAGE_SCN_ALIGN_4BYTES (BIT20|BIT21) ///< 0x00300000
|
||||
#define EFI_IMAGE_SCN_ALIGN_8BYTES BIT22 ///< 0x00400000
|
||||
#define EFI_IMAGE_SCN_ALIGN_16BYTES (BIT20|BIT22) ///< 0x00500000
|
||||
#define EFI_IMAGE_SCN_ALIGN_32BYTES (BIT21|BIT22) ///< 0x00600000
|
||||
#define EFI_IMAGE_SCN_ALIGN_64BYTES (BIT20|BIT21|BIT22) ///< 0x00700000
|
||||
|
||||
#define EFI_IMAGE_SCN_MEM_DISCARDABLE BIT25 ///< 0x02000000
|
||||
#define EFI_IMAGE_SCN_MEM_NOT_CACHED BIT26 ///< 0x04000000
|
||||
#define EFI_IMAGE_SCN_MEM_NOT_PAGED BIT27 ///< 0x08000000
|
||||
#define EFI_IMAGE_SCN_MEM_SHARED BIT28 ///< 0x10000000
|
||||
#define EFI_IMAGE_SCN_MEM_EXECUTE BIT29 ///< 0x20000000
|
||||
#define EFI_IMAGE_SCN_MEM_READ BIT30 ///< 0x40000000
|
||||
#define EFI_IMAGE_SCN_MEM_WRITE BIT31 ///< 0x80000000
|
||||
|
||||
///
|
||||
/// Size of a Symbol Table Record.
|
||||
///
|
||||
#define EFI_IMAGE_SIZEOF_SYMBOL 18
|
||||
|
||||
//
|
||||
// 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.
|
||||
|
||||
//
|
||||
// Symbol Type (fundamental) values.
|
||||
//
|
||||
#define EFI_IMAGE_SYM_TYPE_NULL 0 ///< no type.
|
||||
#define EFI_IMAGE_SYM_TYPE_VOID 1 ///< no valid type.
|
||||
#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
|
||||
|
||||
//
|
||||
// Symbol 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
|
||||
|
||||
//
|
||||
// the following values only be referred in PeCoff, not defined in PECOFF.
|
||||
//
|
||||
#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;
|
||||
|
||||
///
|
||||
/// Size of 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 0x000A
|
||||
#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
|
||||
|
||||
/**
|
||||
Returns the type of a Base Relocation.
|
||||
|
||||
@param[in] Relocation The composite Base Relocation value.
|
||||
**/
|
||||
#define IMAGE_RELOC_TYPE(Relocation) ((Relocation) >> 12U)
|
||||
|
||||
/**
|
||||
Returns the target offset of a Base Relocation.
|
||||
|
||||
@param[in] Relocation The composite Base Relocation value.
|
||||
**/
|
||||
#define IMAGE_RELOC_OFFSET(Relocation) ((Relocation) & 0x0FFFU)
|
||||
|
||||
///
|
||||
/// Based relocation format.
|
||||
///
|
||||
typedef struct {
|
||||
UINT32 VirtualAddress;
|
||||
UINT32 SizeOfBlock;
|
||||
UINT16 Relocations[];
|
||||
} EFI_IMAGE_BASE_RELOCATION_BLOCK;
|
||||
|
||||
//
|
||||
// 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_ARM_MOV32A 5
|
||||
#define EFI_IMAGE_REL_BASED_ARM_MOV32T 7
|
||||
#define EFI_IMAGE_REL_BASED_IA64_IMM64 9
|
||||
#define EFI_IMAGE_REL_BASED_MIPS_JMPADDR16 9
|
||||
#define EFI_IMAGE_REL_BASED_DIR64 10
|
||||
|
||||
///
|
||||
/// Relocation types of RISC-V processor.
|
||||
///
|
||||
#define EFI_IMAGE_REL_BASED_RISCV_HI20 5
|
||||
#define EFI_IMAGE_REL_BASED_RISCV_LOW12I 7
|
||||
#define EFI_IMAGE_REL_BASED_RISCV_LOW12S 8
|
||||
|
||||
///
|
||||
/// 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;
|
||||
|
||||
///
|
||||
/// Size of 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 "// "
|
||||
|
||||
///
|
||||
/// Archive Member Headers
|
||||
///
|
||||
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. (0x60 0x0A).
|
||||
} EFI_IMAGE_ARCHIVE_MEMBER_HEADER;
|
||||
|
||||
///
|
||||
/// Size of EFI_IMAGE_ARCHIVE_MEMBER_HEADER.
|
||||
///
|
||||
#define EFI_IMAGE_SIZEOF_ARCHIVE_MEMBER_HDR 60
|
||||
|
||||
|
||||
//
|
||||
// DLL Support
|
||||
//
|
||||
|
||||
///
|
||||
/// Export Directory Table.
|
||||
///
|
||||
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;
|
||||
|
||||
///
|
||||
/// Hint/Name Table.
|
||||
///
|
||||
typedef struct {
|
||||
UINT16 Hint;
|
||||
UINT8 Name[1];
|
||||
} EFI_IMAGE_IMPORT_BY_NAME;
|
||||
|
||||
///
|
||||
/// Import Address Table RVA (Thunk Table).
|
||||
///
|
||||
typedef struct {
|
||||
union {
|
||||
UINT32 Function;
|
||||
UINT32 Ordinal;
|
||||
EFI_IMAGE_IMPORT_BY_NAME *AddressOfData;
|
||||
} u1;
|
||||
} EFI_IMAGE_THUNK_DATA;
|
||||
|
||||
#define EFI_IMAGE_ORDINAL_FLAG BIT31 ///< Flag for PE32.
|
||||
#define EFI_IMAGE_SNAP_BY_ORDINAL(Ordinal) ((Ordinal & EFI_IMAGE_ORDINAL_FLAG) != 0)
|
||||
#define EFI_IMAGE_ORDINAL(Ordinal) (Ordinal & 0xffff)
|
||||
|
||||
///
|
||||
/// Import Directory Table
|
||||
///
|
||||
typedef struct {
|
||||
UINT32 Characteristics;
|
||||
UINT32 TimeDateStamp;
|
||||
UINT32 ForwarderChain;
|
||||
UINT32 Name;
|
||||
EFI_IMAGE_THUNK_DATA *FirstThunk;
|
||||
} EFI_IMAGE_IMPORT_DESCRIPTOR;
|
||||
|
||||
|
||||
///
|
||||
/// Debug Directory Format.
|
||||
///
|
||||
typedef struct {
|
||||
UINT32 Characteristics;
|
||||
UINT32 TimeDateStamp;
|
||||
UINT16 MajorVersion;
|
||||
UINT16 MinorVersion;
|
||||
UINT32 Type;
|
||||
UINT32 SizeOfData;
|
||||
UINT32 RVA; ///< The address of the debug data when loaded, relative to the image base.
|
||||
UINT32 FileOffset; ///< The file pointer to the debug data.
|
||||
} EFI_IMAGE_DEBUG_DIRECTORY_ENTRY;
|
||||
|
||||
#define EFI_IMAGE_DEBUG_TYPE_CODEVIEW 2 ///< The Visual C++ debug information.
|
||||
|
||||
///
|
||||
/// Debug Data Structure defined in Microsoft C++.
|
||||
///
|
||||
#define CODEVIEW_SIGNATURE_NB10 SIGNATURE_32('N', 'B', '1', '0')
|
||||
typedef struct {
|
||||
UINT32 Signature; ///< "NB10"
|
||||
UINT32 Unknown;
|
||||
UINT32 Unknown2;
|
||||
UINT32 Unknown3;
|
||||
//
|
||||
// Filename of .PDB goes here
|
||||
//
|
||||
} EFI_IMAGE_DEBUG_CODEVIEW_NB10_ENTRY;
|
||||
|
||||
///
|
||||
/// Debug Data Structure defined in Microsoft C++.
|
||||
/// FIXME:
|
||||
/// Documentation available at: https://github.com/dotnet/runtime/blob/main/docs/design/specs/PE-COFF.md
|
||||
///
|
||||
#define CODEVIEW_SIGNATURE_RSDS SIGNATURE_32('R', 'S', 'D', 'S')
|
||||
typedef struct {
|
||||
//
|
||||
// 0x52 0x53 0x44 0x53 (ASCII string: "RSDS")
|
||||
//
|
||||
UINT32 Signature; ///< "RSDS".
|
||||
//
|
||||
// GUID (Globally Unique Identifier) of the associated PDB.
|
||||
//
|
||||
UINT8 Guid[16];
|
||||
//
|
||||
// Iteration of the PDB. The first iteration is 1. The iteration is
|
||||
// incremented each time the PDB content is augmented.
|
||||
//
|
||||
UINT32 Age;
|
||||
//
|
||||
// UTF-8 NUL-terminated path to the associated .pdb file
|
||||
//
|
||||
} EFI_IMAGE_DEBUG_CODEVIEW_RSDS_ENTRY;
|
||||
|
||||
|
||||
///
|
||||
/// Debug Data Structure defined by Apple Mach-O to Coff utility.
|
||||
///
|
||||
#define CODEVIEW_SIGNATURE_MTOC SIGNATURE_32('M', 'T', 'O', 'C')
|
||||
typedef struct {
|
||||
UINT32 Signature; ///< "MTOC".
|
||||
UINT8 Uuid[16];
|
||||
//
|
||||
// Filename of .DLL (Mach-O with debug info) goes here
|
||||
//
|
||||
} EFI_IMAGE_DEBUG_CODEVIEW_MTOC_ENTRY;
|
||||
|
||||
///
|
||||
/// Resource directory entry format.
|
||||
///
|
||||
typedef struct {
|
||||
union {
|
||||
struct {
|
||||
UINT32 NameOffset:31;
|
||||
UINT32 NameIsString:1;
|
||||
} s;
|
||||
UINT32 Id;
|
||||
} u1;
|
||||
union {
|
||||
UINT32 OffsetToData;
|
||||
struct {
|
||||
UINT32 OffsetToDirectory:31;
|
||||
UINT32 DataIsDirectory:1;
|
||||
} s;
|
||||
} u2;
|
||||
} EFI_IMAGE_RESOURCE_DIRECTORY_ENTRY;
|
||||
|
||||
///
|
||||
/// Resource format.
|
||||
///
|
||||
typedef struct {
|
||||
UINT32 Characteristics;
|
||||
UINT32 TimeDateStamp;
|
||||
UINT16 MajorVersion;
|
||||
UINT16 MinorVersion;
|
||||
UINT16 NumberOfNamedEntries;
|
||||
UINT16 NumberOfIdEntries;
|
||||
EFI_IMAGE_RESOURCE_DIRECTORY_ENTRY Entries[];
|
||||
} EFI_IMAGE_RESOURCE_DIRECTORY;
|
||||
|
||||
///
|
||||
/// Resource directory entry for string.
|
||||
///
|
||||
typedef struct {
|
||||
UINT16 Length;
|
||||
CHAR16 String[];
|
||||
} EFI_IMAGE_RESOURCE_DIRECTORY_STRING;
|
||||
|
||||
///
|
||||
/// Resource directory entry for data array.
|
||||
///
|
||||
typedef struct {
|
||||
UINT32 OffsetToData;
|
||||
UINT32 Size;
|
||||
UINT32 CodePage;
|
||||
UINT32 Reserved;
|
||||
} EFI_IMAGE_RESOURCE_DATA_ENTRY;
|
||||
|
||||
///
|
||||
/// Union of PE32 and PE32+ headers.
|
||||
///
|
||||
typedef union {
|
||||
EFI_IMAGE_NT_HEADERS_COMMON_HDR PeCommon;
|
||||
EFI_IMAGE_NT_HEADERS32 Pe32;
|
||||
EFI_IMAGE_NT_HEADERS64 Pe32Plus;
|
||||
} EFI_IMAGE_OPTIONAL_HEADER_UNION;
|
||||
|
||||
#endif // PE_COFF_IMAGE2_H_
|
|
@ -0,0 +1,667 @@
|
|||
/** @file
|
||||
Definitions of the UEFI Executable (UE) file format.
|
||||
|
||||
Copyright (c) 2021 - 2023, Marvin Häuser. All rights reserved.<BR>
|
||||
|
||||
SPDX-License-Identifier: BSD-2-Clause-Patent
|
||||
**/
|
||||
|
||||
#ifndef UE_IMAGE_H_
|
||||
#define UE_IMAGE_H_
|
||||
|
||||
#include <Library/BaseLib.h>
|
||||
|
||||
//
|
||||
// UE segment definitions.
|
||||
//
|
||||
|
||||
///
|
||||
/// Definition of the UE segment permission configurations.
|
||||
///
|
||||
enum {
|
||||
UeSegmentPermX = 0,
|
||||
UeSegmentPermRX = 1,
|
||||
UeSegmentPermRW = 2,
|
||||
//
|
||||
// Read-only is the last value, as this makes it easier to implement it as
|
||||
// the else/default case.
|
||||
//
|
||||
UeSegmentPermR = 3,
|
||||
UeSegmentPermMax
|
||||
};
|
||||
|
||||
///
|
||||
/// The minimum alignment requirement, in bytes, of each UE segment in the UE
|
||||
/// address space.
|
||||
///
|
||||
#define UE_SEGMENT_MIN_ALIGNMENT 0x00001000U
|
||||
|
||||
///
|
||||
/// The maximum alignment requirement, in bytes, of each UE segment in the UE
|
||||
/// address space.
|
||||
///
|
||||
#define UE_SEGMENT_MAX_ALIGNMENT 0x08000000U
|
||||
|
||||
///
|
||||
/// Information about the UE segment in the UE address space.
|
||||
///
|
||||
/// [Bits 19:0] The size, in 4-KiB units, of the UE segment in the UE address
|
||||
/// space.
|
||||
/// [Bits 21:20] The UE segment permissions.
|
||||
/// [Bits 31:22] Reserved for future use. Must be zero.
|
||||
///
|
||||
typedef UINT32 UE_SEGMENT_IMAGE_INFO;
|
||||
|
||||
///
|
||||
/// Definition of a UE segment header.
|
||||
///
|
||||
typedef struct {
|
||||
///
|
||||
/// Information about the UE segment in the UE address space.
|
||||
///
|
||||
UE_SEGMENT_IMAGE_INFO ImageInfo;
|
||||
///
|
||||
/// The size, in bytes, of the UE segment in the UE file.
|
||||
///
|
||||
UINT32 FileSize;
|
||||
} UE_SEGMENT;
|
||||
|
||||
STATIC_ASSERT (
|
||||
sizeof (UE_SEGMENT) == 8 && ALIGNOF (UE_SEGMENT) == 4,
|
||||
"The UE segment definition does not meet the specification."
|
||||
);
|
||||
|
||||
///
|
||||
/// Definition of a UE XIP segment header.
|
||||
///
|
||||
typedef struct {
|
||||
///
|
||||
/// Information about the UE segment in the UE address space.
|
||||
///
|
||||
UE_SEGMENT_IMAGE_INFO ImageInfo;
|
||||
} UE_SEGMENT_XIP;
|
||||
|
||||
STATIC_ASSERT (
|
||||
sizeof (UE_SEGMENT_XIP) == 4 && ALIGNOF (UE_SEGMENT_XIP) == 4,
|
||||
"The UE XIP segment definition does not meet the specification."
|
||||
);
|
||||
|
||||
/**
|
||||
Retrieve the UE segment memory permissions.
|
||||
|
||||
@param[in] ImageInfo The UE segment image information.
|
||||
**/
|
||||
#define UE_SEGMENT_PERMISSIONS(ImageInfo) \
|
||||
((UINT8)(((ImageInfo) >> 20U) & 0x03U))
|
||||
|
||||
/**
|
||||
Retrieve the size, in bytes, of the UE segment in the UE address space.
|
||||
|
||||
@param[in] ImageInfo The UE segment image information.
|
||||
**/
|
||||
#define UE_SEGMENT_SIZE(ImageInfo) ((ImageInfo) << 12U)
|
||||
|
||||
STATIC_ASSERT (
|
||||
IS_ALIGNED (UE_SEGMENT_SIZE (0xFFFFFFFF), UE_SEGMENT_MIN_ALIGNMENT),
|
||||
"The UE segment size definition does not meet the specification."
|
||||
);
|
||||
|
||||
//
|
||||
// UE load table definitions.
|
||||
//
|
||||
|
||||
///
|
||||
/// The alignment, in bytes, of each UE load table in the UE file.
|
||||
///
|
||||
#define UE_LOAD_TABLE_ALIGNMENT 8U
|
||||
|
||||
///
|
||||
/// Definition of the UE load table identifiers.
|
||||
///
|
||||
enum {
|
||||
//
|
||||
// An array of UE fixup roots. Blocks are ordered ascending by their
|
||||
// base address.
|
||||
//
|
||||
UeLoadTableIdReloc = 0x00,
|
||||
//
|
||||
// An instance of the UE debug table..
|
||||
//
|
||||
UeLoadTableIdDebug = 0x01
|
||||
};
|
||||
|
||||
///
|
||||
/// Definition of a UE load table header.
|
||||
///
|
||||
typedef struct {
|
||||
///
|
||||
/// Information about the UE load table.
|
||||
///
|
||||
/// [Bits 28:0] The size, in 8-byte units, of the UE load table in the UE
|
||||
/// file.
|
||||
/// [Bits 31:29] The identifier of the UE load table.
|
||||
///
|
||||
UINT32 FileInfo;
|
||||
} UE_LOAD_TABLE;
|
||||
|
||||
STATIC_ASSERT (
|
||||
sizeof (UE_LOAD_TABLE) == 4 && ALIGNOF (UE_LOAD_TABLE) == 4,
|
||||
"The UE load table definition does not meet the specification."
|
||||
);
|
||||
|
||||
/**
|
||||
Retrieves the UE load table identifier.
|
||||
|
||||
@param[in] FileInfo The UE load table file information.
|
||||
**/
|
||||
#define UE_LOAD_TABLE_ID(FileInfo) ((UINT8)((FileInfo) >> 29U))
|
||||
|
||||
/**
|
||||
Retrieves the size, in bytes, of the UE load table in the UE file.
|
||||
|
||||
@param[in] FileInfo The UE load table file information.
|
||||
**/
|
||||
#define UE_LOAD_TABLE_SIZE(FileInfo) ((FileInfo) << 3U)
|
||||
|
||||
STATIC_ASSERT (
|
||||
IS_ALIGNED (UE_LOAD_TABLE_SIZE (0xFFFFFFFF), UE_LOAD_TABLE_ALIGNMENT),
|
||||
"The UE load table size definition does not meet the specification."
|
||||
);
|
||||
|
||||
//
|
||||
// UE relocation table definitions.
|
||||
//
|
||||
|
||||
///
|
||||
/// Definitions of the generic UE relocation identifiers.
|
||||
///
|
||||
enum {
|
||||
UeReloc32 = 0x00,
|
||||
UeReloc64 = 0x01,
|
||||
UeReloc32NoMeta = 0x02,
|
||||
UeRelocGenericMax
|
||||
};
|
||||
|
||||
#if 0
|
||||
///
|
||||
/// Definition of the ARM UE relocation identifiers.
|
||||
///
|
||||
enum {
|
||||
UeRelocArmMovtMovw = 0x02
|
||||
};
|
||||
#endif
|
||||
|
||||
///
|
||||
/// The alignment requirement for a UE fixup root.
|
||||
///
|
||||
#define UE_FIXUP_ROOT_ALIGNMENT 4U
|
||||
|
||||
STATIC_ASSERT (
|
||||
UE_FIXUP_ROOT_ALIGNMENT <= UE_LOAD_TABLE_ALIGNMENT,
|
||||
"The UE fixup root definition does not meet the specification."
|
||||
);
|
||||
|
||||
///
|
||||
/// Definition of a UE fixup root.
|
||||
///
|
||||
typedef struct {
|
||||
///
|
||||
/// The offset of the first head fixup, in bytes, from the end of the previous
|
||||
/// UE relocation fixup (chained or not). The first UE fixup root is
|
||||
/// relative to 0.
|
||||
///
|
||||
UINT32 FirstOffset;
|
||||
///
|
||||
/// The head fixups of the UE fixup root.
|
||||
///
|
||||
/// [Bits 3:0] The type of the UE relocation fixup.
|
||||
/// [Bits 15:4] The offset of the next UE head fixup from the end of the last
|
||||
/// UE relocation fixup in the chain (if chained). If 0x0FFF, the
|
||||
/// current fixup root is terminated.
|
||||
///
|
||||
UINT16 Heads[];
|
||||
} UE_FIXUP_ROOT;
|
||||
|
||||
STATIC_ASSERT (
|
||||
sizeof (UE_FIXUP_ROOT) == 4 && ALIGNOF (UE_FIXUP_ROOT) == UE_FIXUP_ROOT_ALIGNMENT,
|
||||
"The UE fixup root definition does not meet the specification."
|
||||
);
|
||||
|
||||
STATIC_ASSERT (
|
||||
OFFSET_OF (UE_FIXUP_ROOT, Heads) == sizeof (UE_FIXUP_ROOT),
|
||||
"The UE fixup root definition does not meet the specification."
|
||||
);
|
||||
|
||||
STATIC_ASSERT (
|
||||
sizeof (UE_FIXUP_ROOT) <= UE_LOAD_TABLE_ALIGNMENT,
|
||||
"The UE fixup root definition is misaligned."
|
||||
);
|
||||
|
||||
#define MIN_SIZE_OF_UE_FIXUP_ROOT (sizeof (UE_FIXUP_ROOT) + sizeof (UINT16))
|
||||
|
||||
///
|
||||
/// The maximum offset, in bytes, of the next UE head fixup.
|
||||
///
|
||||
#define UE_HEAD_FIXUP_MAX_OFFSET 0x0FFEU
|
||||
|
||||
///
|
||||
/// UE head fixup offset that terminates a fixup root.
|
||||
///
|
||||
#define UE_HEAD_FIXUP_OFFSET_END 0x0FFFU
|
||||
|
||||
/**
|
||||
Retrieves the target offset of the UE relocation fixup.
|
||||
|
||||
@param[in] FixupInfo The UE relocation fixup information.
|
||||
**/
|
||||
#define UE_RELOC_FIXUP_OFFSET(FixupInfo) ((UINT16)((FixupInfo) >> 4U))
|
||||
|
||||
/**
|
||||
Retrieves the type of the UE relocation fixup.
|
||||
|
||||
@param[in] FixupInfo The UE relocation fixup information.
|
||||
**/
|
||||
#define UE_RELOC_FIXUP_TYPE(FixupInfo) ((FixupInfo) & 0x000FU)
|
||||
|
||||
/**
|
||||
Retrieves the offset of the next UE chained relocation fixup.
|
||||
|
||||
@param[in] FixupInfo The UE relocation fixup information.
|
||||
**/
|
||||
#define UE_CHAINED_RELOC_FIXUP_NEXT_OFFSET(FixupInfo) \
|
||||
((UINT16)((UINT16)(FixupInfo) >> 4U) & 0x0FFFU)
|
||||
|
||||
///
|
||||
/// The maximum offset, in bytes, of the next UE chained relocation fixup.
|
||||
///
|
||||
#define UE_CHAINED_RELOC_FIXUP_MAX_OFFSET 0x0FFEU
|
||||
|
||||
///
|
||||
/// UE chained relocation fixup offset that terminates a chain.
|
||||
///
|
||||
#define UE_CHAINED_RELOC_FIXUP_OFFSET_END 0x0FFFU
|
||||
|
||||
/**
|
||||
Retrieves the type of the next UE chained relocation fixup.
|
||||
|
||||
@param[in] FixupInfo The UE relocation fixup information.
|
||||
**/
|
||||
#define UE_CHAINED_RELOC_FIXUP_NEXT_TYPE(FixupInfo) \
|
||||
((UINT8)((UINT16)(FixupInfo) & 0x0FU))
|
||||
|
||||
///
|
||||
/// The shift exponent for UE chained relocation fixup values.
|
||||
///
|
||||
#define UE_CHAINED_RELOC_FIXUP_VALUE_SHIFT 16U
|
||||
|
||||
/**
|
||||
Retrieves the value of the current UE chained relocation fixup.
|
||||
|
||||
@param[in] FixupInfo The UE relocation fixup information.
|
||||
**/
|
||||
#define UE_CHAINED_RELOC_FIXUP_VALUE(FixupInfo) \
|
||||
RShiftU64 (FixupInfo, UE_CHAINED_RELOC_FIXUP_VALUE_SHIFT)
|
||||
|
||||
///
|
||||
/// Definition of the common header of UE chained relocation fixups.
|
||||
///
|
||||
/// [Bits 3:0] The relocation type of the next chained relocation fixup. Only
|
||||
/// valid when [Bits 15:4] are not 0x0FFF.
|
||||
/// [Bits 15:4] The offset to the next chained relocation fixup from the end
|
||||
/// of the current one. If 0x0FFF, the current chain is terminated.
|
||||
/// Consult the fixup root for further relocation fixups.
|
||||
///
|
||||
typedef UINT16 UE_RELOC_FIXUP_HDR;
|
||||
|
||||
///
|
||||
/// Definition of the generic 64-bit UE chained relocation fixup.
|
||||
///
|
||||
/// [Bits 15:0] The common header of UE chained relocation fixups.
|
||||
/// [Bits 47:16] The address value to relocate.
|
||||
/// [Bits 63:48] Must be zero.
|
||||
///
|
||||
typedef UINT64 UE_RELOC_FIXUP_64;
|
||||
|
||||
///
|
||||
/// The shift exponent for UE chained 32-bit relocation fixup values.
|
||||
///
|
||||
#define UE_CHAINED_RELOC_FIXUP_VALUE_32_SHIFT 12U
|
||||
|
||||
/**
|
||||
Retrieves the value of the current UE chained 32-bit relocation fixup.
|
||||
|
||||
@param[in] FixupInfo The UE relocation fixup information.
|
||||
**/
|
||||
#define UE_CHAINED_RELOC_FIXUP_VALUE_32(FixupInfo) \
|
||||
(UINT32)((UINT32)(FixupInfo) >> UE_CHAINED_RELOC_FIXUP_VALUE_32_SHIFT)
|
||||
|
||||
///
|
||||
/// Definition of the generic 32-bit UE chained relocation fixup.
|
||||
///
|
||||
/// [Bits 11:0] The offset to the next chained relocation fixup from the end
|
||||
/// of the current one. If 0x0FFF, the current chain is terminated.
|
||||
/// Consult the fixup root for further relocation fixups.
|
||||
/// [Bits 31:12] The address value to relocate.
|
||||
///
|
||||
typedef UINT32 UE_RELOC_FIXUP_32;
|
||||
|
||||
#if 0
|
||||
///
|
||||
/// Definition of the ARM Thumb MOVT/MOVW UE chained relocation fixup.
|
||||
///
|
||||
/// [Bits 15:0] The common header of UE chained relocation fixups.
|
||||
/// [Bits 31:16] The 16-bit immediate value to relocate.
|
||||
///
|
||||
typedef UINT32 UE_RELOC_FIXUP_ARM_MOVT_MOVW;
|
||||
#endif
|
||||
|
||||
//
|
||||
// UE debug table definitions.
|
||||
//
|
||||
// NOTE: The UE symbols base address offset is required for conversion of
|
||||
// PE Images that have their first section start after the end of the
|
||||
// Image headers. As PDBs cannot easily be rebased, store the offset.
|
||||
//
|
||||
|
||||
///
|
||||
/// Definition of a UE segment name. Must be \0-terminated.
|
||||
///
|
||||
typedef UINT8 UE_SEGMENT_NAME[8];
|
||||
|
||||
STATIC_ASSERT (
|
||||
sizeof (UE_SEGMENT_NAME) == 8 && ALIGNOF (UE_SEGMENT_NAME) == 1,
|
||||
"The UE segment name definition does not meet the specification."
|
||||
);
|
||||
|
||||
///
|
||||
/// Definition of the UE debug table header.
|
||||
///
|
||||
typedef struct {
|
||||
///
|
||||
/// Information about the image regarding the symbols file.
|
||||
///
|
||||
/// [Bits 1:0] The offset, in image alignment units, to be subtracted from the
|
||||
/// UE base address in order to retrieve the UE symbols base
|
||||
/// address.
|
||||
/// [Bits 7:2] Reserved for future use. Must be zero.
|
||||
///
|
||||
UINT8 ImageInfo;
|
||||
///
|
||||
/// The length, in bytes, of the UE symbols path (excluding the terminator).
|
||||
///
|
||||
UINT8 SymbolsPathLength;
|
||||
///
|
||||
/// The UE symbols path. Must be \0-terminated.
|
||||
///
|
||||
UINT8 SymbolsPath[];
|
||||
///
|
||||
/// The UE segment name table. The order matches the UE segment table.
|
||||
///
|
||||
//UE_SEGMENT_NAME SegmentNames[];
|
||||
} UE_DEBUG_TABLE;
|
||||
|
||||
///
|
||||
/// The minimum size, in bytes, of the UE debug table.
|
||||
///
|
||||
#define MIN_SIZE_OF_UE_DEBUG_TABLE \
|
||||
(OFFSET_OF (UE_DEBUG_TABLE, SymbolsPath) + 1U)
|
||||
|
||||
/**
|
||||
Retrieves the UE symbol address subtrahend in SegmentAlignment-units.
|
||||
|
||||
@param[in] ImageInfo The UE debug table image information.
|
||||
**/
|
||||
#define UE_DEBUG_TABLE_IMAGE_INFO_SYM_SUBTRAHEND_FACTOR(ImageInfo) \
|
||||
((UINT8)((ImageInfo) & 0x03U))
|
||||
|
||||
/**
|
||||
Retrieves the UE segment name table of a UE debug table.
|
||||
|
||||
@param[in] DebugTable The UE debug table.
|
||||
**/
|
||||
#define UE_DEBUG_TABLE_SEGMENT_NAMES(DebugTable) \
|
||||
(CONST UE_SEGMENT_NAME *) ( \
|
||||
(DebugTable)->SymbolsPath + (DebugTable)->SymbolsPathLength + 1 \
|
||||
)
|
||||
|
||||
STATIC_ASSERT (
|
||||
sizeof (UE_DEBUG_TABLE) == 2 && ALIGNOF (UE_DEBUG_TABLE) == 1,
|
||||
"The UE debug table definition does not meet the specification."
|
||||
);
|
||||
|
||||
STATIC_ASSERT (
|
||||
ALIGNOF (UE_DEBUG_TABLE) <= UE_LOAD_TABLE_ALIGNMENT,
|
||||
"The UE debug table definition is misaligned."
|
||||
);
|
||||
|
||||
STATIC_ASSERT (
|
||||
OFFSET_OF (UE_DEBUG_TABLE, SymbolsPath) == sizeof (UE_DEBUG_TABLE),
|
||||
"The UE fixup root definition does not meet the specification."
|
||||
);
|
||||
|
||||
//
|
||||
// UE header definitions.
|
||||
//
|
||||
|
||||
///
|
||||
/// The file magic number of a UE header.
|
||||
///
|
||||
#define UE_HEADER_MAGIC SIGNATURE_16 ('U', 'E')
|
||||
|
||||
///
|
||||
/// Definition of the UE machine identifiers.
|
||||
///
|
||||
enum {
|
||||
UeMachineI386 = 0,
|
||||
UeMachineX64 = 1,
|
||||
UeMachineArmThumbMixed = 2,
|
||||
UeMachineArm64 = 3,
|
||||
UeMachineRiscV32 = 4,
|
||||
UeMachineRiscV64 = 5,
|
||||
UeMachineRiscV128 = 6
|
||||
};
|
||||
|
||||
///
|
||||
/// Definition of the UE subsystem identifiers.
|
||||
///
|
||||
enum {
|
||||
UeSubsystemEfiApplication = 0,
|
||||
UeSubsystemEfiBootServicesDriver = 1,
|
||||
UeSubsystemEfiRuntimeDriver = 2
|
||||
};
|
||||
|
||||
///
|
||||
/// Definition of a UE file header.
|
||||
///
|
||||
typedef struct {
|
||||
///
|
||||
/// The file magic number to identify the UE file format. Must be 'UE'.
|
||||
///
|
||||
UINT16 Magic;
|
||||
///
|
||||
/// Information about the image kind and supported architectures.
|
||||
///
|
||||
/// [Bits 2:0] Indicates the subsystem.
|
||||
/// [Bits 7:3] Indicates the supported architectures.
|
||||
///
|
||||
UINT8 Type;
|
||||
///
|
||||
/// Information about the UE load tables and segments.
|
||||
///
|
||||
/// [Bits 2:0] The number of UE load tables.
|
||||
/// [Bits 7:3] The index of the last segment in the UE segment table.
|
||||
///
|
||||
UINT8 TableCounts;
|
||||
///
|
||||
/// Indicates the offset of the UE entry point in the UE address space.
|
||||
///
|
||||
UINT32 EntryPointAddress;
|
||||
///
|
||||
/// Information about the UE image.
|
||||
///
|
||||
/// [Bits 51:0] The base UEFI page of the UE image, i.e., the base address in
|
||||
/// 4 KiB units.
|
||||
/// [Bits 55:52] Reserved for future use. Must be zero.
|
||||
/// [Bit 56] Indicates whether the UE image is XIP
|
||||
/// [Bit 57] Indicates whether the UE image is designated for a fixed
|
||||
/// address.
|
||||
/// [Bit 58] Indicates whether the UE relocation table has been stripped.
|
||||
/// [Bit 59] Indicates whether UE chained fixups are used.
|
||||
/// [Bits 63:60] The shift exponent, offset by -12, for the UE segment
|
||||
/// alignment in bytes.
|
||||
///
|
||||
UINT64 ImageInfo;
|
||||
///
|
||||
/// The UE segment table. It contains all data of the UE address space.
|
||||
///
|
||||
/// All UE segments are contiguous in the UE address space.
|
||||
/// The offset of the first UE segment in the UE address space is 0.
|
||||
///
|
||||
/// All UE segments' data are contiguous in the UE file.
|
||||
/// The offset of the first UE segment in the UE file is the end of the UE
|
||||
/// file header.
|
||||
///
|
||||
UE_SEGMENT Segments[];
|
||||
///
|
||||
/// The UE load tables. They contain data useful for UE loading.
|
||||
///
|
||||
/// All UE load tables are contiguous in the UE file.
|
||||
/// The offset of the first UE load table in the UE file is the end of the last
|
||||
/// UE segment in the UE file.
|
||||
///
|
||||
/// All UE load tables are ordered ascending by their identifier.
|
||||
///
|
||||
//UE_LOAD_TABLE LoadTables[];
|
||||
} UE_HEADER;
|
||||
|
||||
///
|
||||
/// The minimum size, in bytes, of a valid UE header.
|
||||
///
|
||||
#define MIN_SIZE_OF_UE_HEADER \
|
||||
(OFFSET_OF (UE_HEADER, Segments) + sizeof (UE_SEGMENT))
|
||||
|
||||
STATIC_ASSERT (
|
||||
sizeof (UE_HEADER) == 16 && ALIGNOF (UE_HEADER) == 8,
|
||||
"The UE header definition does not meet the specification."
|
||||
);
|
||||
|
||||
STATIC_ASSERT (
|
||||
ALIGNOF (UE_SEGMENT) <= ALIGNOF (UE_LOAD_TABLE),
|
||||
"The UE header definition is misaligned."
|
||||
);
|
||||
|
||||
STATIC_ASSERT (
|
||||
OFFSET_OF (UE_HEADER, Segments) == sizeof (UE_HEADER),
|
||||
"The UE header definition does not meet the specification."
|
||||
);
|
||||
|
||||
/**
|
||||
Retrieves the UE base address.
|
||||
|
||||
@param[in] ImageInfo The UE header image information.
|
||||
**/
|
||||
#define UE_HEADER_BASE_ADDRESS(ImageInfo) LShiftU64 (ImageInfo, 12)
|
||||
|
||||
/**
|
||||
Retrieves the UE segment alignment, in bytes, as a power of two.
|
||||
|
||||
@param[in] ImageInfo The UE header image information.
|
||||
**/
|
||||
#define UE_HEADER_SEGMENT_ALIGNMENT(ImageInfo) \
|
||||
(1U << ((UINT8)RShiftU64 (ImageInfo, 60) + 12U))
|
||||
|
||||
///
|
||||
/// UE header image information bit that indicates whether the image is XIP.
|
||||
///
|
||||
#define UE_HEADER_IMAGE_INFO_XIP 0x0100000000000000ULL
|
||||
|
||||
///
|
||||
/// UE header image information bit that indicates whether the image is
|
||||
/// designated to be loaded to a fixed address.
|
||||
///
|
||||
#define UE_HEADER_IMAGE_INFO_FIXED_ADDRESS 0x0200000000000000ULL
|
||||
|
||||
///
|
||||
/// UE header image information bit that indicates whether the relocation fixups
|
||||
/// have been stripped.
|
||||
///
|
||||
#define UE_HEADER_IMAGE_INFO_RELOCATION_FIXUPS_STRIPPED 0x0400000000000000ULL
|
||||
|
||||
///
|
||||
/// UE header image information bit that indicates whether UE relocation fixup
|
||||
/// chains are utilized.
|
||||
///
|
||||
#define UE_HEADER_IMAGE_INFO_CHAINED_FIXUPS 0x0800000000000000ULL
|
||||
|
||||
/**
|
||||
Retrieves the UE subsystem.
|
||||
|
||||
@param[in] Type The UE header type information.
|
||||
**/
|
||||
#define UE_HEADER_SUBSYSTEM(Type) ((Type) & 0x07U)
|
||||
|
||||
/**
|
||||
Retrieves the UE supported architectures.
|
||||
|
||||
@param[in] Type The UE header type information.
|
||||
**/
|
||||
#define UE_HEADER_ARCH(Type) ((Type) >> 3U)
|
||||
|
||||
///
|
||||
/// The maximum number of UE load tables.
|
||||
///
|
||||
#define UE_HEADER_NUM_LOAD_TABLES_MAX 7U
|
||||
|
||||
/**
|
||||
Retrieves the number of UE load tables.
|
||||
|
||||
@param[in] TableCounts The UE header segment and load table information.
|
||||
**/
|
||||
#define UE_HEADER_NUM_LOAD_TABLES(TableCounts) ((TableCounts) & 0x07U)
|
||||
|
||||
STATIC_ASSERT (
|
||||
UE_HEADER_NUM_LOAD_TABLES (0xFFU) == UE_HEADER_NUM_LOAD_TABLES_MAX,
|
||||
"The number of load tables violates the specification."
|
||||
);
|
||||
|
||||
///
|
||||
/// The maximum number of UE segments.
|
||||
///
|
||||
#define UE_HEADER_NUM_SEGMENTS_MAX 32U
|
||||
|
||||
/**
|
||||
Retrieves the index of the last UE segment, i.e., their amount minus 1.
|
||||
|
||||
@param[in] TableCounts The UE header segment and load table information.
|
||||
**/
|
||||
#define UE_HEADER_LAST_SEGMENT_INDEX(TableCounts) ((TableCounts) >> 3U)
|
||||
|
||||
STATIC_ASSERT (
|
||||
UE_HEADER_LAST_SEGMENT_INDEX (0xFFU) + 1U == UE_HEADER_NUM_SEGMENTS_MAX,
|
||||
"The number of load tables violates the specification."
|
||||
);
|
||||
|
||||
/**
|
||||
Retrieves the 8 byte aligned UE file size.
|
||||
|
||||
If the file size is larger than this value, the appended data may be the UE
|
||||
certificate table.
|
||||
|
||||
@param[in] FileInfo The UE header file information.
|
||||
**/
|
||||
#define UE_HEADER_FILE_SIZE(FileInfo) ((FileInfo) << 3U)
|
||||
|
||||
STATIC_ASSERT (
|
||||
IS_ALIGNED (UE_HEADER_FILE_SIZE (0xFFFFFFFF), UE_LOAD_TABLE_ALIGNMENT),
|
||||
"The UE file size definition does not meet the specification."
|
||||
);
|
||||
|
||||
///
|
||||
/// The maximum size, in bytes, of a valid UE header.
|
||||
///
|
||||
#define MAX_SIZE_OF_UE_HEADER \
|
||||
MIN_SIZE_OF_UE_HEADER + \
|
||||
UE_HEADER_NUM_SEGMENTS_MAX * sizeof (UE_SEGMENT) + \
|
||||
UE_HEADER_NUM_LOAD_TABLES_MAX * sizeof (UE_LOAD_TABLE)
|
||||
|
||||
#endif // UE_IMAGE_H_
|
|
@ -3028,6 +3028,34 @@ PathCleanUpDirectories(
|
|||
#define INITIALIZE_LIST_HEAD_VARIABLE(ListHead) {&(ListHead), &(ListHead)}
|
||||
|
||||
|
||||
/**
|
||||
Iterates over each node in a doubly linked list using each node's forward link.
|
||||
|
||||
@param Entry A pointer to a list node used as a loop cursor during iteration
|
||||
@param ListHead The head node of the doubly linked list
|
||||
|
||||
**/
|
||||
#define BASE_LIST_FOR_EACH(Entry, ListHead) \
|
||||
for(Entry = (ListHead)->ForwardLink; Entry != (ListHead); Entry = Entry->ForwardLink)
|
||||
|
||||
/**
|
||||
Iterates over each node in a doubly linked list using each node's forward link
|
||||
with safety against node removal.
|
||||
|
||||
This macro uses NextEntry to temporarily store the next list node so the node
|
||||
pointed to by Entry may be deleted in the current loop iteration step and
|
||||
iteration can continue from the node pointed to by NextEntry.
|
||||
|
||||
@param Entry A pointer to a list node used as a loop cursor during iteration
|
||||
@param NextEntry A pointer to a list node used to temporarily store the next node
|
||||
@param ListHead The head node of the doubly linked list
|
||||
|
||||
**/
|
||||
#define BASE_LIST_FOR_EACH_SAFE(Entry, NextEntry, ListHead) \
|
||||
for(Entry = (ListHead)->ForwardLink, NextEntry = Entry->ForwardLink;\
|
||||
Entry != (ListHead); Entry = NextEntry, NextEntry = Entry->ForwardLink)
|
||||
|
||||
|
||||
/**
|
||||
Checks whether FirstEntry and SecondEntry are part of the same doubly-linked
|
||||
list.
|
||||
|
@ -5065,6 +5093,40 @@ CalculateCrc32(
|
|||
IN UINTN Length
|
||||
);
|
||||
|
||||
/**
|
||||
Calculates the CRC16-ANSI checksum of the given buffer.
|
||||
|
||||
@param[in] Buffer Pointer to the buffer.
|
||||
@param[in] Length Length of the buffer, in bytes.
|
||||
@param[in] InitialValue Initial value of the CRC.
|
||||
|
||||
@return The CRC16-ANSI checksum.
|
||||
**/
|
||||
UINT16
|
||||
EFIAPI
|
||||
CalculateCrc16Ansi (
|
||||
IN CONST VOID *Buffer,
|
||||
IN UINTN Length,
|
||||
IN UINT16 InitialValue
|
||||
);
|
||||
|
||||
/**
|
||||
Calculates the CRC32c checksum of the given buffer.
|
||||
|
||||
@param[in] Buffer Pointer to the buffer.
|
||||
@param[in] Length Length of the buffer, in bytes.
|
||||
@param[in] InitialValue Initial value of the CRC.
|
||||
|
||||
@return The CRC32c checksum.
|
||||
**/
|
||||
UINT32
|
||||
EFIAPI
|
||||
CalculateCrc32c (
|
||||
IN CONST VOID *Buffer,
|
||||
IN UINTN Length,
|
||||
IN UINT32 InitialValue
|
||||
);
|
||||
|
||||
//
|
||||
// Base Library CPU Functions
|
||||
//
|
||||
|
|
|
@ -0,0 +1,445 @@
|
|||
/** @file
|
||||
|
||||
BaseOverflowLib
|
||||
|
||||
Copyright (c) 2018, vit9696
|
||||
|
||||
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 __BASE_OVERFLOW_LIB__
|
||||
#define __BASE_OVERFLOW_LIB__
|
||||
|
||||
//
|
||||
// The macros below provide pointer alignment checking interfaces.
|
||||
// TypedPtr - pointer of a dedicated type, which alignment is to be checked.
|
||||
// Align - valid alignment for the target platform (power of two so far).
|
||||
// Type - valid complete typename.
|
||||
// Ptr - raw pointer value, must fit into UINTN, meant to be uintptr_t equivalent.
|
||||
//
|
||||
|
||||
#define BASE_ALIGNOF(Type) (_Alignof (Type))
|
||||
#define BASE_POT_ALIGNED(Align, Ptr) (0ULL == (((UINTN) (Ptr)) & (Align-1U)))
|
||||
#define BASE_TYPE_ALIGNED(Type, Ptr) (BASE_POT_ALIGNED (BASE_ALIGNOF (Type), Ptr))
|
||||
|
||||
//
|
||||
// Force member alignment for the structure.
|
||||
//
|
||||
#if (defined (__STDC__) && __STDC_VERSION__ >= 201112L) || defined (__GNUC__) || defined (__clang__)
|
||||
#define BASE_ALIGNAS(Alignment) _Alignas(Alignment)
|
||||
#else
|
||||
#define BASE_ALIGNAS(Alignment)
|
||||
#endif
|
||||
|
||||
/**
|
||||
Return the result of (Multiplicand * Multiplier / Divisor).
|
||||
|
||||
@param Multiplicand A 64-bit unsigned value.
|
||||
@param Multiplier A 64-bit unsigned value.
|
||||
@param Divisor A 32-bit unsigned value.
|
||||
@param Remainder A pointer to a 32-bit unsigned value. This parameter is
|
||||
optional and may be NULL.
|
||||
|
||||
@return Multiplicand * Multiplier / Divisor.
|
||||
**/
|
||||
UINT64
|
||||
BaseMultThenDivU64x64x32 (
|
||||
IN UINT64 Multiplicand,
|
||||
IN UINT64 Multiplier,
|
||||
IN UINT32 Divisor,
|
||||
OUT UINT32 *Remainder OPTIONAL
|
||||
);
|
||||
|
||||
//
|
||||
// The interfaces below provide base safe arithmetics, reporting
|
||||
// signed integer overflow and unsigned integer wraparound similarly to
|
||||
// os/overflow.h in macOS SDK.
|
||||
//
|
||||
// Each interface may be implemented not only as an actual function, but
|
||||
// a macro as well. Macro implementations are allowed to evaluate the
|
||||
// expressions no more than once, and are supposed to provide faster
|
||||
// compiler builtins if available.
|
||||
//
|
||||
// Each interface returns FALSE when the the stored result is equal to
|
||||
// the infinite precision result, otherwise TRUE. The operands should
|
||||
// be read left to right with the last argument representing a non-NULL
|
||||
// pointer to the resulting value of the same type.
|
||||
//
|
||||
// More information could be found in Clang Extensions documentation:
|
||||
// http://releases.llvm.org/7.0.0/tools/clang/docs/LanguageExtensions.html#checked-arithmetic-builtins
|
||||
//
|
||||
|
||||
//
|
||||
// 32-bit integer addition, subtraction, multiplication, triple addition (A+B+C),
|
||||
// triple multiplication (A*B*C), addition with multiplication ((A+B)*C),
|
||||
// and multiplication with addition (A*B+C) support.
|
||||
//
|
||||
|
||||
BOOLEAN
|
||||
BaseOverflowAddU16 (
|
||||
UINT16 A,
|
||||
UINT16 B,
|
||||
UINT16 *Result
|
||||
);
|
||||
|
||||
BOOLEAN
|
||||
BaseOverflowSubU16 (
|
||||
UINT16 A,
|
||||
UINT16 B,
|
||||
UINT16 *Result
|
||||
);
|
||||
|
||||
BOOLEAN
|
||||
BaseOverflowMulU16 (
|
||||
UINT16 A,
|
||||
UINT16 B,
|
||||
UINT16 *Result
|
||||
);
|
||||
|
||||
BOOLEAN
|
||||
BaseOverflowAddU32 (
|
||||
UINT32 A,
|
||||
UINT32 B,
|
||||
UINT32 *Result
|
||||
);
|
||||
|
||||
BOOLEAN
|
||||
BaseOverflowSubU32 (
|
||||
UINT32 A,
|
||||
UINT32 B,
|
||||
UINT32 *Result
|
||||
);
|
||||
|
||||
BOOLEAN
|
||||
BaseOverflowMulU32 (
|
||||
UINT32 A,
|
||||
UINT32 B,
|
||||
UINT32 *Result
|
||||
);
|
||||
|
||||
BOOLEAN
|
||||
BaseOverflowTriAddU32 (
|
||||
UINT32 A,
|
||||
UINT32 B,
|
||||
UINT32 C,
|
||||
UINT32 *Result
|
||||
);
|
||||
|
||||
BOOLEAN
|
||||
BaseOverflowTriMulU32 (
|
||||
UINT32 A,
|
||||
UINT32 B,
|
||||
UINT32 C,
|
||||
UINT32 *Result
|
||||
);
|
||||
|
||||
BOOLEAN
|
||||
BaseOverflowAddMulU32 (
|
||||
UINT32 A,
|
||||
UINT32 B,
|
||||
UINT32 C,
|
||||
UINT32 *Result
|
||||
);
|
||||
|
||||
BOOLEAN
|
||||
BaseOverflowMulAddU32 (
|
||||
UINT32 A,
|
||||
UINT32 B,
|
||||
UINT32 C,
|
||||
UINT32 *Result
|
||||
);
|
||||
|
||||
BOOLEAN
|
||||
BaseOverflowAlignUpU32 (
|
||||
UINT32 Value,
|
||||
UINT32 Alignment,
|
||||
UINT32 *Result
|
||||
);
|
||||
|
||||
BOOLEAN
|
||||
BaseOverflowAddS32 (
|
||||
INT32 A,
|
||||
INT32 B,
|
||||
INT32 *Result
|
||||
);
|
||||
|
||||
BOOLEAN
|
||||
BaseOverflowSubS32 (
|
||||
INT32 A,
|
||||
INT32 B,
|
||||
INT32 *Result
|
||||
);
|
||||
|
||||
BOOLEAN
|
||||
BaseOverflowMulS32 (
|
||||
INT32 A,
|
||||
INT32 B,
|
||||
INT32 *Result
|
||||
);
|
||||
|
||||
BOOLEAN
|
||||
BaseOverflowTriAddS32 (
|
||||
INT32 A,
|
||||
INT32 B,
|
||||
INT32 C,
|
||||
INT32 *Result
|
||||
);
|
||||
|
||||
BOOLEAN
|
||||
BaseOverflowTriMulS32 (
|
||||
INT32 A,
|
||||
INT32 B,
|
||||
INT32 C,
|
||||
INT32 *Result
|
||||
);
|
||||
|
||||
BOOLEAN
|
||||
BaseOverflowAddMulS32 (
|
||||
INT32 A,
|
||||
INT32 B,
|
||||
INT32 C,
|
||||
INT32 *Result
|
||||
);
|
||||
|
||||
BOOLEAN
|
||||
BaseOverflowMulAddS32 (
|
||||
INT32 A,
|
||||
INT32 B,
|
||||
INT32 C,
|
||||
INT32 *Result
|
||||
);
|
||||
|
||||
//
|
||||
// 64-bit integer addition, subtraction, multiplication, triple addition (A+B+C),
|
||||
// triple multiplication (A*B*C), addition with multiplication ((A+B)*C),
|
||||
// and multiplication with addition (A*B+C) support.
|
||||
//
|
||||
|
||||
BOOLEAN
|
||||
BaseOverflowAddU64 (
|
||||
UINT64 A,
|
||||
UINT64 B,
|
||||
UINT64 *Result
|
||||
);
|
||||
|
||||
BOOLEAN
|
||||
BaseOverflowSubU64 (
|
||||
UINT64 A,
|
||||
UINT64 B,
|
||||
UINT64 *Result
|
||||
);
|
||||
|
||||
BOOLEAN
|
||||
BaseOverflowMulU64 (
|
||||
UINT64 A,
|
||||
UINT64 B,
|
||||
UINT64 *Result
|
||||
);
|
||||
|
||||
BOOLEAN
|
||||
BaseOverflowTriAddU64 (
|
||||
UINT64 A,
|
||||
UINT64 B,
|
||||
UINT64 C,
|
||||
UINT64 *Result
|
||||
);
|
||||
|
||||
BOOLEAN
|
||||
BaseOverflowTriMulU64 (
|
||||
UINT64 A,
|
||||
UINT64 B,
|
||||
UINT64 C,
|
||||
UINT64 *Result
|
||||
);
|
||||
|
||||
BOOLEAN
|
||||
BaseOverflowAddMulU64 (
|
||||
UINT64 A,
|
||||
UINT64 B,
|
||||
UINT64 C,
|
||||
UINT64 *Result
|
||||
);
|
||||
|
||||
BOOLEAN
|
||||
BaseOverflowMulAddU64 (
|
||||
UINT64 A,
|
||||
UINT64 B,
|
||||
UINT64 C,
|
||||
UINT64 *Result
|
||||
);
|
||||
|
||||
BOOLEAN
|
||||
BaseOverflowAddS64 (
|
||||
INT64 A,
|
||||
INT64 B,
|
||||
INT64 *Result
|
||||
);
|
||||
|
||||
BOOLEAN
|
||||
BaseOverflowSubS64 (
|
||||
INT64 A,
|
||||
INT64 B,
|
||||
INT64 *Result
|
||||
);
|
||||
|
||||
BOOLEAN
|
||||
BaseOverflowMulS64 (
|
||||
INT64 A,
|
||||
INT64 B,
|
||||
INT64 *Result
|
||||
);
|
||||
|
||||
BOOLEAN
|
||||
BaseOverflowTriAddS64 (
|
||||
INT64 A,
|
||||
INT64 B,
|
||||
INT64 C,
|
||||
INT64 *Result
|
||||
);
|
||||
|
||||
BOOLEAN
|
||||
BaseOverflowTriMulS64 (
|
||||
INT64 A,
|
||||
INT64 B,
|
||||
INT64 C,
|
||||
INT64 *Result
|
||||
);
|
||||
|
||||
BOOLEAN
|
||||
BaseOverflowAddMulS64 (
|
||||
INT64 A,
|
||||
INT64 B,
|
||||
INT64 C,
|
||||
INT64 *Result
|
||||
);
|
||||
|
||||
BOOLEAN
|
||||
BaseOverflowMulAddS64 (
|
||||
INT64 A,
|
||||
INT64 B,
|
||||
INT64 C,
|
||||
INT64 *Result
|
||||
);
|
||||
|
||||
//
|
||||
// Native integer addition, subtraction, multiplication, triple addition (A+B+C),
|
||||
// triple multiplication (A*B*C), addition with multiplication ((A+B)*C),
|
||||
// and multiplication with addition (A*B+C) support.
|
||||
//
|
||||
|
||||
BOOLEAN
|
||||
BaseOverflowAddUN (
|
||||
UINTN A,
|
||||
UINTN B,
|
||||
UINTN *Result
|
||||
);
|
||||
|
||||
BOOLEAN
|
||||
BaseOverflowSubUN (
|
||||
UINTN A,
|
||||
UINTN B,
|
||||
UINTN *Result
|
||||
);
|
||||
|
||||
BOOLEAN
|
||||
BaseOverflowMulUN (
|
||||
UINTN A,
|
||||
UINTN B,
|
||||
UINTN *Result
|
||||
);
|
||||
|
||||
BOOLEAN
|
||||
BaseOverflowTriAddUN (
|
||||
UINTN A,
|
||||
UINTN B,
|
||||
UINTN C,
|
||||
UINTN *Result
|
||||
);
|
||||
|
||||
BOOLEAN
|
||||
BaseOverflowTriMulUN (
|
||||
UINTN A,
|
||||
UINTN B,
|
||||
UINTN C,
|
||||
UINTN *Result
|
||||
);
|
||||
|
||||
BOOLEAN
|
||||
BaseOverflowAddMulUN (
|
||||
UINTN A,
|
||||
UINTN B,
|
||||
UINTN C,
|
||||
UINTN *Result
|
||||
);
|
||||
|
||||
BOOLEAN
|
||||
BaseOverflowMulAddUN (
|
||||
UINTN A,
|
||||
UINTN B,
|
||||
UINTN C,
|
||||
UINTN *Result
|
||||
);
|
||||
|
||||
BOOLEAN
|
||||
BaseOverflowAddSN (
|
||||
INTN A,
|
||||
INTN B,
|
||||
INTN *Result
|
||||
);
|
||||
|
||||
BOOLEAN
|
||||
BaseOverflowSubSN (
|
||||
INTN A,
|
||||
INTN B,
|
||||
INTN *Result
|
||||
);
|
||||
|
||||
BOOLEAN
|
||||
BaseOverflowMulSN (
|
||||
INTN A,
|
||||
INTN B,
|
||||
INTN *Result
|
||||
);
|
||||
|
||||
BOOLEAN
|
||||
BaseOverflowTriAddSN (
|
||||
INTN A,
|
||||
INTN B,
|
||||
INTN C,
|
||||
INTN *Result
|
||||
);
|
||||
|
||||
BOOLEAN
|
||||
BaseOverflowTriMulSN (
|
||||
INTN A,
|
||||
INTN B,
|
||||
INTN C,
|
||||
INTN *Result
|
||||
);
|
||||
|
||||
BOOLEAN
|
||||
BaseOverflowAddMulSN (
|
||||
INTN A,
|
||||
INTN B,
|
||||
INTN C,
|
||||
INTN *Result
|
||||
);
|
||||
|
||||
BOOLEAN
|
||||
BaseOverflowMulAddSN (
|
||||
INTN A,
|
||||
INTN B,
|
||||
INTN C,
|
||||
INTN *Result
|
||||
);
|
||||
|
||||
#endif // __BASE_OVERFLOW_LIB__
|
|
@ -16,6 +16,7 @@ SPDX-License-Identifier: BSD-2-Clause-Patent
|
|||
#ifndef __DEBUG_LIB_H__
|
||||
#define __DEBUG_LIB_H__
|
||||
|
||||
#include <Library/BaseLib.h> // jief : for CpuBreakpoint() definition
|
||||
//
|
||||
// Declare bits for PcdDebugPropertyMask
|
||||
//
|
||||
|
@ -585,6 +586,20 @@ DebugPrintLevelEnabled (
|
|||
} \
|
||||
} while (FALSE)
|
||||
|
||||
#define DEBUG_RAISE() \
|
||||
do { \
|
||||
if ((PcdGet8 (PcdDebugRaisePropertyMask) & DEBUG_PROPERTY_DEBUG_PRINT_ENABLED) != 0) { \
|
||||
DEBUG ((DEBUG_WARN, "DEBUG RAISE: Constraint violation in %a:%a:%u\n", __FILE__, __func__, __LINE__));\
|
||||
} \
|
||||
\
|
||||
if ((PcdGet8 (PcdDebugRaisePropertyMask) & DEBUG_PROPERTY_DEBUG_ASSERT_ENABLED) != 0) { \
|
||||
ASSERT (FALSE); \
|
||||
} \
|
||||
\
|
||||
if ((PcdGet8 (PcdDebugRaisePropertyMask) & DEBUG_PROPERTY_ASSERT_BREAKPOINT_ENABLED) != 0) { \
|
||||
CpuBreakpoint (); \
|
||||
} \
|
||||
} while (FALSE)
|
||||
|
||||
/**
|
||||
Macro that calls DebugAssert() if the containing record does not have a
|
||||
|
|
|
@ -0,0 +1,75 @@
|
|||
/** @file
|
||||
Provides extended services to allocate and free memory buffers of various memory types and alignments.
|
||||
This header is part of the MemoryAllocationLib library class. Every instance
|
||||
of MemoryAllocationLib must also implement the functions declared by this
|
||||
header. The separation is due to the newly-introduced dependency on
|
||||
MdePkg/Uefi/UefiSpec.h.
|
||||
|
||||
Copyright (c) 2023, Marvin Häuser. All rights reserved.<BR>
|
||||
SPDX-License-Identifier: BSD-2-Clause-Patent
|
||||
|
||||
**/
|
||||
|
||||
#ifndef __MEMORY_ALLOCATION_LIB_EX_H__
|
||||
#define __MEMORY_ALLOCATION_LIB_EX_H__
|
||||
|
||||
/**
|
||||
Allocates one or more 4KB pages of a certain memory type.
|
||||
|
||||
Allocates the number of 4KB pages of a certain memory type and returns a pointer
|
||||
to the allocated buffer. The buffer returned is aligned on a 4KB boundary.
|
||||
|
||||
@param Type The type of allocation to perform.
|
||||
@param MemoryType The type of memory to allocate.
|
||||
@param Pages The number of 4 KB pages to allocate.
|
||||
@param Memory The pointer to a physical address. On input, the
|
||||
way in which the address is used depends on the
|
||||
value of Type.
|
||||
|
||||
@retval EFI_SUCCESS The requested pages were allocated.
|
||||
@retval EFI_OUT_OF_RESOURCES The pages could not be allocated.
|
||||
@retval EFI_NOT_FOUND The requested pages could not be found.
|
||||
|
||||
**/
|
||||
EFI_STATUS
|
||||
EFIAPI
|
||||
AllocatePagesEx (
|
||||
IN EFI_ALLOCATE_TYPE Type,
|
||||
IN EFI_MEMORY_TYPE MemoryType,
|
||||
IN UINTN Pages,
|
||||
IN OUT EFI_PHYSICAL_ADDRESS *Memory
|
||||
);
|
||||
|
||||
/**
|
||||
Allocates one or more 4KB pages of a certain memory type at a specified alignment.
|
||||
|
||||
Allocates the number of 4KB pages specified by Pages of a certain memory type with an alignment
|
||||
specified by Alignment.
|
||||
If Alignment is not a power of two and Alignment is not zero, then ASSERT().
|
||||
If Pages plus EFI_SIZE_TO_PAGES (Alignment) overflows, then ASSERT().
|
||||
|
||||
@param Type The type of allocation to perform.
|
||||
@param MemoryType The type of memory to allocate.
|
||||
@param Pages The number of 4 KB pages to allocate.
|
||||
@param Alignment The requested alignment of the allocation. Must be a power of two.
|
||||
If Alignment is zero, then byte alignment is used.
|
||||
@param Memory The pointer to a physical address. On input, the
|
||||
way in which the address is used depends on the
|
||||
value of Type.
|
||||
|
||||
@retval EFI_SUCCESS The requested pages were allocated.
|
||||
@retval EFI_OUT_OF_RESOURCES The pages could not be allocated.
|
||||
@retval EFI_NOT_FOUND The requested pages could not be found.
|
||||
|
||||
**/
|
||||
EFI_STATUS
|
||||
EFIAPI
|
||||
AllocateAlignedPagesEx (
|
||||
IN EFI_ALLOCATE_TYPE Type,
|
||||
IN EFI_MEMORY_TYPE MemoryType,
|
||||
IN UINTN Pages,
|
||||
IN UINTN Alignment,
|
||||
IN OUT EFI_PHYSICAL_ADDRESS *Memory
|
||||
);
|
||||
|
||||
#endif
|
|
@ -0,0 +1,590 @@
|
|||
/** @file
|
||||
Provides APIs to inspect, load, and relocate PE/COFF Images.
|
||||
|
||||
No implementation of this library may use global variable pointers, as this
|
||||
may cause the emission of Image relocations for this address. This is
|
||||
incompatible with the concept of Image self-relocation, where the Image is
|
||||
loaded in a similar fashion to XIP Images into the memory at an address
|
||||
unknown at compile-time. As such, Image relocation must be safe to perform
|
||||
without any Image relocations applied earlier.
|
||||
|
||||
Copyright (c) 2020 - 2021, Marvin Häuser. All rights reserved.<BR>
|
||||
Copyright (c) 2020, Vitaly Cheptsov. All rights reserved.<BR>
|
||||
Copyright (c) 2020, ISP RAS. All rights reserved.<BR>
|
||||
|
||||
SPDX-License-Identifier: BSD-3-Clause
|
||||
**/
|
||||
|
||||
#ifndef PE_COFF_LIB2_H_
|
||||
#define PE_COFF_LIB2_H_
|
||||
|
||||
#include <IndustryStandard/PeImage2.h>
|
||||
|
||||
#include <Guid/WinCertificate.h>
|
||||
|
||||
typedef enum {
|
||||
UefiImageOriginFv = 0,
|
||||
UefiImageOriginOptionROM = 1,
|
||||
UefiImageOriginUserImage = 2,
|
||||
UefiImageOriginMax
|
||||
} UEFI_IMAGE_ORIGIN;
|
||||
///
|
||||
/// If set, less than 4KB aligned image from firmware volume prevents boot.
|
||||
///
|
||||
#define PCD_IMAGE_PROTECTION_POLICY_FV_STOP_BOOT BIT31
|
||||
|
||||
// FIXME: Where to put this?
|
||||
//
|
||||
// PcdImageLoaderAlignmentPolicy bits.
|
||||
//
|
||||
|
||||
///
|
||||
/// If set, unaligned Image sections are permitted.
|
||||
///
|
||||
#define PCD_ALIGNMENT_POLICY_CONTIGUOUS_SECTIONS BIT0
|
||||
///
|
||||
/// If set, unaligned Image Relocation Block sizes are permitted.
|
||||
///
|
||||
#define PCD_ALIGNMENT_POLICY_RELOCATION_BLOCK_SIZES BIT1
|
||||
///
|
||||
/// If set, unaligned Image certificate sizes are permitted.
|
||||
///
|
||||
#define PCD_ALIGNMENT_POLICY_CERTIFICATE_SIZES BIT2
|
||||
|
||||
// FIXME: Rework docs to consider Inplace dependencies
|
||||
|
||||
/**
|
||||
Returns whether the Image targets the UEFI Subsystem.
|
||||
|
||||
@param[in] Subsystem The Subsystem value from the Image Headers.
|
||||
**/
|
||||
#define IMAGE_IS_EFI_SUBYSYSTEM(Subsystem) \
|
||||
((Subsystem) >= EFI_IMAGE_SUBSYSTEM_EFI_APPLICATION && \
|
||||
(Subsystem) <= EFI_IMAGE_SUBSYSTEM_SAL_RUNTIME_DRIVER)
|
||||
|
||||
///
|
||||
/// Image type enumeration for Image format identification from the context.
|
||||
///
|
||||
typedef enum {
|
||||
PeCoffLoaderTypePe32,
|
||||
PeCoffLoaderTypePe32Plus,
|
||||
PeCoffLoaderTypeMax
|
||||
} PE_COFF_LOADER_IMAGE_TYPE;
|
||||
|
||||
///
|
||||
/// Image context structure used for abstraction and bookkeeping.
|
||||
/// This structure is publicly exposed for memory allocation reasons and must
|
||||
/// not be accessed directly outside of the library implementation.
|
||||
///
|
||||
typedef struct {
|
||||
///
|
||||
/// The preferred load address of the Image.
|
||||
///
|
||||
UINT64 ImageBase;
|
||||
///
|
||||
/// A pointer to the Image raw file buffer.
|
||||
///
|
||||
CONST VOID *FileBuffer;
|
||||
///
|
||||
/// The size, in Bytes, of FileBuffer.
|
||||
///
|
||||
UINT32 FileSize;
|
||||
///
|
||||
/// A pointer to the loaded Image destination.
|
||||
///
|
||||
VOID *ImageBuffer;
|
||||
///
|
||||
/// The offset of the Section Headers from the beginning of the raw file.
|
||||
///
|
||||
UINT32 SectionsOffset;
|
||||
///
|
||||
/// The number of Sections in the Image.
|
||||
///
|
||||
UINT16 NumberOfSections;
|
||||
///
|
||||
/// The size, in Bytes, required to load the Image.
|
||||
///
|
||||
UINT32 SizeOfImage;
|
||||
///
|
||||
/// The alignment, in Bytes, of Image Sections virtual addresses.
|
||||
///
|
||||
UINT32 SectionAlignment;
|
||||
///
|
||||
/// The offset of the Image Header from the beginning of the raw file.
|
||||
///
|
||||
UINT32 ExeHdrOffset;
|
||||
///
|
||||
/// The combined size, in Bytes, of all Image Headers.
|
||||
///
|
||||
UINT32 SizeOfHeaders;
|
||||
///
|
||||
/// The RVA of the Image entry point.
|
||||
///
|
||||
UINT32 AddressOfEntryPoint;
|
||||
///
|
||||
/// Indicates whether relocation information has been stripped from the Image.
|
||||
///
|
||||
BOOLEAN RelocsStripped;
|
||||
///
|
||||
/// The file format of the Image raw file, refer to PE_COFF_LOADER_IMAGE_TYPE.
|
||||
///
|
||||
UINT8 ImageType;
|
||||
///
|
||||
/// The Subsystem value from the Image Header.
|
||||
///
|
||||
UINT16 Subsystem;
|
||||
///
|
||||
/// The Machine value from the Image Header.
|
||||
///
|
||||
UINT16 Machine;
|
||||
///
|
||||
/// The RVA of the Relocation Directory.
|
||||
///
|
||||
UINT32 RelocDirRva;
|
||||
///
|
||||
/// The size, in Bytes, of the Relocation Directory.
|
||||
///
|
||||
UINT32 RelocDirSize;
|
||||
///
|
||||
/// The RVA of the Security Directory.
|
||||
///
|
||||
UINT32 SecDirOffset;
|
||||
///
|
||||
/// The size, in Bytes, of the Security Directory.
|
||||
///
|
||||
UINT32 SecDirSize;
|
||||
} PE_COFF_LOADER_IMAGE_CONTEXT;
|
||||
|
||||
///
|
||||
/// Image runtime context used to relocate the Image during runtime.
|
||||
///
|
||||
typedef struct PE_COFF_LOADER_RUNTIME_CONTEXT_ PE_COFF_LOADER_RUNTIME_CONTEXT;
|
||||
|
||||
/**
|
||||
Adds the digest of Data to HashContext. This function can be called multiple
|
||||
times to compute the digest of discontinuous data.
|
||||
|
||||
@param[in,out] HashContext The context of the current hash.
|
||||
@param[in] Data The data to be hashed.
|
||||
@param[in] DataSize The size, in Bytes, of Data.
|
||||
|
||||
@returns Whether hashing has been successful.
|
||||
**/
|
||||
typedef
|
||||
BOOLEAN
|
||||
(EFIAPI *PE_COFF_LOADER_HASH_UPDATE)(
|
||||
IN OUT VOID *HashContext,
|
||||
IN CONST VOID *Data,
|
||||
IN UINTN DataSize
|
||||
);
|
||||
|
||||
/**
|
||||
Verify the TE, PE32, or PE32+ Image and initialise Context.
|
||||
|
||||
Used offsets and ranges must be aligned and in the bounds of the raw file.
|
||||
Image Section Headers and basic Relocation information must be well-formed.
|
||||
|
||||
FileBuffer must remain valid for the entire lifetime of Context.
|
||||
|
||||
@param[out] Context The context describing the Image.
|
||||
@param[in] FileBuffer The file data to parse as PE Image.
|
||||
@param[in] FileSize The size, in Bytes, of FileBuffer.
|
||||
|
||||
@retval RETURN_SUCCESS The Image context has been initialised successfully.
|
||||
@retval other The file data is malformed.
|
||||
**/
|
||||
RETURN_STATUS
|
||||
PeCoffInitializeContext (
|
||||
OUT PE_COFF_LOADER_IMAGE_CONTEXT *Context,
|
||||
IN CONST VOID *FileBuffer,
|
||||
IN UINT32 FileSize,
|
||||
IN UINT8 ImageOrigin
|
||||
);
|
||||
|
||||
/**
|
||||
Hashes the Image using the Authenticode (PE/COFF Specification 8.1 Appendix A)
|
||||
algorithm.
|
||||
|
||||
@param[in,out] Context The context describing the Image. Must have been
|
||||
initialised by PeCoffInitializeContext().
|
||||
@param[in,out] HashContext The context of the current hash. Must have been
|
||||
initialised for usage with the HashUpdate
|
||||
function.
|
||||
@param[in] HashUpdate The data hashing function.
|
||||
|
||||
@returns Whether hashing has been successful.
|
||||
**/
|
||||
BOOLEAN
|
||||
PeCoffHashImageAuthenticode (
|
||||
IN OUT PE_COFF_LOADER_IMAGE_CONTEXT *Context,
|
||||
IN OUT VOID *HashContext,
|
||||
IN PE_COFF_LOADER_HASH_UPDATE HashUpdate
|
||||
);
|
||||
|
||||
/**
|
||||
Load the Image into the destination memory space.
|
||||
|
||||
@param[in,out] Context The context describing the Image. Must have
|
||||
been initialised by PeCoffInitializeContext().
|
||||
@param[out] Destination The Image destination memory. Must be
|
||||
allocated from page memory.
|
||||
@param[in] DestinationSize The size, in Bytes, of Destination. Must be
|
||||
sufficent to load the Image with regards to
|
||||
its Image section alignment.
|
||||
|
||||
@retval RETURN_SUCCESS The Image was loaded successfully.
|
||||
@retval other The Image could not be loaded successfully.
|
||||
**/
|
||||
RETURN_STATUS
|
||||
PeCoffLoadImage (
|
||||
IN OUT PE_COFF_LOADER_IMAGE_CONTEXT *Context,
|
||||
OUT VOID *Destination,
|
||||
IN UINT32 DestinationSize
|
||||
);
|
||||
|
||||
// FIXME: Docs
|
||||
BOOLEAN
|
||||
PeCoffImageIsInplace (
|
||||
IN OUT PE_COFF_LOADER_IMAGE_CONTEXT *Context
|
||||
);
|
||||
|
||||
/**
|
||||
Equivalent to the PeCoffLoadImage() function for inplace-loading. Ensures that
|
||||
all important raw file offsets match the respective RVAs.
|
||||
|
||||
@param[in,out] Context The context describing the Image. Must have been
|
||||
initialised by PeCoffInitializeContext().
|
||||
|
||||
@retval RETURN_SUCCESS The Image has been inplace-loaded successfully.
|
||||
@retval other The Image is not suitable for inplace-loading.
|
||||
**/
|
||||
RETURN_STATUS
|
||||
PeCoffLoadImageInplace (
|
||||
IN OUT PE_COFF_LOADER_IMAGE_CONTEXT *Context
|
||||
);
|
||||
|
||||
// FIXME: Docs
|
||||
RETURN_STATUS
|
||||
PeCoffRelocateImageInplace (
|
||||
IN OUT PE_COFF_LOADER_IMAGE_CONTEXT *Context
|
||||
);
|
||||
|
||||
/**
|
||||
Retrieves the size required to bookkeep Image runtime relocation information.
|
||||
|
||||
May only be called when PeCoffGetRelocsStripped() returns FALSE.
|
||||
|
||||
@param[in,out] Context The context describing the Image. Must have been
|
||||
loaded by PeCoffLoadImage().
|
||||
@param[out] Size On output, the size, in Bytes, required for the
|
||||
bookkeeping buffer.
|
||||
|
||||
@retval RETURN_SUCCESS The Image runtime context size for the Image was
|
||||
retrieved successfully.
|
||||
@retval other The Image runtime context size for the Image could not
|
||||
be retrieved successfully.
|
||||
**/
|
||||
RETURN_STATUS
|
||||
PeCoffLoaderGetRuntimeContextSize (
|
||||
IN OUT PE_COFF_LOADER_IMAGE_CONTEXT *Context,
|
||||
OUT UINT32 *Size
|
||||
);
|
||||
|
||||
/**
|
||||
Relocate the Image for boot-time usage.
|
||||
|
||||
May only be called when PeCoffGetRelocsStripped() returns FALSE, or with
|
||||
BaseAddress == PeCoffGetImageBase().
|
||||
|
||||
@param[in,out] Context The context describing the Image. Must have
|
||||
been loaded by PeCoffLoadImage().
|
||||
@param[in] BaseAddress The address to relocate the Image to.
|
||||
@param[out] RuntimeContext If not NULL, on output, a bookkeeping data
|
||||
required for Image runtime relocation.
|
||||
@param[in] RuntimeContextSize The size, in Bytes, of RuntimeContext. Must
|
||||
be at least as big as the size returned by
|
||||
PeCoffLoaderGetRuntimeContextSize().
|
||||
|
||||
@retval RETURN_SUCCESS The Image has been relocated successfully.
|
||||
@retval other The Image Relocation Directory is malformed.
|
||||
**/
|
||||
RETURN_STATUS
|
||||
PeCoffRelocateImage (
|
||||
IN OUT PE_COFF_LOADER_IMAGE_CONTEXT *Context,
|
||||
IN UINT64 BaseAddress,
|
||||
OUT PE_COFF_LOADER_RUNTIME_CONTEXT *RuntimeContext OPTIONAL,
|
||||
IN UINT32 RuntimeContextSize
|
||||
);
|
||||
|
||||
/**
|
||||
Relocate Image for Runtime usage.
|
||||
|
||||
May only be called when PeCoffGetRelocsStripped() returns FALSE, or with
|
||||
BaseAddress == PeCoffGetImageBase().
|
||||
|
||||
@param[in,out] Image The Image destination memory. Must have been
|
||||
relocated by PeCoffRelocateImage().
|
||||
@param[in] ImageSize The size, in Bytes, of Image.
|
||||
@param[in] BaseAddress The address to relocate the Image to.
|
||||
@param[in] RuntimeContext The Relocation context obtained by
|
||||
PeCoffRelocateImage().
|
||||
|
||||
@retval RETURN_SUCCESS The Image has been relocated successfully.
|
||||
@retval other The Image could not be relocated successfully.
|
||||
**/
|
||||
RETURN_STATUS
|
||||
PeCoffRuntimeRelocateImage (
|
||||
IN OUT VOID *Image,
|
||||
IN UINT32 ImageSize,
|
||||
IN UINT64 BaseAddress,
|
||||
IN CONST PE_COFF_LOADER_RUNTIME_CONTEXT *RuntimeContext
|
||||
);
|
||||
|
||||
/**
|
||||
Discards optional Image Sections to disguise sensitive data.
|
||||
|
||||
This may destruct the Image Relocation Directory and as such, no function that
|
||||
performs Image relocation may be called after this function has been invoked.
|
||||
|
||||
@param[in,out] Context The context describing the Image. Must have been
|
||||
loaded by PeCoffLoadImage().
|
||||
**/
|
||||
VOID
|
||||
PeCoffDiscardSections (
|
||||
IN OUT PE_COFF_LOADER_IMAGE_CONTEXT *Context
|
||||
);
|
||||
|
||||
/**
|
||||
Retrieves the Image PDB path.
|
||||
|
||||
@param[in,out] Context The context describing the Image. Must have been
|
||||
initialised by PeCoffInitializeContext().
|
||||
@param[out] PdbPath On output, a pointer to the Image PDB path.
|
||||
@param[out] PdbPathSize On output, the size, in Bytes, of *PdbPath.
|
||||
|
||||
@retval RETURN_SUCCESS The Image PDB path was retrieved successfully.
|
||||
@retval other The Image PDB path could not be retrieved
|
||||
successfully.
|
||||
**/
|
||||
RETURN_STATUS
|
||||
PeCoffGetPdbPath (
|
||||
IN CONST PE_COFF_LOADER_IMAGE_CONTEXT *Context,
|
||||
OUT CONST CHAR8 **PdbPath,
|
||||
OUT UINT32 *PdbPathSize
|
||||
);
|
||||
|
||||
/**
|
||||
Retrieves the first certificate from the Image Certificate Directory.
|
||||
|
||||
@param[in,out] Context The context describing the Image. Must have been
|
||||
initialised by PeCoffInitializeContext().
|
||||
@param[out] Certificate On output, the first certificate of the Image.
|
||||
|
||||
@retval RETURN_SUCCESS The certificate has been retrieved successfully.
|
||||
@retval RETURN_NOT_FOUND There is no such certificate.
|
||||
@retval other The Image Certificate Directory is malformed.
|
||||
**/
|
||||
RETURN_STATUS
|
||||
PeCoffGetFirstCertificate (
|
||||
IN OUT PE_COFF_LOADER_IMAGE_CONTEXT *Context,
|
||||
OUT CONST WIN_CERTIFICATE **Certificate
|
||||
);
|
||||
|
||||
/**
|
||||
Retrieves the next certificate from the Image Certificate Directory.
|
||||
|
||||
@param[in,out] Context The context describing the Image. Must have been
|
||||
initialised by PeCoffInitializeContext().
|
||||
@param[out] Certificate On input, the current certificate of the Image.
|
||||
Must have been retrieved by
|
||||
PeCoffGetFirstCertificate().
|
||||
On output, the next certificate of the Image.
|
||||
|
||||
@retval RETURN_SUCCESS The certificate has been retrieved successfully.
|
||||
@retval RETURN_NOT_FOUND There is no such certificate.
|
||||
@retval other The Image Certificate Directory is malformed.
|
||||
**/
|
||||
RETURN_STATUS
|
||||
PeCoffGetNextCertificate (
|
||||
IN OUT PE_COFF_LOADER_IMAGE_CONTEXT *Context,
|
||||
IN OUT CONST WIN_CERTIFICATE **Certificate
|
||||
);
|
||||
|
||||
/**
|
||||
Retrieves the Image Section Table.
|
||||
|
||||
@param[in,out] Context The context describing the Image. Must have been
|
||||
initialised by PeCoffInitializeContext().
|
||||
@param[out] Sections On output, points to the Image Section Table.
|
||||
|
||||
@returns The number of sections in the Image Section Table.
|
||||
**/
|
||||
UINT16
|
||||
PeCoffGetSectionTable (
|
||||
IN OUT PE_COFF_LOADER_IMAGE_CONTEXT *Context,
|
||||
OUT CONST EFI_IMAGE_SECTION_HEADER **Sections
|
||||
);
|
||||
|
||||
/**
|
||||
Retrieves the Image HII data RVA.
|
||||
|
||||
@param[in,out] Context The context describing the Image. Must have been
|
||||
initialised by PeCoffInitializeContext().
|
||||
@param[out] HiiRva On output, the RVA of the HII resource data.
|
||||
@param[out] HiiSize On output, the size, in Bytes, of HiiRva.
|
||||
|
||||
@retval RETURN_SUCCESS The Image HII data has been retrieved successfully.
|
||||
@retval RETURN_NOT_FOUND The Image HII data could not be found.
|
||||
@retval other The Image Resource Directory is malformed.
|
||||
**/
|
||||
RETURN_STATUS
|
||||
PeCoffGetHiiDataRva (
|
||||
IN OUT PE_COFF_LOADER_IMAGE_CONTEXT *Context,
|
||||
OUT UINT32 *HiiRva,
|
||||
OUT UINT32 *HiiSize
|
||||
);
|
||||
|
||||
/**
|
||||
Retrieve the Image entry point RVA.
|
||||
|
||||
@param[in,out] Context The context describing the Image. Must have been
|
||||
initialised by PeCoffInitializeContext().
|
||||
|
||||
@returns The Image entry point RVA.
|
||||
**/
|
||||
UINT32
|
||||
PeCoffGetAddressOfEntryPoint (
|
||||
IN CONST PE_COFF_LOADER_IMAGE_CONTEXT *Context
|
||||
);
|
||||
|
||||
/**
|
||||
Retrieves the Image machine type.
|
||||
|
||||
@param[in,out] Context The context describing the Image. Must have been
|
||||
initialised by PeCoffInitializeContext().
|
||||
|
||||
@returns The Image machine type.
|
||||
**/
|
||||
UINT16
|
||||
PeCoffGetMachine (
|
||||
IN OUT PE_COFF_LOADER_IMAGE_CONTEXT *Context
|
||||
);
|
||||
|
||||
/**
|
||||
Retrieves the Image subsystem type.
|
||||
|
||||
@param[in,out] Context The context describing the Image. Must have been
|
||||
initialised by PeCoffInitializeContext().
|
||||
|
||||
@returns The Image subsystem type.
|
||||
**/
|
||||
UINT16
|
||||
PeCoffGetSubsystem (
|
||||
IN OUT PE_COFF_LOADER_IMAGE_CONTEXT *Context
|
||||
);
|
||||
|
||||
/**
|
||||
Retrieves the Image section alignment.
|
||||
|
||||
@param[in,out] Context The context describing the Image. Must have been
|
||||
initialised by PeCoffInitializeContext().
|
||||
|
||||
@returns The Image section alignment.
|
||||
**/
|
||||
UINT32
|
||||
PeCoffGetSectionAlignment (
|
||||
IN OUT PE_COFF_LOADER_IMAGE_CONTEXT *Context
|
||||
);
|
||||
|
||||
/**
|
||||
Retrieves the size, in Bytes, of the Image memory space.
|
||||
|
||||
@param[in,out] Context The context describing the Image. Must have been
|
||||
initialised by PeCoffInitializeContext().
|
||||
|
||||
@returns The size of the Image memory space.
|
||||
**/
|
||||
UINT32
|
||||
PeCoffGetSizeOfImage (
|
||||
IN OUT PE_COFF_LOADER_IMAGE_CONTEXT *Context
|
||||
);
|
||||
|
||||
/**
|
||||
Retrieves the Image preferred load address.
|
||||
|
||||
@param[in,out] Context The context describing the Image. Must have been
|
||||
initialised by PeCoffInitializeContext().
|
||||
|
||||
@returns The Image preferred load address.
|
||||
**/
|
||||
UINT64
|
||||
PeCoffGetImageBase (
|
||||
IN OUT PE_COFF_LOADER_IMAGE_CONTEXT *Context
|
||||
);
|
||||
|
||||
/**
|
||||
Retrieves the size, in Bytes, of the Image Headers.
|
||||
|
||||
@param[in,out] Context The context describing the Image. Must have been
|
||||
initialised by PeCoffInitializeContext().
|
||||
|
||||
@returns The size of the Image Headers.
|
||||
**/
|
||||
UINT32
|
||||
PeCoffGetSizeOfHeaders (
|
||||
IN OUT PE_COFF_LOADER_IMAGE_CONTEXT *Context
|
||||
);
|
||||
|
||||
/**
|
||||
Returns whether the Image relocations have been stripped.
|
||||
|
||||
@param[in,out] Context The context describing the Image. Must have been
|
||||
initialised by PeCoffInitializeContext().
|
||||
|
||||
@returns Whether the Image relocations have been stripped.
|
||||
**/
|
||||
BOOLEAN
|
||||
PeCoffGetRelocsStripped (
|
||||
IN OUT PE_COFF_LOADER_IMAGE_CONTEXT *Context
|
||||
);
|
||||
|
||||
/**
|
||||
Retrieves the Image load address PeCoffLoadImage() has loaded the Image to.
|
||||
|
||||
May be called only after PeCoffLoadImage() has succeeded.
|
||||
|
||||
@param[in,out] Context The context describing the Image. Must have been
|
||||
initialised by PeCoffInitializeContext().
|
||||
|
||||
@returns The Image load address.
|
||||
**/
|
||||
UINTN
|
||||
PeCoffLoaderGetImageAddress (
|
||||
IN CONST PE_COFF_LOADER_IMAGE_CONTEXT *Context
|
||||
);
|
||||
|
||||
/**
|
||||
Retrieve the immediate data encoded in an ARM MOVW/MOVT instruciton pair.
|
||||
|
||||
@param[in] Instructions Pointer to an ARM MOVW/MOVT insturction pair.
|
||||
|
||||
@returns The Immediate address encoded in the instructions.
|
||||
**/
|
||||
UINT32
|
||||
PeCoffThumbMovwMovtImmediateAddress (
|
||||
IN CONST VOID *Instructions
|
||||
);
|
||||
|
||||
/**
|
||||
Relocate an ARM MOVW/MOVT immediate instruction instruction pair.
|
||||
|
||||
@param[in,out] Instructions Pointer to ARM MOVW/MOVT instruction pair.
|
||||
@param[in] Adjust The delta to add to the addresses.
|
||||
**/
|
||||
VOID
|
||||
PeCoffThumbMovwMovtImmediateFixup (
|
||||
IN OUT VOID *Instructions,
|
||||
IN UINT64 Adjust
|
||||
);
|
||||
|
||||
#endif // PE_COFF_LIB2_H_
|
|
@ -0,0 +1,122 @@
|
|||
/** @file
|
||||
Provides primitives to allocate and free memory buffers of various memory types and alignments.
|
||||
|
||||
The Phase Memory Allocation Library abstracts primitive memory allocation operations. This library
|
||||
allows code to be written in a phase-independent manner because the allocation of memory in PEI, DXE,
|
||||
and SMM (for example) is done via a different mechanism. Using a common library interface makes it
|
||||
much easier to port algorithms from phase to phase.
|
||||
|
||||
Copyright (c) 2006 - 2018, Intel Corporation. All rights reserved.<BR>
|
||||
SPDX-License-Identifier: BSD-2-Clause-Patent
|
||||
|
||||
**/
|
||||
|
||||
#ifndef __PHASE_MEMORY_ALLOCATION_LIB_H__
|
||||
#define __PHASE_MEMORY_ALLOCATION_LIB_H__
|
||||
|
||||
/**
|
||||
Allocates one or more 4KB pages of a certain memory type.
|
||||
|
||||
Allocates the number of 4KB pages of a certain memory type and returns a pointer
|
||||
to the allocated buffer. The buffer returned is aligned on a 4KB boundary.
|
||||
|
||||
@param Type The type of allocation to perform.
|
||||
@param MemoryType The type of memory to allocate.
|
||||
@param Pages The number of 4 KB pages to allocate.
|
||||
@param Memory The pointer to a physical address. On input, the
|
||||
way in which the address is used depends on the
|
||||
value of Type.
|
||||
|
||||
@retval EFI_SUCCESS The requested pages were allocated.
|
||||
@retval EFI_OUT_OF_RESOURCES The pages could not be allocated.
|
||||
@retval EFI_NOT_FOUND The requested pages could not be found.
|
||||
|
||||
**/
|
||||
EFI_STATUS
|
||||
EFIAPI
|
||||
PhaseAllocatePages (
|
||||
IN EFI_ALLOCATE_TYPE Type,
|
||||
IN EFI_MEMORY_TYPE MemoryType,
|
||||
IN UINTN Pages,
|
||||
IN OUT EFI_PHYSICAL_ADDRESS *Memory
|
||||
);
|
||||
|
||||
/**
|
||||
Frees one or more 4KB pages that were previously allocated with one of the page allocation
|
||||
functions in the Memory Allocation Library.
|
||||
|
||||
Frees the number of 4KB pages specified by Pages from the buffer specified by Buffer.
|
||||
Buffer must have been allocated on a previous call to the page allocation services
|
||||
of the Memory Allocation Library. If it is not possible to free allocated pages,
|
||||
then this function will perform no actions.
|
||||
|
||||
If Buffer was not allocated with a page allocation function in the Memory Allocation
|
||||
Library, then ASSERT().
|
||||
If Pages is zero, then ASSERT().
|
||||
|
||||
@param Memory The base physical address of the pages to be freed.
|
||||
@param Pages The number of 4 KB pages to free.
|
||||
|
||||
@retval EFI_SUCCESS The requested pages were freed.
|
||||
@retval EFI_NOT_FOUND The requested memory pages were not allocated with
|
||||
PhaseAllocatePages().
|
||||
|
||||
**/
|
||||
EFI_STATUS
|
||||
EFIAPI
|
||||
PhaseFreePages (
|
||||
IN EFI_PHYSICAL_ADDRESS Memory,
|
||||
IN UINTN Pages
|
||||
);
|
||||
|
||||
/**
|
||||
Allocates a buffer of a certain pool type.
|
||||
|
||||
Allocates the number bytes specified by AllocationSize of a certain pool type and returns a
|
||||
pointer to the allocated buffer. If AllocationSize is 0, then a valid buffer of 0 size is
|
||||
returned. If there is not enough memory remaining to satisfy the request, then NULL is returned.
|
||||
|
||||
@param MemoryType The type of memory to allocate.
|
||||
@param AllocationSize The number of bytes to allocate.
|
||||
|
||||
@return A pointer to the allocated buffer or NULL if allocation fails.
|
||||
|
||||
**/
|
||||
VOID *
|
||||
EFIAPI
|
||||
PhaseAllocatePool (
|
||||
IN EFI_MEMORY_TYPE MemoryType,
|
||||
IN UINTN AllocationSize
|
||||
);
|
||||
|
||||
/**
|
||||
Frees a buffer that was previously allocated with one of the pool allocation functions in the
|
||||
Memory Allocation Library.
|
||||
|
||||
Frees the buffer specified by Buffer. Buffer must have been allocated on a previous call to the
|
||||
pool allocation services of the Memory Allocation Library. If it is not possible to free pool
|
||||
resources, then this function will perform no actions.
|
||||
|
||||
If Buffer was not allocated with a pool allocation function in the Memory Allocation Library,
|
||||
then ASSERT().
|
||||
|
||||
@param Buffer The pointer to the buffer to free.
|
||||
|
||||
**/
|
||||
VOID
|
||||
EFIAPI
|
||||
PhaseFreePool (
|
||||
IN VOID *Buffer
|
||||
);
|
||||
|
||||
///
|
||||
/// The memory type to allocate for calls to AllocatePages().
|
||||
///
|
||||
extern CONST EFI_MEMORY_TYPE gPhaseDefaultDataType;
|
||||
|
||||
///
|
||||
/// The memory type to allocate for calls to AllocateCodePages().
|
||||
///
|
||||
extern CONST EFI_MEMORY_TYPE gPhaseDefaultCodeType;
|
||||
|
||||
#endif
|
|
@ -0,0 +1,181 @@
|
|||
/** @file
|
||||
UEFI Image Loader library implementation for UE Images.
|
||||
|
||||
Copyright (c) 2021 - 2023, Marvin Häuser. All rights reserved.<BR>
|
||||
|
||||
SPDX-License-Identifier: BSD-2-Clause-Patent
|
||||
**/
|
||||
|
||||
#ifndef UE_LIB_H_
|
||||
#define UE_LIB_H_
|
||||
|
||||
#include <IndustryStandard/UeImage.h>
|
||||
|
||||
typedef struct {
|
||||
CONST UINT8 *FileBuffer;
|
||||
UINT32 UnsignedFileSize;
|
||||
UINT8 Subsystem;
|
||||
UINT8 Machine;
|
||||
BOOLEAN FixedAddress;
|
||||
BOOLEAN XIP;
|
||||
UINT8 LastSegmentIndex;
|
||||
UINT32 SegmentsFileOffset; // Unused for XIP
|
||||
UINT32 SegmentAlignment;
|
||||
CONST VOID *Segments;
|
||||
UINT8 SegmentImageInfoIterSize;
|
||||
BOOLEAN RelocsStripped;
|
||||
UINT8 NumLoadTables;
|
||||
UINT32 LoadTablesFileOffset;
|
||||
UINT32 RelocTableSize;
|
||||
CONST UE_LOAD_TABLE *LoadTables;
|
||||
VOID *ImageBuffer;
|
||||
UINT32 ImageSize;
|
||||
UINT32 EntryPointAddress;
|
||||
UINT64 BaseAddress; // Unused for XIP
|
||||
} UE_LOADER_IMAGE_CONTEXT;
|
||||
|
||||
typedef struct UE_LOADER_RUNTIME_CONTEXT_ UE_LOADER_RUNTIME_CONTEXT;
|
||||
|
||||
/**
|
||||
Adds the digest of Data to HashContext. This function can be called multiple
|
||||
times to compute the digest of discontinuous data.
|
||||
|
||||
@param[in,out] HashContext The context of the current hash.
|
||||
@param[in] Data The data to be hashed.
|
||||
@param[in] DataSize The size, in Bytes, of Data.
|
||||
|
||||
@returns Whether hashing has been successful.
|
||||
**/
|
||||
typedef
|
||||
BOOLEAN
|
||||
(EFIAPI *UE_LOADER_HASH_UPDATE)(
|
||||
IN OUT VOID *HashContext,
|
||||
IN CONST VOID *Data,
|
||||
IN UINTN DataSize
|
||||
);
|
||||
|
||||
RETURN_STATUS
|
||||
UeInitializeContextPreHash (
|
||||
OUT UE_LOADER_IMAGE_CONTEXT *Context,
|
||||
IN CONST VOID *FileBuffer,
|
||||
IN UINT32 FileSize
|
||||
);
|
||||
|
||||
RETURN_STATUS
|
||||
UeInitializeContextPostHash (
|
||||
IN OUT UE_LOADER_IMAGE_CONTEXT *Context
|
||||
);
|
||||
|
||||
BOOLEAN
|
||||
UeHashImageDefault (
|
||||
IN OUT UE_LOADER_IMAGE_CONTEXT *Context,
|
||||
IN OUT VOID *HashContext,
|
||||
IN UE_LOADER_HASH_UPDATE HashUpdate
|
||||
);
|
||||
|
||||
RETURN_STATUS
|
||||
UeLoadImage (
|
||||
IN OUT UE_LOADER_IMAGE_CONTEXT *Context,
|
||||
OUT VOID *Destination,
|
||||
IN UINT32 DestinationSize
|
||||
);
|
||||
|
||||
RETURN_STATUS
|
||||
UeLoaderGetRuntimeContextSize (
|
||||
IN OUT UE_LOADER_IMAGE_CONTEXT *Context,
|
||||
OUT UINT32 *Size
|
||||
);
|
||||
|
||||
RETURN_STATUS
|
||||
UeRelocateImage (
|
||||
IN OUT UE_LOADER_IMAGE_CONTEXT *Context,
|
||||
IN UINT64 BaseAddress,
|
||||
OUT UE_LOADER_RUNTIME_CONTEXT *RuntimeContext OPTIONAL,
|
||||
IN UINT32 RuntimeContextSize
|
||||
);
|
||||
|
||||
RETURN_STATUS
|
||||
UeRelocateImageForRuntime (
|
||||
IN OUT VOID *Image,
|
||||
IN UINT32 ImageSize,
|
||||
IN CONST UE_LOADER_RUNTIME_CONTEXT *RuntimeContext,
|
||||
IN UINT64 BaseAddress
|
||||
);
|
||||
|
||||
RETURN_STATUS
|
||||
UeGetSymbolsPath (
|
||||
IN CONST UE_LOADER_IMAGE_CONTEXT *Context,
|
||||
OUT CONST CHAR8 **SymbolsPath,
|
||||
OUT UINT32 *SymbolsPathSize
|
||||
);
|
||||
|
||||
UINTN
|
||||
UeLoaderGetImageDebugAddress (
|
||||
IN CONST UE_LOADER_IMAGE_CONTEXT *Context
|
||||
);
|
||||
|
||||
RETURN_STATUS
|
||||
UeGetSegmentNames (
|
||||
IN CONST UE_LOADER_IMAGE_CONTEXT *Context,
|
||||
OUT CONST UE_SEGMENT_NAME **SegmentNames
|
||||
);
|
||||
|
||||
UINT32
|
||||
UeGetEntryPointAddress (
|
||||
IN CONST UE_LOADER_IMAGE_CONTEXT *Context
|
||||
);
|
||||
|
||||
UINT16
|
||||
UeGetMachine (
|
||||
IN OUT UE_LOADER_IMAGE_CONTEXT *Context
|
||||
);
|
||||
|
||||
UINT16
|
||||
UeGetSubsystem (
|
||||
IN OUT UE_LOADER_IMAGE_CONTEXT *Context
|
||||
);
|
||||
|
||||
UINT32
|
||||
UeGetSegmentAlignment (
|
||||
IN OUT UE_LOADER_IMAGE_CONTEXT *Context
|
||||
);
|
||||
|
||||
UINT32
|
||||
UeGetImageSize (
|
||||
IN OUT UE_LOADER_IMAGE_CONTEXT *Context
|
||||
);
|
||||
|
||||
UINT64
|
||||
UeGetBaseAddress (
|
||||
IN OUT UE_LOADER_IMAGE_CONTEXT *Context
|
||||
);
|
||||
|
||||
BOOLEAN
|
||||
UeGetRelocsStripped (
|
||||
IN OUT UE_LOADER_IMAGE_CONTEXT *Context
|
||||
);
|
||||
|
||||
BOOLEAN
|
||||
UeGetFixedAddress(
|
||||
IN OUT UE_LOADER_IMAGE_CONTEXT *Context
|
||||
);
|
||||
|
||||
UINTN
|
||||
UeLoaderGetImageAddress (
|
||||
IN CONST UE_LOADER_IMAGE_CONTEXT *Context
|
||||
);
|
||||
|
||||
UINT16
|
||||
UeGetSegments (
|
||||
IN CONST UE_LOADER_IMAGE_CONTEXT *Context,
|
||||
OUT CONST UE_SEGMENT **Segments
|
||||
);
|
||||
|
||||
UINT16
|
||||
UeGetSegmentImageInfos (
|
||||
IN OUT UE_LOADER_IMAGE_CONTEXT *Context,
|
||||
OUT CONST UINT32 **SegmentImageInfos,
|
||||
OUT UINT8 *SegmentImageInfoIterSize
|
||||
);
|
||||
|
||||
#endif // UE_LIB_H_
|
|
@ -0,0 +1,47 @@
|
|||
/** @file
|
||||
Provides services to perform additional actions when an UEFI image is loaded
|
||||
or unloaded. This is useful for environment where symbols need to be loaded
|
||||
and unloaded to support source level debugging.
|
||||
|
||||
Copyright (c) 2009 - 2018, Intel Corporation. All rights reserved.<BR>
|
||||
SPDX-License-Identifier: BSD-2-Clause-Patent
|
||||
|
||||
**/
|
||||
|
||||
#ifndef __UEFI_IMAGE_EXTRA_ACTION_LIB_H__
|
||||
#define __UEFI_IMAGE_EXTRA_ACTION_LIB_H__
|
||||
|
||||
#include <Library/UefiImageLib.h>
|
||||
|
||||
/**
|
||||
Performs additional actions after a UEFI image has been loaded and relocated.
|
||||
|
||||
If ImageContext is NULL, then ASSERT().
|
||||
|
||||
@param ImageContext Pointer to the image context structure that describes the
|
||||
UEFI image that has already been loaded and relocated.
|
||||
|
||||
**/
|
||||
VOID
|
||||
EFIAPI
|
||||
UefiImageLoaderRelocateImageExtraAction (
|
||||
IN CONST UEFI_IMAGE_LOADER_IMAGE_CONTEXT *ImageContext
|
||||
);
|
||||
|
||||
/**
|
||||
Performs additional actions just before a UEFI image is unloaded. Any resources
|
||||
that were allocated by UefiImageLoaderRelocateImageExtraAction() must be freed.
|
||||
|
||||
If ImageContext is NULL, then ASSERT().
|
||||
|
||||
@param ImageContext Pointer to the image context structure that describes the
|
||||
UEFI image that is being unloaded.
|
||||
|
||||
**/
|
||||
VOID
|
||||
EFIAPI
|
||||
UefiImageLoaderUnloadImageExtraAction (
|
||||
IN OUT UEFI_IMAGE_LOADER_IMAGE_CONTEXT *ImageContext
|
||||
);
|
||||
|
||||
#endif
|
|
@ -0,0 +1,722 @@
|
|||
// FIXME: Docs
|
||||
#ifndef UEFI_IMAGE_LIB_H_
|
||||
#define UEFI_IMAGE_LIB_H_
|
||||
|
||||
#include <Library/UeImageLib.h>
|
||||
#include <Library/PeCoffLib2.h>
|
||||
|
||||
typedef enum {
|
||||
UefiImageFormatPe = 0,
|
||||
UefiImageFormatUe = 1,
|
||||
UefiImageFormatMax
|
||||
} UEFI_IMAGE_FORMAT;
|
||||
|
||||
#define UEFI_IMAGE_SOURCE_NON_FV 0U
|
||||
#define UEFI_IMAGE_SOURCE_FV 1U
|
||||
#define UEFI_IMAGE_SOURCE_ALL 2U
|
||||
#define UEFI_IMAGE_SOURCE_MAX 3U
|
||||
|
||||
// FIXME: Get rid of pointers.
|
||||
typedef struct {
|
||||
UINT32 ImageBuffer;
|
||||
UINT32 AddressOfEntryPoint;
|
||||
UINT8 ImageType;
|
||||
UINT32 FileBuffer;
|
||||
UINT32 ExeHdrOffset;
|
||||
UINT32 SizeOfImage;
|
||||
UINT32 FileSize;
|
||||
UINT16 Subsystem;
|
||||
UINT32 SectionAlignment;
|
||||
UINT32 SectionsOffset;
|
||||
UINT16 NumberOfSections;
|
||||
UINT32 SizeOfHeaders;
|
||||
} PE_HOB_IMAGE_CONTEXT;
|
||||
|
||||
typedef struct {
|
||||
UINT32 ImageBuffer;
|
||||
UINT32 FileBuffer;
|
||||
UINT32 EntryPointAddress;
|
||||
UINT32 LoadTablesFileOffset;
|
||||
UINT8 NumLoadTables;
|
||||
UINT32 LoadTables;
|
||||
UINT32 Segments;
|
||||
UINT8 LastSegmentIndex;
|
||||
UINT32 SegmentAlignment;
|
||||
UINT32 ImageSize;
|
||||
UINT8 Subsystem;
|
||||
UINT8 SegmentImageInfoIterSize;
|
||||
UINT32 SegmentsFileOffset;
|
||||
} UE_HOB_IMAGE_CONTEXT;
|
||||
|
||||
typedef struct {
|
||||
UINT8 FormatIndex;
|
||||
union {
|
||||
UE_HOB_IMAGE_CONTEXT Ue;
|
||||
PE_HOB_IMAGE_CONTEXT Pe;
|
||||
} Ctx;
|
||||
} HOB_IMAGE_CONTEXT;
|
||||
|
||||
typedef UINT8 UEFI_IMAGE_SOURCE;
|
||||
|
||||
typedef struct {
|
||||
UINT8 FormatIndex;
|
||||
union {
|
||||
UE_LOADER_IMAGE_CONTEXT Ue;
|
||||
PE_COFF_LOADER_IMAGE_CONTEXT Pe;
|
||||
} Ctx;
|
||||
} UEFI_IMAGE_LOADER_IMAGE_CONTEXT;
|
||||
|
||||
typedef struct UEFI_IMAGE_LOADER_RUNTIME_CONTEXT_ UEFI_IMAGE_LOADER_RUNTIME_CONTEXT;
|
||||
|
||||
///
|
||||
/// Image record segment that desribes the UEFI memory permission configuration
|
||||
/// for one segment of the Image.
|
||||
///
|
||||
typedef struct {
|
||||
///
|
||||
/// The size, in Bytes, of the Image record segment.
|
||||
///
|
||||
UINT32 Size;
|
||||
///
|
||||
/// The UEFI memory permission attributes corresponding to this Image record
|
||||
/// segment.
|
||||
///
|
||||
UINT32 Attributes;
|
||||
} UEFI_IMAGE_RECORD_SEGMENT;
|
||||
|
||||
///
|
||||
/// The 32-bit signature that identifies a UEFI_IMAGE_RECORD structure.
|
||||
///
|
||||
#define UEFI_IMAGE_RECORD_SIGNATURE SIGNATURE_32 ('U','I','I','R')
|
||||
|
||||
///
|
||||
/// Image record that describes the UEFI memory permission configuration for
|
||||
/// every segment of the Image.
|
||||
///
|
||||
typedef struct {
|
||||
///
|
||||
/// The signature of the Image record structure. Must be set to
|
||||
/// UEFI_IMAGE_RECORD_SIGNATURE.
|
||||
///
|
||||
UINT32 Signature;
|
||||
///
|
||||
/// The number of Image records. Must be at least 1.
|
||||
///
|
||||
UINT32 NumSegments;
|
||||
///
|
||||
/// A link to allow insertion of the Image record into a doubly-linked list.
|
||||
///
|
||||
LIST_ENTRY Link;
|
||||
///
|
||||
/// The start address of the Image memory space.
|
||||
///
|
||||
UINTN StartAddress;
|
||||
///
|
||||
/// The end address of the Image memory space. Must be equal to StartAddress
|
||||
/// plus the sum of Segments[i].Size for 0 <= i < NumSegments.
|
||||
///
|
||||
UINTN EndAddress;
|
||||
///
|
||||
/// The Image record segments with their corresponding memory permission
|
||||
/// attributes. All Image record segments are contiguous and cover the entire
|
||||
/// Image memory space. The address of an Image record segment can be
|
||||
/// determined by adding the sum of all previous sizes to StartAddress.
|
||||
///
|
||||
UEFI_IMAGE_RECORD_SEGMENT Segments[];
|
||||
} UEFI_IMAGE_RECORD;
|
||||
|
||||
/**
|
||||
Adds the digest of Data to HashContext. This function can be called multiple
|
||||
times to compute the digest of discontinuous data.
|
||||
|
||||
@param[in,out] HashContext The context of the current hash.
|
||||
@param[in] Data The data to be hashed.
|
||||
@param[in] DataSize The size, in Bytes, of Data.
|
||||
|
||||
@returns Whether hashing has been successful.
|
||||
**/
|
||||
typedef
|
||||
BOOLEAN
|
||||
(EFIAPI *UEFI_IMAGE_LOADER_HASH_UPDATE)(
|
||||
IN OUT VOID *HashContext,
|
||||
IN CONST VOID *Data,
|
||||
IN UINTN DataSize
|
||||
);
|
||||
|
||||
// FIXME: Docs
|
||||
RETURN_STATUS
|
||||
UefiImageInitializeContextPreHash (
|
||||
OUT UEFI_IMAGE_LOADER_IMAGE_CONTEXT *Context,
|
||||
IN CONST VOID *FileBuffer,
|
||||
IN UINT32 FileSize,
|
||||
IN UEFI_IMAGE_SOURCE Source,
|
||||
IN UINT8 ImageOrigin
|
||||
);
|
||||
|
||||
RETURN_STATUS
|
||||
UefiImageInitializeContextPostHash (
|
||||
IN OUT UEFI_IMAGE_LOADER_IMAGE_CONTEXT *Context
|
||||
);
|
||||
|
||||
/**
|
||||
Verify the UEFI Image and initialise Context.
|
||||
|
||||
Used offsets and ranges must be aligned and in the bounds of the raw file.
|
||||
Image headers and basic Relocation information must be well-formed.
|
||||
|
||||
FileBuffer must remain valid for the entire lifetime of Context.
|
||||
|
||||
@param[out] Context The context describing the Image.
|
||||
@param[in] FileBuffer The file data to parse as UEFI Image.
|
||||
@param[in] FileSize The size, in Bytes, of FileBuffer.
|
||||
@param[in] Source Determines supported loaders (PE/UE).
|
||||
@param[in] ImageOrigin Determines image protection policy.
|
||||
|
||||
@retval RETURN_SUCCESS The Image context has been initialised successfully.
|
||||
@retval other The file data is malformed.
|
||||
**/
|
||||
RETURN_STATUS
|
||||
UefiImageInitializeContext (
|
||||
OUT UEFI_IMAGE_LOADER_IMAGE_CONTEXT *Context,
|
||||
IN CONST VOID *FileBuffer,
|
||||
IN UINT32 FileSize,
|
||||
IN UEFI_IMAGE_SOURCE Source,
|
||||
IN UINT8 ImageOrigin
|
||||
);
|
||||
|
||||
/**
|
||||
Retrieves the UefiImageLib Image format identifier.
|
||||
|
||||
@param[out] Context The context describing the Image.
|
||||
|
||||
@returns The UefiImageLib format identifier.
|
||||
**/
|
||||
UINT8
|
||||
UefiImageGetFormat (
|
||||
IN OUT UEFI_IMAGE_LOADER_IMAGE_CONTEXT *Context
|
||||
);
|
||||
|
||||
/**
|
||||
Hashes the Image using the format's default hashing algorithm.
|
||||
|
||||
@param[in,out] Context The context describing the Image. Must have been
|
||||
initialised by UefiImageInitializeContext().
|
||||
@param[in,out] HashContext The context of the current hash. Must have been
|
||||
initialised for usage with the HashUpdate
|
||||
function.
|
||||
@param[in] HashUpdate The data hashing function.
|
||||
|
||||
@returns Whether hashing has been successful.
|
||||
**/
|
||||
BOOLEAN
|
||||
UefiImageHashImageDefault (
|
||||
IN OUT UEFI_IMAGE_LOADER_IMAGE_CONTEXT *Context,
|
||||
IN OUT VOID *HashContext,
|
||||
IN UEFI_IMAGE_LOADER_HASH_UPDATE HashUpdate
|
||||
);
|
||||
|
||||
/**
|
||||
Load the Image into the destination memory space.
|
||||
|
||||
@param[in,out] Context The context describing the Image. Must have been
|
||||
initialised by UefiImageInitializeContext().
|
||||
@param[out] Destination The Image destination memory. Must be allocated
|
||||
from page memory.
|
||||
@param[in] DestinationSize The size, in Bytes, of Destination. Must be at
|
||||
least as large as the size returned by
|
||||
UefiImageGetImageSize().
|
||||
|
||||
@retval RETURN_SUCCESS The Image was loaded successfully.
|
||||
@retval other The Image could not be loaded successfully.
|
||||
**/
|
||||
RETURN_STATUS
|
||||
UefiImageLoadImage (
|
||||
IN OUT UEFI_IMAGE_LOADER_IMAGE_CONTEXT *Context,
|
||||
OUT VOID *Destination,
|
||||
IN UINT32 DestinationSize
|
||||
);
|
||||
|
||||
// FIXME: Docs
|
||||
BOOLEAN
|
||||
UefiImageImageIsInplace (
|
||||
IN OUT UEFI_IMAGE_LOADER_IMAGE_CONTEXT *Context
|
||||
);
|
||||
|
||||
/**
|
||||
Equivalent to the UefiImageLoadImage() function for inplace-loading. Ensures that
|
||||
all important raw file offsets match the respective RVAs.
|
||||
|
||||
@param[in,out] Context The context describing the Image. Must have been
|
||||
initialised by UefiImageInitializeContext().
|
||||
|
||||
@retval RETURN_SUCCESS The Image has been inplace-loaded successfully.
|
||||
@retval other The Image is not suitable for inplace-loading.
|
||||
**/
|
||||
RETURN_STATUS
|
||||
UefiImageLoadImageInplace (
|
||||
IN OUT UEFI_IMAGE_LOADER_IMAGE_CONTEXT *Context
|
||||
);
|
||||
|
||||
// FIXME: Docs
|
||||
RETURN_STATUS
|
||||
UefiImageRelocateImageInplace (
|
||||
IN OUT UEFI_IMAGE_LOADER_IMAGE_CONTEXT *Context
|
||||
);
|
||||
|
||||
// FIXME:
|
||||
RETURN_STATUS
|
||||
UefiImageRelocateImageInplaceForExecution (
|
||||
IN OUT UEFI_IMAGE_LOADER_IMAGE_CONTEXT *Context
|
||||
);
|
||||
|
||||
/**
|
||||
Retrieves the size required to bookkeep Image runtime relocation information.
|
||||
|
||||
May only be called when UefiImageGetRelocsStripped() returns FALSE.
|
||||
|
||||
@param[in,out] Context The context describing the Image. Must have been
|
||||
loaded by UefiImageLoadImage().
|
||||
@param[out] Size On output, the size, in Bytes, required for the
|
||||
bookkeeping buffer.
|
||||
|
||||
@retval RETURN_SUCCESS The Image runtime context size for the Image was
|
||||
retrieved successfully.
|
||||
@retval other The Image runtime context size for the Image could not
|
||||
be retrieved successfully.
|
||||
**/
|
||||
RETURN_STATUS
|
||||
UefiImageLoaderGetRuntimeContextSize (
|
||||
IN OUT UEFI_IMAGE_LOADER_IMAGE_CONTEXT *Context,
|
||||
OUT UINT32 *Size
|
||||
);
|
||||
|
||||
/**
|
||||
Relocate the Image for boot-time usage.
|
||||
|
||||
May only be called when UefiImageGetRelocsStripped() returns FALSE, or with
|
||||
BaseAddress == UefiImageGetBaseAddress().
|
||||
|
||||
@param[in,out] Context The context describing the Image. Must have
|
||||
been loaded by UefiImageLoadImage().
|
||||
@param[in] BaseAddress The address to relocate the Image to.
|
||||
@param[out] RuntimeContext If not NULL, on output, a bookkeeping data
|
||||
required for Image runtime relocation.
|
||||
@param[in] RuntimeContextSize The size, in Bytes, of RuntimeContext. Must
|
||||
be at least as big as the size returned by
|
||||
UefiImageLoaderGetRuntimeContextSize().
|
||||
|
||||
@retval RETURN_SUCCESS The Image has been relocated successfully.
|
||||
@retval other The Image Relocation Directory is malformed.
|
||||
**/
|
||||
RETURN_STATUS
|
||||
UefiImageRelocateImage (
|
||||
IN OUT UEFI_IMAGE_LOADER_IMAGE_CONTEXT *Context,
|
||||
IN UINT64 BaseAddress,
|
||||
OUT UEFI_IMAGE_LOADER_RUNTIME_CONTEXT *RuntimeContext OPTIONAL,
|
||||
IN UINT32 RuntimeContextSize
|
||||
);
|
||||
|
||||
/**
|
||||
Load the Image into the destination memory space, relocate Image for boot-time
|
||||
usage, and perform environment-specific actions required to execute code from
|
||||
the Image.
|
||||
|
||||
May only be called when UefiImageGetRelocsStripped() returns FALSE, or with
|
||||
BaseAddress == UefiImageGetBaseAddress().
|
||||
|
||||
@param[in,out] Context The context describing the Image. Must have
|
||||
been initialised by
|
||||
UefiImageInitializeContext().
|
||||
@param[out] Destination The Image destination memory. Must be
|
||||
allocated from page memory.
|
||||
@param[in] DestinationSize The size, in Bytes, of Destination. Must be
|
||||
at least as large as the size returned by
|
||||
UefiImageGetImageSize().
|
||||
@param[out] RuntimeContext If not NULL, on output, a buffer
|
||||
bookkeeping data required for Image runtime
|
||||
relocation.
|
||||
@param[in] RuntimeContextSize The size, in Bytes, of RuntimeContext. Must
|
||||
be at least as big as the size returned by
|
||||
UefiImageLoaderGetRuntimeContextSize().
|
||||
|
||||
@retval RETURN_SUCCESS The Image was loaded successfully.
|
||||
@retval other The Image could not be loaded successfully.
|
||||
**/
|
||||
RETURN_STATUS
|
||||
UefiImageLoadImageForExecution (
|
||||
IN OUT UEFI_IMAGE_LOADER_IMAGE_CONTEXT *Context,
|
||||
OUT VOID *Destination,
|
||||
IN UINT32 DestinationSize,
|
||||
OUT UEFI_IMAGE_LOADER_RUNTIME_CONTEXT *RuntimeContext OPTIONAL,
|
||||
IN UINT32 RuntimeContextSize
|
||||
);
|
||||
|
||||
/**
|
||||
Relocate Image for Runtime usage.
|
||||
|
||||
May only be called when UefiImageGetRelocsStripped() returns FALSE, or with
|
||||
BaseAddress == UefiImageGetBaseAddress().
|
||||
|
||||
@param[in,out] Image The Image destination memory. Must have been
|
||||
relocated by UefiImageRelocateImage().
|
||||
@param[in] ImageSize The size, in Bytes, of Image.
|
||||
@param[in] BaseAddress The address to relocate the Image to.
|
||||
@param[in] RuntimeContext The Relocation context obtained by
|
||||
UefiImageRelocateImage().
|
||||
|
||||
@retval RETURN_SUCCESS The Image has been relocated successfully.
|
||||
@retval other The Image could not be relocated successfully.
|
||||
**/
|
||||
RETURN_STATUS
|
||||
UefiImageRuntimeRelocateImage (
|
||||
IN OUT VOID *Image,
|
||||
IN UINT32 ImageSize,
|
||||
IN UINT64 BaseAddress,
|
||||
IN CONST UEFI_IMAGE_LOADER_RUNTIME_CONTEXT *RuntimeContext
|
||||
);
|
||||
|
||||
/**
|
||||
Relocate Image for Runtime usage, and perform environment-specific actions
|
||||
required to execute code from the Image.
|
||||
|
||||
May only be called when UefiImageGetRelocsStripped() returns FALSE, or with
|
||||
BaseAddress == UefiImageGetBaseAddress().
|
||||
|
||||
@param[in,out] Image The Image destination memory. Must have been
|
||||
relocated by UefiImageRelocateImage().
|
||||
@param[in] ImageSize The size, in Bytes, of Image.
|
||||
@param[in] BaseAddress The address to relocate the Image to.
|
||||
@param[in] RuntimeContext The Relocation context obtained by
|
||||
UefiImageRelocateImage().
|
||||
|
||||
@retval RETURN_SUCCESS The Image has been relocated successfully.
|
||||
@retval other The Image could not be relocated successfully.
|
||||
**/
|
||||
RETURN_STATUS
|
||||
UefiImageRuntimeRelocateImageForExecution (
|
||||
IN OUT VOID *Image,
|
||||
IN UINT32 ImageSize,
|
||||
IN UINT64 BaseAddress,
|
||||
IN CONST UEFI_IMAGE_LOADER_RUNTIME_CONTEXT *RuntimeContext
|
||||
);
|
||||
|
||||
/**
|
||||
Discards optional Image segments to disguise sensitive data.
|
||||
|
||||
This may destruct the Image Relocation Directory and as such, no function that
|
||||
performs Image relocation may be called after this function has been invoked.
|
||||
|
||||
@param[in,out] Context The context describing the Image. Must have been
|
||||
loaded by UefiImageLoadImage().
|
||||
**/
|
||||
VOID
|
||||
UefiImageDiscardSegments (
|
||||
IN OUT UEFI_IMAGE_LOADER_IMAGE_CONTEXT *Context
|
||||
);
|
||||
|
||||
/**
|
||||
Retrieves the Image symbols path.
|
||||
|
||||
@param[in,out] Context The context describing the Image. Must have
|
||||
been initialised by
|
||||
UefiImageInitializeContext().
|
||||
@param[out] SymbolsPath On output, a pointer to the Image symbols
|
||||
path.
|
||||
@param[out] SymbolsPathSize On output, the size, in Bytes, of *
|
||||
SymbolsPath.
|
||||
|
||||
@retval RETURN_SUCCESS The Image symbols path was retrieved successfully.
|
||||
@retval other The Image symbols path could not be retrieved
|
||||
successfully.
|
||||
**/
|
||||
RETURN_STATUS
|
||||
UefiImageGetSymbolsPath (
|
||||
IN CONST UEFI_IMAGE_LOADER_IMAGE_CONTEXT *Context,
|
||||
OUT CONST CHAR8 **SymbolsPath,
|
||||
OUT UINT32 *SymbolsPathSize
|
||||
);
|
||||
|
||||
/**
|
||||
Retrieves the Image module name from the Image symbols path.
|
||||
|
||||
@param[in,out] Context The context describing the Image. Must have
|
||||
been initialised by
|
||||
UefiImageInitializeContext().
|
||||
@param[out] ModuleName Buffer the Image module name is written into.
|
||||
If the name exceeds ModuleNameSize, it will be
|
||||
truncated.
|
||||
@param[out] ModuleNameSize The size, in Bytes, of ModuleName.
|
||||
|
||||
@retval RETURN_SUCCESS The Image module name was retrieved successfully.
|
||||
@retval other The Image module name could not be retrieved
|
||||
successfully.
|
||||
**/
|
||||
RETURN_STATUS
|
||||
UefiImageGetModuleNameFromSymbolsPath (
|
||||
IN OUT UEFI_IMAGE_LOADER_IMAGE_CONTEXT *Context,
|
||||
OUT CHAR8 *ModuleName,
|
||||
IN UINT32 ModuleNameSize
|
||||
);
|
||||
|
||||
// FIXME: Abstract certificates somehow?
|
||||
/**
|
||||
Retrieves the first certificate from the Image Certificate Directory.
|
||||
|
||||
@param[in,out] Context The context describing the Image. Must have been
|
||||
initialised by UefiImageInitializeContext().
|
||||
@param[out] Certificate On output, the first certificate of the Image.
|
||||
|
||||
@retval RETURN_SUCCESS The certificate has been retrieved successfully.
|
||||
@retval RETURN_NOT_FOUND There is no such certificate.
|
||||
@retval other The Image Certificate Directory is malformed.
|
||||
**/
|
||||
RETURN_STATUS
|
||||
UefiImageGetFirstCertificate (
|
||||
IN OUT UEFI_IMAGE_LOADER_IMAGE_CONTEXT *Context,
|
||||
OUT CONST WIN_CERTIFICATE **Certificate
|
||||
);
|
||||
|
||||
/**
|
||||
Retrieves the next certificate from the Image Certificate Directory.
|
||||
|
||||
@param[in,out] Context The context describing the Image. Must have been
|
||||
initialised by UefiImageInitializeContext().
|
||||
@param[out] Certificate On input, the current certificate of the Image.
|
||||
Must have been retrieved by
|
||||
UefiImageGetFirstCertificate().
|
||||
On output, the next certificate of the Image.
|
||||
|
||||
@retval RETURN_SUCCESS The certificate has been retrieved successfully.
|
||||
@retval RETURN_NOT_FOUND There is no such certificate.
|
||||
@retval other The Image Certificate Directory is malformed.
|
||||
**/
|
||||
RETURN_STATUS
|
||||
UefiImageGetNextCertificate (
|
||||
IN OUT UEFI_IMAGE_LOADER_IMAGE_CONTEXT *Context,
|
||||
IN OUT CONST WIN_CERTIFICATE **Certificate
|
||||
);
|
||||
|
||||
/**
|
||||
Retrieves the Image HII data RVA.
|
||||
|
||||
@param[in,out] Context The context describing the Image. Must have been
|
||||
initialised by UefiImageInitializeContext().
|
||||
@param[out] HiiRva On output, the RVA of the HII resource data.
|
||||
@param[out] HiiSize On output, the size, in Bytes, of HiiRva.
|
||||
|
||||
@retval RETURN_SUCCESS The Image HII data has been retrieved successfully.
|
||||
@retval RETURN_NOT_FOUND The Image HII data could not be found.
|
||||
@retval other The Image Resource Directory is malformed.
|
||||
**/
|
||||
RETURN_STATUS
|
||||
UefiImageGetHiiDataRva (
|
||||
IN OUT UEFI_IMAGE_LOADER_IMAGE_CONTEXT *Context,
|
||||
OUT UINT32 *HiiRva,
|
||||
OUT UINT32 *HiiSize
|
||||
);
|
||||
|
||||
/**
|
||||
Retrieve the Image entry point RVA.
|
||||
|
||||
@param[in,out] Context The context describing the Image. Must have been
|
||||
initialised by UefiImageInitializeContext().
|
||||
|
||||
@returns The Image entry point RVA.
|
||||
**/
|
||||
UINT32
|
||||
UefiImageGetEntryPointAddress (
|
||||
IN CONST UEFI_IMAGE_LOADER_IMAGE_CONTEXT *Context
|
||||
);
|
||||
|
||||
/**
|
||||
Retrieves the Image machine type.
|
||||
|
||||
@param[in,out] Context The context describing the Image. Must have been
|
||||
initialised by UefiImageInitializeContext().
|
||||
|
||||
@returns The Image machine type.
|
||||
**/
|
||||
UINT16
|
||||
UefiImageGetMachine (
|
||||
IN OUT UEFI_IMAGE_LOADER_IMAGE_CONTEXT *Context
|
||||
);
|
||||
|
||||
/**
|
||||
Retrieves the Image subsystem type.
|
||||
|
||||
@param[in,out] Context The context describing the Image. Must have been
|
||||
initialised by UefiImageInitializeContext().
|
||||
|
||||
@returns The Image subsystem type.
|
||||
**/
|
||||
UINT16
|
||||
UefiImageGetSubsystem (
|
||||
IN OUT UEFI_IMAGE_LOADER_IMAGE_CONTEXT *Context
|
||||
);
|
||||
|
||||
/**
|
||||
Retrieves the Image segment alignment.
|
||||
|
||||
@param[in,out] Context The context describing the Image. Must have been
|
||||
initialised by UefiImageInitializeContext().
|
||||
|
||||
@returns The Image segment alignment.
|
||||
**/
|
||||
UINT32
|
||||
UefiImageGetSegmentAlignment (
|
||||
IN OUT UEFI_IMAGE_LOADER_IMAGE_CONTEXT *Context
|
||||
);
|
||||
|
||||
/**
|
||||
Retrieves the size, in Bytes, of the Image memory space.
|
||||
|
||||
@param[in,out] Context The context describing the Image. Must have been
|
||||
initialised by UefiImageInitializeContext().
|
||||
|
||||
@returns The size of the Image memory space.
|
||||
**/
|
||||
UINT32
|
||||
UefiImageGetImageSize (
|
||||
IN OUT UEFI_IMAGE_LOADER_IMAGE_CONTEXT *Context
|
||||
);
|
||||
|
||||
/**
|
||||
Retrieves the Image preferred load address.
|
||||
|
||||
@param[in,out] Context The context describing the Image. Must have been
|
||||
initialised by UefiImageInitializeContext().
|
||||
|
||||
@returns The Image preferred load address.
|
||||
**/
|
||||
UINT64
|
||||
UefiImageGetBaseAddress (
|
||||
IN OUT UEFI_IMAGE_LOADER_IMAGE_CONTEXT *Context
|
||||
);
|
||||
|
||||
/**
|
||||
Returns whether the Image relocations have been stripped.
|
||||
|
||||
@param[in,out] Context The context describing the Image. Must have been
|
||||
initialised by UefiImageInitializeContext().
|
||||
|
||||
@returns Whether the Image relocations have been stripped.
|
||||
**/
|
||||
BOOLEAN
|
||||
UefiImageGetRelocsStripped (
|
||||
IN OUT UEFI_IMAGE_LOADER_IMAGE_CONTEXT *Context
|
||||
);
|
||||
|
||||
/**
|
||||
Retrieves the Image load address UefiImageLoadImage() has loaded the Image to.
|
||||
|
||||
May be called only after UefiImageLoadImage() has succeeded.
|
||||
|
||||
@param[in,out] Context The context describing the Image. Must have been
|
||||
initialised by UefiImageInitializeContext().
|
||||
|
||||
@returns The Image load address.
|
||||
**/
|
||||
UINTN
|
||||
UefiImageLoaderGetImageAddress (
|
||||
IN CONST UEFI_IMAGE_LOADER_IMAGE_CONTEXT *Context
|
||||
);
|
||||
|
||||
/**
|
||||
Retrieves the Image debug address. Due to post-processing, the debug address
|
||||
may deviate from the load address. Symbolication must use this address.
|
||||
|
||||
May be called only after UefiImageLoadImage() has succeeded.
|
||||
|
||||
@param[in,out] Context The context describing the Image. Must have been
|
||||
initialised by UefiImageInitializeContext().
|
||||
|
||||
@returns The Image debug address.
|
||||
**/
|
||||
UINTN
|
||||
UefiImageLoaderGetDebugAddress (
|
||||
IN CONST UEFI_IMAGE_LOADER_IMAGE_CONTEXT *Context
|
||||
);
|
||||
|
||||
/**
|
||||
Retrieve the Image entry point address.
|
||||
|
||||
May be called only after UefiImageLoadImage() has succeeded.
|
||||
|
||||
@param[in,out] Context The context describing the Image. Must have been
|
||||
initialised by UefiImageInitializeContext().
|
||||
|
||||
@returns The Image entry point addres.
|
||||
**/
|
||||
UINTN
|
||||
UefiImageLoaderGetImageEntryPoint (
|
||||
IN CONST UEFI_IMAGE_LOADER_IMAGE_CONTEXT *Context
|
||||
);
|
||||
|
||||
/**
|
||||
Constructs an Image record from the Image. Any headers, gaps, or trailers are
|
||||
described as read-only data.
|
||||
|
||||
May be called only after UefiImageLoadImage() has succeeded.
|
||||
|
||||
@param[in,out] Context The context describing the Image. Must have been
|
||||
initialised by UefiImageInitializeContext().
|
||||
|
||||
@retval NULL The Image record could not constructed successfully.
|
||||
@retval other The Image record was constructed successfully and is returned.
|
||||
It is allocated using the AllocatePool() API and is
|
||||
caller-owned as soon as this function returns.
|
||||
**/
|
||||
UEFI_IMAGE_RECORD *
|
||||
UefiImageLoaderGetImageRecord (
|
||||
IN OUT UEFI_IMAGE_LOADER_IMAGE_CONTEXT *Context
|
||||
);
|
||||
|
||||
// FIXME: Docs
|
||||
RETURN_STATUS
|
||||
UefiImageDebugLocateImage (
|
||||
OUT UEFI_IMAGE_LOADER_IMAGE_CONTEXT *Context,
|
||||
IN UINTN Address,
|
||||
IN UINT8 ImageOrigin
|
||||
);
|
||||
|
||||
/**
|
||||
Retrieve the Image fixed loading address.
|
||||
|
||||
This function is only guaranteed to function correctly if the Image was built
|
||||
by a tool with this feature enabled.
|
||||
|
||||
@param[in,out] Context The context describing the Image. Must have been
|
||||
initialised by UefiImageInitializeContext().
|
||||
@param[out] Address On output, the fixed loading address of the Image.
|
||||
*Address is guaranteed to by aligned by the Image
|
||||
segment alignment, and thus the size returned by
|
||||
UefiImageGetImageSize is sufficient to hold the
|
||||
Image.
|
||||
|
||||
@retval RETURN_SUCCESS The Image has a fixed loading address.
|
||||
@retval RETURN_NOT_FOUND The Image does not have a fixed loading address.
|
||||
@retval RETURN_UNSUPPORTED The Image fixed loading address is unaligned.
|
||||
**/
|
||||
RETURN_STATUS
|
||||
UefiImageGetFixedAddress (
|
||||
IN OUT UEFI_IMAGE_LOADER_IMAGE_CONTEXT *Context,
|
||||
OUT UINT64 *Address
|
||||
);
|
||||
|
||||
// FIXME: Docs
|
||||
VOID
|
||||
UefiImageDebugPrintSegments (
|
||||
IN OUT UEFI_IMAGE_LOADER_IMAGE_CONTEXT *Context
|
||||
);
|
||||
|
||||
VOID
|
||||
UefiImageDebugPrintImageRecord (
|
||||
IN CONST UEFI_IMAGE_RECORD *ImageRecord
|
||||
);
|
||||
|
||||
UINTN
|
||||
UefiImageLoaderGetDebugAddress (
|
||||
IN CONST UEFI_IMAGE_LOADER_IMAGE_CONTEXT *Context
|
||||
);
|
||||
|
||||
#endif // UEFI_IMAGE_LIB_H_
|
|
@ -7,6 +7,7 @@
|
|||
|
||||
Copyright (c) 2006 - 2018, Intel Corporation. All rights reserved.<BR>
|
||||
Portions copyright (c) 2011 - 2013, ARM Ltd. All rights reserved.<BR>
|
||||
Copyright (c) 2020, Hewlett Packard Enterprise Development LP. All rights reserved.<BR>
|
||||
|
||||
SPDX-License-Identifier: BSD-2-Clause-Patent
|
||||
|
||||
|
@ -15,8 +16,6 @@ SPDX-License-Identifier: BSD-2-Clause-Patent
|
|||
#ifndef __DEBUG_SUPPORT_H__
|
||||
#define __DEBUG_SUPPORT_H__
|
||||
|
||||
#include <IndustryStandard/PeImage.h>
|
||||
|
||||
typedef struct _EFI_DEBUG_SUPPORT_PROTOCOL EFI_DEBUG_SUPPORT_PROTOCOL;
|
||||
|
||||
///
|
||||
|
@ -428,7 +427,6 @@ typedef struct {
|
|||
// virtual registers - nat bits for R1-R31
|
||||
//
|
||||
UINT64 IntNat;
|
||||
|
||||
} EFI_SYSTEM_CONTEXT_IPF;
|
||||
|
||||
///
|
||||
|
@ -467,8 +465,6 @@ typedef struct {
|
|||
UINT64 Ip;
|
||||
} EFI_SYSTEM_CONTEXT_EBC;
|
||||
|
||||
|
||||
|
||||
///
|
||||
/// ARM processor exception types.
|
||||
///
|
||||
|
@ -513,7 +509,6 @@ typedef struct {
|
|||
UINT32 IFAR;
|
||||
} EFI_SYSTEM_CONTEXT_ARM;
|
||||
|
||||
|
||||
///
|
||||
/// AARCH64 processor exception types.
|
||||
///
|
||||
|
@ -603,6 +598,177 @@ typedef struct {
|
|||
UINT64 FAR; // Fault Address Register
|
||||
} EFI_SYSTEM_CONTEXT_AARCH64;
|
||||
|
||||
///
|
||||
/// RISC-V processor exception types.
|
||||
///
|
||||
#define EXCEPT_RISCV_INST_MISALIGNED 0
|
||||
#define EXCEPT_RISCV_INST_ACCESS_FAULT 1
|
||||
#define EXCEPT_RISCV_ILLEGAL_INST 2
|
||||
#define EXCEPT_RISCV_BREAKPOINT 3
|
||||
#define EXCEPT_RISCV_LOAD_ADDRESS_MISALIGNED 4
|
||||
#define EXCEPT_RISCV_LOAD_ACCESS_FAULT 5
|
||||
#define EXCEPT_RISCV_STORE_AMO_ADDRESS_MISALIGNED 6
|
||||
#define EXCEPT_RISCV_STORE_AMO_ACCESS_FAULT 7
|
||||
#define EXCEPT_RISCV_ENV_CALL_FROM_UMODE 8
|
||||
#define EXCEPT_RISCV_ENV_CALL_FROM_SMODE 9
|
||||
#define EXCEPT_RISCV_ENV_CALL_FROM_VS_MODE 10
|
||||
#define EXCEPT_RISCV_ENV_CALL_FROM_MMODE 11
|
||||
#define EXCEPT_RISCV_INST_ACCESS_PAGE_FAULT 12
|
||||
#define EXCEPT_RISCV_LOAD_ACCESS_PAGE_FAULT 13
|
||||
#define EXCEPT_RISCV_14 14
|
||||
#define EXCEPT_RISCV_STORE_ACCESS_PAGE_FAULT 15
|
||||
#define EXCEPT_RISCV_16 16
|
||||
#define EXCEPT_RISCV_17 17
|
||||
#define EXCEPT_RISCV_18 18
|
||||
#define EXCEPT_RISCV_19 19
|
||||
#define EXCEPT_RISCV_INST_GUEST_PAGE_FAULT 20
|
||||
#define EXCEPT_RISCV_LOAD_GUEST_PAGE_FAULT 21
|
||||
#define EXCEPT_RISCV_VIRTUAL_INSTRUCTION 22
|
||||
#define EXCEPT_RISCV_STORE_GUEST_PAGE_FAULT 23
|
||||
#define EXCEPT_RISCV_MAX_EXCEPTIONS (EXCEPT_RISCV_STORE_GUEST_PAGE_FAULT)
|
||||
|
||||
///
|
||||
/// RISC-V processor exception types for interrupts.
|
||||
///
|
||||
#define EXCEPT_RISCV_IS_IRQ(x) ((x & 0x8000000000000000UL) != 0)
|
||||
#define EXCEPT_RISCV_IRQ_INDEX(x) (x & 0x7FFFFFFFFFFFFFFFUL)
|
||||
#define EXCEPT_RISCV_IRQ_0 0x8000000000000000UL
|
||||
#define EXCEPT_RISCV_IRQ_SOFT_FROM_SMODE 0x8000000000000001UL
|
||||
#define EXCEPT_RISCV_IRQ_SOFT_FROM_VSMODE 0x8000000000000002UL
|
||||
#define EXCEPT_RISCV_IRQ_SOFT_FROM_MMODE 0x8000000000000003UL
|
||||
#define EXCEPT_RISCV_IRQ_4 0x8000000000000004UL
|
||||
#define EXCEPT_RISCV_IRQ_TIMER_FROM_SMODE 0x8000000000000005UL
|
||||
#define EXCEPT_RISCV_MAX_IRQS (EXCEPT_RISCV_IRQ_INDEX(EXCEPT_RISCV_IRQ_TIMER_FROM_SMODE))
|
||||
|
||||
typedef struct {
|
||||
UINT64 X0;
|
||||
UINT64 X1;
|
||||
UINT64 X2;
|
||||
UINT64 X3;
|
||||
UINT64 X4;
|
||||
UINT64 X5;
|
||||
UINT64 X6;
|
||||
UINT64 X7;
|
||||
UINT64 X8;
|
||||
UINT64 X9;
|
||||
UINT64 X10;
|
||||
UINT64 X11;
|
||||
UINT64 X12;
|
||||
UINT64 X13;
|
||||
UINT64 X14;
|
||||
UINT64 X15;
|
||||
UINT64 X16;
|
||||
UINT64 X17;
|
||||
UINT64 X18;
|
||||
UINT64 X19;
|
||||
UINT64 X20;
|
||||
UINT64 X21;
|
||||
UINT64 X22;
|
||||
UINT64 X23;
|
||||
UINT64 X24;
|
||||
UINT64 X25;
|
||||
UINT64 X26;
|
||||
UINT64 X27;
|
||||
UINT64 X28;
|
||||
UINT64 X29;
|
||||
UINT64 X30;
|
||||
UINT64 X31;
|
||||
UINT64 SEPC;
|
||||
UINT32 SSTATUS;
|
||||
UINT32 STVAL;
|
||||
} EFI_SYSTEM_CONTEXT_RISCV64;
|
||||
|
||||
//
|
||||
// LoongArch processor exception types.
|
||||
//
|
||||
#define EXCEPT_LOONGARCH_INT 0
|
||||
#define EXCEPT_LOONGARCH_PIL 1
|
||||
#define EXCEPT_LOONGARCH_PIS 2
|
||||
#define EXCEPT_LOONGARCH_PIF 3
|
||||
#define EXCEPT_LOONGARCH_PME 4
|
||||
#define EXCEPT_LOONGARCH_PNR 5
|
||||
#define EXCEPT_LOONGARCH_PNX 6
|
||||
#define EXCEPT_LOONGARCH_PPI 7
|
||||
#define EXCEPT_LOONGARCH_ADE 8
|
||||
#define EXCEPT_LOONGARCH_ALE 9
|
||||
#define EXCEPT_LOONGARCH_BCE 10
|
||||
#define EXCEPT_LOONGARCH_SYS 11
|
||||
#define EXCEPT_LOONGARCH_BRK 12
|
||||
#define EXCEPT_LOONGARCH_INE 13
|
||||
#define EXCEPT_LOONGARCH_IPE 14
|
||||
#define EXCEPT_LOONGARCH_FPD 15
|
||||
#define EXCEPT_LOONGARCH_SXD 16
|
||||
#define EXCEPT_LOONGARCH_ASXD 17
|
||||
#define EXCEPT_LOONGARCH_FPE 18
|
||||
#define EXCEPT_LOONGARCH_TBR 64 // For code only, there is no such type in the ISA spec, the TLB refill is defined for an independent exception.
|
||||
|
||||
//
|
||||
// LoongArch processor Interrupt types.
|
||||
//
|
||||
#define EXCEPT_LOONGARCH_INT_SIP0 0
|
||||
#define EXCEPT_LOONGARCH_INT_SIP1 1
|
||||
#define EXCEPT_LOONGARCH_INT_IP0 2
|
||||
#define EXCEPT_LOONGARCH_INT_IP1 3
|
||||
#define EXCEPT_LOONGARCH_INT_IP2 4
|
||||
#define EXCEPT_LOONGARCH_INT_IP3 5
|
||||
#define EXCEPT_LOONGARCH_INT_IP4 6
|
||||
#define EXCEPT_LOONGARCH_INT_IP5 7
|
||||
#define EXCEPT_LOONGARCH_INT_IP6 8
|
||||
#define EXCEPT_LOONGARCH_INT_IP7 9
|
||||
#define EXCEPT_LOONGARCH_INT_PMC 10
|
||||
#define EXCEPT_LOONGARCH_INT_TIMER 11
|
||||
#define EXCEPT_LOONGARCH_INT_IPI 12
|
||||
|
||||
//
|
||||
// For coding convenience, define the maximum valid
|
||||
// LoongArch interrupt.
|
||||
//
|
||||
#define MAX_LOONGARCH_INTERRUPT 14
|
||||
|
||||
typedef struct {
|
||||
UINT64 R0;
|
||||
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 CRMD; // CuRrent MoDe information
|
||||
UINT64 PRMD; // PRe-exception MoDe information
|
||||
UINT64 EUEN; // Extended component Unit ENable
|
||||
UINT64 MISC; // MISCellaneous controller
|
||||
UINT64 ECFG; // Exception ConFiGuration
|
||||
UINT64 ESTAT; // Exception STATus
|
||||
UINT64 ERA; // Exception Return Address
|
||||
UINT64 BADV; // BAD Virtual address
|
||||
UINT64 BADI; // BAD Instruction
|
||||
} EFI_SYSTEM_CONTEXT_LOONGARCH64;
|
||||
|
||||
///
|
||||
/// Universal EFI_SYSTEM_CONTEXT definition.
|
||||
|
@ -614,6 +780,8 @@ typedef union {
|
|||
EFI_SYSTEM_CONTEXT_IPF *SystemContextIpf;
|
||||
EFI_SYSTEM_CONTEXT_ARM *SystemContextArm;
|
||||
EFI_SYSTEM_CONTEXT_AARCH64 *SystemContextAArch64;
|
||||
EFI_SYSTEM_CONTEXT_RISCV64 *SystemContextRiscV64;
|
||||
EFI_SYSTEM_CONTEXT_LOONGARCH64 *SystemContextLoongArch64;
|
||||
} EFI_SYSTEM_CONTEXT;
|
||||
|
||||
//
|
||||
|
@ -650,15 +818,14 @@ VOID
|
|||
/// 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
|
||||
IsaArm = IMAGE_FILE_MACHINE_ARMTHUMB_MIXED, ///< 0x01c2
|
||||
IsaAArch64 = IMAGE_FILE_MACHINE_ARM64 ///< 0xAA64
|
||||
IsaIa32 = EFI_IMAGE_MACHINE_IA32, ///< 0x014C
|
||||
IsaX64 = EFI_IMAGE_MACHINE_X64, ///< 0x8664
|
||||
IsaIpf = EFI_IMAGE_MACHINE_IA64, ///< 0x0200
|
||||
IsaEbc = EFI_IMAGE_MACHINE_EBC, ///< 0x0EBC
|
||||
IsaArm = EFI_IMAGE_MACHINE_ARMTHUMB_MIXED, ///< 0x01c2
|
||||
IsaAArch64 = EFI_IMAGE_MACHINE_AARCH64 ///< 0xAA64
|
||||
} EFI_INSTRUCTION_SET_ARCHITECTURE;
|
||||
|
||||
|
||||
//
|
||||
// DebugSupport member function definitions
|
||||
//
|
||||
|
|
|
@ -41,10 +41,6 @@ typedef struct _EFI_TLS_PROTOCOL EFI_TLS_PROTOCOL;
|
|||
/// EFI_TLS_SESSION_DATA_TYPE
|
||||
///
|
||||
typedef enum {
|
||||
///
|
||||
/// Session Configuration
|
||||
///
|
||||
|
||||
///
|
||||
/// TLS session Version. The corresponding Data is of type EFI_TLS_VERSION.
|
||||
///
|
||||
|
@ -86,11 +82,6 @@ typedef enum {
|
|||
/// The corresponding Data is of type EFI_TLS_SESSION_STATE.
|
||||
///
|
||||
EfiTlsSessionState,
|
||||
|
||||
///
|
||||
/// Session information
|
||||
///
|
||||
|
||||
///
|
||||
/// TLS session data client random.
|
||||
/// The corresponding Data is of type EFI_TLS_RANDOM.
|
||||
|
@ -106,9 +97,15 @@ typedef enum {
|
|||
/// The corresponding Data is of type EFI_TLS_MASTER_SECRET.
|
||||
///
|
||||
EfiTlsKeyMaterial,
|
||||
///
|
||||
/// TLS session hostname for validation which is used to verify whether the name
|
||||
/// within the peer certificate matches a given host name.
|
||||
/// This parameter is invalid when EfiTlsVerifyMethod is EFI_TLS_VERIFY_NONE.
|
||||
/// The corresponding Data is of type EFI_TLS_VERIFY_HOST.
|
||||
///
|
||||
EfiTlsVerifyHost,
|
||||
|
||||
EfiTlsSessionDataTypeMaximum
|
||||
|
||||
} EFI_TLS_SESSION_DATA_TYPE;
|
||||
|
||||
///
|
||||
|
@ -187,6 +184,54 @@ typedef UINT32 EFI_TLS_VERIFY;
|
|||
///
|
||||
#define EFI_TLS_VERIFY_CLIENT_ONCE 0x4
|
||||
|
||||
///
|
||||
/// EFI_TLS_VERIFY_HOST_FLAG
|
||||
///
|
||||
typedef UINT32 EFI_TLS_VERIFY_HOST_FLAG;
|
||||
///
|
||||
/// There is no additional flags set for hostname validation.
|
||||
/// Wildcards are supported and they match only in the left-most label.
|
||||
///
|
||||
#define EFI_TLS_VERIFY_FLAG_NONE 0x00
|
||||
///
|
||||
/// Always check the Subject Distinguished Name (DN) in the peer certificate even if the
|
||||
/// certificate contains Subject Alternative Name (SAN).
|
||||
///
|
||||
#define EFI_TLS_VERIFY_FLAG_ALWAYS_CHECK_SUBJECT 0x01
|
||||
///
|
||||
/// Disable the match of all wildcards.
|
||||
///
|
||||
#define EFI_TLS_VERIFY_FLAG_NO_WILDCARDS 0x02
|
||||
///
|
||||
/// Disable the "*" as wildcard in labels that have a prefix or suffix (e.g. "www*" or "*www").
|
||||
///
|
||||
#define EFI_TLS_VERIFY_FLAG_NO_PARTIAL_WILDCARDS 0x04
|
||||
///
|
||||
/// Allow the "*" to match more than one labels. Otherwise, only matches a single label.
|
||||
///
|
||||
#define EFI_TLS_VERIFY_FLAG_MULTI_LABEL_WILDCARDS 0x08
|
||||
///
|
||||
/// Restrict to only match direct child sub-domains which start with ".".
|
||||
/// For example, a name of ".example.com" would match "www.example.com" with this flag,
|
||||
/// but would not match "www.sub.example.com".
|
||||
///
|
||||
#define EFI_TLS_VERIFY_FLAG_SINGLE_LABEL_SUBDOMAINS 0x10
|
||||
///
|
||||
/// Never check the Subject Distinguished Name (DN) even there is no
|
||||
/// Subject Alternative Name (SAN) in the certificate.
|
||||
///
|
||||
#define EFI_TLS_VERIFY_FLAG_NEVER_CHECK_SUBJECT 0x20
|
||||
|
||||
///
|
||||
/// EFI_TLS_VERIFY_HOST
|
||||
///
|
||||
#pragma pack (1)
|
||||
typedef struct {
|
||||
EFI_TLS_VERIFY_HOST_FLAG Flags;
|
||||
CHAR8 *HostName;
|
||||
} EFI_TLS_VERIFY_HOST;
|
||||
#pragma pack ()
|
||||
|
||||
///
|
||||
/// EFI_TLS_RANDOM
|
||||
/// Note: The definition of EFI_TLS_RANDOM is from "RFC 5246 A.4.1.
|
||||
|
|
|
@ -322,9 +322,9 @@ typedef union {
|
|||
///
|
||||
UINT32 RDRAND:1;
|
||||
///
|
||||
/// [Bit 31] Always returns 0.
|
||||
/// [Bit 31] A value of 1 indicates that processor is in Para-Virtualized.
|
||||
///
|
||||
UINT32 NotUsed:1;
|
||||
UINT32 ParaVirtualized : 1;
|
||||
} Bits;
|
||||
///
|
||||
/// All bit fields as a 32-bit value
|
||||
|
|
|
@ -624,3 +624,146 @@ CalculateCrc32(
|
|||
|
||||
return Crc ^ 0xffffffff;
|
||||
}
|
||||
|
||||
GLOBAL_REMOVE_IF_UNREFERENCED STATIC CONST UINT16 mCrc16LookupTable[256] =
|
||||
{
|
||||
0x0000, 0xC0C1, 0xC181, 0x0140, 0xC301, 0x03C0, 0x0280, 0xC241,
|
||||
0xC601, 0x06C0, 0x0780, 0xC741, 0x0500, 0xC5C1, 0xC481, 0x0440,
|
||||
0xCC01, 0x0CC0, 0x0D80, 0xCD41, 0x0F00, 0xCFC1, 0xCE81, 0x0E40,
|
||||
0x0A00, 0xCAC1, 0xCB81, 0x0B40, 0xC901, 0x09C0, 0x0880, 0xC841,
|
||||
0xD801, 0x18C0, 0x1980, 0xD941, 0x1B00, 0xDBC1, 0xDA81, 0x1A40,
|
||||
0x1E00, 0xDEC1, 0xDF81, 0x1F40, 0xDD01, 0x1DC0, 0x1C80, 0xDC41,
|
||||
0x1400, 0xD4C1, 0xD581, 0x1540, 0xD701, 0x17C0, 0x1680, 0xD641,
|
||||
0xD201, 0x12C0, 0x1380, 0xD341, 0x1100, 0xD1C1, 0xD081, 0x1040,
|
||||
0xF001, 0x30C0, 0x3180, 0xF141, 0x3300, 0xF3C1, 0xF281, 0x3240,
|
||||
0x3600, 0xF6C1, 0xF781, 0x3740, 0xF501, 0x35C0, 0x3480, 0xF441,
|
||||
0x3C00, 0xFCC1, 0xFD81, 0x3D40, 0xFF01, 0x3FC0, 0x3E80, 0xFE41,
|
||||
0xFA01, 0x3AC0, 0x3B80, 0xFB41, 0x3900, 0xF9C1, 0xF881, 0x3840,
|
||||
0x2800, 0xE8C1, 0xE981, 0x2940, 0xEB01, 0x2BC0, 0x2A80, 0xEA41,
|
||||
0xEE01, 0x2EC0, 0x2F80, 0xEF41, 0x2D00, 0xEDC1, 0xEC81, 0x2C40,
|
||||
0xE401, 0x24C0, 0x2580, 0xE541, 0x2700, 0xE7C1, 0xE681, 0x2640,
|
||||
0x2200, 0xE2C1, 0xE381, 0x2340, 0xE101, 0x21C0, 0x2080, 0xE041,
|
||||
0xA001, 0x60C0, 0x6180, 0xA141, 0x6300, 0xA3C1, 0xA281, 0x6240,
|
||||
0x6600, 0xA6C1, 0xA781, 0x6740, 0xA501, 0x65C0, 0x6480, 0xA441,
|
||||
0x6C00, 0xACC1, 0xAD81, 0x6D40, 0xAF01, 0x6FC0, 0x6E80, 0xAE41,
|
||||
0xAA01, 0x6AC0, 0x6B80, 0xAB41, 0x6900, 0xA9C1, 0xA881, 0x6840,
|
||||
0x7800, 0xB8C1, 0xB981, 0x7940, 0xBB01, 0x7BC0, 0x7A80, 0xBA41,
|
||||
0xBE01, 0x7EC0, 0x7F80, 0xBF41, 0x7D00, 0xBDC1, 0xBC81, 0x7C40,
|
||||
0xB401, 0x74C0, 0x7580, 0xB541, 0x7700, 0xB7C1, 0xB681, 0x7640,
|
||||
0x7200, 0xB2C1, 0xB381, 0x7340, 0xB101, 0x71C0, 0x7080, 0xB041,
|
||||
0x5000, 0x90C1, 0x9181, 0x5140, 0x9301, 0x53C0, 0x5280, 0x9241,
|
||||
0x9601, 0x56C0, 0x5780, 0x9741, 0x5500, 0x95C1, 0x9481, 0x5440,
|
||||
0x9C01, 0x5CC0, 0x5D80, 0x9D41, 0x5F00, 0x9FC1, 0x9E81, 0x5E40,
|
||||
0x5A00, 0x9AC1, 0x9B81, 0x5B40, 0x9901, 0x59C0, 0x5880, 0x9841,
|
||||
0x8801, 0x48C0, 0x4980, 0x8941, 0x4B00, 0x8BC1, 0x8A81, 0x4A40,
|
||||
0x4E00, 0x8EC1, 0x8F81, 0x4F40, 0x8D01, 0x4DC0, 0x4C80, 0x8C41,
|
||||
0x4400, 0x84C1, 0x8581, 0x4540, 0x8701, 0x47C0, 0x4680, 0x8641,
|
||||
0x8201, 0x42C0, 0x4380, 0x8341, 0x4100, 0x81C1, 0x8081, 0x4040
|
||||
};
|
||||
|
||||
/**
|
||||
Calculates the CRC16-ANSI checksum of the given buffer.
|
||||
|
||||
@param[in] Buffer Pointer to the buffer.
|
||||
@param[in] Length Length of the buffer, in bytes.
|
||||
@param[in] InitialValue Initial value of the CRC.
|
||||
|
||||
@return The CRC16-ANSI checksum.
|
||||
**/
|
||||
UINT16
|
||||
EFIAPI
|
||||
CalculateCrc16Ansi (
|
||||
IN CONST VOID *Buffer,
|
||||
IN UINTN Length,
|
||||
IN UINT16 InitialValue
|
||||
)
|
||||
{
|
||||
CONST UINT8 *Buf;
|
||||
UINT16 Crc;
|
||||
|
||||
Buf = Buffer;
|
||||
|
||||
Crc = InitialValue;
|
||||
|
||||
while (Length-- != 0) {
|
||||
Crc = mCrc16LookupTable[(Crc & 0xFF) ^ *(Buf++)] ^ (Crc >> 8);
|
||||
}
|
||||
|
||||
return Crc;
|
||||
}
|
||||
|
||||
GLOBAL_REMOVE_IF_UNREFERENCED STATIC CONST UINT32 mCrc32cLookupTable[256] = {
|
||||
0x00000000, 0xf26b8303, 0xe13b70f7, 0x1350f3f4, 0xc79a971f, 0x35f1141c,
|
||||
0x26a1e7e8, 0xd4ca64eb, 0x8ad958cf, 0x78b2dbcc, 0x6be22838, 0x9989ab3b,
|
||||
0x4d43cfd0, 0xbf284cd3, 0xac78bf27, 0x5e133c24, 0x105ec76f, 0xe235446c,
|
||||
0xf165b798, 0x030e349b, 0xd7c45070, 0x25afd373, 0x36ff2087, 0xc494a384,
|
||||
0x9a879fa0, 0x68ec1ca3, 0x7bbcef57, 0x89d76c54, 0x5d1d08bf, 0xaf768bbc,
|
||||
0xbc267848, 0x4e4dfb4b, 0x20bd8ede, 0xd2d60ddd, 0xc186fe29, 0x33ed7d2a,
|
||||
0xe72719c1, 0x154c9ac2, 0x061c6936, 0xf477ea35, 0xaa64d611, 0x580f5512,
|
||||
0x4b5fa6e6, 0xb93425e5, 0x6dfe410e, 0x9f95c20d, 0x8cc531f9, 0x7eaeb2fa,
|
||||
0x30e349b1, 0xc288cab2, 0xd1d83946, 0x23b3ba45, 0xf779deae, 0x05125dad,
|
||||
0x1642ae59, 0xe4292d5a, 0xba3a117e, 0x4851927d, 0x5b016189, 0xa96ae28a,
|
||||
0x7da08661, 0x8fcb0562, 0x9c9bf696, 0x6ef07595, 0x417b1dbc, 0xb3109ebf,
|
||||
0xa0406d4b, 0x522bee48, 0x86e18aa3, 0x748a09a0, 0x67dafa54, 0x95b17957,
|
||||
0xcba24573, 0x39c9c670, 0x2a993584, 0xd8f2b687, 0x0c38d26c, 0xfe53516f,
|
||||
0xed03a29b, 0x1f682198, 0x5125dad3, 0xa34e59d0, 0xb01eaa24, 0x42752927,
|
||||
0x96bf4dcc, 0x64d4cecf, 0x77843d3b, 0x85efbe38, 0xdbfc821c, 0x2997011f,
|
||||
0x3ac7f2eb, 0xc8ac71e8, 0x1c661503, 0xee0d9600, 0xfd5d65f4, 0x0f36e6f7,
|
||||
0x61c69362, 0x93ad1061, 0x80fde395, 0x72966096, 0xa65c047d, 0x5437877e,
|
||||
0x4767748a, 0xb50cf789, 0xeb1fcbad, 0x197448ae, 0x0a24bb5a, 0xf84f3859,
|
||||
0x2c855cb2, 0xdeeedfb1, 0xcdbe2c45, 0x3fd5af46, 0x7198540d, 0x83f3d70e,
|
||||
0x90a324fa, 0x62c8a7f9, 0xb602c312, 0x44694011, 0x5739b3e5, 0xa55230e6,
|
||||
0xfb410cc2, 0x092a8fc1, 0x1a7a7c35, 0xe811ff36, 0x3cdb9bdd, 0xceb018de,
|
||||
0xdde0eb2a, 0x2f8b6829, 0x82f63b78, 0x709db87b, 0x63cd4b8f, 0x91a6c88c,
|
||||
0x456cac67, 0xb7072f64, 0xa457dc90, 0x563c5f93, 0x082f63b7, 0xfa44e0b4,
|
||||
0xe9141340, 0x1b7f9043, 0xcfb5f4a8, 0x3dde77ab, 0x2e8e845f, 0xdce5075c,
|
||||
0x92a8fc17, 0x60c37f14, 0x73938ce0, 0x81f80fe3, 0x55326b08, 0xa759e80b,
|
||||
0xb4091bff, 0x466298fc, 0x1871a4d8, 0xea1a27db, 0xf94ad42f, 0x0b21572c,
|
||||
0xdfeb33c7, 0x2d80b0c4, 0x3ed04330, 0xccbbc033, 0xa24bb5a6, 0x502036a5,
|
||||
0x4370c551, 0xb11b4652, 0x65d122b9, 0x97baa1ba, 0x84ea524e, 0x7681d14d,
|
||||
0x2892ed69, 0xdaf96e6a, 0xc9a99d9e, 0x3bc21e9d, 0xef087a76, 0x1d63f975,
|
||||
0x0e330a81, 0xfc588982, 0xb21572c9, 0x407ef1ca, 0x532e023e, 0xa145813d,
|
||||
0x758fe5d6, 0x87e466d5, 0x94b49521, 0x66df1622, 0x38cc2a06, 0xcaa7a905,
|
||||
0xd9f75af1, 0x2b9cd9f2, 0xff56bd19, 0x0d3d3e1a, 0x1e6dcdee, 0xec064eed,
|
||||
0xc38d26c4, 0x31e6a5c7, 0x22b65633, 0xd0ddd530, 0x0417b1db, 0xf67c32d8,
|
||||
0xe52cc12c, 0x1747422f, 0x49547e0b, 0xbb3ffd08, 0xa86f0efc, 0x5a048dff,
|
||||
0x8ecee914, 0x7ca56a17, 0x6ff599e3, 0x9d9e1ae0, 0xd3d3e1ab, 0x21b862a8,
|
||||
0x32e8915c, 0xc083125f, 0x144976b4, 0xe622f5b7, 0xf5720643, 0x07198540,
|
||||
0x590ab964, 0xab613a67, 0xb831c993, 0x4a5a4a90, 0x9e902e7b, 0x6cfbad78,
|
||||
0x7fab5e8c, 0x8dc0dd8f, 0xe330a81a, 0x115b2b19, 0x020bd8ed, 0xf0605bee,
|
||||
0x24aa3f05, 0xd6c1bc06, 0xc5914ff2, 0x37faccf1, 0x69e9f0d5, 0x9b8273d6,
|
||||
0x88d28022, 0x7ab90321, 0xae7367ca, 0x5c18e4c9, 0x4f48173d, 0xbd23943e,
|
||||
0xf36e6f75, 0x0105ec76, 0x12551f82, 0xe03e9c81, 0x34f4f86a, 0xc69f7b69,
|
||||
0xd5cf889d, 0x27a40b9e, 0x79b737ba, 0x8bdcb4b9, 0x988c474d, 0x6ae7c44e,
|
||||
0xbe2da0a5, 0x4c4623a6, 0x5f16d052, 0xad7d5351
|
||||
};
|
||||
|
||||
/**
|
||||
Calculates the CRC32c checksum of the given buffer.
|
||||
|
||||
@param[in] Buffer Pointer to the buffer.
|
||||
@param[in] Length Length of the buffer, in bytes.
|
||||
@param[in] InitialValue Initial value of the CRC.
|
||||
|
||||
@return The CRC32c checksum.
|
||||
**/
|
||||
UINT32
|
||||
EFIAPI
|
||||
CalculateCrc32c (
|
||||
IN CONST VOID *Buffer,
|
||||
IN UINTN Length,
|
||||
IN UINT32 InitialValue
|
||||
)
|
||||
{
|
||||
CONST UINT8 *Buf;
|
||||
UINT32 Crc;
|
||||
|
||||
Buf = Buffer;
|
||||
Crc = ~InitialValue;
|
||||
|
||||
while (Length-- != 0) {
|
||||
Crc = mCrc32cLookupTable[(Crc & 0xFF) ^ *(Buf++)] ^ (Crc >> 8);
|
||||
}
|
||||
|
||||
return ~Crc;
|
||||
}
|
||||
|
|
|
@ -0,0 +1,36 @@
|
|||
/** @file
|
||||
|
||||
BaseOverflowLib
|
||||
|
||||
Copyright (c) 2020, Download-Fritz
|
||||
|
||||
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.
|
||||
|
||||
**/
|
||||
#include <Base.h>
|
||||
|
||||
#include <Library/BaseLib.h>
|
||||
#include <Library/BaseOverflowLib.h>
|
||||
|
||||
BOOLEAN
|
||||
BaseOverflowAlignUpU32 (
|
||||
UINT32 Value,
|
||||
UINT32 Alignment,
|
||||
UINT32 *Result
|
||||
)
|
||||
{
|
||||
BOOLEAN Status;
|
||||
|
||||
Status = BaseOverflowAddU32 (Value, Alignment - 1U, Result);
|
||||
*Result &= ~(Alignment - 1U);
|
||||
|
||||
return Status;
|
||||
}
|
|
@ -0,0 +1,442 @@
|
|||
/** @file
|
||||
|
||||
BaseOverflowLib
|
||||
|
||||
Copyright (c) 2018, vit9696
|
||||
|
||||
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.
|
||||
|
||||
**/
|
||||
|
||||
#include <Base.h>
|
||||
|
||||
#include <Library/BaseLib.h>
|
||||
#include <Library/BaseOverflowLib.h>
|
||||
|
||||
#include "BaseOverflowInternals.h"
|
||||
|
||||
//
|
||||
// Software implementations provided try not to be obviously slow, but primarily
|
||||
// target C99 compliance rather than performance.
|
||||
//
|
||||
|
||||
BOOLEAN
|
||||
BaseOverflowAddU16 (
|
||||
UINT16 A,
|
||||
UINT16 B,
|
||||
UINT16 *Result
|
||||
)
|
||||
{
|
||||
#if defined (BASE_HAS_TYPE_GENERIC_BUILTINS)
|
||||
return __builtin_add_overflow (A, B, Result);
|
||||
#else
|
||||
UINT32 Temp;
|
||||
|
||||
//
|
||||
// I believe casting will be faster on X86 at least.
|
||||
//
|
||||
Temp = A + B;
|
||||
*Result = (UINT16)Temp;
|
||||
if (Temp <= MAX_UINT16) {
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
return TRUE;
|
||||
#endif
|
||||
}
|
||||
|
||||
BOOLEAN
|
||||
BaseOverflowSubU16 (
|
||||
UINT16 A,
|
||||
UINT16 B,
|
||||
UINT16 *Result
|
||||
)
|
||||
{
|
||||
#if defined (BASE_HAS_TYPE_GENERIC_BUILTINS)
|
||||
return __builtin_sub_overflow (A, B, Result);
|
||||
#else
|
||||
*Result = (UINT16)(A - B);
|
||||
|
||||
if (A >= B) {
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
return TRUE;
|
||||
#endif
|
||||
}
|
||||
|
||||
BOOLEAN
|
||||
BaseOverflowMulU16 (
|
||||
UINT16 A,
|
||||
UINT16 B,
|
||||
UINT16 *Result
|
||||
)
|
||||
{
|
||||
#if defined (BASE_HAS_TYPE_GENERIC_BUILTINS)
|
||||
return __builtin_mul_overflow (A, B, Result);
|
||||
#else
|
||||
UINT32 Temp;
|
||||
|
||||
Temp = (UINT32)A * B;
|
||||
*Result = (UINT16)Temp;
|
||||
if (Temp <= MAX_UINT32) {
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
return TRUE;
|
||||
#endif
|
||||
}
|
||||
|
||||
BOOLEAN
|
||||
BaseOverflowAddU32 (
|
||||
UINT32 A,
|
||||
UINT32 B,
|
||||
UINT32 *Result
|
||||
)
|
||||
{
|
||||
#if defined (BASE_HAS_TYPE_GENERIC_BUILTINS)
|
||||
return __builtin_add_overflow (A, B, Result);
|
||||
#elif defined (BASE_HAS_TYPE_SPECIFIC_BUILTINS_64)
|
||||
return __builtin_uadd_overflow (A, B, Result);
|
||||
#else
|
||||
UINT32 Temp;
|
||||
|
||||
//
|
||||
// I believe casting will be faster on X86 at least.
|
||||
//
|
||||
Temp = A + B;
|
||||
*Result = Temp;
|
||||
if (Temp >= A) {
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
return TRUE;
|
||||
#endif
|
||||
}
|
||||
|
||||
BOOLEAN
|
||||
BaseOverflowSubU32 (
|
||||
UINT32 A,
|
||||
UINT32 B,
|
||||
UINT32 *Result
|
||||
)
|
||||
{
|
||||
#if defined (BASE_HAS_TYPE_GENERIC_BUILTINS)
|
||||
return __builtin_sub_overflow (A, B, Result);
|
||||
#elif defined (BASE_HAS_TYPE_SPECIFIC_BUILTINS)
|
||||
return __builtin_usub_overflow (A, B, Result);
|
||||
#else
|
||||
*Result = A - B;
|
||||
if (B <= A) {
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
return TRUE;
|
||||
#endif
|
||||
}
|
||||
|
||||
BOOLEAN
|
||||
BaseOverflowMulU32 (
|
||||
UINT32 A,
|
||||
UINT32 B,
|
||||
UINT32 *Result
|
||||
)
|
||||
{
|
||||
#if defined (BASE_HAS_TYPE_GENERIC_BUILTINS)
|
||||
return __builtin_mul_overflow (A, B, Result);
|
||||
#elif defined (BASE_HAS_TYPE_SPECIFIC_BUILTINS)
|
||||
return __builtin_umul_overflow (A, B, Result);
|
||||
#else
|
||||
UINT64 Temp;
|
||||
|
||||
Temp = (UINT64)A * B;
|
||||
*Result = (UINT32)Temp;
|
||||
if (Temp <= MAX_UINT32) {
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
return TRUE;
|
||||
#endif
|
||||
}
|
||||
|
||||
BOOLEAN
|
||||
BaseOverflowAddS32 (
|
||||
INT32 A,
|
||||
INT32 B,
|
||||
INT32 *Result
|
||||
)
|
||||
{
|
||||
#if defined (BASE_HAS_TYPE_GENERIC_BUILTINS)
|
||||
return __builtin_add_overflow (A, B, Result);
|
||||
#elif defined (BASE_HAS_TYPE_SPECIFIC_BUILTINS)
|
||||
return __builtin_sadd_overflow (A, B, Result);
|
||||
#else
|
||||
INT64 Temp;
|
||||
|
||||
Temp = (INT64)A + B;
|
||||
*Result = (INT32)Temp;
|
||||
if ((Temp >= MIN_INT32) && (Temp <= MAX_INT32)) {
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
return TRUE;
|
||||
#endif
|
||||
}
|
||||
|
||||
BOOLEAN
|
||||
BaseOverflowSubS32 (
|
||||
INT32 A,
|
||||
INT32 B,
|
||||
INT32 *Result
|
||||
)
|
||||
{
|
||||
#if defined (BASE_HAS_TYPE_GENERIC_BUILTINS)
|
||||
return __builtin_sub_overflow (A, B, Result);
|
||||
#elif defined (BASE_HAS_TYPE_SPECIFIC_BUILTINS)
|
||||
return __builtin_ssub_overflow (A, B, Result);
|
||||
#else
|
||||
INT64 Temp;
|
||||
|
||||
Temp = (INT64)A - B;
|
||||
*Result = (INT32)Temp;
|
||||
if ((Temp >= MIN_INT32) && (Temp <= MAX_INT32)) {
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
return TRUE;
|
||||
#endif
|
||||
}
|
||||
|
||||
BOOLEAN
|
||||
BaseOverflowMulS32 (
|
||||
INT32 A,
|
||||
INT32 B,
|
||||
INT32 *Result
|
||||
)
|
||||
{
|
||||
#if defined (BASE_HAS_TYPE_GENERIC_BUILTINS)
|
||||
return __builtin_mul_overflow (A, B, Result);
|
||||
#elif defined (BASE_HAS_TYPE_SPECIFIC_BUILTINS)
|
||||
return __builtin_smul_overflow (A, B, Result);
|
||||
#else
|
||||
INT64 Temp;
|
||||
|
||||
Temp = MultS64x64 (A, B);
|
||||
*Result = (INT32)Temp;
|
||||
if ((Temp >= MIN_INT32) && (Temp <= MAX_INT32)) {
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
return TRUE;
|
||||
#endif
|
||||
}
|
||||
|
||||
BOOLEAN
|
||||
BaseOverflowAddU64 (
|
||||
UINT64 A,
|
||||
UINT64 B,
|
||||
UINT64 *Result
|
||||
)
|
||||
{
|
||||
#if defined (BASE_HAS_TYPE_GENERIC_BUILTINS)
|
||||
return __builtin_add_overflow (A, B, Result);
|
||||
#elif defined (BASE_HAS_TYPE_SPECIFIC_BUILTINS)
|
||||
return __builtin_uaddll_overflow (A, B, Result);
|
||||
#else
|
||||
UINT64 Temp;
|
||||
|
||||
Temp = A + B;
|
||||
*Result = Temp;
|
||||
if (Temp >= A) {
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
return TRUE;
|
||||
#endif
|
||||
}
|
||||
|
||||
BOOLEAN
|
||||
BaseOverflowSubU64 (
|
||||
UINT64 A,
|
||||
UINT64 B,
|
||||
UINT64 *Result
|
||||
)
|
||||
{
|
||||
#if defined (BASE_HAS_TYPE_GENERIC_BUILTINS)
|
||||
return __builtin_sub_overflow (A, B, Result);
|
||||
#elif defined (BASE_HAS_TYPE_SPECIFIC_BUILTINS)
|
||||
return __builtin_usubll_overflow (A, B, Result);
|
||||
#else
|
||||
*Result = A - B;
|
||||
if (B <= A) {
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
return TRUE;
|
||||
#endif
|
||||
}
|
||||
|
||||
BOOLEAN
|
||||
BaseOverflowMulU64 (
|
||||
UINT64 A,
|
||||
UINT64 B,
|
||||
UINT64 *Result
|
||||
)
|
||||
{
|
||||
#if defined (BASE_HAS_TYPE_GENERIC_BUILTINS)
|
||||
return __builtin_mul_overflow (A, B, Result);
|
||||
#elif defined (BASE_HAS_TYPE_SPECIFIC_BUILTINS)
|
||||
return __builtin_umulll_overflow (A, B, Result);
|
||||
#else
|
||||
UINT64 AHi;
|
||||
UINT64 ALo;
|
||||
UINT64 BHi;
|
||||
UINT64 BLo;
|
||||
UINT64 LoBits;
|
||||
UINT64 HiBits1;
|
||||
UINT64 HiBits2;
|
||||
BOOLEAN Overflow;
|
||||
|
||||
//
|
||||
// Based on the 2nd option written by Charphacy, believed to be the fastest portable on x86.
|
||||
// See: https://stackoverflow.com/a/26320664
|
||||
// Implements overflow checking by a series of up to 3 multiplications.
|
||||
//
|
||||
|
||||
AHi = RShiftU64 (A, 32);
|
||||
ALo = A & MAX_UINT32;
|
||||
BHi = RShiftU64 (B, 32);
|
||||
BLo = B & MAX_UINT32;
|
||||
|
||||
LoBits = MultU64x64 (ALo, BLo);
|
||||
if ((AHi == 0) && (BHi == 0)) {
|
||||
*Result = LoBits;
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
Overflow = AHi > 0 && BHi > 0;
|
||||
HiBits1 = MultU64x64 (ALo, BHi);
|
||||
HiBits2 = MultU64x64 (AHi, BLo);
|
||||
|
||||
*Result = LoBits + LShiftU64 (HiBits1 + HiBits2, 32);
|
||||
return Overflow || *Result < LoBits || RShiftU64 (HiBits1, 32) != 0 || RShiftU64 (HiBits2, 32) != 0;
|
||||
#endif
|
||||
}
|
||||
|
||||
BOOLEAN
|
||||
BaseOverflowAddS64 (
|
||||
INT64 A,
|
||||
INT64 B,
|
||||
INT64 *Result
|
||||
)
|
||||
{
|
||||
#if defined (BASE_HAS_TYPE_GENERIC_BUILTINS)
|
||||
return __builtin_add_overflow (A, B, Result);
|
||||
#elif defined (BASE_HAS_TYPE_SPECIFIC_BUILTINS)
|
||||
return __builtin_saddll_overflow (A, B, Result);
|
||||
#else
|
||||
if (((B <= 0) || (A <= MAX_INT64 - B)) && ((B >= 0) || (A >= MIN_INT64 - B))) {
|
||||
*Result = A + B;
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
//
|
||||
// Assign some defined value to *Result.
|
||||
//
|
||||
*Result = 0;
|
||||
return TRUE;
|
||||
#endif
|
||||
}
|
||||
|
||||
BOOLEAN
|
||||
BaseOverflowSubS64 (
|
||||
INT64 A,
|
||||
INT64 B,
|
||||
INT64 *Result
|
||||
)
|
||||
{
|
||||
#if defined (BASE_HAS_TYPE_GENERIC_BUILTINS)
|
||||
return __builtin_sub_overflow (A, B, Result);
|
||||
#elif defined (BASE_HAS_TYPE_SPECIFIC_BUILTINS)
|
||||
return __builtin_ssubll_overflow (A, B, Result);
|
||||
#else
|
||||
if (((B >= 0) || (A <= MAX_INT64 + B)) && ((B <= 0) || (A >= MIN_INT64 + B))) {
|
||||
*Result = A - B;
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
//
|
||||
// Assign some defined value to *Result.
|
||||
//
|
||||
*Result = 0;
|
||||
return TRUE;
|
||||
#endif
|
||||
}
|
||||
|
||||
BOOLEAN
|
||||
BaseOverflowMulS64 (
|
||||
INT64 A,
|
||||
INT64 B,
|
||||
INT64 *Result
|
||||
)
|
||||
{
|
||||
//
|
||||
// Intel 32-bit architectures do not have hardware signed 64-bit
|
||||
// multiplication with overflow.
|
||||
//
|
||||
#if defined (BASE_HAS_TYPE_GENERIC_BUILTINS) && !defined (MDE_CPU_IA32)
|
||||
return __builtin_mul_overflow (A, B, Result);
|
||||
#elif defined (BASE_HAS_TYPE_SPECIFIC_BUILTINS) && !defined (MDE_CPU_IA32)
|
||||
return __builtin_smulll_overflow (A, B, Result);
|
||||
#else
|
||||
UINT64 AU;
|
||||
UINT64 BU;
|
||||
UINT64 ResultU;
|
||||
|
||||
//
|
||||
// It hurts to implement it without unsigned multiplication, maybe rewrite it one day.
|
||||
// The idea taken from BaseSafeIntLib.
|
||||
//
|
||||
|
||||
#define OC_ABS_64(X) (((X) < 0) ? (((UINT64) (-((X) + 1))) + 1) : (UINT64) (X))
|
||||
|
||||
AU = OC_ABS_64 (A);
|
||||
BU = OC_ABS_64 (B);
|
||||
|
||||
if (BaseOverflowMulU64 (AU, BU, &ResultU)) {
|
||||
*Result = 0;
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
//
|
||||
// Split into positive and negative results and check just one range.
|
||||
//
|
||||
if ((A < 0) == (B < 0)) {
|
||||
if (ResultU <= MAX_INT64) {
|
||||
*Result = (INT64)ResultU;
|
||||
return FALSE;
|
||||
}
|
||||
} else {
|
||||
if (ResultU < OC_ABS_64 (MIN_INT64)) {
|
||||
*Result = -((INT64)ResultU);
|
||||
return FALSE;
|
||||
} else if (ResultU == OC_ABS_64 (MIN_INT64)) {
|
||||
*Result = MIN_INT64;
|
||||
return FALSE;
|
||||
}
|
||||
}
|
||||
|
||||
#undef OC_ABS_64
|
||||
|
||||
*Result = 0;
|
||||
return TRUE;
|
||||
#endif
|
||||
}
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue