]> git.proxmox.com Git - mirror_edk2.git/blob - UnixPkg/FvbServicesRuntimeDxe/FWBlockService.c
Update the copyright notice format
[mirror_edk2.git] / UnixPkg / FvbServicesRuntimeDxe / FWBlockService.c
1 /*++
2
3 Copyright (c) 2006 - 2009, 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) {
922 VA_END (args);
923 return EFI_INVALID_PARAMETER;
924 }
925
926 if ((StartingLba + NumOfLba) > NumOfBlocks) {
927 return EFI_INVALID_PARAMETER;
928 }
929 } while (1);
930
931 VA_END (args);
932
933 VA_START (args, This);
934 do {
935 StartingLba = VA_ARG (args, EFI_LBA);
936 if (StartingLba == EFI_LBA_LIST_TERMINATOR) {
937 break;
938 }
939
940 NumOfLba = VA_ARG (args, UINT32);
941
942 while (NumOfLba > 0) {
943 Status = FvbEraseBlock (FvbDevice->Instance, StartingLba, mFvbModuleGlobal, EfiGoneVirtual ());
944 if (EFI_ERROR (Status)) {
945 VA_END (args);
946 return Status;
947 }
948
949 StartingLba++;
950 NumOfLba--;
951 }
952
953 } while (1);
954
955 VA_END (args);
956
957 return EFI_SUCCESS;
958 }
959
960 EFI_STATUS
961 EFIAPI
962 FvbProtocolWrite (
963 IN CONST EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL *This,
964 IN EFI_LBA Lba,
965 IN UINTN Offset,
966 IN OUT UINTN *NumBytes,
967 IN UINT8 *Buffer
968 )
969 /*++
970
971 Routine Description:
972
973 Writes data beginning at Lba:Offset from FV. The write terminates either
974 when *NumBytes of data have been written, or when a block boundary is
975 reached. *NumBytes is updated to reflect the actual number of bytes
976 written. The write opertion does not include erase. This routine will
977 attempt to write only the specified bytes. If the writes do not stick,
978 it will return an error.
979
980 Arguments:
981 This - Calling context
982 Lba - Block in which to begin write
983 Offset - Offset in the block at which to begin write
984 NumBytes - On input, indicates the requested write size. On
985 output, indicates the actual number of bytes written
986 Buffer - Buffer containing source data for the write.
987
988 Returns:
989 EFI_SUCCESS - The firmware volume was written successfully
990 EFI_BAD_BUFFER_SIZE - Write attempted across a LBA boundary. On output,
991 NumBytes contains the total number of bytes
992 actually written
993 EFI_ACCESS_DENIED - The firmware volume is in the WriteDisabled state
994 EFI_DEVICE_ERROR - The block device is not functioning correctly and
995 could not be written
996 EFI_INVALID_PARAMETER - NumBytes or Buffer are NULL
997
998 --*/
999 {
1000
1001 EFI_FW_VOL_BLOCK_DEVICE *FvbDevice;
1002
1003 FvbDevice = FVB_DEVICE_FROM_THIS (This);
1004
1005 return FvbWriteBlock (FvbDevice->Instance, Lba, Offset, NumBytes, Buffer, mFvbModuleGlobal, EfiGoneVirtual ());
1006 }
1007
1008 EFI_STATUS
1009 EFIAPI
1010 FvbProtocolRead (
1011 IN CONST EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL *This,
1012 IN EFI_LBA Lba,
1013 IN UINTN Offset,
1014 IN OUT UINTN *NumBytes,
1015 IN UINT8 *Buffer
1016 )
1017 /*++
1018
1019 Routine Description:
1020
1021 Reads data beginning at Lba:Offset from FV. The Read terminates either
1022 when *NumBytes of data have been read, or when a block boundary is
1023 reached. *NumBytes is updated to reflect the actual number of bytes
1024 written. The write opertion does not include erase. This routine will
1025 attempt to write only the specified bytes. If the writes do not stick,
1026 it will return an error.
1027
1028 Arguments:
1029 This - Calling context
1030 Lba - Block in which to begin Read
1031 Offset - Offset in the block at which to begin Read
1032 NumBytes - On input, indicates the requested write size. On
1033 output, indicates the actual number of bytes Read
1034 Buffer - Buffer containing source data for the Read.
1035
1036 Returns:
1037 EFI_SUCCESS - The firmware volume was read successfully and
1038 contents are in Buffer
1039 EFI_BAD_BUFFER_SIZE - Read attempted across a LBA boundary. On output,
1040 NumBytes contains the total number of bytes returned
1041 in Buffer
1042 EFI_ACCESS_DENIED - The firmware volume is in the ReadDisabled state
1043 EFI_DEVICE_ERROR - The block device is not functioning correctly and
1044 could not be read
1045 EFI_INVALID_PARAMETER - NumBytes or Buffer are NULL
1046
1047 --*/
1048 {
1049
1050 EFI_FW_VOL_BLOCK_DEVICE *FvbDevice;
1051
1052 FvbDevice = FVB_DEVICE_FROM_THIS (This);
1053
1054 return FvbReadBlock (FvbDevice->Instance, Lba, Offset, NumBytes, Buffer, mFvbModuleGlobal, EfiGoneVirtual ());
1055 }
1056 EFI_STATUS
1057 ValidateFvHeader (
1058 EFI_FIRMWARE_VOLUME_HEADER *FwVolHeader
1059 )
1060 /*++
1061
1062 Routine Description:
1063 Check the integrity of firmware volume header
1064
1065 Arguments:
1066 FwVolHeader - A pointer to a firmware volume header
1067
1068 Returns:
1069 EFI_SUCCESS - The firmware volume is consistent
1070 EFI_NOT_FOUND - The firmware volume has corrupted. So it is not an FV
1071
1072 --*/
1073 {
1074 UINT16 *Ptr;
1075 UINT16 HeaderLength;
1076 UINT16 Checksum;
1077
1078 //
1079 // Verify the header revision, header signature, length
1080 // Length of FvBlock cannot be 2**64-1
1081 // HeaderLength cannot be an odd number
1082 //
1083 if ((FwVolHeader->Revision != EFI_FVH_REVISION) ||
1084 (FwVolHeader->Signature != EFI_FVH_SIGNATURE) ||
1085 (FwVolHeader->FvLength == ((UINTN) -1)) ||
1086 ((FwVolHeader->HeaderLength & 0x01) != 0)
1087 ) {
1088 return EFI_NOT_FOUND;
1089 }
1090 //
1091 // Verify the header checksum
1092 //
1093 HeaderLength = (UINT16) (FwVolHeader->HeaderLength / 2);
1094 Ptr = (UINT16 *) FwVolHeader;
1095 Checksum = 0;
1096 while (HeaderLength > 0) {
1097 Checksum = Checksum + (*Ptr);
1098 HeaderLength--;
1099 Ptr++;
1100 }
1101
1102 if (Checksum != 0) {
1103 return EFI_NOT_FOUND;
1104 }
1105
1106 return EFI_SUCCESS;
1107 }
1108
1109 EFI_STATUS
1110 EFIAPI
1111 FvbInitialize (
1112 IN EFI_HANDLE ImageHandle,
1113 IN EFI_SYSTEM_TABLE *SystemTable
1114 )
1115 /*++
1116
1117 Routine Description:
1118 This function does common initialization for FVB services
1119
1120 Arguments:
1121
1122 Returns:
1123
1124 --*/
1125 {
1126 EFI_STATUS Status;
1127 EFI_FW_VOL_INSTANCE *FwhInstance = NULL;
1128 EFI_FIRMWARE_VOLUME_HEADER *FwVolHeader;
1129 EFI_DXE_SERVICES *DxeServices;
1130 EFI_GCD_MEMORY_SPACE_DESCRIPTOR Descriptor;
1131 UINT32 BufferSize;
1132 EFI_FV_BLOCK_MAP_ENTRY *PtrBlockMapEntry;
1133 EFI_HANDLE FwbHandle;
1134 EFI_FW_VOL_BLOCK_DEVICE *FvbDevice;
1135 EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL *OldFwbInterface;
1136 EFI_DEVICE_PATH_PROTOCOL *TempFwbDevicePath;
1137 FV_DEVICE_PATH TempFvbDevicePathData;
1138 UINT32 MaxLbaSize;
1139 EFI_PHYSICAL_ADDRESS BaseAddress;
1140 UINT64 Length;
1141 UINTN NumOfBlocks;
1142 EFI_PEI_HOB_POINTERS FvHob;
1143
1144 //
1145 // Get the DXE services table
1146 //
1147 DxeServices = gDS;
1148
1149 //
1150 // Allocate runtime services data for global variable, which contains
1151 // the private data of all firmware volume block instances
1152 //
1153 Status = gBS->AllocatePool (
1154 EfiRuntimeServicesData,
1155 sizeof (ESAL_FWB_GLOBAL),
1156 (VOID**) &mFvbModuleGlobal
1157 );
1158 ASSERT_EFI_ERROR (Status);
1159
1160 //
1161 // Calculate the total size for all firmware volume block instances
1162 //
1163 BufferSize = 0;
1164
1165 FvHob.Raw = GetHobList ();
1166 while ((FvHob.Raw = GetNextHob (EFI_HOB_TYPE_FV, FvHob.Raw)) != NULL) {
1167 BaseAddress = FvHob.FirmwareVolume->BaseAddress;
1168 Length = FvHob.FirmwareVolume->Length;
1169 //
1170 // Check if it is a "real" flash
1171 //
1172 Status = DxeServices->GetMemorySpaceDescriptor (
1173 BaseAddress,
1174 &Descriptor
1175 );
1176 if (EFI_ERROR (Status)) {
1177 break;
1178 }
1179
1180 if (Descriptor.GcdMemoryType != EfiGcdMemoryTypeMemoryMappedIo) {
1181 FvHob.Raw = GET_NEXT_HOB (FvHob);
1182 continue;
1183 }
1184
1185 FwVolHeader = (EFI_FIRMWARE_VOLUME_HEADER *) (UINTN) BaseAddress;
1186 Status = ValidateFvHeader (FwVolHeader);
1187 if (EFI_ERROR (Status)) {
1188 //
1189 // Get FvbInfo
1190 //
1191 Status = GetFvbInfo (Length, &FwVolHeader);
1192 if (EFI_ERROR (Status)) {
1193 FvHob.Raw = GET_NEXT_HOB (FvHob);
1194 continue;
1195 }
1196 }
1197
1198 BufferSize += (sizeof (EFI_FW_VOL_INSTANCE) + FwVolHeader->HeaderLength - sizeof (EFI_FIRMWARE_VOLUME_HEADER));
1199 FvHob.Raw = GET_NEXT_HOB (FvHob);
1200 }
1201
1202 //
1203 // Only need to allocate once. There is only one copy of physical memory for
1204 // the private data of each FV instance. But in virtual mode or in physical
1205 // mode, the address of the the physical memory may be different.
1206 //
1207 Status = gBS->AllocatePool (
1208 EfiRuntimeServicesData,
1209 BufferSize,
1210 (VOID**) &mFvbModuleGlobal->FvInstance[FVB_PHYSICAL]
1211 );
1212 ASSERT_EFI_ERROR (Status);
1213
1214 //
1215 // Make a virtual copy of the FvInstance pointer.
1216 //
1217 FwhInstance = mFvbModuleGlobal->FvInstance[FVB_PHYSICAL];
1218 mFvbModuleGlobal->FvInstance[FVB_VIRTUAL] = FwhInstance;
1219
1220 mFvbModuleGlobal->NumFv = 0;
1221 MaxLbaSize = 0;
1222
1223 FvHob.Raw = GetHobList ();
1224 while (NULL != (FvHob.Raw = GetNextHob (EFI_HOB_TYPE_FV, FvHob.Raw))) {
1225 BaseAddress = FvHob.FirmwareVolume->BaseAddress;
1226 Length = FvHob.FirmwareVolume->Length;
1227 //
1228 // Check if it is a "real" flash
1229 //
1230 Status = DxeServices->GetMemorySpaceDescriptor (
1231 BaseAddress,
1232 &Descriptor
1233 );
1234 if (EFI_ERROR (Status)) {
1235 break;
1236 }
1237
1238 if (Descriptor.GcdMemoryType != EfiGcdMemoryTypeMemoryMappedIo) {
1239 FvHob.Raw = GET_NEXT_HOB (FvHob);
1240 continue;
1241 }
1242
1243 FwVolHeader = (EFI_FIRMWARE_VOLUME_HEADER *) (UINTN) BaseAddress;
1244 Status = ValidateFvHeader (FwVolHeader);
1245 if (EFI_ERROR (Status)) {
1246 //
1247 // Get FvbInfo to provide in FwhInstance.
1248 //
1249 Status = GetFvbInfo (Length, &FwVolHeader);
1250 if (EFI_ERROR (Status)) {
1251 FvHob.Raw = GET_NEXT_HOB (FvHob);
1252 continue;
1253 }
1254 //
1255 // Write healthy FV header back.
1256 //
1257 CopyMem (
1258 (VOID *) (UINTN) BaseAddress,
1259 (VOID *) FwVolHeader,
1260 FwVolHeader->HeaderLength
1261 );
1262 }
1263
1264 FwhInstance->FvBase[FVB_PHYSICAL] = (UINTN) BaseAddress;
1265 FwhInstance->FvBase[FVB_VIRTUAL] = (UINTN) BaseAddress;
1266
1267 CopyMem ((UINTN *) &(FwhInstance->VolumeHeader), (UINTN *) FwVolHeader, FwVolHeader->HeaderLength);
1268 FwVolHeader = &(FwhInstance->VolumeHeader);
1269 EfiInitializeLock (&(FwhInstance->FvbDevLock), TPL_HIGH_LEVEL);
1270
1271 NumOfBlocks = 0;
1272
1273 for (PtrBlockMapEntry = FwVolHeader->BlockMap; PtrBlockMapEntry->NumBlocks != 0; PtrBlockMapEntry++) {
1274 //
1275 // Get the maximum size of a block. The size will be used to allocate
1276 // buffer for Scratch space, the intermediate buffer for FVB extension
1277 // protocol
1278 //
1279 if (MaxLbaSize < PtrBlockMapEntry->Length) {
1280 MaxLbaSize = PtrBlockMapEntry->Length;
1281 }
1282
1283 NumOfBlocks = NumOfBlocks + PtrBlockMapEntry->NumBlocks;
1284 }
1285 //
1286 // The total number of blocks in the FV.
1287 //
1288 FwhInstance->NumOfBlocks = NumOfBlocks;
1289
1290 //
1291 // Add a FVB Protocol Instance
1292 //
1293 Status = gBS->AllocatePool (
1294 EfiRuntimeServicesData,
1295 sizeof (EFI_FW_VOL_BLOCK_DEVICE),
1296 (VOID**) &FvbDevice
1297 );
1298 ASSERT_EFI_ERROR (Status);
1299
1300 CopyMem (FvbDevice, &mFvbDeviceTemplate, sizeof (EFI_FW_VOL_BLOCK_DEVICE));
1301
1302 FvbDevice->Instance = mFvbModuleGlobal->NumFv;
1303 mFvbModuleGlobal->NumFv++;
1304
1305 //
1306 // Set up the devicepath
1307 //
1308 FvbDevice->DevicePath.MemMapDevPath.StartingAddress = BaseAddress;
1309 FvbDevice->DevicePath.MemMapDevPath.EndingAddress = BaseAddress + (FwVolHeader->FvLength - 1);
1310
1311 //
1312 // Find a handle with a matching device path that has supports FW Block protocol
1313 //
1314 TempFwbDevicePath = (EFI_DEVICE_PATH_PROTOCOL *) &TempFvbDevicePathData;
1315 CopyMem (TempFwbDevicePath, &FvbDevice->DevicePath, sizeof (FV_DEVICE_PATH));
1316 Status = gBS->LocateDevicePath (&gEfiFirmwareVolumeBlockProtocolGuid, &TempFwbDevicePath, &FwbHandle);
1317 if (EFI_ERROR (Status)) {
1318 //
1319 // LocateDevicePath fails so install a new interface and device path
1320 //
1321 FwbHandle = NULL;
1322 Status = gBS->InstallMultipleProtocolInterfaces (
1323 &FwbHandle,
1324 &gEfiFirmwareVolumeBlockProtocolGuid,
1325 &FvbDevice->FwVolBlockInstance,
1326 &gEfiDevicePathProtocolGuid,
1327 &FvbDevice->DevicePath,
1328 NULL
1329 );
1330 ASSERT_EFI_ERROR (Status);
1331 } else if (IsDevicePathEnd (TempFwbDevicePath)) {
1332 //
1333 // Device allready exists, so reinstall the FVB protocol
1334 //
1335 Status = gBS->HandleProtocol (
1336 FwbHandle,
1337 &gEfiFirmwareVolumeBlockProtocolGuid,
1338 (VOID**)&OldFwbInterface
1339 );
1340 ASSERT_EFI_ERROR (Status);
1341
1342 Status = gBS->ReinstallProtocolInterface (
1343 FwbHandle,
1344 &gEfiFirmwareVolumeBlockProtocolGuid,
1345 OldFwbInterface,
1346 &FvbDevice->FwVolBlockInstance
1347 );
1348 ASSERT_EFI_ERROR (Status);
1349
1350 } else {
1351 //
1352 // There was a FVB protocol on an End Device Path node
1353 //
1354 ASSERT (FALSE);
1355 }
1356
1357 FwhInstance = (EFI_FW_VOL_INSTANCE *)
1358 (
1359 (UINTN) ((UINT8 *) FwhInstance) + FwVolHeader->HeaderLength +
1360 (sizeof (EFI_FW_VOL_INSTANCE) - sizeof (EFI_FIRMWARE_VOLUME_HEADER))
1361 );
1362
1363 FvHob.Raw = GET_NEXT_HOB (FvHob);
1364 }
1365
1366 return EFI_SUCCESS;
1367 }