blob: e7061a7e8fa499ce00c06d374b78d5aeb11878b6 [file]
/** @file
Shared mock disk and GPT construction helpers used by the GptLib
host-based unit tests.
Copyright (c) 2026, SUSE LLC. All rights reserved.<BR>
SPDX-License-Identifier: BSD-2-Clause-Patent
**/
#include <Library/BaseLib.h>
#include <Library/BaseMemoryLib.h>
#include "GptLibUnitTestCommon.h"
UINT8 mDiskImage[DISK_IMAGE_SIZE];
EFI_BLOCK_IO_MEDIA mBlockIoMedia;
EFI_BLOCK_IO_PROTOCOL mBlockIo;
EFI_DISK_IO_PROTOCOL mDiskIo;
BOOLEAN mWriteProtected;
CONST EFI_GUID mEspTypeGuid = {
0xC12A7328, 0xF81F, 0x11D2, { 0xBA, 0x4B, 0x00, 0xA0, 0xC9, 0x3E, 0xC9, 0x3B }
};
CONST EFI_GUID mPartitionGuid1 = {
0x11111111, 0x2222, 0x3333, { 0x44, 0x44, 0x55, 0x55, 0x66, 0x66, 0x77, 0x77 }
};
CONST EFI_GUID mPartitionGuid2 = {
0x88888888, 0x9999, 0xAAAA, { 0xBB, 0xBB, 0xCC, 0xCC, 0xDD, 0xDD, 0xEE, 0xEE }
};
/**
Mock implementation of EFI_DISK_IO_PROTOCOL.ReadDisk backed by the in-memory
disk image.
@param[in] This Pointer to the EFI_DISK_IO_PROTOCOL instance.
@param[in] MediaId ID of the medium to read from.
@param[in] Offset Starting byte offset on the logical disk.
@param[in] BufferSize Number of bytes to read.
@param[out] Buffer Buffer into which the data is read.
@retval EFI_SUCCESS The data was read successfully.
@retval EFI_DEVICE_ERROR The request was invalid or out of range.
**/
STATIC
EFI_STATUS
EFIAPI
MockReadDisk (
IN EFI_DISK_IO_PROTOCOL *This,
IN UINT32 MediaId,
IN UINT64 Offset,
IN UINTN BufferSize,
OUT VOID *Buffer
)
{
if ((Buffer == NULL) ||
(MediaId != mBlockIoMedia.MediaId) ||
(Offset > DISK_IMAGE_SIZE) ||
(BufferSize > (DISK_IMAGE_SIZE - Offset)))
{
return EFI_DEVICE_ERROR;
}
CopyMem (Buffer, mDiskImage + Offset, BufferSize);
return EFI_SUCCESS;
}
/**
Mock implementation of EFI_DISK_IO_PROTOCOL.WriteDisk backed by the in-memory
disk image, honoring the write-protected flag.
@param[in] This Pointer to the EFI_DISK_IO_PROTOCOL instance.
@param[in] MediaId ID of the medium to write to.
@param[in] Offset Starting byte offset on the logical disk.
@param[in] BufferSize Number of bytes to write.
@param[in] Buffer Buffer holding the data to write.
@retval EFI_SUCCESS The data was written successfully.
@retval EFI_WRITE_PROTECTED The mock medium is write-protected.
@retval EFI_DEVICE_ERROR The request was invalid or out of range.
**/
STATIC
EFI_STATUS
EFIAPI
MockWriteDisk (
IN EFI_DISK_IO_PROTOCOL *This,
IN UINT32 MediaId,
IN UINT64 Offset,
IN UINTN BufferSize,
IN VOID *Buffer
)
{
if (mWriteProtected) {
return EFI_WRITE_PROTECTED;
}
if ((Buffer == NULL) ||
(MediaId != mBlockIoMedia.MediaId) ||
(Offset > DISK_IMAGE_SIZE) ||
(BufferSize > (DISK_IMAGE_SIZE - Offset)))
{
return EFI_DEVICE_ERROR;
}
CopyMem (mDiskImage + Offset, Buffer, BufferSize);
return EFI_SUCCESS;
}
/**
Return a pointer into the in-memory disk image at the given LBA.
@param[in] Lba Logical block address to locate.
@return Pointer to the start of the requested block within the disk image.
**/
UINT8 *
GetDiskLba (
IN EFI_LBA Lba
)
{
return mDiskImage + (UINTN)(Lba * SECTOR_SIZE);
}
/**
Return a pointer to the primary GPT header within the in-memory disk image.
@return Pointer to the primary EFI_PARTITION_TABLE_HEADER.
**/
EFI_PARTITION_TABLE_HEADER *
GetPrimaryHeader (
VOID
)
{
return (EFI_PARTITION_TABLE_HEADER *)(VOID *)GetDiskLba (PRIMARY_PART_HEADER_LBA);
}
/**
Recompute and store the header CRC32 for the given GPT header.
@param[in,out] Header The GPT header whose CRC32 field is updated.
**/
VOID
UpdateGptHeaderCrc (
IN OUT EFI_PARTITION_TABLE_HEADER *Header
)
{
Header->Header.CRC32 = 0;
Header->Header.CRC32 = CalculateCrc32 (Header, Header->Header.HeaderSize);
}
/**
Populate a partition entry with the ESP type GUID and the given attributes.
@param[in,out] Entry The partition entry to fill.
@param[in] UniquePartitionGuid Unique partition GUID to assign.
@param[in] StartingLba Starting LBA of the partition.
@param[in] EndingLba Ending LBA of the partition.
**/
VOID
FillPartitionEntry (
IN OUT EFI_PARTITION_ENTRY *Entry,
IN CONST EFI_GUID *UniquePartitionGuid,
IN EFI_LBA StartingLba,
IN EFI_LBA EndingLba
)
{
CopyGuid (&Entry->PartitionTypeGUID, &mEspTypeGuid);
CopyGuid (&Entry->UniquePartitionGUID, UniquePartitionGuid);
Entry->StartingLBA = StartingLba;
Entry->EndingLBA = EndingLba;
}
/**
Construct a complete GPT header and partition entry array at the given LBA in
the in-memory disk image, recalculating all CRCs.
@param[in] HeaderLba LBA at which to write the GPT header.
@param[in] AlternateLba Value stored in the header AlternateLBA field.
@param[in] EntryArrayLba LBA at which to write the partition entry array.
@param[in] NumEntries Number of partition entries in the array.
@param[in] EntrySize Size in bytes of each partition entry.
@param[in] NumPartitions Number of populated partition entries.
**/
VOID
WriteGptTableAt (
IN EFI_LBA HeaderLba,
IN EFI_LBA AlternateLba,
IN EFI_LBA EntryArrayLba,
IN UINT32 NumEntries,
IN UINT32 EntrySize,
IN UINT32 NumPartitions
)
{
EFI_PARTITION_TABLE_HEADER *Header;
UINT8 *Array;
UINT32 ArraySize;
ArraySize = NumEntries * EntrySize;
Array = GetDiskLba (EntryArrayLba);
ZeroMem (Array, ArraySize);
if (NumPartitions >= 1) {
FillPartitionEntry ((EFI_PARTITION_ENTRY *)(VOID *)Array, &mPartitionGuid1, 34, 133);
}
if (NumPartitions >= 2) {
FillPartitionEntry ((EFI_PARTITION_ENTRY *)(VOID *)(Array + EntrySize), &mPartitionGuid2, 134, 233);
}
Header = (EFI_PARTITION_TABLE_HEADER *)(VOID *)GetDiskLba (HeaderLba);
ZeroMem (Header, SECTOR_SIZE);
Header->Header.Signature = EFI_PTAB_HEADER_ID;
Header->Header.Revision = TEST_GPT_REVISION_V1;
Header->Header.HeaderSize = sizeof (EFI_PARTITION_TABLE_HEADER);
Header->MyLBA = HeaderLba;
Header->AlternateLBA = AlternateLba;
Header->FirstUsableLBA = FIRST_USABLE_LBA;
Header->LastUsableLBA = LAST_USABLE_LBA;
Header->PartitionEntryLBA = EntryArrayLba;
Header->NumberOfPartitionEntries = NumEntries;
Header->SizeOfPartitionEntry = EntrySize;
Header->PartitionEntryArrayCRC32 = CalculateCrc32 (Array, ArraySize);
UpdateGptHeaderCrc (Header);
}
/**
Reset the mock disk and protocol state and lay down a valid primary GPT.
**/
VOID
SetupDiskWithValidPrimary (
VOID
)
{
ZeroMem (mDiskImage, sizeof (mDiskImage));
ZeroMem (&mBlockIoMedia, sizeof (mBlockIoMedia));
mBlockIoMedia.MediaId = 1;
mBlockIoMedia.BlockSize = SECTOR_SIZE;
mBlockIoMedia.LastBlock = LAST_LBA;
ZeroMem (&mBlockIo, sizeof (mBlockIo));
mBlockIo.Revision = EFI_BLOCK_IO_PROTOCOL_REVISION;
mBlockIo.Media = &mBlockIoMedia;
ZeroMem (&mDiskIo, sizeof (mDiskIo));
mDiskIo.Revision = EFI_DISK_IO_PROTOCOL_REVISION;
mDiskIo.ReadDisk = MockReadDisk;
mDiskIo.WriteDisk = MockWriteDisk;
mWriteProtected = FALSE;
WriteGptTableAt (
PRIMARY_PART_HEADER_LBA,
LAST_LBA,
PRIMARY_PART_HEADER_LBA + 1,
NUM_PARTITION_ENTRIES,
PARTITION_ENTRY_SIZE,
2
);
}
/**
Invoke PartitionValidGptTable against the mock disk at the given LBA.
@param[in] Lba LBA of the GPT header to validate.
@param[out] Header Buffer to receive the validated GPT header.
@retval TRUE The GPT table at Lba is valid.
@retval FALSE The GPT table at Lba is invalid.
**/
BOOLEAN
ValidateAt (
IN EFI_LBA Lba,
OUT EFI_PARTITION_TABLE_HEADER *Header
)
{
return PartitionValidGptTable (&mBlockIo, &mDiskIo, Lba, Header);
}
/**
Initialize a GPT header in memory for PartitionCheckGptEntry tests.
@param[out] Header The GPT header to initialize.
@param[in] NumEntries Number of partition entries to record.
@param[in] EntrySize Size in bytes of each partition entry.
**/
VOID
InitCheckEntryHeader (
OUT EFI_PARTITION_TABLE_HEADER *Header,
IN UINT32 NumEntries,
IN UINT32 EntrySize
)
{
ZeroMem (Header, sizeof (*Header));
Header->FirstUsableLBA = FIRST_USABLE_LBA;
Header->LastUsableLBA = 200;
Header->NumberOfPartitionEntries = NumEntries;
Header->SizeOfPartitionEntry = EntrySize;
}