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