Date   

Why SetVariableCheckHandlerMor() is implemented in VariableSmm and TcgMorLockSmm?

Ni, Ray
 

Qi,

I happened to find that there are duplicated implementations in VariableSmm driver and TcgMorLockSmm driver.

Do you know why the check needs to be done in two places?

 

Can we remove the one in VariableSmm driver?

 

Thanks,

Ray


Re: [PATCH v2 0/5] Fix OvmfXen HVM Direct kernel boot failure

Lin, Gary (HPS OE-Linux)
 

On Fri, Aug 13, 2021 at 09:55:48AM +0000, Yao, Jiewen wrote:
HI Gary
Hi Jiewen,

Several comment:

1) According to our process, we need a Bugzilla. Would you please file it?
Okay, will create a bugzilla entry to track the issue.

2) I do not understand how HVM direct kernel boot is related to S3 enabling.
It seems 1/3/4/5 are for S3, while 2 is for missing driver.
Should we split them to 2 patch set?
Actually the inconsistency between QemuFwCfgS3Enabled() and
PcdAcpiS3Enable casued the boot failure of HVM direct kernel boot.
S3SaveStateDxe checked PcdAcpiS3Enable(=FALSE) and skipped S3BootScript.
On the other hand, PlatformBootManagerBeforeConsole() invoked
QemuFwCfgS3Enabled()(=TRUE) and tried to locate S3BootScript. Since
S3BootScript wasn't installed, it failed with EFI_NOT_FOUND and stopped
the booting. So Patch 1 and 2 are mainly for the booting issues in
OvmfXen. For Patch 3~5, I just try to eliminate the inconsistency to
avoid the potential problems.

I can split them into 2 or 3 patch sets if necessary.

3) Does the S3 issue only happen in direct kernel boot? Or is it a generic issue.

4) Have you validated non direct kernel boot to ensure it still works?
Jim,

Did you encounter any problem with non direct kernel boot VM?


Cheers,

Gary Lin


-----Original Message-----
From: devel@edk2.groups.io <devel@edk2.groups.io> On Behalf Of Lin, Gary
(HPS OE-Linux)
Sent: Friday, August 13, 2021 2:13 PM
To: devel@edk2.groups.io
Subject: [edk2-devel] [PATCH v2 0/5] Fix OvmfXen HVM Direct kernel boot
failure

When using HVM Direct kernel boot with OvmfXen, it could fail at the
S3BootScript due to the inconsistency between QemuFwCfgS3Enabled()
and PcdAcpiS3Enable. Besides, QemuKernelLoaderFsDxe wasn't included
in OvmfXen, so the firmware couldn't fetch kernel/initrd from fw_cfg.

This patch series initializes PcdAcpiS3Enable and adds
QemuKernelLoaderFsDxe into OvmfXen. Besides, QemuFwCfgS3Enabled() is
replaced with PcdAcpiS3Enable in several OVMF libraries to avoid the
potential inconsistency.

v2:
- Amend the description and address "HVM Direct Kernel Boot"
- Add the comment for the conditional test of QemuFwCfgS3Enabled()
- Remove unused QemuFwCfgLib
- Update my email address

Gary Lin (5):
OvmfPkg/OvmfXen: set PcdAcpiS3Enable at initialization
OvmfPkg/OvmfXen: add QemuKernelLoaderFsDxe
OvmfPkg/LockBoxLib: use PcdAcpiS3Enable to detect S3 support
OvmfPkg/PlatformBootManagerLib: use PcdAcpiS3Enable to detect S3
support
OvmfPkg/SmmControl2Dxe: use PcdAcpiS3Enable to detect S3 support

OvmfPkg/OvmfXen.dsc | 1 +
OvmfPkg/OvmfXen.fdf | 1 +
OvmfPkg/Library/LockBoxLib/LockBoxDxeLib.inf | 3 +--
.../PlatformBootManagerLib.inf | 1 +
OvmfPkg/SmmControl2Dxe/SmmControl2Dxe.inf | 2 ++
OvmfPkg/XenPlatformPei/XenPlatformPei.inf | 2 ++
OvmfPkg/Library/LockBoxLib/LockBoxDxe.c | 4 +---
.../Library/PlatformBootManagerLib/BdsPlatform.c | 2 +-
OvmfPkg/SmmControl2Dxe/SmmControl2Dxe.c | 4 +---
OvmfPkg/XenPlatformPei/Platform.c | 13 +++++++++++++
10 files changed, 24 insertions(+), 9 deletions(-)

--
2.31.1





Re: [PATCH] [edk2-staging] BaseTools/FMMT: Change Fv Header to FileSystemGuid3.

Bob Feng
 

Reviewed-by: Bob Feng <bob.c.feng@intel.com>

-----Original Message-----
From: devel@edk2.groups.io <devel@edk2.groups.io> On Behalf Of Bob Feng
Sent: Saturday, August 14, 2021 4:04 PM
To: devel@edk2.groups.io
Cc: Chen, Christine <yuwei.chen@intel.com>; Liming Gao <gaoliming@byosoft.com.cn>
Subject: [edk2-devel] [PATCH] [edk2-staging] BaseTools/FMMT: Change Fv Header to FileSystemGuid3.

From: Yuwei Chen <yuwei.chen@intel.com>

From: Yuwei Chen <yuwei.chen@intel.com>

Following PI spec: when there has Ffs with EFI_FFS_FILE_HEADER2, the Parent Fv of the Ffs need set to FileSystemGuid3; when all the Ffs with EFI_FFS_FILE_HEADER, the Parent Fv of the Ffs need set to FileSystemGuid2.
Currently, when changing the Ffs in Fv from EFI_FFS_FILE_HEADER to EFI_FFS_FILE_HEADER2, the Fv FileSystemGuid does not changed consistent with Ffs type.That caused build issue.

As FileSystemGuid3 is compatible with FileSystemGuid2, change all the Fv header to FileSystemGuid3. This patch modify the FMMT Add/ Replace function, when adding/replacing a new Ffs, set the Parent Fv header to FileSystemGuid3 directly, do not double check size.

Signed-off-by: Yuwei Chen <yuwei.chen@intel.com>
Cc: Bob Feng <bob.c.feng@intel.com>
Cc: Liming Gao <gaoliming@byosoft.com.cn>
---
BaseTools/Source/C/FMMT/FmmtLib.c | 6 +-----
1 file changed, 1 insertion(+), 5 deletions(-)

diff --git a/BaseTools/Source/C/FMMT/FmmtLib.c b/BaseTools/Source/C/FMMT/FmmtLib.c
index 4f6056edba..e1436112ca 100644
--- a/BaseTools/Source/C/FMMT/FmmtLib.c
+++ b/BaseTools/Source/C/FMMT/FmmtLib.c
@@ -3198,11 +3198,7 @@ LibEncapsulateFfsToFv (
CHAR8* SystemCommandFormatString; CHAR8* SystemCommand;- CHAR8* FfsGuid = "8c8ce578-8a3d-4f1c-9935-896185c32dd3";-- if (IsLargeFile == TRUE) {- FfsGuid = "5473c07a-3dcb-4dca-bd6f-1e9689e7349a";- }+ CHAR8* FfsGuid = "5473c07a-3dcb-4dca-bd6f-1e9689e7349a"; SystemCommandFormatString = NULL; SystemCommand = NULL;--
2.27.0.windows.1
GitPatchExtractor 1.1


-=-=-=-=-=-=
Groups.io Links: You receive all messages sent to this group.
View/Reply Online (#79306): https://edk2.groups.io/g/devel/message/79306
Mute This Topic: https://groups.io/mt/84880534/1768742
Group Owner: devel+owner@edk2.groups.io
Unsubscribe: https://edk2.groups.io/g/devel/unsub [bob.c.feng@intel.com] -=-=-=-=-=-=


[Patch v3 3/3] Ext4Pkg: Add .DSC file.

Pedro Falcato
 

This file is required to build Ext4Pkg.

Cc: Leif Lindholm <leif@nuviainc.com>
Cc: Michael D Kinney <michael.d.kinney@intel.com>
Cc: Bret Barkelew <Bret.Barkelew@microsoft.com>

Signed-off-by: Pedro Falcato <pedro.falcato@gmail.com>
---
Features/Ext4Pkg/Ext4Pkg.dsc | 68 ++++++++++++++++++++++++++++++++++++
1 file changed, 68 insertions(+)
create mode 100644 Features/Ext4Pkg/Ext4Pkg.dsc

diff --git a/Features/Ext4Pkg/Ext4Pkg.dsc b/Features/Ext4Pkg/Ext4Pkg.dsc
new file mode 100644
index 0000000000..62cb4e69cf
--- /dev/null
+++ b/Features/Ext4Pkg/Ext4Pkg.dsc
@@ -0,0 +1,68 @@
+## @file=0D
+# Ext4 Package=0D
+#=0D
+# This package provides libraries and drivers related to the ext4 filesys=
tem implementation.=0D
+# More details are available at: https://www.kernel.org/doc/html/v5.4/fil=
esystems/ext4/index.html=0D
+#=0D
+# Copyright (c) 2021 Pedro Falcato=0D
+# SPDX-License-Identifier: BSD-2-Clause-Patent=0D
+#=0D
+##=0D
+=0D
+=0D
+[Defines]=0D
+ PLATFORM_NAME =3D Ext4=0D
+ PLATFORM_GUID =3D 6B4BF998-668B-46D3-BCFA-971F99F8708C=
=0D
+ PLATFORM_VERSION =3D 0.1=0D
+ DSC_SPECIFICATION =3D 0x00010005=0D
+ SUPPORTED_ARCHITECTURES =3D IA32|X64|EBC|ARM|AARCH64|RISCV64=0D
+ OUTPUT_DIRECTORY =3D Build/Ext4Pkg=0D
+ BUILD_TARGETS =3D DEBUG|RELEASE|NOOPT=0D
+ SKUID_IDENTIFIER =3D DEFAULT=0D
+=0D
+[BuildOptions]=0D
+ *_*_*_CC_FLAGS =3D -D DISABLE_NEW_DEPRECATED_INTER=
FACES=0D
+=0D
+[LibraryClasses]=0D
+ #=0D
+ # Entry Point Libraries=0D
+ #=0D
+ UefiDriverEntryPoint|MdePkg/Library/UefiDriverEntryPoint/UefiDriverEntry=
Point.inf=0D
+ #=0D
+ # Common Libraries=0D
+ #=0D
+ BaseLib|MdePkg/Library/BaseLib/BaseLib.inf=0D
+ BaseMemoryLib|MdePkg/Library/BaseMemoryLib/BaseMemoryLib.inf=0D
+ UefiLib|MdePkg/Library/UefiLib/UefiLib.inf=0D
+ PrintLib|MdePkg/Library/BasePrintLib/BasePrintLib.inf=0D
+ PcdLib|MdePkg/Library/BasePcdLibNull/BasePcdLibNull.inf=0D
+ MemoryAllocationLib|MdePkg/Library/UefiMemoryAllocationLib/UefiMemoryAll=
ocationLib.inf=0D
+ UefiBootServicesTableLib|MdePkg/Library/UefiBootServicesTableLib/UefiBoo=
tServicesTableLib.inf=0D
+ UefiRuntimeServicesTableLib|MdePkg/Library/UefiRuntimeServicesTableLib/U=
efiRuntimeServicesTableLib.inf=0D
+ DebugLib|MdePkg/Library/BaseDebugLibNull/BaseDebugLibNull.inf=0D
+ DebugPrintErrorLevelLib|MdePkg/Library/BaseDebugPrintErrorLevelLib/BaseD=
ebugPrintErrorLevelLib.inf=0D
+ DevicePathLib|MdePkg/Library/UefiDevicePathLib/UefiDevicePathLib.inf=0D
+ OrderedCollectionLib|MdePkg/Library/BaseOrderedCollectionRedBlackTreeLib=
/BaseOrderedCollectionRedBlackTreeLib.inf=0D
+ BaseUcs2Utf8Lib|RedfishPkg/Library/BaseUcs2Utf8Lib/BaseUcs2Utf8Lib.inf=0D
+=0D
+##########################################################################=
#########################=0D
+#=0D
+# Components Section - list of the modules and components that will be pro=
cessed by compilation=0D
+# tools and the EDK II tools to generate PE32/PE32+/C=
off image files.=0D
+#=0D
+# Note: The EDK II DSC file is not used to specify how compiled binary ima=
ges get placed=0D
+# into firmware volume images. This section is just a list of module=
s to compile from=0D
+# source into UEFI-compliant binaries.=0D
+# It is the FDF file that contains information on combining binary f=
iles into firmware=0D
+# volume images, whose concept is beyond UEFI and is described in PI=
specification.=0D
+# Binary modules do not need to be listed in this section, as they s=
hould be=0D
+# specified in the FDF file. For example: Shell binary (Shell_Full.e=
fi), FAT binary (Fat.efi),=0D
+# Logo (Logo.bmp), and etc.=0D
+# There may also be modules listed in this section that are not requ=
ired in the FDF file,=0D
+# When a module listed here is excluded from FDF file, then UEFI-com=
pliant binary will be=0D
+# generated for it, but the binary will not be put into any firmware=
volume.=0D
+#=0D
+##########################################################################=
#########################=0D
+=0D
+[Components]=0D
+ Features/Ext4Pkg/Ext4Dxe/Ext4Dxe.inf=0D
--=20
2.32.0


[Patch v3 2/3] Ext4Pkg: Add Ext4Dxe driver.

Pedro Falcato
 

Adds a UEFI EXT4 filesystem driver that implements the EFI_FILE_PROTOCOL
and EFI_SIMPLE_FILE_SYSTEM_PROTOCOL.

Cc: Leif Lindholm <leif@nuviainc.com>
Cc: Michael D Kinney <michael.d.kinney@intel.com>
Cc: Bret Barkelew <Bret.Barkelew@microsoft.com>

Signed-off-by: Pedro Falcato <pedro.falcato@gmail.com>
---
Features/Ext4Pkg/Ext4Dxe/BlockGroup.c | 228 ++++++
Features/Ext4Pkg/Ext4Dxe/Collation.c | 173 +++++
Features/Ext4Pkg/Ext4Dxe/Crc16.c | 75 ++
Features/Ext4Pkg/Ext4Dxe/Crc32c.c | 84 ++
Features/Ext4Pkg/Ext4Dxe/Directory.c | 498 ++++++++++++
Features/Ext4Pkg/Ext4Dxe/DiskUtil.c | 113 +++
Features/Ext4Pkg/Ext4Dxe/Ext4Disk.h | 453 +++++++++++
Features/Ext4Pkg/Ext4Dxe/Ext4Dxe.c | 808 +++++++++++++++++++
Features/Ext4Pkg/Ext4Dxe/Ext4Dxe.h | 1038 +++++++++++++++++++++++++
Features/Ext4Pkg/Ext4Dxe/Ext4Dxe.inf | 149 ++++
Features/Ext4Pkg/Ext4Dxe/Ext4Dxe.uni | 15 +
Features/Ext4Pkg/Ext4Dxe/Extents.c | 595 ++++++++++++++
Features/Ext4Pkg/Ext4Dxe/File.c | 787 +++++++++++++++++++
Features/Ext4Pkg/Ext4Dxe/Inode.c | 465 +++++++++++
Features/Ext4Pkg/Ext4Dxe/Partition.c | 125 +++
Features/Ext4Pkg/Ext4Dxe/Superblock.c | 297 +++++++
16 files changed, 5903 insertions(+)
create mode 100644 Features/Ext4Pkg/Ext4Dxe/BlockGroup.c
create mode 100644 Features/Ext4Pkg/Ext4Dxe/Collation.c
create mode 100644 Features/Ext4Pkg/Ext4Dxe/Crc16.c
create mode 100644 Features/Ext4Pkg/Ext4Dxe/Crc32c.c
create mode 100644 Features/Ext4Pkg/Ext4Dxe/Directory.c
create mode 100644 Features/Ext4Pkg/Ext4Dxe/DiskUtil.c
create mode 100644 Features/Ext4Pkg/Ext4Dxe/Ext4Disk.h
create mode 100644 Features/Ext4Pkg/Ext4Dxe/Ext4Dxe.c
create mode 100644 Features/Ext4Pkg/Ext4Dxe/Ext4Dxe.h
create mode 100644 Features/Ext4Pkg/Ext4Dxe/Ext4Dxe.inf
create mode 100644 Features/Ext4Pkg/Ext4Dxe/Ext4Dxe.uni
create mode 100644 Features/Ext4Pkg/Ext4Dxe/Extents.c
create mode 100644 Features/Ext4Pkg/Ext4Dxe/File.c
create mode 100644 Features/Ext4Pkg/Ext4Dxe/Inode.c
create mode 100644 Features/Ext4Pkg/Ext4Dxe/Partition.c
create mode 100644 Features/Ext4Pkg/Ext4Dxe/Superblock.c

diff --git a/Features/Ext4Pkg/Ext4Dxe/BlockGroup.c b/Features/Ext4Pkg/Ext4D=
xe/BlockGroup.c
new file mode 100644
index 0000000000..abfeff52b1
--- /dev/null
+++ b/Features/Ext4Pkg/Ext4Dxe/BlockGroup.c
@@ -0,0 +1,228 @@
+/** @file=0D
+ Block group related routines=0D
+=0D
+ Copyright (c) 2021 Pedro Falcato All rights reserved.=0D
+ Copyright (c) 2007 - 2018, Intel Corporation. All rights reserved.<BR>=0D
+=0D
+ SPDX-License-Identifier: BSD-2-Clause-Patent=0D
+**/=0D
+=0D
+#include "Ext4Dxe.h"=0D
+=0D
+/**=0D
+ Retrieves a block group descriptor of the ext4 filesystem.=0D
+=0D
+ @param[in] Partition Pointer to the opened ext4 partition.=0D
+ @param[in] BlockGroup Block group number.=0D
+=0D
+ @return A pointer to the block group descriptor.=0D
+**/=0D
+EXT4_BLOCK_GROUP_DESC *=0D
+Ext4GetBlockGroupDesc (=0D
+ IN EXT4_PARTITION *Partition,=0D
+ IN UINT32 BlockGroup=0D
+ )=0D
+{=0D
+ // Maybe assert that the block group nr isn't a nonsense number?=0D
+ return (EXT4_BLOCK_GROUP_DESC *)((CHAR8 *)Partition->BlockGroups + Block=
Group * Partition->DescSize);=0D
+}=0D
+=0D
+/**=0D
+ Reads an inode from disk.=0D
+=0D
+ @param[in] Partition Pointer to the opened partition.=0D
+ @param[in] InodeNum Number of the desired Inode=0D
+ @param[out] OutIno Pointer to where it will be stored a pointer t=
o the read inode.=0D
+=0D
+ @return Status of the inode read.=0D
+**/=0D
+EFI_STATUS=0D
+Ext4ReadInode (=0D
+ IN EXT4_PARTITION *Partition,=0D
+ IN EXT4_INO_NR InodeNum,=0D
+ OUT EXT4_INODE **OutIno=0D
+ )=0D
+{=0D
+ UINT64 InodeOffset;=0D
+ UINT32 BlockGroupNumber;=0D
+ EXT4_INODE *Inode;=0D
+ EXT4_BLOCK_GROUP_DESC *BlockGroup;=0D
+ EXT4_BLOCK_NR InodeTableStart;=0D
+ EFI_STATUS Status;=0D
+=0D
+ BlockGroupNumber =3D (UINT32)DivU64x64Remainder (=0D
+ InodeNum - 1,=0D
+ Partition->SuperBlock.s_inodes_per_group,=0D
+ &InodeOffset=0D
+ );=0D
+=0D
+ // Check for the block group number's correctness=0D
+ if (BlockGroupNumber >=3D Partition->NumberBlockGroups) {=0D
+ return EFI_VOLUME_CORRUPTED;=0D
+ }=0D
+=0D
+ Inode =3D Ext4AllocateInode (Partition);=0D
+=0D
+ if (Inode =3D=3D NULL) {=0D
+ return EFI_OUT_OF_RESOURCES;=0D
+ }=0D
+=0D
+ BlockGroup =3D Ext4GetBlockGroupDesc (Partition, BlockGroupNumber);=0D
+=0D
+ // Note: We'll need to check INODE_UNINIT and friends when/if we add wri=
te support=0D
+=0D
+ InodeTableStart =3D EXT4_BLOCK_NR_FROM_HALFS (=0D
+ Partition,=0D
+ BlockGroup->bg_inode_table_lo,=0D
+ BlockGroup->bg_inode_table_hi=0D
+ );=0D
+=0D
+ Status =3D Ext4ReadDiskIo (=0D
+ Partition,=0D
+ Inode,=0D
+ Partition->InodeSize,=0D
+ EXT4_BLOCK_TO_BYTES (Partition, InodeTableStart) + MultU64x32=
(InodeOffset, Partition->InodeSize)=0D
+ );=0D
+=0D
+ if (EFI_ERROR (Status)) {=0D
+ DEBUG ((=0D
+ DEBUG_ERROR,=0D
+ "[ext4] Error reading inode: status %x; inode offset %lx"=0D
+ " inode table start %lu block group %lu\n",=0D
+ Status,=0D
+ InodeOffset,=0D
+ InodeTableStart,=0D
+ BlockGroupNumber=0D
+ ));=0D
+ FreePool (Inode);=0D
+ return Status;=0D
+ }=0D
+=0D
+ if (!Ext4CheckInodeChecksum (Partition, Inode, InodeNum)) {=0D
+ DEBUG ((=0D
+ DEBUG_ERROR,=0D
+ "[ext4] Inode %llu has invalid checksum (calculated %x)\n",=0D
+ InodeNum,=0D
+ Ext4CalculateInodeChecksum (Partition, Inode, InodeNum)=0D
+ ));=0D
+ FreePool (Inode);=0D
+ return EFI_VOLUME_CORRUPTED;=0D
+ }=0D
+=0D
+ *OutIno =3D Inode;=0D
+ return EFI_SUCCESS;=0D
+}=0D
+=0D
+/**=0D
+ Calculates the checksum of the block group descriptor for METADATA_CSUM=
enabled filesystems.=0D
+ @param[in] Partition Pointer to the opened EXT4 partition.=0D
+ @param[in] BlockGroupDesc Pointer to the block group descriptor.=
=0D
+ @param[in] BlockGroupNum Number of the block group.=0D
+=0D
+ @return The checksum.=0D
+**/=0D
+STATIC=0D
+UINT16=0D
+Ext4CalculateBlockGroupDescChecksumMetadataCsum (=0D
+ IN CONST EXT4_PARTITION *Partition,=0D
+ IN CONST EXT4_BLOCK_GROUP_DESC *BlockGroupDesc,=0D
+ IN UINT32 BlockGroupNum=0D
+ )=0D
+{=0D
+ UINT32 Csum;=0D
+ UINT16 Dummy;=0D
+=0D
+ Dummy =3D 0;=0D
+=0D
+ Csum =3D Ext4CalculateChecksum (Partition, &BlockGroupNum, sizeof (Block=
GroupNum), Partition->InitialSeed);=0D
+ Csum =3D Ext4CalculateChecksum (Partition, BlockGroupDesc, OFFSET_OF (EX=
T4_BLOCK_GROUP_DESC, bg_checksum), Csum);=0D
+ Csum =3D Ext4CalculateChecksum (Partition, &Dummy, sizeof (Dummy), Csum)=
;=0D
+ Csum =3D=0D
+ Ext4CalculateChecksum (=0D
+ Partition,=0D
+ &BlockGroupDesc->bg_block_bitmap_hi,=0D
+ Partition->DescSize - OFFSET_OF (EXT4_BLOCK_GROUP_DESC, bg_block_bit=
map_hi),=0D
+ Csum=0D
+ );=0D
+ return (UINT16)Csum;=0D
+}=0D
+=0D
+/**=0D
+ Calculates the checksum of the block group descriptor for GDT_CSUM enab=
led filesystems.=0D
+ @param[in] Partition Pointer to the opened EXT4 partition.=0D
+ @param[in] BlockGroupDesc Pointer to the block group descriptor.=
=0D
+ @param[in] BlockGroupNum Number of the block group.=0D
+=0D
+ @return The checksum.=0D
+**/=0D
+STATIC=0D
+UINT16=0D
+Ext4CalculateBlockGroupDescChecksumGdtCsum (=0D
+ IN CONST EXT4_PARTITION *Partition,=0D
+ IN CONST EXT4_BLOCK_GROUP_DESC *BlockGroupDesc,=0D
+ IN UINT32 BlockGroupNum=0D
+ )=0D
+{=0D
+ UINT16 Csum;=0D
+ UINT16 Dummy;=0D
+=0D
+ Dummy =3D 0;=0D
+=0D
+ Csum =3D CalculateCrc16 (Partition->SuperBlock.s_uuid, 16, 0);=0D
+ Csum =3D CalculateCrc16 (&BlockGroupNum, sizeof (BlockGroupNum), Csum);=
=0D
+ Csum =3D CalculateCrc16 (BlockGroupDesc, OFFSET_OF (EXT4_BLOCK_GROUP_DES=
C, bg_checksum), Csum);=0D
+ Csum =3D CalculateCrc16 (&Dummy, sizeof (Dummy), Csum);=0D
+ Csum =3D=0D
+ CalculateCrc16 (=0D
+ &BlockGroupDesc->bg_block_bitmap_hi,=0D
+ Partition->DescSize - OFFSET_OF (EXT4_BLOCK_GROUP_DESC, bg_block_bit=
map_hi),=0D
+ Csum=0D
+ );=0D
+ return Csum;=0D
+}=0D
+=0D
+/**=0D
+ Checks if the checksum of the block group descriptor is correct.=0D
+ @param[in] Partition Pointer to the opened EXT4 partition.=0D
+ @param[in] BlockGroupDesc Pointer to the block group descriptor.=
=0D
+ @param[in] BlockGroupNum Number of the block group.=0D
+=0D
+ @return TRUE if checksum is correct, FALSE if there is corruption.=0D
+**/=0D
+BOOLEAN=0D
+Ext4VerifyBlockGroupDescChecksum (=0D
+ IN CONST EXT4_PARTITION *Partition,=0D
+ IN CONST EXT4_BLOCK_GROUP_DESC *BlockGroupDesc,=0D
+ IN UINT32 BlockGroupNum=0D
+ )=0D
+{=0D
+ if (!EXT4_HAS_METADATA_CSUM (Partition) && !EXT4_HAS_GDT_CSUM (Partition=
)) {=0D
+ return TRUE;=0D
+ }=0D
+=0D
+ return Ext4CalculateBlockGroupDescChecksum (Partition, BlockGroupDesc, B=
lockGroupNum) =3D=3D BlockGroupDesc->bg_checksum;=0D
+}=0D
+=0D
+/**=0D
+ Calculates the checksum of the block group descriptor.=0D
+ @param[in] Partition Pointer to the opened EXT4 partition.=0D
+ @param[in] BlockGroupDesc Pointer to the block group descriptor.=
=0D
+ @param[in] BlockGroupNum Number of the block group.=0D
+=0D
+ @return The checksum.=0D
+**/=0D
+UINT16=0D
+Ext4CalculateBlockGroupDescChecksum (=0D
+ IN CONST EXT4_PARTITION *Partition,=0D
+ IN CONST EXT4_BLOCK_GROUP_DESC *BlockGroupDesc,=0D
+ IN UINT32 BlockGroupNum=0D
+ )=0D
+{=0D
+ if (Partition->FeaturesRoCompat & EXT4_FEATURE_RO_COMPAT_METADATA_CSUM) =
{=0D
+ return Ext4CalculateBlockGroupDescChecksumMetadataCsum (Partition, Blo=
ckGroupDesc, BlockGroupNum);=0D
+ } else if (Partition->FeaturesRoCompat & EXT4_FEATURE_RO_COMPAT_GDT_CSUM=
) {=0D
+ return Ext4CalculateBlockGroupDescChecksumGdtCsum (Partition, BlockGro=
upDesc, BlockGroupNum);=0D
+ }=0D
+=0D
+ return 0;=0D
+}=0D
diff --git a/Features/Ext4Pkg/Ext4Dxe/Collation.c b/Features/Ext4Pkg/Ext4Dx=
e/Collation.c
new file mode 100644
index 0000000000..510ab24ebd
--- /dev/null
+++ b/Features/Ext4Pkg/Ext4Dxe/Collation.c
@@ -0,0 +1,173 @@
+/** @file=0D
+ Unicode collation routines=0D
+=0D
+ Copyright (c) 2021 Pedro Falcato All rights reserved.=0D
+ Copyright (c) 2005 - 2017, Intel Corporation. All rights reserved.=0D
+=0D
+ SPDX-License-Identifier: BSD-2-Clause-Patent=0D
+**/=0D
+=0D
+#include <Uefi.h>=0D
+=0D
+#include <Library/UefiLib.h>=0D
+#include <Library/UefiBootServicesTableLib.h>=0D
+#include <Library/MemoryAllocationLib.h>=0D
+=0D
+#include <Protocol/UnicodeCollation.h>=0D
+=0D
+STATIC EFI_UNICODE_COLLATION_PROTOCOL *gUnicodeCollationInterface =3D NUL=
L;=0D
+=0D
+/*=0D
+ * Note: This code is heavily based on FatPkg's Unicode collation, since t=
hey seem to know what=0D
+ * they're doing.=0D
+ * PS: Maybe all this code could be put in a library? It looks heavily sha=
reable.=0D
+**/=0D
+=0D
+/**=0D
+ Worker function to initialize Unicode Collation support.=0D
+=0D
+ It tries to locate Unicode Collation (2) protocol and matches it with cu=
rrent=0D
+ platform language code.=0D
+=0D
+ @param[in] DriverHandle The handle used to open Unicode Collati=
on (2) protocol.=0D
+ @param[in] ProtocolGuid The pointer to Unicode Collation (2) pr=
otocol GUID.=0D
+ @param[in] VariableName The name of the RFC 4646 or ISO 639-2 l=
anguage variable.=0D
+ @param[in] DefaultLanguage The default language in case the RFC 46=
46 or ISO 639-2 language is absent.=0D
+=0D
+ @retval EFI_SUCCESS The Unicode Collation (2) protocol has been=
successfully located.=0D
+ @retval Others The Unicode Collation (2) protocol has not =
been located.=0D
+=0D
+**/=0D
+STATIC=0D
+EFI_STATUS=0D
+Ext4InitialiseUnicodeCollationInternal (=0D
+ IN EFI_HANDLE DriverHandle,=0D
+ IN EFI_GUID *ProtocolGuid,=0D
+ IN CONST CHAR16 *VariableName,=0D
+ IN CONST CHAR8 *DefaultLanguage=0D
+ )=0D
+{=0D
+ UINTN NumHandles;=0D
+ EFI_HANDLE *Handles;=0D
+ EFI_UNICODE_COLLATION_PROTOCOL *Uci;=0D
+ BOOLEAN Iso639Language;=0D
+ CHAR8 *Language;=0D
+ EFI_STATUS RetStatus;=0D
+ EFI_STATUS Status;=0D
+ UINTN Idx;=0D
+ CHAR8 *BestLanguage;=0D
+=0D
+ Iso639Language =3D (BOOLEAN)(ProtocolGuid =3D=3D &gEfiUnicodeCollationPr=
otocolGuid);=0D
+ RetStatus =3D EFI_UNSUPPORTED;=0D
+ GetEfiGlobalVariable2 (VariableName, (VOID **)&Language, NULL);=0D
+=0D
+ Status =3D gBS->LocateHandleBuffer (=0D
+ ByProtocol,=0D
+ ProtocolGuid,=0D
+ NULL,=0D
+ &NumHandles,=0D
+ &Handles=0D
+ );=0D
+ if (EFI_ERROR (Status)) {=0D
+ return Status;=0D
+ }=0D
+=0D
+ for (Idx =3D 0; Idx < NumHandles; Idx++) {=0D
+ Status =3D gBS->OpenProtocol (=0D
+ Handles[Idx],=0D
+ ProtocolGuid,=0D
+ (VOID **)&Uci,=0D
+ DriverHandle,=0D
+ NULL,=0D
+ EFI_OPEN_PROTOCOL_GET_PROTOCOL=0D
+ );=0D
+=0D
+ if (EFI_ERROR (Status)) {=0D
+ continue;=0D
+ }=0D
+=0D
+ BestLanguage =3D GetBestLanguage (=0D
+ Uci->SupportedLanguages,=0D
+ Iso639Language,=0D
+ (Language =3D=3D NULL) ? "" : Language,=0D
+ DefaultLanguage,=0D
+ NULL=0D
+ );=0D
+ if (BestLanguage !=3D NULL) {=0D
+ FreePool (BestLanguage);=0D
+ gUnicodeCollationInterface =3D Uci;=0D
+ RetStatus =3D EFI_SUCCESS;=0D
+ break;=0D
+ }=0D
+ }=0D
+=0D
+ if (Language !=3D NULL) {=0D
+ FreePool (Language);=0D
+ }=0D
+=0D
+ FreePool (Handles);=0D
+ return RetStatus;=0D
+}=0D
+=0D
+/**=0D
+ Initialises Unicode collation, which is needed for case-insensitive str=
ing comparisons=0D
+ within the driver (a good example of an application of this is filename=
comparison).=0D
+=0D
+ @param[in] DriverHandle Handle to the driver image.=0D
+=0D
+ @retval EFI_SUCCESS Unicode collation was successfully initialised.=0D
+ @retval !EFI_SUCCESS Failure.=0D
+**/=0D
+EFI_STATUS=0D
+Ext4InitialiseUnicodeCollation (=0D
+ EFI_HANDLE DriverHandle=0D
+ )=0D
+{=0D
+ EFI_STATUS Status;=0D
+=0D
+ Status =3D EFI_UNSUPPORTED;=0D
+=0D
+ //=0D
+ // First try to use RFC 4646 Unicode Collation 2 Protocol.=0D
+ //=0D
+ Status =3D Ext4InitialiseUnicodeCollationInternal (=0D
+ DriverHandle,=0D
+ &gEfiUnicodeCollation2ProtocolGuid,=0D
+ L"PlatformLang",=0D
+ (CONST CHAR8 *)PcdGetPtr (PcdUefiVariableDefaultPlatformLang)=
=0D
+ );=0D
+ //=0D
+ // If the attempt to use Unicode Collation 2 Protocol fails, then we fal=
l back=0D
+ // on the ISO 639-2 Unicode Collation Protocol.=0D
+ //=0D
+ if (EFI_ERROR (Status)) {=0D
+ Status =3D Ext4InitialiseUnicodeCollationInternal (=0D
+ DriverHandle,=0D
+ &gEfiUnicodeCollationProtocolGuid,=0D
+ L"Lang",=0D
+ (CONST CHAR8 *)PcdGetPtr (PcdUefiVariableDefaultLang)=0D
+ );=0D
+ }=0D
+=0D
+ return Status;=0D
+}=0D
+=0D
+/**=0D
+ Does a case-insensitive string comparison. Refer to EFI_UNICODE_COLLATI=
ON_PROTOCOL's StriColl=0D
+ for more details.=0D
+=0D
+ @param[in] Str1 Pointer to a null terminated string.=0D
+ @param[in] Str2 Pointer to a null terminated string.=0D
+=0D
+ @retval 0 Str1 is equivalent to Str2.=0D
+ @retval >0 Str1 is lexically greater than Str2.=0D
+ @retval <0 Str1 is lexically less than Str2.=0D
+**/=0D
+INTN=0D
+Ext4StrCmpInsensitive (=0D
+ IN CHAR16 *Str1,=0D
+ IN CHAR16 *Str2=0D
+ )=0D
+{=0D
+ return gUnicodeCollationInterface->StriColl (gUnicodeCollationInterface,=
Str1, Str2);=0D
+}=0D
diff --git a/Features/Ext4Pkg/Ext4Dxe/Crc16.c b/Features/Ext4Pkg/Ext4Dxe/Cr=
c16.c
new file mode 100644
index 0000000000..58d0220e4d
--- /dev/null
+++ b/Features/Ext4Pkg/Ext4Dxe/Crc16.c
@@ -0,0 +1,75 @@
+/** @file=0D
+ CRC16 calculation routines.=0D
+=0D
+ Copyright (c) 2021 Pedro Falcato All rights reserved.=0D
+=0D
+ SPDX-License-Identifier: BSD-2-Clause-Patent=0D
+**/=0D
+=0D
+#include <Uefi.h>=0D
+=0D
+STATIC CONST UINT16 gCrc16LookupTable[256] =3D=0D
+{=0D
+ 0x0000, 0x1189, 0x2312, 0x329b, 0x4624, 0x57ad, 0x6536, 0x74bf,=0D
+ 0x8c48, 0x9dc1, 0xaf5a, 0xbed3, 0xca6c, 0xdbe5, 0xe97e, 0xf8f7,=0D
+ 0x0919, 0x1890, 0x2a0b, 0x3b82, 0x4f3d, 0x5eb4, 0x6c2f, 0x7da6,=0D
+ 0x8551, 0x94d8, 0xa643, 0xb7ca, 0xc375, 0xd2fc, 0xe067, 0xf1ee,=0D
+ 0x1232, 0x03bb, 0x3120, 0x20a9, 0x5416, 0x459f, 0x7704, 0x668d,=0D
+ 0x9e7a, 0x8ff3, 0xbd68, 0xace1, 0xd85e, 0xc9d7, 0xfb4c, 0xeac5,=0D
+ 0x1b2b, 0x0aa2, 0x3839, 0x29b0, 0x5d0f, 0x4c86, 0x7e1d, 0x6f94,=0D
+ 0x9763, 0x86ea, 0xb471, 0xa5f8, 0xd147, 0xc0ce, 0xf255, 0xe3dc,=0D
+ 0x2464, 0x35ed, 0x0776, 0x16ff, 0x6240, 0x73c9, 0x4152, 0x50db,=0D
+ 0xa82c, 0xb9a5, 0x8b3e, 0x9ab7, 0xee08, 0xff81, 0xcd1a, 0xdc93,=0D
+ 0x2d7d, 0x3cf4, 0x0e6f, 0x1fe6, 0x6b59, 0x7ad0, 0x484b, 0x59c2,=0D
+ 0xa135, 0xb0bc, 0x8227, 0x93ae, 0xe711, 0xf698, 0xc403, 0xd58a,=0D
+ 0x3656, 0x27df, 0x1544, 0x04cd, 0x7072, 0x61fb, 0x5360, 0x42e9,=0D
+ 0xba1e, 0xab97, 0x990c, 0x8885, 0xfc3a, 0xedb3, 0xdf28, 0xcea1,=0D
+ 0x3f4f, 0x2ec6, 0x1c5d, 0x0dd4, 0x796b, 0x68e2, 0x5a79, 0x4bf0,=0D
+ 0xb307, 0xa28e, 0x9015, 0x819c, 0xf523, 0xe4aa, 0xd631, 0xc7b8,=0D
+ 0x48c8, 0x5941, 0x6bda, 0x7a53, 0x0eec, 0x1f65, 0x2dfe, 0x3c77,=0D
+ 0xc480, 0xd509, 0xe792, 0xf61b, 0x82a4, 0x932d, 0xa1b6, 0xb03f,=0D
+ 0x41d1, 0x5058, 0x62c3, 0x734a, 0x07f5, 0x167c, 0x24e7, 0x356e,=0D
+ 0xcd99, 0xdc10, 0xee8b, 0xff02, 0x8bbd, 0x9a34, 0xa8af, 0xb926,=0D
+ 0x5afa, 0x4b73, 0x79e8, 0x6861, 0x1cde, 0x0d57, 0x3fcc, 0x2e45,=0D
+ 0xd6b2, 0xc73b, 0xf5a0, 0xe429, 0x9096, 0x811f, 0xb384, 0xa20d,=0D
+ 0x53e3, 0x426a, 0x70f1, 0x6178, 0x15c7, 0x044e, 0x36d5, 0x275c,=0D
+ 0xdfab, 0xce22, 0xfcb9, 0xed30, 0x998f, 0x8806, 0xba9d, 0xab14,=0D
+ 0x6cac, 0x7d25, 0x4fbe, 0x5e37, 0x2a88, 0x3b01, 0x099a, 0x1813,=0D
+ 0xe0e4, 0xf16d, 0xc3f6, 0xd27f, 0xa6c0, 0xb749, 0x85d2, 0x945b,=0D
+ 0x65b5, 0x743c, 0x46a7, 0x572e, 0x2391, 0x3218, 0x0083, 0x110a,=0D
+ 0xe9fd, 0xf874, 0xcaef, 0xdb66, 0xafd9, 0xbe50, 0x8ccb, 0x9d42,=0D
+ 0x7e9e, 0x6f17, 0x5d8c, 0x4c05, 0x38ba, 0x2933, 0x1ba8, 0x0a21,=0D
+ 0xf2d6, 0xe35f, 0xd1c4, 0xc04d, 0xb4f2, 0xa57b, 0x97e0, 0x8669,=0D
+ 0x7787, 0x660e, 0x5495, 0x451c, 0x31a3, 0x202a, 0x12b1, 0x0338,=0D
+ 0xfbcf, 0xea46, 0xd8dd, 0xc954, 0xbdeb, 0xac62, 0x9ef9, 0x8f70=0D
+};=0D
+=0D
+/**=0D
+ Calculates the CRC16 checksum of the given buffer.=0D
+=0D
+ @param[in] Buffer Pointer to the buffer.=0D
+ @param[in] Length Length of the buffer, in bytes.=0D
+ @param[in] InitialValue Initial value of the CRC.=0D
+=0D
+ @return The CRC16 checksum.=0D
+**/=0D
+UINT16=0D
+CalculateCrc16 (=0D
+ IN CONST VOID *Buffer,=0D
+ IN UINTN Length,=0D
+ IN UINT16 InitialValue=0D
+ )=0D
+{=0D
+ CONST UINT8 *Buf;=0D
+ UINT16 Crc;=0D
+=0D
+ Buf =3D Buffer;=0D
+=0D
+ Crc =3D ~InitialValue;=0D
+=0D
+ while (Length-- !=3D 0) {=0D
+ Crc =3D gCrc16LookupTable[(Crc & 0xFF) ^ *(Buf++)] ^ (Crc >> 8);=0D
+ }=0D
+=0D
+ return ~Crc;=0D
+}=0D
diff --git a/Features/Ext4Pkg/Ext4Dxe/Crc32c.c b/Features/Ext4Pkg/Ext4Dxe/C=
rc32c.c
new file mode 100644
index 0000000000..9601316240
--- /dev/null
+++ b/Features/Ext4Pkg/Ext4Dxe/Crc32c.c
@@ -0,0 +1,84 @@
+/** @file=0D
+ CRC32c calculation routines.=0D
+=0D
+ Copyright (c) 2021 Pedro Falcato All rights reserved.=0D
+=0D
+ SPDX-License-Identifier: BSD-2-Clause-Patent=0D
+**/=0D
+=0D
+#include <Uefi.h>=0D
+=0D
+STATIC CONST UINT32 gCrc32cLookupTable[256] =3D {=0D
+ 0x00000000, 0xf26b8303, 0xe13b70f7, 0x1350f3f4, 0xc79a971f, 0x35f1141c,=
=0D
+ 0x26a1e7e8, 0xd4ca64eb, 0x8ad958cf, 0x78b2dbcc, 0x6be22838, 0x9989ab3b,=
=0D
+ 0x4d43cfd0, 0xbf284cd3, 0xac78bf27, 0x5e133c24, 0x105ec76f, 0xe235446c,=
=0D
+ 0xf165b798, 0x030e349b, 0xd7c45070, 0x25afd373, 0x36ff2087, 0xc494a384,=
=0D
+ 0x9a879fa0, 0x68ec1ca3, 0x7bbcef57, 0x89d76c54, 0x5d1d08bf, 0xaf768bbc,=
=0D
+ 0xbc267848, 0x4e4dfb4b, 0x20bd8ede, 0xd2d60ddd, 0xc186fe29, 0x33ed7d2a,=
=0D
+ 0xe72719c1, 0x154c9ac2, 0x061c6936, 0xf477ea35, 0xaa64d611, 0x580f5512,=
=0D
+ 0x4b5fa6e6, 0xb93425e5, 0x6dfe410e, 0x9f95c20d, 0x8cc531f9, 0x7eaeb2fa,=
=0D
+ 0x30e349b1, 0xc288cab2, 0xd1d83946, 0x23b3ba45, 0xf779deae, 0x05125dad,=
=0D
+ 0x1642ae59, 0xe4292d5a, 0xba3a117e, 0x4851927d, 0x5b016189, 0xa96ae28a,=
=0D
+ 0x7da08661, 0x8fcb0562, 0x9c9bf696, 0x6ef07595, 0x417b1dbc, 0xb3109ebf,=
=0D
+ 0xa0406d4b, 0x522bee48, 0x86e18aa3, 0x748a09a0, 0x67dafa54, 0x95b17957,=
=0D
+ 0xcba24573, 0x39c9c670, 0x2a993584, 0xd8f2b687, 0x0c38d26c, 0xfe53516f,=
=0D
+ 0xed03a29b, 0x1f682198, 0x5125dad3, 0xa34e59d0, 0xb01eaa24, 0x42752927,=
=0D
+ 0x96bf4dcc, 0x64d4cecf, 0x77843d3b, 0x85efbe38, 0xdbfc821c, 0x2997011f,=
=0D
+ 0x3ac7f2eb, 0xc8ac71e8, 0x1c661503, 0xee0d9600, 0xfd5d65f4, 0x0f36e6f7,=
=0D
+ 0x61c69362, 0x93ad1061, 0x80fde395, 0x72966096, 0xa65c047d, 0x5437877e,=
=0D
+ 0x4767748a, 0xb50cf789, 0xeb1fcbad, 0x197448ae, 0x0a24bb5a, 0xf84f3859,=
=0D
+ 0x2c855cb2, 0xdeeedfb1, 0xcdbe2c45, 0x3fd5af46, 0x7198540d, 0x83f3d70e,=
=0D
+ 0x90a324fa, 0x62c8a7f9, 0xb602c312, 0x44694011, 0x5739b3e5, 0xa55230e6,=
=0D
+ 0xfb410cc2, 0x092a8fc1, 0x1a7a7c35, 0xe811ff36, 0x3cdb9bdd, 0xceb018de,=
=0D
+ 0xdde0eb2a, 0x2f8b6829, 0x82f63b78, 0x709db87b, 0x63cd4b8f, 0x91a6c88c,=
=0D
+ 0x456cac67, 0xb7072f64, 0xa457dc90, 0x563c5f93, 0x082f63b7, 0xfa44e0b4,=
=0D
+ 0xe9141340, 0x1b7f9043, 0xcfb5f4a8, 0x3dde77ab, 0x2e8e845f, 0xdce5075c,=
=0D
+ 0x92a8fc17, 0x60c37f14, 0x73938ce0, 0x81f80fe3, 0x55326b08, 0xa759e80b,=
=0D
+ 0xb4091bff, 0x466298fc, 0x1871a4d8, 0xea1a27db, 0xf94ad42f, 0x0b21572c,=
=0D
+ 0xdfeb33c7, 0x2d80b0c4, 0x3ed04330, 0xccbbc033, 0xa24bb5a6, 0x502036a5,=
=0D
+ 0x4370c551, 0xb11b4652, 0x65d122b9, 0x97baa1ba, 0x84ea524e, 0x7681d14d,=
=0D
+ 0x2892ed69, 0xdaf96e6a, 0xc9a99d9e, 0x3bc21e9d, 0xef087a76, 0x1d63f975,=
=0D
+ 0x0e330a81, 0xfc588982, 0xb21572c9, 0x407ef1ca, 0x532e023e, 0xa145813d,=
=0D
+ 0x758fe5d6, 0x87e466d5, 0x94b49521, 0x66df1622, 0x38cc2a06, 0xcaa7a905,=
=0D
+ 0xd9f75af1, 0x2b9cd9f2, 0xff56bd19, 0x0d3d3e1a, 0x1e6dcdee, 0xec064eed,=
=0D
+ 0xc38d26c4, 0x31e6a5c7, 0x22b65633, 0xd0ddd530, 0x0417b1db, 0xf67c32d8,=
=0D
+ 0xe52cc12c, 0x1747422f, 0x49547e0b, 0xbb3ffd08, 0xa86f0efc, 0x5a048dff,=
=0D
+ 0x8ecee914, 0x7ca56a17, 0x6ff599e3, 0x9d9e1ae0, 0xd3d3e1ab, 0x21b862a8,=
=0D
+ 0x32e8915c, 0xc083125f, 0x144976b4, 0xe622f5b7, 0xf5720643, 0x07198540,=
=0D
+ 0x590ab964, 0xab613a67, 0xb831c993, 0x4a5a4a90, 0x9e902e7b, 0x6cfbad78,=
=0D
+ 0x7fab5e8c, 0x8dc0dd8f, 0xe330a81a, 0x115b2b19, 0x020bd8ed, 0xf0605bee,=
=0D
+ 0x24aa3f05, 0xd6c1bc06, 0xc5914ff2, 0x37faccf1, 0x69e9f0d5, 0x9b8273d6,=
=0D
+ 0x88d28022, 0x7ab90321, 0xae7367ca, 0x5c18e4c9, 0x4f48173d, 0xbd23943e,=
=0D
+ 0xf36e6f75, 0x0105ec76, 0x12551f82, 0xe03e9c81, 0x34f4f86a, 0xc69f7b69,=
=0D
+ 0xd5cf889d, 0x27a40b9e, 0x79b737ba, 0x8bdcb4b9, 0x988c474d, 0x6ae7c44e,=
=0D
+ 0xbe2da0a5, 0x4c4623a6, 0x5f16d052, 0xad7d5351=0D
+};=0D
+=0D
+/**=0D
+ Calculates the CRC32c checksum of the given buffer.=0D
+=0D
+ @param[in] Buffer Pointer to the buffer.=0D
+ @param[in] Length Length of the buffer, in bytes.=0D
+ @param[in] InitialValue Initial value of the CRC.=0D
+=0D
+ @return The CRC32c checksum.=0D
+**/=0D
+UINT32=0D
+CalculateCrc32c (=0D
+ IN CONST VOID *Buffer,=0D
+ IN UINTN Length,=0D
+ IN UINT32 InitialValue=0D
+ )=0D
+{=0D
+ CONST UINT8 *Buf;=0D
+ UINT32 Crc;=0D
+=0D
+ Buf =3D Buffer;=0D
+ Crc =3D ~InitialValue;=0D
+=0D
+ while (Length-- !=3D 0) {=0D
+ Crc =3D gCrc32cLookupTable[(Crc & 0xFF) ^ *(Buf++)] ^ (Crc >> 8);=0D
+ }=0D
+=0D
+ return ~Crc;=0D
+}=0D
diff --git a/Features/Ext4Pkg/Ext4Dxe/Directory.c b/Features/Ext4Pkg/Ext4Dx=
e/Directory.c
new file mode 100644
index 0000000000..081c6bf0f4
--- /dev/null
+++ b/Features/Ext4Pkg/Ext4Dxe/Directory.c
@@ -0,0 +1,498 @@
+/** @file=0D
+ Directory related routines=0D
+=0D
+ Copyright (c) 2021 Pedro Falcato All rights reserved.=0D
+=0D
+ SPDX-License-Identifier: BSD-2-Clause-Patent=0D
+**/=0D
+=0D
+#include "Ext4Dxe.h"=0D
+=0D
+#include <Library/BaseUcs2Utf8Lib.h>=0D
+=0D
+/**=0D
+ Retrieves the filename of the directory entry and converts it to UTF-16=
/UCS-2=0D
+=0D
+ @param[in] Entry Pointer to a EXT4_DIR_ENTRY.=0D
+ @param[out] Ucs2FileName Pointer to an array of CHAR16's, of siz=
e EXT4_NAME_MAX + 1.=0D
+=0D
+ @retval EFI_SUCCESS The filename was succesfully retrieved and conver=
ted to UCS2.=0D
+ @retval !EFI_SUCCESS Failure.=0D
+**/=0D
+EFI_STATUS=0D
+Ext4GetUcs2DirentName (=0D
+ IN EXT4_DIR_ENTRY *Entry,=0D
+ OUT CHAR16 Ucs2FileName[EXT4_NAME_MAX + 1]=0D
+ )=0D
+{=0D
+ CHAR8 Utf8NameBuf[EXT4_NAME_MAX + 1];=0D
+ UINT16 *Str;=0D
+ EFI_STATUS Status;=0D
+=0D
+ CopyMem (Utf8NameBuf, Entry->name, Entry->name_len);=0D
+=0D
+ Utf8NameBuf[Entry->name_len] =3D '\0';=0D
+=0D
+ // Unfortunately, BaseUcs2Utf8Lib doesn't have a convert-buffer-to-buffe=
r-like=0D
+ // function. Therefore, we need to allocate from the pool (inside UTF8St=
rToUCS2),=0D
+ // copy it to our out buffer (Ucs2FileName) and free.=0D
+=0D
+ Status =3D UTF8StrToUCS2 (Utf8NameBuf, &Str);=0D
+=0D
+ if (EFI_ERROR (Status)) {=0D
+ return Status;=0D
+ }=0D
+=0D
+ Status =3D StrCpyS (Ucs2FileName, EXT4_NAME_MAX + 1, Str);=0D
+=0D
+ FreePool (Str);=0D
+=0D
+ return Status;=0D
+}=0D
+=0D
+/**=0D
+ Retrieves a directory entry.=0D
+=0D
+ @param[in] Directory Pointer to the opened directory.=0D
+ @param[in] NameUnicode Pointer to the UCS-2 formatted filename.=0D
+ @param[in] Partition Pointer to the ext4 partition.=0D
+ @param[out] Result Pointer to the destination directory entry.=
=0D
+=0D
+ @return The result of the operation.=0D
+**/=0D
+EFI_STATUS=0D
+Ext4RetrieveDirent (=0D
+ IN EXT4_FILE *Directory,=0D
+ IN CONST CHAR16 *Name,=0D
+ IN EXT4_PARTITION *Partition,=0D
+ OUT EXT4_DIR_ENTRY *Result=0D
+ )=0D
+{=0D
+ EFI_STATUS Status;=0D
+ CHAR8 *Buf;=0D
+ UINT64 Off;=0D
+ EXT4_INODE *Inode;=0D
+ UINT64 DirInoSize;=0D
+ UINT32 BlockRemainder;=0D
+ UINTN Length;=0D
+ CHAR8 *BufPtr;=0D
+ EXT4_DIR_ENTRY *Entry;=0D
+ UINTN RemainingBlock;=0D
+ CHAR16 DirentUcs2Name[EXT4_NAME_MAX + 1];=0D
+ UINTN ToCopy;=0D
+=0D
+ Status =3D EFI_NOT_FOUND;=0D
+ Buf =3D AllocatePool (Partition->BlockSize);=0D
+=0D
+ if (Buf =3D=3D NULL) {=0D
+ return EFI_OUT_OF_RESOURCES;=0D
+ }=0D
+=0D
+ Off =3D 0;=0D
+=0D
+ Inode =3D Directory->Inode;=0D
+ DirInoSize =3D EXT4_INODE_SIZE (Inode);=0D
+=0D
+ DivU64x32Remainder (DirInoSize, Partition->BlockSize, &BlockRemainder);=
=0D
+ if (BlockRemainder !=3D 0) {=0D
+ // Directory inodes need to have block aligned sizes=0D
+ return EFI_VOLUME_CORRUPTED;=0D
+ }=0D
+=0D
+ while (Off < DirInoSize) {=0D
+ Length =3D Partition->BlockSize;=0D
+=0D
+ Status =3D Ext4Read (Partition, Directory, Buf, Off, &Length);=0D
+=0D
+ if (Status !=3D EFI_SUCCESS) {=0D
+ FreePool (Buf);=0D
+ return Status;=0D
+ }=0D
+=0D
+ for (BufPtr =3D Buf; BufPtr < Buf + Partition->BlockSize; ) {=0D
+ Entry =3D (EXT4_DIR_ENTRY *)BufPtr;=0D
+ if (Entry->rec_len =3D=3D 0) {=0D
+ FreePool (Buf);=0D
+ return EFI_VOLUME_CORRUPTED;=0D
+ }=0D
+=0D
+ RemainingBlock =3D Partition->BlockSize - (BufPtr - Buf);=0D
+=0D
+ if (Entry->name_len > RemainingBlock || Entry->rec_len > RemainingBl=
ock) {=0D
+ // Corrupted filesystem=0D
+ FreePool (Buf);=0D
+ return EFI_VOLUME_CORRUPTED;=0D
+ }=0D
+=0D
+ // Ignore names bigger than our limit.=0D
+=0D
+ /* Note: I think having a limit is sane because:=0D
+ 1) It's nicer to work with.=0D
+ 2) Linux and a number of BSDs also have a filename limit of 255.=0D
+ */=0D
+ if (Entry->name_len > EXT4_NAME_MAX) {=0D
+ continue;=0D
+ }=0D
+=0D
+ // Unused entry=0D
+ if (Entry->inode =3D=3D 0) {=0D
+ BufPtr +=3D Entry->rec_len;=0D
+ continue;=0D
+ }=0D
+=0D
+ Status =3D Ext4GetUcs2DirentName (Entry, DirentUcs2Name);=0D
+=0D
+ /* In theory, this should never fail.=0D
+ * In reality, it's quite possible that it can fail, considering fil=
enames in=0D
+ * Linux (and probably other nixes) are just null-terminated bags of=
bytes, and don't=0D
+ * need to form valid ASCII/UTF-8 sequences.=0D
+ */=0D
+ if (EFI_ERROR (Status)) {=0D
+ // If we error out, skip this entry=0D
+ // I'm not sure if this is correct behaviour, but I don't think th=
ere's a precedent here.=0D
+ BufPtr +=3D Entry->rec_len;=0D
+ continue;=0D
+ }=0D
+=0D
+ if (Entry->name_len =3D=3D StrLen (Name) &&=0D
+ !Ext4StrCmpInsensitive (DirentUcs2Name, (CHAR16 *)Name)) {=0D
+ ToCopy =3D MIN (Entry->rec_len, sizeof (EXT4_DIR_ENTRY));=0D
+=0D
+ CopyMem (Result, Entry, ToCopy);=0D
+ FreePool (Buf);=0D
+ return EFI_SUCCESS;=0D
+ }=0D
+=0D
+ BufPtr +=3D Entry->rec_len;=0D
+ }=0D
+=0D
+ Off +=3D Partition->BlockSize;=0D
+ }=0D
+=0D
+ FreePool (Buf);=0D
+ return EFI_NOT_FOUND;=0D
+}=0D
+=0D
+/**=0D
+ Opens a file using a directory entry.=0D
+=0D
+ @param[in] Partition Pointer to the ext4 partition.=0D
+ @param[in] OpenMode Mode in which the file is supposed to be op=
en.=0D
+ @param[out] OutFile Pointer to the newly opened file.=0D
+ @param[in] Entry Directory entry to be used.=0D
+=0D
+ @retval EFI_STATUS Result of the operation=0D
+**/=0D
+EFI_STATUS=0D
+Ext4OpenDirent (=0D
+ IN EXT4_PARTITION *Partition,=0D
+ IN UINT64 OpenMode,=0D
+ OUT EXT4_FILE **OutFile,=0D
+ IN EXT4_DIR_ENTRY *Entry=0D
+ )=0D
+{=0D
+ EFI_STATUS Status;=0D
+ CHAR16 FileName[EXT4_NAME_MAX + 1];=0D
+ EXT4_FILE *File;=0D
+=0D
+ File =3D AllocateZeroPool (sizeof (EXT4_FILE));=0D
+=0D
+ if (File =3D=3D NULL) {=0D
+ Status =3D EFI_OUT_OF_RESOURCES;=0D
+ goto Error;=0D
+ }=0D
+=0D
+ Status =3D Ext4GetUcs2DirentName (Entry, FileName);=0D
+=0D
+ if (EFI_ERROR (Status)) {=0D
+ goto Error;=0D
+ }=0D
+=0D
+ File->FileName =3D AllocateZeroPool (StrSize (FileName));=0D
+=0D
+ if (!File->FileName) {=0D
+ Status =3D EFI_OUT_OF_RESOURCES;=0D
+ goto Error;=0D
+ }=0D
+=0D
+ Status =3D Ext4InitExtentsMap (File);=0D
+=0D
+ if (EFI_ERROR (Status)) {=0D
+ goto Error;=0D
+ }=0D
+=0D
+ // This should not fail.=0D
+ StrCpyS (File->FileName, ARRAY_SIZE (FileName), FileName);=0D
+=0D
+ File->InodeNum =3D Entry->inode;=0D
+=0D
+ Ext4SetupFile (File, Partition);=0D
+=0D
+ Status =3D Ext4ReadInode (Partition, Entry->inode, &File->Inode);=0D
+=0D
+ if (EFI_ERROR (Status)) {=0D
+ goto Error;=0D
+ }=0D
+=0D
+ *OutFile =3D File;=0D
+=0D
+ InsertTailList (&Partition->OpenFiles, &File->OpenFilesListNode);=0D
+=0D
+ return EFI_SUCCESS;=0D
+=0D
+Error:=0D
+ if (File !=3D NULL) {=0D
+ if (File->FileName !=3D NULL) {=0D
+ FreePool (File->FileName);=0D
+ }=0D
+=0D
+ if (File->ExtentsMap !=3D NULL) {=0D
+ OrderedCollectionUninit (File->ExtentsMap);=0D
+ }=0D
+=0D
+ FreePool (File);=0D
+ }=0D
+=0D
+ return Status;=0D
+}=0D
+=0D
+/**=0D
+ Opens a file.=0D
+=0D
+ @param[in] Directory Pointer to the opened directory.=0D
+ @param[in] Name Pointer to the UCS-2 formatted filename.=0D
+ @param[in] Partition Pointer to the ext4 partition.=0D
+ @param[in] OpenMode Mode in which the file is supposed to be op=
en.=0D
+ @param[out] OutFile Pointer to the newly opened file.=0D
+=0D
+ @return Result of the operation.=0D
+**/=0D
+EFI_STATUS=0D
+Ext4OpenFile (=0D
+ IN EXT4_FILE *Directory,=0D
+ IN CONST CHAR16 *Name,=0D
+ IN EXT4_PARTITION *Partition,=0D
+ IN UINT64 OpenMode,=0D
+ OUT EXT4_FILE **OutFile=0D
+ )=0D
+{=0D
+ EXT4_DIR_ENTRY Entry;=0D
+ EFI_STATUS Status;=0D
+=0D
+ Status =3D Ext4RetrieveDirent (Directory, Name, Partition, &Entry);=0D
+=0D
+ if (EFI_ERROR (Status)) {=0D
+ return Status;=0D
+ }=0D
+=0D
+ // EFI requires us to error out on ".." opens for the root directory=0D
+ if (Entry.inode =3D=3D Directory->InodeNum) {=0D
+ return EFI_NOT_FOUND;=0D
+ }=0D
+=0D
+ return Ext4OpenDirent (Partition, OpenMode, OutFile, &Entry);=0D
+}=0D
+=0D
+/**=0D
+ Open the root directory on a volume.=0D
+=0D
+ @param[in] This A pointer to the volume to open the root directory.=0D
+ @param[out] Root A pointer to the location to return the opened file ha=
ndle for the=0D
+ root directory.=0D
+=0D
+ @retval EFI_SUCCESS The device was opened.=0D
+ @retval EFI_UNSUPPORTED This volume does not support the requested =
file system type.=0D
+ @retval EFI_NO_MEDIA The device has no medium.=0D
+ @retval EFI_DEVICE_ERROR The device reported an error.=0D
+ @retval EFI_VOLUME_CORRUPTED The file system structures are corrupted.=0D
+ @retval EFI_ACCESS_DENIED The service denied access to the file.=0D
+ @retval EFI_OUT_OF_RESOURCES The volume was not opened due to lack of re=
sources.=0D
+ @retval EFI_MEDIA_CHANGED The device has a different medium in it or =
the medium is no=0D
+ longer supported. Any existing file handles=
for this volume are=0D
+ no longer valid. To access the files on the=
new medium, the=0D
+ volume must be reopened with OpenVolume().=
=0D
+=0D
+**/=0D
+EFI_STATUS=0D
+EFIAPI=0D
+Ext4OpenVolume (=0D
+ IN EFI_SIMPLE_FILE_SYSTEM_PROTOCOL *This,=0D
+ OUT EFI_FILE_PROTOCOL **Root=0D
+ )=0D
+{=0D
+ EXT4_INODE *RootInode;=0D
+ EFI_STATUS Status;=0D
+ EXT4_FILE *RootDir;=0D
+=0D
+ // 2 is always the root inode number in ext4=0D
+ Status =3D Ext4ReadInode ((EXT4_PARTITION *)This, 2, &RootInode);=0D
+=0D
+ if (EFI_ERROR (Status)) {=0D
+ DEBUG ((DEBUG_ERROR, "[ext4] Could not open root inode - status %x\n",=
Status));=0D
+ return Status;=0D
+ }=0D
+=0D
+ RootDir =3D AllocateZeroPool (sizeof (EXT4_FILE));=0D
+=0D
+ if (!RootDir) {=0D
+ FreePool (RootInode);=0D
+ return EFI_OUT_OF_RESOURCES;=0D
+ }=0D
+=0D
+ // The filename will be "\"(null terminated of course)=0D
+ RootDir->FileName =3D AllocateZeroPool (2 * sizeof (CHAR16));=0D
+=0D
+ if (!RootDir->FileName) {=0D
+ FreePool (RootDir);=0D
+ FreePool (RootInode);=0D
+ return EFI_OUT_OF_RESOURCES;=0D
+ }=0D
+=0D
+ RootDir->FileName[0] =3D L'\\';=0D
+=0D
+ RootDir->Inode =3D RootInode;=0D
+ RootDir->InodeNum =3D 2;=0D
+=0D
+ Status =3D Ext4InitExtentsMap (RootDir);=0D
+=0D
+ if (EFI_ERROR (Status)) {=0D
+ FreePool (RootDir->FileName);=0D
+ FreePool (RootInode);=0D
+ FreePool (RootDir);=0D
+ return EFI_OUT_OF_RESOURCES;=0D
+ }=0D
+=0D
+ Ext4SetupFile (RootDir, (EXT4_PARTITION *)This);=0D
+ *Root =3D &RootDir->Protocol;=0D
+=0D
+ InsertTailList (&((EXT4_PARTITION *)This)->OpenFiles, &RootDir->OpenFile=
sListNode);=0D
+=0D
+ return EFI_SUCCESS;=0D
+}=0D
+=0D
+/**=0D
+ Validates a directory entry.=0D
+=0D
+ @param[in] Dirent Pointer to the directory entry.=0D
+=0D
+ @retval TRUE Valid directory entry.=0D
+ FALSE Invalid directory entry.=0D
+**/=0D
+STATIC=0D
+BOOLEAN=0D
+Ext4ValidDirent (=0D
+ IN CONST EXT4_DIR_ENTRY *Dirent=0D
+ )=0D
+{=0D
+ UINTN RequiredSize;=0D
+=0D
+ RequiredSize =3D Dirent->name_len + EXT4_MIN_DIR_ENTRY_LEN;=0D
+=0D
+ if (Dirent->rec_len < RequiredSize) {=0D
+ DEBUG ((DEBUG_ERROR, "[ext4] dirent size %lu too small (compared to %l=
u)\n", Dirent->rec_len, RequiredSize));=0D
+ return FALSE;=0D
+ }=0D
+=0D
+ // Dirent sizes need to be 4 byte aligned=0D
+ if (Dirent->rec_len % 4) {=0D
+ return FALSE;=0D
+ }=0D
+=0D
+ return TRUE;=0D
+}=0D
+=0D
+/**=0D
+ Reads a directory entry.=0D
+=0D
+ @param[in] Partition Pointer to the ext4 partition.=0D
+ @param[in] File Pointer to the open directory.=0D
+ @param[out] Buffer Pointer to the output buffer.=0D
+ @param[in] Offset Initial directory position.=0D
+ @param[in out] OutLength Pointer to a UINTN that contains the length=
of the buffer,=0D
+ and the length of the actual EFI_FILE_INFO =
after the call.=0D
+=0D
+ @return Result of the operation.=0D
+**/=0D
+EFI_STATUS=0D
+Ext4ReadDir (=0D
+ IN EXT4_PARTITION *Partition,=0D
+ IN EXT4_FILE *File,=0D
+ OUT VOID *Buffer,=0D
+ IN UINT64 Offset,=0D
+ IN OUT UINTN *OutLength=0D
+ )=0D
+{=0D
+ EXT4_INODE *DirIno;=0D
+ EFI_STATUS Status;=0D
+ UINT64 DirInoSize;=0D
+ UINTN Len;=0D
+ UINT32 BlockRemainder;=0D
+ EXT4_DIR_ENTRY Entry;=0D
+ EXT4_FILE *TempFile;=0D
+=0D
+ DirIno =3D File->Inode;=0D
+ Status =3D EFI_SUCCESS;=0D
+ DirInoSize =3D EXT4_INODE_SIZE (DirIno);=0D
+=0D
+ DivU64x32Remainder (DirInoSize, Partition->BlockSize, &BlockRemainder);=
=0D
+ if (BlockRemainder !=3D 0) {=0D
+ // Directory inodes need to have block aligned sizes=0D
+ return EFI_VOLUME_CORRUPTED;=0D
+ }=0D
+=0D
+ while (TRUE) {=0D
+ TempFile =3D NULL;=0D
+=0D
+ // We (try to) read the maximum size of a directory entry at a time=0D
+ // Note that we don't need to read any padding that may exist after it=
.=0D
+ Len =3D sizeof (Entry);=0D
+ Status =3D Ext4Read (Partition, File, &Entry, Offset, &Len);=0D
+=0D
+ if (EFI_ERROR (Status)) {=0D
+ goto Out;=0D
+ }=0D
+=0D
+ if (Len =3D=3D 0) {=0D
+ *OutLength =3D 0;=0D
+ Status =3D EFI_SUCCESS;=0D
+ goto Out;=0D
+ }=0D
+=0D
+ if (Len < EXT4_MIN_DIR_ENTRY_LEN) {=0D
+ Status =3D EFI_VOLUME_CORRUPTED;=0D
+ goto Out;=0D
+ }=0D
+=0D
+ // Invalid directory entry length=0D
+ if (!Ext4ValidDirent (&Entry)) {=0D
+ DEBUG ((DEBUG_ERROR, "[ext4] Invalid dirent at offset %lu\n", Offset=
));=0D
+ Status =3D EFI_VOLUME_CORRUPTED;=0D
+ goto Out;=0D
+ }=0D
+=0D
+ if (Entry.inode =3D=3D 0) {=0D
+ // When inode =3D 0, it's unused=0D
+ Offset +=3D Entry.rec_len;=0D
+ continue;=0D
+ }=0D
+=0D
+ Status =3D Ext4OpenDirent (Partition, EFI_FILE_MODE_READ, &TempFile, &=
Entry);=0D
+=0D
+ if (EFI_ERROR (Status)) {=0D
+ goto Out;=0D
+ }=0D
+=0D
+ Status =3D Ext4GetFileInfo (TempFile, Buffer, OutLength);=0D
+ if (!EFI_ERROR (Status)) {=0D
+ File->Position =3D Offset + Entry.rec_len;=0D
+ }=0D
+=0D
+ Ext4CloseInternal (TempFile);=0D
+=0D
+ goto Out;=0D
+ }=0D
+=0D
+ Status =3D EFI_SUCCESS;=0D
+Out:=0D
+ return Status;=0D
+}=0D
diff --git a/Features/Ext4Pkg/Ext4Dxe/DiskUtil.c b/Features/Ext4Pkg/Ext4Dxe=
/DiskUtil.c
new file mode 100644
index 0000000000..da81203747
--- /dev/null
+++ b/Features/Ext4Pkg/Ext4Dxe/DiskUtil.c
@@ -0,0 +1,113 @@
+/** @file=0D
+ Disk utilities=0D
+=0D
+ Copyright (c) 2021 Pedro Falcato All rights reserved.=0D
+ SPDX-License-Identifier: BSD-2-Clause-Patent=0D
+**/=0D
+#include "Ext4Dxe.h"=0D
+=0D
+/**=0D
+ Reads from the partition's disk using the DISK_IO protocol.=0D
+=0D
+ @param[in] Partition Pointer to the opened ext4 partition.=0D
+ @param[out] Buffer Pointer to a destination buffer.=0D
+ @param[in] Length Length of the destination buffer.=0D
+ @param[in] Offset Offset, in bytes, of the location to read.=0D
+=0D
+ @return Success status of the disk read.=0D
+**/=0D
+EFI_STATUS=0D
+Ext4ReadDiskIo (=0D
+ IN EXT4_PARTITION *Partition,=0D
+ OUT VOID *Buffer,=0D
+ IN UINTN Length,=0D
+ IN UINT64 Offset=0D
+ )=0D
+{=0D
+ return EXT4_DISK_IO (Partition)->ReadDisk (=0D
+ EXT4_DISK_IO (Partition),=0D
+ EXT4_MEDIA_ID (Partition),=0D
+ Offset,=0D
+ Length,=0D
+ Buffer=0D
+ );=0D
+}=0D
+=0D
+/**=0D
+ Reads blocks from the partition's disk using the DISK_IO protocol.=0D
+=0D
+ @param[in] Partition Pointer to the opened ext4 partition.=0D
+ @param[out] Buffer Pointer to a destination buffer.=0D
+ @param[in] NumberBlocks Length of the read, in filesystem blocks.=0D
+ @param[in] BlockNumber Starting block number.=0D
+=0D
+ @return Success status of the read.=0D
+**/=0D
+EFI_STATUS=0D
+Ext4ReadBlocks (=0D
+ IN EXT4_PARTITION *Partition,=0D
+ OUT VOID *Buffer,=0D
+ IN UINTN NumberBlocks,=0D
+ IN EXT4_BLOCK_NR BlockNumber=0D
+ )=0D
+{=0D
+ UINT64 Offset;=0D
+ UINTN Length;=0D
+=0D
+ Offset =3D MultU64x32 (BlockNumber, Partition->BlockSize);=0D
+ Length =3D NumberBlocks * Partition->BlockSize;=0D
+=0D
+ // Check for overflow on the block -> byte conversions.=0D
+ // Partition->BlockSize is never 0, so we don't need to check for that.=
=0D
+=0D
+ if (Offset > DivU64x32 ((UINT64)- 1, Partition->BlockSize)) {=0D
+ return EFI_INVALID_PARAMETER;=0D
+ }=0D
+=0D
+ if (Length > (UINTN)- 1/Partition->BlockSize) {=0D
+ return EFI_INVALID_PARAMETER;=0D
+ }=0D
+=0D
+ return Ext4ReadDiskIo (Partition, Buffer, Length, Offset);=0D
+}=0D
+=0D
+/**=0D
+ Allocates a buffer and reads blocks from the partition's disk using the=
DISK_IO protocol.=0D
+ This function is deprecated and will be removed in the future.=0D
+=0D
+ @param[in] Partition Pointer to the opened ext4 partition.=0D
+ @param[in] NumberBlocks Length of the read, in filesystem blocks.=0D
+ @param[in] BlockNumber Starting block number.=0D
+=0D
+ @return Buffer allocated by AllocatePool, or NULL if some part of the p=
rocess=0D
+ failed.=0D
+**/=0D
+VOID *=0D
+Ext4AllocAndReadBlocks (=0D
+ IN EXT4_PARTITION *Partition,=0D
+ IN UINTN NumberBlocks,=0D
+ IN EXT4_BLOCK_NR BlockNumber=0D
+ )=0D
+{=0D
+ VOID *Buf;=0D
+ UINTN Length;=0D
+=0D
+ Length =3D NumberBlocks * Partition->BlockSize;=0D
+=0D
+ if (Length > (UINTN)- 1/Partition->BlockSize) {=0D
+ return NULL;=0D
+ }=0D
+=0D
+ Buf =3D AllocatePool (Length);=0D
+=0D
+ if (Buf =3D=3D NULL) {=0D
+ return NULL;=0D
+ }=0D
+=0D
+ if (Ext4ReadBlocks (Partition, Buf, NumberBlocks, BlockNumber) !=3D EFI_=
SUCCESS) {=0D
+ FreePool (Buf);=0D
+ return NULL;=0D
+ }=0D
+=0D
+ return Buf;=0D
+}=0D
diff --git a/Features/Ext4Pkg/Ext4Dxe/Ext4Disk.h b/Features/Ext4Pkg/Ext4Dxe=
/Ext4Disk.h
new file mode 100644
index 0000000000..54a6f8c21e
--- /dev/null
+++ b/Features/Ext4Pkg/Ext4Dxe/Ext4Disk.h
@@ -0,0 +1,453 @@
+/** @file Raw filesystem data structures=0D
+=0D
+ Copyright (c) 2021 Pedro Falcato All rights reserved.=0D
+ SPDX-License-Identifier: BSD-2-Clause-Patent=0D
+=0D
+ Layout of an EXT2/3/4 filesystem:=0D
+ (note: this driver has been developed using=0D
+ https://www.kernel.org/doc/html/latest/filesystems/ext4/index.html as=0D
+ documentation).=0D
+=0D
+ An ext2/3/4 filesystem (here on out referred to as simply an ext4 filesy=
stem,=0D
+ due to the similarities) is composed of various concepts:=0D
+=0D
+ 1) Superblock=0D
+ The superblock is the structure near (1024 bytes offset from the star=
t)=0D
+ the start of the partition, and describes the filesystem in general.=
=0D
+ Here, we get to know the size of the filesystem's blocks, which featu=
res=0D
+ it supports or not, whether it's been cleanly unmounted, how many blo=
cks=0D
+ we have, etc.=0D
+=0D
+ 2) Block groups=0D
+ EXT4 filesystems are divided into block groups, and each block group =
covers=0D
+ s_blocks_per_group(8 * Block Size) blocks. Each block group has an=0D
+ associated block group descriptor; these are present directly after t=
he=0D
+ superblock. Each block group descriptor contains the location of the=
=0D
+ inode table, and the inode and block bitmaps (note these bitmaps are =
only=0D
+ a block long, which gets us the 8 * Block Size formula covered previo=
usly).=0D
+=0D
+ 3) Blocks=0D
+ The ext4 filesystem is divided in blocks, of size s_log_block_size ^ =
1024.=0D
+ Blocks can be allocated using individual block groups's bitmaps. Note=
=0D
+ that block 0 is invalid and its presence on extents/block tables mean=
s=0D
+ it's part of a file hole, and that particular location must be read a=
s=0D
+ a block full of zeros.=0D
+=0D
+ 4) Inodes=0D
+ The ext4 filesystem divides files/directories into inodes (originally=
=0D
+ index nodes). Each file/socket/symlink/directory/etc (here on out ref=
erred=0D
+ to as a file, since there is no distinction under the ext4 filesystem=
) is=0D
+ stored as a /nameless/ inode, that is stored in some block group's in=
ode=0D
+ table. Each inode has s_inode_size size (or GOOD_OLD_INODE_SIZE if it=
's=0D
+ an old filesystem), and holds various metadata about the file. Since =
the=0D
+ largest inode structure right now is ~160 bytes, the rest of the inod=
e=0D
+ contains inline extended attributes. Inodes' data is stored using eit=
her=0D
+ data blocks (under ext2/3) or extents (under ext4).=0D
+=0D
+ 5) Extents=0D
+ Ext4 inodes store data in extents. These let N contiguous logical blo=
cks=0D
+ that are represented by N contiguous physical blocks be represented b=
y a=0D
+ single extent structure, which minimizes filesystem metadata bloat an=
d=0D
+ speeds up block mapping (particularly due to the fact that high-quali=
ty=0D
+ ext4 implementations like linux's try /really/ hard to make the file=
=0D
+ contiguous, so it's common to have files with almost 0 fragmentation)=
.=0D
+ Inodes that use extents store them in a tree, and the top of the tree=
=0D
+ is stored on i_data. The tree's leaves always start with an=0D
+ EXT4_EXTENT_HEADER and contain EXT4_EXTENT_INDEX on eh_depth !=3D 0 a=
nd=0D
+ EXT4_EXTENT on eh_depth =3D 0; these entries are always sorted by log=
ical=0D
+ block.=0D
+=0D
+ 6) Directories=0D
+ Ext4 directories are files that store name -> inode mappings for the=
=0D
+ logical directory; this is where files get their names, which means e=
xt4=0D
+ inodes do not themselves have names, since they can be linked (presen=
t)=0D
+ multiple times with different names. Directories can store entries in=
two=0D
+ different ways:=0D
+ 1) Classical linear directories: They store entries as a mostly-lin=
ked=0D
+ mostly-list of EXT4_DIR_ENTRY.=0D
+ 2) Hash tree directories: These are used for larger directories, wi=
th=0D
+ hundreds of entries, and are designed in a backwards compatible =
way.=0D
+ These are not yet implemented in the Ext4Dxe driver.=0D
+=0D
+ 7) Journal=0D
+ Ext3/4 filesystems have a journal to help protect the filesystem agai=
nst=0D
+ system crashes. This is not yet implemented in Ext4Dxe but is describ=
ed=0D
+ in detail in the Linux kernel's documentation.=0D
+**/=0D
+=0D
+#ifndef EXT4_DISK_H_=0D
+#define EXT4_DISK_H_=0D
+=0D
+#include <Uefi.h>=0D
+=0D
+#define EXT4_SUPERBLOCK_OFFSET 1024U=0D
+=0D
+#define EXT4_SIGNATURE 0xEF53U=0D
+=0D
+#define EXT4_FS_STATE_UNMOUNTED 0x1=0D
+#define EXT4_FS_STATE_ERRORS_DETECTED 0x2=0D
+#define EXT4_FS_STATE_RECOVERING_ORPHANS 0x4=0D
+=0D
+#define EXT4_ERRORS_CONTINUE 1=0D
+#define EXT4_ERRORS_RO 2=0D
+#define EXT4_ERRORS_PANIC 3=0D
+=0D
+#define EXT4_LINUX_ID 0=0D
+#define EXT4_GNU_HURD_ID 1=0D
+#define EXT4_MASIX_ID 2=0D
+#define EXT4_FREEBSD_ID 3=0D
+#define EXT4_LITES_ID 4=0D
+=0D
+#define EXT4_GOOD_OLD_REV 0=0D
+#define EXT4_DYNAMIC_REV 1=0D
+=0D
+#define EXT4_CHECKSUM_CRC32C 0x1=0D
+=0D
+#define EXT4_FEATURE_COMPAT_DIR_PREALLOC 0x01=0D
+#define EXT4_FEATURE_COMPAT_IMAGIC_INODES 0x02=0D
+#define EXT3_FEATURE_COMPAT_HAS_JOURNAL 0x04=0D
+#define EXT4_FEATURE_COMPAT_EXT_ATTR 0x08=0D
+#define EXT4_FEATURE_COMPAT_RESIZE_INO 0x10=0D
+#define EXT4_FEATURE_COMPAT_DIR_INDEX 0x20=0D
+=0D
+#define EXT4_FEATURE_INCOMPAT_COMPRESSION 0x00001=0D
+#define EXT4_FEATURE_INCOMPAT_FILETYPE 0x00002=0D
+#define EXT4_FEATURE_INCOMPAT_RECOVER 0x00004=0D
+#define EXT4_FEATURE_INCOMPAT_JOURNAL_DEV 0x00008=0D
+#define EXT4_FEATURE_INCOMPAT_META_BG 0x00010=0D
+#define EXT4_FEATURE_INCOMPAT_EXTENTS 0x00040=0D
+#define EXT4_FEATURE_INCOMPAT_64BIT 0x00080=0D
+#define EXT4_FEATURE_INCOMPAT_MMP 0x00100=0D
+#define EXT4_FEATURE_INCOMPAT_FLEX_BG 0x00200=0D
+#define EXT4_FEATURE_INCOMPAT_EA_INODE 0x00400=0D
+// It's not clear whether or not this feature (below) is used right now=0D
+#define EXT4_FEATURE_INCOMPAT_DIRDATA 0x01000=0D
+#define EXT4_FEATURE_INCOMPAT_CSUM_SEED 0x02000=0D
+#define EXT4_FEATURE_INCOMPAT_LARGEDIR 0x04000=0D
+#define EXT4_FEATURE_INCOMPAT_INLINE_DATA 0x08000=0D
+#define EXT4_FEATURE_INCOMPAT_ENCRYPT 0x10000=0D
+=0D
+#define EXT4_FEATURE_RO_COMPAT_SPARSE_SUPER 0x0001=0D
+#define EXT4_FEATURE_RO_COMPAT_LARGE_FILE 0x0002=0D
+#define EXT4_FEATURE_RO_COMPAT_BTREE_DIR 0x0004 // Unused=0D
+#define EXT4_FEATURE_RO_COMPAT_HUGE_FILE 0x0008=0D
+#define EXT4_FEATURE_RO_COMPAT_GDT_CSUM 0x0010=0D
+#define EXT4_FEATURE_RO_COMPAT_DIR_NLINK 0x0020=0D
+#define EXT4_FEATURE_RO_COMPAT_EXTRA_ISIZE 0x0040=0D
+#define EXT4_FEATURE_RO_COMPAT_HAS_SNAPSHOT 0x0080 // Not implemente=
d in ext4=0D
+#define EXT4_FEATURE_RO_COMPAT_QUOTA 0x0100=0D
+#define EXT4_FEATURE_RO_COMPAT_BIGALLOC 0x0200=0D
+#define EXT4_FEATURE_RO_COMPAT_METADATA_CSUM 0x0400=0D
+#define EXT4_FEATURE_RO_COMPAT_REPLICA 0x0800 // Not used=0D
+=0D
+// We explicitly don't recognise this, so we get read only.=0D
+#define EXT4_FEATURE_RO_COMPAT_READONLY 0x1000=0D
+#define EXT4_FEATURE_RO_COMPAT_PROJECT 0x2000=0D
+=0D
+/* Important notes about the features=0D
+ * Absolutely needed features:=0D
+ * 1) Every incompat, because we might want to mount root filesystems=0D
+ * 2) Relevant RO_COMPATs(I'm not sure of what to do wrt quota, project=
)=0D
+**/=0D
+=0D
+#define EXT4_INO_TYPE_FIFO 0x1000=0D
+#define EXT4_INO_TYPE_CHARDEV 0x2000=0D
+#define EXT4_INO_TYPE_DIR 0x4000=0D
+#define EXT4_INO_TYPE_BLOCKDEV 0x6000=0D
+#define EXT4_INO_TYPE_REGFILE 0x8000=0D
+#define EXT4_INO_TYPE_SYMLINK 0xA000=0D
+#define EXT4_INO_TYPE_UNIX_SOCK 0xC000=0D
+=0D
+/* Inode flags */=0D
+#define EXT4_SECRM_FL 0x00000001=0D
+#define EXT4_UNRM_FL 0x00000002=0D
+#define EXT4_COMPR_FL 0x00000004=0D
+#define EXT4_SYNC_FL 0x00000008=0D
+#define EXT4_IMMUTABLE_FL 0x00000010=0D
+#define EXT4_APPEND_FL 0x00000020=0D
+#define EXT4_NODUMP_FL 0x00000040=0D
+#define EXT4_NOATIME_FL 0x00000080=0D
+#define EXT4_DIRTY_FL 0x00000100=0D
+#define EXT4_COMPRBLK_FL 0x00000200=0D
+#define EXT4_NOCOMPR_FL 0x00000400=0D
+#define EXT4_ECOMPR_FL 0x00000800=0D
+#define EXT4_BTREE_FL 0x00001000=0D
+#define EXT4_INDEX_FL 0x00002000=0D
+#define EXT4_JOURNAL_DATA_FL 0x00004000=0D
+#define EXT4_NOTAIL_FL 0x00008000=0D
+#define EXT4_DIRSYNC_FL 0x00010000=0D
+#define EXT4_TOPDIR_FL 0x00020000=0D
+#define EXT4_HUGE_FILE_FL 0x00040000=0D
+#define EXT4_EXTENTS_FL 0x00080000=0D
+#define EXT4_VERITY_FL 0x00100000=0D
+#define EXT4_EA_INODE_FL 0x00200000=0D
+#define EXT4_RESERVED_FL 0x80000000=0D
+=0D
+/* File type flags that are stored in the directory entries */=0D
+#define EXT4_FT_UNKNOWN 0=0D
+#define EXT4_FT_REG_FILE 1=0D
+#define EXT4_FT_DIR 2=0D
+#define EXT4_FT_CHRDEV 3=0D
+#define EXT4_FT_BLKDEV 4=0D
+#define EXT4_FT_FIFO 5=0D
+#define EXT4_FT_SOCK 6=0D
+#define EXT4_FT_SYMLINK 7=0D
+=0D
+typedef struct {=0D
+ UINT32 s_inodes_count;=0D
+ UINT32 s_blocks_count;=0D
+ UINT32 s_r_blocks_count;=0D
+ UINT32 s_free_blocks_count;=0D
+ UINT32 s_free_inodes_count;=0D
+ UINT32 s_first_data_block;=0D
+ UINT32 s_log_block_size;=0D
+ UINT32 s_log_frag_size;=0D
+ UINT32 s_blocks_per_group;=0D
+ UINT32 s_frags_per_group;=0D
+ UINT32 s_inodes_per_group;=0D
+ UINT32 s_mtime;=0D
+ UINT32 s_wtime;=0D
+ UINT16 s_mnt_count;=0D
+ UINT16 s_max_mnt_count;=0D
+ UINT16 s_magic;=0D
+ UINT16 s_state;=0D
+ UINT16 s_errors;=0D
+ UINT16 s_minor_rev_level;=0D
+ UINT32 s_lastcheck;=0D
+ UINT32 s_check_interval;=0D
+ UINT32 s_creator_os;=0D
+ UINT32 s_rev_level;=0D
+ UINT16 s_def_resuid;=0D
+ UINT16 s_def_resgid;=0D
+=0D
+ /* Every field after this comment is revision >=3D 1 */=0D
+=0D
+ UINT32 s_first_ino;=0D
+ UINT16 s_inode_size;=0D
+ UINT16 s_block_group_nr;=0D
+ UINT32 s_feature_compat;=0D
+ UINT32 s_feature_incompat;=0D
+ UINT32 s_feature_ro_compat;=0D
+ UINT8 s_uuid[16];=0D
+ UINT8 s_volume_name[16];=0D
+ UINT8 s_last_mounted[64];=0D
+ UINT32 s_algo_bitmap;=0D
+ UINT8 s_prealloc_blocks;=0D
+ UINT8 s_prealloc_dir_blocks;=0D
+ UINT16 unused;=0D
+ UINT8 s_journal_uuid[16];=0D
+ UINT32 s_journal_inum;=0D
+ UINT32 s_journal_dev;=0D
+ UINT32 s_last_orphan;=0D
+ UINT32 s_hash_seed[4];=0D
+ UINT8 s_def_hash_version;=0D
+ UINT8 s_jnl_backup_type;=0D
+ UINT16 s_desc_size;=0D
+ UINT32 s_default_mount_options;=0D
+ UINT32 s_first_meta_bg;=0D
+ UINT32 s_mkfs_time;=0D
+ UINT32 s_jnl_blocks[17];=0D
+ UINT32 s_blocks_count_hi;=0D
+ UINT32 s_r_blocks_count_hi;=0D
+ UINT32 s_free_blocks_count_hi;=0D
+ UINT16 s_min_extra_isize;=0D
+ UINT16 s_want_extra_isize;=0D
+ UINT32 s_flags;=0D
+ UINT16 s_raid_stride;=0D
+ UINT16 s_mmp_interval;=0D
+ UINT64 s_mmp_block;=0D
+ UINT32 s_raid_stride_width;=0D
+ UINT8 s_log_groups_per_flex;=0D
+ UINT8 s_checksum_type; // Only valid value is 1 - CRC32C=0D
+ UINT16 s_reserved_pad;=0D
+ UINT64 s_kbytes_written;=0D
+=0D
+ // Snapshot stuff isn't used in Linux and isn't implemented here=0D
+ UINT32 s_snapshot_inum;=0D
+ UINT32 s_snapshot_id;=0D
+ UINT64 s_snapshot_r_blocks_count;=0D
+ UINT32 s_snapshot_list;=0D
+ UINT32 s_error_count;=0D
+ UINT32 s_first_error_time;=0D
+ UINT32 s_first_error_ino;=0D
+ UINT64 s_first_error_block;=0D
+ UINT8 s_first_error_func[32];=0D
+ UINT32 s_first_error_line;=0D
+ UINT32 s_last_error_time;=0D
+ UINT32 s_last_error_ino;=0D
+ UINT32 s_last_error_line;=0D
+ UINT64 s_last_error_block;=0D
+ UINT8 s_last_error_func[32];=0D
+ UINT8 s_mount_opts[64];=0D
+ UINT32 s_usr_quota_inum;=0D
+ UINT32 s_grp_quota_inum;=0D
+ UINT32 s_overhead_blocks;=0D
+ UINT32 s_backup_bgs[2]; // sparse_super2=0D
+ UINT8 s_encrypt_algos[4];=0D
+ UINT8 s_encrypt_pw_salt[16];=0D
+ UINT32 s_lpf_ino;=0D
+ UINT32 s_prj_quota_inum;=0D
+ UINT32 s_checksum_seed;=0D
+ UINT32 s_reserved[98];=0D
+ UINT32 s_checksum;=0D
+} EXT4_SUPERBLOCK;=0D
+=0D
+STATIC_ASSERT (sizeof (EXT4_SUPERBLOCK) =3D=3D 1024, "ext4 superblock stru=
ct has incorrect size");=0D
+=0D
+typedef struct {=0D
+ UINT32 bg_block_bitmap_lo;=0D
+ UINT32 bg_inode_bitmap_lo;=0D
+ UINT32 bg_inode_table_lo;=0D
+ UINT16 bg_free_blocks_count_lo;=0D
+ UINT16 bg_free_inodes_count_lo;=0D
+ UINT16 bg_used_dirs_count_lo;=0D
+ UINT16 bg_flags;=0D
+ UINT32 bg_exclude_bitmap_lo;=0D
+ UINT16 bg_block_bitmap_csum_lo;=0D
+ UINT16 bg_inode_bitmap_csum_lo;=0D
+ UINT16 bg_itable_unused_lo;=0D
+ UINT16 bg_checksum;=0D
+ UINT32 bg_block_bitmap_hi;=0D
+ UINT32 bg_inode_bitmap_hi;=0D
+ UINT32 bg_inode_table_hi;=0D
+ UINT16 bg_free_blocks_count_hi;=0D
+ UINT16 bg_free_inodes_count_hi;=0D
+ UINT16 bg_used_dirs_count_hi;=0D
+ UINT16 bg_itable_unused_hi;=0D
+ UINT32 bg_exclude_bitmap_hi;=0D
+ UINT16 bg_block_bitmap_csum_hi;=0D
+ UINT16 bg_inode_bitmap_csum_hi;=0D
+ UINT32 bg_reserved;=0D
+} EXT4_BLOCK_GROUP_DESC;=0D
+=0D
+#define EXT4_OLD_BLOCK_DESC_SIZE 32=0D
+#define EXT4_64BIT_BLOCK_DESC_SIZE 64=0D
+=0D
+STATIC_ASSERT (=0D
+ sizeof (EXT4_BLOCK_GROUP_DESC) =3D=3D EXT4_64BIT_BLOCK_DESC_SIZE,=0D
+ "ext4 block group descriptor struct has incorrect size"=0D
+ );=0D
+=0D
+#define EXT4_DBLOCKS 12=0D
+#define EXT4_IND_BLOCK 12=0D
+#define EXT4_DIND_BLOCK 13=0D
+#define EXT4_TIND_BLOCK 14=0D
+#define EXT4_NR_BLOCKS 15=0D
+=0D
+#define EXT4_GOOD_OLD_INODE_SIZE 128=0D
+=0D
+typedef struct _Ext4_I_OSD2_Linux {=0D
+ UINT16 l_i_blocks_high;=0D
+ UINT16 l_i_file_acl_high;=0D
+ UINT16 l_i_uid_high;=0D
+ UINT16 l_i_gid_high;=0D
+ UINT16 l_i_checksum_lo;=0D
+ UINT16 l_i_reserved;=0D
+} EXT4_OSD2_LINUX;=0D
+=0D
+typedef struct _Ext4_I_OSD2_Hurd {=0D
+ UINT16 h_i_reserved1;=0D
+ UINT16 h_i_mode_high;=0D
+ UINT16 h_i_uid_high;=0D
+ UINT16 h_i_gid_high;=0D
+ UINT32 h_i_author;=0D
+} EXT4_OSD2_HURD;=0D
+=0D
+typedef union {=0D
+ // Note: Toolchain-specific defines (such as "linux") stops us from usin=
g simpler names down here.=0D
+ EXT4_OSD2_LINUX data_linux;=0D
+ EXT4_OSD2_HURD data_hurd;=0D
+} EXT4_OSD2;=0D
+=0D
+typedef struct _Ext4Inode {=0D
+ UINT16 i_mode;=0D
+ UINT16 i_uid;=0D
+ UINT32 i_size_lo;=0D
+ UINT32 i_atime;=0D
+ UINT32 i_ctime;=0D
+ UINT32 i_mtime;=0D
+ UINT32 i_dtime;=0D
+ UINT16 i_gid;=0D
+ UINT16 i_links;=0D
+ UINT32 i_blocks;=0D
+ UINT32 i_flags;=0D
+ UINT32 i_os_spec;=0D
+ UINT32 i_data[EXT4_NR_BLOCKS];=0D
+ UINT32 i_generation;=0D
+ UINT32 i_file_acl;=0D
+ UINT32 i_size_hi;=0D
+ UINT32 i_faddr;=0D
+=0D
+ EXT4_OSD2 i_osd2;=0D
+=0D
+ UINT16 i_extra_isize;=0D
+ UINT16 i_checksum_hi;=0D
+ UINT32 i_ctime_extra;=0D
+ UINT32 i_mtime_extra;=0D
+ UINT32 i_atime_extra;=0D
+ UINT32 i_crtime;=0D
+ UINT32 i_crtime_extra;=0D
+ UINT32 i_version_hi;=0D
+ UINT32 i_projid;=0D
+} EXT4_INODE;=0D
+=0D
+typedef struct {=0D
+ UINT32 inode;=0D
+ UINT16 rec_len;=0D
+ UINT8 name_len;=0D
+ UINT8 file_type;=0D
+ CHAR8 name[255];=0D
+} EXT4_DIR_ENTRY;=0D
+=0D
+#define EXT4_MIN_DIR_ENTRY_LEN 8=0D
+=0D
+// This on-disk structure is present at the bottom of the extent tree=0D
+typedef struct {=0D
+ // First logical block=0D
+ UINT32 ee_block;=0D
+ // Length of the extent, in blocks=0D
+ UINT16 ee_len;=0D
+ // The physical (filesystem-relative) block is split between the high 16=
bits=0D
+ // and the low 32 bits - this forms a 48-bit block number=0D
+ UINT16 ee_start_hi;=0D
+ UINT32 ee_start_lo;=0D
+} EXT4_EXTENT;=0D
+=0D
+// This on-disk structure is present at all levels except the bottom=0D
+typedef struct {=0D
+ // This index covers logical blocks from 'ei_block'=0D
+ UINT32 ei_block;=0D
+ // Block of the next level of the extent tree, similarly split in a high=
and low portion.=0D
+ UINT32 ei_leaf_lo;=0D
+ UINT16 ei_leaf_hi;=0D
+=0D
+ UINT16 ei_unused;=0D
+} EXT4_EXTENT_INDEX;=0D
+=0D
+typedef struct {=0D
+ // Needs to be EXT4_EXTENT_HEADER_MAGIC=0D
+ UINT16 eh_magic;=0D
+ // Number of entries=0D
+ UINT16 eh_entries;=0D
+ // Maximum number of entries that could follow this header=0D
+ UINT16 eh_max;=0D
+ // Depth of this node in the tree - the tree can be at most 5 levels dee=
p=0D
+ UINT16 eh_depth;=0D
+ // Unused by standard ext4=0D
+ UINT32 eh_generation;=0D
+} EXT4_EXTENT_HEADER;=0D
+=0D
+#define EXT4_EXTENT_HEADER_MAGIC 0xF30A=0D
+=0D
+// Specified by ext4 docs and backed by a bunch of math=0D
+#define EXT4_EXTENT_TREE_MAX_DEPTH 5=0D
+=0D
+typedef struct {=0D
+ // CRC32C of UUID + inode number + igeneration + extent block=0D
+ UINT32 eb_checksum;=0D
+} EXT4_EXTENT_TAIL;=0D
+=0D
+typedef UINT64 EXT4_BLOCK_NR;=0D
+typedef UINT32 EXT4_INO_NR;=0D
+=0D
+#endif=0D
diff --git a/Features/Ext4Pkg/Ext4Dxe/Ext4Dxe.c b/Features/Ext4Pkg/Ext4Dxe/=
Ext4Dxe.c
new file mode 100644
index 0000000000..71360ea894
--- /dev/null
+++ b/Features/Ext4Pkg/Ext4Dxe/Ext4Dxe.c
@@ -0,0 +1,808 @@
+/** @file=0D
+ Driver entry point=0D
+=0D
+ Copyright (c) 2021 Pedro Falcato All rights reserved.=0D
+ SPDX-License-Identifier: BSD-2-Clause-Patent=0D
+**/=0D
+=0D
+#include "Ext4Dxe.h"=0D
+#include "Uefi/UefiBaseType.h"=0D
+=0D
+GLOBAL_REMOVE_IF_UNREFERENCED EFI_UNICODE_STRING_TABLE mExt4DriverNameTab=
le[] =3D {=0D
+ {=0D
+ "eng;en",=0D
+ L"Ext4 File System Driver"=0D
+ },=0D
+ {=0D
+ NULL,=0D
+ NULL=0D
+ }=0D
+};=0D
+=0D
+GLOBAL_REMOVE_IF_UNREFERENCED EFI_UNICODE_STRING_TABLE mExt4ControllerNam=
eTable[] =3D {=0D
+ {=0D
+ "eng;en",=0D
+ L"Ext4 File System"=0D
+ },=0D
+ {=0D
+ NULL,=0D
+ NULL=0D
+ }=0D
+};=0D
+=0D
+// Needed by gExt4ComponentName*=0D
+=0D
+/**=0D
+ Retrieves a Unicode string that is the user-readable name of the EFI Dri=
ver.=0D
+=0D
+ @param[in] This A pointer to the EFI_COMPONENT_NAME_PROTOCOL inst=
ance.=0D
+ @param[in] Language A pointer to a three-character ISO 639-2 language=
identifier.=0D
+ This is the language of the driver name that that the=
caller=0D
+ is requesting, and it must match one of the languages=
specified=0D
+ in SupportedLanguages. The number of languages suppo=
rted by a=0D
+ driver is up to the driver writer.=0D
+ @param[out] DriverName A pointer to the Unicode string to return. This=
Unicode string=0D
+ is the name of the driver specified by This in the la=
nguage=0D
+ specified by Language.=0D
+=0D
+ @retval EFI_SUCCESS The Unicode string for the Driver specifie=
d by This=0D
+ and the language specified by Language was=
returned=0D
+ in DriverName.=0D
+ @retval EFI_INVALID_PARAMETER Language is NULL.=0D
+ @retval EFI_INVALID_PARAMETER DriverName is NULL.=0D
+ @retval EFI_UNSUPPORTED The driver specified by This does not supp=
ort the=0D
+ language specified by Language.=0D
+=0D
+**/=0D
+EFI_STATUS=0D
+EFIAPI=0D
+Ext4ComponentNameGetDriverName (=0D
+ IN EFI_COMPONENT_NAME_PROTOCOL *This,=0D
+ IN CHAR8 *Language,=0D
+ OUT CHAR16 **DriverName=0D
+ );=0D
+=0D
+/**=0D
+ Retrieves a Unicode string that is the user readable name of the control=
ler=0D
+ that is being managed by an EFI Driver.=0D
+=0D
+ @param[in] This A pointer to the EFI_COMPONENT_NAME_PROTOCO=
L instance.=0D
+ @param[in] ControllerHandle The handle of a controller that the driver =
specified by=0D
+ This is managing. This handle specifies th=
e controller=0D
+ whose name is to be returned.=0D
+ @param[in] ChildHandle The handle of the child controller to retri=
eve the name=0D
+ of. This is an optional parameter that may=
be NULL. It=0D
+ will be NULL for device drivers. It will a=
lso be NULL=0D
+ for a bus drivers that wish to retrieve the=
name of the=0D
+ bus controller. It will not be NULL for a =
bus driver=0D
+ that wishes to retrieve the name of a child=
controller.=0D
+ @param[in] Language A pointer to a three character ISO 639-2 la=
nguage=0D
+ identifier. This is the language of the co=
ntroller name=0D
+ that the caller is requesting, and it must =
match one=0D
+ of the languages specified in SupportedLang=
uages. The=0D
+ number of languages supported by a driver i=
s up to the=0D
+ driver writer.=0D
+ @param[out] ControllerName A pointer to the Unicode string to return. =
This Unicode=0D
+ string is the name of the controller specif=
ied by=0D
+ ControllerHandle and ChildHandle in the lan=
guage specified=0D
+ by Language, from the point of view of the =
driver specified=0D
+ by This.=0D
+=0D
+ @retval EFI_SUCCESS The Unicode string for the user-readable n=
ame in the=0D
+ language specified by Language for the dri=
ver=0D
+ specified by This was returned in DriverNa=
me.=0D
+ @retval EFI_INVALID_PARAMETER ControllerHandle is NULL.=0D
+ @retval EFI_INVALID_PARAMETER ChildHandle is not NULL and it is not a va=
lid EFI_HANDLE.=0D
+ @retval EFI_INVALID_PARAMETER Language is NULL.=0D
+ @retval EFI_INVALID_PARAMETER ControllerName is NULL.=0D
+ @retval EFI_UNSUPPORTED The driver specified by This is not curren=
tly managing=0D
+ the controller specified by ControllerHand=
le and=0D
+ ChildHandle.=0D
+ @retval EFI_UNSUPPORTED The driver specified by This does not supp=
ort the=0D
+ language specified by Language.=0D
+=0D
+**/=0D
+EFI_STATUS=0D
+EFIAPI=0D
+Ext4ComponentNameGetControllerName (=0D
+ IN EFI_COMPONENT_NAME_PROTOCOL *This,=
=0D
+ IN EFI_HANDLE Control=
lerHandle,=0D
+ IN EFI_HANDLE ChildHandle OPTIONA=
L,=0D
+ IN CHAR8 *Langua=
ge,=0D
+ OUT CHAR16 **Contr=
ollerName=0D
+ );=0D
+=0D
+extern EFI_COMPONENT_NAME_PROTOCOL gExt4ComponentName;=0D
+=0D
+GLOBAL_REMOVE_IF_UNREFERENCED EFI_COMPONENT_NAME_PROTOCOL gExt4ComponentN=
ame =3D {=0D
+ Ext4ComponentNameGetDriverName,=0D
+ Ext4ComponentNameGetControllerName,=0D
+ "eng"=0D
+};=0D
+=0D
+//=0D
+// EFI Component Name 2 Protocol=0D
+//=0D
+GLOBAL_REMOVE_IF_UNREFERENCED EFI_COMPONENT_NAME2_PROTOCOL gExt4Component=
Name2 =3D {=0D
+ (EFI_COMPONENT_NAME2_GET_DRIVER_NAME)Ext4ComponentNameGetDriverName,=0D
+ (EFI_COMPONENT_NAME2_GET_CONTROLLER_NAME)Ext4ComponentNameGetControllerN=
ame,=0D
+ "en"=0D
+};=0D
+=0D
+// Needed by gExt4BindingProtocol=0D
+=0D
+/**=0D
+ Tests to see if this driver supports a given controller. If a child devi=
ce is provided,=0D
+ it further tests to see if this driver supports creating a handle for th=
e specified child device.=0D
+=0D
+ This function checks to see if the driver specified by This supports the=
device specified by=0D
+ ControllerHandle. Drivers will typically use the device path attached to=
=0D
+ ControllerHandle and/or the services from the bus I/O abstraction attach=
ed to=0D
+ ControllerHandle to determine if the driver supports ControllerHandle. T=
his function=0D
+ may be called many times during platform initialization. In order to red=
uce boot times, the tests=0D
+ performed by this function must be very small, and take as little time a=
s possible to execute. This=0D
+ function must not change the state of any hardware devices, and this fun=
ction must be aware that the=0D
+ device specified by ControllerHandle may already be managed by the same =
driver or a=0D
+ different driver. This function must match its calls to AllocatePages() =
with FreePages(),=0D
+ AllocatePool() with FreePool(), and OpenProtocol() with CloseProtocol().=
=0D
+ Because ControllerHandle may have been previously started by the same dr=
iver, if a protocol is=0D
+ already in the opened state, then it must not be closed with CloseProtoc=
ol(). This is required=0D
+ to guarantee the state of ControllerHandle is not modified by this funct=
ion.=0D
+=0D
+ @param[in] This A pointer to the EFI_DRIVER_BINDING_PRO=
TOCOL instance.=0D
+ @param[in] ControllerHandle The handle of the controller to test. T=
his handle=0D
+ must support a protocol interface that =
supplies=0D
+ an I/O abstraction to the driver.=0D
+ @param[in] RemainingDevicePath A pointer to the remaining portion of a=
device path. This=0D
+ parameter is ignored by device drivers,=
and is optional for bus=0D
+ drivers. For bus drivers, if this param=
eter is not NULL, then=0D
+ the bus driver must determine if the bu=
s controller specified=0D
+ by ControllerHandle and the child contr=
oller specified=0D
+ by RemainingDevicePath are both support=
ed by this=0D
+ bus driver.=0D
+=0D
+ @retval EFI_SUCCESS The device specified by ControllerHandl=
e and=0D
+ RemainingDevicePath is supported by the=
driver specified by This.=0D
+ @retval EFI_ALREADY_STARTED The device specified by ControllerHandl=
e and=0D
+ RemainingDevicePath is already being ma=
naged by the driver=0D
+ specified by This.=0D
+ @retval EFI_ACCESS_DENIED The device specified by ControllerHandl=
e and=0D
+ RemainingDevicePath is already being ma=
naged by a different=0D
+ driver or an application that requires =
exclusive access.=0D
+ Currently not implemented.=0D
+ @retval EFI_UNSUPPORTED The device specified by ControllerHandl=
e and=0D
+ RemainingDevicePath is not supported by=
the driver specified by This.=0D
+**/=0D
+EFI_STATUS=0D
+EFIAPI=0D
+Ext4IsBindingSupported (=0D
+ IN EFI_DRIVER_BINDING_PROTOCOL *BindingProtocol,=0D
+ IN EFI_HANDLE ControllerHandle,=0D
+ IN EFI_DEVICE_PATH *RemainingDevicePath OPTIONAL=0D
+ );=0D
+=0D
+/**=0D
+ Starts a device controller or a bus controller.=0D
+=0D
+ The Start() function is designed to be invoked from the EFI boot service=
ConnectController().=0D
+ As a result, much of the error checking on the parameters to Start() has=
been moved into this=0D
+ common boot service. It is legal to call Start() from other locations,=0D
+ but the following calling restrictions must be followed, or the system b=
ehavior will not be deterministic.=0D
+ 1. ControllerHandle must be a valid EFI_HANDLE.=0D
+ 2. If RemainingDevicePath is not NULL, then it must be a pointer to a na=
turally aligned=0D
+ EFI_DEVICE_PATH_PROTOCOL.=0D
+ 3. Prior to calling Start(), the Supported() function for the driver spe=
cified by This must=0D
+ have been called with the same calling parameters, and Supported() mu=
st have returned EFI_SUCCESS.=0D
+=0D
+ @param[in] This A pointer to the EFI_DRIVER_BINDING_PRO=
TOCOL instance.=0D
+ @param[in] ControllerHandle The handle of the controller to start. =
This handle=0D
+ must support a protocol interface that =
supplies=0D
+ an I/O abstraction to the driver.=0D
+ @param[in] RemainingDevicePath A pointer to the remaining portion of a=
device path. This=0D
+ parameter is ignored by device drivers,=
and is optional for bus=0D
+ drivers. For a bus driver, if this para=
meter is NULL, then handles=0D
+ for all the children of Controller are =
created by this driver.=0D
+ If this parameter is not NULL and the f=
irst Device Path Node is=0D
+ not the End of Device Path Node, then o=
nly the handle for the=0D
+ child device specified by the first Dev=
ice Path Node of=0D
+ RemainingDevicePath is created by this =
driver.=0D
+ If the first Device Path Node of Remain=
ingDevicePath is=0D
+ the End of Device Path Node, no child h=
andle is created by this=0D
+ driver.=0D
+=0D
+ @retval EFI_SUCCESS The device was started.=0D
+ @retval EFI_DEVICE_ERROR The device could not be started due to =
a device error.Currently not implemented.=0D
+ @retval EFI_OUT_OF_RESOURCES The request could not be completed due =
to a lack of resources.=0D
+ @retval Others The driver failded to start the device.=
=0D
+=0D
+**/=0D
+EFI_STATUS=0D
+EFIAPI=0D
+Ext4Bind (=0D
+ IN EFI_DRIVER_BINDING_PROTOCOL *BindingProtocol,=0D
+ IN EFI_HANDLE ControllerHandle,=0D
+ IN EFI_DEVICE_PATH *RemainingDevicePath OPTIONAL=0D
+ );=0D
+=0D
+/**=0D
+ Stops a device controller or a bus controller.=0D
+=0D
+ The Stop() function is designed to be invoked from the EFI boot service =
DisconnectController().=0D
+ As a result, much of the error checking on the parameters to Stop() has =
been moved=0D
+ into this common boot service. It is legal to call Stop() from other loc=
ations,=0D
+ but the following calling restrictions must be followed, or the system b=
ehavior will not be deterministic.=0D
+ 1. ControllerHandle must be a valid EFI_HANDLE that was used on a previo=
us call to this=0D
+ same driver's Start() function.=0D
+ 2. The first NumberOfChildren handles of ChildHandleBuffer must all be a=
valid=0D
+ EFI_HANDLE. In addition, all of these handles must have been created =
in this driver's=0D
+ Start() function, and the Start() function must have called OpenProto=
col() on=0D
+ ControllerHandle with an Attribute of EFI_OPEN_PROTOCOL_BY_CHILD_CONT=
ROLLER.=0D
+=0D
+ @param[in] This A pointer to the EFI_DRIVER_BINDING_PROTOC=
OL instance.=0D
+ @param[in] ControllerHandle A handle to the device being stopped. The =
handle must=0D
+ support a bus specific I/O protocol for th=
e driver=0D
+ to use to stop the device.=0D
+ @param[in] NumberOfChildren The number of child device handles in Chil=
dHandleBuffer.=0D
+ @param[in] ChildHandleBuffer An array of child handles to be freed. May=
be NULL=0D
+ if NumberOfChildren is 0.=0D
+=0D
+ @retval EFI_SUCCESS The device was stopped.=0D
+ @retval EFI_DEVICE_ERROR The device could not be stopped due to a d=
evice error.=0D
+=0D
+**/=0D
+EFI_STATUS=0D
+EFIAPI=0D
+Ext4Stop (=0D
+ IN EFI_DRIVER_BINDING_PROTOCOL *This,=0D
+ IN EFI_HANDLE ControllerHandle,=0D
+ IN UINTN NumberOfChildren,=0D
+ IN EFI_HANDLE *ChildHandleBuffer OPTIONAL=0D
+ );=0D
+=0D
+EFI_DRIVER_BINDING_PROTOCOL gExt4BindingProtocol =3D=0D
+{=0D
+ Ext4IsBindingSupported,=0D
+ Ext4Bind,=0D
+ Ext4Stop,=0D
+ EXT4_DRIVER_VERSION=0D
+};=0D
+=0D
+/**=0D
+ Retrieves a Unicode string that is the user readable name of the control=
ler=0D
+ that is being managed by an EFI Driver.=0D
+=0D
+ @param[in] This A pointer to the EFI_COMPONENT_NAME_PROTOCO=
L instance.=0D
+ @param[in] ControllerHandle The handle of a controller that the driver =
specified by=0D
+ This is managing. This handle specifies th=
e controller=0D
+ whose name is to be returned.=0D
+ @param[in] ChildHandle The handle of the child controller to retri=
eve the name=0D
+ of. This is an optional parameter that may=
be NULL. It=0D
+ will be NULL for device drivers. It will a=
lso be NULL=0D
+ for a bus drivers that wish to retrieve the=
name of the=0D
+ bus controller. It will not be NULL for a =
bus driver=0D
+ that wishes to retrieve the name of a child=
controller.=0D
+ @param[in] Language A pointer to a three character ISO 639-2 la=
nguage=0D
+ identifier. This is the language of the co=
ntroller name=0D
+ that the caller is requesting, and it must =
match one=0D
+ of the languages specified in SupportedLang=
uages. The=0D
+ number of languages supported by a driver i=
s up to the=0D
+ driver writer.=0D
+ @param[out] ControllerName A pointer to the Unicode string to return.=
This Unicode=0D
+ string is the name of the controller speci=
fied by=0D
+ ControllerHandle and ChildHandle in the la=
nguage specified=0D
+ by Language, from the point of view of the=
driver specified=0D
+ by This.=0D
+=0D
+ @retval EFI_SUCCESS The Unicode string for the user-readable n=
ame in the=0D
+ language specified by Language for the dri=
ver=0D
+ specified by This was returned in DriverNa=
me.=0D
+ @retval EFI_INVALID_PARAMETER ControllerHandle is NULL.=0D
+ @retval EFI_INVALID_PARAMETER ChildHandle is not NULL and it is not a va=
lid EFI_HANDLE.=0D
+ @retval EFI_INVALID_PARAMETER Language is NULL.=0D
+ @retval EFI_INVALID_PARAMETER ControllerName is NULL.=0D
+ @retval EFI_UNSUPPORTED The driver specified by This is not curren=
tly managing=0D
+ the controller specified by ControllerHand=
le and=0D
+ ChildHandle.=0D
+ @retval EFI_UNSUPPORTED The driver specified by This does not supp=
ort the=0D
+ language specified by Language.=0D
+=0D
+**/=0D
+EFI_STATUS=0D
+EFIAPI=0D
+Ext4ComponentNameGetControllerName (=0D
+ IN EFI_COMPONENT_NAME_PROTOCOL *This,=
=0D
+ IN EFI_HANDLE Control=
lerHandle,=0D
+ IN EFI_HANDLE ChildHandle OPTIONA=
L,=0D
+ IN CHAR8 *Langua=
ge,=0D
+ OUT CHAR16 **Contr=
ollerName=0D
+ )=0D
+{=0D
+ EFI_STATUS Status;=0D
+=0D
+ if (ChildHandle !=3D NULL) {=0D
+ return EFI_UNSUPPORTED;=0D
+ }=0D
+=0D
+ // Test if the driver manages ControllHandle=0D
+ Status =3D EfiTestManagedDevice (=0D
+ ControllerHandle,=0D
+ gExt4BindingProtocol.DriverBindingHandle,=0D
+ &gEfiDiskIoProtocolGuid=0D
+ );=0D
+=0D
+ if (EFI_ERROR (Status)) {=0D
+ return Status;=0D
+ }=0D
+=0D
+ return LookupUnicodeString2 (=0D
+ Language,=0D
+ This->SupportedLanguages,=0D
+ mExt4ControllerNameTable,=0D
+ ControllerName,=0D
+ (BOOLEAN)(This =3D=3D &gExt4ComponentName)=0D
+ );=0D
+}=0D
+=0D
+/**=0D
+ Retrieves a Unicode string that is the user-readable name of the EFI Dri=
ver.=0D
+=0D
+ @param[in] This A pointer to the EFI_COMPONENT_NAME_PROTOCOL ins=
tance.=0D
+ @param[in] Language A pointer to a three-character ISO 639-2 languag=
e identifier.=0D
+ This is the language of the driver name that tha=
t the caller=0D
+ is requesting, and it must match one of the lang=
uages specified=0D
+ in SupportedLanguages. The number of languages =
supported by a=0D
+ driver is up to the driver writer.=0D
+ @param[out] DriverName A pointer to the Unicode string to return. This=
Unicode string=0D
+ is the name of the driver specified by This in t=
he language=0D
+ specified by Language.=0D
+=0D
+ @retval EFI_SUCCESS The Unicode string for the Driver specifie=
d by This=0D
+ and the language specified by Language was=
returned=0D
+ in DriverName.=0D
+ @retval EFI_INVALID_PARAMETER Language is NULL.=0D
+ @retval EFI_INVALID_PARAMETER DriverName is NULL.=0D
+ @retval EFI_UNSUPPORTED The driver specified by This does not supp=
ort the=0D
+ language specified by Language.=0D
+=0D
+**/=0D
+EFI_STATUS=0D
+EFIAPI=0D
+Ext4ComponentNameGetDriverName (=0D
+ IN EFI_COMPONENT_NAME_PROTOCOL *This,=0D
+ IN CHAR8 *Language,=0D
+ OUT CHAR16 **DriverName=0D
+ )=0D
+{=0D
+ return LookupUnicodeString2 (=0D
+ Language,=0D
+ This->SupportedLanguages,=0D
+ mExt4DriverNameTable,=0D
+ DriverName,=0D
+ (BOOLEAN)(This =3D=3D &gExt4ComponentName)=0D
+ );=0D
+}=0D
+=0D
+/**=0D
+ Stops a device controller or a bus controller.=0D
+=0D
+ The Stop() function is designed to be invoked from the EFI boot service =
DisconnectController().=0D
+ As a result, much of the error checking on the parameters to Stop() has =
been moved=0D
+ into this common boot service. It is legal to call Stop() from other loc=
ations,=0D
+ but the following calling restrictions must be followed, or the system b=
ehavior will not be deterministic.=0D
+ 1. ControllerHandle must be a valid EFI_HANDLE that was used on a previo=
us call to this=0D
+ same driver's Start() function.=0D
+ 2. The first NumberOfChildren handles of ChildHandleBuffer must all be a=
valid=0D
+ EFI_HANDLE. In addition, all of these handles must have been created =
in this driver's=0D
+ Start() function, and the Start() function must have called OpenProto=
col() on=0D
+ ControllerHandle with an Attribute of EFI_OPEN_PROTOCOL_BY_CHILD_CONT=
ROLLER.=0D
+=0D
+ @param[in] This A pointer to the EFI_DRIVER_BINDING_PROTOC=
OL instance.=0D
+ @param[in] ControllerHandle A handle to the device being stopped. The =
handle must=0D
+ support a bus specific I/O protocol for th=
e driver=0D
+ to use to stop the device.=0D
+ @param[in] NumberOfChildren The number of child device handles in Chil=
dHandleBuffer.=0D
+ @param[in] ChildHandleBuffer An array of child handles to be freed. May=
be NULL=0D
+ if NumberOfChildren is 0.=0D
+=0D
+ @retval EFI_SUCCESS The device was stopped.=0D
+ @retval EFI_DEVICE_ERROR The device could not be stopped due to a d=
evice error.=0D
+=0D
+**/=0D
+EFI_STATUS=0D
+EFIAPI=0D
+Ext4Stop (=0D
+ IN EFI_DRIVER_BINDING_PROTOCOL *This,=0D
+ IN EFI_HANDLE ControllerHandle,=0D
+ IN UINTN NumberOfChildren,=0D
+ IN EFI_HANDLE *ChildHandleBuffer OPTIONAL=0D
+ )=0D
+{=0D
+ EFI_STATUS Status;=0D
+ EFI_SIMPLE_FILE_SYSTEM_PROTOCOL *Sfs;=0D
+ EXT4_PARTITION *Partition;=0D
+ BOOLEAN HasDiskIo2;=0D
+=0D
+ Status =3D gBS->OpenProtocol (=0D
+ ControllerHandle,=0D
+ &gEfiSimpleFileSystemProtocolGuid,=0D
+ (VOID **)&Sfs,=0D
+ This->DriverBindingHandle,=0D
+ ControllerHandle,=0D
+ EFI_OPEN_PROTOCOL_GET_PROTOCOL=0D
+ );=0D
+=0D
+ if (EFI_ERROR (Status)) {=0D
+ return Status;=0D
+ }=0D
+=0D
+ Partition =3D (EXT4_PARTITION *)Sfs;=0D
+=0D
+ HasDiskIo2 =3D EXT4_DISK_IO2 (Partition) !=3D NULL;=0D
+=0D
+ Status =3D Ext4UnmountAndFreePartition (Partition);=0D
+=0D
+ if (EFI_ERROR (Status)) {=0D
+ return Status;=0D
+ }=0D
+=0D
+ Status =3D gBS->UninstallMultipleProtocolInterfaces (=0D
+ ControllerHandle,=0D
+ &gEfiSimpleFileSystemProtocolGuid,=0D
+ &Partition->Interface,=0D
+ NULL=0D
+ );=0D
+=0D
+ if (EFI_ERROR (Status)) {=0D
+ return Status;=0D
+ }=0D
+=0D
+ // Close all open protocols (DiskIo, DiskIo2, BlockIo)=0D
+=0D
+ Status =3D gBS->CloseProtocol (=0D
+ ControllerHandle,=0D
+ &gEfiDiskIoProtocolGuid,=0D
+ This->DriverBindingHandle,=0D
+ ControllerHandle=0D
+ );=0D
+=0D
+ if (EFI_ERROR (Status)) {=0D
+ return Status;=0D
+ }=0D
+=0D
+ Status =3D gBS->CloseProtocol (=0D
+ ControllerHandle,=0D
+ &gEfiBlockIoProtocolGuid,=0D
+ This->DriverBindingHandle,=0D
+ ControllerHandle=0D
+ );=0D
+=0D
+ if (EFI_ERROR (Status)) {=0D
+ return Status;=0D
+ }=0D
+=0D
+ if (HasDiskIo2) {=0D
+ Status =3D gBS->CloseProtocol (=0D
+ ControllerHandle,=0D
+ &gEfiDiskIo2ProtocolGuid,=0D
+ This->DriverBindingHandle,=0D
+ ControllerHandle=0D
+ );=0D
+=0D
+ if (EFI_ERROR (Status)) {=0D
+ return Status;=0D
+ }=0D
+ }=0D
+=0D
+ return Status;=0D
+}=0D
+=0D
+/**=0D
+ Ext4Dxe Driver's entry point.=0D
+=0D
+ Called at load time.=0D
+=0D
+ @param[in] ImageHandle Handle to the image.=0D
+ @param[in] SystemTable Pointer to the EFI_SYSTEM_TABLE.=0D
+ @return Result of the load.=0D
+**/=0D
+EFI_STATUS=0D
+EFIAPI=0D
+Ext4EntryPoint (=0D
+ IN EFI_HANDLE ImageHandle,=0D
+ IN EFI_SYSTEM_TABLE *SystemTable=0D
+ )=0D
+{=0D
+ EFI_STATUS Status;=0D
+=0D
+ Status =3D EfiLibInstallAllDriverProtocols2 (=0D
+ ImageHandle,=0D
+ SystemTable,=0D
+ &gExt4BindingProtocol,=0D
+ ImageHandle,=0D
+ &gExt4ComponentName,=0D
+ &gExt4ComponentName2,=0D
+ NULL,=0D
+ NULL,=0D
+ NULL,=0D
+ NULL=0D
+ );=0D
+=0D
+ if (EFI_ERROR (Status)) {=0D
+ return Status;=0D
+ }=0D
+=0D
+ return Ext4InitialiseUnicodeCollation (ImageHandle);=0D
+}=0D
+=0D
+/**=0D
+ Ext4Dxe Driver's unload callback.=0D
+=0D
+ Called at unload time.=0D
+=0D
+ @param[in] ImageHandle Handle to the image.=0D
+ @return Result of the unload.=0D
+**/=0D
+EFI_STATUS=0D
+EFIAPI=0D
+Ext4Unload (=0D
+ IN EFI_HANDLE ImageHandle=0D
+ )=0D
+{=0D
+ EFI_STATUS Status;=0D
+ EFI_HANDLE *DeviceHandleBuffer;=0D
+ UINTN DeviceHandleCount;=0D
+ UINTN Index;=0D
+ EFI_HANDLE Handle;=0D
+=0D
+ Status =3D gBS->LocateHandleBuffer (=0D
+ AllHandles,=0D
+ NULL,=0D
+ NULL,=0D
+ &DeviceHandleCount,=0D
+ &DeviceHandleBuffer=0D
+ );=0D
+ if (EFI_ERROR (Status)) {=0D
+ return Status;=0D
+ }=0D
+=0D
+ for (Index =3D 0; Index < DeviceHandleCount; Index++) {=0D
+ Handle =3D DeviceHandleBuffer[Index];=0D
+=0D
+ Status =3D EfiTestManagedDevice (Handle, ImageHandle, &gEfiDiskIoProto=
colGuid);=0D
+=0D
+ if (Status =3D=3D EFI_SUCCESS) {=0D
+ Status =3D gBS->DisconnectController (Handle, ImageHandle, NULL);=0D
+=0D
+ if (EFI_ERROR (Status)) {=0D
+ break;=0D
+ }=0D
+ }=0D
+ }=0D
+=0D
+ FreePool (DeviceHandleBuffer);=0D
+=0D
+ Status =3D EfiLibUninstallAllDriverProtocols2 (=0D
+ &gExt4BindingProtocol,=0D
+ &gExt4ComponentName,=0D
+ &gExt4ComponentName2,=0D
+ NULL,=0D
+ NULL,=0D
+ NULL,=0D
+ NULL=0D
+ );=0D
+=0D
+ return Status;=0D
+}=0D
+=0D
+/**=0D
+ Tests to see if this driver supports a given controller. If a child devi=
ce is provided,=0D
+ it further tests to see if this driver supports creating a handle for th=
e specified child device.=0D
+=0D
+ This function checks to see if the driver specified by This supports the=
device specified by=0D
+ ControllerHandle. Drivers will typically use the device path attached to=
=0D
+ ControllerHandle and/or the services from the bus I/O abstraction attach=
ed to=0D
+ ControllerHandle to determine if the driver supports ControllerHandle. T=
his function=0D
+ may be called many times during platform initialization. In order to red=
uce boot times, the tests=0D
+ performed by this function must be very small, and take as little time a=
s possible to execute. This=0D
+ function must not change the state of any hardware devices, and this fun=
ction must be aware that the=0D
+ device specified by ControllerHandle may already be managed by the same =
driver or a=0D
+ different driver. This function must match its calls to AllocatePages() =
with FreePages(),=0D
+ AllocatePool() with FreePool(), and OpenProtocol() with CloseProtocol().=
=0D
+ Because ControllerHandle may have been previously started by the same dr=
iver, if a protocol is=0D
+ already in the opened state, then it must not be closed with CloseProtoc=
ol(). This is required=0D
+ to guarantee the state of ControllerHandle is not modified by this funct=
ion.=0D
+=0D
+ @param[in] This A pointer to the EFI_DRIVER_BINDING_PRO=
TOCOL instance.=0D
+ @param[in] ControllerHandle The handle of the controller to test. T=
his handle=0D
+ must support a protocol interface that =
supplies=0D
+ an I/O abstraction to the driver.=0D
+ @param[in] RemainingDevicePath A pointer to the remaining portion of a=
device path. This=0D
+ parameter is ignored by device drivers,=
and is optional for bus=0D
+ drivers. For bus drivers, if this param=
eter is not NULL, then=0D
+ the bus driver must determine if the bu=
s controller specified=0D
+ by ControllerHandle and the child contr=
oller specified=0D
+ by RemainingDevicePath are both support=
ed by this=0D
+ bus driver.=0D
+=0D
+ @retval EFI_SUCCESS The device specified by ControllerHandl=
e and=0D
+ RemainingDevicePath is supported by the=
driver specified by This.=0D
+ @retval EFI_ALREADY_STARTED The device specified by ControllerHandl=
e and=0D
+ RemainingDevicePath is already being ma=
naged by the driver=0D
+ specified by This.=0D
+ @retval EFI_ACCESS_DENIED The device specified by ControllerHandl=
e and=0D
+ RemainingDevicePath is already being ma=
naged by a different=0D
+ driver or an application that requires =
exclusive access.=0D
+ Currently not implemented.=0D
+ @retval EFI_UNSUPPORTED The device specified by ControllerHandl=
e and=0D
+ RemainingDevicePath is not supported by=
the driver specified by This.=0D
+**/=0D
+EFI_STATUS=0D
+EFIAPI=0D
+Ext4IsBindingSupported (=0D
+ IN EFI_DRIVER_BINDING_PROTOCOL *BindingProtocol,=0D
+ IN EFI_HANDLE ControllerHandle,=0D
+ IN EFI_DEVICE_PATH *RemainingDevicePath OPTIONAL=0D
+ )=0D
+{=0D
+ // Note to self: EFI_OPEN_PROTOCOL_TEST_PROTOCOL lets us not close the=0D
+ // protocol and ignore the output argument entirely=0D
+=0D
+ EFI_STATUS Status;=0D
+=0D
+ Status =3D gBS->OpenProtocol (=0D
+ ControllerHandle,=0D
+ &gEfiDiskIoProtocolGuid,=0D
+ NULL,=0D
+ BindingProtocol->ImageHandle,=0D
+ ControllerHandle,=0D
+ EFI_OPEN_PROTOCOL_TEST_PROTOCOL=0D
+ );=0D
+=0D
+ if (EFI_ERROR (Status)) {=0D
+ return Status;=0D
+ }=0D
+=0D
+ Status =3D gBS->OpenProtocol (=0D
+ ControllerHandle,=0D
+ &gEfiBlockIoProtocolGuid,=0D
+ NULL,=0D
+ BindingProtocol->ImageHandle,=0D
+ ControllerHandle,=0D
+ EFI_OPEN_PROTOCOL_TEST_PROTOCOL=0D
+ );=0D
+ return Status;=0D
+}=0D
+=0D
+/**=0D
+ Starts a device controller or a bus controller.=0D
+=0D
+ The Start() function is designed to be invoked from the EFI boot service=
ConnectController().=0D
+ As a result, much of the error checking on the parameters to Start() has=
been moved into this=0D
+ common boot service. It is legal to call Start() from other locations,=0D
+ but the following calling restrictions must be followed, or the system b=
ehavior will not be deterministic.=0D
+ 1. ControllerHandle must be a valid EFI_HANDLE.=0D
+ 2. If RemainingDevicePath is not NULL, then it must be a pointer to a na=
turally aligned=0D
+ EFI_DEVICE_PATH_PROTOCOL.=0D
+ 3. Prior to calling Start(), the Supported() function for the driver spe=
cified by This must=0D
+ have been called with the same calling parameters, and Supported() mu=
st have returned EFI_SUCCESS.=0D
+=0D
+ @param[in] This A pointer to the EFI_DRIVER_BINDING_PRO=
TOCOL instance.=0D
+ @param[in] ControllerHandle The handle of the controller to start. =
This handle=0D
+ must support a protocol interface that =
supplies=0D
+ an I/O abstraction to the driver.=0D
+ @param[in] RemainingDevicePath A pointer to the remaining portion of a=
device path. This=0D
+ parameter is ignored by device drivers,=
and is optional for bus=0D
+ drivers. For a bus driver, if this para=
meter is NULL, then handles=0D
+ for all the children of Controller are =
created by this driver.=0D
+ If this parameter is not NULL and the f=
irst Device Path Node is=0D
+ not the End of Device Path Node, then o=
nly the handle for the=0D
+ child device specified by the first Dev=
ice Path Node of=0D
+ RemainingDevicePath is created by this =
driver.=0D
+ If the first Device Path Node of Remain=
ingDevicePath is=0D
+ the End of Device Path Node, no child h=
andle is created by this=0D
+ driver.=0D
+=0D
+ @retval EFI_SUCCESS The device was started.=0D
+ @retval EFI_DEVICE_ERROR The device could not be started due to =
a device error.Currently not implemented.=0D
+ @retval EFI_OUT_OF_RESOURCES The request could not be completed due =
to a lack of resources.=0D
+ @retval Others The driver failded to start the device.=
=0D
+=0D
+**/=0D
+EFI_STATUS=0D
+EFIAPI=0D
+Ext4Bind (=0D
+ IN EFI_DRIVER_BINDING_PROTOCOL *BindingProtocol,=0D
+ IN EFI_HANDLE ControllerHandle,=0D
+ IN EFI_DEVICE_PATH *RemainingDevicePath OPTIONAL=0D
+ )=0D
+{=0D
+ EFI_DISK_IO_PROTOCOL *DiskIo;=0D
+ EFI_DISK_IO2_PROTOCOL *DiskIo2;=0D
+ EFI_BLOCK_IO_PROTOCOL *BlockIo;=0D
+ EFI_STATUS Status;=0D
+=0D
+ DiskIo2 =3D NULL;=0D
+ BlockIo =3D NULL;=0D
+ DiskIo =3D NULL;=0D
+=0D
+ Status =3D gBS->OpenProtocol (=0D
+ ControllerHandle,=0D
+ &gEfiDiskIoProtocolGuid,=0D
+ (VOID **)&DiskIo,=0D
+ BindingProtocol->ImageHandle,=0D
+ ControllerHandle,=0D
+ EFI_OPEN_PROTOCOL_BY_DRIVER=0D
+ );=0D
+=0D
+ if (EFI_ERROR (Status)) {=0D
+ goto Error;=0D
+ }=0D
+=0D
+ DEBUG ((DEBUG_INFO, "[Ext4] Controller supports DISK_IO\n"));=0D
+=0D
+ Status =3D gBS->OpenProtocol (=0D
+ ControllerHandle,=0D
+ &gEfiDiskIo2ProtocolGuid,=0D
+ (VOID **)&DiskIo2,=0D
+ BindingProtocol->ImageHandle,=0D
+ ControllerHandle,=0D
+ EFI_OPEN_PROTOCOL_BY_DRIVER=0D
+ );=0D
+ // It's okay to not support DISK_IO2=0D
+=0D
+ if (DiskIo2 !=3D NULL) {=0D
+ DEBUG ((DEBUG_INFO, "[Ext4] Controller supports DISK_IO2\n"));=0D
+ }=0D
+=0D
+ Status =3D gBS->OpenProtocol (=0D
+ ControllerHandle,=0D
+ &gEfiBlockIoProtocolGuid,=0D
+ (VOID **)&BlockIo,=0D
+ BindingProtocol->ImageHandle,=0D
+ ControllerHandle,=0D
+ EFI_OPEN_PROTOCOL_GET_PROTOCOL=0D
+ );=0D
+=0D
+ if (EFI_ERROR (Status)) {=0D
+ goto Error;=0D
+ }=0D
+=0D
+ Status =3D Ext4OpenPartition (ControllerHandle, DiskIo, DiskIo2, BlockIo=
);=0D
+=0D
+ if (EFI_ERROR (Status)) {=0D
+ DEBUG ((DEBUG_ERROR, "[ext4] Error mounting: %r\n", Status));=0D
+ // Falls through to Error=0D
+ } else {=0D
+ return Status;=0D
+ }=0D
+=0D
+Error:=0D
+ if (DiskIo) {=0D
+ gBS->CloseProtocol (=0D
+ ControllerHandle,=0D
+ &gEfiDiskIoProtocolGuid,=0D
+ BindingProtocol->ImageHandle,=0D
+ ControllerHandle=0D
+ );=0D
+ }=0D
+=0D
+ if (DiskIo2) {=0D
+ gBS->CloseProtocol (=0D
+ ControllerHandle,=0D
+ &gEfiDiskIo2ProtocolGuid,=0D
+ BindingProtocol->ImageHandle,=0D
+ ControllerHandle=0D
+ );=0D
+ }=0D
+=0D
+ if (BlockIo) {=0D
+ gBS->CloseProtocol (=0D
+ ControllerHandle,=0D
+ &gEfiBlockIoProtocolGuid,=0D
+ BindingProtocol->ImageHandle,=0D
+ ControllerHandle=0D
+ );=0D
+ }=0D
+=0D
+ return Status;=0D
+}=0D
diff --git a/Features/Ext4Pkg/Ext4Dxe/Ext4Dxe.h b/Features/Ext4Pkg/Ext4Dxe/=
Ext4Dxe.h
new file mode 100644
index 0000000000..93f0a8a04a
--- /dev/null
+++ b/Features/Ext4Pkg/Ext4Dxe/Ext4Dxe.h
@@ -0,0 +1,1038 @@
+/** @file=0D
+ Common header for the driver=0D
+=0D
+ Copyright (c) 2021 Pedro Falcato All rights reserved.=0D
+ SPDX-License-Identifier: BSD-2-Clause-Patent=0D
+**/=0D
+=0D
+#ifndef EXT4_H_=0D
+#define EXT4_H_=0D
+=0D
+#include <Uefi.h>=0D
+=0D
+#include <Guid/FileInfo.h>=0D
+#include <Guid/FileSystemInfo.h>=0D
+#include <Guid/FileSystemVolumeLabelInfo.h>=0D
+#include <Protocol/BlockIo.h>=0D
+#include <Protocol/DiskIo.h>=0D
+#include <Protocol/DiskIo2.h>=0D
+#include <Protocol/SimpleFileSystem.h>=0D
+=0D
+#include <Library/PcdLib.h>=0D
+#include <Library/DebugLib.h>=0D
+#include <Library/UefiLib.h>=0D
+#include <Library/BaseLib.h>=0D
+#include <Library/BaseMemoryLib.h>=0D
+#include <Library/MemoryAllocationLib.h>=0D
+#include <Library/UefiDriverEntryPoint.h>=0D
+#include <Library/UefiBootServicesTableLib.h>=0D
+#include <Library/UefiRuntimeServicesTableLib.h>=0D
+#include <Library/OrderedCollectionLib.h>=0D
+=0D
+#include "Ext4Disk.h"=0D
+=0D
+#define EXT4_NAME_MAX 255=0D
+=0D
+#define EXT4_DRIVER_VERSION 0x0000=0D
+=0D
+/**=0D
+ Opens an ext4 partition and installs the Simple File System protocol.=0D
+=0D
+ @param[in] DeviceHandle Handle to the block device.=0D
+ @param[in] DiskIo Pointer to an EFI_DISK_IO_PROTOCOL.=
=0D
+ @param[in opt] DiskIo2 Pointer to an EFI_DISK_IO2_PROTOCOL,=
if supported.=0D
+ @param[in] BlockIo Pointer to an EFI_BLOCK_IO_PROTOCOL.=
=0D
+=0D
+ @retval EFI_SUCCESS The opening was successful.=0D
+ !EFI_SUCCESS Opening failed.=0D
+**/=0D
+EFI_STATUS=0D
+Ext4OpenPartition (=0D
+ IN EFI_HANDLE DeviceHandle,=0D
+ IN EFI_DISK_IO_PROTOCOL *DiskIo,=0D
+ IN OPTIONAL EFI_DISK_IO2_PROTOCOL *DiskIo2,=0D
+ IN EFI_BLOCK_IO_PROTOCOL *BlockIo=0D
+ );=0D
+=0D
+typedef struct _Ext4File EXT4_FILE;=0D
+=0D
+typedef struct _Ext4_PARTITION {=0D
+ EFI_SIMPLE_FILE_SYSTEM_PROTOCOL Interface;=0D
+ EFI_DISK_IO_PROTOCOL *DiskIo;=0D
+ EFI_DISK_IO2_PROTOCOL *DiskIo2;=0D
+ EFI_BLOCK_IO_PROTOCOL *BlockIo;=0D
+=0D
+ EXT4_SUPERBLOCK SuperBlock;=0D
+ BOOLEAN Unmounting;=0D
+=0D
+ UINT32 FeaturesIncompat;=0D
+ UINT32 FeaturesCompat;=0D
+ UINT32 FeaturesRoCompat;=0D
+ UINT32 InodeSize;=0D
+ UINT32 BlockSize;=0D
+ BOOLEAN ReadOnly;=0D
+ UINT64 NumberBlockGroups;=0D
+ EXT4_BLOCK_NR NumberBlocks;=0D
+=0D
+ EXT4_BLOCK_GROUP_DESC *BlockGroups;=0D
+ UINT32 DescSize;=0D
+ EXT4_FILE *Root;=0D
+=0D
+ UINT32 InitialSeed;=0D
+=0D
+ LIST_ENTRY OpenFiles;=0D
+} EXT4_PARTITION;=0D
+=0D
+/**=0D
+ Opens and parses the superblock.=0D
+=0D
+ @param[out] Partition Partition structure to fill with filesystem d=
etails.=0D
+ @retval EFI_SUCCESS Parsing was succesful and the partition is a=
=0D
+ valid ext4 partition.=0D
+**/=0D
+EFI_STATUS=0D
+Ext4OpenSuperblock (=0D
+ OUT EXT4_PARTITION *Partition=0D
+ );=0D
+=0D
+/**=0D
+ Retrieves the EFI_BLOCK_IO_PROTOCOL of the partition.=0D
+=0D
+ @param[in] Partition Pointer to the opened ext4 partition.=0D
+ @return The Block IO protocol associated with the partition.=0D
+**/=0D
+#define EXT4_BLOCK_IO(Partition) Partition->BlockIo=0D
+=0D
+/**=0D
+ Retrieves the EFI_DISK_IO_PROTOCOL of the partition.=0D
+=0D
+ @param[in] Partition Pointer to the opened ext4 partition.=0D
+ @return The Disk IO protocol associated with the partition.=0D
+**/=0D
+#define EXT4_DISK_IO(Partition) Partition->DiskIo=0D
+=0D
+/**=0D
+ Retrieves the EFI_DISK_IO2_PROTOCOL of the partition.=0D
+=0D
+ @param[in] Partition Pointer to the opened ext4 partition.=0D
+ @return The Disk IO 2 protocol associated with the partition, or NULL i=
f=0D
+ not supported.=0D
+**/=0D
+#define EXT4_DISK_IO2(Partition) Partition->DiskIo2=0D
+=0D
+/**=0D
+ Retrieves the media ID of the partition.=0D
+=0D
+ @param[in] Partition Pointer to the opened ext4 partition.=0D
+ @return The media ID associated with the partition.=0D
+**/=0D
+#define EXT4_MEDIA_ID(Partition) Partition->BlockIo->Media->MediaId=0D
+=0D
+/**=0D
+ Reads from the partition's disk using the DISK_IO protocol.=0D
+=0D
+ @param[in] Partition Pointer to the opened ext4 partition.=0D
+ @param[out] Buffer Pointer to a destination buffer.=0D
+ @param[in] Length Length of the destination buffer.=0D
+ @param[in] Offset Offset, in bytes, of the location to read.=0D
+=0D
+ @return Success status of the disk read.=0D
+**/=0D
+EFI_STATUS=0D
+Ext4ReadDiskIo (=0D
+ IN EXT4_PARTITION *Partition,=0D
+ OUT VOID *Buffer,=0D
+ IN UINTN Length,=0D
+ IN UINT64 Offset=0D
+ );=0D
+=0D
+/**=0D
+ Reads blocks from the partition's disk using the DISK_IO protocol.=0D
+=0D
+ @param[in] Partition Pointer to the opened ext4 partition.=0D
+ @param[out] Buffer Pointer to a destination buffer.=0D
+ @param[in] NumberBlocks Length of the read, in filesystem blocks.=0D
+ @param[in] BlockNumber Starting block number.=0D
+=0D
+ @return Success status of the read.=0D
+**/=0D
+EFI_STATUS=0D
+Ext4ReadBlocks (=0D
+ IN EXT4_PARTITION *Partition,=0D
+ OUT VOID *Buffer,=0D
+ IN UINTN NumberBlocks,=0D
+ IN EXT4_BLOCK_NR BlockNumber=0D
+ );=0D
+=0D
+/**=0D
+ Allocates a buffer and reads blocks from the partition's disk using the=
DISK_IO protocol.=0D
+ This function is deprecated and will be removed in the future.=0D
+=0D
+ @param[in] Partition Pointer to the opened ext4 partition.=0D
+ @param[in] NumberBlocks Length of the read, in filesystem blocks.=0D
+ @param[in] BlockNumber Starting block number.=0D
+=0D
+ @return Buffer allocated by AllocatePool, or NULL if some part of the p=
rocess=0D
+ failed.=0D
+**/=0D
+VOID *=0D
+Ext4AllocAndReadBlocks (=0D
+ IN EXT4_PARTITION *Partition,=0D
+ IN UINTN NumberBlocks,=0D
+ IN EXT4_BLOCK_NR BlockNumber=0D
+ );=0D
+=0D
+/**=0D
+ Checks if the opened partition has the 64-bit feature (see EXT4_FEATURE=
_INCOMPAT_64BIT).=0D
+=0D
+ @param[in] Partition Pointer to the opened ext4 partition.=0D
+=0D
+ @return TRUE if EXT4_FEATURE_INCOMPAT_64BIT is enabled, else FALSE.=0D
+**/=0D
+#define EXT4_IS_64_BIT(Partition) ((Partition->FeaturesIncompat & EXT4_FE=
ATURE_INCOMPAT_64BIT) !=3D 0)=0D
+=0D
+/**=0D
+ Composes an EXT4_BLOCK_NR safely, from two halfs.=0D
+=0D
+ @param[in] Partition Pointer to the opened ext4 partition.=0D
+ @param[in] Low Low half of the block number.=0D
+ @param[in] High High half of the block number.=0D
+=0D
+ @return The block number formed by Low, and if 64 bit is enabled, High.=
=0D
+**/=0D
+#define EXT4_BLOCK_NR_FROM_HALFS(Partition, Low, High) \=0D
+ EXT4_IS_64_BIT (Partition) ? (Low | LShiftU64 (High, 32)) : Low=0D
+=0D
+/**=0D
+ Retrieves a block group descriptor of the ext4 filesystem.=0D
+=0D
+ @param[in] Partition Pointer to the opened ext4 partition.=0D
+ @param[in] BlockGroup Block group number.=0D
+=0D
+ @return A pointer to the block group descriptor.=0D
+**/=0D
+EXT4_BLOCK_GROUP_DESC *=0D
+Ext4GetBlockGroupDesc (=0D
+ IN EXT4_PARTITION *Partition,=0D
+ IN UINT32 BlockGroup=0D
+ );=0D
+=0D
+/**=0D
+ Reads an inode from disk.=0D
+=0D
+ @param[in] Partition Pointer to the opened partition.=0D
+ @param[in] InodeNum Number of the desired Inode=0D
+ @param[out] OutIno Pointer to where it will be stored a pointer t=
o the read inode.=0D
+=0D
+ @return Status of the inode read.=0D
+**/=0D
+EFI_STATUS=0D
+Ext4ReadInode (=0D
+ IN EXT4_PARTITION *Partition,=0D
+ IN EXT4_INO_NR InodeNum,=0D
+ OUT EXT4_INODE **OutIno=0D
+ );=0D
+=0D
+/**=0D
+ Converts blocks to bytes.=0D
+=0D
+ @param[in] Partition Pointer to the opened partition.=0D
+ @param[in] Block Block number/number of blocks.=0D
+=0D
+ @return The number of bytes.=0D
+**/=0D
+#define EXT4_BLOCK_TO_BYTES(Partition, Block) MultU64x32 (Block, Partitio=
n->BlockSize)=0D
+=0D
+/**=0D
+ Reads from an EXT4 inode.=0D
+ @param[in] Partition Pointer to the opened EXT4 partition.=0D
+ @param[in] File Pointer to the opened file.=0D
+ @param[out] Buffer Pointer to the buffer.=0D
+ @param[in] Offset Offset of the read.=0D
+ @param[in out] Length Pointer to the length of the buffer, in b=
ytes.=0D
+ After a succesful read, it's updated to t=
he number of read bytes.=0D
+=0D
+ @return Status of the read operation.=0D
+**/=0D
+EFI_STATUS=0D
+Ext4Read (=0D
+ IN EXT4_PARTITION *Partition,=0D
+ IN EXT4_FILE *File,=0D
+ OUT VOID *Buffer,=0D
+ IN UINT64 Offset,=0D
+ IN OUT UINTN *Length=0D
+ );=0D
+=0D
+/**=0D
+ Retrieves the size of the inode.=0D
+=0D
+ @param[in] Inode Pointer to the ext4 inode.=0D
+=0D
+ @return The size of the inode, in bytes.=0D
+**/=0D
+#define EXT4_INODE_SIZE(Inode) (LShiftU64 (Inode->i_size_hi, 32) | Inode-=
i_size_lo)=0D
+=0D
+/**=0D
+ Retrieves an extent from an EXT4 inode.=0D
+ @param[in] Partition Pointer to the opened EXT4 partition.=0D
+ @param[in] File Pointer to the opened file.=0D
+ @param[in] LogicalBlock Block number which the returned extent mu=
st cover.=0D
+ @param[out] Extent Pointer to the output buffer, where the e=
xtent will be copied to.=0D
+=0D
+ @retval EFI_SUCCESS Retrieval was succesful.=0D
+ @retval EFI_NO_MAPPING Block has no mapping.=0D
+**/=0D
+EFI_STATUS=0D
+Ext4GetExtent (=0D
+ IN EXT4_PARTITION *Partition,=0D
+ IN EXT4_FILE *File,=0D
+ IN EXT4_BLOCK_NR LogicalBlock,=0D
+ OUT EXT4_EXTENT *Extent=0D
+ );=0D
+=0D
+struct _Ext4File {=0D
+ EFI_FILE_PROTOCOL Protocol;=0D
+ EXT4_INODE *Inode;=0D
+ EXT4_INO_NR InodeNum;=0D
+=0D
+ UINT64 OpenMode;=0D
+ UINT64 Position;=0D
+=0D
+ EXT4_PARTITION *Partition;=0D
+ CHAR16 *FileName;=0D
+=0D
+ ORDERED_COLLECTION *ExtentsMap;=0D
+=0D
+ LIST_ENTRY OpenFilesListNode;=0D
+};=0D
+=0D
+#define EXT4_FILE_FROM_OPEN_FILES_NODE(Node) BASE_CR (Node, EXT4_FILE, Op=
enFilesListNode)=0D
+=0D
+/**=0D
+ Retrieves a directory entry.=0D
+=0D
+ @param[in] Directory Pointer to the opened directory.=0D
+ @param[in] NameUnicode Pointer to the UCS-2 formatted filename.=0D
+ @param[in] Partition Pointer to the ext4 partition.=0D
+ @param[out] Result Pointer to the destination directory entry.=
=0D
+=0D
+ @return The result of the operation.=0D
+**/=0D
+EFI_STATUS=0D
+Ext4RetrieveDirent (=0D
+ IN EXT4_FILE *Directory,=0D
+ IN CONST CHAR16 *NameUnicode,=0D
+ IN EXT4_PARTITION *Partition,=0D
+ OUT EXT4_DIR_ENTRY *Result=0D
+ );=0D
+=0D
+/**=0D
+ Opens a file.=0D
+=0D
+ @param[in] Directory Pointer to the opened directory.=0D
+ @param[in] Name Pointer to the UCS-2 formatted filename.=0D
+ @param[in] Partition Pointer to the ext4 partition.=0D
+ @param[in] OpenMode Mode in which the file is supposed to be op=
en.=0D
+ @param[out] OutFile Pointer to the newly opened file.=0D
+=0D
+ @return Result of the operation.=0D
+**/=0D
+EFI_STATUS=0D
+Ext4OpenFile (=0D
+ IN EXT4_FILE *Directory,=0D
+ IN CONST CHAR16 *Name,=0D
+ IN EXT4_PARTITION *Partition,=0D
+ IN UINT64 OpenMode,=0D
+ OUT EXT4_FILE **OutFile=0D
+ );=0D
+=0D
+/**=0D
+ Opens a file using a directory entry.=0D
+=0D
+ @param[in] Partition Pointer to the ext4 partition.=0D
+ @param[in] OpenMode Mode in which the file is supposed to be op=
en.=0D
+ @param[out] OutFile Pointer to the newly opened file.=0D
+ @param[in] Entry Directory entry to be used.=0D
+=0D
+ @retval EFI_STATUS Result of the operation=0D
+**/=0D
+EFI_STATUS=0D
+Ext4OpenDirent (=0D
+ IN EXT4_PARTITION *Partition,=0D
+ IN UINT64 OpenMode,=0D
+ OUT EXT4_FILE **OutFile,=0D
+ IN EXT4_DIR_ENTRY *Entry=0D
+ );=0D
+=0D
+/**=0D
+ Allocates a zeroed inode structure.=0D
+ @param[in] Partition Pointer to the opened EXT4 partition.=0D
+=0D
+ @return Pointer to the allocated structure, from the pool,=0D
+ with size Partition->InodeSize.=0D
+**/=0D
+EXT4_INODE *=0D
+Ext4AllocateInode (=0D
+ IN EXT4_PARTITION *Partition=0D
+ );=0D
+=0D
+// Part of the EFI_SIMPLE_FILE_SYSTEM_PROTOCOL=0D
+=0D
+/**=0D
+ Open the root directory on a volume.=0D
+=0D
+ @param[in] This A pointer to the volume to open the root directory.=0D
+ @param[out] Root A pointer to the location to return the opened file ha=
ndle for the=0D
+ root directory.=0D
+=0D
+ @retval EFI_SUCCESS The device was opened.=0D
+ @retval EFI_UNSUPPORTED This volume does not support the requested =
file system type.=0D
+ @retval EFI_NO_MEDIA The device has no medium.=0D
+ @retval EFI_DEVICE_ERROR The device reported an error.=0D
+ @retval EFI_VOLUME_CORRUPTED The file system structures are corrupted.=0D
+ @retval EFI_ACCESS_DENIED The service denied access to the file.=0D
+ @retval EFI_OUT_OF_RESOURCES The volume was not opened due to lack of re=
sources.=0D
+ @retval EFI_MEDIA_CHANGED The device has a different medium in it or =
the medium is no=0D
+ longer supported. Any existing file handles=
for this volume are=0D
+ no longer valid. To access the files on the=
new medium, the=0D
+ volume must be reopened with OpenVolume().=
=0D
+=0D
+**/=0D
+EFI_STATUS=0D
+EFIAPI=0D
+Ext4OpenVolume (=0D
+ IN EFI_SIMPLE_FILE_SYSTEM_PROTOCOL *This,=0D
+ IN EFI_FILE_PROTOCOL **Root=0D
+ );=0D
+=0D
+// End of EFI_SIMPLE_FILE_SYSTEM_PROTOCOL=0D
+=0D
+/**=0D
+ Sets up the protocol and metadata of a file that is being opened.=0D
+=0D
+ @param[in out] File Pointer to the file.=0D
+ @param[in] Partition Pointer to the opened partition.=0D
+**/=0D
+VOID=0D
+Ext4SetupFile (=0D
+ IN OUT EXT4_FILE *File,=0D
+ IN EXT4_PARTITION *Partition=0D
+ );=0D
+=0D
+/**=0D
+ Closes a file.=0D
+=0D
+ @param[in] File Pointer to the file.=0D
+=0D
+ @return Status of the closing of the file.=0D
+**/=0D
+EFI_STATUS=0D
+Ext4CloseInternal (=0D
+ IN EXT4_FILE *File=0D
+ );=0D
+=0D
+// Part of the EFI_FILE_PROTOCOL=0D
+=0D
+/**=0D
+ Opens a new file relative to the source file's location.=0D
+=0D
+ @param[in] This A pointer to the EFI_FILE_PROTOCOL instance that =
is the file=0D
+ handle to the source location. This would typical=
ly be an open=0D
+ handle to a directory.=0D
+ @param[out] NewHandle A pointer to the location to return the opened ha=
ndle for the new=0D
+ file.=0D
+ @param[in] FileName The Null-terminated string of the name of the fil=
e to be opened.=0D
+ The file name may contain the following path modi=
fiers: "\", ".",=0D
+ and "..".=0D
+ @param[in] OpenMode The mode to open the file. The only valid combina=
tions that the=0D
+ file may be opened with are: Read, Read/Write, or=
Create/Read/Write.=0D
+ @param[in] Attributes Only valid for EFI_FILE_MODE_CREATE, in which cas=
e these are the=0D
+ attribute bits for the newly created file.=0D
+=0D
+ @retval EFI_SUCCESS The file was opened.=0D
+ @retval EFI_NOT_FOUND The specified file could not be found on th=
e device.=0D
+ @retval EFI_NO_MEDIA The device has no medium.=0D
+ @retval EFI_MEDIA_CHANGED The device has a different medium in it or =
the medium is no=0D
+ longer supported.=0D
+ @retval EFI_DEVICE_ERROR The device reported an error.=0D
+ @retval EFI_VOLUME_CORRUPTED The file system structures are corrupted.=0D
+ @retval EFI_WRITE_PROTECTED An attempt was made to create a file, or op=
en a file for write=0D
+ when the media is write-protected.=0D
+ @retval EFI_ACCESS_DENIED The service denied access to the file.=0D
+ @retval EFI_OUT_OF_RESOURCES Not enough resources were available to open=
the file.=0D
+ @retval EFI_VOLUME_FULL The volume is full.=0D
+=0D
+**/=0D
+EFI_STATUS=0D
+EFIAPI=0D
+Ext4Open (=0D
+ IN EFI_FILE_PROTOCOL *This,=0D
+ OUT EFI_FILE_PROTOCOL **NewHandle,=0D
+ IN CHAR16 *FileName,=0D
+ IN UINT64 OpenMode,=0D
+ IN UINT64 Attributes=0D
+ );=0D
+=0D
+/**=0D
+ Closes a specified file handle.=0D
+=0D
+ @param[in] This A pointer to the EFI_FILE_PROTOCOL instance th=
at is the file=0D
+ handle to close.=0D
+=0D
+ @retval EFI_SUCCESS The file was closed.=0D
+=0D
+**/=0D
+EFI_STATUS=0D
+EFIAPI=0D
+Ext4Close (=0D
+ IN EFI_FILE_PROTOCOL *This=0D
+ );=0D
+=0D
+/**=0D
+ Close and delete the file handle.=0D
+=0D
+ @param[in] This A pointer to the EFI_FILE_PROTOCOL =
instance that is the=0D
+ handle to the file to delete.=0D
+=0D
+ @retval EFI_SUCCESS The file was closed and deleted, and th=
e handle was closed.=0D
+ @retval EFI_WARN_DELETE_FAILURE The handle was closed, but the file was=
not deleted.=0D
+=0D
+**/=0D
+EFI_STATUS=0D
+EFIAPI=0D
+Ext4Delete (=0D
+ IN EFI_FILE_PROTOCOL *This=0D
+ );=0D
+=0D
+/**=0D
+ Reads data from a file.=0D
+=0D
+ @param[in] This A pointer to the EFI_FILE_PROTOCOL inst=
ance that is the file=0D
+ handle to read data from.=0D
+ @param[in out] BufferSize On input, the size of the Buffer. On ou=
tput, the amount of data=0D
+ returned in Buffer. In both cases, the =
size is measured in bytes.=0D
+ @param[out] Buffer The buffer into which the data is read.=
=0D
+=0D
+ @retval EFI_SUCCESS Data was read.=0D
+ @retval EFI_NO_MEDIA The device has no medium.=0D
+ @retval EFI_DEVICE_ERROR The device reported an error.=0D
+ @retval EFI_DEVICE_ERROR An attempt was made to read from a deleted =
file.=0D
+ @retval EFI_DEVICE_ERROR On entry, the current file position is beyo=
nd the end of the file.=0D
+ @retval EFI_VOLUME_CORRUPTED The file system structures are corrupted.=0D
+ @retval EFI_BUFFER_TOO_SMALL The BufferSize is too small to read the cur=
rent directory=0D
+ entry. BufferSize has been updated with the=
size=0D
+ needed to complete the request.=0D
+=0D
+**/=0D
+EFI_STATUS=0D
+EFIAPI=0D
+Ext4ReadFile (=0D
+ IN EFI_FILE_PROTOCOL *This,=0D
+ IN OUT UINTN *BufferSize,=0D
+ OUT VOID *Buffer=0D
+ );=0D
+=0D
+/**=0D
+ Writes data to a file.=0D
+=0D
+ @param[in] This A pointer to the EFI_FILE_PROTOCOL instance =
that is the file=0D
+ handle to write data to.=0D
+ @param[in out] BufferSize On input, the size of the Buffer. On output,=
the amount of data=0D
+ actually written. In both cases, the size is=
measured in bytes.=0D
+ @param[in] Buffer The buffer of data to write.=0D
+=0D
+ @retval EFI_SUCCESS Data was written.=0D
+ @retval EFI_UNSUPPORTED Writes to open directory files are not supp=
orted.=0D
+ @retval EFI_NO_MEDIA The device has no medium.=0D
+ @retval EFI_DEVICE_ERROR The device reported an error.=0D
+ @retval EFI_DEVICE_ERROR An attempt was made to write to a deleted f=
ile.=0D
+ @retval EFI_VOLUME_CORRUPTED The file system structures are corrupted.=0D
+ @retval EFI_WRITE_PROTECTED The file or medium is write-protected.=0D
+ @retval EFI_ACCESS_DENIED The file was opened read only.=0D
+ @retval EFI_VOLUME_FULL The volume is full.=0D
+=0D
+**/=0D
+EFI_STATUS=0D
+EFIAPI=0D
+Ext4WriteFile (=0D
+ IN EFI_FILE_PROTOCOL *This,=0D
+ IN OUT UINTN *BufferSize,=0D
+ IN VOID *Buffer=0D
+ );=0D
+=0D
+/**=0D
+ Returns a file's current position.=0D
+=0D
+ @param[in] This A pointer to the EFI_FILE_PROTOCOL instance=
that is the file=0D
+ handle to get the current position on.=0D
+ @param[out] Position The address to return the file's current po=
sition value.=0D
+=0D
+ @retval EFI_SUCCESS The position was returned.=0D
+ @retval EFI_UNSUPPORTED The request is not valid on open directories.=0D
+ @retval EFI_DEVICE_ERROR An attempt was made to get the position from a =
deleted file.=0D
+=0D
+**/=0D
+EFI_STATUS=0D
+EFIAPI=0D
+Ext4GetPosition (=0D
+ IN EFI_FILE_PROTOCOL *This,=0D
+ OUT UINT64 *Position=0D
+ );=0D
+=0D
+/**=0D
+ Sets a file's current position.=0D
+=0D
+ @param[in] This A pointer to the EFI_FILE_PROTOCOL instance =
that is the=0D
+ file handle to set the requested position on=
.=0D
+ @param[in] Position The byte position from the start of the file =
to set.=0D
+=0D
+ @retval EFI_SUCCESS The position was set.=0D
+ @retval EFI_UNSUPPORTED The seek request for nonzero is not valid on op=
en=0D
+ directories.=0D
+ @retval EFI_DEVICE_ERROR An attempt was made to set the position of a de=
leted file.=0D
+=0D
+**/=0D
+EFI_STATUS=0D
+EFIAPI=0D
+Ext4SetPosition (=0D
+ IN EFI_FILE_PROTOCOL *This,=0D
+ IN UINT64 Position=0D
+ );=0D
+=0D
+/**=0D
+ Returns information about a file.=0D
+=0D
+ @param[in] This A pointer to the EFI_FILE_PROTOCOL insta=
nce that is the file=0D
+ handle the requested information is for.=
=0D
+ @param[in] InformationType The type identifier for the information =
being requested.=0D
+ @param[in out] BufferSize On input, the size of Buffer. On output,=
the amount of data=0D
+ returned in Buffer. In both cases, the s=
ize is measured in bytes.=0D
+ @param[out] Buffer A pointer to the data buffer to return. =
The buffer's type is=0D
+ indicated by InformationType.=0D
+=0D
+ @retval EFI_SUCCESS The information was returned.=0D
+ @retval EFI_UNSUPPORTED The InformationType is not known.=0D
+ @retval EFI_NO_MEDIA The device has no medium.=0D
+ @retval EFI_DEVICE_ERROR The device reported an error.=0D
+ @retval EFI_VOLUME_CORRUPTED The file system structures are corrupted.=0D
+ @retval EFI_BUFFER_TOO_SMALL The BufferSize is too small to read the cur=
rent directory entry.=0D
+ BufferSize has been updated with the size n=
eeded to complete=0D
+ the request.=0D
+**/=0D
+EFI_STATUS=0D
+EFIAPI=0D
+Ext4GetInfo (=0D
+ IN EFI_FILE_PROTOCOL *This,=0D
+ IN EFI_GUID *InformationType,=0D
+ IN OUT UINTN *BufferSize,=0D
+ OUT VOID *Buffer=0D
+ );=0D
+=0D
+/**=0D
+ Sets information about a file.=0D
+=0D
+ @param[in] This A pointer to the EFI_FILE_PROTOCOL instance =
that is the file=0D
+ handle the information is for.=0D
+ @param[in] InformationType The type identifier for the information bein=
g set.=0D
+ @param[in] BufferSize The size, in bytes, of Buffer.=0D
+ @param[in] Buffer A pointer to the data buffer to write. The b=
uffer's type is=0D
+ indicated by InformationType.=0D
+=0D
+ @retval EFI_SUCCESS The information was set.=0D
+ @retval EFI_UNSUPPORTED The InformationType is not known.=0D
+ @retval EFI_NO_MEDIA The device has no medium.=0D
+ @retval EFI_DEVICE_ERROR The device reported an error.=0D
+ @retval EFI_VOLUME_CORRUPTED The file system structures are corrupted.=0D
+ @retval EFI_WRITE_PROTECTED InformationType is EFI_FILE_INFO_ID and the=
media is=0D
+ read-only.=0D
+ @retval EFI_WRITE_PROTECTED InformationType is EFI_FILE_PROTOCOL_SYSTEM=
_INFO_ID=0D
+ and the media is read only.=0D
+ @retval EFI_WRITE_PROTECTED InformationType is EFI_FILE_SYSTEM_VOLUME_L=
ABEL_ID=0D
+ and the media is read-only.=0D
+ @retval EFI_ACCESS_DENIED An attempt is made to change the name of a =
file to a=0D
+ file that is already present.=0D
+ @retval EFI_ACCESS_DENIED An attempt is being made to change the EFI_=
FILE_DIRECTORY=0D
+ Attribute.=0D
+ @retval EFI_ACCESS_DENIED An attempt is being made to change the size=
of a directory.=0D
+ @retval EFI_ACCESS_DENIED InformationType is EFI_FILE_INFO_ID and the=
file was opened=0D
+ read-only and an attempt is being made to m=
odify a field=0D
+ other than Attribute.=0D
+ @retval EFI_VOLUME_FULL The volume is full.=0D
+ @retval EFI_BAD_BUFFER_SIZE BufferSize is smaller than the size of the =
type indicated=0D
+ by InformationType.=0D
+=0D
+**/=0D
+EFI_STATUS=0D
+EFIAPI=0D
+Ext4SetInfo (=0D
+ IN EFI_FILE_PROTOCOL *This,=0D
+ IN EFI_GUID *InformationType,=0D
+ IN UINTN BufferSize,=0D
+ IN VOID *Buffer=0D
+ );=0D
+=0D
+// EFI_FILE_PROTOCOL implementation ends here.=0D
+=0D
+/**=0D
+ Checks if a file is a directory.=0D
+ @param[in] File Pointer to the opened file.=0D
+=0D
+ @return TRUE if file is a directory.=0D
+**/=0D
+BOOLEAN=0D
+Ext4FileIsDir (=0D
+ IN CONST EXT4_FILE *File=0D
+ );=0D
+=0D
+/**=0D
+ Checks if a file is a regular file.=0D
+ @param[in] File Pointer to the opened file.=0D
+=0D
+ @return BOOLEAN TRUE if file is a regular file.=0D
+**/=0D
+BOOLEAN=0D
+Ext4FileIsReg (=0D
+ IN CONST EXT4_FILE *File=0D
+ );=0D
+=0D
+// In EFI we can't open FIFO pipes, UNIX sockets, character/block devices =
since these concepts are=0D
+// at the kernel level and are OS dependent.=0D
+=0D
+/**=0D
+ Checks if a file is openable.=0D
+ @param[in] File Pointer to the file trying to be opened.=0D
+=0D
+=0D
+ @return TRUE if file is openable. A file is considered openable if=0D
+ it's a regular file or a directory, since most other file types=
=0D
+ don't make sense under UEFI.=0D
+**/=0D
+#define Ext4FileIsOpenable(File) (Ext4FileIsReg (File) || Ext4FileIsDir (=
File))=0D
+=0D
+#define EXT4_INODE_HAS_FIELD(Inode, \=0D
+ Field) (Inode->i_extra_isize + EXT4_GOOD_OLD=
_INODE_SIZE >=3D OFFSET_OF (EXT4_INODE, Field) + \=0D
+ sizeof (((EXT4_INODE *)NULL)->Field)=
)=0D
+=0D
+/**=0D
+ Calculates the physical space used by a file.=0D
+ @param[in] File Pointer to the opened file.=0D
+=0D
+ @return Physical space used by a file, in bytes.=0D
+**/=0D
+UINT64=0D
+Ext4FilePhysicalSpace (=0D
+ IN EXT4_FILE *File=0D
+ );=0D
+=0D
+/**=0D
+ Gets the file's last access time.=0D
+ @param[in] File Pointer to the opened file.=0D
+ @param[out] Time Pointer to an EFI_TIME structure.=0D
+**/=0D
+VOID=0D
+Ext4FileATime (=0D
+ IN EXT4_FILE *File,=0D
+ OUT EFI_TIME *Time=0D
+ );=0D
+=0D
+/**=0D
+ Gets the file's last (data) modification time.=0D
+ @param[in] File Pointer to the opened file.=0D
+ @param[out] Time Pointer to an EFI_TIME structure.=0D
+**/=0D
+VOID=0D
+Ext4FileMTime (=0D
+ IN EXT4_FILE *File,=0D
+ OUT EFI_TIME *Time=0D
+ );=0D
+=0D
+/**=0D
+ Gets the file's creation time, if possible.=0D
+ @param[in] File Pointer to the opened file.=0D
+ @param[out] Time Pointer to an EFI_TIME structure.=0D
+ In the case where the the creation time isn't re=
corded,=0D
+ Time is zeroed.=0D
+**/=0D
+VOID=0D
+Ext4FileCreateTime (=0D
+ IN EXT4_FILE *File,=0D
+ OUT EFI_TIME *Time=0D
+ );=0D
+=0D
+/**=0D
+ Initialises Unicode collation, which is needed for case-insensitive str=
ing comparisons=0D
+ within the driver (a good example of an application of this is filename=
comparison).=0D
+=0D
+ @param[in] DriverHandle Handle to the driver image.=0D
+=0D
+ @retval EFI_SUCCESS Unicode collation was successfully initialised.=0D
+ @retval !EFI_SUCCESS Failure.=0D
+**/=0D
+EFI_STATUS=0D
+Ext4InitialiseUnicodeCollation (=0D
+ EFI_HANDLE DriverHandle=0D
+ );=0D
+=0D
+/**=0D
+ Does a case-insensitive string comparison. Refer to EFI_UNICODE_COLLATI=
ON_PROTOCOL's StriColl=0D
+ for more details.=0D
+=0D
+ @param[in] Str1 Pointer to a null terminated string.=0D
+ @param[in] Str2 Pointer to a null terminated string.=0D
+=0D
+ @retval 0 Str1 is equivalent to Str2.=0D
+ @retval >0 Str1 is lexically greater than Str2.=0D
+ @retval <0 Str1 is lexically less than Str2.=0D
+**/=0D
+INTN=0D
+Ext4StrCmpInsensitive (=0D
+ IN CHAR16 *Str1,=0D
+ IN CHAR16 *Str2=0D
+ );=0D
+=0D
+/**=0D
+ Retrieves the filename of the directory entry and converts it to UTF-16=
/UCS-2=0D
+=0D
+ @param[in] Entry Pointer to a EXT4_DIR_ENTRY.=0D
+ @param[out] Ucs2FileName Pointer to an array of CHAR16's, of siz=
e EXT4_NAME_MAX + 1.=0D
+=0D
+ @retval EFI_SUCCESS Unicode collation was successfully initialised.=0D
+ @retval !EFI_SUCCESS Failure.=0D
+**/=0D
+EFI_STATUS=0D
+Ext4GetUcs2DirentName (=0D
+ IN EXT4_DIR_ENTRY *Entry,=0D
+ OUT CHAR16 Ucs2FileName[EXT4_NAME_MAX + 1]=0D
+ );=0D
+=0D
+/**=0D
+ Retrieves information about the file and stores it in the EFI_FILE_INFO=
format.=0D
+=0D
+ @param[in] File Pointer to an opened file.=0D
+ @param[out] Info Pointer to a EFI_FILE_INFO.=0D
+ @param[in out] BufferSize Pointer to the buffer size=0D
+=0D
+ @return Status of the file information request.=0D
+**/=0D
+EFI_STATUS=0D
+Ext4GetFileInfo (=0D
+ IN EXT4_FILE *File,=0D
+ OUT EFI_FILE_INFO *Info,=0D
+ IN OUT UINTN *BufferSize=0D
+ );=0D
+=0D
+/**=0D
+ Reads a directory entry.=0D
+=0D
+ @param[in] Partition Pointer to the ext4 partition.=0D
+ @param[in] File Pointer to the open directory.=0D
+ @param[out] Buffer Pointer to the output buffer.=0D
+ @param[in] Offset Initial directory position.=0D
+ @param[in out] OutLength Pointer to a UINTN that contains the length=
of the buffer,=0D
+ and the length of the actual EFI_FILE_INFO =
after the call.=0D
+=0D
+ @return Result of the operation.=0D
+**/=0D
+EFI_STATUS=0D
+Ext4ReadDir (=0D
+ IN EXT4_PARTITION *Partition,=0D
+ IN EXT4_FILE *File,=0D
+ OUT VOID *Buffer,=0D
+ IN UINT64 Offset,=0D
+ IN OUT UINTN *OutLength=0D
+ );=0D
+=0D
+/**=0D
+ Initialises the (empty) extents map, that will work as a cache of exten=
ts.=0D
+=0D
+ @param[in] File Pointer to the open file.=0D
+=0D
+ @return Result of the operation.=0D
+**/=0D
+EFI_STATUS=0D
+Ext4InitExtentsMap (=0D
+ IN EXT4_FILE *File=0D
+ );=0D
+=0D
+/**=0D
+ Frees the extents map, deleting every extent stored.=0D
+=0D
+ @param[in] File Pointer to the open file.=0D
+**/=0D
+VOID=0D
+Ext4FreeExtentsMap (=0D
+ IN EXT4_FILE *File=0D
+ );=0D
+=0D
+/**=0D
+ Calculates the CRC32c checksum of the given buffer.=0D
+=0D
+ @param[in] Buffer Pointer to the buffer.=0D
+ @param[in] Length Length of the buffer, in bytes.=0D
+ @param[in] InitialValue Initial value of the CRC.=0D
+=0D
+ @return The CRC32c checksum.=0D
+**/=0D
+UINT32=0D
+CalculateCrc32c (=0D
+ IN CONST VOID *Buffer,=0D
+ IN UINTN Length,=0D
+ IN UINT32 InitialValue=0D
+ );=0D
+=0D
+/**=0D
+ Calculates the CRC16 checksum of the given buffer.=0D
+=0D
+ @param[in] Buffer Pointer to the buffer.=0D
+ @param[in] Length Length of the buffer, in bytes.=0D
+ @param[in] InitialValue Initial value of the CRC.=0D
+=0D
+ @return The CRC16 checksum.=0D
+**/=0D
+UINT16=0D
+CalculateCrc16 (=0D
+ IN CONST VOID *Buffer,=0D
+ IN UINTN Length,=0D
+ IN UINT16 InitialValue=0D
+ );=0D
+=0D
+/**=0D
+ Calculates the checksum of the given buffer.=0D
+ @param[in] Partition Pointer to the opened EXT4 partition.=0D
+ @param[in] Buffer Pointer to the buffer.=0D
+ @param[in] Length Length of the buffer, in bytes.=0D
+ @param[in] InitialValue Initial value of the CRC.=0D
+=0D
+ @return The checksum.=0D
+**/=0D
+UINT32=0D
+Ext4CalculateChecksum (=0D
+ IN CONST EXT4_PARTITION *Partition,=0D
+ IN CONST VOID *Buffer,=0D
+ IN UINTN Length,=0D
+ IN UINT32 InitialValue=0D
+ );=0D
+=0D
+/**=0D
+ Calculates the checksum of the given inode.=0D
+ @param[in] Partition Pointer to the opened EXT4 partition.=0D
+ @param[in] Inode Pointer to the inode.=0D
+ @param[in] InodeNum Inode number.=0D
+=0D
+ @return The checksum.=0D
+**/=0D
+UINT32=0D
+Ext4CalculateInodeChecksum (=0D
+ IN CONST EXT4_PARTITION *Partition,=0D
+ IN CONST EXT4_INODE *Inode,=0D
+ IN EXT4_INO_NR InodeNum=0D
+ );=0D
+=0D
+/**=0D
+ Checks if the checksum of the inode is correct.=0D
+ @param[in] Partition Pointer to the opened EXT4 partition.=0D
+ @param[in] Inode Pointer to the inode.=0D
+ @param[in] InodeNum Inode number.=0D
+=0D
+ @return TRUE if checksum is correct, FALSE if there is corruption.=0D
+**/=0D
+BOOLEAN=0D
+Ext4CheckInodeChecksum (=0D
+ IN CONST EXT4_PARTITION *Partition,=0D
+ IN CONST EXT4_INODE *Inode,=0D
+ IN EXT4_INO_NR InodeNum=0D
+ );=0D
+=0D
+/**=0D
+ Unmounts and frees an ext4 partition.=0D
+=0D
+ @param[in] Partition Pointer to the opened partition.=0D
+=0D
+ @return Status of the unmount.=0D
+**/=0D
+EFI_STATUS=0D
+Ext4UnmountAndFreePartition (=0D
+ IN EXT4_PARTITION *Partition=0D
+ );=0D
+=0D
+/**=0D
+ Checks if the checksum of the block group descriptor is correct.=0D
+ @param[in] Partition Pointer to the opened EXT4 partition.=0D
+ @param[in] BlockGroupDesc Pointer to the block group descriptor.=
=0D
+ @param[in] BlockGroupNum Number of the block group.=0D
+=0D
+ @return TRUE if checksum is correct, FALSE if there is corruption.=0D
+**/=0D
+BOOLEAN=0D
+Ext4VerifyBlockGroupDescChecksum (=0D
+ IN CONST EXT4_PARTITION *Partition,=0D
+ IN CONST EXT4_BLOCK_GROUP_DESC *BlockGroupDesc,=0D
+ IN UINT32 BlockGroupNum=0D
+ );=0D
+=0D
+/**=0D
+ Calculates the checksum of the block group descriptor.=0D
+ @param[in] Partition Pointer to the opened EXT4 partition.=0D
+ @param[in] BlockGroupDesc Pointer to the block group descriptor.=
=0D
+ @param[in] BlockGroupNum Number of the block group.=0D
+=0D
+ @return The checksum.=0D
+**/=0D
+UINT16=0D
+Ext4CalculateBlockGroupDescChecksum (=0D
+ IN CONST EXT4_PARTITION *Partition,=0D
+ IN CONST EXT4_BLOCK_GROUP_DESC *BlockGroupDesc,=0D
+ IN UINT32 BlockGroupNum=0D
+ );=0D
+=0D
+/**=0D
+ Verifies the existance of a particular RO compat feature set.=0D
+ @param[in] Partition Pointer to the opened EXT4 partitio=
n.=0D
+ @param[in] RoCompatFeatureSet Feature set to test.=0D
+=0D
+ @return TRUE if all features are supported, else FALSE.=0D
+**/=0D
+#define EXT4_HAS_RO_COMPAT(Partition, RoCompatFeatureSet) \=0D
+ ((Partition->FeaturesRoCompat & RoCompatFeatureSet) =3D=3D RoCompatFeatu=
reSet)=0D
+=0D
+/**=0D
+ Verifies the existance of a particular compat feature set.=0D
+ @param[in] Partition Pointer to the opened EXT4 partitio=
n.=0D
+ @param[in] CompatFeatureSet Feature set to test.=0D
+=0D
+ @return TRUE if all features are supported, else FALSE.=0D
+**/=0D
+#define EXT4_HAS_COMPAT(Partition, CompatFeatureSet) \=0D
+ ((Partition->FeaturesCompat & CompatFeatureSet) =3D=3D CompatFeatureSet)=
=0D
+=0D
+/**=0D
+ Verifies the existance of a particular compat feature set.=0D
+ @param[in] Partition Pointer to the opened EXT4 partitio=
n.=0D
+ @param[in] IncompatFeatureSet Feature set to test.=0D
+=0D
+ @return TRUE if all features are supported, else FALSE.=0D
+**/=0D
+#define EXT4_HAS_INCOMPAT(Partition, IncompatFeatureSet) \=0D
+ ((Partition->FeaturesIncompat & IncompatFeatureSet) =3D=3D IncompatFeatu=
reSet)=0D
+=0D
+// Note: Might be a good idea to provide generic Ext4Has$feature() through=
macros.=0D
+=0D
+/**=0D
+ Checks if metadata_csum is enabled on the partition.=0D
+ @param[in] Partition Pointer to the opened EXT4 partitio=
n.=0D
+=0D
+ @return TRUE if the metadata_csum is supported, else FALSE.=0D
+**/=0D
+#define EXT4_HAS_METADATA_CSUM(Partition) \=0D
+ EXT4_HAS_RO_COMPAT (Partition, EXT4_FEATURE_RO_COMPAT_METADATA_CSUM)=0D
+=0D
+/**=0D
+ Checks if gdt_csum is enabled on the partition.=0D
+ @param[in] Partition Pointer to the opened EXT4 partitio=
n.=0D
+=0D
+ @return TRUE if the gdt_csum is supported, else FALSE.=0D
+**/=0D
+#define EXT4_HAS_GDT_CSUM(Partition) \=0D
+ EXT4_HAS_RO_COMPAT (Partition, EXT4_FEATURE_RO_COMPAT_METADATA_CSUM)=0D
+=0D
+#endif=0D
diff --git a/Features/Ext4Pkg/Ext4Dxe/Ext4Dxe.inf b/Features/Ext4Pkg/Ext4Dx=
e/Ext4Dxe.inf
new file mode 100644
index 0000000000..6533de6247
--- /dev/null
+++ b/Features/Ext4Pkg/Ext4Dxe/Ext4Dxe.inf
@@ -0,0 +1,149 @@
+## @file=0D
+# Ext4 Package=0D
+#=0D
+# UEFI Driver that produces the Simple File System Protocol for a partiti=
on that is formatted=0D
+# with the EXT4 file system.=0D
+# More details are available at: https://www.kernel.org/doc/html/v5.4/fil=
esystems/ext4/index.html=0D
+#=0D
+# Copyright (c) 2021 Pedro Falcato=0D
+# SPDX-License-Identifier: BSD-2-Clause-Patent=0D
+#=0D
+# Layout of an EXT2/3/4 filesystem:=0D
+# (note: this driver has been developed using=0D
+# https://www.kernel.org/doc/html/latest/filesystems/ext4/index.html as=
=0D
+# documentation).=0D
+#=0D
+# An ext2/3/4 filesystem (here on out referred to as simply an ext4 file=
system,=0D
+# due to the similarities) is composed of various concepts:=0D
+#=0D
+# 1) Superblock=0D
+# The superblock is the structure near (1024 bytes offset from the st=
art)=0D
+# the start of the partition, and describes the filesystem in general=
.=0D
+# Here, we get to know the size of the filesystem's blocks, which fea=
tures=0D
+# it supports or not, whether it's been cleanly unmounted, how many b=
locks=0D
+# we have, etc.=0D
+#=0D
+# 2) Block groups=0D
+# EXT4 filesystems are divided into block groups, and each block grou=
p covers=0D
+# s_blocks_per_group(8 * Block Size) blocks. Each block group has an=
=0D
+# associated block group descriptor; these are present directly after=
the=0D
+# superblock. Each block group descriptor contains the location of th=
e=0D
+# inode table, and the inode and block bitmaps (note these bitmaps ar=
e only=0D
+# a block long, which gets us the 8 * Block Size formula covered prev=
iously).=0D
+#=0D
+# 3) Blocks=0D
+# The ext4 filesystem is divided in blocks, of size s_log_block_size =
^ 1024.=0D
+# Blocks can be allocated using individual block groups's bitmaps. No=
te=0D
+# that block 0 is invalid and its presence on extents/block tables me=
ans=0D
+# it's part of a file hole, and that particular location must be read=
as=0D
+# a block full of zeros.=0D
+#=0D
+# 4) Inodes=0D
+# The ext4 filesystem divides files/directories into inodes (original=
ly=0D
+# index nodes). Each file/socket/symlink/directory/etc (here on out r=
eferred=0D
+# to as a file, since there is no distinction under the ext4 filesyst=
em) is=0D
+# stored as a /nameless/ inode, that is stored in some block group's =
inode=0D
+# table. Each inode has s_inode_size size (or GOOD_OLD_INODE_SIZE if =
it's=0D
+# an old filesystem), and holds various metadata about the file. Sinc=
e the=0D
+# largest inode structure right now is ~160 bytes, the rest of the in=
ode=0D
+# contains inline extended attributes. Inodes' data is stored using e=
ither=0D
+# data blocks (under ext2/3) or extents (under ext4).=0D
+#=0D
+# 5) Extents=0D
+# Ext4 inodes store data in extents. These let N contiguous logical b=
locks=0D
+# that are represented by N contiguous physical blocks be represented=
by a=0D
+# single extent structure, which minimizes filesystem metadata bloat =
and=0D
+# speeds up block mapping (particularly due to the fact that high-qua=
lity=0D
+# ext4 implementations like linux's try /really/ hard to make the fil=
e=0D
+# contiguous, so it's common to have files with almost 0 fragmentatio=
n).=0D
+# Inodes that use extents store them in a tree, and the top of the tr=
ee=0D
+# is stored on i_data. The tree's leaves always start with an=0D
+# EXT4_EXTENT_HEADER and contain EXT4_EXTENT_INDEX on eh_depth !=3D 0=
and=0D
+# EXT4_EXTENT on eh_depth =3D 0; these entries are always sorted by l=
ogical=0D
+# block.=0D
+#=0D
+# 6) Directories=0D
+# Ext4 directories are files that store name -> inode mappings for th=
e=0D
+# logical directory; this is where files get their names, which means=
ext4=0D
+# inodes do not themselves have names, since they can be linked (pres=
ent)=0D
+# multiple times with different names. Directories can store entries =
in two=0D
+# different ways:=0D
+# 1) Classical linear directories: They store entries as a mostly-l=
inked=0D
+# mostly-list of EXT4_DIR_ENTRY.=0D
+# 2) Hash tree directories: These are used for larger directories, =
with=0D
+# hundreds of entries, and are designed in a backwards compatibl=
e way.=0D
+# These are not yet implemented in the Ext4Dxe driver.=0D
+#=0D
+# 7) Journal=0D
+# Ext3/4 filesystems have a journal to help protect the filesystem ag=
ainst=0D
+# system crashes. This is not yet implemented in Ext4Dxe but is descr=
ibed=0D
+# in detail in the Linux kernel's documentation.=0D
+##=0D
+=0D
+=0D
+[Defines]=0D
+ INF_VERSION =3D 0x00010005=0D
+ BASE_NAME =3D Ext4Dxe=0D
+ MODULE_UNI_FILE =3D Ext4Dxe.uni=0D
+ FILE_GUID =3D 75F2B676-D73B-45CB-B7C1-303C7F4E6FD6=
=0D
+ MODULE_TYPE =3D UEFI_DRIVER=0D
+ VERSION_STRING =3D 1.0=0D
+=0D
+ ENTRY_POINT =3D Ext4EntryPoint=0D
+ UNLOAD_IMAGE =3D Ext4Unload=0D
+=0D
+#=0D
+# The following information is for reference only and not required by the =
build tools.=0D
+#=0D
+# VALID_ARCHITECTURES =3D IA32 X64 EBC=0D
+#=0D
+=0D
+[Sources]=0D
+ Ext4Dxe.c=0D
+ Partition.c=0D
+ DiskUtil.c=0D
+ Superblock.c=0D
+ BlockGroup.c=0D
+ Inode.c=0D
+ Directory.c=0D
+ Extents.c=0D
+ File.c=0D
+ Collation.c=0D
+ Crc32c.c=0D
+ Crc16.c=0D
+ Ext4Disk.h=0D
+ Ext4Dxe.h=0D
+=0D
+[Packages]=0D
+ MdePkg/MdePkg.dec=0D
+ RedfishPkg/RedfishPkg.dec=0D
+=0D
+[LibraryClasses]=0D
+ UefiRuntimeServicesTableLib=0D
+ UefiBootServicesTableLib=0D
+ MemoryAllocationLib=0D
+ BaseMemoryLib=0D
+ BaseLib=0D
+ UefiLib=0D
+ UefiDriverEntryPoint=0D
+ DebugLib=0D
+ PcdLib=0D
+ OrderedCollectionLib=0D
+ BaseUcs2Utf8Lib=0D
+=0D
+[Guids]=0D
+ gEfiFileInfoGuid ## SOMETIMES_CONSUMES ## UNDEFIN=
ED=0D
+ gEfiFileSystemInfoGuid ## SOMETIMES_CONSUMES ## UNDEFIN=
ED=0D
+ gEfiFileSystemVolumeLabelInfoIdGuid ## SOMETIMES_CONSUMES ## UNDEFIN=
ED=0D
+=0D
+[Protocols]=0D
+ gEfiDiskIoProtocolGuid ## TO_START=0D
+ gEfiDiskIo2ProtocolGuid ## TO_START=0D
+ gEfiBlockIoProtocolGuid ## TO_START=0D
+ gEfiSimpleFileSystemProtocolGuid ## BY_START=0D
+ gEfiUnicodeCollationProtocolGuid ## TO_START=0D
+ gEfiUnicodeCollation2ProtocolGuid ## TO_START=0D
+=0D
+[Pcd]=0D
+ gEfiMdePkgTokenSpaceGuid.PcdUefiVariableDefaultLang ## SOMETIM=
ES_CONSUMES=0D
+ gEfiMdePkgTokenSpaceGuid.PcdUefiVariableDefaultPlatformLang ## SOMETIM=
ES_CONSUMES=0D
diff --git a/Features/Ext4Pkg/Ext4Dxe/Ext4Dxe.uni b/Features/Ext4Pkg/Ext4Dx=
e/Ext4Dxe.uni
new file mode 100644
index 0000000000..7476fbf9bd
--- /dev/null
+++ b/Features/Ext4Pkg/Ext4Dxe/Ext4Dxe.uni
@@ -0,0 +1,15 @@
+## @file=0D
+# Ext4 Package=0D
+#=0D
+# UEFI Driver that produces the Simple File System Protocol for a partiti=
on that is formatted=0D
+# with the EXT4 file system.=0D
+# More details are available at: https://www.kernel.org/doc/html/v5.4/fil=
esystems/ext4/index.html=0D
+#=0D
+# Copyright (c) 2021 Pedro Falcato=0D
+# SPDX-License-Identifier: BSD-2-Clause-Patent=0D
+#=0D
+##=0D
+=0D
+#string STR_MODULE_ABSTRACT #language en-US "UEFI driver for th=
e EXT4 file system."=0D
+=0D
+#string STR_MODULE_DESCRIPTION #language en-US "Produces the EFI S=
imple File System protocol."=0D
diff --git a/Features/Ext4Pkg/Ext4Dxe/Extents.c b/Features/Ext4Pkg/Ext4Dxe/=
Extents.c
new file mode 100644
index 0000000000..5fa2fe098d
--- /dev/null
+++ b/Features/Ext4Pkg/Ext4Dxe/Extents.c
@@ -0,0 +1,595 @@
+/** @file=0D
+ Extent related routines=0D
+=0D
+ Copyright (c) 2021 Pedro Falcato All rights reserved.=0D
+ SPDX-License-Identifier: BSD-2-Clause-Patent=0D
+**/=0D
+=0D
+#include "Ext4Dxe.h"=0D
+=0D
+/**=0D
+ Checks if the checksum of the extent data block is correct.=0D
+ @param[in] ExtHeader Pointer to the EXT4_EXTENT_HEADER.=0D
+ @param[in] File Pointer to the file.=0D
+=0D
+ @return TRUE if the checksum is correct, FALSE if there is corruption.=
=0D
+**/=0D
+BOOLEAN=0D
+Ext4CheckExtentChecksum (=0D
+ IN CONST EXT4_EXTENT_HEADER *ExtHeader,=0D
+ IN CONST EXT4_FILE *File=0D
+ );=0D
+=0D
+/**=0D
+ Calculates the checksum of the extent data block.=0D
+ @param[in] ExtHeader Pointer to the EXT4_EXTENT_HEADER.=0D
+ @param[in] File Pointer to the file.=0D
+=0D
+ @return The checksum.=0D
+**/=0D
+UINT32=0D
+Ext4CalculateExtentChecksum (=0D
+ IN CONST EXT4_EXTENT_HEADER *ExtHeader,=0D
+ IN CONST EXT4_FILE *File=0D
+ );=0D
+=0D
+/**=0D
+ Caches a range of extents, by allocating pool memory for each extent an=
d adding it to the tree.=0D
+=0D
+ @param[in] File Pointer to the open file.=0D
+ @param[in] Extents Pointer to an array of extents.=0D
+ @param[in] NumberExtents Length of the array.=0D
+**/=0D
+VOID=0D
+Ext4CacheExtents (=0D
+ IN EXT4_FILE *File,=0D
+ IN CONST EXT4_EXTENT *Extents,=0D
+ IN UINT16 NumberExtents=0D
+ );=0D
+=0D
+/**=0D
+ Gets an extent from the extents cache of the file.=0D
+=0D
+ @param[in] File Pointer to the open file.=0D
+ @param[in] Block Block we want to grab.=0D
+=0D
+ @return Pointer to the extent, or NULL if it was not found.=0D
+**/=0D
+EXT4_EXTENT *=0D
+Ext4GetExtentFromMap (=0D
+ IN EXT4_FILE *File,=0D
+ IN UINT32 Block=0D
+ );=0D
+=0D
+/**=0D
+ Retrieves the pointer to the top of the extent tree.=0D
+ @param[in] Inode Pointer to the inode structure.=0D
+=0D
+ @return Pointer to an EXT4_EXTENT_HEADER. This pointer is inside=0D
+ the inode and must not be freed.=0D
+**/=0D
+STATIC=0D
+EXT4_EXTENT_HEADER *=0D
+Ext4GetInoExtentHeader (=0D
+ IN EXT4_INODE *Inode=0D
+ )=0D
+{=0D
+ return (EXT4_EXTENT_HEADER *)Inode->i_data;=0D
+}=0D
+=0D
+/**=0D
+ Checks if an extent header is valid.=0D
+ @param[in] Header Pointer to the EXT4_EXTENT_HEADER struct=
ure.=0D
+=0D
+ @return TRUE if valid, FALSE if not.=0D
+**/=0D
+STATIC=0D
+BOOLEAN=0D
+Ext4ExtentHeaderValid (=0D
+ IN CONST EXT4_EXTENT_HEADER *Header=0D
+ )=0D
+{=0D
+ if (Header->eh_depth > EXT4_EXTENT_TREE_MAX_DEPTH) {=0D
+ DEBUG ((DEBUG_ERROR, "[ext4] Invalid extent header depth %u\n", Header=
->eh_depth));=0D
+ return FALSE;=0D
+ }=0D
+=0D
+ if (Header->eh_magic !=3D EXT4_EXTENT_HEADER_MAGIC) {=0D
+ DEBUG ((DEBUG_ERROR, "[ext4] Invalid extent header magic %x\n", Header=
->eh_magic));=0D
+ return FALSE;=0D
+ }=0D
+=0D
+ if (Header->eh_max < Header->eh_entries) {=0D
+ DEBUG ((=0D
+ DEBUG_ERROR,=0D
+ "[ext4] Invalid extent header num entries %u max entries %u\n",=0D
+ Header->eh_entries,=0D
+ Header->eh_max=0D
+ ));=0D
+ return FALSE;=0D
+ }=0D
+=0D
+ return TRUE;=0D
+}=0D
+=0D
+/**=0D
+ Performs a binary search for a EXT4_EXTENT_INDEX that corresponds to a=
=0D
+ logical block in a given extent tree node.=0D
+=0D
+ @param[in] Header Pointer to the EXT4_EXTENT_HEADER struct=
ure.=0D
+ @param[in] LogicalBlock Block that will be searched=0D
+=0D
+ @return Pointer to the found EXT4_EXTENT_INDEX.=0D
+**/=0D
+STATIC=0D
+EXT4_EXTENT_INDEX *=0D
+Ext4BinsearchExtentIndex (=0D
+ IN EXT4_EXTENT_HEADER *Header,=0D
+ IN EXT4_BLOCK_NR LogicalBlock=0D
+ )=0D
+{=0D
+ EXT4_EXTENT_INDEX *l;=0D
+ EXT4_EXTENT_INDEX *r;=0D
+ EXT4_EXTENT_INDEX *m;=0D
+=0D
+ l =3D ((EXT4_EXTENT_INDEX *)(Header + 1)) + 1;=0D
+ r =3D ((EXT4_EXTENT_INDEX *)(Header + 1)) + Header->eh_entries - 1;=0D
+=0D
+ // Perform a mostly-standard binary search on the array=0D
+ // This works very nicely because the extents arrays are always sorted.=
=0D
+=0D
+ while (l <=3D r) {=0D
+ m =3D l + (r - l) / 2;=0D
+=0D
+ if (LogicalBlock < m->ei_block) {=0D
+ r =3D m - 1;=0D
+ } else {=0D
+ l =3D m + 1;=0D
+ }=0D
+ }=0D
+=0D
+ return l - 1;=0D
+}=0D
+=0D
+/**=0D
+ Performs a binary search for a EXT4_EXTENT that corresponds to a=0D
+ logical block in a given extent tree node.=0D
+=0D
+ @param[in] Header Pointer to the EXT4_EXTENT_HEADER struct=
ure.=0D
+ @param[in] LogicalBlock Block that will be searched=0D
+=0D
+ @return Pointer to the found EXT4_EXTENT_INDEX, else NULL if the array =
is empty.=0D
+ Note: The caller must check if the logical block=0D
+ is actually mapped under the given extent.=0D
+**/=0D
+STATIC=0D
+EXT4_EXTENT *=0D
+Ext4BinsearchExtentExt (=0D
+ IN EXT4_EXTENT_HEADER *Header,=0D
+ IN EXT4_BLOCK_NR LogicalBlock=0D
+ )=0D
+{=0D
+ EXT4_EXTENT *l;=0D
+ EXT4_EXTENT *r;=0D
+ EXT4_EXTENT *m;=0D
+=0D
+ l =3D ((EXT4_EXTENT *)(Header + 1)) + 1;=0D
+ r =3D ((EXT4_EXTENT *)(Header + 1)) + Header->eh_entries - 1;=0D
+ // Perform a mostly-standard binary search on the array=0D
+ // This works very nicely because the extents arrays are always sorted.=
=0D
+=0D
+ // Empty array=0D
+ if (Header->eh_entries =3D=3D 0) {=0D
+ return NULL;=0D
+ }=0D
+=0D
+ while (l <=3D r) {=0D
+ m =3D l + (r - l) / 2;=0D
+=0D
+ if (LogicalBlock < m->ee_block) {=0D
+ r =3D m - 1;=0D
+ } else {=0D
+ l =3D m + 1;=0D
+ }=0D
+ }=0D
+=0D
+ return l - 1;=0D
+}=0D
+=0D
+/**=0D
+ Retrieves the leaf block from an EXT4_EXTENT_INDEX.=0D
+=0D
+ @param[in] Index Pointer to the EXT4_EXTENT_INDEX structu=
re.=0D
+=0D
+ @return Block number of the leaf node.=0D
+**/=0D
+STATIC=0D
+EXT4_BLOCK_NR=0D
+Ext4ExtentIdxLeafBlock (=0D
+ IN EXT4_EXTENT_INDEX *Index=0D
+ )=0D
+{=0D
+ return LShiftU64 (Index->ei_leaf_hi, 32) | Index->ei_leaf_lo;=0D
+}=0D
+=0D
+/**=0D
+ Retrieves an extent from an EXT4 inode.=0D
+ @param[in] Partition Pointer to the opened EXT4 partition.=0D
+ @param[in] File Pointer to the opened file.=0D
+ @param[in] LogicalBlock Block number which the returned extent mu=
st cover.=0D
+ @param[out] Extent Pointer to the output buffer, where the e=
xtent will be copied to.=0D
+=0D
+ @retval EFI_SUCCESS Retrieval was succesful.=0D
+ @retval EFI_NO_MAPPING Block has no mapping.=0D
+**/=0D
+EFI_STATUS=0D
+Ext4GetExtent (=0D
+ IN EXT4_PARTITION *Partition,=0D
+ IN EXT4_FILE *File,=0D
+ IN EXT4_BLOCK_NR LogicalBlock,=0D
+ OUT EXT4_EXTENT *Extent=0D
+ )=0D
+{=0D
+ EXT4_INODE *Inode;=0D
+ VOID *Buffer;=0D
+ EXT4_EXTENT *Ext;=0D
+ UINT32 CurrentDepth;=0D
+ EXT4_EXTENT_HEADER *ExtHeader;=0D
+ EXT4_EXTENT_INDEX *Index;=0D
+ EFI_STATUS Status;=0D
+=0D
+ Inode =3D File->Inode;=0D
+ Ext =3D NULL;=0D
+ Buffer =3D NULL;=0D
+=0D
+ DEBUG ((DEBUG_FS, "[ext4] Looking up extent for block %lu\n", LogicalBlo=
ck));=0D
+=0D
+ if (!(Inode->i_flags & EXT4_EXTENTS_FL)) {=0D
+ return EFI_UNSUPPORTED;=0D
+ }=0D
+=0D
+ // ext4 does not have support for logical block numbers bigger than UINT=
32_MAX=0D
+ if (LogicalBlock > (UINT32)- 1) {=0D
+ return EFI_NO_MAPPING;=0D
+ }=0D
+=0D
+ // Note: Right now, holes are the single biggest reason for cache misses=
=0D
+ // We should find a way to get (or cache) holes=0D
+ if ((Ext =3D Ext4GetExtentFromMap (File, (UINT32)LogicalBlock)) !=3D NUL=
L) {=0D
+ *Extent =3D *Ext;=0D
+=0D
+ return EFI_SUCCESS;=0D
+ }=0D
+=0D
+ // Slow path, we'll need to read from disk and (try to) cache those exte=
nts.=0D
+=0D
+ ExtHeader =3D Ext4GetInoExtentHeader (Inode);=0D
+=0D
+ if (!Ext4ExtentHeaderValid (ExtHeader)) {=0D
+ return EFI_VOLUME_CORRUPTED;=0D
+ }=0D
+=0D
+ CurrentDepth =3D ExtHeader->eh_depth;=0D
+=0D
+ while (ExtHeader->eh_depth !=3D 0) {=0D
+ CurrentDepth--;=0D
+ // While depth !=3D 0, we're traversing the tree itself and not any le=
aves=0D
+ // As such, every entry is an EXT4_EXTENT_INDEX entry=0D
+ // Note: Entries after the extent header, either index or actual exten=
t, are always sorted.=0D
+ // Therefore, we can use binary search, and it's actually the standard=
for doing so=0D
+ // (see FreeBSD).=0D
+=0D
+ Index =3D Ext4BinsearchExtentIndex (ExtHeader, LogicalBlock);=0D
+=0D
+ if (Buffer =3D=3D NULL) {=0D
+ Buffer =3D AllocatePool (Partition->BlockSize);=0D
+ if (Buffer =3D=3D NULL) {=0D
+ return EFI_OUT_OF_RESOURCES;=0D
+ }=0D
+ }=0D
+=0D
+ // Read the leaf block onto the previously-allocated buffer.=0D
+=0D
+ Status =3D Ext4ReadBlocks (Partition, Buffer, 1, Ext4ExtentIdxLeafBloc=
k (Index));=0D
+ if (EFI_ERROR (Status)) {=0D
+ FreePool (Buffer);=0D
+ return Status;=0D
+ }=0D
+=0D
+ ExtHeader =3D Buffer;=0D
+=0D
+ if (!Ext4ExtentHeaderValid (ExtHeader)) {=0D
+ FreePool (Buffer);=0D
+ return EFI_VOLUME_CORRUPTED;=0D
+ }=0D
+=0D
+ if (!Ext4CheckExtentChecksum (ExtHeader, File)) {=0D
+ DEBUG ((DEBUG_ERROR, "[ext4] Invalid extent checksum\n"));=0D
+ FreePool (Buffer);=0D
+ return EFI_VOLUME_CORRUPTED;=0D
+ }=0D
+=0D
+ if (ExtHeader->eh_depth !=3D CurrentDepth) {=0D
+ FreePool (Buffer);=0D
+ return EFI_VOLUME_CORRUPTED;=0D
+ }=0D
+ }=0D
+=0D
+ /* We try to cache every extent under a single leaf, since it's quite li=
kely that we=0D
+ * may need to access things sequentially. Furthermore, ext4 block alloc=
ation as done=0D
+ * by linux (and possibly other systems) is quite fancy and usually it r=
esults in a small number of extents.=0D
+ * Therefore, we shouldn't have any memory issues.=0D
+ **/=0D
+ Ext4CacheExtents (File, (EXT4_EXTENT *)(ExtHeader + 1), ExtHeader->eh_en=
tries);=0D
+=0D
+ Ext =3D Ext4BinsearchExtentExt (ExtHeader, LogicalBlock);=0D
+=0D
+ if (!Ext) {=0D
+ if (Buffer !=3D NULL) {=0D
+ FreePool (Buffer);=0D
+ }=0D
+=0D
+ return EFI_NO_MAPPING;=0D
+ }=0D
+=0D
+ if (!(LogicalBlock >=3D Ext->ee_block && Ext->ee_block + Ext->ee_len > L=
ogicalBlock)) {=0D
+ // This extent does not cover the block=0D
+ if (Buffer !=3D NULL) {=0D
+ FreePool (Buffer);=0D
+ }=0D
+=0D
+ return EFI_NO_MAPPING;=0D
+ }=0D
+=0D
+ *Extent =3D *Ext;=0D
+=0D
+ if (Buffer !=3D NULL) {=0D
+ FreePool (Buffer);=0D
+ }=0D
+=0D
+ return EFI_SUCCESS;=0D
+}=0D
+=0D
+/**=0D
+ Compare two EXT4_EXTENT structs.=0D
+ Used in the extent map's ORDERED_COLLECTION.=0D
+=0D
+ @param[in] UserStruct1 Pointer to the first user structure.=0D
+=0D
+ @param[in] UserStruct2 Pointer to the second user structure.=0D
+=0D
+ @retval <0 If UserStruct1 compares less than UserStruct2.=0D
+=0D
+ @retval 0 If UserStruct1 compares equal to UserStruct2.=0D
+=0D
+ @retval >0 If UserStruct1 compares greater than UserStruct2.=0D
+**/=0D
+STATIC=0D
+INTN=0D
+EFIAPI=0D
+Ext4ExtentsMapStructCompare (=0D
+ IN CONST VOID *UserStruct1,=0D
+ IN CONST VOID *UserStruct2=0D
+ )=0D
+{=0D
+ CONST EXT4_EXTENT *Extent1;=0D
+ CONST EXT4_EXTENT *Extent2;=0D
+=0D
+ Extent1 =3D UserStruct1;=0D
+ Extent2 =3D UserStruct2;=0D
+=0D
+ return Extent1->ee_block < Extent2->ee_block ? - 1 :=0D
+ Extent1->ee_block > Extent2->ee_block ? 1 : 0;=0D
+}=0D
+=0D
+/**=0D
+ Compare a standalone key against a EXT4_EXTENT containing an embedded ke=
y.=0D
+ Used in the extent map's ORDERED_COLLECTION.=0D
+=0D
+ @param[in] StandaloneKey Pointer to the bare key.=0D
+=0D
+ @param[in] UserStruct Pointer to the user structure with the embedde=
d=0D
+ key.=0D
+=0D
+ @retval <0 If StandaloneKey compares less than UserStruct's key.=0D
+=0D
+ @retval 0 If StandaloneKey compares equal to UserStruct's key.=0D
+=0D
+ @retval >0 If StandaloneKey compares greater than UserStruct's key.=0D
+**/=0D
+STATIC=0D
+INTN=0D
+EFIAPI=0D
+Ext4ExtentsMapKeyCompare (=0D
+ IN CONST VOID *StandaloneKey,=0D
+ IN CONST VOID *UserStruct=0D
+ )=0D
+{=0D
+ CONST EXT4_EXTENT *Extent;=0D
+ UINT32 Block;=0D
+=0D
+ // Note that logical blocks are 32-bits in size so no truncation can hap=
pen here=0D
+ // with regards to 32-bit architectures.=0D
+ Extent =3D UserStruct;=0D
+ Block =3D (UINT32)(UINTN)StandaloneKey;=0D
+=0D
+ if (Block >=3D Extent->ee_block && Block < Extent->ee_block + Extent->ee=
_len) {=0D
+ return 0;=0D
+ }=0D
+=0D
+ return Block < Extent->ee_block ? - 1 :=0D
+ Block > Extent->ee_block ? 1 : 0;=0D
+}=0D
+=0D
+/**=0D
+ Initialises the (empty) extents map, that will work as a cache of exten=
ts.=0D
+=0D
+ @param[in] File Pointer to the open file.=0D
+=0D
+ @return Result of the operation.=0D
+**/=0D
+EFI_STATUS=0D
+Ext4InitExtentsMap (=0D
+ IN EXT4_FILE *File=0D
+ )=0D
+{=0D
+ File->ExtentsMap =3D OrderedCollectionInit (Ext4ExtentsMapStructCompare,=
Ext4ExtentsMapKeyCompare);=0D
+ if (!File->ExtentsMap) {=0D
+ return EFI_OUT_OF_RESOURCES;=0D
+ }=0D
+=0D
+ return EFI_SUCCESS;=0D
+}=0D
+=0D
+/**=0D
+ Frees the extents map, deleting every extent stored.=0D
+=0D
+ @param[in] File Pointer to the open file.=0D
+**/=0D
+VOID=0D
+Ext4FreeExtentsMap (=0D
+ IN EXT4_FILE *File=0D
+ )=0D
+{=0D
+ // Keep calling Min(), so we get an arbitrary node we can delete.=0D
+ // If Min() returns NULL, it's empty.=0D
+=0D
+ ORDERED_COLLECTION_ENTRY *MinEntry;=0D
+ EXT4_EXTENT *Ext;=0D
+=0D
+ MinEntry =3D NULL;=0D
+=0D
+ while ((MinEntry =3D OrderedCollectionMin (File->ExtentsMap)) !=3D NULL)=
{=0D
+ OrderedCollectionDelete (File->ExtentsMap, MinEntry, (VOID **)&Ext);=0D
+ FreePool (Ext);=0D
+ }=0D
+=0D
+ ASSERT (OrderedCollectionIsEmpty (File->ExtentsMap));=0D
+=0D
+ OrderedCollectionUninit (File->ExtentsMap);=0D
+ File->ExtentsMap =3D NULL;=0D
+}=0D
+=0D
+/**=0D
+ Caches a range of extents, by allocating pool memory for each extent an=
d adding it to the tree.=0D
+=0D
+ @param[in] File Pointer to the open file.=0D
+ @param[in] Extents Pointer to an array of extents.=0D
+ @param[in] NumberExtents Length of the array.=0D
+**/=0D
+VOID=0D
+Ext4CacheExtents (=0D
+ IN EXT4_FILE *File,=0D
+ IN CONST EXT4_EXTENT *Extents,=0D
+ IN UINT16 NumberExtents=0D
+ )=0D
+{=0D
+ UINT16 Idx;=0D
+ EXT4_EXTENT *Extent;=0D
+ EFI_STATUS Status;=0D
+=0D
+ /* Note that any out of memory condition might mean we don't get to cach=
e a whole leaf of extents=0D
+ * in which case, future insertions might fail.=0D
+ */=0D
+=0D
+ for (Idx =3D 0; Idx < NumberExtents; Idx++, Extents++) {=0D
+ Extent =3D AllocatePool (sizeof (EXT4_EXTENT));=0D
+=0D
+ if (Extent =3D=3D NULL) {=0D
+ return;=0D
+ }=0D
+=0D
+ CopyMem (Extent, Extents, sizeof (EXT4_EXTENT));=0D
+ Status =3D OrderedCollectionInsert (File->ExtentsMap, NULL, Extent);=0D
+=0D
+ // EFI_ALREADY_STARTED =3D already exists in the tree.=0D
+ if (EFI_ERROR (Status)) {=0D
+ FreePool (Extent);=0D
+=0D
+ if (Status =3D=3D EFI_ALREADY_STARTED) {=0D
+ continue;=0D
+ }=0D
+=0D
+ return;=0D
+ }=0D
+ }=0D
+}=0D
+=0D
+/**=0D
+ Gets an extent from the extents cache of the file.=0D
+=0D
+ @param[in] File Pointer to the open file.=0D
+ @param[in] Block Block we want to grab.=0D
+=0D
+ @return Pointer to the extent, or NULL if it was not found.=0D
+**/=0D
+EXT4_EXTENT *=0D
+Ext4GetExtentFromMap (=0D
+ IN EXT4_FILE *File,=0D
+ IN UINT32 Block=0D
+ )=0D
+{=0D
+ ORDERED_COLLECTION_ENTRY *Entry;=0D
+=0D
+ Entry =3D OrderedCollectionFind (File->ExtentsMap, (CONST VOID *)(UINTN)=
Block);=0D
+=0D
+ if (Entry =3D=3D NULL) {=0D
+ return NULL;=0D
+ }=0D
+=0D
+ return OrderedCollectionUserStruct (Entry);=0D
+}=0D
+=0D
+/**=0D
+ Calculates the checksum of the extent data block.=0D
+ @param[in] ExtHeader Pointer to the EXT4_EXTENT_HEADER.=0D
+ @param[in] File Pointer to the file.=0D
+=0D
+ @return The checksum.=0D
+**/=0D
+UINT32=0D
+Ext4CalculateExtentChecksum (=0D
+ IN CONST EXT4_EXTENT_HEADER *ExtHeader,=0D
+ IN CONST EXT4_FILE *File=0D
+ )=0D
+{=0D
+ UINT32 Csum;=0D
+ EXT4_PARTITION *Partition;=0D
+ EXT4_INODE *Inode;=0D
+=0D
+ Partition =3D File->Partition;=0D
+ Inode =3D File->Inode;=0D
+=0D
+ Csum =3D Ext4CalculateChecksum (Partition, &File->InodeNum, sizeof (EXT4=
_INO_NR), Partition->InitialSeed);=0D
+ Csum =3D Ext4CalculateChecksum (Partition, &Inode->i_generation, sizeof =
(Inode->i_generation), Csum);=0D
+ Csum =3D Ext4CalculateChecksum (Partition, ExtHeader, Partition->BlockSi=
ze - sizeof (EXT4_EXTENT_TAIL), Csum);=0D
+=0D
+ return Csum;=0D
+}=0D
+=0D
+/**=0D
+ Checks if the checksum of the extent data block is correct.=0D
+ @param[in] ExtHeader Pointer to the EXT4_EXTENT_HEADER.=0D
+ @param[in] File Pointer to the file.=0D
+=0D
+ @return TRUE if the checksum is correct, FALSE if there is corruption.=
=0D
+**/=0D
+BOOLEAN=0D
+Ext4CheckExtentChecksum (=0D
+ IN CONST EXT4_EXTENT_HEADER *ExtHeader,=0D
+ IN CONST EXT4_FILE *File=0D
+ )=0D
+{=0D
+ EXT4_PARTITION *Partition;=0D
+ EXT4_EXTENT_TAIL *Tail;=0D
+=0D
+ Partition =3D File->Partition;=0D
+=0D
+ if (!EXT4_HAS_METADATA_CSUM (Partition)) {=0D
+ return TRUE;=0D
+ }=0D
+=0D
+ Tail =3D (EXT4_EXTENT_TAIL *)((CONST CHAR8 *)ExtHeader + (Partition->Blo=
ckSize - 4));=0D
+=0D
+ return Tail->eb_checksum =3D=3D Ext4CalculateExtentChecksum (ExtHeader, =
File);=0D
+}=0D
diff --git a/Features/Ext4Pkg/Ext4Dxe/File.c b/Features/Ext4Pkg/Ext4Dxe/Fil=
e.c
new file mode 100644
index 0000000000..0f5fa6f73f
--- /dev/null
+++ b/Features/Ext4Pkg/Ext4Dxe/File.c
@@ -0,0 +1,787 @@
+/** @file=0D
+ EFI_FILE_PROTOCOL implementation for EXT4=0D
+=0D
+ Copyright (c) 2021 Pedro Falcato All rights reserved.=0D
+ SPDX-License-Identifier: BSD-2-Clause-Patent=0D
+**/=0D
+=0D
+#include "Ext4Dxe.h"=0D
+=0D
+#include <Library/BaseUcs2Utf8Lib.h>=0D
+=0D
+/**=0D
+ Duplicates a file structure.=0D
+=0D
+ @param[in] Original Pointer to the original file.=0D
+=0D
+ @return Pointer to the new file structure.=0D
+**/=0D
+STATIC=0D
+EXT4_FILE *=0D
+Ext4DuplicateFile (=0D
+ IN CONST EXT4_FILE *Original=0D
+ );=0D
+=0D
+/**=0D
+ Gets the next path segment.=0D
+=0D
+ @param[in] Path Pointer to the rest of the path.=0D
+ @param[out] PathSegment Pointer to the buffer that will hold the =
path segment.=0D
+ Note: It's necessarily EXT4_NAME_MAX +1 l=
ong.=0D
+ @param[out] Length Pointer to the UINTN that will hold the l=
ength of the path segment.=0D
+=0D
+ @retval !EFI_SUCCESS The path segment is too large(> EXT4_NAME=
_MAX).=0D
+**/=0D
+STATIC=0D
+EFI_STATUS=0D
+GetPathSegment (=0D
+ IN CONST CHAR16 *Path, OUT CHAR16 *PathSegment, OUT UINTN *Length=0D
+ )=0D
+{=0D
+ CONST CHAR16 *Start;=0D
+ CONST CHAR16 *End;=0D
+=0D
+ Start =3D Path;=0D
+ End =3D Path;=0D
+=0D
+ // The path segment ends on a backslash or a null terminator=0D
+ for ( ; *End !=3D L'\0' && *End !=3D L'\\'; End++) {=0D
+ }=0D
+=0D
+ *Length =3D End - Start;=0D
+=0D
+ return StrnCpyS (PathSegment, EXT4_NAME_MAX, Start, End - Start);=0D
+}=0D
+=0D
+/**=0D
+ Detects if we have more path segments on the path.=0D
+=0D
+ @param[in] Path Pointer to the rest of the path.=0D
+ @return True if we're on the last segment, false if there are=
more=0D
+ segments.=0D
+**/=0D
+STATIC=0D
+BOOLEAN=0D
+Ext4IsLastPathSegment (=0D
+ IN CONST CHAR16 *Path=0D
+ )=0D
+{=0D
+ while (Path[0] =3D=3D L'\\') {=0D
+ Path++;=0D
+ }=0D
+=0D
+ return Path[0] =3D=3D '\0';=0D
+}=0D
+=0D
+#define EXT4_INO_PERM_READ_OWNER 0400=0D
+#define EXT4_INO_PERM_WRITE_OWNER 0200=0D
+#define EXT4_INO_PERM_EXEC_OWNER 0100=0D
+=0D
+/**=0D
+ Detects if we have permissions to open the file on the desired mode.=0D
+=0D
+ @param[in out] File Pointer to the file we're opening.=0D
+ @param[in] OpenMode Mode in which to open the file.=0D
+=0D
+ @return True if the open was succesful, false if we don't hav=
e=0D
+ enough permissions.=0D
+**/=0D
+STATIC=0D
+BOOLEAN=0D
+Ext4ApplyPermissions (=0D
+ IN OUT EXT4_FILE *File, IN UINT64 OpenMode=0D
+ )=0D
+{=0D
+ UINT16 NeededPerms;=0D
+=0D
+ NeededPerms =3D 0;=0D
+=0D
+ if ((OpenMode & EFI_FILE_MODE_READ) !=3D 0) {=0D
+ NeededPerms |=3D EXT4_INO_PERM_READ_OWNER;=0D
+ }=0D
+=0D
+ if ((OpenMode & EFI_FILE_MODE_WRITE) !=3D 0) {=0D
+ NeededPerms |=3D EXT4_INO_PERM_WRITE_OWNER;=0D
+ }=0D
+=0D
+ if ((File->Inode->i_mode & NeededPerms) !=3D NeededPerms) {=0D
+ return FALSE;=0D
+ }=0D
+=0D
+ File->OpenMode =3D OpenMode;=0D
+=0D
+ return TRUE;=0D
+}=0D
+=0D
+/**=0D
+ Detects if we have permissions to search on the directory.=0D
+=0D
+ @param[in out] File Pointer to the open directory.=0D
+=0D
+ @return True if we have permission to search, else false.=0D
+**/=0D
+STATIC=0D
+BOOLEAN=0D
+Ext4DirCanLookup (=0D
+ IN CONST EXT4_FILE *File=0D
+ )=0D
+{=0D
+ // In UNIX, executable permission on directories means that we have perm=
ission to look up=0D
+ // files in a directory.=0D
+ return (File->Inode->i_mode & EXT4_INO_PERM_EXEC_OWNER) =3D=3D EXT4_INO_=
PERM_EXEC_OWNER;=0D
+}=0D
+=0D
+/**=0D
+ Opens a new file relative to the source file's location.=0D
+=0D
+ @param[in] This A pointer to the EFI_FILE_PROTOCOL instance that =
is the file=0D
+ handle to the source location. This would typical=
ly be an open=0D
+ handle to a directory.=0D
+ @param[out] NewHandle A pointer to the location to return the opened ha=
ndle for the new=0D
+ file.=0D
+ @param[in] FileName The Null-terminated string of the name of the fil=
e to be opened.=0D
+ The file name may contain the following path modi=
fiers: "\", ".",=0D
+ and "..".=0D
+ @param[in] OpenMode The mode to open the file. The only valid combina=
tions that the=0D
+ file may be opened with are: Read, Read/Write, or=
Create/Read/Write.=0D
+ @param[in] Attributes Only valid for EFI_FILE_MODE_CREATE, in which cas=
e these are the=0D
+ attribute bits for the newly created file.=0D
+=0D
+ @retval EFI_SUCCESS The file was opened.=0D
+ @retval EFI_NOT_FOUND The specified file could not be found on th=
e device.=0D
+ @retval EFI_NO_MEDIA The device has no medium.=0D
+ @retval EFI_MEDIA_CHANGED The device has a different medium in it or =
the medium is no=0D
+ longer supported.=0D
+ @retval EFI_DEVICE_ERROR The device reported an error.=0D
+ @retval EFI_VOLUME_CORRUPTED The file system structures are corrupted.=0D
+ @retval EFI_WRITE_PROTECTED An attempt was made to create a file, or op=
en a file for write=0D
+ when the media is write-protected.=0D
+ @retval EFI_ACCESS_DENIED The service denied access to the file.=0D
+ @retval EFI_OUT_OF_RESOURCES Not enough resources were available to open=
the file.=0D
+ @retval EFI_VOLUME_FULL The volume is full.=0D
+=0D
+**/=0D
+EFI_STATUS=0D
+EFIAPI=0D
+Ext4Open (=0D
+ IN EFI_FILE_PROTOCOL *This,=0D
+ OUT EFI_FILE_PROTOCOL **NewHandle,=0D
+ IN CHAR16 *FileName,=0D
+ IN UINT64 OpenMode,=0D
+ IN UINT64 Attributes=0D
+ )=0D
+{=0D
+ EXT4_FILE *Current;=0D
+ EXT4_PARTITION *Partition;=0D
+ UINTN Level;=0D
+ CHAR16 PathSegment[EXT4_NAME_MAX + 1];=0D
+ UINTN Length;=0D
+ EXT4_FILE *File;=0D
+ EFI_STATUS Status;=0D
+=0D
+ Current =3D (EXT4_FILE *)This;=0D
+ Partition =3D Current->Partition;=0D
+ Level =3D 0;=0D
+=0D
+ DEBUG ((DEBUG_FS, "[ext4] Ext4Open %s\n", FileName));=0D
+ // If the path starts with a backslash, we treat the root directory as t=
he base directory=0D
+ if (FileName[0] =3D=3D L'\\') {=0D
+ FileName++;=0D
+ Current =3D Partition->Root;=0D
+ }=0D
+=0D
+ while (FileName[0] !=3D L'\0') {=0D
+ // Discard leading path separators=0D
+ while (FileName[0] =3D=3D L'\\') {=0D
+ FileName++;=0D
+ }=0D
+=0D
+ if (GetPathSegment (FileName, PathSegment, &Length) !=3D EFI_SUCCESS) =
{=0D
+ return EFI_BUFFER_TOO_SMALL;=0D
+ }=0D
+=0D
+ // Reached the end of the path=0D
+ if (Length =3D=3D 0) {=0D
+ break;=0D
+ }=0D
+=0D
+ FileName +=3D Length;=0D
+=0D
+ DEBUG ((DEBUG_FS, "[ext4] Opening %s\n", PathSegment));=0D
+=0D
+ if (!Ext4FileIsDir (Current)) {=0D
+ return EFI_INVALID_PARAMETER;=0D
+ }=0D
+=0D
+ if (!Ext4IsLastPathSegment (FileName)) {=0D
+ if (!Ext4DirCanLookup (Current)) {=0D
+ return EFI_ACCESS_DENIED;=0D
+ }=0D
+ }=0D
+=0D
+ Status =3D Ext4OpenFile (Current, PathSegment, Partition, EFI_FILE_MOD=
E_READ, &File);=0D
+=0D
+ if (EFI_ERROR (Status) && Status !=3D EFI_NOT_FOUND) {=0D
+ return Status;=0D
+ } else if (Status =3D=3D EFI_NOT_FOUND) {=0D
+ // We explicitly ignore the EFI_FILE_MODE_CREATE flag, since we don'=
t have write support=0D
+ /// If/ we add write support, this should be changed.=0D
+ return Status;=0D
+ }=0D
+=0D
+ // Check if this is a valid file to open in EFI=0D
+=0D
+ // What to do with symlinks? They're nonsense when absolute but may=0D
+ // be useful when they're relative. Right now, they're ignored, since =
they=0D
+ // bring a lot of trouble for something that's not as useful in our ca=
se.=0D
+ // If you want to link, use hard links.=0D
+=0D
+ if (!Ext4FileIsOpenable (File)) {=0D
+ Ext4CloseInternal (File);=0D
+ // This looks like an /okay/ status to return.=0D
+ return EFI_ACCESS_DENIED;=0D
+ }=0D
+=0D
+ if (Level !=3D 0) {=0D
+ // Careful not to close the base directory=0D
+ Ext4CloseInternal (Current);=0D
+ }=0D
+=0D
+ Level++;=0D
+=0D
+ Current =3D File;=0D
+ }=0D
+=0D
+ if (Level =3D=3D 0) {=0D
+ // We opened the base directory again, so we need to duplicate the fil=
e structure=0D
+ Current =3D Ext4DuplicateFile (Current);=0D
+ if (Current =3D=3D NULL) {=0D
+ return EFI_OUT_OF_RESOURCES;=0D
+ }=0D
+ }=0D
+=0D
+ if (!Ext4ApplyPermissions (Current, OpenMode)) {=0D
+ Ext4CloseInternal (Current);=0D
+ return EFI_ACCESS_DENIED;=0D
+ }=0D
+=0D
+ *NewHandle =3D &Current->Protocol;=0D
+=0D
+ DEBUG ((DEBUG_FS, "Opened filename %s\n", Current->FileName));=0D
+ return EFI_SUCCESS;=0D
+}=0D
+=0D
+/**=0D
+ Closes a specified file handle.=0D
+=0D
+ @param[in] This A pointer to the EFI_FILE_PROTOCOL instance th=
at is the file=0D
+ handle to close.=0D
+=0D
+ @retval EFI_SUCCESS The file was closed.=0D
+=0D
+**/=0D
+EFI_STATUS=0D
+EFIAPI=0D
+Ext4Close (=0D
+ IN EFI_FILE_PROTOCOL *This=0D
+ )=0D
+{=0D
+ return Ext4CloseInternal ((EXT4_FILE *)This);=0D
+}=0D
+=0D
+/**=0D
+ Closes a file.=0D
+=0D
+ @param[in] File Pointer to the file.=0D
+=0D
+ @return Status of the closing of the file.=0D
+**/=0D
+EFI_STATUS=0D
+Ext4CloseInternal (=0D
+ IN EXT4_FILE *File=0D
+ )=0D
+{=0D
+ if (File =3D=3D File->Partition->Root && !File->Partition->Unmounting) {=
=0D
+ return EFI_SUCCESS;=0D
+ }=0D
+=0D
+ DEBUG ((DEBUG_FS, "[ext4] Closed file %p (inode %lu)\n", File, File->Ino=
deNum));=0D
+ RemoveEntryList (&File->OpenFilesListNode);=0D
+ FreePool (File->FileName);=0D
+ FreePool (File->Inode);=0D
+ Ext4FreeExtentsMap (File);=0D
+ FreePool (File);=0D
+ return EFI_SUCCESS;=0D
+}=0D
+=0D
+/**=0D
+ Close and delete the file handle.=0D
+=0D
+ @param[in] This A pointer to the EFI_FILE_PROTOCOL =
instance that is the=0D
+ handle to the file to delete.=0D
+=0D
+ @retval EFI_SUCCESS The file was closed and deleted, and th=
e handle was closed.=0D
+ @retval EFI_WARN_DELETE_FAILURE The handle was closed, but the file was=
not deleted.=0D
+=0D
+**/=0D
+EFI_STATUS=0D
+EFIAPI=0D
+Ext4Delete (=0D
+ IN EFI_FILE_PROTOCOL *This=0D
+ )=0D
+{=0D
+ // We do a regular close here since we don't have write support.=0D
+ Ext4Close (This);=0D
+ return EFI_WARN_DELETE_FAILURE;=0D
+}=0D
+=0D
+/**=0D
+ Reads data from a file.=0D
+=0D
+ @param[in] This A pointer to the EFI_FILE_PROTOCOL inst=
ance that is the file=0D
+ handle to read data from.=0D
+ @param[in out] BufferSize On input, the size of the Buffer. On ou=
tput, the amount of data=0D
+ returned in Buffer. In both cases, the =
size is measured in bytes.=0D
+ @param[out] Buffer The buffer into which the data is read.=
=0D
+=0D
+ @retval EFI_SUCCESS Data was read.=0D
+ @retval EFI_NO_MEDIA The device has no medium.=0D
+ @retval EFI_DEVICE_ERROR The device reported an error.=0D
+ @retval EFI_DEVICE_ERROR An attempt was made to read from a deleted =
file.=0D
+ @retval EFI_DEVICE_ERROR On entry, the current file position is beyo=
nd the end of the file.=0D
+ @retval EFI_VOLUME_CORRUPTED The file system structures are corrupted.=0D
+ @retval EFI_BUFFER_TOO_SMALL The BufferSize is too small to read the cur=
rent directory=0D
+ entry. BufferSize has been updated with the=
size=0D
+ needed to complete the request.=0D
+=0D
+**/=0D
+EFI_STATUS=0D
+EFIAPI=0D
+Ext4ReadFile (=0D
+ IN EFI_FILE_PROTOCOL *This,=0D
+ IN OUT UINTN *BufferSize,=0D
+ OUT VOID *Buffer=0D
+ )=0D
+{=0D
+ EXT4_FILE *File;=0D
+ EXT4_PARTITION *Partition;=0D
+ EFI_STATUS Status;=0D
+=0D
+ File =3D (EXT4_FILE *)This;=0D
+ Partition =3D File->Partition;=0D
+=0D
+ ASSERT (Ext4FileIsOpenable (File));=0D
+=0D
+ if (Ext4FileIsReg (File)) {=0D
+ Status =3D Ext4Read (Partition, File, Buffer, File->Position, BufferSi=
ze);=0D
+ if (Status =3D=3D EFI_SUCCESS) {=0D
+ File->Position +=3D *BufferSize;=0D
+ }=0D
+=0D
+ return Status;=0D
+ } else if (Ext4FileIsDir (File)) {=0D
+ Status =3D Ext4ReadDir (Partition, File, Buffer, File->Position, Buffe=
rSize);=0D
+=0D
+ return Status;=0D
+ }=0D
+=0D
+ return EFI_SUCCESS;=0D
+}=0D
+=0D
+/**=0D
+ Writes data to a file.=0D
+=0D
+ @param[in] This A pointer to the EFI_FILE_PROTOCOL instance =
that is the file=0D
+ handle to write data to.=0D
+ @param[in out] BufferSize On input, the size of the Buffer. On output,=
the amount of data=0D
+ actually written. In both cases, the size is=
measured in bytes.=0D
+ @param[in] Buffer The buffer of data to write.=0D
+=0D
+ @retval EFI_SUCCESS Data was written.=0D
+ @retval EFI_UNSUPPORTED Writes to open directory files are not supp=
orted.=0D
+ @retval EFI_NO_MEDIA The device has no medium.=0D
+ @retval EFI_DEVICE_ERROR The device reported an error.=0D
+ @retval EFI_DEVICE_ERROR An attempt was made to write to a deleted f=
ile.=0D
+ @retval EFI_VOLUME_CORRUPTED The file system structures are corrupted.=0D
+ @retval EFI_WRITE_PROTECTED The file or medium is write-protected.=0D
+ @retval EFI_ACCESS_DENIED The file was opened read only.=0D
+ @retval EFI_VOLUME_FULL The volume is full.=0D
+=0D
+**/=0D
+EFI_STATUS=0D
+EFIAPI=0D
+Ext4WriteFile (=0D
+ IN EFI_FILE_PROTOCOL *This,=0D
+ IN OUT UINTN *BufferSize,=0D
+ IN VOID *Buffer=0D
+ )=0D
+{=0D
+ EXT4_FILE *File;=0D
+=0D
+ File =3D (EXT4_FILE *)This;=0D
+=0D
+ if (!(File->OpenMode & EFI_FILE_MODE_WRITE)) {=0D
+ return EFI_ACCESS_DENIED;=0D
+ }=0D
+=0D
+ return EFI_WRITE_PROTECTED;=0D
+}=0D
+=0D
+/**=0D
+ Returns a file's current position.=0D
+=0D
+ @param[in] This A pointer to the EFI_FILE_PROTOCOL instance=
that is the file=0D
+ handle to get the current position on.=0D
+ @param[out] Position The address to return the file's current po=
sition value.=0D
+=0D
+ @retval EFI_SUCCESS The position was returned.=0D
+ @retval EFI_UNSUPPORTED The request is not valid on open directories.=0D
+ @retval EFI_DEVICE_ERROR An attempt was made to get the position from a =
deleted file.=0D
+=0D
+**/=0D
+EFI_STATUS=0D
+EFIAPI=0D
+Ext4GetPosition (=0D
+ IN EFI_FILE_PROTOCOL *This,=0D
+ OUT UINT64 *Position=0D
+ )=0D
+{=0D
+ EXT4_FILE *File;=0D
+=0D
+ File =3D (EXT4_FILE *)This;=0D
+=0D
+ if (Ext4FileIsDir (File)) {=0D
+ return EFI_UNSUPPORTED;=0D
+ }=0D
+=0D
+ *Position =3D File->Position;=0D
+=0D
+ return EFI_SUCCESS;=0D
+}=0D
+=0D
+/**=0D
+ Sets a file's current position.=0D
+=0D
+ @param[in] This A pointer to the EFI_FILE_PROTOCOL instance =
that is the=0D
+ file handle to set the requested position on=
.=0D
+ @param[in] Position The byte position from the start of the file =
to set.=0D
+=0D
+ @retval EFI_SUCCESS The position was set.=0D
+ @retval EFI_UNSUPPORTED The seek request for nonzero is not valid on op=
en=0D
+ directories.=0D
+ @retval EFI_DEVICE_ERROR An attempt was made to set the position of a de=
leted file.=0D
+=0D
+**/=0D
+EFI_STATUS=0D
+EFIAPI=0D
+Ext4SetPosition (=0D
+ IN EFI_FILE_PROTOCOL *This,=0D
+ IN UINT64 Position=0D
+ )=0D
+{=0D
+ EXT4_FILE *File;=0D
+=0D
+ File =3D (EXT4_FILE *)This;=0D
+=0D
+ // Only seeks to 0 (so it resets the ReadDir operation) are allowed=0D
+ if (Ext4FileIsDir (File) && Position !=3D 0) {=0D
+ return EFI_UNSUPPORTED;=0D
+ }=0D
+=0D
+ // -1 (0xffffff.......) seeks to the end of the file=0D
+ if (Position =3D=3D (UINT64)- 1) {=0D
+ Position =3D EXT4_INODE_SIZE (File->Inode);=0D
+ }=0D
+=0D
+ File->Position =3D Position;=0D
+=0D
+ return EFI_SUCCESS;=0D
+}=0D
+=0D
+/**=0D
+ Retrieves information about the file and stores it in the EFI_FILE_INFO=
format.=0D
+=0D
+ @param[in] File Pointer to an opened file.=0D
+ @param[out] Info Pointer to a EFI_FILE_INFO.=0D
+ @param[in out] BufferSize Pointer to the buffer size=0D
+=0D
+ @return Status of the file information request.=0D
+**/=0D
+EFI_STATUS=0D
+Ext4GetFileInfo (=0D
+ IN EXT4_FILE *File, OUT EFI_FILE_INFO *Info, IN OUT UINTN *BufferSize=0D
+ )=0D
+{=0D
+ UINTN FileNameLen;=0D
+ UINTN FileNameSize;=0D
+ UINTN NeededLength;=0D
+=0D
+ FileNameLen =3D StrLen (File->FileName);=0D
+ FileNameSize =3D StrSize (File->FileName);=0D
+=0D
+ NeededLength =3D SIZE_OF_EFI_FILE_INFO + FileNameSize;=0D
+=0D
+ if (*BufferSize < NeededLength) {=0D
+ *BufferSize =3D NeededLength;=0D
+ return EFI_BUFFER_TOO_SMALL;=0D
+ }=0D
+=0D
+ Info->FileSize =3D EXT4_INODE_SIZE (File->Inode);=0D
+ Info->PhysicalSize =3D Ext4FilePhysicalSpace (File);=0D
+ Ext4FileATime (File, &Info->LastAccessTime);=0D
+ Ext4FileMTime (File, &Info->ModificationTime);=0D
+ Ext4FileCreateTime (File, &Info->LastAccessTime);=0D
+ Info->Attribute =3D 0;=0D
+ Info->Size =3D NeededLength;=0D
+=0D
+ if (Ext4FileIsDir (File)) {=0D
+ Info->Attribute |=3D EFI_FILE_DIRECTORY;=0D
+ }=0D
+=0D
+ *BufferSize =3D NeededLength;=0D
+=0D
+ return StrCpyS (Info->FileName, FileNameLen + 1, File->FileName);=0D
+}=0D
+=0D
+/**=0D
+ Retrieves information about the filesystem and stores it in the EFI_FIL=
E_SYSTEM_INFO format.=0D
+=0D
+ @param[in] Part Pointer to the opened partition.=0D
+ @param[out] Info Pointer to a EFI_FILE_SYSTEM_INFO.=0D
+ @param[in out] BufferSize Pointer to the buffer size=0D
+=0D
+ @return Status of the file information request.=0D
+**/=0D
+STATIC=0D
+EFI_STATUS=0D
+Ext4GetFilesystemInfo (=0D
+ IN EXT4_PARTITION *Part, OUT EFI_FILE_SYSTEM_INFO *Info, IN OUT UINTN *B=
ufferSize=0D
+ )=0D
+{=0D
+ // Length of s_volume_name + null terminator=0D
+ CHAR8 TempVolName[16 + 1];=0D
+ CHAR16 *VolumeName;=0D
+ UINTN VolNameLength;=0D
+ EFI_STATUS Status;=0D
+ UINTN NeededLength;=0D
+ EXT4_BLOCK_NR TotalBlocks;=0D
+ EXT4_BLOCK_NR FreeBlocks;=0D
+=0D
+ VolNameLength =3D 0;=0D
+ VolumeName =3D NULL;=0D
+=0D
+ // s_volume_name is only valid on dynamic revision; old filesystems don'=
t support this=0D
+ if (Part->SuperBlock.s_rev_level =3D=3D EXT4_DYNAMIC_REV) {=0D
+ CopyMem (TempVolName, (CONST CHAR8 *)Part->SuperBlock.s_volume_name, 1=
6);=0D
+ TempVolName[16] =3D '\0';=0D
+=0D
+ Status =3D UTF8StrToUCS2 (TempVolName, &VolumeName);=0D
+=0D
+ if (EFI_ERROR (Status)) {=0D
+ return Status;=0D
+ }=0D
+=0D
+ VolNameLength =3D StrLen (VolumeName);=0D
+ }=0D
+=0D
+ NeededLength =3D SIZE_OF_EFI_FILE_SYSTEM_INFO;=0D
+=0D
+ if (VolumeName !=3D NULL) {=0D
+ NeededLength +=3D StrSize (VolumeName);=0D
+ } else {=0D
+ // If we don't have a volume name, we set VolumeLabel to a single null=
terminator=0D
+ NeededLength +=3D sizeof (CHAR16);=0D
+ }=0D
+=0D
+ if (*BufferSize < NeededLength) {=0D
+ *BufferSize =3D NeededLength;=0D
+=0D
+ if (VolumeName !=3D NULL) {=0D
+ FreePool (VolumeName);=0D
+ }=0D
+=0D
+ return EFI_BUFFER_TOO_SMALL;=0D
+ }=0D
+=0D
+ TotalBlocks =3D Part->NumberBlocks;=0D
+=0D
+ FreeBlocks =3D EXT4_BLOCK_NR_FROM_HALFS (=0D
+ Part,=0D
+ Part->SuperBlock.s_free_blocks_count,=0D
+ Part->SuperBlock.s_free_blocks_count_hi=0D
+ );=0D
+=0D
+ Info->BlockSize =3D Part->BlockSize;=0D
+ Info->Size =3D NeededLength;=0D
+ Info->ReadOnly =3D Part->ReadOnly;=0D
+ Info->VolumeSize =3D MultU64x32 (TotalBlocks, Part->BlockSize);=0D
+ Info->FreeSpace =3D MultU64x32 (FreeBlocks, Part->BlockSize);=0D
+=0D
+ if (VolumeName !=3D NULL) {=0D
+ StrCpyS (Info->VolumeLabel, VolNameLength + 1, VolumeName);=0D
+ } else {=0D
+ Info->VolumeLabel[0] =3D L'\0';=0D
+ }=0D
+=0D
+ if (VolumeName !=3D NULL) {=0D
+ FreePool (VolumeName);=0D
+ }=0D
+=0D
+ *BufferSize =3D NeededLength;=0D
+=0D
+ return EFI_SUCCESS;=0D
+}=0D
+=0D
+/**=0D
+ Returns information about a file.=0D
+=0D
+ @param[in] This A pointer to the EFI_FILE_PROTOCOL insta=
nce that is the file=0D
+ handle the requested information is for.=
=0D
+ @param[in] InformationType The type identifier for the information =
being requested.=0D
+ @param[in out] BufferSize On input, the size of Buffer. On output,=
the amount of data=0D
+ returned in Buffer. In both cases, the s=
ize is measured in bytes.=0D
+ @param[out] Buffer A pointer to the data buffer to return. =
The buffer's type is=0D
+ indicated by InformationType.=0D
+=0D
+ @retval EFI_SUCCESS The information was returned.=0D
+ @retval EFI_UNSUPPORTED The InformationType is not known.=0D
+ @retval EFI_NO_MEDIA The device has no medium.=0D
+ @retval EFI_DEVICE_ERROR The device reported an error.=0D
+ @retval EFI_VOLUME_CORRUPTED The file system structures are corrupted.=0D
+ @retval EFI_BUFFER_TOO_SMALL The BufferSize is too small to read the cur=
rent directory entry.=0D
+ BufferSize has been updated with the size n=
eeded to complete=0D
+ the request.=0D
+**/=0D
+EFI_STATUS=0D
+EFIAPI=0D
+Ext4GetInfo (=0D
+ IN EFI_FILE_PROTOCOL *This,=0D
+ IN EFI_GUID *InformationType,=0D
+ IN OUT UINTN *BufferSize,=0D
+ OUT VOID *Buffer=0D
+ )=0D
+{=0D
+ if (CompareGuid (InformationType, &gEfiFileInfoGuid)) {=0D
+ return Ext4GetFileInfo ((EXT4_FILE *)This, Buffer, BufferSize);=0D
+ }=0D
+=0D
+ if (CompareGuid (InformationType, &gEfiFileSystemInfoGuid)) {=0D
+ return Ext4GetFilesystemInfo (((EXT4_FILE *)This)->Partition, Buffer, =
BufferSize);=0D
+ }=0D
+=0D
+ return EFI_UNSUPPORTED;=0D
+}=0D
+=0D
+/**=0D
+ Duplicates a file structure.=0D
+=0D
+ @param[in] Original Pointer to the original file.=0D
+=0D
+ @return Pointer to the new file structure.=0D
+**/=0D
+STATIC=0D
+EXT4_FILE *=0D
+Ext4DuplicateFile (=0D
+ IN CONST EXT4_FILE *Original=0D
+ )=0D
+{=0D
+ EXT4_PARTITION *Partition;=0D
+ EXT4_FILE *File;=0D
+=0D
+ Partition =3D Original->Partition;=0D
+ File =3D AllocateZeroPool (sizeof (EXT4_FILE));=0D
+=0D
+ if (File =3D=3D NULL) {=0D
+ return NULL;=0D
+ }=0D
+=0D
+ File->Inode =3D Ext4AllocateInode (Partition);=0D
+ if (File->Inode =3D=3D NULL) {=0D
+ FreePool (File);=0D
+ return NULL;=0D
+ }=0D
+=0D
+ CopyMem (File->Inode, Original->Inode, Partition->InodeSize);=0D
+=0D
+ File->FileName =3D AllocateZeroPool (StrSize (Original->FileName));=0D
+ if (File->FileName =3D=3D NULL) {=0D
+ FreePool (File->Inode);=0D
+ FreePool (File);=0D
+ return NULL;=0D
+ }=0D
+=0D
+ StrCpyS (File->FileName, StrLen (Original->FileName) + 1, Original->File=
Name);=0D
+=0D
+ File->Position =3D 0;=0D
+ Ext4SetupFile (File, Partition);=0D
+ File->InodeNum =3D Original->InodeNum;=0D
+ File->OpenMode =3D 0; // Will be filled by other code=0D
+=0D
+ if (!Ext4InitExtentsMap (File)) {=0D
+ FreePool (File->FileName);=0D
+ FreePool (File->Inode);=0D
+ FreePool (File);=0D
+ return NULL;=0D
+ }=0D
+=0D
+ InsertTailList (&Partition->OpenFiles, &File->OpenFilesListNode);=0D
+=0D
+ return File;=0D
+}=0D
+=0D
+/**=0D
+ Sets information about a file.=0D
+=0D
+ @param[in] This A pointer to the EFI_FILE_PROTOCOL instance =
that is the file=0D
+ handle the information is for.=0D
+ @param[in] InformationType The type identifier for the information bein=
g set.=0D
+ @param[in] BufferSize The size, in bytes, of Buffer.=0D
+ @param[in] Buffer A pointer to the data buffer to write. The b=
uffer's type is=0D
+ indicated by InformationType.=0D
+=0D
+ @retval EFI_SUCCESS The information was set.=0D
+ @retval EFI_UNSUPPORTED The InformationType is not known.=0D
+ @retval EFI_NO_MEDIA The device has no medium.=0D
+ @retval EFI_DEVICE_ERROR The device reported an error.=0D
+ @retval EFI_VOLUME_CORRUPTED The file system structures are corrupted.=0D
+ @retval EFI_WRITE_PROTECTED InformationType is EFI_FILE_INFO_ID and the=
media is=0D
+ read-only.=0D
+ @retval EFI_WRITE_PROTECTED InformationType is EFI_FILE_PROTOCOL_SYSTEM=
_INFO_ID=0D
+ and the media is read only.=0D
+ @retval EFI_WRITE_PROTECTED InformationType is EFI_FILE_SYSTEM_VOLUME_L=
ABEL_ID=0D
+ and the media is read-only.=0D
+ @retval EFI_ACCESS_DENIED An attempt is made to change the name of a =
file to a=0D
+ file that is already present.=0D
+ @retval EFI_ACCESS_DENIED An attempt is being made to change the EFI_=
FILE_DIRECTORY=0D
+ Attribute.=0D
+ @retval EFI_ACCESS_DENIED An attempt is being made to change the size=
of a directory.=0D
+ @retval EFI_ACCESS_DENIED InformationType is EFI_FILE_INFO_ID and the=
file was opened=0D
+ read-only and an attempt is being made to m=
odify a field=0D
+ other than Attribute.=0D
+ @retval EFI_VOLUME_FULL The volume is full.=0D
+ @retval EFI_BAD_BUFFER_SIZE BufferSize is smaller than the size of the =
type indicated=0D
+ by InformationType.=0D
+=0D
+**/=0D
+EFI_STATUS=0D
+EFIAPI=0D
+Ext4SetInfo (=0D
+ IN EFI_FILE_PROTOCOL *This,=0D
+ IN EFI_GUID *InformationType,=0D
+ IN UINTN BufferSize,=0D
+ IN VOID *Buffer=0D
+ )=0D
+{=0D
+ EXT4_FILE *File;=0D
+ EXT4_PARTITION *Part;=0D
+=0D
+ File =3D (EXT4_FILE *)This;=0D
+ Part =3D File->Partition;=0D
+=0D
+ if (Part->ReadOnly) {=0D
+ return EFI_WRITE_PROTECTED;=0D
+ }=0D
+=0D
+ // There's no write support just yet.=0D
+ return EFI_UNSUPPORTED;=0D
+}=0D
diff --git a/Features/Ext4Pkg/Ext4Dxe/Inode.c b/Features/Ext4Pkg/Ext4Dxe/In=
ode.c
new file mode 100644
index 0000000000..1bbff9e69f
--- /dev/null
+++ b/Features/Ext4Pkg/Ext4Dxe/Inode.c
@@ -0,0 +1,465 @@
+/** @file=0D
+ Inode related routines=0D
+=0D
+ Copyright (c) 2021 Pedro Falcato All rights reserved.=0D
+ SPDX-License-Identifier: BSD-2-Clause-Patent=0D
+=0D
+ EpochToEfiTime copied from EmbeddedPkg/Library/TimeBaseLib.c=0D
+ Copyright (c) 2016, Hisilicon Limited. All rights reserved.=0D
+ Copyright (c) 2016-2019, Linaro Limited. All rights reserved.=0D
+ Copyright (c) 2021, Ampere Computing LLC. All rights reserved.=0D
+**/=0D
+=0D
+#include "Ext4Dxe.h"=0D
+=0D
+/**=0D
+ Calculates the checksum of the given inode.=0D
+ @param[in] Partition Pointer to the opened EXT4 partition.=0D
+ @param[in] Inode Pointer to the inode.=0D
+ @param[in] InodeNum Inode number.=0D
+=0D
+ @return The checksum.=0D
+**/=0D
+UINT32=0D
+Ext4CalculateInodeChecksum (=0D
+ IN CONST EXT4_PARTITION *Partition,=0D
+ IN CONST EXT4_INODE *Inode,=0D
+ IN EXT4_INO_NR InodeNum=0D
+ )=0D
+{=0D
+ UINT32 Crc;=0D
+ UINT16 Dummy;=0D
+ BOOLEAN HasSecondChecksumField;=0D
+ CONST VOID *RestOfInode;=0D
+ UINTN RestOfInodeLength;=0D
+ UINTN Length;=0D
+=0D
+ HasSecondChecksumField =3D EXT4_INODE_HAS_FIELD (Inode, i_checksum_hi);=
=0D
+=0D
+ Dummy =3D 0;=0D
+=0D
+ Crc =3D Ext4CalculateChecksum (Partition, &InodeNum, sizeof (InodeNum), =
Partition->InitialSeed);=0D
+ Crc =3D Ext4CalculateChecksum (Partition, &Inode->i_generation, sizeof (=
Inode->i_generation), Crc);=0D
+=0D
+ Crc =3D Ext4CalculateChecksum (=0D
+ Partition,=0D
+ Inode,=0D
+ OFFSET_OF (EXT4_INODE, i_osd2.data_linux.l_i_checksum_lo),=0D
+ Crc=0D
+ );=0D
+=0D
+ Crc =3D Ext4CalculateChecksum (Partition, &Dummy, sizeof (Dummy), Crc);=
=0D
+=0D
+ RestOfInode =3D &Inode->i_osd2.data_linux.l_i_reserved;=0D
+ RestOfInodeLength =3D Partition->InodeSize - OFFSET_OF (EXT4_INODE, i_os=
d2.data_linux.l_i_reserved);=0D
+=0D
+ if (HasSecondChecksumField) {=0D
+ Length =3D OFFSET_OF (EXT4_INODE, i_checksum_hi) - OFFSET_OF (EXT4_INO=
DE, i_osd2.data_linux.l_i_reserved);=0D
+=0D
+ Crc =3D Ext4CalculateChecksum (Partition, &Inode->i_osd2.data_linux.l_=
i_reserved, Length, Crc);=0D
+ Crc =3D Ext4CalculateChecksum (Partition, &Dummy, sizeof (Dummy), Crc)=
;=0D
+=0D
+ // 4 is the size of the i_extra_size field + the size of i_checksum_hi=
=0D
+ RestOfInodeLength =3D Partition->InodeSize - EXT4_GOOD_OLD_INODE_SIZE =
- 4;=0D
+ RestOfInode =3D &Inode->i_ctime_extra;=0D
+ }=0D
+=0D
+ Crc =3D Ext4CalculateChecksum (Partition, RestOfInode, RestOfInodeLength=
, Crc);=0D
+=0D
+ return Crc;=0D
+}=0D
+=0D
+/**=0D
+ Reads from an EXT4 inode.=0D
+ @param[in] Partition Pointer to the opened EXT4 partition.=0D
+ @param[in] File Pointer to the opened file.=0D
+ @param[out] Buffer Pointer to the buffer.=0D
+ @param[in] Offset Offset of the read.=0D
+ @param[in out] Length Pointer to the length of the buffer, in b=
ytes.=0D
+ After a succesful read, it's updated to t=
he number of read bytes.=0D
+=0D
+ @return Status of the read operation.=0D
+**/=0D
+EFI_STATUS=0D
+Ext4Read (=0D
+ IN EXT4_PARTITION *Partition,=0D
+ IN EXT4_FILE *File,=0D
+ OUT VOID *Buffer,=0D
+ IN UINT64 Offset,=0D
+ IN OUT UINTN *Length=0D
+ )=0D
+{=0D
+ DEBUG ((DEBUG_FS, "[ext4] Ext4Read(Offset %lu, Length %lu)\n", Offset, *=
Length));=0D
+ EXT4_INODE *Inode;=0D
+ UINT64 InodeSize;=0D
+ UINT64 CurrentSeek;=0D
+ UINTN RemainingRead;=0D
+ UINTN BeenRead;=0D
+ UINTN WasRead;=0D
+ EXT4_EXTENT Extent;=0D
+ UINT32 BlockOff;=0D
+ EFI_STATUS Status;=0D
+ BOOLEAN HasBackingExtent;=0D
+ UINT32 HoleOff;=0D
+ UINTN HoleLen;=0D
+ UINT64 ExtentStartBytes;=0D
+ UINT64 ExtentLengthBytes;=0D
+ UINT64 ExtentLogicalBytes;=0D
+=0D
+ // Our extent offset is the difference between CurrentSeek and ExtentLog=
icalBytes=0D
+ UINT64 ExtentOffset;=0D
+ UINTN ExtentMayRead;=0D
+=0D
+ Inode =3D File->Inode;=0D
+ InodeSize =3D EXT4_INODE_SIZE (Inode);=0D
+ CurrentSeek =3D Offset;=0D
+ RemainingRead =3D *Length;=0D
+ BeenRead =3D 0;=0D
+=0D
+ if (Offset > InodeSize) {=0D
+ return EFI_DEVICE_ERROR;=0D
+ }=0D
+=0D
+ if (RemainingRead > InodeSize - Offset) {=0D
+ RemainingRead =3D (UINTN)(InodeSize - Offset);=0D
+ }=0D
+=0D
+ while (RemainingRead !=3D 0) {=0D
+ WasRead =3D 0;=0D
+=0D
+ // The algorithm here is to get the extent corresponding to the curren=
t block=0D
+ // and then read as much as we can from the current extent.=0D
+=0D
+ Status =3D Ext4GetExtent (=0D
+ Partition,=0D
+ File,=0D
+ DivU64x32Remainder (CurrentSeek, Partition->BlockSize, &Blo=
ckOff),=0D
+ &Extent=0D
+ );=0D
+=0D
+ if (Status !=3D EFI_SUCCESS && Status !=3D EFI_NO_MAPPING) {=0D
+ return Status;=0D
+ }=0D
+=0D
+ HasBackingExtent =3D Status !=3D EFI_NO_MAPPING;=0D
+=0D
+ if (!HasBackingExtent) {=0D
+ HoleOff =3D BlockOff;=0D
+ HoleLen =3D Partition->BlockSize - HoleOff;=0D
+ WasRead =3D HoleLen > RemainingRead ? RemainingRead : HoleLen;=0D
+ // Potential improvement: In the future, we could get the hole's tot=
a=0D
+ // size and memset all that=0D
+ SetMem (Buffer, WasRead, 0);=0D
+ } else {=0D
+ ExtentStartBytes =3D MultU64x32 (=0D
+ LShiftU64 (Extent.ee_start_hi, 32) |=0D
+ Extent.ee_start_lo,=0D
+ Partition->BlockSize=0D
+ );=0D
+ ExtentLengthBytes =3D Extent.ee_len * Partition->BlockSize;=0D
+ ExtentLogicalBytes =3D (UINT64)Extent.ee_block * Partition->BlockSiz=
e;=0D
+ ExtentOffset =3D CurrentSeek - ExtentLogicalBytes;=0D
+ ExtentMayRead =3D (UINTN)(ExtentLengthBytes - ExtentOffset);=0D
+=0D
+ WasRead =3D ExtentMayRead > RemainingRead ? RemainingRead : ExtentMa=
yRead;=0D
+=0D
+ Status =3D Ext4ReadDiskIo (Partition, Buffer, WasRead, ExtentStartBy=
tes + ExtentOffset);=0D
+=0D
+ if (EFI_ERROR (Status)) {=0D
+ DEBUG ((=0D
+ DEBUG_ERROR,=0D
+ "[ext4] Error %x reading [%lu, %lu]\n",=0D
+ Status,=0D
+ ExtentStartBytes + ExtentOffset,=0D
+ ExtentStartBytes + ExtentOffset + WasRead - 1=0D
+ ));=0D
+ return Status;=0D
+ }=0D
+ }=0D
+=0D
+ RemainingRead -=3D WasRead;=0D
+ Buffer =3D (VOID *)((CHAR8 *)Buffer + WasRead);=0D
+ BeenRead +=3D WasRead;=0D
+ CurrentSeek +=3D WasRead;=0D
+ }=0D
+=0D
+ *Length =3D BeenRead;=0D
+=0D
+ return EFI_SUCCESS;=0D
+}=0D
+=0D
+/**=0D
+ Allocates a zeroed inode structure.=0D
+ @param[in] Partition Pointer to the opened EXT4 partition.=0D
+=0D
+ @return Pointer to the allocated structure, from the pool,=0D
+ with size Partition->InodeSize.=0D
+**/=0D
+EXT4_INODE *=0D
+Ext4AllocateInode (=0D
+ IN EXT4_PARTITION *Partition=0D
+ )=0D
+{=0D
+ BOOLEAN NeedsToZeroRest;=0D
+ UINT32 InodeSize;=0D
+ EXT4_INODE *Inode;=0D
+=0D
+ NeedsToZeroRest =3D FALSE;=0D
+ InodeSize =3D Partition->InodeSize;=0D
+=0D
+ // We allocate a structure of at least sizeof(EXT4_INODE), but in the fu=
ture, when=0D
+ // write support is added and we need to flush inodes to disk, we could =
have a bit better=0D
+ // distinction between the on-disk inode and a separate, nicer to work w=
ith inode struct.=0D
+ // It's important to note that EXT4_INODE includes fields that may not e=
xist in an actual=0D
+ // filesystem (the minimum inode size is 128 byte and at the moment the =
size of EXT4_INODE=0D
+ // is 160 bytes).=0D
+=0D
+ if (InodeSize < sizeof (EXT4_INODE)) {=0D
+ InodeSize =3D sizeof (EXT4_INODE);=0D
+ NeedsToZeroRest =3D TRUE;=0D
+ }=0D
+=0D
+ Inode =3D AllocateZeroPool (InodeSize);=0D
+=0D
+ if (!Inode) {=0D
+ return NULL;=0D
+ }=0D
+=0D
+ if (NeedsToZeroRest) {=0D
+ Inode->i_extra_isize =3D 0;=0D
+ }=0D
+=0D
+ return Inode;=0D
+}=0D
+=0D
+/**=0D
+ Checks if a file is a directory.=0D
+ @param[in] File Pointer to the opened file.=0D
+=0D
+ @return TRUE if file is a directory.=0D
+**/=0D
+BOOLEAN=0D
+Ext4FileIsDir (=0D
+ IN CONST EXT4_FILE *File=0D
+ )=0D
+{=0D
+ return (File->Inode->i_mode & EXT4_INO_TYPE_DIR) =3D=3D EXT4_INO_TYPE_DI=
R;=0D
+}=0D
+=0D
+/**=0D
+ Checks if a file is a regular file.=0D
+ @param[in] File Pointer to the opened file.=0D
+=0D
+ @return BOOLEAN TRUE if file is a regular file.=0D
+**/=0D
+BOOLEAN=0D
+Ext4FileIsReg (=0D
+ IN CONST EXT4_FILE *File=0D
+ )=0D
+{=0D
+ return (File->Inode->i_mode & EXT4_INO_TYPE_REGFILE) =3D=3D EXT4_INO_TYP=
E_REGFILE;=0D
+}=0D
+=0D
+/**=0D
+ Calculates the physical space used by a file.=0D
+ @param[in] File Pointer to the opened file.=0D
+=0D
+ @return Physical space used by a file, in bytes.=0D
+**/=0D
+UINT64=0D
+Ext4FilePhysicalSpace (=0D
+ IN EXT4_FILE *File=0D
+ )=0D
+{=0D
+ BOOLEAN HugeFile;=0D
+ UINT64 Blocks;=0D
+=0D
+ HugeFile =3D EXT4_HAS_RO_COMPAT (File->Partition, EXT4_FEATURE_RO_COMPAT=
_HUGE_FILE);=0D
+ Blocks =3D File->Inode->i_blocks;=0D
+=0D
+ if (HugeFile) {=0D
+ Blocks |=3D LShiftU64 (File->Inode->i_osd2.data_linux.l_i_blocks_high,=
32);=0D
+=0D
+ // If HUGE_FILE is enabled and EXT4_HUGE_FILE_FL is set in the inode's=
flags, each unit=0D
+ // in i_blocks corresponds to an actual filesystem block=0D
+ if (File->Inode->i_flags & EXT4_HUGE_FILE_FL) {=0D
+ return MultU64x32 (Blocks, File->Partition->BlockSize);=0D
+ }=0D
+ }=0D
+=0D
+ // Else, each i_blocks unit corresponds to 512 bytes=0D
+ return MultU64x32 (Blocks, 512);=0D
+}=0D
+=0D
+// Copied from EmbeddedPkg at my mentor's request.=0D
+// The lack of comments and good variable names is frightening...=0D
+=0D
+/**=0D
+ Converts Epoch seconds (elapsed since 1970 JANUARY 01, 00:00:00 UTC) to =
EFI_TIME.=0D
+=0D
+ @param[in] EpochSeconds Epoch seconds.=0D
+ @param[out] Time The time converted to UEFI format.=0D
+=0D
+**/=0D
+STATIC=0D
+VOID=0D
+EFIAPI=0D
+EpochToEfiTime (=0D
+ IN UINTN EpochSeconds,=0D
+ OUT EFI_TIME *Time=0D
+ )=0D
+{=0D
+ UINTN a;=0D
+ UINTN b;=0D
+ UINTN c;=0D
+ UINTN d;=0D
+ UINTN g;=0D
+ UINTN j;=0D
+ UINTN m;=0D
+ UINTN y;=0D
+ UINTN da;=0D
+ UINTN db;=0D
+ UINTN dc;=0D
+ UINTN dg;=0D
+ UINTN hh;=0D
+ UINTN mm;=0D
+ UINTN ss;=0D
+ UINTN J;=0D
+=0D
+ J =3D (EpochSeconds / 86400) + 2440588;=0D
+ j =3D J + 32044;=0D
+ g =3D j / 146097;=0D
+ dg =3D j % 146097;=0D
+ c =3D (((dg / 36524) + 1) * 3) / 4;=0D
+ dc =3D dg - (c * 36524);=0D
+ b =3D dc / 1461;=0D
+ db =3D dc % 1461;=0D
+ a =3D (((db / 365) + 1) * 3) / 4;=0D
+ da =3D db - (a * 365);=0D
+ y =3D (g * 400) + (c * 100) + (b * 4) + a;=0D
+ m =3D (((da * 5) + 308) / 153) - 2;=0D
+ d =3D da - (((m + 4) * 153) / 5) + 122;=0D
+=0D
+ Time->Year =3D (UINT16)(y - 4800 + ((m + 2) / 12));=0D
+ Time->Month =3D ((m + 2) % 12) + 1;=0D
+ Time->Day =3D (UINT8)(d + 1);=0D
+=0D
+ ss =3D EpochSeconds % 60;=0D
+ a =3D (EpochSeconds - ss) / 60;=0D
+ mm =3D a % 60;=0D
+ b =3D (a - mm) / 60;=0D
+ hh =3D b % 24;=0D
+=0D
+ Time->Hour =3D (UINT8)hh;=0D
+ Time->Minute =3D (UINT8)mm;=0D
+ Time->Second =3D (UINT8)ss;=0D
+ Time->Nanosecond =3D 0;=0D
+}=0D
+=0D
+// The time format used to (de/en)code timestamp and timestamp_extra is do=
cumented on=0D
+// the ext4 docs page in kernel.org=0D
+#define EXT4_EXTRA_TIMESTAMP_MASK ((1 << 2) - 1)=0D
+=0D
+#define EXT4_FILE_GET_TIME_GENERIC(Name, Field) \=0D
+ VOID \=0D
+ Ext4File ## Name (IN EXT4_FILE *File, OUT EFI_TIME *Time) \=0D
+ { \=0D
+ EXT4_INODE *Inode =3D File->Inode; \=0D
+ UINT64 SecondsEpoch =3D Inode->Field; \=0D
+ UINT32 Nanoseconds =3D 0; \=0D
+ \=0D
+ if (EXT4_INODE_HAS_FIELD (Inode, Field ## _extra)) { \=0D
+ SecondsEpoch |=3D LShiftU64 ((UINT64)(Inode->Field ## _extra & EXT4_=
EXTRA_TIMESTAMP_MASK), 32); \=0D
+ Nanoseconds =3D Inode->Field ## _extra >> 2; =
\=0D
+ } =
\=0D
+ EpochToEfiTime ((UINTN)SecondsEpoch, Time); =
\=0D
+ Time->Nanosecond =3D Nanoseconds; =
\=0D
+ }=0D
+=0D
+// Note: EpochToEfiTime should be adjusted to take in a UINT64 instead of =
a UINTN, in order to avoid Y2038=0D
+// on 32-bit systems.=0D
+=0D
+/**=0D
+ Gets the file's last access time.=0D
+ @param[in] File Pointer to the opened file.=0D
+ @param[out] Time Pointer to an EFI_TIME structure.=0D
+**/=0D
+EXT4_FILE_GET_TIME_GENERIC (ATime, i_atime);=0D
+=0D
+/**=0D
+ Gets the file's last (data) modification time.=0D
+ @param[in] File Pointer to the opened file.=0D
+ @param[out] Time Pointer to an EFI_TIME structure.=0D
+**/=0D
+EXT4_FILE_GET_TIME_GENERIC (MTime, i_mtime);=0D
+=0D
+/**=0D
+ Gets the file's creation time.=0D
+ @param[in] File Pointer to the opened file.=0D
+ @param[out] Time Pointer to an EFI_TIME structure.=0D
+**/=0D
+STATIC=0D
+EXT4_FILE_GET_TIME_GENERIC (=0D
+ CrTime, i_crtime=0D
+ );=0D
+=0D
+/**=0D
+ Gets the file's creation time, if possible.=0D
+ @param[in] File Pointer to the opened file.=0D
+ @param[out] Time Pointer to an EFI_TIME structure.=0D
+ In the case where the the creation time isn't re=
corded,=0D
+ Time is zeroed.=0D
+**/=0D
+VOID=0D
+Ext4FileCreateTime (=0D
+ IN EXT4_FILE *File,=0D
+ OUT EFI_TIME *Time=0D
+ )=0D
+{=0D
+ EXT4_INODE *Inode;=0D
+=0D
+ Inode =3D File->Inode;=0D
+=0D
+ if (!EXT4_INODE_HAS_FIELD (Inode, i_crtime)) {=0D
+ SetMem (Time, sizeof (EFI_TIME), 0);=0D
+ return;=0D
+ }=0D
+=0D
+ Ext4FileCrTime (File, Time);=0D
+}=0D
+=0D
+/**=0D
+ Checks if the checksum of the inode is correct.=0D
+ @param[in] Partition Pointer to the opened EXT4 partition.=0D
+ @param[in] Inode Pointer to the inode.=0D
+ @param[in] InodeNum Inode number.=0D
+=0D
+ @return TRUE if checksum is correct, FALSE if there is corruption.=0D
+**/=0D
+BOOLEAN=0D
+Ext4CheckInodeChecksum (=0D
+ IN CONST EXT4_PARTITION *Partition,=0D
+ IN CONST EXT4_INODE *Inode,=0D
+ IN EXT4_INO_NR InodeNum=0D
+ )=0D
+{=0D
+ UINT32 Csum;=0D
+ UINT32 DiskCsum;=0D
+=0D
+ if (!EXT4_HAS_METADATA_CSUM (Partition)) {=0D
+ return TRUE;=0D
+ }=0D
+=0D
+ Csum =3D Ext4CalculateInodeChecksum (Partition, Inode, InodeNum);=0D
+=0D
+ DiskCsum =3D Inode->i_osd2.data_linux.l_i_checksum_lo;=0D
+=0D
+ if (EXT4_INODE_HAS_FIELD (Inode, i_checksum_hi)) {=0D
+ DiskCsum |=3D ((UINT32)Inode->i_checksum_hi) << 16;=0D
+ } else {=0D
+ // Only keep the lower bits for the comparison if the checksum is 16 b=
its.=0D
+ Csum &=3D 0xffff;=0D
+ }=0D
+=0D
+ return Csum =3D=3D DiskCsum;=0D
+}=0D
diff --git a/Features/Ext4Pkg/Ext4Dxe/Partition.c b/Features/Ext4Pkg/Ext4Dx=
e/Partition.c
new file mode 100644
index 0000000000..2258bac76a
--- /dev/null
+++ b/Features/Ext4Pkg/Ext4Dxe/Partition.c
@@ -0,0 +1,125 @@
+/** @file=0D
+ Driver entry point=0D
+=0D
+ Copyright (c) 2021 Pedro Falcato All rights reserved.=0D
+ SPDX-License-Identifier: BSD-2-Clause-Patent=0D
+**/=0D
+=0D
+#include "Ext4Dxe.h"=0D
+=0D
+/**=0D
+ Opens an ext4 partition and installs the Simple File System protocol.=0D
+=0D
+ @param[in] DeviceHandle Handle to the block device.=0D
+ @param[in] DiskIo Pointer to an EFI_DISK_IO_PROTOCOL.=
=0D
+ @param[in opt] DiskIo2 Pointer to an EFI_DISK_IO2_PROTOCOL,=
if supported.=0D
+ @param[in] BlockIo Pointer to an EFI_BLOCK_IO_PROTOCOL.=
=0D
+=0D
+ @retval EFI_SUCCESS The opening was successful.=0D
+ !EFI_SUCCESS Opening failed.=0D
+**/=0D
+EFI_STATUS=0D
+Ext4OpenPartition (=0D
+ IN EFI_HANDLE DeviceHandle,=0D
+ IN EFI_DISK_IO_PROTOCOL *DiskIo,=0D
+ IN OPTIONAL EFI_DISK_IO2_PROTOCOL *DiskIo2,=0D
+ IN EFI_BLOCK_IO_PROTOCOL *BlockIo=0D
+ )=0D
+{=0D
+ EXT4_PARTITION *Part;=0D
+ EFI_STATUS Status;=0D
+=0D
+ Part =3D AllocateZeroPool (sizeof (*Part));=0D
+=0D
+ if (Part =3D=3D NULL) {=0D
+ return EFI_OUT_OF_RESOURCES;=0D
+ }=0D
+=0D
+ InitializeListHead (&Part->OpenFiles);=0D
+=0D
+ Part->BlockIo =3D BlockIo;=0D
+ Part->DiskIo =3D DiskIo;=0D
+ Part->DiskIo2 =3D DiskIo2;=0D
+=0D
+ Status =3D Ext4OpenSuperblock (Part);=0D
+=0D
+ if (EFI_ERROR (Status)) {=0D
+ FreePool (Part);=0D
+ return Status;=0D
+ }=0D
+=0D
+ Part->Interface.Revision =3D EFI_SIMPLE_FILE_SYSTEM_PROTOCOL_REVISION;=
=0D
+ Part->Interface.OpenVolume =3D Ext4OpenVolume;=0D
+ Status =3D gBS->InstallMultipleProtocolInterfaces (=0D
+ &DeviceHandle,=0D
+ &gEfiSimpleFileSystemProtocolGuid,=0D
+ &Part->Interface,=0D
+ NULL=0D
+ );=0D
+=0D
+ if (EFI_ERROR (Status)) {=0D
+ FreePool (Part);=0D
+ return Status;=0D
+ }=0D
+=0D
+ return EFI_SUCCESS;=0D
+}=0D
+=0D
+/**=0D
+ Sets up the protocol and metadata of a file that is being opened.=0D
+=0D
+ @param[in out] File Pointer to the file.=0D
+ @param[in] Partition Pointer to the opened partition.=0D
+**/=0D
+VOID=0D
+Ext4SetupFile (=0D
+ IN OUT EXT4_FILE *File,=0D
+ IN EXT4_PARTITION *Partition=0D
+ )=0D
+{=0D
+ // Note: We don't yet support revision 2 of the file protocol=0D
+ // (needs DISK_IO2 + asynchronous IO)=0D
+ File->Protocol.Revision =3D EFI_FILE_PROTOCOL_REVISION;=0D
+ File->Protocol.Open =3D Ext4Open;=0D
+ File->Protocol.Close =3D Ext4Close;=0D
+ File->Protocol.Delete =3D Ext4Delete;=0D
+ File->Protocol.Read =3D Ext4ReadFile;=0D
+ File->Protocol.Write =3D Ext4WriteFile;=0D
+ File->Protocol.SetPosition =3D Ext4SetPosition;=0D
+ File->Protocol.GetPosition =3D Ext4GetPosition;=0D
+ File->Protocol.GetInfo =3D Ext4GetInfo;=0D
+ File->Protocol.SetInfo =3D Ext4SetInfo;=0D
+=0D
+ File->Partition =3D Partition;=0D
+}=0D
+=0D
+/**=0D
+ Unmounts and frees an ext4 partition.=0D
+=0D
+ @param[in] Partition Pointer to the opened partition.=0D
+=0D
+ @retval Status of the unmount.=0D
+**/=0D
+EFI_STATUS=0D
+Ext4UnmountAndFreePartition (=0D
+ IN EXT4_PARTITION *Partition=0D
+ )=0D
+{=0D
+ LIST_ENTRY *Entry;=0D
+ LIST_ENTRY *NextEntry;=0D
+ EXT4_FILE *File;=0D
+=0D
+ Partition->Unmounting =3D TRUE;=0D
+ Ext4CloseInternal (Partition->Root);=0D
+=0D
+ BASE_LIST_FOR_EACH_SAFE (Entry, NextEntry, &Partition->OpenFiles) {=0D
+ File =3D EXT4_FILE_FROM_OPEN_FILES_NODE (Entry);=0D
+=0D
+ Ext4CloseInternal (File);=0D
+ }=0D
+=0D
+ FreePool (Partition->BlockGroups);=0D
+ FreePool (Partition);=0D
+=0D
+ return EFI_SUCCESS;=0D
+}=0D
diff --git a/Features/Ext4Pkg/Ext4Dxe/Superblock.c b/Features/Ext4Pkg/Ext4D=
xe/Superblock.c
new file mode 100644
index 0000000000..8231831115
--- /dev/null
+++ b/Features/Ext4Pkg/Ext4Dxe/Superblock.c
@@ -0,0 +1,297 @@
+/** @file=0D
+ Superblock managing routines=0D
+=0D
+ Copyright (c) 2021 Pedro Falcato All rights reserved.=0D
+ SPDX-License-Identifier: BSD-2-Clause-Patent=0D
+**/=0D
+=0D
+#include "Ext4Dxe.h"=0D
+=0D
+STATIC CONST UINT32 gSupportedCompatFeat =3D EXT4_FEATURE_COMPAT_EXT_ATTR=
;=0D
+=0D
+STATIC CONST UINT32 gSupportedRoCompatFeat =3D=0D
+ EXT4_FEATURE_RO_COMPAT_DIR_NLINK | EXT4_FEATURE_RO_COMPAT_EXTRA_ISIZE |=
=0D
+ EXT4_FEATURE_RO_COMPAT_HUGE_FILE | EXT4_FEATURE_RO_COMPAT_LARGE_FILE |=0D
+ EXT4_FEATURE_RO_COMPAT_GDT_CSUM | EXT4_FEATURE_RO_COMPAT_METADATA_CSUM |=
EXT4_FEATURE_RO_COMPAT_SPARSE_SUPER;=0D
+=0D
+STATIC CONST UINT32 gSupportedIncompatFeat =3D=0D
+ EXT4_FEATURE_INCOMPAT_64BIT | EXT4_FEATURE_INCOMPAT_DIRDATA |=0D
+ EXT4_FEATURE_INCOMPAT_FLEX_BG | EXT4_FEATURE_INCOMPAT_FILETYPE |=0D
+ EXT4_FEATURE_INCOMPAT_EXTENTS | EXT4_FEATURE_INCOMPAT_LARGEDIR |=0D
+ EXT4_FEATURE_INCOMPAT_MMP;=0D
+=0D
+// Future features that may be nice additions in the future:=0D
+// 1) Btree support: Required for write support and would speed up lookups=
in large directories.=0D
+// 2) meta_bg: Required to mount meta_bg-enabled partitions.=0D
+=0D
+// Note: We ignore MMP because it's impossible that it's mapped elsewhere,=
=0D
+// I think (unless there's some sort of network setup where we're accessin=
g a remote partition).=0D
+=0D
+// Note on corruption signaling:=0D
+// We (Ext4Dxe) could signal corruption by setting s_state to |=3D EXT4_FS=
_STATE_ERRORS_DETECTED.=0D
+// I've decided against that, because right now the driver is read-only, a=
nd=0D
+// that would mean we would need to writeback the superblock. If something=
like=0D
+// this is desired, it's fairly trivial to look for EFI_VOLUME_CORRUPTED=0D
+// references and add some Ext4SignalCorruption function + function call.=
=0D
+=0D
+/**=0D
+ Does brief validation of the ext4 superblock.=0D
+=0D
+ @param[in] Sb Pointer to the read superblock.=0D
+=0D
+ @return TRUE if a valid ext4 superblock, else FALSE.=0D
+**/=0D
+BOOLEAN=0D
+Ext4SuperblockValidate (=0D
+ CONST EXT4_SUPERBLOCK *Sb=0D
+ )=0D
+{=0D
+ if (Sb->s_magic !=3D EXT4_SIGNATURE) {=0D
+ return FALSE;=0D
+ }=0D
+=0D
+ if (Sb->s_rev_level !=3D EXT4_DYNAMIC_REV && Sb->s_rev_level !=3D EXT4_G=
OOD_OLD_REV) {=0D
+ return FALSE;=0D
+ }=0D
+=0D
+ // Is this correct behaviour? Imagine the power cuts out, should the sys=
tem fail to boot because=0D
+ // we're scared of touching something corrupt?=0D
+ if ((Sb->s_state & EXT4_FS_STATE_UNMOUNTED) =3D=3D 0) {=0D
+ return FALSE;=0D
+ }=0D
+=0D
+ return TRUE;=0D
+}=0D
+=0D
+/**=0D
+ Calculates the superblock's checksum.=0D
+=0D
+ @param[in] Partition Pointer to the opened partition.=0D
+ @param[in] Sb Pointer to the superblock.=0D
+=0D
+ @return The superblock's checksum.=0D
+**/=0D
+STATIC=0D
+UINT32=0D
+Ext4CalculateSuperblockChecksum (=0D
+ EXT4_PARTITION *Partition,=0D
+ CONST EXT4_SUPERBLOCK *Sb=0D
+ )=0D
+{=0D
+ // Most checksums require us to go through a dummy 0 as part of the requ=
irement=0D
+ // that the checksum is done over a structure with its checksum field =
=3D 0.=0D
+ UINT32 Checksum;=0D
+=0D
+ Checksum =3D Ext4CalculateChecksum (=0D
+ Partition,=0D
+ Sb,=0D
+ OFFSET_OF (EXT4_SUPERBLOCK, s_checksum),=0D
+ ~0U=0D
+ );=0D
+=0D
+ return Checksum;=0D
+}=0D
+=0D
+/**=0D
+ Verifies that the superblock's checksum is valid.=0D
+=0D
+ @param[in] Partition Pointer to the opened partition.=0D
+ @param[in] Sb Pointer to the superblock.=0D
+=0D
+ @return The superblock's checksum.=0D
+**/=0D
+STATIC=0D
+BOOLEAN=0D
+Ext4VerifySuperblockChecksum (=0D
+ EXT4_PARTITION *Partition,=0D
+ CONST EXT4_SUPERBLOCK *Sb=0D
+ )=0D
+{=0D
+ if (!EXT4_HAS_METADATA_CSUM (Partition)) {=0D
+ return TRUE;=0D
+ }=0D
+=0D
+ return Sb->s_checksum =3D=3D Ext4CalculateSuperblockChecksum (Partition,=
Sb);=0D
+}=0D
+=0D
+/**=0D
+ Opens and parses the superblock.=0D
+=0D
+ @param[out] Partition Partition structure to fill with filesystem d=
etails.=0D
+ @retval EFI_SUCCESS Parsing was succesful and the partition is a=
=0D
+ valid ext4 partition.=0D
+**/=0D
+EFI_STATUS=0D
+Ext4OpenSuperblock (=0D
+ OUT EXT4_PARTITION *Partition=0D
+ )=0D
+{=0D
+ UINT32 Index;=0D
+ EFI_STATUS Status;=0D
+ EXT4_SUPERBLOCK *Sb;=0D
+ UINT32 NrBlocksRem;=0D
+ UINTN NrBlocks;=0D
+ UINT32 UnsupportedRoCompat;=0D
+ EXT4_BLOCK_GROUP_DESC *Desc;=0D
+=0D
+ Status =3D Ext4ReadDiskIo (=0D
+ Partition,=0D
+ &Partition->SuperBlock,=0D
+ sizeof (EXT4_SUPERBLOCK),=0D
+ EXT4_SUPERBLOCK_OFFSET=0D
+ );=0D
+=0D
+ if (EFI_ERROR (Status)) {=0D
+ return Status;=0D
+ }=0D
+=0D
+ Sb =3D &Partition->SuperBlock;=0D
+=0D
+ if (!Ext4SuperblockValidate (Sb)) {=0D
+ return EFI_VOLUME_CORRUPTED;=0D
+ }=0D
+=0D
+ if (Sb->s_rev_level =3D=3D EXT4_DYNAMIC_REV) {=0D
+ Partition->FeaturesCompat =3D Sb->s_feature_compat;=0D
+ Partition->FeaturesIncompat =3D Sb->s_feature_incompat;=0D
+ Partition->FeaturesRoCompat =3D Sb->s_feature_ro_compat;=0D
+ Partition->InodeSize =3D Sb->s_inode_size;=0D
+ } else {=0D
+ // GOOD_OLD_REV=0D
+ Partition->FeaturesCompat =3D Partition->FeaturesIncompat =3D Partitio=
n->FeaturesRoCompat =3D 0;=0D
+ Partition->InodeSize =3D EXT4_GOOD_OLD_INODE_SIZE;=0D
+ }=0D
+=0D
+ // Now, check for the feature set of the filesystem=0D
+ // It's essential to check for this to avoid filesystem corruption and t=
o avoid=0D
+ // accidentally opening an ext2/3/4 filesystem we don't understand, whic=
h would be disasterous.=0D
+=0D
+ if (Partition->FeaturesIncompat & ~gSupportedIncompatFeat) {=0D
+ DEBUG ((DEBUG_ERROR, "[ext4] Unsupported features %lx\n",=0D
+ Partition->FeaturesIncompat & ~gSupportedIncompatFeat));=0D
+ return EFI_UNSUPPORTED;=0D
+ }=0D
+=0D
+ // This should be removed once we add ext2/3 support in the future.=0D
+ if ((Partition->FeaturesIncompat & EXT4_FEATURE_INCOMPAT_EXTENTS) =3D=3D=
0) {=0D
+ return EFI_UNSUPPORTED;=0D
+ }=0D
+=0D
+ // At the time of writing, it's the only supported checksum.=0D
+ if (Partition->FeaturesCompat & EXT4_FEATURE_RO_COMPAT_METADATA_CSUM &&=
=0D
+ Sb->s_checksum_type !=3D EXT4_CHECKSUM_CRC32C) {=0D
+ return EFI_UNSUPPORTED;=0D
+ }=0D
+=0D
+ if (Partition->FeaturesIncompat & EXT4_FEATURE_INCOMPAT_CSUM_SEED) {=0D
+ Partition->InitialSeed =3D Sb->s_checksum_seed;=0D
+ } else {=0D
+ Partition->InitialSeed =3D Ext4CalculateChecksum (Partition, Sb->s_uui=
d, 16, ~0U);=0D
+ }=0D
+=0D
+ UnsupportedRoCompat =3D Partition->FeaturesRoCompat & ~gSupportedRoCompa=
tFeat;=0D
+=0D
+ if (UnsupportedRoCompat !=3D 0) {=0D
+ DEBUG ((DEBUG_WARN, "[ext4] Unsupported ro compat %x\n", UnsupportedRo=
Compat));=0D
+ Partition->ReadOnly =3D TRUE;=0D
+ }=0D
+=0D
+ // gSupportedCompatFeat is documentation-only since we never need to acc=
ess it.=0D
+ // The line below avoids unused variable warnings.=0D
+ (VOID)gSupportedCompatFeat;=0D
+=0D
+ DEBUG ((DEBUG_FS, "Read only =3D %u\n", Partition->ReadOnly));=0D
+=0D
+ Partition->BlockSize =3D (UINT32)LShiftU64 (1024, Sb->s_log_block_size);=
=0D
+=0D
+ // The size of a block group can also be calculated as 8 * Partition->Bl=
ockSize=0D
+ if (Sb->s_blocks_per_group !=3D 8 * Partition->BlockSize) {=0D
+ return EFI_UNSUPPORTED;=0D
+ }=0D
+=0D
+ Partition->NumberBlocks =3D EXT4_BLOCK_NR_FROM_HALFS (Partition, Sb->s_b=
locks_count, Sb->s_blocks_count_hi);=0D
+ Partition->NumberBlockGroups =3D DivU64x32 (Partition->NumberBlocks, Sb-=
s_blocks_per_group);=0D
+=0D
+ DEBUG ((=0D
+ DEBUG_FS,=0D
+ "[ext4] Number of blocks =3D %lu\n[ext4] Number of block groups: %lu\n=
",=0D
+ Partition->NumberBlocks,=0D
+ Partition->NumberBlockGroups=0D
+ ));=0D
+=0D
+ if (EXT4_IS_64_BIT (Partition)) {=0D
+ Partition->DescSize =3D Sb->s_desc_size;=0D
+ } else {=0D
+ Partition->DescSize =3D EXT4_OLD_BLOCK_DESC_SIZE;=0D
+ }=0D
+=0D
+ if (Partition->DescSize < EXT4_64BIT_BLOCK_DESC_SIZE && EXT4_IS_64_BIT (=
Partition)) {=0D
+ // 64 bit filesystems need DescSize to be 64 bytes=0D
+ return EFI_VOLUME_CORRUPTED;=0D
+ }=0D
+=0D
+ if (!Ext4VerifySuperblockChecksum (Partition, Sb)) {=0D
+ DEBUG ((DEBUG_ERROR, "[ext4] Bad superblock checksum %lx\n", Ext4Calcu=
lateSuperblockChecksum (Partition, Sb)));=0D
+ return EFI_VOLUME_CORRUPTED;=0D
+ }=0D
+=0D
+ NrBlocks =3D (UINTN)DivU64x32Remainder (=0D
+ MultU64x32 (Partition->NumberBlockGroups, Partition-=
DescSize),=0D
+ Partition->BlockSize,=0D
+ &NrBlocksRem=0D
+ );=0D
+=0D
+ if (NrBlocksRem !=3D 0) {=0D
+ NrBlocks++;=0D
+ }=0D
+=0D
+ Partition->BlockGroups =3D Ext4AllocAndReadBlocks (Partition, NrBlocks, =
Partition->BlockSize =3D=3D 1024 ? 2 : 1);=0D
+=0D
+ if (!Partition->BlockGroups) {=0D
+ return EFI_OUT_OF_RESOURCES;=0D
+ }=0D
+=0D
+ for (Index =3D 0; Index < Partition->NumberBlockGroups; Index++) {=0D
+ Desc =3D Ext4GetBlockGroupDesc (Partition, Index);=0D
+ if (!Ext4VerifyBlockGroupDescChecksum (Partition, Desc, Index)) {=0D
+ DEBUG ((DEBUG_ERROR, "[ext4] Block group descriptor %u has an invali=
d checksum\n", Index));=0D
+ return EFI_VOLUME_CORRUPTED;=0D
+ }=0D
+ }=0D
+=0D
+ // Note that the cast below is completely safe, because EXT4_FILE is a s=
pecialisation of EFI_FILE_PROTOCOL=0D
+ Status =3D Ext4OpenVolume (&Partition->Interface, (EFI_FILE_PROTOCOL **)=
&Partition->Root);=0D
+=0D
+ return Status;=0D
+}=0D
+=0D
+/**=0D
+ Calculates the checksum of the given buffer.=0D
+ @param[in] Partition Pointer to the opened EXT4 partition.=0D
+ @param[in] Buffer Pointer to the buffer.=0D
+ @param[in] Length Length of the buffer, in bytes.=0D
+ @param[in] InitialValue Initial value of the CRC.=0D
+=0D
+ @return The checksum.=0D
+**/=0D
+UINT32=0D
+Ext4CalculateChecksum (=0D
+ IN CONST EXT4_PARTITION *Partition,=0D
+ IN CONST VOID *Buffer,=0D
+ IN UINTN Length,=0D
+ IN UINT32 InitialValue=0D
+ )=0D
+{=0D
+ if (!EXT4_HAS_METADATA_CSUM (Partition)) {=0D
+ return 0;=0D
+ }=0D
+=0D
+ switch (Partition->SuperBlock.s_checksum_type) {=0D
+ case EXT4_CHECKSUM_CRC32C:=0D
+ // For some reason, EXT4 really likes non-inverted CRC32C checksums,=
so we stick to that here.=0D
+ return ~CalculateCrc32c(Buffer, Length, ~InitialValue);=0D
+ default:=0D
+ UNREACHABLE ();=0D
+ return 0;=0D
+ }=0D
+}=0D
--=20
2.32.0


[Patch v3 1/3] Ext4Pkg: Add Ext4Pkg.dec and Ext4Pkg.uni.

Pedro Falcato
 

These files are needed to build Ext4Pkg.

Cc: Leif Lindholm <leif@nuviainc.com>
Cc: Michael D Kinney <michael.d.kinney@intel.com>
Cc: Bret Barkelew <Bret.Barkelew@microsoft.com>

Signed-off-by: Pedro Falcato <pedro.falcato@gmail.com>
---
Features/Ext4Pkg/Ext4Pkg.dec | 17 +++++++++++++++++
Features/Ext4Pkg/Ext4Pkg.uni | 14 ++++++++++++++
2 files changed, 31 insertions(+)
create mode 100644 Features/Ext4Pkg/Ext4Pkg.dec
create mode 100644 Features/Ext4Pkg/Ext4Pkg.uni

diff --git a/Features/Ext4Pkg/Ext4Pkg.dec b/Features/Ext4Pkg/Ext4Pkg.dec
new file mode 100644
index 0000000000..f1f8b39c3c
--- /dev/null
+++ b/Features/Ext4Pkg/Ext4Pkg.dec
@@ -0,0 +1,17 @@
+## @file=0D
+# Ext4 Package=0D
+#=0D
+# This package provides libraries and drivers related to the ext4 filesys=
tem implementation.=0D
+# More details are available at: https://www.kernel.org/doc/html/v5.4/fil=
esystems/ext4/index.html=0D
+#=0D
+# Copyright (c) 2021 Pedro Falcato=0D
+# SPDX-License-Identifier: BSD-2-Clause-Patent=0D
+#=0D
+##=0D
+=0D
+[Defines]=0D
+ DEC_SPECIFICATION =3D 0x00010005=0D
+ PACKAGE_NAME =3D Ext4Pkg=0D
+ PACKAGE_UNI_FILE =3D Ext4Pkg.uni=0D
+ PACKAGE_GUID =3D 6B4BF998-668B-46D3-BCFA-971F99F8708C=
=0D
+ PACKAGE_VERSION =3D 0.1=0D
diff --git a/Features/Ext4Pkg/Ext4Pkg.uni b/Features/Ext4Pkg/Ext4Pkg.uni
new file mode 100644
index 0000000000..abeadd8fd9
--- /dev/null
+++ b/Features/Ext4Pkg/Ext4Pkg.uni
@@ -0,0 +1,14 @@
+## @file=0D
+# Ext4 Package=0D
+#=0D
+# This package provides libraries and drivers related to the ext4 filesys=
tem implementation.=0D
+# More details are available at: https://www.kernel.org/doc/html/v5.4/fil=
esystems/ext4/index.html=0D
+#=0D
+# Copyright (c) 2021 Pedro Falcato=0D
+# SPDX-License-Identifier: BSD-2-Clause-Patent=0D
+#=0D
+##=0D
+=0D
+#string STR_PACKAGE_ABSTRACT #language en-US "Module implementa=
tions for the EXT4 file system"=0D
+=0D
+#string STR_PACKAGE_DESCRIPTION #language en-US "This package cont=
ains UEFI drivers and libraries for the EXT4 file system."=0D
--=20
2.32.0


[Patch v3 0/3] Ext4Pkg: Add Ext4Pkg

Pedro Falcato
 

This patch-set adds Ext4Pkg, a package designed to hold various drivers and
utilities related to the EXT4 filesystem.

Right now, it holds a single read-only UEFI EXT4 driver (Ext4Dxe), which consumes the
DISK_IO, BLOCK_IO and DISK_IO2 protocols and produce EFI_FILE_PROTOCOL and
EFI_SIMPLE_FILE_SYSTEM_PROTOCOL; this driver allows the mounting of EXT4 partitions and
the reading of their contents.

A relevant RFC discussion, which includes a more in-depth walkthrough of EXT4 internals and
driver limitations is available at https://edk2.groups.io/g/devel/topic/84368561.

This patch set is version 3 and attempts to address issues raised by the
community in v2's code review.

Cc: Leif Lindholm <leif@nuviainc.com>
Cc: Michael D Kinney <michael.d.kinney@intel.com>
Cc: Bret Barkelew <Bret.Barkelew@microsoft.com>

Pedro Falcato (3):
Ext4Pkg: Add Ext4Pkg.dec and Ext4Pkg.uni.
Ext4Pkg: Add Ext4Dxe driver.
Ext4Pkg: Add .DSC file.

Features/Ext4Pkg/Ext4Dxe/BlockGroup.c | 228 ++++++
Features/Ext4Pkg/Ext4Dxe/Collation.c | 173 +++++
Features/Ext4Pkg/Ext4Dxe/Crc16.c | 75 ++
Features/Ext4Pkg/Ext4Dxe/Crc32c.c | 84 ++
Features/Ext4Pkg/Ext4Dxe/Directory.c | 498 ++++++++++++
Features/Ext4Pkg/Ext4Dxe/DiskUtil.c | 113 +++
Features/Ext4Pkg/Ext4Dxe/Ext4Disk.h | 453 +++++++++++
Features/Ext4Pkg/Ext4Dxe/Ext4Dxe.c | 808 +++++++++++++++++++
Features/Ext4Pkg/Ext4Dxe/Ext4Dxe.h | 1038 +++++++++++++++++++++++++
Features/Ext4Pkg/Ext4Dxe/Ext4Dxe.inf | 149 ++++
Features/Ext4Pkg/Ext4Dxe/Ext4Dxe.uni | 15 +
Features/Ext4Pkg/Ext4Dxe/Extents.c | 595 ++++++++++++++
Features/Ext4Pkg/Ext4Dxe/File.c | 787 +++++++++++++++++++
Features/Ext4Pkg/Ext4Dxe/Inode.c | 465 +++++++++++
Features/Ext4Pkg/Ext4Dxe/Partition.c | 125 +++
Features/Ext4Pkg/Ext4Dxe/Superblock.c | 297 +++++++
Features/Ext4Pkg/Ext4Pkg.dec | 17 +
Features/Ext4Pkg/Ext4Pkg.dsc | 68 ++
Features/Ext4Pkg/Ext4Pkg.uni | 14 +
19 files changed, 6002 insertions(+)
create mode 100644 Features/Ext4Pkg/Ext4Dxe/BlockGroup.c
create mode 100644 Features/Ext4Pkg/Ext4Dxe/Collation.c
create mode 100644 Features/Ext4Pkg/Ext4Dxe/Crc16.c
create mode 100644 Features/Ext4Pkg/Ext4Dxe/Crc32c.c
create mode 100644 Features/Ext4Pkg/Ext4Dxe/Directory.c
create mode 100644 Features/Ext4Pkg/Ext4Dxe/DiskUtil.c
create mode 100644 Features/Ext4Pkg/Ext4Dxe/Ext4Disk.h
create mode 100644 Features/Ext4Pkg/Ext4Dxe/Ext4Dxe.c
create mode 100644 Features/Ext4Pkg/Ext4Dxe/Ext4Dxe.h
create mode 100644 Features/Ext4Pkg/Ext4Dxe/Ext4Dxe.inf
create mode 100644 Features/Ext4Pkg/Ext4Dxe/Ext4Dxe.uni
create mode 100644 Features/Ext4Pkg/Ext4Dxe/Extents.c
create mode 100644 Features/Ext4Pkg/Ext4Dxe/File.c
create mode 100644 Features/Ext4Pkg/Ext4Dxe/Inode.c
create mode 100644 Features/Ext4Pkg/Ext4Dxe/Partition.c
create mode 100644 Features/Ext4Pkg/Ext4Dxe/Superblock.c
create mode 100644 Features/Ext4Pkg/Ext4Pkg.dec
create mode 100644 Features/Ext4Pkg/Ext4Pkg.dsc
create mode 100644 Features/Ext4Pkg/Ext4Pkg.uni

--
2.32.0


[PATCH V2 3/3] MdeModulePkg: Consume new alignment-related macros

Marvin Häuser
 

This patch substitutes the macros that were renamed in the first
patch with the new, shared alignment macros.

Cc: Jian J Wang <jian.j.wang@intel.com>
Cc: Hao A Wu <hao.a.wu@intel.com>
Cc: Ray Ni <ray.ni@intel.com>
Cc: Vitaly Cheptsov <vit9696@protonmail.com>
Signed-off-by: Marvin Häuser <mhaeuser@posteo.de>
---
MdeModulePkg/Bus/Ata/AhciPei/AhciMode.c | 2 +-
MdeModulePkg/Bus/Ata/AhciPei/AhciPeiPassThru.c | 6 ++--
MdeModulePkg/Bus/Ata/AtaAtapiPassThru/AtaAtapiPassThru.c | 12 +++----
MdeModulePkg/Bus/Ata/AtaBusDxe/AtaPassThruExecute.c | 2 +-
MdeModulePkg/Bus/Scsi/ScsiDiskDxe/ScsiDisk.c | 4 +--
MdeModulePkg/Bus/Ufs/UfsPassThruDxe/UfsPassThru.c | 6 ++--
MdeModulePkg/Universal/EbcDxe/EbcExecute.c | 36 ++++++++++----------
MdeModulePkg/Bus/Ata/AhciPei/AhciPei.h | 1 -
MdeModulePkg/Bus/Ata/AtaAtapiPassThru/AtaAtapiPassThru.h | 2 --
MdeModulePkg/Bus/Ata/AtaBusDxe/AtaBus.h | 1 -
MdeModulePkg/Bus/Scsi/ScsiDiskDxe/ScsiDisk.h | 2 --
MdeModulePkg/Bus/Ufs/UfsBlockIoPei/UfsBlockIoPei.h | 2 --
MdeModulePkg/Bus/Ufs/UfsPassThruDxe/UfsPassThru.h | 2 --
MdeModulePkg/Universal/EbcDxe/EbcExecute.h | 3 +-
14 files changed, 35 insertions(+), 46 deletions(-)

diff --git a/MdeModulePkg/Bus/Ata/AhciPei/AhciMode.c b/MdeModulePkg/Bus/Ata/AhciPei/AhciMode.c
index cc32b5de4f98..520197aee752 100644
--- a/MdeModulePkg/Bus/Ata/AhciPei/AhciMode.c
+++ b/MdeModulePkg/Bus/Ata/AhciPei/AhciMode.c
@@ -2099,7 +2099,7 @@ TrustTransferAtaDevice (
// ATA PassThru PPI.
//
if ((AtaPassThru->Mode->IoAlign > 1) &&
- !ADDRESS_IS_ALIGNED_ (Buffer, AtaPassThru->Mode->IoAlign)) {
+ !ADDRESS_IS_ALIGNED (Buffer, AtaPassThru->Mode->IoAlign)) {
NewBuffer = AllocateAlignedPages (
EFI_SIZE_TO_PAGES (TransferLength),
AtaPassThru->Mode->IoAlign
diff --git a/MdeModulePkg/Bus/Ata/AhciPei/AhciPeiPassThru.c b/MdeModulePkg/Bus/Ata/AhciPei/AhciPeiPassThru.c
index 31ded8a31048..057ad42d596b 100644
--- a/MdeModulePkg/Bus/Ata/AhciPei/AhciPeiPassThru.c
+++ b/MdeModulePkg/Bus/Ata/AhciPei/AhciPeiPassThru.c
@@ -193,15 +193,15 @@ AhciAtaPassThruPassThru (
}

IoAlign = This->Mode->IoAlign;
- if ((IoAlign > 1) && !ADDRESS_IS_ALIGNED_ (Packet->InDataBuffer, IoAlign)) {
+ if ((IoAlign > 1) && !ADDRESS_IS_ALIGNED (Packet->InDataBuffer, IoAlign)) {
return EFI_INVALID_PARAMETER;
}

- if ((IoAlign > 1) && !ADDRESS_IS_ALIGNED_ (Packet->OutDataBuffer, IoAlign)) {
+ if ((IoAlign > 1) && !ADDRESS_IS_ALIGNED (Packet->OutDataBuffer, IoAlign)) {
return EFI_INVALID_PARAMETER;
}

- if ((IoAlign > 1) && !ADDRESS_IS_ALIGNED_ (Packet->Asb, IoAlign)) {
+ if ((IoAlign > 1) && !ADDRESS_IS_ALIGNED (Packet->Asb, IoAlign)) {
return EFI_INVALID_PARAMETER;
}

diff --git a/MdeModulePkg/Bus/Ata/AtaAtapiPassThru/AtaAtapiPassThru.c b/MdeModulePkg/Bus/Ata/AtaAtapiPassThru/AtaAtapiPassThru.c
index cf98fcdaf344..c7b3cfce1340 100644
--- a/MdeModulePkg/Bus/Ata/AtaAtapiPassThru/AtaAtapiPassThru.c
+++ b/MdeModulePkg/Bus/Ata/AtaAtapiPassThru/AtaAtapiPassThru.c
@@ -1281,15 +1281,15 @@ AtaPassThruPassThru (

Instance = ATA_PASS_THRU_PRIVATE_DATA_FROM_THIS (This);

- if ((This->Mode->IoAlign > 1) && !ADDRESS_IS_ALIGNED_(Packet->InDataBuffer, This->Mode->IoAlign)) {
+ if ((This->Mode->IoAlign > 1) && !ADDRESS_IS_ALIGNED(Packet->InDataBuffer, This->Mode->IoAlign)) {
return EFI_INVALID_PARAMETER;
}

- if ((This->Mode->IoAlign > 1) && !ADDRESS_IS_ALIGNED_(Packet->OutDataBuffer, This->Mode->IoAlign)) {
+ if ((This->Mode->IoAlign > 1) && !ADDRESS_IS_ALIGNED(Packet->OutDataBuffer, This->Mode->IoAlign)) {
return EFI_INVALID_PARAMETER;
}

- if ((This->Mode->IoAlign > 1) && !ADDRESS_IS_ALIGNED_(Packet->Asb, This->Mode->IoAlign)) {
+ if ((This->Mode->IoAlign > 1) && !ADDRESS_IS_ALIGNED(Packet->Asb, This->Mode->IoAlign)) {
return EFI_INVALID_PARAMETER;
}

@@ -2012,15 +2012,15 @@ ExtScsiPassThruPassThru (
return EFI_INVALID_PARAMETER;
}

- if ((This->Mode->IoAlign > 1) && !ADDRESS_IS_ALIGNED_(Packet->InDataBuffer, This->Mode->IoAlign)) {
+ if ((This->Mode->IoAlign > 1) && !ADDRESS_IS_ALIGNED(Packet->InDataBuffer, This->Mode->IoAlign)) {
return EFI_INVALID_PARAMETER;
}

- if ((This->Mode->IoAlign > 1) && !ADDRESS_IS_ALIGNED_(Packet->OutDataBuffer, This->Mode->IoAlign)) {
+ if ((This->Mode->IoAlign > 1) && !ADDRESS_IS_ALIGNED(Packet->OutDataBuffer, This->Mode->IoAlign)) {
return EFI_INVALID_PARAMETER;
}

- if ((This->Mode->IoAlign > 1) && !ADDRESS_IS_ALIGNED_(Packet->SenseData, This->Mode->IoAlign)) {
+ if ((This->Mode->IoAlign > 1) && !ADDRESS_IS_ALIGNED(Packet->SenseData, This->Mode->IoAlign)) {
return EFI_INVALID_PARAMETER;
}

diff --git a/MdeModulePkg/Bus/Ata/AtaBusDxe/AtaPassThruExecute.c b/MdeModulePkg/Bus/Ata/AtaBusDxe/AtaPassThruExecute.c
index 471fb6a7f440..eabab8ac5bc5 100644
--- a/MdeModulePkg/Bus/Ata/AtaBusDxe/AtaPassThruExecute.c
+++ b/MdeModulePkg/Bus/Ata/AtaBusDxe/AtaPassThruExecute.c
@@ -1036,7 +1036,7 @@ TrustTransferAtaDevice (
// Check the alignment of the incoming buffer prior to invoking underlying ATA PassThru
//
AtaPassThru = AtaDevice->AtaBusDriverData->AtaPassThru;
- if ((AtaPassThru->Mode->IoAlign > 1) && !ADDRESS_IS_ALIGNED_ (Buffer, AtaPassThru->Mode->IoAlign)) {
+ if ((AtaPassThru->Mode->IoAlign > 1) && !ADDRESS_IS_ALIGNED (Buffer, AtaPassThru->Mode->IoAlign)) {
NewBuffer = AllocateAlignedBuffer (AtaDevice, TransferLength);
if (NewBuffer == NULL) {
return EFI_OUT_OF_RESOURCES;
diff --git a/MdeModulePkg/Bus/Scsi/ScsiDiskDxe/ScsiDisk.c b/MdeModulePkg/Bus/Scsi/ScsiDiskDxe/ScsiDisk.c
index 81c0fa217a0b..81db2efd0599 100644
--- a/MdeModulePkg/Bus/Scsi/ScsiDiskDxe/ScsiDisk.c
+++ b/MdeModulePkg/Bus/Scsi/ScsiDiskDxe/ScsiDisk.c
@@ -1956,7 +1956,7 @@ ScsiDiskReceiveData (
goto Done;
}

- if ((ScsiDiskDevice->ScsiIo->IoAlign > 1) && !ADDRESS_IS_ALIGNED_ (PayloadBuffer, ScsiDiskDevice->ScsiIo->IoAlign)) {
+ if ((ScsiDiskDevice->ScsiIo->IoAlign > 1) && !ADDRESS_IS_ALIGNED (PayloadBuffer, ScsiDiskDevice->ScsiIo->IoAlign)) {
AlignedBuffer = AllocateAlignedBuffer (ScsiDiskDevice, PayloadBufferSize);
if (AlignedBuffer == NULL) {
Status = EFI_OUT_OF_RESOURCES;
@@ -2171,7 +2171,7 @@ ScsiDiskSendData (
goto Done;
}

- if ((ScsiDiskDevice->ScsiIo->IoAlign > 1) && !ADDRESS_IS_ALIGNED_ (PayloadBuffer, ScsiDiskDevice->ScsiIo->IoAlign)) {
+ if ((ScsiDiskDevice->ScsiIo->IoAlign > 1) && !ADDRESS_IS_ALIGNED (PayloadBuffer, ScsiDiskDevice->ScsiIo->IoAlign)) {
AlignedBuffer = AllocateAlignedBuffer (ScsiDiskDevice, PayloadBufferSize);
if (AlignedBuffer == NULL) {
Status = EFI_OUT_OF_RESOURCES;
diff --git a/MdeModulePkg/Bus/Ufs/UfsPassThruDxe/UfsPassThru.c b/MdeModulePkg/Bus/Ufs/UfsPassThruDxe/UfsPassThru.c
index abfb422d1ea3..c4d01a20fcbe 100644
--- a/MdeModulePkg/Bus/Ufs/UfsPassThruDxe/UfsPassThru.c
+++ b/MdeModulePkg/Bus/Ufs/UfsPassThruDxe/UfsPassThru.c
@@ -170,15 +170,15 @@ UfsPassThruPassThru (
return EFI_INVALID_PARAMETER;
}

- if ((This->Mode->IoAlign > 1) && !ADDRESS_IS_ALIGNED_(Packet->InDataBuffer, This->Mode->IoAlign)) {
+ if ((This->Mode->IoAlign > 1) && !ADDRESS_IS_ALIGNED(Packet->InDataBuffer, This->Mode->IoAlign)) {
return EFI_INVALID_PARAMETER;
}

- if ((This->Mode->IoAlign > 1) && !ADDRESS_IS_ALIGNED_(Packet->OutDataBuffer, This->Mode->IoAlign)) {
+ if ((This->Mode->IoAlign > 1) && !ADDRESS_IS_ALIGNED(Packet->OutDataBuffer, This->Mode->IoAlign)) {
return EFI_INVALID_PARAMETER;
}

- if ((This->Mode->IoAlign > 1) && !ADDRESS_IS_ALIGNED_(Packet->SenseData, This->Mode->IoAlign)) {
+ if ((This->Mode->IoAlign > 1) && !ADDRESS_IS_ALIGNED(Packet->SenseData, This->Mode->IoAlign)) {
return EFI_INVALID_PARAMETER;
}

diff --git a/MdeModulePkg/Universal/EbcDxe/EbcExecute.c b/MdeModulePkg/Universal/EbcDxe/EbcExecute.c
index 35f60cabdeb4..ba66f441bcea 100644
--- a/MdeModulePkg/Universal/EbcDxe/EbcExecute.c
+++ b/MdeModulePkg/Universal/EbcDxe/EbcExecute.c
@@ -2004,7 +2004,7 @@ ExecuteJMP (
// check for alignment, and jump absolute.
//
Data64 = (UINT64) VmReadImmed64 (VmPtr, 2);
- if (!ADDRESS_IS_ALIGNED_ ((UINTN) Data64, sizeof (UINT16))) {
+ if (!ADDRESS_IS_ALIGNED ((UINTN) Data64, sizeof (UINT16))) {
EbcDebugSignalException (
EXCEPT_EBC_ALIGNMENT_CHECK,
EXCEPTION_FLAG_FATAL,
@@ -2059,7 +2059,7 @@ ExecuteJMP (
// Form: JMP32 @Rx {Index32}
//
Addr = VmReadMemN (VmPtr, (UINTN) Data64 + Index32);
- if (!ADDRESS_IS_ALIGNED_ ((UINTN) Addr, sizeof (UINT16))) {
+ if (!ADDRESS_IS_ALIGNED ((UINTN) Addr, sizeof (UINT16))) {
EbcDebugSignalException (
EXCEPT_EBC_ALIGNMENT_CHECK,
EXCEPTION_FLAG_FATAL,
@@ -2082,7 +2082,7 @@ ExecuteJMP (
// Form: JMP32 Rx {Immed32}
//
Addr = (UINTN) (Data64 + Index32);
- if (!ADDRESS_IS_ALIGNED_ ((UINTN) Addr, sizeof (UINT16))) {
+ if (!ADDRESS_IS_ALIGNED ((UINTN) Addr, sizeof (UINT16))) {
EbcDebugSignalException (
EXCEPT_EBC_ALIGNMENT_CHECK,
EXCEPTION_FLAG_FATAL,
@@ -3128,7 +3128,7 @@ ExecuteRET (
// Pull the return address off the VM app's stack and set the IP
// to it
//
- if (!ADDRESS_IS_ALIGNED_ ((UINTN) VmPtr->Gpr[0], sizeof (UINT16))) {
+ if (!ADDRESS_IS_ALIGNED ((UINTN) VmPtr->Gpr[0], sizeof (UINT16))) {
EbcDebugSignalException (
EXCEPT_EBC_ALIGNMENT_CHECK,
EXCEPTION_FLAG_FATAL,
@@ -4693,7 +4693,7 @@ VmWriteMem16 (
//
// Do a simple write if aligned
//
- if (ADDRESS_IS_ALIGNED_ (Addr, sizeof (UINT16))) {
+ if (ADDRESS_IS_ALIGNED (Addr, sizeof (UINT16))) {
*(UINT16 *) Addr = Data;
} else {
//
@@ -4756,7 +4756,7 @@ VmWriteMem32 (
//
// Do a simple write if aligned
//
- if (ADDRESS_IS_ALIGNED_ (Addr, sizeof (UINT32))) {
+ if (ADDRESS_IS_ALIGNED (Addr, sizeof (UINT32))) {
*(UINT32 *) Addr = Data;
} else {
//
@@ -4819,7 +4819,7 @@ VmWriteMem64 (
//
// Do a simple write if aligned
//
- if (ADDRESS_IS_ALIGNED_ (Addr, sizeof (UINT64))) {
+ if (ADDRESS_IS_ALIGNED (Addr, sizeof (UINT64))) {
*(UINT64 *) Addr = Data;
} else {
//
@@ -4885,7 +4885,7 @@ VmWriteMemN (
//
// Do a simple write if aligned
//
- if (ADDRESS_IS_ALIGNED_ (Addr, sizeof (UINTN))) {
+ if (ADDRESS_IS_ALIGNED (Addr, sizeof (UINTN))) {
*(UINTN *) Addr = Data;
} else {
for (Index = 0; Index < sizeof (UINTN) / sizeof (UINT32); Index++) {
@@ -4949,7 +4949,7 @@ VmReadImmed16 (
//
// Read direct if aligned
//
- if (ADDRESS_IS_ALIGNED_ ((UINTN) VmPtr->Ip + Offset, sizeof (INT16))) {
+ if (ADDRESS_IS_ALIGNED ((UINTN) VmPtr->Ip + Offset, sizeof (INT16))) {
return * (INT16 *) (VmPtr->Ip + Offset);
} else {
//
@@ -4993,7 +4993,7 @@ VmReadImmed32 (
//
// Read direct if aligned
//
- if (ADDRESS_IS_ALIGNED_ ((UINTN) VmPtr->Ip + Offset, sizeof (UINT32))) {
+ if (ADDRESS_IS_ALIGNED ((UINTN) VmPtr->Ip + Offset, sizeof (UINT32))) {
return * (INT32 *) (VmPtr->Ip + Offset);
}
//
@@ -5032,7 +5032,7 @@ VmReadImmed64 (
//
// Read direct if aligned
//
- if (ADDRESS_IS_ALIGNED_ ((UINTN) VmPtr->Ip + Offset, sizeof (UINT64))) {
+ if (ADDRESS_IS_ALIGNED ((UINTN) VmPtr->Ip + Offset, sizeof (UINT64))) {
return * (UINT64 *) (VmPtr->Ip + Offset);
}
//
@@ -5069,7 +5069,7 @@ VmReadCode16 (
//
// Read direct if aligned
//
- if (ADDRESS_IS_ALIGNED_ ((UINTN) VmPtr->Ip + Offset, sizeof (UINT16))) {
+ if (ADDRESS_IS_ALIGNED ((UINTN) VmPtr->Ip + Offset, sizeof (UINT16))) {
return * (UINT16 *) (VmPtr->Ip + Offset);
} else {
//
@@ -5110,7 +5110,7 @@ VmReadCode32 (
//
// Read direct if aligned
//
- if (ADDRESS_IS_ALIGNED_ ((UINTN) VmPtr->Ip + Offset, sizeof (UINT32))) {
+ if (ADDRESS_IS_ALIGNED ((UINTN) VmPtr->Ip + Offset, sizeof (UINT32))) {
return * (UINT32 *) (VmPtr->Ip + Offset);
}
//
@@ -5147,7 +5147,7 @@ VmReadCode64 (
//
// Read direct if aligned
//
- if (ADDRESS_IS_ALIGNED_ ((UINTN) VmPtr->Ip + Offset, sizeof (UINT64))) {
+ if (ADDRESS_IS_ALIGNED ((UINTN) VmPtr->Ip + Offset, sizeof (UINT64))) {
return * (UINT64 *) (VmPtr->Ip + Offset);
}
//
@@ -5210,7 +5210,7 @@ VmReadMem16 (
//
// Read direct if aligned
//
- if (ADDRESS_IS_ALIGNED_ (Addr, sizeof (UINT16))) {
+ if (ADDRESS_IS_ALIGNED (Addr, sizeof (UINT16))) {
return * (UINT16 *) Addr;
}
//
@@ -5243,7 +5243,7 @@ VmReadMem32 (
//
// Read direct if aligned
//
- if (ADDRESS_IS_ALIGNED_ (Addr, sizeof (UINT32))) {
+ if (ADDRESS_IS_ALIGNED (Addr, sizeof (UINT32))) {
return * (UINT32 *) Addr;
}
//
@@ -5280,7 +5280,7 @@ VmReadMem64 (
//
// Read direct if aligned
//
- if (ADDRESS_IS_ALIGNED_ (Addr, sizeof (UINT64))) {
+ if (ADDRESS_IS_ALIGNED (Addr, sizeof (UINT64))) {
return * (UINT64 *) Addr;
}
//
@@ -5349,7 +5349,7 @@ VmReadMemN (
//
// Read direct if aligned
//
- if (ADDRESS_IS_ALIGNED_ (Addr, sizeof (UINTN))) {
+ if (ADDRESS_IS_ALIGNED (Addr, sizeof (UINTN))) {
return * (UINTN *) Addr;
}
//
diff --git a/MdeModulePkg/Bus/Ata/AhciPei/AhciPei.h b/MdeModulePkg/Bus/Ata/AhciPei/AhciPei.h
index 2a74c9984791..59bb9e5d0bca 100644
--- a/MdeModulePkg/Bus/Ata/AhciPei/AhciPei.h
+++ b/MdeModulePkg/Bus/Ata/AhciPei/AhciPei.h
@@ -145,7 +145,6 @@ typedef union {
#define AHCI_PORT_SERR 0x0030
#define AHCI_PORT_CI 0x0038

-#define ADDRESS_IS_ALIGNED_(addr, size) (((UINTN) (addr) & (size - 1)) == 0)
#define TIMER_PERIOD_SECONDS(Seconds) MultU64x32((UINT64)(Seconds), 10000000)

#pragma pack(1)
diff --git a/MdeModulePkg/Bus/Ata/AtaAtapiPassThru/AtaAtapiPassThru.h b/MdeModulePkg/Bus/Ata/AtaAtapiPassThru/AtaAtapiPassThru.h
index aa3472a71677..99bbf7d14a17 100644
--- a/MdeModulePkg/Bus/Ata/AtaAtapiPassThru/AtaAtapiPassThru.h
+++ b/MdeModulePkg/Bus/Ata/AtaAtapiPassThru/AtaAtapiPassThru.h
@@ -147,8 +147,6 @@ struct _ATA_NONBLOCK_TASK {
#define ATA_ATAPI_TIMEOUT EFI_TIMER_PERIOD_SECONDS(3)
#define ATA_SPINUP_TIMEOUT EFI_TIMER_PERIOD_SECONDS(10)

-#define ADDRESS_IS_ALIGNED_(addr, size) (((UINTN) (addr) & (size - 1)) == 0)
-
#define ATA_PASS_THRU_PRIVATE_DATA_FROM_THIS(a) \
CR (a, \
ATA_ATAPI_PASS_THRU_INSTANCE, \
diff --git a/MdeModulePkg/Bus/Ata/AtaBusDxe/AtaBus.h b/MdeModulePkg/Bus/Ata/AtaBusDxe/AtaBus.h
index 13767a8a13c8..172d2d61ea6c 100644
--- a/MdeModulePkg/Bus/Ata/AtaBusDxe/AtaBus.h
+++ b/MdeModulePkg/Bus/Ata/AtaBusDxe/AtaBus.h
@@ -76,7 +76,6 @@
#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 ADDRESS_IS_ALIGNED_(addr, size) (((UINTN) (addr) & (size - 1)) == 0)

//
// ATA bus data structure for ATA controller
diff --git a/MdeModulePkg/Bus/Scsi/ScsiDiskDxe/ScsiDisk.h b/MdeModulePkg/Bus/Scsi/ScsiDiskDxe/ScsiDisk.h
index abe1d06a98da..36fac258f3e6 100644
--- a/MdeModulePkg/Bus/Scsi/ScsiDiskDxe/ScsiDisk.h
+++ b/MdeModulePkg/Bus/Scsi/ScsiDiskDxe/ScsiDisk.h
@@ -39,8 +39,6 @@ SPDX-License-Identifier: BSD-2-Clause-Patent

#define IS_DEVICE_FIXED(a) (a)->FixedDevice ? 1 : 0

-#define ADDRESS_IS_ALIGNED_(addr, size) (((UINTN) (addr) & (size - 1)) == 0)
-
#define UFS_WLUN_RPMB 0xC4

typedef struct {
diff --git a/MdeModulePkg/Bus/Ufs/UfsBlockIoPei/UfsBlockIoPei.h b/MdeModulePkg/Bus/Ufs/UfsBlockIoPei/UfsBlockIoPei.h
index 4802fdc0ab9b..7306106a4454 100644
--- a/MdeModulePkg/Bus/Ufs/UfsBlockIoPei/UfsBlockIoPei.h
+++ b/MdeModulePkg/Bus/Ufs/UfsBlockIoPei/UfsBlockIoPei.h
@@ -133,8 +133,6 @@ typedef struct _UFS_PEIM_HC_PRIVATE_DATA {

#define ROUNDUP8(x) (((x) % 8 == 0) ? (x) : ((x) / 8 + 1) * 8)

-#define ADDRESS_IS_ALIGNED_(addr, size) (((UINTN) (addr) & (size - 1)) == 0)
-
#define GET_UFS_PEIM_HC_PRIVATE_DATA_FROM_THIS(a) CR (a, UFS_PEIM_HC_PRIVATE_DATA, BlkIoPpi, UFS_PEIM_HC_SIG)
#define GET_UFS_PEIM_HC_PRIVATE_DATA_FROM_THIS2(a) CR (a, UFS_PEIM_HC_PRIVATE_DATA, BlkIo2Ppi, UFS_PEIM_HC_SIG)
#define GET_UFS_PEIM_HC_PRIVATE_DATA_FROM_THIS_NOTIFY(a) CR (a, UFS_PEIM_HC_PRIVATE_DATA, EndOfPeiNotifyList, UFS_PEIM_HC_SIG)
diff --git a/MdeModulePkg/Bus/Ufs/UfsPassThruDxe/UfsPassThru.h b/MdeModulePkg/Bus/Ufs/UfsPassThruDxe/UfsPassThru.h
index da3bf78bf9bc..11b5b197b67a 100644
--- a/MdeModulePkg/Bus/Ufs/UfsPassThruDxe/UfsPassThru.h
+++ b/MdeModulePkg/Bus/Ufs/UfsPassThruDxe/UfsPassThru.h
@@ -105,8 +105,6 @@ typedef struct {

#define ROUNDUP8(x) (((x) % 8 == 0) ? (x) : ((x) / 8 + 1) * 8)

-#define ADDRESS_IS_ALIGNED_(addr, size) (((UINTN) (addr) & (size - 1)) == 0)
-
#define UFS_PASS_THRU_PRIVATE_DATA_FROM_THIS(a) \
CR (a, \
UFS_PASS_THRU_PRIVATE_DATA, \
diff --git a/MdeModulePkg/Universal/EbcDxe/EbcExecute.h b/MdeModulePkg/Universal/EbcDxe/EbcExecute.h
index f21c757a75b4..dcbdc66637e9 100644
--- a/MdeModulePkg/Universal/EbcDxe/EbcExecute.h
+++ b/MdeModulePkg/Universal/EbcDxe/EbcExecute.h
@@ -14,8 +14,7 @@ SPDX-License-Identifier: BSD-2-Clause-Patent
//
// Macros to check and set alignment
//
-#define ASSERT_ALIGNED(addr, size) ASSERT (!((UINT32) (addr) & (size - 1)))
-#define ADDRESS_IS_ALIGNED_(addr, size) !((UINT32) (addr) & (size - 1))
+#define ASSERT_ALIGNED(addr, size) ASSERT (ADDRESS_IS_ALIGNED (addr, size))

//
// Debug macro
--
2.31.1


[PATCH V2 2/3] MdePkg/Base.h: Introduce various alignment-related macros

Marvin Häuser
 

ALIGNOF: Determining the alignment requirement of data types is
crucial to ensure safe memory accesses when parsing untrusted data.

IS_POW2: Determining whether a value is a power of two is important
to verify whether untrusted values are valid alignment values.

IS_ALIGNED: In combination with ALIGNOF data offsets can be verified.
A more general version of the IS_ALIGNED macro previously defined by several modules.

ADDRESS_IS_ALIGNED: Variant of IS_ALIGNED for pointers and addresses.
Replaces module-specific definitions throughout the codebase.

ALIGN_VALUE_ADDEND: The addend to align up can be used to directly
determine the required offset for data alignment.

Cc: Michael D Kinney <michael.d.kinney@intel.com>
Cc: Liming Gao <gaoliming@byosoft.com.cn>
Cc: Zhiguang Liu <zhiguang.liu@intel.com>
Cc: Vitaly Cheptsov <vit9696@protonmail.com>
Signed-off-by: Marvin Häuser <mhaeuser@posteo.de>
---
MdePkg/Include/Base.h | 90 +++++++++++++++++++-
1 file changed, 89 insertions(+), 1 deletion(-)

diff --git a/MdePkg/Include/Base.h b/MdePkg/Include/Base.h
index 2da08b0c787f..32d0e512e05f 100644
--- a/MdePkg/Include/Base.h
+++ b/MdePkg/Include/Base.h
@@ -789,6 +789,35 @@ 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(__GNUC__) || defined(__clang__) || (defined(_MSC_VER) && _MSC_VER >= 1900)
+ //
+ // All supported versions of GCC and Clang, as well as MSVC 2015 and later,
+ // support the standard operator _Alignof.
+ //
+ #define ALIGNOF(TYPE) _Alignof (TYPE)
+#elif defined(_MSC_VER)
+ //
+ // Earlier versions of MSVC, at least MSVC 2008 and later, 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.
@@ -824,6 +853,21 @@ STATIC_ASSERT (sizeof (CHAR16) == 2, "sizeof (CHAR16) does not meet UEFI Specif
STATIC_ASSERT (sizeof (L'A') == 2, "sizeof (L'A') does not meet UEFI Specification Data Type requirements");
STATIC_ASSERT (sizeof (L"A") == 4, "sizeof (L\"A\") does not meet UEFI Specification Data Type requirements");

+STATIC_ASSERT (ALIGNOF (BOOLEAN) == sizeof (BOOLEAN), "Alignment of BOOLEAN does not meet UEFI Specification Data Type requirements");
+STATIC_ASSERT (ALIGNOF (INT8) == sizeof (INT8), "Alignment of INT8 does not meet UEFI Specification Data Type requirements");
+STATIC_ASSERT (ALIGNOF (UINT8) == sizeof (UINT8), "Alignment of INT16 does not meet UEFI Specification Data Type requirements");
+STATIC_ASSERT (ALIGNOF (INT16) == sizeof (INT16), "Alignment of INT16 does not meet UEFI Specification Data Type requirements");
+STATIC_ASSERT (ALIGNOF (UINT16) == sizeof (UINT16), "Alignment of UINT16 does not meet UEFI Specification Data Type requirements");
+STATIC_ASSERT (ALIGNOF (INT32) == sizeof (INT32), "Alignment of INT32 does not meet UEFI Specification Data Type requirements");
+STATIC_ASSERT (ALIGNOF (UINT32) == sizeof (UINT32), "Alignment of UINT32 does not meet UEFI Specification Data Type requirements");
+STATIC_ASSERT (ALIGNOF (INT64) == sizeof (INT64), "Alignment of INT64 does not meet UEFI Specification Data Type requirements");
+STATIC_ASSERT (ALIGNOF (UINT64) == sizeof (UINT64), "Alignment of UINT64 does not meet UEFI Specification Data Type requirements");
+STATIC_ASSERT (ALIGNOF (CHAR8) == sizeof (CHAR8), "Alignment of CHAR8 does not meet UEFI Specification Data Type requirements");
+STATIC_ASSERT (ALIGNOF (CHAR16) == sizeof (CHAR16), "Alignment of CHAR16 does not meet UEFI Specification Data Type requirements");
+STATIC_ASSERT (ALIGNOF (INTN) == sizeof (INTN), "Alignment of INTN does not meet UEFI Specification Data Type requirements");
+STATIC_ASSERT (ALIGNOF (UINTN) == sizeof (UINTN), "Alignment of UINTN does not meet UEFI Specification Data Type requirements");
+STATIC_ASSERT (ALIGNOF (VOID *) == sizeof (VOID *), "Alignment of VOID * does not meet UEFI Specification Data Type requirements");
+
//
// The following three enum types are used to verify that the compiler
// configuration for enum types is compliant with Section 2.3.1 of the
@@ -847,6 +891,10 @@ STATIC_ASSERT (sizeof (__VERIFY_UINT8_ENUM_SIZE) == 4, "Size of enum does not me
STATIC_ASSERT (sizeof (__VERIFY_UINT16_ENUM_SIZE) == 4, "Size of enum does not meet UEFI Specification Data Type requirements");
STATIC_ASSERT (sizeof (__VERIFY_UINT32_ENUM_SIZE) == 4, "Size of enum does not meet UEFI Specification Data Type requirements");

+STATIC_ASSERT (ALIGNOF (__VERIFY_UINT8_ENUM_SIZE) == sizeof (__VERIFY_UINT8_ENUM_SIZE), "Alignment of enum does not meet UEFI Specification Data Type requirements");
+STATIC_ASSERT (ALIGNOF (__VERIFY_UINT16_ENUM_SIZE) == sizeof (__VERIFY_UINT16_ENUM_SIZE), "Alignment of enum does not meet UEFI Specification Data Type requirements");
+STATIC_ASSERT (ALIGNOF (__VERIFY_UINT32_ENUM_SIZE) == sizeof (__VERIFY_UINT32_ENUM_SIZE), "Alignment of enum does not meet UEFI Specification Data Type requirements");
+
/**
Macro that returns a pointer to the data structure that contains a specified field of
that data structure. This is a lightweight method to hide information by placing a
@@ -868,6 +916,46 @@ 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.
+
+ @return Whether Value is a power of two.
+**/
+#define IS_POW2(Value) ((Value) != 0U && ((Value) & ((Value) - 1U)) == 0U)
+
+/**
+ 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.
+
+ @return Whether Value is aligned by Alignment.
+**/
+#define IS_ALIGNED(Value, Alignment) (((Value) & ((Alignment) - 1U)) == 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.
+
+ @return Whether Address is 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.

@@ -880,7 +968,7 @@ STATIC_ASSERT (sizeof (__VERIFY_UINT32_ENUM_SIZE) == 4, "Size of enum does not m
@return A value up to the next boundary.

**/
-#define ALIGN_VALUE(Value, Alignment) ((Value) + (((Alignment) - (Value)) & ((Alignment) - 1)))
+#define ALIGN_VALUE(Value, Alignment) ((Value) + ALIGN_VALUE_ADDEND (Value, Alignment))

/**
Adjust a pointer by adding the minimum offset required for it to be aligned on
--
2.31.1


[PATCH 1/1] MdeModulePkg/EbcDxe: Mitigate memcpy intrinsics

Marvin Häuser
 

Assignments of structure values cause the emission of memcpy()
intrinsics by the CLANG38 toolchain. Substitute the assignments with
calls to CopyMem() to mitigate the issue.

Cc: Jian J Wang <jian.j.wang@intel.com>
Cc: Hao A Wu <hao.a.wu@intel.com>
Cc: Vitaly Cheptsov <vit9696@protonmail.com>
Signed-off-by: Marvin Häuser <mhaeuser@posteo.de>
---
MdeModulePkg/Universal/EbcDxe/EbcDebugger/Edb.c | 6 +++++-
MdeModulePkg/Universal/EbcDxe/EbcDebugger/EdbCmdBreakpoint.c | 6 +++++-
MdeModulePkg/Universal/EbcDxe/EbcDebugger/EdbHook.c | 6 +++++-
3 files changed, 15 insertions(+), 3 deletions(-)

diff --git a/MdeModulePkg/Universal/EbcDxe/EbcDebugger/Edb.c b/MdeModulePkg/Universal/EbcDxe/EbcDebugger/Edb.c
index 611b2de5d81f..e417f4870f3d 100644
--- a/MdeModulePkg/Universal/EbcDxe/EbcDebugger/Edb.c
+++ b/MdeModulePkg/Universal/EbcDxe/EbcDebugger/Edb.c
@@ -219,7 +219,11 @@ EdbCheckBreakpoint (
//
// If hit, record current breakpoint
//
- DebuggerPrivate->DebuggerBreakpointContext[EFI_DEBUGGER_BREAKPOINT_MAX] = DebuggerPrivate->DebuggerBreakpointContext[Index];
+ CopyMem (
+ &DebuggerPrivate->DebuggerBreakpointContext[EFI_DEBUGGER_BREAKPOINT_MAX],
+ &DebuggerPrivate->DebuggerBreakpointContext[Index],
+ sizeof (DebuggerPrivate->DebuggerBreakpointContext[EFI_DEBUGGER_BREAKPOINT_MAX])
+ );
DebuggerPrivate->DebuggerBreakpointContext[EFI_DEBUGGER_BREAKPOINT_MAX].State = TRUE;
//
// Do not set Breakpoint flag. We record the address here just let it not patch breakpoint address when de-init.
diff --git a/MdeModulePkg/Universal/EbcDxe/EbcDebugger/EdbCmdBreakpoint.c b/MdeModulePkg/Universal/EbcDxe/EbcDebugger/EdbCmdBreakpoint.c
index e0c797be247f..5d32c684066e 100644
--- a/MdeModulePkg/Universal/EbcDxe/EbcDebugger/EdbCmdBreakpoint.c
+++ b/MdeModulePkg/Universal/EbcDxe/EbcDebugger/EdbCmdBreakpoint.c
@@ -158,7 +158,11 @@ DebuggerBreakpointDel (
// Delete this breakpoint
//
for (BpIndex = Index; BpIndex < DebuggerPrivate->DebuggerBreakpointCount - 1; BpIndex++) {
- DebuggerPrivate->DebuggerBreakpointContext[BpIndex] = DebuggerPrivate->DebuggerBreakpointContext[BpIndex + 1];
+ CopyMem (
+ &DebuggerPrivate->DebuggerBreakpointContext[BpIndex],
+ &DebuggerPrivate->DebuggerBreakpointContext[BpIndex + 1],
+ sizeof (DebuggerPrivate->DebuggerBreakpointContext[BpIndex])
+ );
}
ZeroMem (
&DebuggerPrivate->DebuggerBreakpointContext[BpIndex],
diff --git a/MdeModulePkg/Universal/EbcDxe/EbcDebugger/EdbHook.c b/MdeModulePkg/Universal/EbcDxe/EbcDebugger/EdbHook.c
index 83257a2c25fe..1bfe5240c760 100644
--- a/MdeModulePkg/Universal/EbcDxe/EbcDebugger/EdbHook.c
+++ b/MdeModulePkg/Universal/EbcDxe/EbcDebugger/EdbHook.c
@@ -230,7 +230,11 @@ EbcDebuggerPushTraceDestEntry (
//
ASSERT (mDebuggerPrivate.TraceEntry[EFI_DEBUGGER_TRACE_MAX].Type == Type);
for (Index = 0; Index < EFI_DEBUGGER_TRACE_MAX; Index++) {
- mDebuggerPrivate.TraceEntry[Index] = mDebuggerPrivate.TraceEntry[Index + 1];
+ CopyMem (
+ &mDebuggerPrivate.TraceEntry[Index],
+ &mDebuggerPrivate.TraceEntry[Index + 1],
+ sizeof (mDebuggerPrivate.TraceEntry[Index])
+ );
}
mDebuggerPrivate.TraceEntry[EFI_DEBUGGER_CALLSTACK_MAX - 1].DestAddress = DestEntry;
mDebuggerPrivate.TraceEntryCount = EFI_DEBUGGER_TRACE_MAX;
--
2.31.1


[PATCH V2 1/3] MdeModulePkg: Rename IS_ALIGNED macros to avoid name collisions

Marvin Häuser
 

This patch is a preparation for the patches that follow. The
subsequent patches will introduce and integrate new alignment-related
macros, which collide with existing definitions in MdeModulePkg.
Temporarily rename them to avoid build failure, till they can be
substituted with the new, shared definitions.

Cc: Jian J Wang <jian.j.wang@intel.com>
Cc: Hao A Wu <hao.a.wu@intel.com>
Cc: Ray Ni <ray.ni@intel.com>
Signed-off-by: Marvin Häuser <mhaeuser@posteo.de>
---
MdeModulePkg/Bus/Ata/AhciPei/AhciMode.c | 2 +-
MdeModulePkg/Bus/Ata/AhciPei/AhciPeiPassThru.c | 6 ++--
MdeModulePkg/Bus/Ata/AtaAtapiPassThru/AtaAtapiPassThru.c | 12 +++----
MdeModulePkg/Bus/Ata/AtaBusDxe/AtaPassThruExecute.c | 2 +-
MdeModulePkg/Bus/Scsi/ScsiDiskDxe/ScsiDisk.c | 4 +--
MdeModulePkg/Bus/Ufs/UfsPassThruDxe/UfsPassThru.c | 6 ++--
MdeModulePkg/Universal/EbcDxe/EbcExecute.c | 36 ++++++++++----------
MdeModulePkg/Bus/Ata/AhciPei/AhciPei.h | 2 +-
MdeModulePkg/Bus/Ata/AtaAtapiPassThru/AtaAtapiPassThru.h | 2 +-
MdeModulePkg/Bus/Ata/AtaBusDxe/AtaBus.h | 2 +-
MdeModulePkg/Bus/Scsi/ScsiDiskDxe/ScsiDisk.h | 2 +-
MdeModulePkg/Bus/Ufs/UfsBlockIoPei/UfsBlockIoPei.h | 2 +-
MdeModulePkg/Bus/Ufs/UfsPassThruDxe/UfsPassThru.h | 2 +-
MdeModulePkg/Universal/EbcDxe/EbcExecute.h | 2 +-
14 files changed, 41 insertions(+), 41 deletions(-)

diff --git a/MdeModulePkg/Bus/Ata/AhciPei/AhciMode.c b/MdeModulePkg/Bus/Ata/AhciPei/AhciMode.c
index 7636ad27c86c..cc32b5de4f98 100644
--- a/MdeModulePkg/Bus/Ata/AhciPei/AhciMode.c
+++ b/MdeModulePkg/Bus/Ata/AhciPei/AhciMode.c
@@ -2099,7 +2099,7 @@ TrustTransferAtaDevice (
// ATA PassThru PPI.
//
if ((AtaPassThru->Mode->IoAlign > 1) &&
- !IS_ALIGNED (Buffer, AtaPassThru->Mode->IoAlign)) {
+ !ADDRESS_IS_ALIGNED_ (Buffer, AtaPassThru->Mode->IoAlign)) {
NewBuffer = AllocateAlignedPages (
EFI_SIZE_TO_PAGES (TransferLength),
AtaPassThru->Mode->IoAlign
diff --git a/MdeModulePkg/Bus/Ata/AhciPei/AhciPeiPassThru.c b/MdeModulePkg/Bus/Ata/AhciPei/AhciPeiPassThru.c
index 191b78c88541..31ded8a31048 100644
--- a/MdeModulePkg/Bus/Ata/AhciPei/AhciPeiPassThru.c
+++ b/MdeModulePkg/Bus/Ata/AhciPei/AhciPeiPassThru.c
@@ -193,15 +193,15 @@ AhciAtaPassThruPassThru (
}

IoAlign = This->Mode->IoAlign;
- if ((IoAlign > 1) && !IS_ALIGNED (Packet->InDataBuffer, IoAlign)) {
+ if ((IoAlign > 1) && !ADDRESS_IS_ALIGNED_ (Packet->InDataBuffer, IoAlign)) {
return EFI_INVALID_PARAMETER;
}

- if ((IoAlign > 1) && !IS_ALIGNED (Packet->OutDataBuffer, IoAlign)) {
+ if ((IoAlign > 1) && !ADDRESS_IS_ALIGNED_ (Packet->OutDataBuffer, IoAlign)) {
return EFI_INVALID_PARAMETER;
}

- if ((IoAlign > 1) && !IS_ALIGNED (Packet->Asb, IoAlign)) {
+ if ((IoAlign > 1) && !ADDRESS_IS_ALIGNED_ (Packet->Asb, IoAlign)) {
return EFI_INVALID_PARAMETER;
}

diff --git a/MdeModulePkg/Bus/Ata/AtaAtapiPassThru/AtaAtapiPassThru.c b/MdeModulePkg/Bus/Ata/AtaAtapiPassThru/AtaAtapiPassThru.c
index 86fe9d954fdb..cf98fcdaf344 100644
--- a/MdeModulePkg/Bus/Ata/AtaAtapiPassThru/AtaAtapiPassThru.c
+++ b/MdeModulePkg/Bus/Ata/AtaAtapiPassThru/AtaAtapiPassThru.c
@@ -1281,15 +1281,15 @@ AtaPassThruPassThru (

Instance = ATA_PASS_THRU_PRIVATE_DATA_FROM_THIS (This);

- if ((This->Mode->IoAlign > 1) && !IS_ALIGNED(Packet->InDataBuffer, This->Mode->IoAlign)) {
+ if ((This->Mode->IoAlign > 1) && !ADDRESS_IS_ALIGNED_(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) && !ADDRESS_IS_ALIGNED_(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) && !ADDRESS_IS_ALIGNED_(Packet->Asb, This->Mode->IoAlign)) {
return EFI_INVALID_PARAMETER;
}

@@ -2012,15 +2012,15 @@ ExtScsiPassThruPassThru (
return EFI_INVALID_PARAMETER;
}

- if ((This->Mode->IoAlign > 1) && !IS_ALIGNED(Packet->InDataBuffer, This->Mode->IoAlign)) {
+ if ((This->Mode->IoAlign > 1) && !ADDRESS_IS_ALIGNED_(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) && !ADDRESS_IS_ALIGNED_(Packet->OutDataBuffer, This->Mode->IoAlign)) {
return EFI_INVALID_PARAMETER;
}

- if ((This->Mode->IoAlign > 1) && !IS_ALIGNED(Packet->SenseData, This->Mode->IoAlign)) {
+ if ((This->Mode->IoAlign > 1) && !ADDRESS_IS_ALIGNED_(Packet->SenseData, This->Mode->IoAlign)) {
return EFI_INVALID_PARAMETER;
}

diff --git a/MdeModulePkg/Bus/Ata/AtaBusDxe/AtaPassThruExecute.c b/MdeModulePkg/Bus/Ata/AtaBusDxe/AtaPassThruExecute.c
index 79026a4a957d..471fb6a7f440 100644
--- a/MdeModulePkg/Bus/Ata/AtaBusDxe/AtaPassThruExecute.c
+++ b/MdeModulePkg/Bus/Ata/AtaBusDxe/AtaPassThruExecute.c
@@ -1036,7 +1036,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) && !ADDRESS_IS_ALIGNED_ (Buffer, AtaPassThru->Mode->IoAlign)) {
NewBuffer = AllocateAlignedBuffer (AtaDevice, TransferLength);
if (NewBuffer == NULL) {
return EFI_OUT_OF_RESOURCES;
diff --git a/MdeModulePkg/Bus/Scsi/ScsiDiskDxe/ScsiDisk.c b/MdeModulePkg/Bus/Scsi/ScsiDiskDxe/ScsiDisk.c
index c80e78fa8a6b..81c0fa217a0b 100644
--- a/MdeModulePkg/Bus/Scsi/ScsiDiskDxe/ScsiDisk.c
+++ b/MdeModulePkg/Bus/Scsi/ScsiDiskDxe/ScsiDisk.c
@@ -1956,7 +1956,7 @@ ScsiDiskReceiveData (
goto Done;
}

- if ((ScsiDiskDevice->ScsiIo->IoAlign > 1) && !IS_ALIGNED (PayloadBuffer, ScsiDiskDevice->ScsiIo->IoAlign)) {
+ if ((ScsiDiskDevice->ScsiIo->IoAlign > 1) && !ADDRESS_IS_ALIGNED_ (PayloadBuffer, ScsiDiskDevice->ScsiIo->IoAlign)) {
AlignedBuffer = AllocateAlignedBuffer (ScsiDiskDevice, PayloadBufferSize);
if (AlignedBuffer == NULL) {
Status = EFI_OUT_OF_RESOURCES;
@@ -2171,7 +2171,7 @@ ScsiDiskSendData (
goto Done;
}

- if ((ScsiDiskDevice->ScsiIo->IoAlign > 1) && !IS_ALIGNED (PayloadBuffer, ScsiDiskDevice->ScsiIo->IoAlign)) {
+ if ((ScsiDiskDevice->ScsiIo->IoAlign > 1) && !ADDRESS_IS_ALIGNED_ (PayloadBuffer, ScsiDiskDevice->ScsiIo->IoAlign)) {
AlignedBuffer = AllocateAlignedBuffer (ScsiDiskDevice, PayloadBufferSize);
if (AlignedBuffer == NULL) {
Status = EFI_OUT_OF_RESOURCES;
diff --git a/MdeModulePkg/Bus/Ufs/UfsPassThruDxe/UfsPassThru.c b/MdeModulePkg/Bus/Ufs/UfsPassThruDxe/UfsPassThru.c
index 92ff958f161e..abfb422d1ea3 100644
--- a/MdeModulePkg/Bus/Ufs/UfsPassThruDxe/UfsPassThru.c
+++ b/MdeModulePkg/Bus/Ufs/UfsPassThruDxe/UfsPassThru.c
@@ -170,15 +170,15 @@ UfsPassThruPassThru (
return EFI_INVALID_PARAMETER;
}

- if ((This->Mode->IoAlign > 1) && !IS_ALIGNED(Packet->InDataBuffer, This->Mode->IoAlign)) {
+ if ((This->Mode->IoAlign > 1) && !ADDRESS_IS_ALIGNED_(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) && !ADDRESS_IS_ALIGNED_(Packet->OutDataBuffer, This->Mode->IoAlign)) {
return EFI_INVALID_PARAMETER;
}

- if ((This->Mode->IoAlign > 1) && !IS_ALIGNED(Packet->SenseData, This->Mode->IoAlign)) {
+ if ((This->Mode->IoAlign > 1) && !ADDRESS_IS_ALIGNED_(Packet->SenseData, This->Mode->IoAlign)) {
return EFI_INVALID_PARAMETER;
}

diff --git a/MdeModulePkg/Universal/EbcDxe/EbcExecute.c b/MdeModulePkg/Universal/EbcDxe/EbcExecute.c
index 1c4a4f5155c9..35f60cabdeb4 100644
--- a/MdeModulePkg/Universal/EbcDxe/EbcExecute.c
+++ b/MdeModulePkg/Universal/EbcDxe/EbcExecute.c
@@ -2004,7 +2004,7 @@ ExecuteJMP (
// check for alignment, and jump absolute.
//
Data64 = (UINT64) VmReadImmed64 (VmPtr, 2);
- if (!IS_ALIGNED ((UINTN) Data64, sizeof (UINT16))) {
+ if (!ADDRESS_IS_ALIGNED_ ((UINTN) Data64, sizeof (UINT16))) {
EbcDebugSignalException (
EXCEPT_EBC_ALIGNMENT_CHECK,
EXCEPTION_FLAG_FATAL,
@@ -2059,7 +2059,7 @@ ExecuteJMP (
// Form: JMP32 @Rx {Index32}
//
Addr = VmReadMemN (VmPtr, (UINTN) Data64 + Index32);
- if (!IS_ALIGNED ((UINTN) Addr, sizeof (UINT16))) {
+ if (!ADDRESS_IS_ALIGNED_ ((UINTN) Addr, sizeof (UINT16))) {
EbcDebugSignalException (
EXCEPT_EBC_ALIGNMENT_CHECK,
EXCEPTION_FLAG_FATAL,
@@ -2082,7 +2082,7 @@ ExecuteJMP (
// Form: JMP32 Rx {Immed32}
//
Addr = (UINTN) (Data64 + Index32);
- if (!IS_ALIGNED ((UINTN) Addr, sizeof (UINT16))) {
+ if (!ADDRESS_IS_ALIGNED_ ((UINTN) Addr, sizeof (UINT16))) {
EbcDebugSignalException (
EXCEPT_EBC_ALIGNMENT_CHECK,
EXCEPTION_FLAG_FATAL,
@@ -3128,7 +3128,7 @@ ExecuteRET (
// Pull the return address off the VM app's stack and set the IP
// to it
//
- if (!IS_ALIGNED ((UINTN) VmPtr->Gpr[0], sizeof (UINT16))) {
+ if (!ADDRESS_IS_ALIGNED_ ((UINTN) VmPtr->Gpr[0], sizeof (UINT16))) {
EbcDebugSignalException (
EXCEPT_EBC_ALIGNMENT_CHECK,
EXCEPTION_FLAG_FATAL,
@@ -4693,7 +4693,7 @@ VmWriteMem16 (
//
// Do a simple write if aligned
//
- if (IS_ALIGNED (Addr, sizeof (UINT16))) {
+ if (ADDRESS_IS_ALIGNED_ (Addr, sizeof (UINT16))) {
*(UINT16 *) Addr = Data;
} else {
//
@@ -4756,7 +4756,7 @@ VmWriteMem32 (
//
// Do a simple write if aligned
//
- if (IS_ALIGNED (Addr, sizeof (UINT32))) {
+ if (ADDRESS_IS_ALIGNED_ (Addr, sizeof (UINT32))) {
*(UINT32 *) Addr = Data;
} else {
//
@@ -4819,7 +4819,7 @@ VmWriteMem64 (
//
// Do a simple write if aligned
//
- if (IS_ALIGNED (Addr, sizeof (UINT64))) {
+ if (ADDRESS_IS_ALIGNED_ (Addr, sizeof (UINT64))) {
*(UINT64 *) Addr = Data;
} else {
//
@@ -4885,7 +4885,7 @@ VmWriteMemN (
//
// Do a simple write if aligned
//
- if (IS_ALIGNED (Addr, sizeof (UINTN))) {
+ if (ADDRESS_IS_ALIGNED_ (Addr, sizeof (UINTN))) {
*(UINTN *) Addr = Data;
} else {
for (Index = 0; Index < sizeof (UINTN) / sizeof (UINT32); Index++) {
@@ -4949,7 +4949,7 @@ VmReadImmed16 (
//
// Read direct if aligned
//
- if (IS_ALIGNED ((UINTN) VmPtr->Ip + Offset, sizeof (INT16))) {
+ if (ADDRESS_IS_ALIGNED_ ((UINTN) VmPtr->Ip + Offset, sizeof (INT16))) {
return * (INT16 *) (VmPtr->Ip + Offset);
} else {
//
@@ -4993,7 +4993,7 @@ VmReadImmed32 (
//
// Read direct if aligned
//
- if (IS_ALIGNED ((UINTN) VmPtr->Ip + Offset, sizeof (UINT32))) {
+ if (ADDRESS_IS_ALIGNED_ ((UINTN) VmPtr->Ip + Offset, sizeof (UINT32))) {
return * (INT32 *) (VmPtr->Ip + Offset);
}
//
@@ -5032,7 +5032,7 @@ VmReadImmed64 (
//
// Read direct if aligned
//
- if (IS_ALIGNED ((UINTN) VmPtr->Ip + Offset, sizeof (UINT64))) {
+ if (ADDRESS_IS_ALIGNED_ ((UINTN) VmPtr->Ip + Offset, sizeof (UINT64))) {
return * (UINT64 *) (VmPtr->Ip + Offset);
}
//
@@ -5069,7 +5069,7 @@ VmReadCode16 (
//
// Read direct if aligned
//
- if (IS_ALIGNED ((UINTN) VmPtr->Ip + Offset, sizeof (UINT16))) {
+ if (ADDRESS_IS_ALIGNED_ ((UINTN) VmPtr->Ip + Offset, sizeof (UINT16))) {
return * (UINT16 *) (VmPtr->Ip + Offset);
} else {
//
@@ -5110,7 +5110,7 @@ VmReadCode32 (
//
// Read direct if aligned
//
- if (IS_ALIGNED ((UINTN) VmPtr->Ip + Offset, sizeof (UINT32))) {
+ if (ADDRESS_IS_ALIGNED_ ((UINTN) VmPtr->Ip + Offset, sizeof (UINT32))) {
return * (UINT32 *) (VmPtr->Ip + Offset);
}
//
@@ -5147,7 +5147,7 @@ VmReadCode64 (
//
// Read direct if aligned
//
- if (IS_ALIGNED ((UINTN) VmPtr->Ip + Offset, sizeof (UINT64))) {
+ if (ADDRESS_IS_ALIGNED_ ((UINTN) VmPtr->Ip + Offset, sizeof (UINT64))) {
return * (UINT64 *) (VmPtr->Ip + Offset);
}
//
@@ -5210,7 +5210,7 @@ VmReadMem16 (
//
// Read direct if aligned
//
- if (IS_ALIGNED (Addr, sizeof (UINT16))) {
+ if (ADDRESS_IS_ALIGNED_ (Addr, sizeof (UINT16))) {
return * (UINT16 *) Addr;
}
//
@@ -5243,7 +5243,7 @@ VmReadMem32 (
//
// Read direct if aligned
//
- if (IS_ALIGNED (Addr, sizeof (UINT32))) {
+ if (ADDRESS_IS_ALIGNED_ (Addr, sizeof (UINT32))) {
return * (UINT32 *) Addr;
}
//
@@ -5280,7 +5280,7 @@ VmReadMem64 (
//
// Read direct if aligned
//
- if (IS_ALIGNED (Addr, sizeof (UINT64))) {
+ if (ADDRESS_IS_ALIGNED_ (Addr, sizeof (UINT64))) {
return * (UINT64 *) Addr;
}
//
@@ -5349,7 +5349,7 @@ VmReadMemN (
//
// Read direct if aligned
//
- if (IS_ALIGNED (Addr, sizeof (UINTN))) {
+ if (ADDRESS_IS_ALIGNED_ (Addr, sizeof (UINTN))) {
return * (UINTN *) Addr;
}
//
diff --git a/MdeModulePkg/Bus/Ata/AhciPei/AhciPei.h b/MdeModulePkg/Bus/Ata/AhciPei/AhciPei.h
index 2be78076bee7..2a74c9984791 100644
--- a/MdeModulePkg/Bus/Ata/AhciPei/AhciPei.h
+++ b/MdeModulePkg/Bus/Ata/AhciPei/AhciPei.h
@@ -145,7 +145,7 @@ typedef union {
#define AHCI_PORT_SERR 0x0030
#define AHCI_PORT_CI 0x0038

-#define IS_ALIGNED(addr, size) (((UINTN) (addr) & (size - 1)) == 0)
+#define ADDRESS_IS_ALIGNED_(addr, size) (((UINTN) (addr) & (size - 1)) == 0)
#define TIMER_PERIOD_SECONDS(Seconds) MultU64x32((UINT64)(Seconds), 10000000)

#pragma pack(1)
diff --git a/MdeModulePkg/Bus/Ata/AtaAtapiPassThru/AtaAtapiPassThru.h b/MdeModulePkg/Bus/Ata/AtaAtapiPassThru/AtaAtapiPassThru.h
index 5f582b9b3e76..aa3472a71677 100644
--- a/MdeModulePkg/Bus/Ata/AtaAtapiPassThru/AtaAtapiPassThru.h
+++ b/MdeModulePkg/Bus/Ata/AtaAtapiPassThru/AtaAtapiPassThru.h
@@ -147,7 +147,7 @@ struct _ATA_NONBLOCK_TASK {
#define ATA_ATAPI_TIMEOUT EFI_TIMER_PERIOD_SECONDS(3)
#define ATA_SPINUP_TIMEOUT EFI_TIMER_PERIOD_SECONDS(10)

-#define IS_ALIGNED(addr, size) (((UINTN) (addr) & (size - 1)) == 0)
+#define ADDRESS_IS_ALIGNED_(addr, size) (((UINTN) (addr) & (size - 1)) == 0)

#define ATA_PASS_THRU_PRIVATE_DATA_FROM_THIS(a) \
CR (a, \
diff --git a/MdeModulePkg/Bus/Ata/AtaBusDxe/AtaBus.h b/MdeModulePkg/Bus/Ata/AtaBusDxe/AtaBus.h
index a5a865209942..13767a8a13c8 100644
--- a/MdeModulePkg/Bus/Ata/AtaBusDxe/AtaBus.h
+++ b/MdeModulePkg/Bus/Ata/AtaBusDxe/AtaBus.h
@@ -76,7 +76,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 ADDRESS_IS_ALIGNED_(addr, size) (((UINTN) (addr) & (size - 1)) == 0)

//
// ATA bus data structure for ATA controller
diff --git a/MdeModulePkg/Bus/Scsi/ScsiDiskDxe/ScsiDisk.h b/MdeModulePkg/Bus/Scsi/ScsiDiskDxe/ScsiDisk.h
index ed9bbd6f8ba8..abe1d06a98da 100644
--- a/MdeModulePkg/Bus/Scsi/ScsiDiskDxe/ScsiDisk.h
+++ b/MdeModulePkg/Bus/Scsi/ScsiDiskDxe/ScsiDisk.h
@@ -39,7 +39,7 @@ SPDX-License-Identifier: BSD-2-Clause-Patent

#define IS_DEVICE_FIXED(a) (a)->FixedDevice ? 1 : 0

-#define IS_ALIGNED(addr, size) (((UINTN) (addr) & (size - 1)) == 0)
+#define ADDRESS_IS_ALIGNED_(addr, size) (((UINTN) (addr) & (size - 1)) == 0)

#define UFS_WLUN_RPMB 0xC4

diff --git a/MdeModulePkg/Bus/Ufs/UfsBlockIoPei/UfsBlockIoPei.h b/MdeModulePkg/Bus/Ufs/UfsBlockIoPei/UfsBlockIoPei.h
index 6e2305aa2bc2..4802fdc0ab9b 100644
--- a/MdeModulePkg/Bus/Ufs/UfsBlockIoPei/UfsBlockIoPei.h
+++ b/MdeModulePkg/Bus/Ufs/UfsBlockIoPei/UfsBlockIoPei.h
@@ -133,7 +133,7 @@ typedef struct _UFS_PEIM_HC_PRIVATE_DATA {

#define ROUNDUP8(x) (((x) % 8 == 0) ? (x) : ((x) / 8 + 1) * 8)

-#define IS_ALIGNED(addr, size) (((UINTN) (addr) & (size - 1)) == 0)
+#define ADDRESS_IS_ALIGNED_(addr, size) (((UINTN) (addr) & (size - 1)) == 0)

#define GET_UFS_PEIM_HC_PRIVATE_DATA_FROM_THIS(a) CR (a, UFS_PEIM_HC_PRIVATE_DATA, BlkIoPpi, UFS_PEIM_HC_SIG)
#define GET_UFS_PEIM_HC_PRIVATE_DATA_FROM_THIS2(a) CR (a, UFS_PEIM_HC_PRIVATE_DATA, BlkIo2Ppi, UFS_PEIM_HC_SIG)
diff --git a/MdeModulePkg/Bus/Ufs/UfsPassThruDxe/UfsPassThru.h b/MdeModulePkg/Bus/Ufs/UfsPassThruDxe/UfsPassThru.h
index 79b86f7e6b3d..da3bf78bf9bc 100644
--- a/MdeModulePkg/Bus/Ufs/UfsPassThruDxe/UfsPassThru.h
+++ b/MdeModulePkg/Bus/Ufs/UfsPassThruDxe/UfsPassThru.h
@@ -105,7 +105,7 @@ typedef struct {

#define ROUNDUP8(x) (((x) % 8 == 0) ? (x) : ((x) / 8 + 1) * 8)

-#define IS_ALIGNED(addr, size) (((UINTN) (addr) & (size - 1)) == 0)
+#define ADDRESS_IS_ALIGNED_(addr, size) (((UINTN) (addr) & (size - 1)) == 0)

#define UFS_PASS_THRU_PRIVATE_DATA_FROM_THIS(a) \
CR (a, \
diff --git a/MdeModulePkg/Universal/EbcDxe/EbcExecute.h b/MdeModulePkg/Universal/EbcDxe/EbcExecute.h
index 1cb68bc5385a..f21c757a75b4 100644
--- a/MdeModulePkg/Universal/EbcDxe/EbcExecute.h
+++ b/MdeModulePkg/Universal/EbcDxe/EbcExecute.h
@@ -15,7 +15,7 @@ SPDX-License-Identifier: BSD-2-Clause-Patent
// Macros to check and set alignment
//
#define ASSERT_ALIGNED(addr, size) ASSERT (!((UINT32) (addr) & (size - 1)))
-#define IS_ALIGNED(addr, size) !((UINT32) (addr) & (size - 1))
+#define ADDRESS_IS_ALIGNED_(addr, size) !((UINT32) (addr) & (size - 1))

//
// Debug macro
--
2.31.1


[PATCH 1/1] MdeModulePkg/CapsuleApp: Add missing EFIAPI specifier

Marvin Häuser
 

The function CompareFileNameInAlphabet() is passed by pointer to a
generic sorting function. Said pointer declares a function type with
the EFIAPI calling convention. As CompareFileNameInAlphabet() lacks
said specifier, this causes build issues with toolchains that do not
use the EFIAPI calling convention by default, such as CLANG38.

Add the missing specifier to resolve the issue.

Cc: Jian J Wang <jian.j.wang@intel.com>
Cc: Hao A Wu <hao.a.wu@intel.com>
Cc: Liming Gao <gaoliming@byosoft.com.cn>
Cc: Guomin Jiang <guomin.jiang@intel.com>
Cc: Vitaly Cheptsov <vit9696@protonmail.com>
Signed-off-by: Marvin Häuser <mhaeuser@posteo.de>
---
MdeModulePkg/Application/CapsuleApp/CapsuleDump.c | 1 +
1 file changed, 1 insertion(+)

diff --git a/MdeModulePkg/Application/CapsuleApp/CapsuleDump.c b/MdeModulePkg/Application/CapsuleApp/CapsuleDump.c
index 5725e2f6dd5b..30a4a984f318 100644
--- a/MdeModulePkg/Application/CapsuleApp/CapsuleDump.c
+++ b/MdeModulePkg/Application/CapsuleApp/CapsuleDump.c
@@ -622,6 +622,7 @@ SplitFileNameExtension (

**/
INTN
+EFIAPI
CompareFileNameInAlphabet (
IN VOID *Left,
IN VOID *Right
--
2.31.1


Re: [PATCH v2 2/2] UefiCpuPkg: ResetVector Tool additional debug prints

Ashraf Ali S
 

Hi.,

Is this Patch Uploaded in GitHub?

Regards,
Ashraf Ali S
Intel Technology India Pvt. Ltd.

-----Original Message-----
From: Ni, Ray <ray.ni@intel.com>
Sent: Tuesday, July 27, 2021 10:42 AM
To: S, Ashraf Ali <ashraf.ali.s@intel.com>; devel@edk2.groups.io
Cc: Kumar, Rahul1 <rahul1.kumar@intel.com>; De, Debkumar <debkumar.de@intel.com>; Han, Harry <harry.han@intel.com>; West, Catharine <catharine.west@intel.com>; V, Sangeetha <sangeetha.v@intel.com>
Subject: RE: [PATCH v2 2/2] UefiCpuPkg: ResetVector Tool additional debug prints

Reviewed-by: Ray Ni <ray.ni@Intel.com>

-----Original Message-----
From: S, Ashraf Ali <ashraf.ali.s@intel.com>
Sent: Friday, July 23, 2021 4:40 PM
To: devel@edk2.groups.io
Cc: S, Ashraf Ali <ashraf.ali.s@intel.com>; Ni, Ray
<ray.ni@intel.com>; Kumar, Rahul1 <rahul1.kumar@intel.com>; De,
Debkumar <debkumar.de@intel.com>; Han, Harry <harry.han@intel.com>;
West, Catharine <catharine.west@intel.com>; V, Sangeetha
<sangeetha.v@intel.com>
Subject: [PATCH v2 2/2] UefiCpuPkg: ResetVector Tool additional debug
prints

REF:https://bugzilla.tianocore.org/show_bug.cgi?id=3506

Before executing the nasm command, added print statement to know what
commands are executing.
before printing the output file need check the status of command which
is executed. if the status is 0 then only print the output file name.

Cc: Ray Ni <ray.ni@intel.com>
Cc: Rahul Kumar <rahul1.kumar@intel.com>
Cc: Debkumar De <debkumar.de@intel.com>
Cc: Harry Han <harry.han@intel.com>
Cc: Catharine West <catharine.west@intel.com>
Cc: Sangeetha V <sangeetha.v@intel.com>
Signed-off-by: Ashraf Ali S <ashraf.ali.s@intel.com>
---
UefiCpuPkg/ResetVector/Vtf0/Build.py | 5 ++++-
1 file changed, 4 insertions(+), 1 deletion(-)

diff --git a/UefiCpuPkg/ResetVector/Vtf0/Build.py
b/UefiCpuPkg/ResetVector/Vtf0/Build.py
index 55f4edd87b..b791d32762 100644
--- a/UefiCpuPkg/ResetVector/Vtf0/Build.py
+++ b/UefiCpuPkg/ResetVector/Vtf0/Build.py
@@ -32,9 +32,12 @@ for arch in ('ia32', 'x64'):
'-o', output,
'Vtf0.nasmb',
)
+ print(f"Command : {' '.join(commandLine)}")
ret = RunCommand(commandLine)
+ if ret != 0:
+ print(f"something went wrong while executing {commandLine[-1]}")
+ sys.exit()
print('\tASM\t' + output)
- if ret != 0: sys.exit(ret)

commandLine = (
'python',
--
2.30.2.windows.1


Re: [PATCH v2 0/3] reuse the SevEsWork area

Min Xu
 

Hi, Brijesh
May I know is there some progress of this patch set? I noticed some comments have been given to the patch-set.

Thanks!
Min

-----Original Message-----
From: Brijesh Singh <brijesh.singh@amd.com>
Sent: Friday, August 6, 2021 4:42 AM
To: devel@edk2.groups.io
Cc: James Bottomley <jejb@linux.ibm.com>; Xu, Min M
<min.m.xu@intel.com>; Yao, Jiewen <jiewen.yao@intel.com>; Tom
Lendacky <thomas.lendacky@amd.com>; Justen, Jordan L
<jordan.l.justen@intel.com>; Ard Biesheuvel <ardb+tianocore@kernel.org>;
Erdem Aktas <erdemaktas@google.com>; Michael Roth
<Michael.Roth@amd.com>; Brijesh Singh <brijesh.singh@amd.com>
Subject: [PATCH v2 0/3] reuse the SevEsWork area

Based on the discussion on the mailing list, we agreed that instead of wasting
extra page in the MEMFD, we can reuse the SevEsWorkArea buffer for the
TDX. To avoid any confusion, lets introduce a OvmfWorkArea that will
contains 32 bytes of header followed by the actual workarea.

While at it, move the code to clear the GHCB page from PageTable build to
AmdSev.asm.

I have used the existing TDX BZ for it because the request came during the
TDX patch review. if anyone have concern please let me know and I will
happily create a new BZ.

Full tree is at: https://github.com/AMDESE/ovmf/tree/sev-new-work-area

Brijesh Singh (3):
OvmfPkg: introduce a common work area
OvmfPkg/ResetVector: update SEV support to use new work area format
OvmfPkg/ResetVector: move the GHCB page setup in AmdSev.asm

Cc: James Bottomley <jejb@linux.ibm.com>
Cc: Min Xu <min.m.xu@intel.com>
Cc: Jiewen Yao <jiewen.yao@intel.com>
Cc: Tom Lendacky <thomas.lendacky@amd.com>
Cc: Jordan Justen <jordan.l.justen@intel.com>
Cc: Ard Biesheuvel <ardb+tianocore@kernel.org>
Cc: Erdem Aktas <erdemaktas@google.com>

Changes since v1:
- address Jiewen's feedback.

Brijesh Singh (3):
OvmfPkg: introduce a common work area
OvmfPkg/ResetVector: update SEV support to use new work area format
OvmfPkg/ResetVector: move the GHCB page setup in AmdSev.asm

OvmfPkg/OvmfPkg.dec | 12 +++
OvmfPkg/OvmfPkgX64.fdf | 9 +-
OvmfPkg/PlatformPei/PlatformPei.inf | 4 +-
OvmfPkg/ResetVector/ResetVector.inf | 1 +
OvmfPkg/Sec/SecMain.inf | 2 +
OvmfPkg/Include/Library/MemEncryptSevLib.h | 21 +---
OvmfPkg/Include/WorkArea.h | 67 +++++++++++++
OvmfPkg/PlatformPei/MemDetect.c | 32 +++---
OvmfPkg/Sec/SecMain.c | 32 +++++-
OvmfPkg/OvmfPkgDefines.fdf.inc | 6 ++
OvmfPkg/ResetVector/Ia32/AmdSev.asm | 111 +++++++++++++++++---
-
OvmfPkg/ResetVector/Ia32/PageTables64.asm | 57 ++---------
OvmfPkg/ResetVector/ResetVector.nasmb | 1 +
13 files changed, 247 insertions(+), 108 deletions(-) create mode 100644
OvmfPkg/Include/WorkArea.h

--
2.17.1


Re: [PATCH 20/23] MdePkg: Add AllocatePagesWithMemoryType support in PeiMemoryAllocationLib

Min Xu
 

Thanks much for the reminder. You're right. I will update my code in the next version.

-----Original Message-----
From: Kinney, Michael D <michael.d.kinney@intel.com>
Sent: Friday, August 13, 2021 4:43 AM
To: Xu, Min M <min.m.xu@intel.com>; devel@edk2.groups.io; Kinney,
Michael D <michael.d.kinney@intel.com>
Cc: Liming Gao <gaoliming@byosoft.com.cn>; Liu, Zhiguang
<zhiguang.liu@intel.com>; Yao, Jiewen <jiewen.yao@intel.com>
Subject: RE: [PATCH 20/23] MdePkg: Add AllocatePagesWithMemoryType
support in PeiMemoryAllocationLib

Hi Min,

This patch adds a new API to the lib class.

That type of change requires updates to all the lib instances.

In the design of the MemoryAllocationLib, of a type specific allocation was
needed, a new API was added for that type. What memory types are needed
that require this new API.

If a variety of memory types are required, then why not just use the
PeiServicesLib API:

EFI_STATUS
EFIAPI
PeiServicesAllocatePages (
IN EFI_MEMORY_TYPE MemoryType,
IN UINTN Pages,
OUT EFI_PHYSICAL_ADDRESS *Memory
);

Thanks,

Mike

-----Original Message-----
From: Xu, Min M <min.m.xu@intel.com>
Sent: Thursday, August 12, 2021 4:57 AM
To: devel@edk2.groups.io
Cc: Xu, Min M <min.m.xu@intel.com>; Kinney, Michael D
<michael.d.kinney@intel.com>; Liming Gao <gaoliming@byosoft.com.cn>;
Liu, Zhiguang <zhiguang.liu@intel.com>; Yao, Jiewen
<jiewen.yao@intel.com>
Subject: [PATCH 20/23] MdePkg: Add AllocatePagesWithMemoryType
support
in PeiMemoryAllocationLib

RFC: https://bugzilla.tianocore.org/show_bug.cgi?id=3429

Allocates one or more 4KB pages of given type MemoryType.

Allocates the number of 4KB pages of MemoryType 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.

Cc: Michael D Kinney <michael.d.kinney@intel.com>
Cc: Liming Gao <gaoliming@byosoft.com.cn>
Cc: Zhiguang Liu <zhiguang.liu@intel.com>
Cc: Jiewen Yao <jiewen.yao@intel.com>
Signed-off-by: Min Xu <min.m.xu@intel.com>
---
MdePkg/Include/Library/MemoryAllocationLib.h | 21 +++++++++++++++
.../MemoryAllocationLib.c | 27 +++++++++++++++++++
2 files changed, 48 insertions(+)

diff --git a/MdePkg/Include/Library/MemoryAllocationLib.h
b/MdePkg/Include/Library/MemoryAllocationLib.h
index 65a30cf146dd..2bdc0592ef3e 100644
--- a/MdePkg/Include/Library/MemoryAllocationLib.h
+++ b/MdePkg/Include/Library/MemoryAllocationLib.h
@@ -484,4 +484,25 @@ FreePool (
IN VOID *Buffer
);

+/**
+ Allocates one or more 4KB pages of given type MemoryType.
+
+ Allocates the number of 4KB pages of MemoryType 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 Type of memory to use for this allocation.
+ @param Pages The number of 4 KB pages to allocate.
+
+ @return A pointer to the allocated buffer or NULL if allocation fails.
+
+**/
+VOID *
+EFIAPI
+AllocatePagesWithMemoryType (
+ IN UINTN MemoryType,
+ IN UINTN Pages
+ );
+
#endif
diff --git
a/MdePkg/Library/PeiMemoryAllocationLib/MemoryAllocationLib.c
b/MdePkg/Library/PeiMemoryAllocationLib/MemoryAllocationLib.c
index b3f9df74f139..dcb313349729 100644
--- a/MdePkg/Library/PeiMemoryAllocationLib/MemoryAllocationLib.c
+++ b/MdePkg/Library/PeiMemoryAllocationLib/MemoryAllocationLib.c
@@ -839,4 +839,31 @@ FreePool (
//
}

+/**
+ Allocates one or more 4KB pages of given type MemoryType.

+ Allocates the number of 4KB pages of MemoryType 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 Type of memory to use for this allocation.
+ @param Pages The number of 4 KB pages to allocate.
+
+ @return A pointer to the allocated buffer or NULL if allocation fails.
+
+**/
+VOID *
+EFIAPI
+AllocatePagesWithMemoryType (
+ IN UINTN MemoryType,
+ IN UINTN Pages
+ )
+{
+ if (MemoryType >= EfiMaxMemoryType) {
+ ASSERT (FALSE);
+ return NULL;
+ }
+
+ return InternalAllocatePages (MemoryType, Pages); }
--
2.29.2.windows.2


Event: TianoCore Design Meeting - APAC/NAMO - 08/20/2021 #cal-reminder

devel@edk2.groups.io Calendar <noreply@...>
 

Reminder: TianoCore Design Meeting - APAC/NAMO

When:
08/20/2021
9:30am to 10:30am
(UTC+08:00) Asia/Shanghai

Where:
Microsoft Teams

Organizer: Ray Ni ray.ni@...

View Event

Description:

TOPIC

  1. NA

For more info, see here: https://www.tianocore.org/design-meeting/


Microsoft Teams meeting

Join on your computer or mobile app

Click here to join the meeting

Join with a video conferencing device

teams@...

Video Conference ID: 119 715 416 0

Alternate VTC dialing instructions

Learn More | Meeting options


[PATCH v1 1/1] MdeModulePkg/PeiCore: Remove MigrateSecModulesInFv()

Michael Kubacki
 

REF:https://bugzilla.tianocore.org/show_bug.cgi?id=3564

This function has not been called since it was added in commit
9bedaec. If the function were to remain, it would need to be
re-evaluated and tested. This change removes the function since
it is not being used.

Cc: Jian J Wang <jian.j.wang@intel.com>
Cc: Hao A Wu <hao.a.wu@intel.com>
Cc: Dandan Bi <dandan.bi@intel.com>
Cc: Liming Gao <gaoliming@byosoft.com.cn>
Cc: Debkumar De <debkumar.de@intel.com>
Cc: Harry Han <harry.han@intel.com>
Cc: Catharine West <catharine.west@intel.com>
Cc: Marvin Häuser <mhaeuser@posteo.de>
Signed-off-by: Michael Kubacki <michael.kubacki@microsoft.com>
---
MdeModulePkg/Core/Pei/Dispatcher/Dispatcher.c | 96 --------------------
1 file changed, 96 deletions(-)

diff --git a/MdeModulePkg/Core/Pei/Dispatcher/Dispatcher.c b/MdeModulePkg/Core/Pei/Dispatcher/Dispatcher.c
index 3369585bcce8..61d4b67c64b9 100644
--- a/MdeModulePkg/Core/Pei/Dispatcher/Dispatcher.c
+++ b/MdeModulePkg/Core/Pei/Dispatcher/Dispatcher.c
@@ -1057,102 +1057,6 @@ ConvertStatusCodeCallbacks (
}
}

-/**
- Migrates SEC modules in the given firmware volume.
-
- Migrating SECURITY_CORE files requires special treatment since they are not tracked for PEI dispatch.
-
- This functioun should be called after the FV has been copied to its post-memory location and the PEI Core FV list has
- been updated.
-
- @param Private Pointer to the PeiCore's private data structure.
- @param FvIndex The firmware volume index to migrate.
- @param OrgFvHandle The handle to the firmware volume in temporary memory.
-
- @retval EFI_SUCCESS SEC modules were migrated successfully
- @retval EFI_INVALID_PARAMETER The Private pointer is NULL or FvCount is invalid.
- @retval EFI_NOT_FOUND Can't find valid FFS header.
-
-**/
-EFI_STATUS
-EFIAPI
-MigrateSecModulesInFv (
- IN PEI_CORE_INSTANCE *Private,
- IN UINTN FvIndex,
- IN UINTN OrgFvHandle
- )
-{
- EFI_STATUS Status;
- EFI_STATUS FindFileStatus;
- EFI_PEI_FILE_HANDLE MigratedFileHandle;
- EFI_PEI_FILE_HANDLE FileHandle;
- UINT32 SectionAuthenticationStatus;
- UINT32 FileSize;
- VOID *OrgPe32SectionData;
- VOID *Pe32SectionData;
- EFI_FFS_FILE_HEADER *FfsFileHeader;
- EFI_COMMON_SECTION_HEADER *Section;
- BOOLEAN IsFfs3Fv;
- UINTN SectionInstance;
-
- if (Private == NULL || FvIndex >= Private->FvCount) {
- return EFI_INVALID_PARAMETER;
- }
-
- do {
- FindFileStatus = PeiFfsFindNextFile (
- GetPeiServicesTablePointer (),
- EFI_FV_FILETYPE_SECURITY_CORE,
- Private->Fv[FvIndex].FvHandle,
- &MigratedFileHandle
- );
- if (!EFI_ERROR (FindFileStatus ) && MigratedFileHandle != NULL) {
- FileHandle = (EFI_PEI_FILE_HANDLE) ((UINTN) MigratedFileHandle - (UINTN) Private->Fv[FvIndex].FvHandle + OrgFvHandle);
- FfsFileHeader = (EFI_FFS_FILE_HEADER *) MigratedFileHandle;
-
- DEBUG ((DEBUG_VERBOSE, " Migrating SEC_CORE MigratedFileHandle at 0x%x.\n", (UINTN) MigratedFileHandle));
- DEBUG ((DEBUG_VERBOSE, " FileHandle at 0x%x.\n", (UINTN) FileHandle));
-
- IsFfs3Fv = CompareGuid (&Private->Fv[FvIndex].FvHeader->FileSystemGuid, &gEfiFirmwareFileSystem3Guid);
- if (IS_FFS_FILE2 (FfsFileHeader)) {
- ASSERT (FFS_FILE2_SIZE (FfsFileHeader) > 0x00FFFFFF);
- if (!IsFfs3Fv) {
- DEBUG ((DEBUG_ERROR, "It is a FFS3 formatted file: %g in a non-FFS3 formatted FV.\n", &FfsFileHeader->Name));
- return EFI_NOT_FOUND;
- }
- Section = (EFI_COMMON_SECTION_HEADER *) ((UINT8 *) FfsFileHeader + sizeof (EFI_FFS_FILE_HEADER2));
- FileSize = FFS_FILE2_SIZE (FfsFileHeader) - sizeof (EFI_FFS_FILE_HEADER2);
- } else {
- Section = (EFI_COMMON_SECTION_HEADER *) ((UINT8 *) FfsFileHeader + sizeof (EFI_FFS_FILE_HEADER));
- FileSize = FFS_FILE_SIZE (FfsFileHeader) - sizeof (EFI_FFS_FILE_HEADER);
- }
-
- SectionInstance = 1;
- SectionAuthenticationStatus = 0;
- Status = ProcessSection (
- GetPeiServicesTablePointer (),
- EFI_SECTION_PE32,
- &SectionInstance,
- Section,
- FileSize,
- &Pe32SectionData,
- &SectionAuthenticationStatus,
- IsFfs3Fv
- );
-
- if (!EFI_ERROR (Status)) {
- OrgPe32SectionData = (VOID *) ((UINTN) Pe32SectionData - (UINTN) MigratedFileHandle + (UINTN) FileHandle);
- DEBUG ((DEBUG_VERBOSE, " PE32 section in migrated file at 0x%x.\n", (UINTN) Pe32SectionData));
- DEBUG ((DEBUG_VERBOSE, " PE32 section in original file at 0x%x.\n", (UINTN) OrgPe32SectionData));
- Status = LoadAndRelocatePeCoffImageInPlace (OrgPe32SectionData, Pe32SectionData);
- ASSERT_EFI_ERROR (Status);
- }
- }
- } while (!EFI_ERROR (FindFileStatus));
-
- return EFI_SUCCESS;
-}
-
/**
Migrates PEIMs in the given firmware volume.

--
2.29.2.windows.2


Re: [PATCH v4 1/6] OvmfPkg/TPM: Import PeiDxeTpmPlatformHierarchyLib.c from edk2-platforms

Marvin Häuser
 

Good day Stefan,

Do you think you could split the first patch into a 1:1 initial import and have a modifications commit separately?

One of my big issues with EDK II is duplicated code. I look at it, I don't understand why it is duplicated. I look at the differences, I don't understand why they are there. I dig deeper into the matter (e.g. git blame), and I realise there is no reason but someone was taking a copy+paste route, and future contributors did not know or care about the respective other piece of code. This series standalone is basically that out-of-the-box, with no future changes needed. I'll suggest once more to enforce a code duplication ban, both within edk2, and between edk2 and edk2-platforms.

It would of course be great if you submitted a follow-up series to drop the old library from edk2-platforms. If you plan not to, and all maintainers agree to merge this without such a series being submitted, please CC me so I know when this is merged and can propose such a patch set myself.

Best regards,
Marvin

On 13/08/2021 21:02, Stefan Berger wrote:

On 8/13/21 2:47 PM, Sean Brogan wrote:
Thanks for the link as i missed that message.

To me this just points out more problems with how OVMF is being managed in the edk2 project and the uselessness of edk2 platforms as anything more than just a dumping ground repo to hold sample code.  But that is a problem larger than this patchset.

I guess if you are going doing option 2 can we rename the library interface you are defining in OvmfPkg so it doesn't conflict with the existing one in edk2-platforms/minplatform. That would mean change:

I have now created v5 here with the latest code appearing in SecurityPkg again: https://github.com/stefanberger/edk2/commits/stefanberger/ovmf_disable_platform_hierarchy.v5

I can probably post that pretty quickly but I'll be out for a while. If it's urgent, someone else can pick it it up from there. I tested it on QEMU for x86 and aarch64 and test-compiled on various platforms that I touched (some didn't compile for me before the changes).

What I wasn't sure about is whether edk2-platforms is a 'holding area' for code to be imported ideally 1:1 into edk2. So I ended up making those changes already in v1 to cut out a dependency. If what I have in v5 (or also v4) is sufficient for general consumption, then let's put it into SecurityPkg.


   Stefan



* name in OvmfPkg.dec file
* header file in OvmfPkg/Include/Library
* all references in DSC file for mapping an instance
* all references in your INFs for dependency

Thanks
Sean






On 8/12/2021 3:19 PM, Stefan Berger wrote:

On 8/12/21 4:59 PM, Sean Brogan wrote:
This seems like a bad place for a general purpose lib that many other platforms may take a dependency on.

In v1 this was SecurityPkg.  OvmfPkg is a platform package and therefore not a good place to define broad interfaces.

What caused this to move here?

Option 2 from this message: https://listman.redhat.com/archives/edk2-devel-archive/2021-August/msg00398.html

   Stefan



Thanks
Sean




Re: [PATCH v4 0/6] Ovmf: Disable the TPM2 platform hierarchy

Yao, Jiewen
 

From what I have seen, OvmfPkg already duplicated a lots of common lib. It is NOT desired, but I can understand why.

Personally, I hope we can align the implementation in MinPlatformPkg. Then we just need move to whole design from in MinPlatformPkg to SecurityPkg. - That is my preference.
However, if there is real need to NOT take the full MinPlatformPkg implementation, I am also OK to add OvmfPkg specific implementation.

Since Marc-André Lureau and you are listed as OVMF TPM feature review, I would like to get your preference.
Do you want to take full MinPlatformPkg design to OvmfPkg?

Microsoft just posted a new TPM hierarchy design in MinPlatformPkg. I would like ask the Microsoft (Sean Brogan, Bret Barkelew, Michael Kubacki) as well
Do you think there is value to move TPM hierarchy design from MinPlatformPkg to SecurityPkg?

Thank you
Yao Jiewen

-----Original Message-----
From: Stefan Berger <stefanb@linux.ibm.com>
Sent: Friday, August 13, 2021 8:32 PM
To: Stefan Berger <stefanb@linux.vnet.ibm.com>; devel@edk2.groups.io; Yao,
Jiewen <jiewen.yao@intel.com>
Cc: marcandre.lureau@redhat.com; lersek@redhat.com;
dick_wilkins@phoenix.com; James.Bottomley@HansenPartnership.com
Subject: Re: [PATCH v4 0/6] Ovmf: Disable the TPM2 platform hierarchy

Yao,

  do you have any comments on this series? Would SecurityPkg be a
better place for it?


    Stefan


On 8/12/21 12:59 PM, Stefan Berger wrote:
This series imports code from the edk2-platforms project related to
changing the password of the TPM2 platform hierarchy and uses it to
disable the TPM2 platform hierarchy in Ovmf and ArmVirtPkg. It
addresses the Ovmf aspects of the following bugs:

https://bugzilla.tianocore.org/show_bug.cgi?id=3510
https://bugzilla.tianocore.org/show_bug.cgi?id=3499

I have patched the .dsc files and successfully test-built with most of
them. Some I could not build because they failed for other reasons
unrelated to this series.

I tested the changes with QEMU on x86 following the build of
ArmVirtQemu.dsc and OvmfPkgX64.dsc.

The disablement of the platform hierarchy is done after possibly
handling PPI. Following TPM 2 logs on Arm, only PCR extensions are
following afterwards until GRUB takes over.

Neither one of the following commands should work anymore on first
try:

With IBM tss2 tools:
tsshierarchychangeauth -hi p -pwdn newpass

With Intel tss2 tools:
tpm2_changeauth -c platform newpass

Regards,
Stefan

v4:
- Fixed and simplified code imported from edk2-platforms

v3:
- Referencing Null implementation on Bhyve and Xen platforms
- Add support in ArmVirtPkg

Stefan Berger (6):
OvmfPkg/TPM: Import PeiDxeTpmPlatformHierarchyLib.c from
edk2-platforms
OvmfPkg/TPM: Add a NULL implementation of TpmPlatformHierarchyLib
OvmfPkg: Reference new TPM classes in the build system for compilation
OvmfPkg: Disable the TPM2 platform hierarchy
ArmVirtPkg: Reference new TPM classes in the build system for
compilation
ArmVirtPkg: Disable the TPM2 platform hierarchy

ArmVirtPkg/ArmVirtCloudHv.dsc | 1 +
ArmVirtPkg/ArmVirtQemu.dsc | 3 +
ArmVirtPkg/ArmVirtQemuKernel.dsc | 1 +
ArmVirtPkg/ArmVirtXen.dsc | 1 +
.../PlatformBootManagerLib/PlatformBm.c | 6 +
.../PlatformBootManagerLib.inf | 1 +
OvmfPkg/AmdSev/AmdSevX64.dsc | 3 +
OvmfPkg/Bhyve/BhyveX64.dsc | 1 +
.../Include/Library/TpmPlatformHierarchyLib.h | 27 +++
.../PeiDxeTpmPlatformHierarchyLib.c | 200 ++++++++++++++++++
.../PeiDxeTpmPlatformHierarchyLib.inf | 40 ++++
.../PeiDxeTpmPlatformHierarchyLib.c | 19 ++
.../PeiDxeTpmPlatformHierarchyLib.inf | 31 +++
.../PlatformBootManagerLib/BdsPlatform.c | 6 +
.../PlatformBootManagerLib.inf | 1 +
.../PlatformBootManagerLibBhyve/BdsPlatform.c | 7 +
.../PlatformBootManagerLibGrub/BdsPlatform.c | 7 +
OvmfPkg/OvmfPkgIa32.dsc | 3 +
OvmfPkg/OvmfPkgIa32X64.dsc | 3 +
OvmfPkg/OvmfPkgX64.dsc | 3 +
OvmfPkg/OvmfXen.dsc | 1 +
21 files changed, 365 insertions(+)
create mode 100644 OvmfPkg/Include/Library/TpmPlatformHierarchyLib.h
create mode 100644
OvmfPkg/Library/PeiDxeTpmPlatformHierarchyLib/PeiDxeTpmPlatformHierarch
yLib.c
create mode 100644
OvmfPkg/Library/PeiDxeTpmPlatformHierarchyLib/PeiDxeTpmPlatformHierarch
yLib.inf
create mode 100644
OvmfPkg/Library/PeiDxeTpmPlatformHierarchyLibNull/PeiDxeTpmPlatformHiera
rchyLib.c
create mode 100644
OvmfPkg/Library/PeiDxeTpmPlatformHierarchyLibNull/PeiDxeTpmPlatformHiera
rchyLib.inf


Re: SecCore evacuation in PeiCore?

Marvin Häuser
 

Hey Michael,

Thank you for your response! It was actually quicker than I imagined. :)

I think I understand, but please let me try to get this absolutely right. Can I think of "SecMigrationPei" as a sort of "SecCorePostMem", which either is loaded into permanent RAM directly or is shadowed because it is a PEIM unlike SecCore - and it republishes all public data, most especially PPIs, such that the entire PEI stage no longer has any references to the original SecCore at all, and the SecCore module basically just sits there in the ROM, and its exposed data is either discarded or orphaned? Is that about right?

I think I hit the alignment issue of SecCore too, but only for X64 builds (likely just because the size happens to be lucky for IA32) of OVMF. Pretty much sure it's just ResetVector positioning. What would be the issue with moving the ResetVector into a separate component, with its fixed position in FD (this is actually how UefiCpuPkg/VTF0 works), and having SecCore aligned correctly? Not specifically to restore MigrateSecModulesInFv(), but as future-proofing to ensure expected outputs. In fact, I noticed because my new PE loader code was upset about the unaligned XIP load address.

Also thanks for your patch!

Best regards,
Marvin

On 13/08/2021 18:51, Michael Kubacki wrote:
Hi Marvin,

I apologize for the delayed response, I missed this message earlier. The function was called from EvacuateTempRam() in the initial set of patches:
[PATCH 1/6] MdeModulePkg/PeiCore: Enable T-RAM evacuation in PeiCore (CVE-2019-11098) (groups.io) <https://edk2.groups.io/g/devel/message/61823>

I was not involved in the patch series on the mailing list (job role change at the time) but as a comment in that patch notes, there was an inconsistency observed in PE32 section alignment in SEC modules. I don't see where this was resolved other than the calls being removed later in the series. SecCore migration would not occur implicitly in the PeiCore flow but there is functionality for SEC data migration in UefiCpuPkg/SecMigrationPei.

Based on what I see now, I'd be happy to send a patch to remove MigrateSecModulesInFv().

Thanks,
Michael

On 8/7/2021 2:54 PM, Marvin Häuser wrote:
Good day everyone,
Good day Michael,

The commit that introduced T-RAM evacuation [1] also introduced the function "MigrateSecModulesInFv()". It also is explicitly mentioned as part of the control flow in the commit message. As far as I can see, since then till today this function has never been called anywhere. Was this some draft function that accidentally made it into the patch, or did the caller get lost somewhere? The description makes sense to me and I'm not experienced enough with the PeiCore control flow to tell whether the PEIM migration somehow covers SecCore implicitly. Also I noticed it only supports SecCore in a PE/COFF section, not a TE section. Is there a rationale for that?

Thank you for your time!

Best regards,
Marvin


[1] https://github.com/tianocore/edk2/commit/9bedaec05b7b8ba9aee248361bb61a85a26726cb


6741 - 6760 of 85991