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