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