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