1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
|
/** @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;
}
|