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