]> git.proxmox.com Git - mirror_edk2.git/blob - UefiPayloadPkg/FvbRuntimeDxe/FvbService.c
OvmfPkg/PlatformPei: set the Hypervisor Features PCD
[mirror_edk2.git] / UefiPayloadPkg / FvbRuntimeDxe / FvbService.c
1 /** @file
2 Firmware Volume Block Driver to provide FVB service.
3
4 Copyright (c) 2014 - 2021, Intel Corporation. All rights reserved.<BR>
5 SPDX-License-Identifier: BSD-2-Clause-Patent
6
7 **/
8
9 #include "FvbService.h"
10
11 //
12 // Global variable for this FVB driver which contains
13 // the private data of all firmware volume block instances
14 //
15 FWB_GLOBAL mFvbModuleGlobal;
16
17 FV_MEMMAP_DEVICE_PATH mFvMemmapDevicePathTemplate = {
18 {
19 {
20 HARDWARE_DEVICE_PATH,
21 HW_MEMMAP_DP,
22 {
23 (UINT8)(sizeof (MEMMAP_DEVICE_PATH)),
24 (UINT8)(sizeof (MEMMAP_DEVICE_PATH) >> 8)
25 }
26 },
27 EfiMemoryMappedIO,
28 (EFI_PHYSICAL_ADDRESS)0,
29 (EFI_PHYSICAL_ADDRESS)0,
30 },
31 {
32 END_DEVICE_PATH_TYPE,
33 END_ENTIRE_DEVICE_PATH_SUBTYPE,
34 {
35 END_DEVICE_PATH_LENGTH,
36 0
37 }
38 }
39 };
40
41 FV_PIWG_DEVICE_PATH mFvPIWGDevicePathTemplate = {
42 {
43 {
44 MEDIA_DEVICE_PATH,
45 MEDIA_PIWG_FW_VOL_DP,
46 {
47 (UINT8)(sizeof (MEDIA_FW_VOL_DEVICE_PATH)),
48 (UINT8)(sizeof (MEDIA_FW_VOL_DEVICE_PATH) >> 8)
49 }
50 },
51 { 0 }
52 },
53 {
54 END_DEVICE_PATH_TYPE,
55 END_ENTIRE_DEVICE_PATH_SUBTYPE,
56 {
57 END_DEVICE_PATH_LENGTH,
58 0
59 }
60 }
61 };
62
63 EFI_FW_VOL_BLOCK_DEVICE mFvbDeviceTemplate = {
64 FVB_DEVICE_SIGNATURE,
65 NULL,
66 0, // Instance
67 {
68 FvbProtocolGetAttributes,
69 FvbProtocolSetAttributes,
70 FvbProtocolGetPhysicalAddress,
71 FvbProtocolGetBlockSize,
72 FvbProtocolRead,
73 FvbProtocolWrite,
74 FvbProtocolEraseBlocks,
75 NULL
76 } // FwVolBlockInstance
77 };
78
79 /**
80 Get the pointer to EFI_FW_VOL_INSTANCE from the buffer pointed
81 by mFvbModuleGlobal.FvInstance based on a index.
82 Each EFI_FW_VOL_INSTANCE is with variable length as
83 we have a block map at the end of the EFI_FIRMWARE_VOLUME_HEADER.
84
85 @param[in] Instance The index of the EFI_FW_VOL_INSTANCE.
86
87 @return A pointer to EFI_FW_VOL_INSTANCE.
88
89 **/
90 EFI_FW_VOL_INSTANCE *
91 GetFvbInstance (
92 IN UINTN Instance
93 )
94 {
95 EFI_FW_VOL_INSTANCE *FwhRecord;
96
97 if ( Instance >= mFvbModuleGlobal.NumFv ) {
98 ASSERT_EFI_ERROR (EFI_INVALID_PARAMETER);
99 return NULL;
100 }
101
102 //
103 // Find the right instance of the FVB private data
104 //
105 FwhRecord = mFvbModuleGlobal.FvInstance;
106 while ( Instance > 0 ) {
107 FwhRecord = (EFI_FW_VOL_INSTANCE *)((UINTN)((UINT8 *)FwhRecord) +
108 FwhRecord->VolumeHeader.HeaderLength +
109 (sizeof (EFI_FW_VOL_INSTANCE) - sizeof (EFI_FIRMWARE_VOLUME_HEADER)));
110 Instance--;
111 }
112
113 return FwhRecord;
114 }
115
116 /**
117 Get the EFI_FVB_ATTRIBUTES_2 of a FV.
118
119 @param[in] Instance The index of the EFI_FW_VOL_INSTANCE.
120
121 @retval EFI_FVB_ATTRIBUTES_2 of the FV identified by Instance.
122
123 **/
124 STATIC
125 EFI_FVB_ATTRIBUTES_2
126 FvbGetVolumeAttributes (
127 IN UINTN Instance
128 )
129 {
130 EFI_FW_VOL_INSTANCE *FwInstance;
131
132 FwInstance = GetFvbInstance (Instance);
133 ASSERT (FwInstance != NULL);
134
135 if (FwInstance == NULL) {
136 return 0;
137 }
138
139 return FwInstance->VolumeHeader.Attributes;
140 }
141
142 /**
143 Retrieves the starting address of an LBA in an FV. It also
144 return a few other attribut of the FV.
145
146 @param[in] Instance The index of the EFI_FW_VOL_INSTANCE.
147 @param[in] Lba The logical block address
148 @param[out] LbaAddress On output, contains the physical starting address
149 of the Lba
150 @param[out] LbaLength On output, contains the length of the block
151 @param[out] NumOfBlocks A pointer to a caller allocated UINTN in which the
152 number of consecutive blocks starting with Lba is
153 returned. All blocks in this range have a size of
154 BlockSize
155
156 @retval EFI_SUCCESS Successfully returns
157 @retval EFI_INVALID_PARAMETER Instance not found
158
159 **/
160 STATIC
161 EFI_STATUS
162 FvbGetLbaAddress (
163 IN UINTN Instance,
164 IN EFI_LBA Lba,
165 OUT UINTN *LbaAddress,
166 OUT UINTN *LbaLength,
167 OUT UINTN *NumOfBlocks
168 )
169 {
170 UINT32 NumBlocks;
171 UINT32 BlockLength;
172 UINTN Offset;
173 EFI_LBA StartLba;
174 EFI_LBA NextLba;
175 EFI_FW_VOL_INSTANCE *FwhInstance;
176 EFI_FV_BLOCK_MAP_ENTRY *BlockMap;
177
178 //
179 // Find the right instance of the FVB private data
180 //
181 FwhInstance = GetFvbInstance (Instance);
182 if (FwhInstance == NULL) {
183 return EFI_INVALID_PARAMETER;
184 }
185
186 StartLba = 0;
187 Offset = 0;
188 BlockMap = &FwhInstance->VolumeHeader.BlockMap[0];
189 ASSERT (BlockMap != NULL);
190
191 //
192 // Parse the blockmap of the FV to find which map entry the Lba belongs to
193 //
194 while (TRUE) {
195 if ( BlockMap != NULL) {
196 NumBlocks = BlockMap->NumBlocks;
197 BlockLength = BlockMap->Length;
198 }
199
200 if ((NumBlocks == 0) || (BlockLength == 0)) {
201 return EFI_INVALID_PARAMETER;
202 }
203
204 NextLba = StartLba + NumBlocks;
205
206 //
207 // The map entry found
208 //
209 if ((Lba >= StartLba) && (Lba < NextLba)) {
210 Offset = Offset + (UINTN)MultU64x32 ((Lba - StartLba), BlockLength);
211 if (LbaAddress != NULL) {
212 *LbaAddress = FwhInstance->FvBase + Offset;
213 }
214
215 if (LbaLength != NULL) {
216 *LbaLength = BlockLength;
217 }
218
219 if (NumOfBlocks != NULL) {
220 *NumOfBlocks = (UINTN)(NextLba - Lba);
221 }
222
223 return EFI_SUCCESS;
224 }
225
226 StartLba = NextLba;
227 Offset = Offset + NumBlocks * BlockLength;
228 BlockMap++;
229 }
230 }
231
232 /**
233 Reads specified number of bytes into a buffer from the specified block
234
235 @param[in] Instance The FV instance to be read from
236 @param[in] Lba The logical block address to be read from
237 @param[in] BlockOffset Offset into the block at which to begin reading
238 @param[in, out] NumBytes Pointer that on input contains the total size of
239 the buffer. On output, it contains the total number
240 of bytes read
241 @param[in] Buffer Pointer to a caller allocated buffer that will be
242 used to hold the data read
243
244
245 @retval EFI_SUCCESS The firmware volume was read successfully and
246 contents are in Buffer
247 @retval EFI_BAD_BUFFER_SIZE Read attempted across a LBA boundary. On output,
248 NumBytes contains the total number of bytes returned
249 in Buffer
250 @retval EFI_ACCESS_DENIED The firmware volume is in the ReadDisabled state
251 @retval EFI_DEVICE_ERROR The block device is not functioning correctly and
252 could not be read
253 @retval EFI_INVALID_PARAMETER Instance not found, or NumBytes, Buffer are NULL
254
255 **/
256 STATIC
257 EFI_STATUS
258 FvbReadBlock (
259 IN UINTN Instance,
260 IN EFI_LBA Lba,
261 IN UINTN BlockOffset,
262 IN OUT UINTN *NumBytes,
263 IN UINT8 *Buffer
264 )
265 {
266 EFI_FVB_ATTRIBUTES_2 Attributes;
267 UINTN LbaAddress;
268 UINTN LbaLength;
269 EFI_STATUS Status;
270 EFI_STATUS ReadStatus;
271
272 if ((NumBytes == NULL) || (Buffer == NULL)) {
273 return (EFI_INVALID_PARAMETER);
274 }
275
276 if (*NumBytes == 0) {
277 return (EFI_INVALID_PARAMETER);
278 }
279
280 Status = FvbGetLbaAddress (Instance, Lba, &LbaAddress, &LbaLength, NULL);
281 if (EFI_ERROR (Status)) {
282 return Status;
283 }
284
285 Attributes = FvbGetVolumeAttributes (Instance);
286
287 if ((Attributes & EFI_FVB2_READ_STATUS) == 0) {
288 return (EFI_ACCESS_DENIED);
289 }
290
291 if (BlockOffset > LbaLength) {
292 return (EFI_INVALID_PARAMETER);
293 }
294
295 if (LbaLength < (*NumBytes + BlockOffset)) {
296 *NumBytes = (UINT32)(LbaLength - BlockOffset);
297 Status = EFI_BAD_BUFFER_SIZE;
298 }
299
300 ReadStatus = LibFvbFlashDeviceRead (LbaAddress + BlockOffset, NumBytes, Buffer);
301 if (EFI_ERROR (ReadStatus)) {
302 return ReadStatus;
303 }
304
305 return Status;
306 }
307
308 /**
309 Writes specified number of bytes from the input buffer to the block
310
311 @param[in] Instance The FV instance to be written to
312 @param[in] Lba The starting logical block index to write to
313 @param[in] BlockOffset Offset into the block at which to begin writing
314 @param[in, out] NumBytes Pointer that on input contains the total size of
315 the buffer. On output, it contains the total number
316 of bytes actually written
317 @param[in] Buffer Pointer to a caller allocated buffer that contains
318 the source for the write
319 @retval EFI_SUCCESS The firmware volume was written successfully
320 @retval EFI_BAD_BUFFER_SIZE Write attempted across a LBA boundary. On output,
321 NumBytes contains the total number of bytes
322 actually written
323 @retval EFI_ACCESS_DENIED The firmware volume is in the WriteDisabled state
324 @retval EFI_DEVICE_ERROR The block device is not functioning correctly and
325 could not be written
326 @retval EFI_INVALID_PARAMETER Instance not found, or NumBytes, Buffer are NULL
327
328 **/
329 EFI_STATUS
330 FvbWriteBlock (
331 IN UINTN Instance,
332 IN EFI_LBA Lba,
333 IN UINTN BlockOffset,
334 IN OUT UINTN *NumBytes,
335 IN UINT8 *Buffer
336 )
337 {
338 EFI_FVB_ATTRIBUTES_2 Attributes;
339 UINTN LbaAddress;
340 UINTN LbaLength;
341 EFI_STATUS Status;
342
343 if ((NumBytes == NULL) || (Buffer == NULL)) {
344 return (EFI_INVALID_PARAMETER);
345 }
346
347 if (*NumBytes == 0) {
348 return (EFI_INVALID_PARAMETER);
349 }
350
351 Status = FvbGetLbaAddress (Instance, Lba, &LbaAddress, &LbaLength, NULL);
352 if (EFI_ERROR (Status)) {
353 return Status;
354 }
355
356 //
357 // Check if the FV is write enabled
358 //
359 Attributes = FvbGetVolumeAttributes (Instance);
360 if ((Attributes & EFI_FVB2_WRITE_STATUS) == 0) {
361 return EFI_ACCESS_DENIED;
362 }
363
364 //
365 // Perform boundary checks and adjust NumBytes
366 //
367 if (BlockOffset > LbaLength) {
368 return EFI_INVALID_PARAMETER;
369 }
370
371 if ( LbaLength < (*NumBytes + BlockOffset)) {
372 DEBUG ((
373 DEBUG_ERROR,
374 "FvWriteBlock: Reducing Numbytes from 0x%x to 0x%x\n",
375 *NumBytes,
376 (UINT32)(LbaLength - BlockOffset)
377 ));
378 *NumBytes = (UINT32)(LbaLength - BlockOffset);
379 return EFI_BAD_BUFFER_SIZE;
380 }
381
382 LibFvbFlashDeviceBlockLock (LbaAddress, LbaLength, FALSE);
383 Status = LibFvbFlashDeviceWrite (LbaAddress + BlockOffset, NumBytes, Buffer);
384
385 LibFvbFlashDeviceBlockLock (LbaAddress, LbaLength, TRUE);
386 WriteBackInvalidateDataCacheRange ((VOID *)(LbaAddress + BlockOffset), *NumBytes);
387 return Status;
388 }
389
390 /**
391 Erases and initializes a firmware volume block
392
393 @param[in] Instance The FV instance to be erased
394 @param[in] Lba The logical block index to be erased
395
396 @retval EFI_SUCCESS The erase request was successfully completed
397 @retval EFI_ACCESS_DENIED The firmware volume is in the WriteDisabled state
398 @retval EFI_DEVICE_ERROR The block device is not functioning correctly and
399 could not be written. Firmware device may have been
400 partially erased
401 @retval EFI_INVALID_PARAMETER Instance not found
402
403 **/
404 EFI_STATUS
405 FvbEraseBlock (
406 IN UINTN Instance,
407 IN EFI_LBA Lba
408 )
409 {
410 EFI_FVB_ATTRIBUTES_2 Attributes;
411 UINTN LbaAddress;
412 UINTN LbaLength;
413 EFI_STATUS Status;
414
415 //
416 // Check if the FV is write enabled
417 //
418 Attributes = FvbGetVolumeAttributes (Instance);
419
420 if ((Attributes & EFI_FVB2_WRITE_STATUS) == 0) {
421 return (EFI_ACCESS_DENIED);
422 }
423
424 //
425 // Get the starting address of the block for erase.
426 //
427 Status = FvbGetLbaAddress (Instance, Lba, &LbaAddress, &LbaLength, NULL);
428 if (EFI_ERROR (Status)) {
429 return Status;
430 }
431
432 LibFvbFlashDeviceBlockLock (LbaAddress, LbaLength, FALSE);
433
434 Status = LibFvbFlashDeviceBlockErase (LbaAddress, LbaLength);
435
436 LibFvbFlashDeviceBlockLock (LbaAddress, LbaLength, TRUE);
437
438 WriteBackInvalidateDataCacheRange ((VOID *)LbaAddress, LbaLength);
439
440 return Status;
441 }
442
443 /**
444 Modifies the current settings of the firmware volume according to the
445 input parameter, and returns the new setting of the volume
446
447 @param[in] Instance The FV instance whose attributes is going to be
448 modified
449 @param[in, out] Attributes On input, it is a pointer to EFI_FVB_ATTRIBUTES_2
450 containing the desired firmware volume settings.
451 On successful return, it contains the new settings
452 of the firmware volume
453
454 @retval EFI_SUCCESS Successfully returns
455 @retval EFI_ACCESS_DENIED The volume setting is locked and cannot be modified
456 @retval EFI_INVALID_PARAMETER Instance not found, or The attributes requested are
457 in conflict with the capabilities as declared in the
458 firmware volume header
459
460 **/
461 STATIC
462 EFI_STATUS
463 FvbSetVolumeAttributes (
464 IN UINTN Instance,
465 IN OUT EFI_FVB_ATTRIBUTES_2 *Attributes
466 )
467 {
468 EFI_FW_VOL_INSTANCE *FwhInstance;
469 EFI_FVB_ATTRIBUTES_2 OldAttributes;
470 EFI_FVB_ATTRIBUTES_2 *AttribPtr;
471 EFI_FVB_ATTRIBUTES_2 UnchangedAttributes;
472 UINT32 Capabilities;
473 UINT32 OldStatus;
474 UINT32 NewStatus;
475
476 //
477 // Find the right instance of the FVB private data
478 //
479 FwhInstance = GetFvbInstance (Instance);
480 if (FwhInstance == NULL) {
481 return EFI_INVALID_PARAMETER;
482 }
483
484 AttribPtr = (EFI_FVB_ATTRIBUTES_2 *)&(FwhInstance->VolumeHeader.Attributes);
485 ASSERT (AttribPtr != NULL);
486 if ( AttribPtr == NULL) {
487 return EFI_INVALID_PARAMETER;
488 }
489
490 OldAttributes = *AttribPtr;
491 Capabilities = OldAttributes & EFI_FVB2_CAPABILITIES;
492 OldStatus = OldAttributes & EFI_FVB2_STATUS;
493 NewStatus = *Attributes & EFI_FVB2_STATUS;
494
495 UnchangedAttributes = EFI_FVB2_READ_DISABLED_CAP | \
496 EFI_FVB2_READ_ENABLED_CAP | \
497 EFI_FVB2_WRITE_DISABLED_CAP | \
498 EFI_FVB2_WRITE_ENABLED_CAP | \
499 EFI_FVB2_LOCK_CAP | \
500 EFI_FVB2_STICKY_WRITE | \
501 EFI_FVB2_MEMORY_MAPPED | \
502 EFI_FVB2_ERASE_POLARITY | \
503 EFI_FVB2_READ_LOCK_CAP | \
504 EFI_FVB2_WRITE_LOCK_CAP | \
505 EFI_FVB2_ALIGNMENT;
506
507 //
508 // Some attributes of FV is read only can *not* be set
509 //
510 if ((OldAttributes & UnchangedAttributes) ^ (*Attributes & UnchangedAttributes)) {
511 return EFI_INVALID_PARAMETER;
512 }
513
514 //
515 // If firmware volume is locked, no status bit can be updated
516 //
517 if ((OldAttributes & EFI_FVB2_LOCK_STATUS) != 0) {
518 if ((OldStatus ^ NewStatus) != 0) {
519 return EFI_ACCESS_DENIED;
520 }
521 }
522
523 //
524 // Test read disable
525 //
526 if ((Capabilities & EFI_FVB2_READ_DISABLED_CAP) == 0) {
527 if ((NewStatus & EFI_FVB2_READ_STATUS) == 0) {
528 return EFI_INVALID_PARAMETER;
529 }
530 }
531
532 //
533 // Test read enable
534 //
535 if ((Capabilities & EFI_FVB2_READ_ENABLED_CAP) == 0) {
536 if ((NewStatus & EFI_FVB2_READ_STATUS) != 0) {
537 return EFI_INVALID_PARAMETER;
538 }
539 }
540
541 //
542 // Test write disable
543 //
544 if ((Capabilities & EFI_FVB2_WRITE_DISABLED_CAP) == 0) {
545 if ((NewStatus & EFI_FVB2_WRITE_STATUS) == 0) {
546 return EFI_INVALID_PARAMETER;
547 }
548 }
549
550 //
551 // Test write enable
552 //
553 if ((Capabilities & EFI_FVB2_WRITE_ENABLED_CAP) == 0) {
554 if ((NewStatus & EFI_FVB2_WRITE_STATUS) != 0) {
555 return EFI_INVALID_PARAMETER;
556 }
557 }
558
559 //
560 // Test lock
561 //
562 if ((Capabilities & EFI_FVB2_LOCK_CAP) == 0) {
563 if ((NewStatus & EFI_FVB2_LOCK_STATUS) != 0) {
564 return EFI_INVALID_PARAMETER;
565 }
566 }
567
568 *AttribPtr = (*AttribPtr) & (0xFFFFFFFF & (~EFI_FVB2_STATUS));
569 *AttribPtr = (*AttribPtr) | NewStatus;
570 *Attributes = *AttribPtr;
571
572 return EFI_SUCCESS;
573 }
574
575 /**
576 Retrieves the physical address of the device.
577
578 @param[in] This A pointer to EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL.
579 @param[out] Address Output buffer containing the address.
580
581 @retval EFI_SUCCESS The function always return successfully.
582 @retval EFI_INVALID_PARAMETER Instance not found.
583
584 **/
585 EFI_STATUS
586 EFIAPI
587 FvbProtocolGetPhysicalAddress (
588 IN CONST EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL *This,
589 OUT EFI_PHYSICAL_ADDRESS *Address
590 )
591 {
592 EFI_FW_VOL_BLOCK_DEVICE *FvbDevice;
593 EFI_FW_VOL_INSTANCE *FwhInstance;
594
595 FvbDevice = FVB_DEVICE_FROM_THIS (This);
596 FwhInstance = GetFvbInstance (FvbDevice->Instance);
597 if (FwhInstance == NULL) {
598 return EFI_INVALID_PARAMETER;
599 }
600
601 *Address = FwhInstance->FvBase;
602 return EFI_SUCCESS;
603 }
604
605 /**
606 Retrieve the size of a logical block
607
608 @param[in] This Calling context
609 @param[in] Lba Indicates which block to return the size for.
610 @param[out] BlockSize A pointer to a caller allocated UINTN in which
611 the size of the block is returned
612 @param[out] NumOfBlocks A pointer to a caller allocated UINTN in which the
613 number of consecutive blocks starting with Lba is
614 returned. All blocks in this range have a size of
615 BlockSize
616
617 @retval EFI_SUCCESS The function always return successfully.
618
619 **/
620 EFI_STATUS
621 EFIAPI
622 FvbProtocolGetBlockSize (
623 IN CONST EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL *This,
624 IN EFI_LBA Lba,
625 OUT UINTN *BlockSize,
626 OUT UINTN *NumOfBlocks
627 )
628 {
629 EFI_FW_VOL_BLOCK_DEVICE *FvbDevice;
630
631 FvbDevice = FVB_DEVICE_FROM_THIS (This);
632 return FvbGetLbaAddress (FvbDevice->Instance, Lba, NULL, BlockSize, NumOfBlocks);
633 }
634
635 /**
636 Retrieves Volume attributes. No polarity translations are done.
637
638 @param[in] This Calling context
639 @param[out] Attributes Output buffer which contains attributes
640
641 @retval EFI_SUCCESS The function always return successfully.
642
643 **/
644 EFI_STATUS
645 EFIAPI
646 FvbProtocolGetAttributes (
647 IN CONST EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL *This,
648 OUT EFI_FVB_ATTRIBUTES_2 *Attributes
649 )
650 {
651 EFI_FW_VOL_BLOCK_DEVICE *FvbDevice;
652
653 FvbDevice = FVB_DEVICE_FROM_THIS (This);
654 *Attributes = FvbGetVolumeAttributes (FvbDevice->Instance);
655
656 return EFI_SUCCESS;
657 }
658
659 /**
660 Sets Volume attributes. No polarity translations are done.
661
662 @param[in] This Calling context
663 @param[in, out] Attributes Output buffer which contains attributes
664
665 @retval EFI_SUCCESS The function always return successfully.
666
667 **/
668 EFI_STATUS
669 EFIAPI
670 FvbProtocolSetAttributes (
671 IN CONST EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL *This,
672 IN OUT EFI_FVB_ATTRIBUTES_2 *Attributes
673 )
674 {
675 EFI_STATUS Status;
676 EFI_FW_VOL_BLOCK_DEVICE *FvbDevice;
677
678 FvbDevice = FVB_DEVICE_FROM_THIS (This);
679 Status = FvbSetVolumeAttributes (FvbDevice->Instance, Attributes);
680 return Status;
681 }
682
683 /**
684 This function erases one or more blocks as denoted by the
685 variable argument list. The entire parameter list of blocks must be verified
686 prior to erasing any blocks. If a block is requested that does not exist
687 within the associated firmware volume (it has a larger index than the last
688 block of the firmware volume), the EraseBlock() function must return
689 EFI_INVALID_PARAMETER without modifying the contents of the firmware volume.
690
691 @param[in] This Calling context
692 @param[in] ... Starting LBA followed by Number of Lba to erase.
693 a -1 to terminate the list.
694
695 @retval EFI_SUCCESS The erase request was successfully completed
696 @retval EFI_ACCESS_DENIED The firmware volume is in the WriteDisabled state
697 @retval EFI_DEVICE_ERROR The block device is not functioning correctly and
698 could not be written. Firmware device may have been
699 partially erased
700
701 **/
702 EFI_STATUS
703 EFIAPI
704 FvbProtocolEraseBlocks (
705 IN CONST EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL *This,
706 ...
707 )
708 {
709 EFI_FW_VOL_BLOCK_DEVICE *FvbDevice;
710 EFI_FW_VOL_INSTANCE *FwhInstance;
711 UINTN NumOfBlocks;
712 VA_LIST args;
713 EFI_LBA StartingLba;
714 UINTN NumOfLba;
715 EFI_STATUS Status;
716
717 FvbDevice = FVB_DEVICE_FROM_THIS (This);
718 FwhInstance = GetFvbInstance (FvbDevice->Instance);
719 if (FwhInstance == NULL) {
720 return EFI_OUT_OF_RESOURCES;
721 }
722
723 NumOfBlocks = FwhInstance->NumOfBlocks;
724 VA_START (args, This);
725
726 do {
727 StartingLba = VA_ARG (args, EFI_LBA);
728 if ( StartingLba == EFI_LBA_LIST_TERMINATOR ) {
729 break;
730 }
731
732 NumOfLba = VA_ARG (args, UINT32);
733
734 //
735 // Check input parameters
736 //
737 if (NumOfLba == 0) {
738 VA_END (args);
739 return EFI_INVALID_PARAMETER;
740 }
741
742 if ((StartingLba + NumOfLba) > NumOfBlocks ) {
743 return EFI_INVALID_PARAMETER;
744 }
745 } while (1);
746
747 VA_END (args);
748
749 VA_START (args, This);
750 do {
751 StartingLba = VA_ARG (args, EFI_LBA);
752 if (StartingLba == EFI_LBA_LIST_TERMINATOR) {
753 break;
754 }
755
756 NumOfLba = VA_ARG (args, UINT32);
757
758 while ( NumOfLba > 0 ) {
759 Status = FvbEraseBlock (FvbDevice->Instance, StartingLba);
760 if ( EFI_ERROR (Status)) {
761 VA_END (args);
762 return Status;
763 }
764
765 StartingLba++;
766 NumOfLba--;
767 }
768 } while (1);
769
770 VA_END (args);
771
772 return EFI_SUCCESS;
773 }
774
775 /**
776 Writes data beginning at Lba:Offset from FV. The write terminates either
777 when *NumBytes of data have been written, or when a block boundary is
778 reached. *NumBytes is updated to reflect the actual number of bytes
779 written. The write opertion does not include erase. This routine will
780 attempt to write only the specified bytes. If the writes do not stick,
781 it will return an error.
782
783 @param[in] This Calling context
784 @param[in] Lba Block in which to begin write
785 @param[in] Offset Offset in the block at which to begin write
786 @param[in,out] NumBytes On input, indicates the requested write size. On
787 output, indicates the actual number of bytes written
788 @param[in] Buffer Buffer containing source data for the write.
789
790 @retval EFI_SUCCESS The firmware volume was written successfully
791 @retval EFI_BAD_BUFFER_SIZE Write attempted across a LBA boundary. On output,
792 NumBytes contains the total number of bytes
793 actually written
794 @retval EFI_ACCESS_DENIED The firmware volume is in the WriteDisabled state
795 @retval EFI_DEVICE_ERROR The block device is not functioning correctly and
796 could not be written
797 @retval EFI_INVALID_PARAMETER NumBytes or Buffer are NULL
798
799 **/
800 EFI_STATUS
801 EFIAPI
802 FvbProtocolWrite (
803 IN CONST EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL *This,
804 IN EFI_LBA Lba,
805 IN UINTN Offset,
806 IN OUT UINTN *NumBytes,
807 IN UINT8 *Buffer
808 )
809 {
810 EFI_FW_VOL_BLOCK_DEVICE *FvbDevice;
811 EFI_STATUS Status;
812
813 FvbDevice = FVB_DEVICE_FROM_THIS (This);
814 Status = FvbWriteBlock (FvbDevice->Instance, Lba, Offset, NumBytes, Buffer);
815 DEBUG ((
816 DEBUG_VERBOSE,
817 "FvbWrite: Lba: 0x%lx Offset: 0x%x NumBytes: 0x%x, Buffer: 0x%x Status:%r\n",
818 Lba,
819 Offset,
820 *NumBytes,
821 Buffer,
822 Status
823 ));
824
825 return Status;
826 }
827
828 /**
829 Reads data beginning at Lba:Offset from FV. The Read terminates either
830 when *NumBytes of data have been read, or when a block boundary is
831 reached. *NumBytes is updated to reflect the actual number of bytes
832 written. The write opertion does not include erase. This routine will
833 attempt to write only the specified bytes. If the writes do not stick,
834 it will return an error.
835
836 @param[in] This Calling context
837 @param[in] Lba Block in which to begin write
838 @param[in] Offset Offset in the block at which to begin write
839 @param[in,out] NumBytes On input, indicates the requested write size. On
840 output, indicates the actual number of bytes written
841 @param[out] Buffer Buffer containing source data for the write.
842
843
844 Returns:
845 @retval EFI_SUCCESS The firmware volume was read successfully and
846 contents are in Buffer
847 @retval EFI_BAD_BUFFER_SIZE Read attempted across a LBA boundary. On output,
848 NumBytes contains the total number of bytes returned
849 in Buffer
850 @retval EFI_ACCESS_DENIED The firmware volume is in the ReadDisabled state
851 @retval EFI_DEVICE_ERROR The block device is not functioning correctly and
852 could not be read
853 @retval EFI_INVALID_PARAMETER NumBytes or Buffer are NULL
854
855 **/
856 EFI_STATUS
857 EFIAPI
858 FvbProtocolRead (
859 IN CONST EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL *This,
860 IN EFI_LBA Lba,
861 IN UINTN Offset,
862 IN OUT UINTN *NumBytes,
863 OUT UINT8 *Buffer
864 )
865 {
866 EFI_FW_VOL_BLOCK_DEVICE *FvbDevice;
867 EFI_STATUS Status;
868
869 FvbDevice = FVB_DEVICE_FROM_THIS (This);
870 Status = FvbReadBlock (FvbDevice->Instance, Lba, Offset, NumBytes, Buffer);
871 DEBUG ((
872 DEBUG_VERBOSE,
873 "FvbRead: Lba: 0x%lx Offset: 0x%x NumBytes: 0x%x, Buffer: 0x%x, Status:%r\n",
874 Lba,
875 Offset,
876 *NumBytes,
877 Buffer,
878 Status
879 ));
880
881 return Status;
882 }
883
884 /**
885 Check the integrity of firmware volume header in FvBase
886
887 @param[in] FvBase A pointer to firmware volume base address.
888
889 @retval TRUE The firmware volume is consistent
890 @retval FALSE The firmware volume has corrupted.
891
892 **/
893 BOOLEAN
894 IsFvHeaderValid (
895 IN EFI_PHYSICAL_ADDRESS FvBase
896 )
897 {
898 UINT16 Sum;
899 EFI_FIRMWARE_VOLUME_HEADER *FwVolHeader;
900
901 FwVolHeader = (EFI_FIRMWARE_VOLUME_HEADER *)(UINTN)FvBase;
902 if (FvBase == PcdGet32 (PcdFlashNvStorageVariableBase)) {
903 if (CompareMem (&FwVolHeader->FileSystemGuid, &gEfiSystemNvDataFvGuid, sizeof (EFI_GUID)) != 0 ) {
904 DEBUG ((DEBUG_INFO, " --FileSystemGuid not match: %g\n", &FwVolHeader->FileSystemGuid));
905 return FALSE;
906 }
907 } else {
908 if (CompareMem (&FwVolHeader->FileSystemGuid, &gEfiFirmwareFileSystem2Guid, sizeof (EFI_GUID)) != 0 ) {
909 DEBUG ((DEBUG_INFO, " --not expected guid.\n"));
910 return FALSE;
911 }
912 }
913
914 if ((FwVolHeader->Revision != EFI_FVH_REVISION) ||
915 (FwVolHeader->Signature != EFI_FVH_SIGNATURE) ||
916 (FwVolHeader->FvLength == ((UINTN)-1)) ||
917 ((FwVolHeader->HeaderLength & 0x01) != 0))
918 {
919 DEBUG ((DEBUG_INFO, " -- >Revision = 0x%x, Signature = 0x%x\n", FwVolHeader->Revision, FwVolHeader->Signature));
920 DEBUG ((DEBUG_INFO, " -- >FvLength = 0x%lx, HeaderLength = 0x%x\n", FwVolHeader->FvLength, FwVolHeader->HeaderLength));
921 return FALSE;
922 }
923
924 Sum = CalculateSum16 ((UINT16 *)FwVolHeader, FwVolHeader->HeaderLength);
925 if (Sum != 0) {
926 DEBUG ((DEBUG_INFO, "error: checksum: 0x%04X (expect 0x0)\n", Sum));
927 return FALSE;
928 }
929
930 return TRUE;
931 }
932
933 /**
934 Get intial variable data.
935
936 @param[out] VarData Valid variable data.
937 @param[out] VarSize Valid variable size.
938
939 @retval RETURN_SUCCESS Successfully found initial variable data.
940 @retval RETURN_NOT_FOUND Failed to find the variable data file from FV.
941 @retval EFI_INVALID_PARAMETER VarData or VarSize is null.
942
943 **/
944 EFI_STATUS
945 GetInitialVariableData (
946 OUT VOID **VarData,
947 OUT UINTN *VarSize
948 )
949 {
950 EFI_STATUS Status;
951 VOID *ImageData;
952 UINTN ImageSize;
953 EFI_FIRMWARE_VOLUME_HEADER *FvHeader;
954 VARIABLE_STORE_HEADER *VariableStore;
955 AUTHENTICATED_VARIABLE_HEADER *Variable;
956 UINTN VariableSize;
957 UINTN VarEndAddr;
958
959 if ((VarData == NULL) || (VarSize == NULL)) {
960 return EFI_INVALID_PARAMETER;
961 }
962
963 Status = GetSectionFromAnyFv (PcdGetPtr (PcdNvsDataFile), EFI_SECTION_RAW, 0, &ImageData, &ImageSize);
964 if (EFI_ERROR (Status)) {
965 return Status;
966 }
967
968 FvHeader = (EFI_FIRMWARE_VOLUME_HEADER *)ImageData;
969 VariableStore = (VARIABLE_STORE_HEADER *)((UINT8 *)ImageData + FvHeader->HeaderLength);
970 VarEndAddr = (UINTN)VariableStore + VariableStore->Size;
971 Variable = (AUTHENTICATED_VARIABLE_HEADER *)HEADER_ALIGN (VariableStore + 1);
972 *VarData = (VOID *)Variable;
973 while (((UINTN)Variable < VarEndAddr)) {
974 if (Variable->StartId != VARIABLE_DATA) {
975 break;
976 }
977
978 VariableSize = sizeof (AUTHENTICATED_VARIABLE_HEADER) + Variable->DataSize + Variable->NameSize;
979 Variable = (AUTHENTICATED_VARIABLE_HEADER *)HEADER_ALIGN ((UINTN)Variable + VariableSize);
980 }
981
982 *VarSize = (UINTN)Variable - HEADER_ALIGN (VariableStore + 1);
983
984 return EFI_SUCCESS;
985 }
986
987 /**
988 The function does the necessary initialization work for
989 Firmware Volume Block Driver.
990
991 @retval EFI_SUCCESS This funtion always return EFI_SUCCESS.
992 It will ASSERT on errors.
993
994 **/
995 EFI_STATUS
996 FvbInitialize (
997 VOID
998 )
999 {
1000 EFI_FW_VOL_INSTANCE *FwVolInstance;
1001 EFI_FIRMWARE_VOLUME_HEADER *FvHeader;
1002 EFI_FV_BLOCK_MAP_ENTRY *BlockMap;
1003 EFI_PHYSICAL_ADDRESS BaseAddress;
1004 UINTN WriteAddr;
1005 EFI_STATUS Status;
1006 UINTN BufferSize;
1007 UINTN Length;
1008 VARIABLE_STORE_HEADER VariableStore;
1009 VOID *VarData;
1010
1011 InitVariableStore ();
1012 BaseAddress = PcdGet32 (PcdFlashNvStorageVariableBase);
1013 FvHeader = (EFI_FIRMWARE_VOLUME_HEADER *)(UINTN)BaseAddress;
1014
1015 //
1016 // Check FV header and variable store header
1017 //
1018 if (!IsFvHeaderValid (BaseAddress)) {
1019 //
1020 // Write back a healthy FV header
1021 //
1022 DEBUG ((DEBUG_ERROR, "Fvb: Writing back a healthy FV header: 0x%lx\n", BaseAddress));
1023 FvHeader = GetFvHeaderTemplate ();
1024 LibFvbFlashDeviceBlockLock ((UINTN)BaseAddress, FvHeader->BlockMap->Length, FALSE);
1025
1026 Status = LibFvbFlashDeviceBlockErase ((UINTN)BaseAddress, FvHeader->BlockMap->Length);
1027 ASSERT_EFI_ERROR (Status);
1028
1029 Length = FvHeader->HeaderLength;
1030 WriteAddr = (UINTN)BaseAddress;
1031 Status = LibFvbFlashDeviceWrite (WriteAddr, &Length, (UINT8 *)FvHeader);
1032 WriteAddr += Length;
1033 ASSERT_EFI_ERROR (Status);
1034
1035 //
1036 // Write back variable store header
1037 //
1038 VariableStore.Size = PcdGet32 (PcdFlashNvStorageVariableSize) - FvHeader->HeaderLength;
1039 VariableStore.Format = VARIABLE_STORE_FORMATTED;
1040 VariableStore.State = VARIABLE_STORE_HEALTHY;
1041 CopyGuid (&VariableStore.Signature, &gEfiAuthenticatedVariableGuid);
1042 BufferSize = sizeof (VARIABLE_STORE_HEADER);
1043 Status = LibFvbFlashDeviceWrite (WriteAddr, &BufferSize, (UINT8 *)&VariableStore);
1044 WriteAddr += BufferSize;
1045 ASSERT_EFI_ERROR (Status);
1046
1047 //
1048 // Write initial variable data if found
1049 //
1050 Status = GetInitialVariableData (&VarData, &Length);
1051 if (!EFI_ERROR (Status)) {
1052 Status = LibFvbFlashDeviceWrite (WriteAddr, &Length, (UINT8 *)VarData);
1053 ASSERT_EFI_ERROR (Status);
1054 }
1055
1056 LibFvbFlashDeviceBlockLock ((UINTN)BaseAddress, FvHeader->BlockMap->Length, TRUE);
1057 WriteBackInvalidateDataCacheRange ((VOID *)(UINTN)BaseAddress, FvHeader->BlockMap->Length);
1058 }
1059
1060 //
1061 // Create a new FW volume instance for NVS variable
1062 //
1063 BufferSize = FvHeader->HeaderLength + sizeof (EFI_FW_VOL_INSTANCE) - sizeof (EFI_FIRMWARE_VOLUME_HEADER);
1064 FwVolInstance = (EFI_FW_VOL_INSTANCE *)AllocateRuntimeZeroPool (BufferSize);
1065 if (FwVolInstance == NULL) {
1066 return EFI_OUT_OF_RESOURCES;
1067 }
1068
1069 FwVolInstance->FvBase = (UINTN)BaseAddress;
1070 CopyMem (&FwVolInstance->VolumeHeader, FvHeader, FvHeader->HeaderLength);
1071
1072 //
1073 // Process the block map for each FV. Assume it has same block size.
1074 //
1075 FwVolInstance->NumOfBlocks = 0;
1076 FvHeader = &FwVolInstance->VolumeHeader;
1077 for (BlockMap = FvHeader->BlockMap; BlockMap->NumBlocks != 0; BlockMap++) {
1078 FwVolInstance->NumOfBlocks += BlockMap->NumBlocks;
1079 }
1080
1081 //
1082 // Add a FVB Protocol Instance
1083 //
1084 Status = InstallFvbProtocol (FwVolInstance, mFvbModuleGlobal.NumFv);
1085 mFvbModuleGlobal.NumFv++;
1086 mFvbModuleGlobal.FvInstance = FwVolInstance;
1087
1088 return Status;
1089 }