]> git.proxmox.com Git - mirror_edk2.git/blob - EmulatorPkg/FvbServicesRuntimeDxe/FWBlockService.c
EmulatorPkg: Replace BSD License with BSD+Patent License
[mirror_edk2.git] / EmulatorPkg / FvbServicesRuntimeDxe / FWBlockService.c
1 /*++ @file
2
3 Copyright (c) 2006 - 2012, Intel Corporation. All rights reserved.<BR>
4 Portions copyright (c) 2011, Apple Inc. All rights reserved.
5 SPDX-License-Identifier: BSD-2-Clause-Patent
6
7 **/
8
9 #include "PiDxe.h"
10 #include <Guid/EventGroup.h>
11 #include <Protocol/FirmwareVolumeBlock.h>
12 #include <Protocol/DevicePath.h>
13
14 #include <Library/UefiLib.h>
15 #include <Library/UefiDriverEntryPoint.h>
16 #include <Library/BaseLib.h>
17 #include <Library/DxeServicesTableLib.h>
18 #include <Library/UefiRuntimeLib.h>
19 #include <Library/DebugLib.h>
20 #include <Library/HobLib.h>
21 #include <Library/BaseMemoryLib.h>
22 #include <Library/MemoryAllocationLib.h>
23 #include <Library/UefiBootServicesTableLib.h>
24 #include <Library/DevicePathLib.h>
25
26 #include "FwBlockService.h"
27
28 ESAL_FWB_GLOBAL *mFvbModuleGlobal;
29
30 #define EFI_FVB2_STATUS (EFI_FVB2_READ_STATUS | EFI_FVB2_WRITE_STATUS | EFI_FVB2_LOCK_STATUS)
31
32 EFI_FW_VOL_BLOCK_DEVICE mFvbDeviceTemplate = {
33 FVB_DEVICE_SIGNATURE,
34 {
35 {
36 {
37 HARDWARE_DEVICE_PATH,
38 HW_MEMMAP_DP,
39 {
40 sizeof (MEMMAP_DEVICE_PATH),
41 0
42 }
43 },
44 EfiMemoryMappedIO,
45 0,
46 0,
47 },
48 {
49 END_DEVICE_PATH_TYPE,
50 END_ENTIRE_DEVICE_PATH_SUBTYPE,
51 {
52 sizeof (EFI_DEVICE_PATH_PROTOCOL),
53 0
54 }
55 }
56 },
57 0,
58 {
59 FvbProtocolGetAttributes,
60 FvbProtocolSetAttributes,
61 FvbProtocolGetPhysicalAddress,
62 FvbProtocolGetBlockSize,
63 FvbProtocolRead,
64 FvbProtocolWrite,
65 FvbProtocolEraseBlocks,
66 NULL
67 }
68 };
69
70
71
72 VOID
73 EFIAPI
74 FvbVirtualddressChangeEvent (
75 IN EFI_EVENT Event,
76 IN VOID *Context
77 )
78 /*++
79
80 Routine Description:
81
82 Fixup internal data so that EFI and SAL can be call in virtual mode.
83 Call the passed in Child Notify event and convert the mFvbModuleGlobal
84 date items to there virtual address.
85
86 mFvbModuleGlobal->FvInstance[FVB_PHYSICAL] - Physical copy of instance data
87 mFvbModuleGlobal->FvInstance[FVB_VIRTUAL] - Virtual pointer to common
88 instance data.
89
90 Arguments:
91
92 (Standard EFI notify event - EFI_EVENT_NOTIFY)
93
94 Returns:
95
96 None
97
98 **/
99 {
100 EFI_FW_VOL_INSTANCE *FwhInstance;
101 UINTN Index;
102
103 EfiConvertPointer (0x0, (VOID **) &mFvbModuleGlobal->FvInstance[FVB_VIRTUAL]);
104
105 //
106 // Convert the base address of all the instances
107 //
108 Index = 0;
109 FwhInstance = mFvbModuleGlobal->FvInstance[FVB_PHYSICAL];
110 while (Index < mFvbModuleGlobal->NumFv) {
111 EfiConvertPointer (0x0, (VOID **) &FwhInstance->FvBase[FVB_VIRTUAL]);
112 FwhInstance = (EFI_FW_VOL_INSTANCE *)
113 (
114 (UINTN) ((UINT8 *) FwhInstance) + FwhInstance->VolumeHeader.HeaderLength +
115 (sizeof (EFI_FW_VOL_INSTANCE) - sizeof (EFI_FIRMWARE_VOLUME_HEADER))
116 );
117 Index++;
118 }
119
120 EfiConvertPointer (0x0, (VOID **) &mFvbModuleGlobal);
121 }
122
123 EFI_STATUS
124 GetFvbInstance (
125 IN UINTN Instance,
126 IN ESAL_FWB_GLOBAL *Global,
127 OUT EFI_FW_VOL_INSTANCE **FwhInstance,
128 IN BOOLEAN Virtual
129 )
130 /*++
131
132 Routine Description:
133 Retrieves the physical address of a memory mapped FV
134
135 Arguments:
136 Instance - The FV instance whose base address is going to be
137 returned
138 Global - Pointer to ESAL_FWB_GLOBAL that contains all
139 instance data
140 FwhInstance - The EFI_FW_VOL_INSTANCE fimrware instance structure
141 Virtual - Whether CPU is in virtual or physical mode
142
143 Returns:
144 EFI_SUCCESS - Successfully returns
145 EFI_INVALID_PARAMETER - Instance not found
146
147 **/
148 {
149 EFI_FW_VOL_INSTANCE *FwhRecord;
150
151 if (Instance >= Global->NumFv) {
152 return EFI_INVALID_PARAMETER;
153 }
154 //
155 // Find the right instance of the FVB private data
156 //
157 FwhRecord = Global->FvInstance[Virtual];
158 while (Instance > 0) {
159 FwhRecord = (EFI_FW_VOL_INSTANCE *)
160 (
161 (UINTN) ((UINT8 *) FwhRecord) + FwhRecord->VolumeHeader.HeaderLength +
162 (sizeof (EFI_FW_VOL_INSTANCE) - sizeof (EFI_FIRMWARE_VOLUME_HEADER))
163 );
164 Instance--;
165 }
166
167 *FwhInstance = FwhRecord;
168
169 return EFI_SUCCESS;
170 }
171
172 EFI_STATUS
173 FvbGetPhysicalAddress (
174 IN UINTN Instance,
175 OUT EFI_PHYSICAL_ADDRESS *Address,
176 IN ESAL_FWB_GLOBAL *Global,
177 IN BOOLEAN Virtual
178 )
179 /*++
180
181 Routine Description:
182 Retrieves the physical address of a memory mapped FV
183
184 Arguments:
185 Instance - The FV instance whose base address is going to be
186 returned
187 Address - Pointer to a caller allocated EFI_PHYSICAL_ADDRESS
188 that on successful return, contains the base address
189 of the firmware volume.
190 Global - Pointer to ESAL_FWB_GLOBAL that contains all
191 instance data
192 Virtual - Whether CPU is in virtual or physical mode
193
194 Returns:
195 EFI_SUCCESS - Successfully returns
196 EFI_INVALID_PARAMETER - Instance not found
197
198 **/
199 {
200 EFI_FW_VOL_INSTANCE *FwhInstance = NULL;
201 EFI_STATUS Status;
202
203 //
204 // Find the right instance of the FVB private data
205 //
206 Status = GetFvbInstance (Instance, Global, &FwhInstance, Virtual);
207 ASSERT_EFI_ERROR (Status);
208 *Address = FwhInstance->FvBase[Virtual];
209
210 return EFI_SUCCESS;
211 }
212
213 EFI_STATUS
214 FvbGetVolumeAttributes (
215 IN UINTN Instance,
216 OUT EFI_FVB_ATTRIBUTES_2 *Attributes,
217 IN ESAL_FWB_GLOBAL *Global,
218 IN BOOLEAN Virtual
219 )
220 /*++
221
222 Routine Description:
223 Retrieves attributes, insures positive polarity of attribute bits, returns
224 resulting attributes in output parameter
225
226 Arguments:
227 Instance - The FV instance whose attributes is going to be
228 returned
229 Attributes - Output buffer which contains attributes
230 Global - Pointer to ESAL_FWB_GLOBAL that contains all
231 instance data
232 Virtual - Whether CPU is in virtual or physical mode
233
234 Returns:
235 EFI_SUCCESS - Successfully returns
236 EFI_INVALID_PARAMETER - Instance not found
237
238 **/
239 {
240 EFI_FW_VOL_INSTANCE *FwhInstance = NULL;
241 EFI_STATUS Status;
242
243 //
244 // Find the right instance of the FVB private data
245 //
246 Status = GetFvbInstance (Instance, Global, &FwhInstance, Virtual);
247 ASSERT_EFI_ERROR (Status);
248 *Attributes = FwhInstance->VolumeHeader.Attributes;
249
250 return EFI_SUCCESS;
251 }
252
253 EFI_STATUS
254 FvbGetLbaAddress (
255 IN UINTN Instance,
256 IN EFI_LBA Lba,
257 OUT UINTN *LbaAddress,
258 OUT UINTN *LbaLength,
259 OUT UINTN *NumOfBlocks,
260 IN ESAL_FWB_GLOBAL *Global,
261 IN BOOLEAN Virtual
262 )
263 /*++
264
265 Routine Description:
266 Retrieves the starting address of an LBA in an FV
267
268 Arguments:
269 Instance - The FV instance which the Lba belongs to
270 Lba - The logical block address
271 LbaAddress - On output, contains the physical starting address
272 of the Lba
273 LbaLength - On output, contains the length of the block
274 NumOfBlocks - A pointer to a caller allocated UINTN in which the
275 number of consecutive blocks starting with Lba is
276 returned. All blocks in this range have a size of
277 BlockSize
278 Global - Pointer to ESAL_FWB_GLOBAL that contains all
279 instance data
280 Virtual - Whether CPU is in virtual or physical mode
281
282 Returns:
283 EFI_SUCCESS - Successfully returns
284 EFI_INVALID_PARAMETER - Instance not found
285
286 **/
287 {
288 UINT32 NumBlocks;
289 UINT32 BlockLength;
290 UINTN Offset;
291 EFI_LBA StartLba;
292 EFI_LBA NextLba;
293 EFI_FW_VOL_INSTANCE *FwhInstance = NULL;
294 EFI_FV_BLOCK_MAP_ENTRY *BlockMap;
295 EFI_STATUS Status;
296
297 //
298 // Find the right instance of the FVB private data
299 //
300 Status = GetFvbInstance (Instance, Global, &FwhInstance, Virtual);
301 ASSERT_EFI_ERROR (Status);
302
303 StartLba = 0;
304 Offset = 0;
305 BlockMap = &(FwhInstance->VolumeHeader.BlockMap[0]);
306
307 //
308 // Parse the blockmap of the FV to find which map entry the Lba belongs to
309 //
310 while (TRUE) {
311 NumBlocks = BlockMap->NumBlocks;
312 BlockLength = BlockMap->Length;
313
314 if (NumBlocks == 0 || BlockLength == 0) {
315 return EFI_INVALID_PARAMETER;
316 }
317
318 NextLba = StartLba + NumBlocks;
319
320 //
321 // The map entry found
322 //
323 if (Lba >= StartLba && Lba < NextLba) {
324 Offset = Offset + (UINTN) MultU64x32 ((Lba - StartLba), BlockLength);
325 if (LbaAddress != NULL) {
326 *LbaAddress = FwhInstance->FvBase[Virtual] + Offset;
327 }
328
329 if (LbaLength != NULL) {
330 *LbaLength = BlockLength;
331 }
332
333 if (NumOfBlocks != NULL) {
334 *NumOfBlocks = (UINTN) (NextLba - Lba);
335 }
336
337 return EFI_SUCCESS;
338 }
339
340 StartLba = NextLba;
341 Offset = Offset + NumBlocks * BlockLength;
342 BlockMap++;
343 }
344 }
345
346 EFI_STATUS
347 FvbReadBlock (
348 IN UINTN Instance,
349 IN EFI_LBA Lba,
350 IN UINTN BlockOffset,
351 IN OUT UINTN *NumBytes,
352 IN UINT8 *Buffer,
353 IN ESAL_FWB_GLOBAL *Global,
354 IN BOOLEAN Virtual
355 )
356 /*++
357
358 Routine Description:
359 Reads specified number of bytes into a buffer from the specified block
360
361 Arguments:
362 Instance - The FV instance to be read from
363 Lba - The logical block address to be read from
364 BlockOffset - Offset into the block at which to begin reading
365 NumBytes - Pointer that on input contains the total size of
366 the buffer. On output, it contains the total number
367 of bytes read
368 Buffer - Pointer to a caller allocated buffer that will be
369 used to hold the data read
370 Global - Pointer to ESAL_FWB_GLOBAL that contains all
371 instance data
372 Virtual - Whether CPU is in virtual or physical mode
373
374 Returns:
375 EFI_SUCCESS - The firmware volume was read successfully and
376 contents are in Buffer
377 EFI_BAD_BUFFER_SIZE - Read attempted across a LBA boundary. On output,
378 NumBytes contains the total number of bytes returned
379 in Buffer
380 EFI_ACCESS_DENIED - The firmware volume is in the ReadDisabled state
381 EFI_DEVICE_ERROR - The block device is not functioning correctly and
382 could not be read
383 EFI_INVALID_PARAMETER - Instance not found, or NumBytes, Buffer are NULL
384
385 **/
386 {
387 EFI_FVB_ATTRIBUTES_2 Attributes;
388 UINTN LbaAddress;
389 UINTN LbaLength;
390 EFI_STATUS Status;
391
392 //
393 // Check for invalid conditions
394 //
395 if ((NumBytes == NULL) || (Buffer == NULL)) {
396 return EFI_INVALID_PARAMETER;
397 }
398
399 if (*NumBytes == 0) {
400 return EFI_INVALID_PARAMETER;
401 }
402
403 Status = FvbGetLbaAddress (Instance, Lba, &LbaAddress, &LbaLength, NULL, Global, Virtual);
404 if (EFI_ERROR (Status)) {
405 return Status;
406 }
407 //
408 // Check if the FV is read enabled
409 //
410 FvbGetVolumeAttributes (Instance, &Attributes, Global, Virtual);
411
412 if ((Attributes & EFI_FVB2_READ_STATUS) == 0) {
413 return EFI_ACCESS_DENIED;
414 }
415 //
416 // Perform boundary checks and adjust NumBytes
417 //
418 if (BlockOffset > LbaLength) {
419 return EFI_INVALID_PARAMETER;
420 }
421
422 if (LbaLength < (*NumBytes + BlockOffset)) {
423 *NumBytes = (UINT32) (LbaLength - BlockOffset);
424 Status = EFI_BAD_BUFFER_SIZE;
425 }
426
427 CopyMem (Buffer, (UINT8 *) (LbaAddress + BlockOffset), (UINTN) (*NumBytes));
428
429 return Status;
430 }
431
432 EFI_STATUS
433 FvbWriteBlock (
434 IN UINTN Instance,
435 IN EFI_LBA Lba,
436 IN UINTN BlockOffset,
437 IN OUT UINTN *NumBytes,
438 IN UINT8 *Buffer,
439 IN ESAL_FWB_GLOBAL *Global,
440 IN BOOLEAN Virtual
441 )
442 /*++
443
444 Routine Description:
445 Writes specified number of bytes from the input buffer to the block
446
447 Arguments:
448 Instance - The FV instance to be written to
449 Lba - The starting logical block index to write to
450 BlockOffset - Offset into the block at which to begin writing
451 NumBytes - Pointer that on input contains the total size of
452 the buffer. On output, it contains the total number
453 of bytes actually written
454 Buffer - Pointer to a caller allocated buffer that contains
455 the source for the write
456 Global - Pointer to ESAL_FWB_GLOBAL that contains all
457 instance data
458 Virtual - Whether CPU is in virtual or physical mode
459
460 Returns:
461 EFI_SUCCESS - The firmware volume was written successfully
462 EFI_BAD_BUFFER_SIZE - Write attempted across a LBA boundary. On output,
463 NumBytes contains the total number of bytes
464 actually written
465 EFI_ACCESS_DENIED - The firmware volume is in the WriteDisabled state
466 EFI_DEVICE_ERROR - The block device is not functioning correctly and
467 could not be written
468 EFI_INVALID_PARAMETER - Instance not found, or NumBytes, Buffer are NULL
469
470 **/
471 {
472 EFI_FVB_ATTRIBUTES_2 Attributes;
473 UINTN LbaAddress;
474 UINTN LbaLength;
475 EFI_STATUS Status;
476
477 //
478 // Check for invalid conditions
479 //
480 if ((NumBytes == NULL) || (Buffer == NULL)) {
481 return EFI_INVALID_PARAMETER;
482 }
483
484 if (*NumBytes == 0) {
485 return EFI_INVALID_PARAMETER;
486 }
487
488 Status = FvbGetLbaAddress (Instance, Lba, &LbaAddress, &LbaLength, NULL, Global, Virtual);
489 if (EFI_ERROR (Status)) {
490 return Status;
491 }
492 //
493 // Check if the FV is write enabled
494 //
495 FvbGetVolumeAttributes (Instance, &Attributes, Global, Virtual);
496
497 if ((Attributes & EFI_FVB2_WRITE_STATUS) == 0) {
498 return EFI_ACCESS_DENIED;
499 }
500 //
501 // Perform boundary checks and adjust NumBytes
502 //
503 if (BlockOffset > LbaLength) {
504 return EFI_INVALID_PARAMETER;
505 }
506
507 if (LbaLength < (*NumBytes + BlockOffset)) {
508 *NumBytes = (UINT32) (LbaLength - BlockOffset);
509 Status = EFI_BAD_BUFFER_SIZE;
510 }
511 //
512 // Write data
513 //
514 CopyMem ((UINT8 *) (LbaAddress + BlockOffset), Buffer, (UINTN) (*NumBytes));
515
516 return Status;
517 }
518
519 EFI_STATUS
520 FvbEraseBlock (
521 IN UINTN Instance,
522 IN EFI_LBA Lba,
523 IN ESAL_FWB_GLOBAL *Global,
524 IN BOOLEAN Virtual
525 )
526 /*++
527
528 Routine Description:
529 Erases and initializes a firmware volume block
530
531 Arguments:
532 Instance - The FV instance to be erased
533 Lba - The logical block index to be erased
534 Global - Pointer to ESAL_FWB_GLOBAL that contains all
535 instance data
536 Virtual - Whether CPU is in virtual or physical mode
537
538 Returns:
539 EFI_SUCCESS - The erase request was successfully completed
540 EFI_ACCESS_DENIED - The firmware volume is in the WriteDisabled state
541 EFI_DEVICE_ERROR - The block device is not functioning correctly and
542 could not be written. Firmware device may have been
543 partially erased
544 EFI_INVALID_PARAMETER - Instance not found
545
546 **/
547 {
548
549 EFI_FVB_ATTRIBUTES_2 Attributes;
550 UINTN LbaAddress;
551 UINTN LbaLength;
552 EFI_STATUS Status;
553 UINT8 Data;
554
555 //
556 // Check if the FV is write enabled
557 //
558 FvbGetVolumeAttributes (Instance, &Attributes, Global, Virtual);
559
560 if ((Attributes & EFI_FVB2_WRITE_STATUS) == 0) {
561 return EFI_ACCESS_DENIED;
562 }
563 //
564 // Get the starting address of the block for erase.
565 //
566 Status = FvbGetLbaAddress (Instance, Lba, &LbaAddress, &LbaLength, NULL, Global, Virtual);
567
568 if (EFI_ERROR (Status)) {
569 return Status;
570 }
571
572 if ((Attributes & EFI_FVB2_ERASE_POLARITY) != 0) {
573 Data = 0xFF;
574 } else {
575 Data = 0x0;
576 }
577
578 SetMem ((UINT8 *) LbaAddress, LbaLength, Data);
579
580 return EFI_SUCCESS;
581 }
582
583 EFI_STATUS
584 FvbSetVolumeAttributes (
585 IN UINTN Instance,
586 IN OUT EFI_FVB_ATTRIBUTES_2 *Attributes,
587 IN ESAL_FWB_GLOBAL *Global,
588 IN BOOLEAN Virtual
589 )
590 /*++
591
592 Routine Description:
593 Modifies the current settings of the firmware volume according to the
594 input parameter, and returns the new setting of the volume
595
596 Arguments:
597 Instance - The FV instance whose attributes is going to be
598 modified
599 Attributes - On input, it is a pointer to EFI_FVB_ATTRIBUTES_2
600 containing the desired firmware volume settings.
601 On successful return, it contains the new settings
602 of the firmware volume
603 Global - Pointer to ESAL_FWB_GLOBAL that contains all
604 instance data
605 Virtual - Whether CPU is in virtual or physical mode
606
607 Returns:
608 EFI_SUCCESS - Successfully returns
609 EFI_ACCESS_DENIED - The volume setting is locked and cannot be modified
610 EFI_INVALID_PARAMETER - Instance not found, or The attributes requested are
611 in conflict with the capabilities as declared in the
612 firmware volume header
613
614 **/
615 {
616 EFI_FW_VOL_INSTANCE *FwhInstance = NULL;
617 EFI_FVB_ATTRIBUTES_2 OldAttributes;
618 EFI_FVB_ATTRIBUTES_2 *AttribPtr;
619 UINT32 Capabilities;
620 UINT32 OldStatus;
621 UINT32 NewStatus;
622 EFI_STATUS Status;
623 EFI_FVB_ATTRIBUTES_2 UnchangedAttributes;
624
625
626 //
627 // Find the right instance of the FVB private data
628 //
629 Status = GetFvbInstance (Instance, Global, &FwhInstance, Virtual);
630 ASSERT_EFI_ERROR (Status);
631
632 AttribPtr = (EFI_FVB_ATTRIBUTES_2 *) &(FwhInstance->VolumeHeader.Attributes);
633 OldAttributes = *AttribPtr;
634 Capabilities = OldAttributes & (EFI_FVB2_READ_DISABLED_CAP | \
635 EFI_FVB2_READ_ENABLED_CAP | \
636 EFI_FVB2_WRITE_DISABLED_CAP | \
637 EFI_FVB2_WRITE_ENABLED_CAP | \
638 EFI_FVB2_LOCK_CAP \
639 );
640
641 OldStatus = OldAttributes & EFI_FVB2_STATUS;
642 NewStatus = *Attributes & EFI_FVB2_STATUS;
643 UnchangedAttributes = EFI_FVB2_READ_DISABLED_CAP | \
644 EFI_FVB2_READ_ENABLED_CAP | \
645 EFI_FVB2_WRITE_DISABLED_CAP | \
646 EFI_FVB2_WRITE_ENABLED_CAP | \
647 EFI_FVB2_LOCK_CAP | \
648 EFI_FVB2_STICKY_WRITE | \
649 EFI_FVB2_MEMORY_MAPPED | \
650 EFI_FVB2_ERASE_POLARITY | \
651 EFI_FVB2_READ_LOCK_CAP | \
652 EFI_FVB2_WRITE_LOCK_CAP | \
653 EFI_FVB2_ALIGNMENT;
654
655 //
656 // Some attributes of FV is read only can *not* be set
657 //
658 if ((OldAttributes & UnchangedAttributes) ^ (*Attributes & UnchangedAttributes)) {
659 return EFI_INVALID_PARAMETER;
660 }
661
662 //
663 // If firmware volume is locked, no status bit can be updated
664 //
665 if (OldAttributes & EFI_FVB2_LOCK_STATUS) {
666 if (OldStatus ^ NewStatus) {
667 return EFI_ACCESS_DENIED;
668 }
669 }
670 //
671 // Test read disable
672 //
673 if ((Capabilities & EFI_FVB2_READ_DISABLED_CAP) == 0) {
674 if ((NewStatus & EFI_FVB2_READ_STATUS) == 0) {
675 return EFI_INVALID_PARAMETER;
676 }
677 }
678 //
679 // Test read enable
680 //
681 if ((Capabilities & EFI_FVB2_READ_ENABLED_CAP) == 0) {
682 if (NewStatus & EFI_FVB2_READ_STATUS) {
683 return EFI_INVALID_PARAMETER;
684 }
685 }
686 //
687 // Test write disable
688 //
689 if ((Capabilities & EFI_FVB2_WRITE_DISABLED_CAP) == 0) {
690 if ((NewStatus & EFI_FVB2_WRITE_STATUS) == 0) {
691 return EFI_INVALID_PARAMETER;
692 }
693 }
694 //
695 // Test write enable
696 //
697 if ((Capabilities & EFI_FVB2_WRITE_ENABLED_CAP) == 0) {
698 if (NewStatus & EFI_FVB2_WRITE_STATUS) {
699 return EFI_INVALID_PARAMETER;
700 }
701 }
702 //
703 // Test lock
704 //
705 if ((Capabilities & EFI_FVB2_LOCK_CAP) == 0) {
706 if (NewStatus & EFI_FVB2_LOCK_STATUS) {
707 return EFI_INVALID_PARAMETER;
708 }
709 }
710
711 *AttribPtr = (*AttribPtr) & (0xFFFFFFFF & (~EFI_FVB2_STATUS));
712 *AttribPtr = (*AttribPtr) | NewStatus;
713 *Attributes = *AttribPtr;
714
715 return EFI_SUCCESS;
716 }
717 //
718 // FVB protocol APIs
719 //
720 EFI_STATUS
721 EFIAPI
722 FvbProtocolGetPhysicalAddress (
723 IN CONST EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL *This,
724 OUT EFI_PHYSICAL_ADDRESS *Address
725 )
726 /*++
727
728 Routine Description:
729
730 Retrieves the physical address of the device.
731
732 Arguments:
733
734 This - Calling context
735 Address - Output buffer containing the address.
736
737 Returns:
738
739 Returns:
740 EFI_SUCCESS - Successfully returns
741
742 **/
743 {
744 EFI_FW_VOL_BLOCK_DEVICE *FvbDevice;
745
746 FvbDevice = FVB_DEVICE_FROM_THIS (This);
747
748 return FvbGetPhysicalAddress (FvbDevice->Instance, Address, mFvbModuleGlobal, EfiGoneVirtual ());
749 }
750
751 EFI_STATUS
752 EFIAPI
753 FvbProtocolGetBlockSize (
754 IN CONST EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL *This,
755 IN EFI_LBA Lba,
756 OUT UINTN *BlockSize,
757 OUT UINTN *NumOfBlocks
758 )
759 /*++
760
761 Routine Description:
762 Retrieve the size of a logical block
763
764 Arguments:
765 This - Calling context
766 Lba - Indicates which block to return the size for.
767 BlockSize - A pointer to a caller allocated UINTN in which
768 the size of the block is returned
769 NumOfBlocks - a pointer to a caller allocated UINTN in which the
770 number of consecutive blocks starting with Lba is
771 returned. All blocks in this range have a size of
772 BlockSize
773
774 Returns:
775 EFI_SUCCESS - The firmware volume was read successfully and
776 contents are in Buffer
777
778 **/
779 {
780 EFI_FW_VOL_BLOCK_DEVICE *FvbDevice;
781
782 FvbDevice = FVB_DEVICE_FROM_THIS (This);
783
784 return FvbGetLbaAddress (
785 FvbDevice->Instance,
786 Lba,
787 NULL,
788 BlockSize,
789 NumOfBlocks,
790 mFvbModuleGlobal,
791 EfiGoneVirtual ()
792 );
793 }
794
795 EFI_STATUS
796 EFIAPI
797 FvbProtocolGetAttributes (
798 IN CONST EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL *This,
799 OUT EFI_FVB_ATTRIBUTES_2 *Attributes
800 )
801 /*++
802
803 Routine Description:
804 Retrieves Volume attributes. No polarity translations are done.
805
806 Arguments:
807 This - Calling context
808 Attributes - output buffer which contains attributes
809
810 Returns:
811 EFI_SUCCESS - Successfully returns
812
813 **/
814 {
815 EFI_FW_VOL_BLOCK_DEVICE *FvbDevice;
816
817 FvbDevice = FVB_DEVICE_FROM_THIS (This);
818
819 return FvbGetVolumeAttributes (FvbDevice->Instance, Attributes, mFvbModuleGlobal, EfiGoneVirtual ());
820 }
821
822 EFI_STATUS
823 EFIAPI
824 FvbProtocolSetAttributes (
825 IN CONST EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL *This,
826 IN OUT EFI_FVB_ATTRIBUTES_2 *Attributes
827 )
828 /*++
829
830 Routine Description:
831 Sets Volume attributes. No polarity translations are done.
832
833 Arguments:
834 This - Calling context
835 Attributes - output buffer which contains attributes
836
837 Returns:
838 EFI_SUCCESS - Successfully returns
839
840 **/
841 {
842 EFI_FW_VOL_BLOCK_DEVICE *FvbDevice;
843
844 FvbDevice = FVB_DEVICE_FROM_THIS (This);
845
846 return FvbSetVolumeAttributes (FvbDevice->Instance, Attributes, mFvbModuleGlobal, EfiGoneVirtual ());
847 }
848
849 EFI_STATUS
850 EFIAPI
851 FvbProtocolEraseBlocks (
852 IN CONST EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL *This,
853 ...
854 )
855 /*++
856
857 Routine Description:
858
859 The EraseBlock() function erases one or more blocks as denoted by the
860 variable argument list. The entire parameter list of blocks must be verified
861 prior to erasing any blocks. If a block is requested that does not exist
862 within the associated firmware volume (it has a larger index than the last
863 block of the firmware volume), the EraseBlock() function must return
864 EFI_INVALID_PARAMETER without modifying the contents of the firmware volume.
865
866 Arguments:
867 This - Calling context
868 ... - Starting LBA followed by Number of Lba to erase.
869 a -1 to terminate the list.
870
871 Returns:
872 EFI_SUCCESS - The erase request was successfully completed
873 EFI_ACCESS_DENIED - The firmware volume is in the WriteDisabled state
874 EFI_DEVICE_ERROR - The block device is not functioning correctly and
875 could not be written. Firmware device may have been
876 partially erased
877
878 **/
879 {
880 EFI_FW_VOL_BLOCK_DEVICE *FvbDevice;
881 EFI_FW_VOL_INSTANCE *FwhInstance = NULL;
882 UINTN NumOfBlocks;
883 VA_LIST args;
884 EFI_LBA StartingLba;
885 UINTN NumOfLba;
886 EFI_STATUS Status;
887
888 FvbDevice = FVB_DEVICE_FROM_THIS (This);
889
890 Status = GetFvbInstance (FvbDevice->Instance, mFvbModuleGlobal, &FwhInstance, EfiGoneVirtual ());
891 ASSERT_EFI_ERROR (Status);
892
893 NumOfBlocks = FwhInstance->NumOfBlocks;
894
895 VA_START (args, This);
896
897 do {
898 StartingLba = VA_ARG (args, EFI_LBA);
899 if (StartingLba == EFI_LBA_LIST_TERMINATOR) {
900 break;
901 }
902
903 NumOfLba = VA_ARG (args, UINTN);
904
905 //
906 // Check input parameters
907 //
908 if (NumOfLba == 0 || (StartingLba + NumOfLba) > NumOfBlocks) {
909 VA_END (args);
910 return EFI_INVALID_PARAMETER;
911 }
912 } while (1);
913
914 VA_END (args);
915
916 VA_START (args, This);
917 do {
918 StartingLba = VA_ARG (args, EFI_LBA);
919 if (StartingLba == EFI_LBA_LIST_TERMINATOR) {
920 break;
921 }
922
923 NumOfLba = VA_ARG (args, UINTN);
924
925 while (NumOfLba > 0) {
926 Status = FvbEraseBlock (FvbDevice->Instance, StartingLba, mFvbModuleGlobal, EfiGoneVirtual ());
927 if (EFI_ERROR (Status)) {
928 VA_END (args);
929 return Status;
930 }
931
932 StartingLba++;
933 NumOfLba--;
934 }
935
936 } while (1);
937
938 VA_END (args);
939
940 return EFI_SUCCESS;
941 }
942
943 EFI_STATUS
944 EFIAPI
945 FvbProtocolWrite (
946 IN CONST EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL *This,
947 IN EFI_LBA Lba,
948 IN UINTN Offset,
949 IN OUT UINTN *NumBytes,
950 IN UINT8 *Buffer
951 )
952 /*++
953
954 Routine Description:
955
956 Writes data beginning at Lba:Offset from FV. The write terminates either
957 when *NumBytes of data have been written, or when a block boundary is
958 reached. *NumBytes is updated to reflect the actual number of bytes
959 written. The write opertion does not include erase. This routine will
960 attempt to write only the specified bytes. If the writes do not stick,
961 it will return an error.
962
963 Arguments:
964 This - Calling context
965 Lba - Block in which to begin write
966 Offset - Offset in the block at which to begin write
967 NumBytes - On input, indicates the requested write size. On
968 output, indicates the actual number of bytes written
969 Buffer - Buffer containing source data for the write.
970
971 Returns:
972 EFI_SUCCESS - The firmware volume was written successfully
973 EFI_BAD_BUFFER_SIZE - Write attempted across a LBA boundary. On output,
974 NumBytes contains the total number of bytes
975 actually written
976 EFI_ACCESS_DENIED - The firmware volume is in the WriteDisabled state
977 EFI_DEVICE_ERROR - The block device is not functioning correctly and
978 could not be written
979 EFI_INVALID_PARAMETER - NumBytes or Buffer are NULL
980
981 **/
982 {
983
984 EFI_FW_VOL_BLOCK_DEVICE *FvbDevice;
985
986 FvbDevice = FVB_DEVICE_FROM_THIS (This);
987
988 return FvbWriteBlock (FvbDevice->Instance, Lba, Offset, NumBytes, Buffer, mFvbModuleGlobal, EfiGoneVirtual ());
989 }
990
991 EFI_STATUS
992 EFIAPI
993 FvbProtocolRead (
994 IN CONST EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL *This,
995 IN EFI_LBA Lba,
996 IN UINTN Offset,
997 IN OUT UINTN *NumBytes,
998 IN UINT8 *Buffer
999 )
1000 /*++
1001
1002 Routine Description:
1003
1004 Reads data beginning at Lba:Offset from FV. The Read terminates either
1005 when *NumBytes of data have been read, or when a block boundary is
1006 reached. *NumBytes is updated to reflect the actual number of bytes
1007 written. The write opertion does not include erase. This routine will
1008 attempt to write only the specified bytes. If the writes do not stick,
1009 it will return an error.
1010
1011 Arguments:
1012 This - Calling context
1013 Lba - Block in which to begin Read
1014 Offset - Offset in the block at which to begin Read
1015 NumBytes - On input, indicates the requested write size. On
1016 output, indicates the actual number of bytes Read
1017 Buffer - Buffer containing source data for the Read.
1018
1019 Returns:
1020 EFI_SUCCESS - The firmware volume was read successfully and
1021 contents are in Buffer
1022 EFI_BAD_BUFFER_SIZE - Read attempted across a LBA boundary. On output,
1023 NumBytes contains the total number of bytes returned
1024 in Buffer
1025 EFI_ACCESS_DENIED - The firmware volume is in the ReadDisabled state
1026 EFI_DEVICE_ERROR - The block device is not functioning correctly and
1027 could not be read
1028 EFI_INVALID_PARAMETER - NumBytes or Buffer are NULL
1029
1030 **/
1031 {
1032
1033 EFI_FW_VOL_BLOCK_DEVICE *FvbDevice;
1034
1035 FvbDevice = FVB_DEVICE_FROM_THIS (This);
1036
1037 return FvbReadBlock (FvbDevice->Instance, Lba, Offset, NumBytes, Buffer, mFvbModuleGlobal, EfiGoneVirtual ());
1038 }
1039 EFI_STATUS
1040 ValidateFvHeader (
1041 EFI_FIRMWARE_VOLUME_HEADER *FwVolHeader
1042 )
1043 /*++
1044
1045 Routine Description:
1046 Check the integrity of firmware volume header
1047
1048 Arguments:
1049 FwVolHeader - A pointer to a firmware volume header
1050
1051 Returns:
1052 EFI_SUCCESS - The firmware volume is consistent
1053 EFI_NOT_FOUND - The firmware volume has corrupted. So it is not an FV
1054
1055 **/
1056 {
1057 UINT16 *Ptr;
1058 UINT16 HeaderLength;
1059 UINT16 Checksum;
1060
1061 //
1062 // Verify the header revision, header signature, length
1063 // Length of FvBlock cannot be 2**64-1
1064 // HeaderLength cannot be an odd number
1065 //
1066 if ((FwVolHeader->Revision != EFI_FVH_REVISION) ||
1067 (FwVolHeader->Signature != EFI_FVH_SIGNATURE) ||
1068 (FwVolHeader->FvLength == ((UINTN) -1)) ||
1069 ((FwVolHeader->HeaderLength & 0x01) != 0)
1070 ) {
1071 return EFI_NOT_FOUND;
1072 }
1073 //
1074 // Verify the header checksum
1075 //
1076 HeaderLength = (UINT16) (FwVolHeader->HeaderLength / 2);
1077 Ptr = (UINT16 *) FwVolHeader;
1078 Checksum = 0;
1079 while (HeaderLength > 0) {
1080 Checksum = Checksum + (*Ptr);
1081 HeaderLength--;
1082 Ptr++;
1083 }
1084
1085 if (Checksum != 0) {
1086 return EFI_NOT_FOUND;
1087 }
1088
1089 return EFI_SUCCESS;
1090 }
1091
1092 EFI_STATUS
1093 EFIAPI
1094 FvbInitialize (
1095 IN EFI_HANDLE ImageHandle,
1096 IN EFI_SYSTEM_TABLE *SystemTable
1097 )
1098 /*++
1099
1100 Routine Description:
1101 This function does common initialization for FVB services
1102
1103 Arguments:
1104
1105 Returns:
1106
1107 **/
1108 {
1109 EFI_STATUS Status;
1110 EFI_FW_VOL_INSTANCE *FwhInstance = NULL;
1111 EFI_FIRMWARE_VOLUME_HEADER *FwVolHeader;
1112 EFI_DXE_SERVICES *DxeServices;
1113 EFI_GCD_MEMORY_SPACE_DESCRIPTOR Descriptor;
1114 UINT32 BufferSize;
1115 EFI_FV_BLOCK_MAP_ENTRY *PtrBlockMapEntry;
1116 EFI_HANDLE FwbHandle;
1117 EFI_FW_VOL_BLOCK_DEVICE *FvbDevice;
1118 EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL *OldFwbInterface;
1119 EFI_DEVICE_PATH_PROTOCOL *TempFwbDevicePath;
1120 FV_DEVICE_PATH TempFvbDevicePathData;
1121 UINT32 MaxLbaSize;
1122 EFI_PHYSICAL_ADDRESS BaseAddress;
1123 UINT64 Length;
1124 UINTN NumOfBlocks;
1125 EFI_PEI_HOB_POINTERS FvHob;
1126
1127 //
1128 // Get the DXE services table
1129 //
1130 DxeServices = gDS;
1131
1132 //
1133 // Allocate runtime services data for global variable, which contains
1134 // the private data of all firmware volume block instances
1135 //
1136 Status = gBS->AllocatePool (
1137 EfiRuntimeServicesData,
1138 sizeof (ESAL_FWB_GLOBAL),
1139 (VOID**) &mFvbModuleGlobal
1140 );
1141 ASSERT_EFI_ERROR (Status);
1142
1143 //
1144 // Calculate the total size for all firmware volume block instances
1145 //
1146 BufferSize = 0;
1147
1148 FvHob.Raw = GetHobList ();
1149 while ((FvHob.Raw = GetNextHob (EFI_HOB_TYPE_FV, FvHob.Raw)) != NULL) {
1150 BaseAddress = FvHob.FirmwareVolume->BaseAddress;
1151 Length = FvHob.FirmwareVolume->Length;
1152 //
1153 // Check if it is a "real" flash
1154 //
1155 Status = DxeServices->GetMemorySpaceDescriptor (
1156 BaseAddress,
1157 &Descriptor
1158 );
1159 if (EFI_ERROR (Status)) {
1160 break;
1161 }
1162
1163 if (Descriptor.GcdMemoryType != EfiGcdMemoryTypeMemoryMappedIo) {
1164 FvHob.Raw = GET_NEXT_HOB (FvHob);
1165 continue;
1166 }
1167
1168 FwVolHeader = (EFI_FIRMWARE_VOLUME_HEADER *) (UINTN) BaseAddress;
1169 Status = ValidateFvHeader (FwVolHeader);
1170 if (EFI_ERROR (Status)) {
1171 //
1172 // Get FvbInfo
1173 //
1174 Status = GetFvbInfo (Length, &FwVolHeader);
1175 if (EFI_ERROR (Status)) {
1176 FvHob.Raw = GET_NEXT_HOB (FvHob);
1177 continue;
1178 }
1179 }
1180
1181 BufferSize += (sizeof (EFI_FW_VOL_INSTANCE) + FwVolHeader->HeaderLength - sizeof (EFI_FIRMWARE_VOLUME_HEADER));
1182 FvHob.Raw = GET_NEXT_HOB (FvHob);
1183 }
1184
1185 //
1186 // Only need to allocate once. There is only one copy of physical memory for
1187 // the private data of each FV instance. But in virtual mode or in physical
1188 // mode, the address of the the physical memory may be different.
1189 //
1190 Status = gBS->AllocatePool (
1191 EfiRuntimeServicesData,
1192 BufferSize,
1193 (VOID**) &mFvbModuleGlobal->FvInstance[FVB_PHYSICAL]
1194 );
1195 ASSERT_EFI_ERROR (Status);
1196
1197 //
1198 // Make a virtual copy of the FvInstance pointer.
1199 //
1200 FwhInstance = mFvbModuleGlobal->FvInstance[FVB_PHYSICAL];
1201 mFvbModuleGlobal->FvInstance[FVB_VIRTUAL] = FwhInstance;
1202
1203 mFvbModuleGlobal->NumFv = 0;
1204 MaxLbaSize = 0;
1205
1206 FvHob.Raw = GetHobList ();
1207 while (NULL != (FvHob.Raw = GetNextHob (EFI_HOB_TYPE_FV, FvHob.Raw))) {
1208 BaseAddress = FvHob.FirmwareVolume->BaseAddress;
1209 Length = FvHob.FirmwareVolume->Length;
1210 //
1211 // Check if it is a "real" flash
1212 //
1213 Status = DxeServices->GetMemorySpaceDescriptor (
1214 BaseAddress,
1215 &Descriptor
1216 );
1217 if (EFI_ERROR (Status)) {
1218 break;
1219 }
1220
1221 if (Descriptor.GcdMemoryType != EfiGcdMemoryTypeMemoryMappedIo) {
1222 FvHob.Raw = GET_NEXT_HOB (FvHob);
1223 continue;
1224 }
1225
1226 FwVolHeader = (EFI_FIRMWARE_VOLUME_HEADER *) (UINTN) BaseAddress;
1227 Status = ValidateFvHeader (FwVolHeader);
1228 if (EFI_ERROR (Status)) {
1229 //
1230 // Get FvbInfo to provide in FwhInstance.
1231 //
1232 Status = GetFvbInfo (Length, &FwVolHeader);
1233 if (EFI_ERROR (Status)) {
1234 FvHob.Raw = GET_NEXT_HOB (FvHob);
1235 continue;
1236 }
1237 //
1238 // Write healthy FV header back.
1239 //
1240 CopyMem (
1241 (VOID *) (UINTN) BaseAddress,
1242 (VOID *) FwVolHeader,
1243 FwVolHeader->HeaderLength
1244 );
1245 }
1246
1247 FwhInstance->FvBase[FVB_PHYSICAL] = (UINTN) BaseAddress;
1248 FwhInstance->FvBase[FVB_VIRTUAL] = (UINTN) BaseAddress;
1249
1250 CopyMem ((UINTN *) &(FwhInstance->VolumeHeader), (UINTN *) FwVolHeader, FwVolHeader->HeaderLength);
1251 FwVolHeader = &(FwhInstance->VolumeHeader);
1252 EfiInitializeLock (&(FwhInstance->FvbDevLock), TPL_HIGH_LEVEL);
1253
1254 NumOfBlocks = 0;
1255
1256 for (PtrBlockMapEntry = FwVolHeader->BlockMap; PtrBlockMapEntry->NumBlocks != 0; PtrBlockMapEntry++) {
1257 //
1258 // Get the maximum size of a block. The size will be used to allocate
1259 // buffer for Scratch space, the intermediate buffer for FVB extension
1260 // protocol
1261 //
1262 if (MaxLbaSize < PtrBlockMapEntry->Length) {
1263 MaxLbaSize = PtrBlockMapEntry->Length;
1264 }
1265
1266 NumOfBlocks = NumOfBlocks + PtrBlockMapEntry->NumBlocks;
1267 }
1268 //
1269 // The total number of blocks in the FV.
1270 //
1271 FwhInstance->NumOfBlocks = NumOfBlocks;
1272
1273 //
1274 // Add a FVB Protocol Instance
1275 //
1276 Status = gBS->AllocatePool (
1277 EfiRuntimeServicesData,
1278 sizeof (EFI_FW_VOL_BLOCK_DEVICE),
1279 (VOID**) &FvbDevice
1280 );
1281 ASSERT_EFI_ERROR (Status);
1282
1283 CopyMem (FvbDevice, &mFvbDeviceTemplate, sizeof (EFI_FW_VOL_BLOCK_DEVICE));
1284
1285 FvbDevice->Instance = mFvbModuleGlobal->NumFv;
1286 mFvbModuleGlobal->NumFv++;
1287
1288 //
1289 // Set up the devicepath
1290 //
1291 FvbDevice->DevicePath.MemMapDevPath.StartingAddress = BaseAddress;
1292 FvbDevice->DevicePath.MemMapDevPath.EndingAddress = BaseAddress + (FwVolHeader->FvLength - 1);
1293
1294 //
1295 // Find a handle with a matching device path that has supports FW Block protocol
1296 //
1297 TempFwbDevicePath = (EFI_DEVICE_PATH_PROTOCOL *) &TempFvbDevicePathData;
1298 CopyMem (TempFwbDevicePath, &FvbDevice->DevicePath, sizeof (FV_DEVICE_PATH));
1299 Status = gBS->LocateDevicePath (&gEfiFirmwareVolumeBlockProtocolGuid, &TempFwbDevicePath, &FwbHandle);
1300 if (EFI_ERROR (Status)) {
1301 //
1302 // LocateDevicePath fails so install a new interface and device path
1303 //
1304 FwbHandle = NULL;
1305 Status = gBS->InstallMultipleProtocolInterfaces (
1306 &FwbHandle,
1307 &gEfiFirmwareVolumeBlockProtocolGuid,
1308 &FvbDevice->FwVolBlockInstance,
1309 &gEfiDevicePathProtocolGuid,
1310 &FvbDevice->DevicePath,
1311 NULL
1312 );
1313 ASSERT_EFI_ERROR (Status);
1314 } else if (IsDevicePathEnd (TempFwbDevicePath)) {
1315 //
1316 // Device allready exists, so reinstall the FVB protocol
1317 //
1318 Status = gBS->HandleProtocol (
1319 FwbHandle,
1320 &gEfiFirmwareVolumeBlockProtocolGuid,
1321 (VOID**)&OldFwbInterface
1322 );
1323 ASSERT_EFI_ERROR (Status);
1324
1325 Status = gBS->ReinstallProtocolInterface (
1326 FwbHandle,
1327 &gEfiFirmwareVolumeBlockProtocolGuid,
1328 OldFwbInterface,
1329 &FvbDevice->FwVolBlockInstance
1330 );
1331 ASSERT_EFI_ERROR (Status);
1332
1333 } else {
1334 //
1335 // There was a FVB protocol on an End Device Path node
1336 //
1337 ASSERT (FALSE);
1338 }
1339
1340 FwhInstance = (EFI_FW_VOL_INSTANCE *)
1341 (
1342 (UINTN) ((UINT8 *) FwhInstance) + FwVolHeader->HeaderLength +
1343 (sizeof (EFI_FW_VOL_INSTANCE) - sizeof (EFI_FIRMWARE_VOLUME_HEADER))
1344 );
1345
1346 FvHob.Raw = GET_NEXT_HOB (FvHob);
1347 }
1348
1349 return EFI_SUCCESS;
1350 }