]> git.proxmox.com Git - mirror_edk2.git/blame - OvmfPkg/QemuFlashFvbServicesRuntimeDxe/FwBlockService.c
OvmfPkg: Replace BSD License with BSD+Patent License
[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
b26f0cf9 5 SPDX-License-Identifier: BSD-2-Clause-Patent\r
a4ce9ffd 6\r
ea0d111e 7 Module Name:\r
a4ce9ffd 8\r
ea0d111e 9 FWBlockService.c\r
a4ce9ffd 10\r
ea0d111e
LE
11 Abstract:\r
12\r
13 Revision History\r
a4ce9ffd
JJ
14\r
15**/\r
16\r
a4ce9ffd
JJ
17//\r
18// The protocols, PPI and GUID defintions for this module\r
19//\r
a4ce9ffd 20#include <Protocol/DevicePath.h>\r
0f2eb31c 21#include <Protocol/FirmwareVolumeBlock.h>\r
a4ce9ffd
JJ
22\r
23//\r
24// The Library classes this module consumes\r
25//\r
a4ce9ffd 26#include <Library/BaseLib.h>\r
a4ce9ffd 27#include <Library/BaseMemoryLib.h>\r
0f2eb31c
LE
28#include <Library/DebugLib.h>\r
29#include <Library/DevicePathLib.h>\r
30#include <Library/DxeServicesTableLib.h>\r
a4ce9ffd
JJ
31#include <Library/MemoryAllocationLib.h>\r
32#include <Library/UefiBootServicesTableLib.h>\r
a4ce9ffd
JJ
33\r
34#include "FwBlockService.h"\r
35#include "QemuFlash.h"\r
36\r
ea0d111e
LE
37#define EFI_FVB2_STATUS \\r
38 (EFI_FVB2_READ_STATUS | EFI_FVB2_WRITE_STATUS | EFI_FVB2_LOCK_STATUS)\r
a4ce9ffd
JJ
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
a4ce9ffd
JJ
105EFI_STATUS\r
106GetFvbInstance (\r
107 IN UINTN Instance,\r
108 IN ESAL_FWB_GLOBAL *Global,\r
109301e5 109 OUT EFI_FW_VOL_INSTANCE **FwhInstance\r
a4ce9ffd
JJ
110 )\r
111/*++\r
112\r
ea0d111e
LE
113 Routine Description:\r
114 Retrieves the physical address of a memory mapped FV\r
a4ce9ffd 115\r
ea0d111e
LE
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 fimrware instance structure\r
a4ce9ffd 122\r
ea0d111e
LE
123 Returns:\r
124 EFI_SUCCESS - Successfully returns\r
125 EFI_INVALID_PARAMETER - Instance not found\r
a4ce9ffd
JJ
126\r
127--*/\r
128{\r
129 EFI_FW_VOL_INSTANCE *FwhRecord;\r
130\r
8c01a99b 131 *FwhInstance = NULL;\r
a4ce9ffd
JJ
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
109301e5 138 FwhRecord = Global->FvInstance;\r
a4ce9ffd
JJ
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
109301e5 157 IN ESAL_FWB_GLOBAL *Global\r
a4ce9ffd
JJ
158 )\r
159/*++\r
160\r
ea0d111e
LE
161 Routine Description:\r
162 Retrieves the physical address of a memory mapped FV\r
a4ce9ffd 163\r
ea0d111e
LE
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
a4ce9ffd 172\r
ea0d111e
LE
173 Returns:\r
174 EFI_SUCCESS - Successfully returns\r
175 EFI_INVALID_PARAMETER - Instance not found\r
a4ce9ffd
JJ
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
109301e5 185 Status = GetFvbInstance (Instance, Global, &FwhInstance);\r
a4ce9ffd 186 ASSERT_EFI_ERROR (Status);\r
109301e5 187 *Address = FwhInstance->FvBase;\r
a4ce9ffd
JJ
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
109301e5 196 IN ESAL_FWB_GLOBAL *Global\r
a4ce9ffd
JJ
197 )\r
198/*++\r
199\r
ea0d111e
LE
200 Routine Description:\r
201 Retrieves attributes, insures positive polarity of attribute bits, returns\r
202 resulting attributes in output parameter\r
a4ce9ffd 203\r
ea0d111e
LE
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
a4ce9ffd 210\r
ea0d111e
LE
211 Returns:\r
212 EFI_SUCCESS - Successfully returns\r
213 EFI_INVALID_PARAMETER - Instance not found\r
a4ce9ffd
JJ
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
109301e5 223 Status = GetFvbInstance (Instance, Global, &FwhInstance);\r
a4ce9ffd
JJ
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
109301e5 237 IN ESAL_FWB_GLOBAL *Global\r
a4ce9ffd
JJ
238 )\r
239/*++\r
240\r
ea0d111e
LE
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
ea0d111e
LE
256\r
257 Returns:\r
258 EFI_SUCCESS - Successfully returns\r
259 EFI_INVALID_PARAMETER - Instance not found\r
a4ce9ffd
JJ
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
109301e5 275 Status = GetFvbInstance (Instance, Global, &FwhInstance);\r
a4ce9ffd
JJ
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
109301e5 301 *LbaAddress = FwhInstance->FvBase + Offset;\r
a4ce9ffd
JJ
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
109301e5 325 IN ESAL_FWB_GLOBAL *Global\r
a4ce9ffd
JJ
326 )\r
327/*++\r
328\r
ea0d111e
LE
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
ea0d111e
LE
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
a4ce9ffd
JJ
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
109301e5 364 Status = GetFvbInstance (Instance, Global, &FwhInstance);\r
a4ce9ffd
JJ
365 ASSERT_EFI_ERROR (Status);\r
366\r
ea0d111e
LE
367 AttribPtr =\r
368 (EFI_FVB_ATTRIBUTES_2 *) &(FwhInstance->VolumeHeader.Attributes);\r
a4ce9ffd
JJ
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
ea0d111e
LE
394 if ((OldAttributes & UnchangedAttributes) ^\r
395 (*Attributes & UnchangedAttributes)) {\r
a4ce9ffd
JJ
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
ea0d111e 465 Routine Description:\r
a4ce9ffd 466\r
ea0d111e 467 Retrieves the physical address of the device.\r
a4ce9ffd 468\r
ea0d111e 469 Arguments:\r
a4ce9ffd 470\r
ea0d111e
LE
471 This - Calling context\r
472 Address - Output buffer containing the address.\r
a4ce9ffd 473\r
ea0d111e
LE
474 Returns:\r
475 EFI_SUCCESS - Successfully returns\r
a4ce9ffd
JJ
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
ea0d111e 483 return FvbGetPhysicalAddress (FvbDevice->Instance, Address,\r
109301e5 484 mFvbModuleGlobal);\r
a4ce9ffd
JJ
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
ea0d111e
LE
497 Routine Description:\r
498 Retrieve the size of a logical block\r
a4ce9ffd 499\r
ea0d111e
LE
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
a4ce9ffd 509\r
ea0d111e
LE
510 Returns:\r
511 EFI_SUCCESS - The firmware volume was read successfully and\r
512 contents are in Buffer\r
a4ce9ffd
JJ
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
109301e5 526 mFvbModuleGlobal\r
a4ce9ffd
JJ
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
ea0d111e
LE
538 Routine Description:\r
539 Retrieves Volume attributes. No polarity translations are done.\r
a4ce9ffd 540\r
ea0d111e
LE
541 Arguments:\r
542 This - Calling context\r
543 Attributes - output buffer which contains attributes\r
a4ce9ffd 544\r
ea0d111e
LE
545 Returns:\r
546 EFI_SUCCESS - Successfully returns\r
a4ce9ffd
JJ
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
ea0d111e 554 return FvbGetVolumeAttributes (FvbDevice->Instance, Attributes,\r
109301e5 555 mFvbModuleGlobal);\r
a4ce9ffd
JJ
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
ea0d111e
LE
566 Routine Description:\r
567 Sets Volume attributes. No polarity translations are done.\r
a4ce9ffd 568\r
ea0d111e
LE
569 Arguments:\r
570 This - Calling context\r
571 Attributes - output buffer which contains attributes\r
a4ce9ffd 572\r
ea0d111e
LE
573 Returns:\r
574 EFI_SUCCESS - Successfully returns\r
a4ce9ffd
JJ
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
ea0d111e 582 return FvbSetVolumeAttributes (FvbDevice->Instance, Attributes,\r
109301e5 583 mFvbModuleGlobal);\r
a4ce9ffd
JJ
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
ea0d111e 594 Routine Description:\r
a4ce9ffd 595\r
ea0d111e
LE
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
a4ce9ffd 603\r
ea0d111e
LE
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
a4ce9ffd 608\r
ea0d111e
LE
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
a4ce9ffd
JJ
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
ea0d111e 628 Status = GetFvbInstance (FvbDevice->Instance, mFvbModuleGlobal,\r
109301e5 629 &FwhInstance);\r
a4ce9ffd
JJ
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
38292c08 642 NumOfLba = VA_ARG (args, UINTN);\r
a4ce9ffd
JJ
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
38292c08 662 NumOfLba = VA_ARG (args, UINTN);\r
a4ce9ffd
JJ
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
ea0d111e
LE
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 opertion 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
a4ce9ffd
JJ
720\r
721--*/\r
722{\r
ea0d111e
LE
723 return QemuFlashWrite ((EFI_LBA)Lba, (UINTN)Offset, NumBytes,\r
724 (UINT8 *)Buffer);\r
a4ce9ffd
JJ
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
ea0d111e
LE
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 opertion 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
a4ce9ffd
JJ
765\r
766--*/\r
767{\r
ea0d111e
LE
768 return QemuFlashRead ((EFI_LBA)Lba, (UINTN)Offset, NumBytes,\r
769 (UINT8 *)Buffer);\r
a4ce9ffd
JJ
770}\r
771\r
772EFI_STATUS\r
773ValidateFvHeader (\r
774 EFI_FIRMWARE_VOLUME_HEADER *FwVolHeader\r
775 )\r
776/*++\r
777\r
ea0d111e
LE
778 Routine Description:\r
779 Check the integrity of firmware volume header\r
a4ce9ffd 780\r
ea0d111e
LE
781 Arguments:\r
782 FwVolHeader - A pointer to a firmware volume header\r
a4ce9ffd 783\r
ea0d111e
LE
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
a4ce9ffd
JJ
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
141f0c64 805\r
a4ce9ffd
JJ
806 //\r
807 // Verify the header checksum\r
808 //\r
809\r
ea0d111e
LE
810 Checksum = CalculateSum16 ((UINT16 *) FwVolHeader,\r
811 FwVolHeader->HeaderLength);\r
a4ce9ffd
JJ
812 if (Checksum != 0) {\r
813 UINT16 Expected;\r
814\r
c4046161
JJ
815 Expected =\r
816 (UINT16) (((UINTN) FwVolHeader->Checksum + 0x10000 - Checksum) & 0xffff);\r
a4ce9ffd
JJ
817\r
818 DEBUG ((EFI_D_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
a4ce9ffd
JJ
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
141f0c64 843 Length =\r
a4ce9ffd
JJ
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
ea0d111e
LE
862 DEBUG ((EFI_D_INFO,\r
863 "Variable FV header is not valid. It will be reinitialized.\n"));\r
a4ce9ffd
JJ
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
1c590152 879 Status = QemuFlashEraseBlock (Offset / BlockSize);\r
a4ce9ffd
JJ
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
1c590152 888 Start / BlockSize,\r
a4ce9ffd
JJ
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
ea0d111e
LE
907 Routine Description:\r
908 This function does common initialization for FVB services\r
a4ce9ffd 909\r
ea0d111e 910 Arguments:\r
a4ce9ffd 911\r
ea0d111e 912 Returns:\r
a4ce9ffd
JJ
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
a4ce9ffd 921 EFI_FW_VOL_BLOCK_DEVICE *FvbDevice;\r
a4ce9ffd
JJ
922 UINT32 MaxLbaSize;\r
923 EFI_PHYSICAL_ADDRESS BaseAddress;\r
1e62c89c 924 UINTN Length;\r
a4ce9ffd 925 UINTN NumOfBlocks;\r
65157ade 926 RETURN_STATUS PcdStatus;\r
a4ce9ffd
JJ
927\r
928 if (EFI_ERROR (QemuFlashInitialize ())) {\r
929 //\r
930 // Return an error so image will be unloaded\r
931 //\r
ea0d111e
LE
932 DEBUG ((EFI_D_INFO,\r
933 "QEMU flash was not detected. Writable FVB is not being installed.\n"));\r
a4ce9ffd
JJ
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
ea0d111e
LE
949 DEBUG ((EFI_D_INFO,\r
950 "QEMU Flash: Unable to initialize variable FV header\n"));\r
a4ce9ffd
JJ
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 ((EFI_D_INFO, "EFI_ERROR (GetFvbInfo (Length, &FwVolHeader))\n"));\r
963 return EFI_WRITE_PROTECTED;\r
964 }\r
965 }\r
966\r
ea0d111e
LE
967 BufferSize = (sizeof (EFI_FW_VOL_INSTANCE) +\r
968 FwVolHeader->HeaderLength -\r
969 sizeof (EFI_FIRMWARE_VOLUME_HEADER)\r
970 );\r
109301e5
LE
971 mFvbModuleGlobal->FvInstance = AllocateRuntimePool (BufferSize);\r
972 ASSERT (mFvbModuleGlobal->FvInstance != NULL);\r
a4ce9ffd 973\r
109301e5 974 FwhInstance = mFvbModuleGlobal->FvInstance;\r
a4ce9ffd
JJ
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
109301e5 983 FwhInstance->FvBase = (UINTN) BaseAddress;\r
a4ce9ffd 984\r
ea0d111e
LE
985 CopyMem ((UINTN *) &(FwhInstance->VolumeHeader), (UINTN *) FwVolHeader,\r
986 FwVolHeader->HeaderLength);\r
a4ce9ffd 987 FwVolHeader = &(FwhInstance->VolumeHeader);\r
a4ce9ffd
JJ
988\r
989 NumOfBlocks = 0;\r
990\r
ea0d111e
LE
991 for (PtrBlockMapEntry = FwVolHeader->BlockMap;\r
992 PtrBlockMapEntry->NumBlocks != 0;\r
993 PtrBlockMapEntry++) {\r
a4ce9ffd
JJ
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
ea0d111e
LE
1024 FV_MEMMAP_DEVICE_PATH *FvMemmapDevicePath;\r
1025\r
a4ce9ffd
JJ
1026 //\r
1027 // FV does not contains extension header, then produce MEMMAP_DEVICE_PATH\r
1028 //\r
ea0d111e
LE
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
a4ce9ffd 1035 } else {\r
ea0d111e
LE
1036 FV_PIWG_DEVICE_PATH *FvPiwgDevicePath;\r
1037\r
1038 FvPiwgDevicePath = AllocateCopyPool (sizeof (FV_PIWG_DEVICE_PATH),\r
1039 &mFvPIWGDevicePathTemplate);\r
a4ce9ffd 1040 CopyGuid (\r
ea0d111e 1041 &FvPiwgDevicePath->FvDevPath.FvName,\r
a4ce9ffd
JJ
1042 (GUID *)(UINTN)(BaseAddress + FwVolHeader->ExtHeaderOffset)\r
1043 );\r
ea0d111e 1044 FvbDevice->DevicePath = (EFI_DEVICE_PATH_PROTOCOL *)FvPiwgDevicePath;\r
a4ce9ffd
JJ
1045 }\r
1046\r
1047 //\r
1767877a 1048 // Module type specific hook.\r
a4ce9ffd 1049 //\r
1767877a 1050 InstallProtocolInterfaces (FvbDevice);\r
a4ce9ffd 1051\r
966363d5 1052 MarkIoMemoryRangeForRuntimeAccess (BaseAddress, Length);\r
a4ce9ffd
JJ
1053\r
1054 //\r
1055 // Set several PCD values to point to flash\r
1056 //\r
65157ade 1057 PcdStatus = PcdSet64S (\r
a4ce9ffd
JJ
1058 PcdFlashNvStorageVariableBase64,\r
1059 (UINTN) PcdGet32 (PcdOvmfFlashNvStorageVariableBase)\r
1060 );\r
65157ade
LE
1061 ASSERT_RETURN_ERROR (PcdStatus);\r
1062 PcdStatus = PcdSet32S (\r
a4ce9ffd
JJ
1063 PcdFlashNvStorageFtwWorkingBase,\r
1064 PcdGet32 (PcdOvmfFlashNvStorageFtwWorkingBase)\r
1065 );\r
65157ade
LE
1066 ASSERT_RETURN_ERROR (PcdStatus);\r
1067 PcdStatus = PcdSet32S (\r
a4ce9ffd
JJ
1068 PcdFlashNvStorageFtwSpareBase,\r
1069 PcdGet32 (PcdOvmfFlashNvStorageFtwSpareBase)\r
1070 );\r
65157ade 1071 ASSERT_RETURN_ERROR (PcdStatus);\r
a4ce9ffd
JJ
1072\r
1073 FwhInstance = (EFI_FW_VOL_INSTANCE *)\r
1074 (\r
1075 (UINTN) ((UINT8 *) FwhInstance) + FwVolHeader->HeaderLength +\r
1076 (sizeof (EFI_FW_VOL_INSTANCE) - sizeof (EFI_FIRMWARE_VOLUME_HEADER))\r
1077 );\r
1078\r
1767877a
LE
1079 //\r
1080 // Module type specific hook.\r
1081 //\r
1082 InstallVirtualAddressChangeHandler ();\r
a4ce9ffd 1083\r
65157ade
LE
1084 PcdStatus = PcdSetBoolS (PcdOvmfFlashVariablesEnable, TRUE);\r
1085 ASSERT_RETURN_ERROR (PcdStatus);\r
a4ce9ffd
JJ
1086 return EFI_SUCCESS;\r
1087}\r