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