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