]> git.proxmox.com Git - mirror_edk2.git/blame - OvmfPkg/EmuVariableFvbRuntimeDxe/Fvb.c
UefiCpuPkg: Move AsmRelocateApLoopStart from Mpfuncs.nasm to AmdSev.nasm
[mirror_edk2.git] / OvmfPkg / EmuVariableFvbRuntimeDxe / Fvb.c
CommitLineData
670d495b 1/** @file\r
2 Firmware Block Services to support emulating non-volatile variables\r
3 by pretending that a memory buffer is storage for the NV variables.\r
4\r
c30f1e09 5 Copyright (c) 2006 - 2013, Intel Corporation. All rights reserved.<BR>\r
b26f0cf9 6 SPDX-License-Identifier: BSD-2-Clause-Patent\r
670d495b 7\r
8**/\r
9\r
10#include "PiDxe.h"\r
11#include <Guid/EventGroup.h>\r
12#include <Guid/SystemNvDataGuid.h>\r
13#include <Guid/VariableFormat.h>\r
14\r
15#include <Protocol/FirmwareVolumeBlock.h>\r
16#include <Protocol/DevicePath.h>\r
17\r
18#include <Library/UefiLib.h>\r
19#include <Library/UefiDriverEntryPoint.h>\r
20#include <Library/BaseLib.h>\r
21#include <Library/UefiRuntimeLib.h>\r
22#include <Library/DebugLib.h>\r
23#include <Library/BaseMemoryLib.h>\r
24#include <Library/MemoryAllocationLib.h>\r
25#include <Library/UefiBootServicesTableLib.h>\r
26#include <Library/DevicePathLib.h>\r
27#include <Library/PcdLib.h>\r
28#include <Library/PlatformFvbLib.h>\r
29#include "Fvb.h"\r
30\r
bdf93df8 31#define EFI_AUTHENTICATED_VARIABLE_GUID \\r
32{ 0xaaf32c78, 0x947b, 0x439a, { 0xa1, 0x80, 0x2e, 0x14, 0x4e, 0xc3, 0x77, 0x92 } }\r
33\r
670d495b 34//\r
35// Virtual Address Change Event\r
36//\r
37// This is needed for runtime variable access.\r
38//\r
ac0a286f 39EFI_EVENT mEmuVarsFvbAddrChangeEvent = NULL;\r
670d495b 40\r
41//\r
42// This is the single instance supported by this driver. It\r
43// supports the FVB and Device Path protocols.\r
44//\r
ac0a286f 45EFI_FW_VOL_BLOCK_DEVICE mEmuVarsFvb = {\r
670d495b 46 FVB_DEVICE_SIGNATURE,\r
47 { // DevicePath\r
48 {\r
49 {\r
50 HARDWARE_DEVICE_PATH,\r
51 HW_MEMMAP_DP,\r
52 {\r
53 sizeof (MEMMAP_DEVICE_PATH),\r
54 0\r
55 }\r
56 },\r
57 EfiMemoryMappedIO,\r
58 0,\r
59 0,\r
60 },\r
61 {\r
62 END_DEVICE_PATH_TYPE,\r
63 END_ENTIRE_DEVICE_PATH_SUBTYPE,\r
64 {\r
65 sizeof (EFI_DEVICE_PATH_PROTOCOL),\r
66 0\r
67 }\r
68 }\r
69 },\r
ac0a286f 70 NULL, // BufferPtr\r
7e832926 71 EMU_FVB_BLOCK_SIZE, // BlockSize\r
ac0a286f 72 EMU_FVB_SIZE, // Size\r
670d495b 73 { // FwVolBlockInstance\r
74 FvbProtocolGetAttributes,\r
75 FvbProtocolSetAttributes,\r
76 FvbProtocolGetPhysicalAddress,\r
77 FvbProtocolGetBlockSize,\r
78 FvbProtocolRead,\r
79 FvbProtocolWrite,\r
80 FvbProtocolEraseBlocks,\r
81 NULL\r
82 },\r
83};\r
84\r
670d495b 85/**\r
86 Notification function of EVT_SIGNAL_VIRTUAL_ADDRESS_CHANGE.\r
87\r
88 This is a notification function registered on EVT_SIGNAL_VIRTUAL_ADDRESS_CHANGE event.\r
89 It converts pointer to new virtual address.\r
90\r
91 @param Event Event whose notification function is being invoked.\r
92 @param Context Pointer to the notification function's context.\r
93\r
94**/\r
95VOID\r
96EFIAPI\r
97FvbVirtualAddressChangeEvent (\r
ac0a286f
MK
98 IN EFI_EVENT Event,\r
99 IN VOID *Context\r
670d495b 100 )\r
101{\r
102 EfiConvertPointer (0x0, &mEmuVarsFvb.BufferPtr);\r
103}\r
104\r
670d495b 105//\r
106// FVB protocol APIs\r
107//\r
108\r
109/**\r
110 The GetPhysicalAddress() function retrieves the base address of\r
111 a memory-mapped firmware volume. This function should be called\r
112 only for memory-mapped firmware volumes.\r
113\r
949b0f3b 114 @param This Indicates the EFI_FIRMWARE_VOLUME_BLOCK2_PROTOCOL instance.\r
89f385ce 115\r
670d495b 116 @param Address Pointer to a caller-allocated\r
117 EFI_PHYSICAL_ADDRESS that, on successful\r
118 return from GetPhysicalAddress(), contains the\r
119 base address of the firmware volume.\r
89f385ce 120\r
670d495b 121 @retval EFI_SUCCESS The firmware volume base address is returned.\r
89f385ce 122\r
670d495b 123 @retval EFI_NOT_SUPPORTED The firmware volume is not memory mapped.\r
124\r
125**/\r
126EFI_STATUS\r
127EFIAPI\r
128FvbProtocolGetPhysicalAddress (\r
ac0a286f
MK
129 IN CONST EFI_FIRMWARE_VOLUME_BLOCK2_PROTOCOL *This,\r
130 OUT EFI_PHYSICAL_ADDRESS *Address\r
670d495b 131 )\r
132{\r
ac0a286f 133 EFI_FW_VOL_BLOCK_DEVICE *FvbDevice;\r
670d495b 134\r
135 FvbDevice = FVB_DEVICE_FROM_THIS (This);\r
136\r
ac0a286f 137 *Address = (EFI_PHYSICAL_ADDRESS)(UINTN)FvbDevice->BufferPtr;\r
670d495b 138\r
139 return EFI_SUCCESS;\r
140}\r
141\r
670d495b 142/**\r
143 The GetBlockSize() function retrieves the size of the requested\r
144 block. It also returns the number of additional blocks with\r
145 the identical size. The GetBlockSize() function is used to\r
146 retrieve the block map (see EFI_FIRMWARE_VOLUME_HEADER).\r
147\r
148\r
949b0f3b 149 @param This Indicates the EFI_FIRMWARE_VOLUME_BLOCK2_PROTOCOL instance.\r
670d495b 150\r
151 @param Lba Indicates the block for which to return the size.\r
152\r
153 @param BlockSize Pointer to a caller-allocated UINTN in which\r
154 the size of the block is returned.\r
155\r
156 @param NumberOfBlocks Pointer to a caller-allocated UINTN in\r
157 which the number of consecutive blocks,\r
158 starting with Lba, is returned. All\r
159 blocks in this range have a size of\r
160 BlockSize.\r
161\r
89f385ce 162\r
670d495b 163 @retval EFI_SUCCESS The firmware volume base address is returned.\r
89f385ce 164\r
670d495b 165 @retval EFI_INVALID_PARAMETER The requested LBA is out of range.\r
166\r
167**/\r
168EFI_STATUS\r
169EFIAPI\r
170FvbProtocolGetBlockSize (\r
ac0a286f
MK
171 IN CONST EFI_FIRMWARE_VOLUME_BLOCK2_PROTOCOL *This,\r
172 IN EFI_LBA Lba,\r
173 OUT UINTN *BlockSize,\r
174 OUT UINTN *NumberOfBlocks\r
670d495b 175 )\r
176{\r
ac0a286f 177 EFI_FW_VOL_BLOCK_DEVICE *FvbDevice;\r
670d495b 178\r
7e832926 179 if (Lba >= EMU_FVB_NUM_TOTAL_BLOCKS) {\r
670d495b 180 return EFI_INVALID_PARAMETER;\r
181 }\r
182\r
183 FvbDevice = FVB_DEVICE_FROM_THIS (This);\r
184\r
ac0a286f 185 *BlockSize = FvbDevice->BlockSize;\r
7e832926 186 *NumberOfBlocks = (UINTN)(EMU_FVB_NUM_TOTAL_BLOCKS - Lba);\r
670d495b 187\r
188 return EFI_SUCCESS;\r
189}\r
190\r
670d495b 191/**\r
192 The GetAttributes() function retrieves the attributes and\r
193 current settings of the block. Status Codes Returned\r
194\r
949b0f3b 195 @param This Indicates the EFI_FIRMWARE_VOLUME_BLOCK2_PROTOCOL instance.\r
670d495b 196\r
197 @param Attributes Pointer to EFI_FVB_ATTRIBUTES_2 in which the\r
198 attributes and current settings are\r
199 returned. Type EFI_FVB_ATTRIBUTES_2 is defined\r
200 in EFI_FIRMWARE_VOLUME_HEADER.\r
201\r
202 @retval EFI_SUCCESS The firmware volume attributes were\r
203 returned.\r
204\r
205**/\r
206EFI_STATUS\r
207EFIAPI\r
208FvbProtocolGetAttributes (\r
ac0a286f
MK
209 IN CONST EFI_FIRMWARE_VOLUME_BLOCK2_PROTOCOL *This,\r
210 OUT EFI_FVB_ATTRIBUTES_2 *Attributes\r
670d495b 211 )\r
212{\r
213 *Attributes =\r
ac0a286f
MK
214 (EFI_FVB_ATTRIBUTES_2)(\r
215 EFI_FVB2_READ_ENABLED_CAP |\r
216 EFI_FVB2_READ_STATUS |\r
217 EFI_FVB2_WRITE_ENABLED_CAP |\r
218 EFI_FVB2_WRITE_STATUS |\r
219 EFI_FVB2_ERASE_POLARITY\r
220 );\r
670d495b 221\r
222 return EFI_SUCCESS;\r
223}\r
224\r
670d495b 225/**\r
226 The SetAttributes() function sets configurable firmware volume\r
227 attributes and returns the new settings of the firmware volume.\r
228\r
949b0f3b 229 @param This Indicates the EFI_FIRMWARE_VOLUME_BLOCK2_PROTOCOL instance.\r
670d495b 230\r
231 @param Attributes On input, Attributes is a pointer to\r
232 EFI_FVB_ATTRIBUTES_2 that contains the\r
233 desired firmware volume settings. On\r
234 successful return, it contains the new\r
235 settings of the firmware volume. Type\r
236 EFI_FVB_ATTRIBUTES_2 is defined in\r
237 EFI_FIRMWARE_VOLUME_HEADER.\r
89f385ce 238\r
670d495b 239 @retval EFI_SUCCESS The firmware volume attributes were returned.\r
240\r
241 @retval EFI_INVALID_PARAMETER The attributes requested are in\r
242 conflict with the capabilities\r
243 as declared in the firmware\r
244 volume header.\r
245\r
246**/\r
247EFI_STATUS\r
248EFIAPI\r
249FvbProtocolSetAttributes (\r
ac0a286f
MK
250 IN CONST EFI_FIRMWARE_VOLUME_BLOCK2_PROTOCOL *This,\r
251 IN OUT EFI_FVB_ATTRIBUTES_2 *Attributes\r
670d495b 252 )\r
253{\r
254 return EFI_ACCESS_DENIED;\r
255}\r
256\r
670d495b 257/**\r
258 Erases and initializes a firmware volume block.\r
259\r
260 The EraseBlocks() function erases one or more blocks as denoted\r
261 by the variable argument list. The entire parameter list of\r
262 blocks must be verified before erasing any blocks. If a block is\r
263 requested that does not exist within the associated firmware\r
264 volume (it has a larger index than the last block of the\r
265 firmware volume), the EraseBlocks() function must return the\r
266 status code EFI_INVALID_PARAMETER without modifying the contents\r
267 of the firmware volume. Implementations should be mindful that\r
268 the firmware volume might be in the WriteDisabled state. If it\r
269 is in this state, the EraseBlocks() function must return the\r
270 status code EFI_ACCESS_DENIED without modifying the contents of\r
271 the firmware volume. All calls to EraseBlocks() must be fully\r
272 flushed to the hardware before the EraseBlocks() service\r
273 returns.\r
274\r
949b0f3b 275 @param This Indicates the EFI_FIRMWARE_VOLUME_BLOCK2_PROTOCOL\r
670d495b 276 instance.\r
277\r
278 @param ... The variable argument list is a list of tuples.\r
279 Each tuple describes a range of LBAs to erase\r
280 and consists of the following:\r
281 - An EFI_LBA that indicates the starting LBA\r
282 - A UINTN that indicates the number of blocks to\r
283 erase\r
284\r
285 The list is terminated with an\r
286 EFI_LBA_LIST_TERMINATOR. For example, the\r
287 following indicates that two ranges of blocks\r
288 (5-7 and 10-11) are to be erased: EraseBlocks\r
289 (This, 5, 3, 10, 2, EFI_LBA_LIST_TERMINATOR);\r
290\r
291 @retval EFI_SUCCESS The erase request was successfully\r
292 completed.\r
89f385ce 293\r
670d495b 294 @retval EFI_ACCESS_DENIED The firmware volume is in the\r
295 WriteDisabled state.\r
296 @retval EFI_DEVICE_ERROR The block device is not functioning\r
297 correctly and could not be written.\r
298 The firmware device may have been\r
299 partially erased.\r
300 @retval EFI_INVALID_PARAMETER One or more of the LBAs listed\r
301 in the variable argument list do\r
89f385ce 302 not exist in the firmware volume.\r
670d495b 303\r
304**/\r
305EFI_STATUS\r
306EFIAPI\r
307FvbProtocolEraseBlocks (\r
ac0a286f 308 IN CONST EFI_FIRMWARE_VOLUME_BLOCK2_PROTOCOL *This,\r
670d495b 309 ...\r
310 )\r
311{\r
ac0a286f
MK
312 EFI_FW_VOL_BLOCK_DEVICE *FvbDevice;\r
313 VA_LIST Args;\r
314 EFI_LBA StartingLba;\r
315 UINTN NumOfLba;\r
316 UINT8 *ErasePtr;\r
317 UINTN EraseSize;\r
670d495b 318\r
319 FvbDevice = FVB_DEVICE_FROM_THIS (This);\r
670d495b 320\r
7e832926
LE
321 //\r
322 // Check input parameters\r
323 //\r
324 VA_START (Args, This);\r
670d495b 325 do {\r
7e832926 326 StartingLba = VA_ARG (Args, EFI_LBA);\r
670d495b 327 if (StartingLba == EFI_LBA_LIST_TERMINATOR) {\r
328 break;\r
329 }\r
ac0a286f 330\r
7e832926 331 NumOfLba = VA_ARG (Args, UINTN);\r
670d495b 332\r
ac0a286f
MK
333 if ((StartingLba > EMU_FVB_NUM_TOTAL_BLOCKS) ||\r
334 (NumOfLba > EMU_FVB_NUM_TOTAL_BLOCKS - StartingLba))\r
335 {\r
7e832926 336 VA_END (Args);\r
670d495b 337 return EFI_INVALID_PARAMETER;\r
338 }\r
670d495b 339 } while (1);\r
ac0a286f 340\r
7e832926 341 VA_END (Args);\r
670d495b 342\r
7e832926
LE
343 //\r
344 // Erase blocks\r
345 //\r
346 VA_START (Args, This);\r
347 do {\r
348 StartingLba = VA_ARG (Args, EFI_LBA);\r
349 if (StartingLba == EFI_LBA_LIST_TERMINATOR) {\r
350 break;\r
351 }\r
ac0a286f 352\r
7e832926 353 NumOfLba = VA_ARG (Args, UINTN);\r
670d495b 354\r
ac0a286f 355 ErasePtr = FvbDevice->BufferPtr;\r
7e832926
LE
356 ErasePtr += (UINTN)StartingLba * FvbDevice->BlockSize;\r
357 EraseSize = NumOfLba * FvbDevice->BlockSize;\r
670d495b 358\r
7e832926
LE
359 SetMem (ErasePtr, EraseSize, ERASED_UINT8);\r
360 } while (1);\r
ac0a286f 361\r
7e832926 362 VA_END (Args);\r
670d495b 363\r
7e832926
LE
364 //\r
365 // Call platform hook\r
366 //\r
367 VA_START (Args, This);\r
368 PlatformFvbBlocksErased (This, Args);\r
369 VA_END (Args);\r
670d495b 370\r
371 return EFI_SUCCESS;\r
372}\r
373\r
670d495b 374/**\r
375 Writes the specified number of bytes from the input buffer to the block.\r
376\r
377 The Write() function writes the specified number of bytes from\r
378 the provided buffer to the specified block and offset. If the\r
379 firmware volume is sticky write, the caller must ensure that\r
380 all the bits of the specified range to write are in the\r
381 EFI_FVB_ERASE_POLARITY state before calling the Write()\r
382 function, or else the result will be unpredictable. This\r
383 unpredictability arises because, for a sticky-write firmware\r
384 volume, a write may negate a bit in the EFI_FVB_ERASE_POLARITY\r
385 state but cannot flip it back again. In general, before\r
386 calling the Write() function, the caller should call the\r
387 EraseBlocks() function first to erase the specified block to\r
388 write. A block erase cycle will transition bits from the\r
389 (NOT)EFI_FVB_ERASE_POLARITY state back to the\r
390 EFI_FVB_ERASE_POLARITY state. Implementations should be\r
391 mindful that the firmware volume might be in the WriteDisabled\r
392 state. If it is in this state, the Write() function must\r
393 return the status code EFI_ACCESS_DENIED without modifying the\r
394 contents of the firmware volume. The Write() function must\r
395 also prevent spanning block boundaries. If a write is\r
396 requested that spans a block boundary, the write must store up\r
397 to the boundary but not beyond. The output parameter NumBytes\r
398 must be set to correctly indicate the number of bytes actually\r
399 written. The caller must be aware that a write may be\r
400 partially completed. All writes, partial or otherwise, must be\r
401 fully flushed to the hardware before the Write() service\r
402 returns.\r
403\r
949b0f3b 404 @param This Indicates the EFI_FIRMWARE_VOLUME_BLOCK2_PROTOCOL instance.\r
89f385ce 405\r
670d495b 406 @param Lba The starting logical block index to write to.\r
89f385ce 407\r
670d495b 408 @param Offset Offset into the block at which to begin writing.\r
89f385ce 409\r
670d495b 410 @param NumBytes Pointer to a UINTN. At entry, *NumBytes\r
411 contains the total size of the buffer. At\r
412 exit, *NumBytes contains the total number of\r
413 bytes actually written.\r
89f385ce 414\r
670d495b 415 @param Buffer Pointer to a caller-allocated buffer that\r
416 contains the source for the write.\r
89f385ce 417\r
670d495b 418 @retval EFI_SUCCESS The firmware volume was written successfully.\r
89f385ce 419\r
670d495b 420 @retval EFI_BAD_BUFFER_SIZE The write was attempted across an\r
421 LBA boundary. On output, NumBytes\r
422 contains the total number of bytes\r
423 actually written.\r
89f385ce 424\r
670d495b 425 @retval EFI_ACCESS_DENIED The firmware volume is in the\r
426 WriteDisabled state.\r
89f385ce 427\r
670d495b 428 @retval EFI_DEVICE_ERROR The block device is malfunctioning\r
429 and could not be written.\r
430\r
431\r
432**/\r
433EFI_STATUS\r
434EFIAPI\r
435FvbProtocolWrite (\r
ac0a286f
MK
436 IN CONST EFI_FIRMWARE_VOLUME_BLOCK2_PROTOCOL *This,\r
437 IN EFI_LBA Lba,\r
438 IN UINTN Offset,\r
439 IN OUT UINTN *NumBytes,\r
440 IN UINT8 *Buffer\r
670d495b 441 )\r
442{\r
ac0a286f
MK
443 EFI_FW_VOL_BLOCK_DEVICE *FvbDevice;\r
444 UINT8 *FvbDataPtr;\r
445 EFI_STATUS Status;\r
670d495b 446\r
447 FvbDevice = FVB_DEVICE_FROM_THIS (This);\r
448\r
ac0a286f
MK
449 if ((Lba >= EMU_FVB_NUM_TOTAL_BLOCKS) ||\r
450 (Offset > FvbDevice->BlockSize))\r
451 {\r
670d495b 452 return EFI_INVALID_PARAMETER;\r
453 }\r
454\r
7e832926
LE
455 Status = EFI_SUCCESS;\r
456 if (*NumBytes > FvbDevice->BlockSize - Offset) {\r
670d495b 457 *NumBytes = FvbDevice->BlockSize - Offset;\r
ac0a286f 458 Status = EFI_BAD_BUFFER_SIZE;\r
670d495b 459 }\r
460\r
ac0a286f 461 FvbDataPtr = FvbDevice->BufferPtr;\r
7e832926
LE
462 FvbDataPtr += (UINTN)Lba * FvbDevice->BlockSize;\r
463 FvbDataPtr += Offset;\r
670d495b 464\r
7e832926
LE
465 CopyMem (FvbDataPtr, Buffer, *NumBytes);\r
466 PlatformFvbDataWritten (This, Lba, Offset, *NumBytes, Buffer);\r
467 return Status;\r
670d495b 468}\r
469\r
670d495b 470/**\r
471 Reads the specified number of bytes into a buffer from the specified block.\r
472\r
473 The Read() function reads the requested number of bytes from the\r
474 requested block and stores them in the provided buffer.\r
475 Implementations should be mindful that the firmware volume\r
476 might be in the ReadDisabled state. If it is in this state,\r
477 the Read() function must return the status code\r
478 EFI_ACCESS_DENIED without modifying the contents of the\r
479 buffer. The Read() function must also prevent spanning block\r
480 boundaries. If a read is requested that would span a block\r
481 boundary, the read must read up to the boundary but not\r
482 beyond. The output parameter NumBytes must be set to correctly\r
483 indicate the number of bytes actually read. The caller must be\r
484 aware that a read may be partially completed.\r
485\r
949b0f3b 486 @param This Indicates the EFI_FIRMWARE_VOLUME_BLOCK2_PROTOCOL instance.\r
89f385ce 487\r
670d495b 488 @param Lba The starting logical block index\r
489 from which to read.\r
490\r
491 @param Offset Offset into the block at which to begin reading.\r
492\r
493 @param NumBytes Pointer to a UINTN. At entry, *NumBytes\r
494 contains the total size of the buffer. At\r
495 exit, *NumBytes contains the total number of\r
496 bytes read.\r
497\r
498 @param Buffer Pointer to a caller-allocated buffer that will\r
499 be used to hold the data that is read.\r
500\r
501 @retval EFI_SUCCESS The firmware volume was read successfully\r
502 and contents are in Buffer.\r
89f385ce 503\r
670d495b 504 @retval EFI_BAD_BUFFER_SIZE Read attempted across an LBA\r
505 boundary. On output, NumBytes\r
506 contains the total number of bytes\r
507 returned in Buffer.\r
89f385ce 508\r
670d495b 509 @retval EFI_ACCESS_DENIED The firmware volume is in the\r
510 ReadDisabled state.\r
89f385ce 511\r
670d495b 512 @retval EFI_DEVICE_ERROR The block device is not\r
513 functioning correctly and could\r
514 not be read.\r
515\r
516**/\r
517EFI_STATUS\r
518EFIAPI\r
519FvbProtocolRead (\r
ac0a286f
MK
520 IN CONST EFI_FIRMWARE_VOLUME_BLOCK2_PROTOCOL *This,\r
521 IN EFI_LBA Lba,\r
522 IN UINTN Offset,\r
523 IN OUT UINTN *NumBytes,\r
524 IN OUT UINT8 *Buffer\r
670d495b 525 )\r
526{\r
ac0a286f
MK
527 EFI_FW_VOL_BLOCK_DEVICE *FvbDevice;\r
528 UINT8 *FvbDataPtr;\r
529 EFI_STATUS Status;\r
670d495b 530\r
531 FvbDevice = FVB_DEVICE_FROM_THIS (This);\r
532\r
ac0a286f
MK
533 if ((Lba >= EMU_FVB_NUM_TOTAL_BLOCKS) ||\r
534 (Offset > FvbDevice->BlockSize))\r
535 {\r
670d495b 536 return EFI_INVALID_PARAMETER;\r
537 }\r
538\r
7e832926
LE
539 Status = EFI_SUCCESS;\r
540 if (*NumBytes > FvbDevice->BlockSize - Offset) {\r
670d495b 541 *NumBytes = FvbDevice->BlockSize - Offset;\r
ac0a286f 542 Status = EFI_BAD_BUFFER_SIZE;\r
670d495b 543 }\r
544\r
ac0a286f 545 FvbDataPtr = FvbDevice->BufferPtr;\r
7e832926
LE
546 FvbDataPtr += (UINTN)Lba * FvbDevice->BlockSize;\r
547 FvbDataPtr += Offset;\r
670d495b 548\r
7e832926
LE
549 CopyMem (Buffer, FvbDataPtr, *NumBytes);\r
550 PlatformFvbDataRead (This, Lba, Offset, *NumBytes, Buffer);\r
551 return Status;\r
670d495b 552}\r
553\r
670d495b 554/**\r
555 Check the integrity of firmware volume header.\r
556\r
557 @param[in] FwVolHeader - A pointer to a firmware volume header\r
558\r
559 @retval EFI_SUCCESS - The firmware volume is consistent\r
560 @retval EFI_NOT_FOUND - The firmware volume has been corrupted.\r
561\r
562**/\r
563EFI_STATUS\r
564ValidateFvHeader (\r
ac0a286f 565 IN EFI_FIRMWARE_VOLUME_HEADER *FwVolHeader\r
670d495b 566 )\r
567{\r
568 UINT16 Checksum;\r
569\r
570 //\r
571 // Verify the header revision, header signature, length\r
572 // Length of FvBlock cannot be 2**64-1\r
573 // HeaderLength cannot be an odd number\r
574 //\r
575 if ((FwVolHeader->Revision != EFI_FVH_REVISION) ||\r
576 (FwVolHeader->Signature != EFI_FVH_SIGNATURE) ||\r
577 (FwVolHeader->FvLength != EMU_FVB_SIZE) ||\r
578 (FwVolHeader->HeaderLength != EMU_FV_HEADER_LENGTH)\r
ac0a286f
MK
579 )\r
580 {\r
70d5086c 581 DEBUG ((DEBUG_INFO, "EMU Variable FVB: Basic FV headers were invalid\n"));\r
670d495b 582 return EFI_NOT_FOUND;\r
583 }\r
ac0a286f 584\r
670d495b 585 //\r
586 // Verify the header checksum\r
587 //\r
ac0a286f 588 Checksum = CalculateSum16 ((VOID *)FwVolHeader, FwVolHeader->HeaderLength);\r
670d495b 589\r
590 if (Checksum != 0) {\r
70d5086c 591 DEBUG ((DEBUG_INFO, "EMU Variable FVB: FV checksum was invalid\n"));\r
670d495b 592 return EFI_NOT_FOUND;\r
593 }\r
594\r
595 return EFI_SUCCESS;\r
596}\r
597\r
670d495b 598/**\r
599 Initializes the FV Header and Variable Store Header\r
600 to support variable operations.\r
601\r
602 @param[in] Ptr - Location to initialize the headers\r
603\r
604**/\r
605VOID\r
606InitializeFvAndVariableStoreHeaders (\r
ac0a286f 607 IN VOID *Ptr\r
670d495b 608 )\r
609{\r
bdf93df8 610 //\r
611 // Templates for authenticated variable FV header\r
612 //\r
ac0a286f 613 STATIC FVB_FV_HDR_AND_VARS_TEMPLATE FvAndAuthenticatedVarTemplate = {\r
bdf93df8 614 { // EFI_FIRMWARE_VOLUME_HEADER FvHdr;\r
615 // UINT8 ZeroVector[16];\r
616 { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 },\r
617\r
618 // EFI_GUID FileSystemGuid;\r
619 EFI_SYSTEM_NV_DATA_FV_GUID,\r
620\r
621 // UINT64 FvLength;\r
622 EMU_FVB_SIZE,\r
623\r
624 // UINT32 Signature;\r
625 EFI_FVH_SIGNATURE,\r
626\r
627 // EFI_FVB_ATTRIBUTES_2 Attributes;\r
628 0x4feff,\r
629\r
630 // UINT16 HeaderLength;\r
631 EMU_FV_HEADER_LENGTH,\r
632\r
633 // UINT16 Checksum;\r
634 0,\r
635\r
636 // UINT16 ExtHeaderOffset;\r
637 0,\r
638\r
639 // UINT8 Reserved[1];\r
ac0a286f 640 { 0 },\r
bdf93df8 641\r
642 // UINT8 Revision;\r
643 EFI_FVH_REVISION,\r
644\r
645 // EFI_FV_BLOCK_MAP_ENTRY BlockMap[1];\r
ce68d3bc
SZ
646 {\r
647 {\r
7e832926 648 EMU_FVB_NUM_TOTAL_BLOCKS, // UINT32 NumBlocks;\r
ac0a286f 649 EMU_FVB_BLOCK_SIZE // UINT32 Length;\r
ce68d3bc 650 }\r
bdf93df8 651 }\r
652 },\r
653 // EFI_FV_BLOCK_MAP_ENTRY EndBlockMap;\r
654 { 0, 0 }, // End of block map\r
655 { // VARIABLE_STORE_HEADER VarHdr;\r
ac0a286f
MK
656 // EFI_GUID Signature; // need authenticated variables for secure boot\r
657 EFI_AUTHENTICATED_VARIABLE_GUID,\r
bdf93df8 658\r
659 // UINT32 Size;\r
660 (\r
ac0a286f
MK
661 FixedPcdGet32 (PcdFlashNvStorageVariableSize) -\r
662 OFFSET_OF (FVB_FV_HDR_AND_VARS_TEMPLATE, VarHdr)\r
bdf93df8 663 ),\r
664\r
665 // UINT8 Format;\r
666 VARIABLE_STORE_FORMATTED,\r
667\r
668 // UINT8 State;\r
669 VARIABLE_STORE_HEALTHY,\r
670\r
671 // UINT16 Reserved;\r
672 0,\r
673\r
674 // UINT32 Reserved1;\r
675 0\r
676 }\r
677 };\r
678\r
670d495b 679 EFI_FIRMWARE_VOLUME_HEADER *Fv;\r
680\r
681 //\r
682 // Copy the template structure into the location\r
683 //\r
6d7af0c9
LE
684 CopyMem (\r
685 Ptr,\r
686 &FvAndAuthenticatedVarTemplate,\r
687 sizeof FvAndAuthenticatedVarTemplate\r
688 );\r
670d495b 689\r
690 //\r
691 // Update the checksum for the FV header\r
692 //\r
ac0a286f 693 Fv = (EFI_FIRMWARE_VOLUME_HEADER *)Ptr;\r
670d495b 694 Fv->Checksum = CalculateCheckSum16 (Ptr, Fv->HeaderLength);\r
695}\r
696\r
670d495b 697/**\r
698 Main entry point.\r
699\r
89f385ce 700 @param[in] ImageHandle The firmware allocated handle for the EFI image.\r
670d495b 701 @param[in] SystemTable A pointer to the EFI System Table.\r
89f385ce 702\r
670d495b 703 @retval EFI_SUCCESS Successfully initialized.\r
704\r
705**/\r
706EFI_STATUS\r
707EFIAPI\r
708FvbInitialize (\r
ac0a286f
MK
709 IN EFI_HANDLE ImageHandle,\r
710 IN EFI_SYSTEM_TABLE *SystemTable\r
670d495b 711 )\r
712{\r
ac0a286f
MK
713 EFI_STATUS Status;\r
714 VOID *Ptr;\r
715 VOID *SubPtr;\r
716 BOOLEAN Initialize;\r
717 EFI_HANDLE Handle;\r
718 EFI_PHYSICAL_ADDRESS Address;\r
719 RETURN_STATUS PcdStatus;\r
670d495b 720\r
70d5086c 721 DEBUG ((DEBUG_INFO, "EMU Variable FVB Started\n"));\r
670d495b 722\r
723 //\r
724 // Verify that the PCD's are set correctly.\r
725 //\r
ac0a286f
MK
726 ASSERT (\r
727 FixedPcdGet32 (PcdFlashNvStorageFtwSpareSize) %\r
728 EMU_FVB_BLOCK_SIZE == 0\r
729 );\r
670d495b 730 if (\r
ac0a286f
MK
731 (PcdGet32 (PcdFlashNvStorageVariableSize) +\r
732 PcdGet32 (PcdFlashNvStorageFtwWorkingSize)\r
733 ) >\r
734 EMU_FVB_NUM_SPARE_BLOCKS * EMU_FVB_BLOCK_SIZE\r
735 )\r
736 {\r
70d5086c 737 DEBUG ((DEBUG_ERROR, "EMU Variable invalid PCD sizes\n"));\r
670d495b 738 return EFI_INVALID_PARAMETER;\r
739 }\r
740\r
4313b26d 741 if (PcdGet64 (PcdFlashNvStorageVariableBase64) != 0) {\r
ac0a286f
MK
742 DEBUG ((\r
743 DEBUG_INFO,\r
744 "Disabling EMU Variable FVB since "\r
745 "flash variables appear to be supported.\n"\r
746 ));\r
4313b26d
JJ
747 return EFI_ABORTED;\r
748 }\r
749\r
670d495b 750 //\r
751 // By default we will initialize the FV contents. But, if\r
752 // PcdEmuVariableNvStoreReserved is non-zero, then we will\r
753 // use this location for our buffer.\r
754 //\r
755 // If this location does not have a proper FV header, then\r
756 // we will initialize it.\r
757 //\r
758 Initialize = TRUE;\r
759 if (PcdGet64 (PcdEmuVariableNvStoreReserved) != 0) {\r
ac0a286f 760 Ptr = (VOID *)(UINTN)PcdGet64 (PcdEmuVariableNvStoreReserved);\r
670d495b 761 DEBUG ((\r
70d5086c 762 DEBUG_INFO,\r
670d495b 763 "EMU Variable FVB: Using pre-reserved block at %p\n",\r
764 Ptr\r
765 ));\r
766 Status = ValidateFvHeader (Ptr);\r
767 if (!EFI_ERROR (Status)) {\r
70d5086c 768 DEBUG ((DEBUG_INFO, "EMU Variable FVB: Found valid pre-existing FV\n"));\r
670d495b 769 Initialize = FALSE;\r
770 }\r
771 } else {\r
7e832926 772 Ptr = AllocateRuntimePages (EFI_SIZE_TO_PAGES (EMU_FVB_SIZE));\r
670d495b 773 }\r
774\r
775 mEmuVarsFvb.BufferPtr = Ptr;\r
776\r
777 //\r
778 // Initialize the main FV header and variable store header\r
779 //\r
780 if (Initialize) {\r
781 SetMem (Ptr, EMU_FVB_SIZE, ERASED_UINT8);\r
782 InitializeFvAndVariableStoreHeaders (Ptr);\r
783 }\r
ac0a286f 784\r
2b20a34f 785 PcdStatus = PcdSet64S (PcdFlashNvStorageVariableBase64, (UINTN)Ptr);\r
6348eea6 786 ASSERT_RETURN_ERROR (PcdStatus);\r
670d495b 787\r
788 //\r
789 // Initialize the Fault Tolerant Write data area\r
790 //\r
ac0a286f 791 SubPtr = (VOID *)((UINT8 *)Ptr + PcdGet32 (PcdFlashNvStorageVariableSize));\r
2b20a34f 792 PcdStatus = PcdSet64S (\r
793 PcdFlashNvStorageFtwWorkingBase64,\r
794 (UINTN)SubPtr\r
ac0a286f 795 );\r
6348eea6 796 ASSERT_RETURN_ERROR (PcdStatus);\r
670d495b 797\r
798 //\r
799 // Initialize the Fault Tolerant Write spare block\r
800 //\r
ac0a286f 801 SubPtr = (VOID *)((UINT8 *)Ptr +\r
7e832926 802 EMU_FVB_NUM_SPARE_BLOCKS * EMU_FVB_BLOCK_SIZE);\r
2b20a34f 803 PcdStatus = PcdSet64S (\r
804 PcdFlashNvStorageFtwSpareBase64,\r
805 (UINTN)SubPtr\r
ac0a286f 806 );\r
6348eea6 807 ASSERT_RETURN_ERROR (PcdStatus);\r
670d495b 808\r
809 //\r
810 // Setup FVB device path\r
811 //\r
ac0a286f 812 Address = (EFI_PHYSICAL_ADDRESS)(UINTN)Ptr;\r
670d495b 813 mEmuVarsFvb.DevicePath.MemMapDevPath.StartingAddress = Address;\r
ac0a286f 814 mEmuVarsFvb.DevicePath.MemMapDevPath.EndingAddress = Address + EMU_FVB_SIZE - 1;\r
670d495b 815\r
816 //\r
817 // Install the protocols\r
818 //\r
70d5086c 819 DEBUG ((DEBUG_INFO, "Installing FVB for EMU Variable support\n"));\r
670d495b 820 Handle = 0;\r
821 Status = gBS->InstallMultipleProtocolInterfaces (\r
822 &Handle,\r
949b0f3b 823 &gEfiFirmwareVolumeBlock2ProtocolGuid,\r
670d495b 824 &mEmuVarsFvb.FwVolBlockInstance,\r
825 &gEfiDevicePathProtocolGuid,\r
826 &mEmuVarsFvb.DevicePath,\r
827 NULL\r
828 );\r
829 ASSERT_EFI_ERROR (Status);\r
830\r
831 //\r
832 // Register for the virtual address change event\r
833 //\r
834 Status = gBS->CreateEventEx (\r
835 EVT_NOTIFY_SIGNAL,\r
836 TPL_NOTIFY,\r
837 FvbVirtualAddressChangeEvent,\r
838 NULL,\r
839 &gEfiEventVirtualAddressChangeGuid,\r
840 &mEmuVarsFvbAddrChangeEvent\r
841 );\r
842 ASSERT_EFI_ERROR (Status);\r
843\r
844 return EFI_SUCCESS;\r
845}\r