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