/** @file Shared mock disk and GPT construction helpers used by the GptLib host-based unit tests. Copyright (c) 2026, SUSE LLC. All rights reserved.
SPDX-License-Identifier: BSD-2-Clause-Patent **/ #include #include #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; }