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