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