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