]> git.proxmox.com Git - mirror_edk2.git/blame_incremental - OvmfPkg/EmuVariableFvbRuntimeDxe/Fvb.c
BaseTools: Library hashing fix and optimization for --hash feature
[mirror_edk2.git] / OvmfPkg / EmuVariableFvbRuntimeDxe / Fvb.c
... / ...
CommitLineData
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
5 Copyright (c) 2006 - 2013, Intel Corporation. All rights reserved.<BR>\r
6 SPDX-License-Identifier: BSD-2-Clause-Patent\r
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
31#define EFI_AUTHENTICATED_VARIABLE_GUID \\r
32{ 0xaaf32c78, 0x947b, 0x439a, { 0xa1, 0x80, 0x2e, 0x14, 0x4e, 0xc3, 0x77, 0x92 } }\r
33\r
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
71 EMU_FVB_BLOCK_SIZE, // BlockSize\r
72 EMU_FVB_SIZE, // Size\r
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
116 @param This Indicates the EFI_FIRMWARE_VOLUME_BLOCK2_PROTOCOL instance.\r
117\r
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
122\r
123 @retval EFI_SUCCESS The firmware volume base address is returned.\r
124\r
125 @retval EFI_NOT_SUPPORTED The firmware volume is not memory mapped.\r
126\r
127**/\r
128EFI_STATUS\r
129EFIAPI\r
130FvbProtocolGetPhysicalAddress (\r
131 IN CONST EFI_FIRMWARE_VOLUME_BLOCK2_PROTOCOL *This,\r
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
152 @param This Indicates the EFI_FIRMWARE_VOLUME_BLOCK2_PROTOCOL instance.\r
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
165\r
166 @retval EFI_SUCCESS The firmware volume base address is returned.\r
167\r
168 @retval EFI_INVALID_PARAMETER The requested LBA is out of range.\r
169\r
170**/\r
171EFI_STATUS\r
172EFIAPI\r
173FvbProtocolGetBlockSize (\r
174 IN CONST EFI_FIRMWARE_VOLUME_BLOCK2_PROTOCOL *This,\r
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
182 if (Lba >= EMU_FVB_NUM_TOTAL_BLOCKS) {\r
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
189 *NumberOfBlocks = (UINTN)(EMU_FVB_NUM_TOTAL_BLOCKS - Lba);\r
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
199 @param This Indicates the EFI_FIRMWARE_VOLUME_BLOCK2_PROTOCOL instance.\r
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
213 IN CONST EFI_FIRMWARE_VOLUME_BLOCK2_PROTOCOL *This,\r
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
234 @param This Indicates the EFI_FIRMWARE_VOLUME_BLOCK2_PROTOCOL instance.\r
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
243\r
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
255 IN CONST EFI_FIRMWARE_VOLUME_BLOCK2_PROTOCOL *This,\r
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
281 @param This Indicates the EFI_FIRMWARE_VOLUME_BLOCK2_PROTOCOL\r
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
299\r
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
308 not exist in the firmware volume.\r
309\r
310**/\r
311EFI_STATUS\r
312EFIAPI\r
313FvbProtocolEraseBlocks (\r
314 IN CONST EFI_FIRMWARE_VOLUME_BLOCK2_PROTOCOL *This,\r
315 ...\r
316 )\r
317{\r
318 EFI_FW_VOL_BLOCK_DEVICE *FvbDevice;\r
319 VA_LIST Args;\r
320 EFI_LBA StartingLba;\r
321 UINTN NumOfLba;\r
322 UINT8 *ErasePtr;\r
323 UINTN EraseSize;\r
324\r
325 FvbDevice = FVB_DEVICE_FROM_THIS (This);\r
326\r
327 //\r
328 // Check input parameters\r
329 //\r
330 VA_START (Args, This);\r
331 do {\r
332 StartingLba = VA_ARG (Args, EFI_LBA);\r
333 if (StartingLba == EFI_LBA_LIST_TERMINATOR) {\r
334 break;\r
335 }\r
336 NumOfLba = VA_ARG (Args, UINTN);\r
337\r
338 if (StartingLba > EMU_FVB_NUM_TOTAL_BLOCKS ||\r
339 NumOfLba > EMU_FVB_NUM_TOTAL_BLOCKS - StartingLba) {\r
340 VA_END (Args);\r
341 return EFI_INVALID_PARAMETER;\r
342 }\r
343 } while (1);\r
344 VA_END (Args);\r
345\r
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
356\r
357 ErasePtr = FvbDevice->BufferPtr;\r
358 ErasePtr += (UINTN)StartingLba * FvbDevice->BlockSize;\r
359 EraseSize = NumOfLba * FvbDevice->BlockSize;\r
360\r
361 SetMem (ErasePtr, EraseSize, ERASED_UINT8);\r
362 } while (1);\r
363 VA_END (Args);\r
364\r
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
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
406 @param This Indicates the EFI_FIRMWARE_VOLUME_BLOCK2_PROTOCOL instance.\r
407\r
408 @param Lba The starting logical block index to write to.\r
409\r
410 @param Offset Offset into the block at which to begin writing.\r
411\r
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
416\r
417 @param Buffer Pointer to a caller-allocated buffer that\r
418 contains the source for the write.\r
419\r
420 @retval EFI_SUCCESS The firmware volume was written successfully.\r
421\r
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
426\r
427 @retval EFI_ACCESS_DENIED The firmware volume is in the\r
428 WriteDisabled state.\r
429\r
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
438 IN CONST EFI_FIRMWARE_VOLUME_BLOCK2_PROTOCOL *This,\r
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
445 EFI_FW_VOL_BLOCK_DEVICE *FvbDevice;\r
446 UINT8 *FvbDataPtr;\r
447 EFI_STATUS Status;\r
448\r
449 FvbDevice = FVB_DEVICE_FROM_THIS (This);\r
450\r
451 if (Lba >= EMU_FVB_NUM_TOTAL_BLOCKS ||\r
452 Offset > FvbDevice->BlockSize) {\r
453 return EFI_INVALID_PARAMETER;\r
454 }\r
455\r
456 Status = EFI_SUCCESS;\r
457 if (*NumBytes > FvbDevice->BlockSize - Offset) {\r
458 *NumBytes = FvbDevice->BlockSize - Offset;\r
459 Status = EFI_BAD_BUFFER_SIZE;\r
460 }\r
461\r
462 FvbDataPtr = FvbDevice->BufferPtr;\r
463 FvbDataPtr += (UINTN)Lba * FvbDevice->BlockSize;\r
464 FvbDataPtr += Offset;\r
465\r
466 CopyMem (FvbDataPtr, Buffer, *NumBytes);\r
467 PlatformFvbDataWritten (This, Lba, Offset, *NumBytes, Buffer);\r
468 return Status;\r
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
488 @param This Indicates the EFI_FIRMWARE_VOLUME_BLOCK2_PROTOCOL instance.\r
489\r
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
505\r
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
510\r
511 @retval EFI_ACCESS_DENIED The firmware volume is in the\r
512 ReadDisabled state.\r
513\r
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
522 IN CONST EFI_FIRMWARE_VOLUME_BLOCK2_PROTOCOL *This,\r
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
531 EFI_STATUS Status;\r
532\r
533 FvbDevice = FVB_DEVICE_FROM_THIS (This);\r
534\r
535 if (Lba >= EMU_FVB_NUM_TOTAL_BLOCKS ||\r
536 Offset > FvbDevice->BlockSize) {\r
537 return EFI_INVALID_PARAMETER;\r
538 }\r
539\r
540 Status = EFI_SUCCESS;\r
541 if (*NumBytes > FvbDevice->BlockSize - Offset) {\r
542 *NumBytes = FvbDevice->BlockSize - Offset;\r
543 Status = EFI_BAD_BUFFER_SIZE;\r
544 }\r
545\r
546 FvbDataPtr = FvbDevice->BufferPtr;\r
547 FvbDataPtr += (UINTN)Lba * FvbDevice->BlockSize;\r
548 FvbDataPtr += Offset;\r
549\r
550 CopyMem (Buffer, FvbDataPtr, *NumBytes);\r
551 PlatformFvbDataRead (This, Lba, Offset, *NumBytes, Buffer);\r
552 return Status;\r
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
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
641 {0},\r
642\r
643 // UINT8 Revision;\r
644 EFI_FVH_REVISION,\r
645\r
646 // EFI_FV_BLOCK_MAP_ENTRY BlockMap[1];\r
647 {\r
648 {\r
649 EMU_FVB_NUM_TOTAL_BLOCKS, // UINT32 NumBlocks;\r
650 EMU_FVB_BLOCK_SIZE // UINT32 Length;\r
651 }\r
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
662 FixedPcdGet32 (PcdFlashNvStorageVariableSize) -\r
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
680 EFI_FIRMWARE_VOLUME_HEADER *Fv;\r
681\r
682 //\r
683 // Copy the template structure into the location\r
684 //\r
685 CopyMem (\r
686 Ptr,\r
687 &FvAndAuthenticatedVarTemplate,\r
688 sizeof FvAndAuthenticatedVarTemplate\r
689 );\r
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
698/**\r
699 Main entry point.\r
700\r
701 @param[in] ImageHandle The firmware allocated handle for the EFI image.\r
702 @param[in] SystemTable A pointer to the EFI System Table.\r
703\r
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
720 RETURN_STATUS PcdStatus;\r
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
727 ASSERT (FixedPcdGet32 (PcdFlashNvStorageFtwSpareSize) %\r
728 EMU_FVB_BLOCK_SIZE == 0);\r
729 if (\r
730 (PcdGet32 (PcdFlashNvStorageVariableSize) +\r
731 PcdGet32 (PcdFlashNvStorageFtwWorkingSize)\r
732 ) >\r
733 EMU_FVB_NUM_SPARE_BLOCKS * EMU_FVB_BLOCK_SIZE\r
734 ) {\r
735 DEBUG ((EFI_D_ERROR, "EMU Variable invalid PCD sizes\n"));\r
736 return EFI_INVALID_PARAMETER;\r
737 }\r
738\r
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
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
767 Ptr = AllocateRuntimePages (EFI_SIZE_TO_PAGES (EMU_FVB_SIZE));\r
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
779 PcdStatus = PcdSet64S (PcdFlashNvStorageVariableBase64, (UINT32)(UINTN) Ptr);\r
780 ASSERT_RETURN_ERROR (PcdStatus);\r
781\r
782 //\r
783 // Initialize the Fault Tolerant Write data area\r
784 //\r
785 SubPtr = (VOID*) ((UINT8*) Ptr + PcdGet32 (PcdFlashNvStorageVariableSize));\r
786 PcdStatus = PcdSet32S (PcdFlashNvStorageFtwWorkingBase,\r
787 (UINT32)(UINTN) SubPtr);\r
788 ASSERT_RETURN_ERROR (PcdStatus);\r
789\r
790 //\r
791 // Initialize the Fault Tolerant Write spare block\r
792 //\r
793 SubPtr = (VOID*) ((UINT8*) Ptr +\r
794 EMU_FVB_NUM_SPARE_BLOCKS * EMU_FVB_BLOCK_SIZE);\r
795 PcdStatus = PcdSet32S (PcdFlashNvStorageFtwSpareBase,\r
796 (UINT32)(UINTN) SubPtr);\r
797 ASSERT_RETURN_ERROR (PcdStatus);\r
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
813 &gEfiFirmwareVolumeBlock2ProtocolGuid,\r
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