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