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