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