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 FixedPcdGet32 (PcdFlashNvStorageFtwSpareSize), // BlockSize
78 2 * FixedPcdGet32 (PcdFlashNvStorageFtwSpareSize), // 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
FvbVirtualAddressChangeEvent(IN EFI_EVENT Event,IN VOID * Context)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
FvbProtocolGetPhysicalAddress(IN CONST EFI_FIRMWARE_VOLUME_BLOCK2_PROTOCOL * This,OUT EFI_PHYSICAL_ADDRESS * Address)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
FvbProtocolGetBlockSize(IN CONST EFI_FIRMWARE_VOLUME_BLOCK2_PROTOCOL * This,IN EFI_LBA Lba,OUT UINTN * BlockSize,OUT UINTN * NumberOfBlocks)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 > 1) {
189 return EFI_INVALID_PARAMETER;
190 }
191
192 FvbDevice = FVB_DEVICE_FROM_THIS (This);
193
194 *BlockSize = FvbDevice->BlockSize;
195 *NumberOfBlocks = (UINTN) (2 - (UINTN) 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
FvbProtocolGetAttributes(IN CONST EFI_FIRMWARE_VOLUME_BLOCK2_PROTOCOL * This,OUT EFI_FVB_ATTRIBUTES_2 * Attributes)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
FvbProtocolSetAttributes(IN CONST EFI_FIRMWARE_VOLUME_BLOCK2_PROTOCOL * This,IN OUT EFI_FVB_ATTRIBUTES_2 * Attributes)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
FvbProtocolEraseBlocks(IN CONST EFI_FIRMWARE_VOLUME_BLOCK2_PROTOCOL * This,...)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 Erase;
329 VOID *ErasePtr;
330 UINTN EraseSize;
331
332 FvbDevice = FVB_DEVICE_FROM_THIS (This);
333 Erase = 0;
334
335 VA_START (args, This);
336
337 do {
338 StartingLba = VA_ARG (args, EFI_LBA);
339 if (StartingLba == EFI_LBA_LIST_TERMINATOR) {
340 break;
341 }
342
343 NumOfLba = VA_ARG (args, UINT32);
344
345 //
346 // Check input parameters
347 //
348 if ((NumOfLba == 0) || (StartingLba > 1) || ((StartingLba + NumOfLba) > 2)) {
349 VA_END (args);
350 return EFI_INVALID_PARAMETER;
351 }
352
353 if (StartingLba == 0) {
354 Erase = (UINT8) (Erase | BIT0);
355 }
356 if ((StartingLba + NumOfLba) == 2) {
357 Erase = (UINT8) (Erase | BIT1);
358 }
359
360 } while (1);
361
362 VA_END (args);
363
364 ErasePtr = (UINT8*) FvbDevice->BufferPtr;
365 EraseSize = 0;
366
367 if ((Erase & BIT0) != 0) {
368 EraseSize = EraseSize + FvbDevice->BlockSize;
369 } else {
370 ErasePtr = (VOID*) ((UINT8*)ErasePtr + FvbDevice->BlockSize);
371 }
372
373 if ((Erase & BIT1) != 0) {
374 EraseSize = EraseSize + FvbDevice->BlockSize;
375 }
376
377 if (EraseSize != 0) {
378 SetMem (
379 (VOID*) ErasePtr,
380 EraseSize,
381 ERASED_UINT8
382 );
383 VA_START (args, This);
384 PlatformFvbBlocksErased (This, args);
385 VA_END (args);
386 }
387
388 return EFI_SUCCESS;
389 }
390
391
392 /**
393 Writes the specified number of bytes from the input buffer to the block.
394
395 The Write() function writes the specified number of bytes from
396 the provided buffer to the specified block and offset. If the
397 firmware volume is sticky write, the caller must ensure that
398 all the bits of the specified range to write are in the
399 EFI_FVB_ERASE_POLARITY state before calling the Write()
400 function, or else the result will be unpredictable. This
401 unpredictability arises because, for a sticky-write firmware
402 volume, a write may negate a bit in the EFI_FVB_ERASE_POLARITY
403 state but cannot flip it back again. In general, before
404 calling the Write() function, the caller should call the
405 EraseBlocks() function first to erase the specified block to
406 write. A block erase cycle will transition bits from the
407 (NOT)EFI_FVB_ERASE_POLARITY state back to the
408 EFI_FVB_ERASE_POLARITY state. Implementations should be
409 mindful that the firmware volume might be in the WriteDisabled
410 state. If it is in this state, the Write() function must
411 return the status code EFI_ACCESS_DENIED without modifying the
412 contents of the firmware volume. The Write() function must
413 also prevent spanning block boundaries. If a write is
414 requested that spans a block boundary, the write must store up
415 to the boundary but not beyond. The output parameter NumBytes
416 must be set to correctly indicate the number of bytes actually
417 written. The caller must be aware that a write may be
418 partially completed. All writes, partial or otherwise, must be
419 fully flushed to the hardware before the Write() service
420 returns.
421
422 @param This Indicates the EFI_FIRMWARE_VOLUME_BLOCK2_PROTOCOL instance.
423
424 @param Lba The starting logical block index to write to.
425
426 @param Offset Offset into the block at which to begin writing.
427
428 @param NumBytes Pointer to a UINTN. At entry, *NumBytes
429 contains the total size of the buffer. At
430 exit, *NumBytes contains the total number of
431 bytes actually written.
432
433 @param Buffer Pointer to a caller-allocated buffer that
434 contains the source for the write.
435
436 @retval EFI_SUCCESS The firmware volume was written successfully.
437
438 @retval EFI_BAD_BUFFER_SIZE The write was attempted across an
439 LBA boundary. On output, NumBytes
440 contains the total number of bytes
441 actually written.
442
443 @retval EFI_ACCESS_DENIED The firmware volume is in the
444 WriteDisabled state.
445
446 @retval EFI_DEVICE_ERROR The block device is malfunctioning
447 and could not be written.
448
449
450 **/
451 EFI_STATUS
452 EFIAPI
FvbProtocolWrite(IN CONST EFI_FIRMWARE_VOLUME_BLOCK2_PROTOCOL * This,IN EFI_LBA Lba,IN UINTN Offset,IN OUT UINTN * NumBytes,IN UINT8 * Buffer)453 FvbProtocolWrite (
454 IN CONST EFI_FIRMWARE_VOLUME_BLOCK2_PROTOCOL *This,
455 IN EFI_LBA Lba,
456 IN UINTN Offset,
457 IN OUT UINTN *NumBytes,
458 IN UINT8 *Buffer
459 )
460 {
461
462 EFI_FW_VOL_BLOCK_DEVICE *FvbDevice;
463 UINT8 *FvbDataPtr;
464
465 FvbDevice = FVB_DEVICE_FROM_THIS (This);
466
467 if ((Lba > 1) || (Offset > FvbDevice->BlockSize)) {
468 return EFI_INVALID_PARAMETER;
469 }
470
471 if ((Offset + *NumBytes) > FvbDevice->BlockSize) {
472 *NumBytes = FvbDevice->BlockSize - Offset;
473 }
474
475 FvbDataPtr =
476 (UINT8*) FvbDevice->BufferPtr +
477 MultU64x32 (Lba, (UINT32) FvbDevice->BlockSize) +
478 Offset;
479
480 if (*NumBytes > 0) {
481 CopyMem (FvbDataPtr, Buffer, *NumBytes);
482 PlatformFvbDataWritten (This, Lba, Offset, *NumBytes, Buffer);
483 }
484
485 return EFI_SUCCESS;
486 }
487
488
489 /**
490 Reads the specified number of bytes into a buffer from the specified block.
491
492 The Read() function reads the requested number of bytes from the
493 requested block and stores them in the provided buffer.
494 Implementations should be mindful that the firmware volume
495 might be in the ReadDisabled state. If it is in this state,
496 the Read() function must return the status code
497 EFI_ACCESS_DENIED without modifying the contents of the
498 buffer. The Read() function must also prevent spanning block
499 boundaries. If a read is requested that would span a block
500 boundary, the read must read up to the boundary but not
501 beyond. The output parameter NumBytes must be set to correctly
502 indicate the number of bytes actually read. The caller must be
503 aware that a read may be partially completed.
504
505 @param This Indicates the EFI_FIRMWARE_VOLUME_BLOCK2_PROTOCOL instance.
506
507 @param Lba The starting logical block index
508 from which to read.
509
510 @param Offset Offset into the block at which to begin reading.
511
512 @param NumBytes Pointer to a UINTN. At entry, *NumBytes
513 contains the total size of the buffer. At
514 exit, *NumBytes contains the total number of
515 bytes read.
516
517 @param Buffer Pointer to a caller-allocated buffer that will
518 be used to hold the data that is read.
519
520 @retval EFI_SUCCESS The firmware volume was read successfully
521 and contents are in Buffer.
522
523 @retval EFI_BAD_BUFFER_SIZE Read attempted across an LBA
524 boundary. On output, NumBytes
525 contains the total number of bytes
526 returned in Buffer.
527
528 @retval EFI_ACCESS_DENIED The firmware volume is in the
529 ReadDisabled state.
530
531 @retval EFI_DEVICE_ERROR The block device is not
532 functioning correctly and could
533 not be read.
534
535 **/
536 EFI_STATUS
537 EFIAPI
FvbProtocolRead(IN CONST EFI_FIRMWARE_VOLUME_BLOCK2_PROTOCOL * This,IN EFI_LBA Lba,IN UINTN Offset,IN OUT UINTN * NumBytes,IN OUT UINT8 * Buffer)538 FvbProtocolRead (
539 IN CONST EFI_FIRMWARE_VOLUME_BLOCK2_PROTOCOL *This,
540 IN EFI_LBA Lba,
541 IN UINTN Offset,
542 IN OUT UINTN *NumBytes,
543 IN OUT UINT8 *Buffer
544 )
545 {
546 EFI_FW_VOL_BLOCK_DEVICE *FvbDevice;
547 UINT8 *FvbDataPtr;
548
549 FvbDevice = FVB_DEVICE_FROM_THIS (This);
550
551 if ((Lba > 1) || (Offset > FvbDevice->BlockSize)) {
552 return EFI_INVALID_PARAMETER;
553 }
554
555 if ((Offset + *NumBytes) > FvbDevice->BlockSize) {
556 *NumBytes = FvbDevice->BlockSize - Offset;
557 }
558
559 FvbDataPtr =
560 (UINT8*) FvbDevice->BufferPtr +
561 MultU64x32 (Lba, (UINT32) FvbDevice->BlockSize) +
562 Offset;
563
564 if (*NumBytes > 0) {
565 CopyMem (Buffer, FvbDataPtr, *NumBytes);
566 PlatformFvbDataRead (This, Lba, Offset, *NumBytes, Buffer);
567 }
568
569 return EFI_SUCCESS;
570 }
571
572
573 /**
574 Check the integrity of firmware volume header.
575
576 @param[in] FwVolHeader - A pointer to a firmware volume header
577
578 @retval EFI_SUCCESS - The firmware volume is consistent
579 @retval EFI_NOT_FOUND - The firmware volume has been corrupted.
580
581 **/
582 EFI_STATUS
ValidateFvHeader(IN EFI_FIRMWARE_VOLUME_HEADER * FwVolHeader)583 ValidateFvHeader (
584 IN EFI_FIRMWARE_VOLUME_HEADER *FwVolHeader
585 )
586 {
587 UINT16 Checksum;
588
589 //
590 // Verify the header revision, header signature, length
591 // Length of FvBlock cannot be 2**64-1
592 // HeaderLength cannot be an odd number
593 //
594 if ((FwVolHeader->Revision != EFI_FVH_REVISION) ||
595 (FwVolHeader->Signature != EFI_FVH_SIGNATURE) ||
596 (FwVolHeader->FvLength != EMU_FVB_SIZE) ||
597 (FwVolHeader->HeaderLength != EMU_FV_HEADER_LENGTH)
598 ) {
599 DEBUG ((EFI_D_INFO, "EMU Variable FVB: Basic FV headers were invalid\n"));
600 return EFI_NOT_FOUND;
601 }
602 //
603 // Verify the header checksum
604 //
605 Checksum = CalculateSum16((VOID*) FwVolHeader, FwVolHeader->HeaderLength);
606
607 if (Checksum != 0) {
608 DEBUG ((EFI_D_INFO, "EMU Variable FVB: FV checksum was invalid\n"));
609 return EFI_NOT_FOUND;
610 }
611
612 return EFI_SUCCESS;
613 }
614
615
616 /**
617 Initializes the FV Header and Variable Store Header
618 to support variable operations.
619
620 @param[in] Ptr - Location to initialize the headers
621
622 **/
623 VOID
InitializeFvAndVariableStoreHeaders(IN VOID * Ptr)624 InitializeFvAndVariableStoreHeaders (
625 IN VOID *Ptr
626 )
627 {
628 //
629 // Templates for standard (non-authenticated) variable FV header
630 //
631 STATIC FVB_FV_HDR_AND_VARS_TEMPLATE FvAndVarTemplate = {
632 { // EFI_FIRMWARE_VOLUME_HEADER FvHdr;
633 // UINT8 ZeroVector[16];
634 { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
635
636 // EFI_GUID FileSystemGuid;
637 EFI_SYSTEM_NV_DATA_FV_GUID,
638
639 // UINT64 FvLength;
640 EMU_FVB_SIZE,
641
642 // UINT32 Signature;
643 EFI_FVH_SIGNATURE,
644
645 // EFI_FVB_ATTRIBUTES_2 Attributes;
646 0x4feff,
647
648 // UINT16 HeaderLength;
649 EMU_FV_HEADER_LENGTH,
650
651 // UINT16 Checksum;
652 0,
653
654 // UINT16 ExtHeaderOffset;
655 0,
656
657 // UINT8 Reserved[1];
658 {0},
659
660 // UINT8 Revision;
661 EFI_FVH_REVISION,
662
663 // EFI_FV_BLOCK_MAP_ENTRY BlockMap[1];
664 {
665 {
666 2, // UINT32 NumBlocks;
667 EMU_FVB_BLOCK_SIZE // UINT32 Length;
668 }
669 }
670 },
671 // EFI_FV_BLOCK_MAP_ENTRY EndBlockMap;
672 { 0, 0 }, // End of block map
673 { // VARIABLE_STORE_HEADER VarHdr;
674 // EFI_GUID Signature;
675 EFI_VARIABLE_GUID,
676
677 // UINT32 Size;
678 (
679 FixedPcdGet32 (PcdVariableStoreSize) -
680 OFFSET_OF (FVB_FV_HDR_AND_VARS_TEMPLATE, VarHdr)
681 ),
682
683 // UINT8 Format;
684 VARIABLE_STORE_FORMATTED,
685
686 // UINT8 State;
687 VARIABLE_STORE_HEALTHY,
688
689 // UINT16 Reserved;
690 0,
691
692 // UINT32 Reserved1;
693 0
694 }
695 };
696
697 //
698 // Templates for authenticated variable FV header
699 //
700 STATIC FVB_FV_HDR_AND_VARS_TEMPLATE FvAndAuthenticatedVarTemplate = {
701 { // EFI_FIRMWARE_VOLUME_HEADER FvHdr;
702 // UINT8 ZeroVector[16];
703 { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
704
705 // EFI_GUID FileSystemGuid;
706 EFI_SYSTEM_NV_DATA_FV_GUID,
707
708 // UINT64 FvLength;
709 EMU_FVB_SIZE,
710
711 // UINT32 Signature;
712 EFI_FVH_SIGNATURE,
713
714 // EFI_FVB_ATTRIBUTES_2 Attributes;
715 0x4feff,
716
717 // UINT16 HeaderLength;
718 EMU_FV_HEADER_LENGTH,
719
720 // UINT16 Checksum;
721 0,
722
723 // UINT16 ExtHeaderOffset;
724 0,
725
726 // UINT8 Reserved[1];
727 {0},
728
729 // UINT8 Revision;
730 EFI_FVH_REVISION,
731
732 // EFI_FV_BLOCK_MAP_ENTRY BlockMap[1];
733 {
734 {
735 2, // UINT32 NumBlocks;
736 EMU_FVB_BLOCK_SIZE // UINT32 Length;
737 }
738 }
739 },
740 // EFI_FV_BLOCK_MAP_ENTRY EndBlockMap;
741 { 0, 0 }, // End of block map
742 { // VARIABLE_STORE_HEADER VarHdr;
743 // EFI_GUID Signature; // need authenticated variables for secure boot
744 EFI_AUTHENTICATED_VARIABLE_GUID,
745
746 // UINT32 Size;
747 (
748 FixedPcdGet32 (PcdVariableStoreSize) -
749 OFFSET_OF (FVB_FV_HDR_AND_VARS_TEMPLATE, VarHdr)
750 ),
751
752 // UINT8 Format;
753 VARIABLE_STORE_FORMATTED,
754
755 // UINT8 State;
756 VARIABLE_STORE_HEALTHY,
757
758 // UINT16 Reserved;
759 0,
760
761 // UINT32 Reserved1;
762 0
763 }
764 };
765
766 EFI_FIRMWARE_VOLUME_HEADER *Fv;
767
768 //
769 // Copy the template structure into the location
770 //
771 if (FeaturePcdGet (PcdSecureBootEnable) == FALSE) {
772 CopyMem (Ptr, (VOID*)&FvAndVarTemplate, sizeof (FvAndVarTemplate));
773 } else {
774 CopyMem (Ptr, (VOID*)&FvAndAuthenticatedVarTemplate, sizeof (FvAndAuthenticatedVarTemplate));
775 }
776
777 //
778 // Update the checksum for the FV header
779 //
780 Fv = (EFI_FIRMWARE_VOLUME_HEADER*) Ptr;
781 Fv->Checksum = CalculateCheckSum16 (Ptr, Fv->HeaderLength);
782 }
783
784 /**
785 Main entry point.
786
787 @param[in] ImageHandle The firmware allocated handle for the EFI image.
788 @param[in] SystemTable A pointer to the EFI System Table.
789
790 @retval EFI_SUCCESS Successfully initialized.
791
792 **/
793 EFI_STATUS
794 EFIAPI
FvbInitialize(IN EFI_HANDLE ImageHandle,IN EFI_SYSTEM_TABLE * SystemTable)795 FvbInitialize (
796 IN EFI_HANDLE ImageHandle,
797 IN EFI_SYSTEM_TABLE *SystemTable
798 )
799 {
800 EFI_STATUS Status;
801 VOID *Ptr;
802 VOID *SubPtr;
803 BOOLEAN Initialize;
804 EFI_HANDLE Handle;
805 EFI_PHYSICAL_ADDRESS Address;
806
807 DEBUG ((EFI_D_INFO, "EMU Variable FVB Started\n"));
808
809 //
810 // Verify that the PCD's are set correctly.
811 //
812 if (
813 (PcdGet32 (PcdVariableStoreSize) +
814 PcdGet32 (PcdFlashNvStorageFtwWorkingSize)
815 ) >
816 EMU_FVB_BLOCK_SIZE
817 ) {
818 DEBUG ((EFI_D_ERROR, "EMU Variable invalid PCD sizes\n"));
819 return EFI_INVALID_PARAMETER;
820 }
821
822 if (PcdGet64 (PcdFlashNvStorageVariableBase64) != 0) {
823 DEBUG ((EFI_D_INFO, "Disabling EMU Variable FVB since "
824 "flash variables appear to be supported.\n"));
825 return EFI_ABORTED;
826 }
827
828 //
829 // By default we will initialize the FV contents. But, if
830 // PcdEmuVariableNvStoreReserved is non-zero, then we will
831 // use this location for our buffer.
832 //
833 // If this location does not have a proper FV header, then
834 // we will initialize it.
835 //
836 Initialize = TRUE;
837 if (PcdGet64 (PcdEmuVariableNvStoreReserved) != 0) {
838 Ptr = (VOID*)(UINTN) PcdGet64 (PcdEmuVariableNvStoreReserved);
839 DEBUG ((
840 EFI_D_INFO,
841 "EMU Variable FVB: Using pre-reserved block at %p\n",
842 Ptr
843 ));
844 Status = ValidateFvHeader (Ptr);
845 if (!EFI_ERROR (Status)) {
846 DEBUG ((EFI_D_INFO, "EMU Variable FVB: Found valid pre-existing FV\n"));
847 Initialize = FALSE;
848 }
849 } else {
850 Ptr = AllocateAlignedRuntimePages (
851 EFI_SIZE_TO_PAGES (EMU_FVB_SIZE),
852 SIZE_64KB
853 );
854 }
855
856 mEmuVarsFvb.BufferPtr = Ptr;
857
858 //
859 // Initialize the main FV header and variable store header
860 //
861 if (Initialize) {
862 SetMem (Ptr, EMU_FVB_SIZE, ERASED_UINT8);
863 InitializeFvAndVariableStoreHeaders (Ptr);
864 }
865 PcdSet64 (PcdFlashNvStorageVariableBase64, (UINT32)(UINTN) Ptr);
866
867 //
868 // Initialize the Fault Tolerant Write data area
869 //
870 SubPtr = (VOID*) ((UINT8*) Ptr + PcdGet32 (PcdVariableStoreSize));
871 PcdSet32 (PcdFlashNvStorageFtwWorkingBase, (UINT32)(UINTN) SubPtr);
872
873 //
874 // Initialize the Fault Tolerant Write spare block
875 //
876 SubPtr = (VOID*) ((UINT8*) Ptr + EMU_FVB_BLOCK_SIZE);
877 PcdSet32 (PcdFlashNvStorageFtwSpareBase, (UINT32)(UINTN) SubPtr);
878
879 //
880 // Setup FVB device path
881 //
882 Address = (EFI_PHYSICAL_ADDRESS)(UINTN) Ptr;
883 mEmuVarsFvb.DevicePath.MemMapDevPath.StartingAddress = Address;
884 mEmuVarsFvb.DevicePath.MemMapDevPath.EndingAddress = Address + EMU_FVB_SIZE - 1;
885
886 //
887 // Install the protocols
888 //
889 DEBUG ((EFI_D_INFO, "Installing FVB for EMU Variable support\n"));
890 Handle = 0;
891 Status = gBS->InstallMultipleProtocolInterfaces (
892 &Handle,
893 &gEfiFirmwareVolumeBlock2ProtocolGuid,
894 &mEmuVarsFvb.FwVolBlockInstance,
895 &gEfiDevicePathProtocolGuid,
896 &mEmuVarsFvb.DevicePath,
897 NULL
898 );
899 ASSERT_EFI_ERROR (Status);
900
901 //
902 // Register for the virtual address change event
903 //
904 Status = gBS->CreateEventEx (
905 EVT_NOTIFY_SIGNAL,
906 TPL_NOTIFY,
907 FvbVirtualAddressChangeEvent,
908 NULL,
909 &gEfiEventVirtualAddressChangeGuid,
910 &mEmuVarsFvbAddrChangeEvent
911 );
912 ASSERT_EFI_ERROR (Status);
913
914 return EFI_SUCCESS;
915 }
916
917
918