]> git.proxmox.com Git - mirror_edk2.git/blame - OvmfPkg/QemuFlashFvbServicesRuntimeDxe/FwBlockService.c
OvmfPkg/QemuFlashFvbServicesRuntimeDxe: Do not expose MMIO in SMM build
[mirror_edk2.git] / OvmfPkg / QemuFlashFvbServicesRuntimeDxe / FwBlockService.c
CommitLineData
a4ce9ffd
JJ
1/**@file\r
2\r
ea0d111e 3 Copyright (c) 2006 - 2014, Intel Corporation. All rights reserved.<BR>\r
a4ce9ffd 4\r
ea0d111e
LE
5 This program and the accompanying materials are licensed and made available\r
6 under the terms and conditions of the BSD License which accompanies this\r
7 distribution. The full text of the license may be found at\r
8 http://opensource.org/licenses/bsd-license.php\r
a4ce9ffd 9\r
ea0d111e
LE
10 THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
11 WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
a4ce9ffd 12\r
ea0d111e 13 Module Name:\r
a4ce9ffd 14\r
ea0d111e 15 FWBlockService.c\r
a4ce9ffd 16\r
ea0d111e
LE
17 Abstract:\r
18\r
19 Revision History\r
a4ce9ffd
JJ
20\r
21**/\r
22\r
a4ce9ffd
JJ
23//\r
24// The protocols, PPI and GUID defintions for this module\r
25//\r
a4ce9ffd 26#include <Protocol/DevicePath.h>\r
0f2eb31c 27#include <Protocol/FirmwareVolumeBlock.h>\r
a4ce9ffd
JJ
28\r
29//\r
30// The Library classes this module consumes\r
31//\r
a4ce9ffd 32#include <Library/BaseLib.h>\r
a4ce9ffd 33#include <Library/BaseMemoryLib.h>\r
0f2eb31c
LE
34#include <Library/DebugLib.h>\r
35#include <Library/DevicePathLib.h>\r
36#include <Library/DxeServicesTableLib.h>\r
a4ce9ffd
JJ
37#include <Library/MemoryAllocationLib.h>\r
38#include <Library/UefiBootServicesTableLib.h>\r
a4ce9ffd
JJ
39\r
40#include "FwBlockService.h"\r
41#include "QemuFlash.h"\r
42\r
ea0d111e
LE
43#define EFI_FVB2_STATUS \\r
44 (EFI_FVB2_READ_STATUS | EFI_FVB2_WRITE_STATUS | EFI_FVB2_LOCK_STATUS)\r
a4ce9ffd
JJ
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
a4ce9ffd
JJ
111EFI_STATUS\r
112GetFvbInstance (\r
113 IN UINTN Instance,\r
114 IN ESAL_FWB_GLOBAL *Global,\r
109301e5 115 OUT EFI_FW_VOL_INSTANCE **FwhInstance\r
a4ce9ffd
JJ
116 )\r
117/*++\r
118\r
ea0d111e
LE
119 Routine Description:\r
120 Retrieves the physical address of a memory mapped FV\r
a4ce9ffd 121\r
ea0d111e
LE
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
a4ce9ffd 128\r
ea0d111e
LE
129 Returns:\r
130 EFI_SUCCESS - Successfully returns\r
131 EFI_INVALID_PARAMETER - Instance not found\r
a4ce9ffd
JJ
132\r
133--*/\r
134{\r
135 EFI_FW_VOL_INSTANCE *FwhRecord;\r
136\r
8c01a99b 137 *FwhInstance = NULL;\r
a4ce9ffd
JJ
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
109301e5 144 FwhRecord = Global->FvInstance;\r
a4ce9ffd
JJ
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
109301e5 163 IN ESAL_FWB_GLOBAL *Global\r
a4ce9ffd
JJ
164 )\r
165/*++\r
166\r
ea0d111e
LE
167 Routine Description:\r
168 Retrieves the physical address of a memory mapped FV\r
a4ce9ffd 169\r
ea0d111e
LE
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
a4ce9ffd 178\r
ea0d111e
LE
179 Returns:\r
180 EFI_SUCCESS - Successfully returns\r
181 EFI_INVALID_PARAMETER - Instance not found\r
a4ce9ffd
JJ
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
109301e5 191 Status = GetFvbInstance (Instance, Global, &FwhInstance);\r
a4ce9ffd 192 ASSERT_EFI_ERROR (Status);\r
109301e5 193 *Address = FwhInstance->FvBase;\r
a4ce9ffd
JJ
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
109301e5 202 IN ESAL_FWB_GLOBAL *Global\r
a4ce9ffd
JJ
203 )\r
204/*++\r
205\r
ea0d111e
LE
206 Routine Description:\r
207 Retrieves attributes, insures positive polarity of attribute bits, returns\r
208 resulting attributes in output parameter\r
a4ce9ffd 209\r
ea0d111e
LE
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
a4ce9ffd 216\r
ea0d111e
LE
217 Returns:\r
218 EFI_SUCCESS - Successfully returns\r
219 EFI_INVALID_PARAMETER - Instance not found\r
a4ce9ffd
JJ
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
109301e5 229 Status = GetFvbInstance (Instance, Global, &FwhInstance);\r
a4ce9ffd
JJ
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
109301e5 243 IN ESAL_FWB_GLOBAL *Global\r
a4ce9ffd
JJ
244 )\r
245/*++\r
246\r
ea0d111e
LE
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
ea0d111e
LE
262\r
263 Returns:\r
264 EFI_SUCCESS - Successfully returns\r
265 EFI_INVALID_PARAMETER - Instance not found\r
a4ce9ffd
JJ
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
109301e5 281 Status = GetFvbInstance (Instance, Global, &FwhInstance);\r
a4ce9ffd
JJ
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
109301e5 307 *LbaAddress = FwhInstance->FvBase + Offset;\r
a4ce9ffd
JJ
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
109301e5 331 IN ESAL_FWB_GLOBAL *Global\r
a4ce9ffd
JJ
332 )\r
333/*++\r
334\r
ea0d111e
LE
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
ea0d111e
LE
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
a4ce9ffd
JJ
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
109301e5 370 Status = GetFvbInstance (Instance, Global, &FwhInstance);\r
a4ce9ffd
JJ
371 ASSERT_EFI_ERROR (Status);\r
372\r
ea0d111e
LE
373 AttribPtr =\r
374 (EFI_FVB_ATTRIBUTES_2 *) &(FwhInstance->VolumeHeader.Attributes);\r
a4ce9ffd
JJ
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
ea0d111e
LE
400 if ((OldAttributes & UnchangedAttributes) ^\r
401 (*Attributes & UnchangedAttributes)) {\r
a4ce9ffd
JJ
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
ea0d111e 471 Routine Description:\r
a4ce9ffd 472\r
ea0d111e 473 Retrieves the physical address of the device.\r
a4ce9ffd 474\r
ea0d111e 475 Arguments:\r
a4ce9ffd 476\r
ea0d111e
LE
477 This - Calling context\r
478 Address - Output buffer containing the address.\r
a4ce9ffd 479\r
ea0d111e
LE
480 Returns:\r
481 EFI_SUCCESS - Successfully returns\r
a4ce9ffd
JJ
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
ea0d111e 489 return FvbGetPhysicalAddress (FvbDevice->Instance, Address,\r
109301e5 490 mFvbModuleGlobal);\r
a4ce9ffd
JJ
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
ea0d111e
LE
503 Routine Description:\r
504 Retrieve the size of a logical block\r
a4ce9ffd 505\r
ea0d111e
LE
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
a4ce9ffd 515\r
ea0d111e
LE
516 Returns:\r
517 EFI_SUCCESS - The firmware volume was read successfully and\r
518 contents are in Buffer\r
a4ce9ffd
JJ
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
109301e5 532 mFvbModuleGlobal\r
a4ce9ffd
JJ
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
ea0d111e
LE
544 Routine Description:\r
545 Retrieves Volume attributes. No polarity translations are done.\r
a4ce9ffd 546\r
ea0d111e
LE
547 Arguments:\r
548 This - Calling context\r
549 Attributes - output buffer which contains attributes\r
a4ce9ffd 550\r
ea0d111e
LE
551 Returns:\r
552 EFI_SUCCESS - Successfully returns\r
a4ce9ffd
JJ
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
ea0d111e 560 return FvbGetVolumeAttributes (FvbDevice->Instance, Attributes,\r
109301e5 561 mFvbModuleGlobal);\r
a4ce9ffd
JJ
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
ea0d111e
LE
572 Routine Description:\r
573 Sets Volume attributes. No polarity translations are done.\r
a4ce9ffd 574\r
ea0d111e
LE
575 Arguments:\r
576 This - Calling context\r
577 Attributes - output buffer which contains attributes\r
a4ce9ffd 578\r
ea0d111e
LE
579 Returns:\r
580 EFI_SUCCESS - Successfully returns\r
a4ce9ffd
JJ
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
ea0d111e 588 return FvbSetVolumeAttributes (FvbDevice->Instance, Attributes,\r
109301e5 589 mFvbModuleGlobal);\r
a4ce9ffd
JJ
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
ea0d111e 600 Routine Description:\r
a4ce9ffd 601\r
ea0d111e
LE
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
a4ce9ffd 609\r
ea0d111e
LE
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
a4ce9ffd 614\r
ea0d111e
LE
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
a4ce9ffd
JJ
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
ea0d111e 634 Status = GetFvbInstance (FvbDevice->Instance, mFvbModuleGlobal,\r
109301e5 635 &FwhInstance);\r
a4ce9ffd
JJ
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
38292c08 648 NumOfLba = VA_ARG (args, UINTN);\r
a4ce9ffd
JJ
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
38292c08 668 NumOfLba = VA_ARG (args, UINTN);\r
a4ce9ffd
JJ
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
ea0d111e
LE
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
a4ce9ffd
JJ
726\r
727--*/\r
728{\r
ea0d111e
LE
729 return QemuFlashWrite ((EFI_LBA)Lba, (UINTN)Offset, NumBytes,\r
730 (UINT8 *)Buffer);\r
a4ce9ffd
JJ
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
ea0d111e
LE
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
a4ce9ffd
JJ
771\r
772--*/\r
773{\r
ea0d111e
LE
774 return QemuFlashRead ((EFI_LBA)Lba, (UINTN)Offset, NumBytes,\r
775 (UINT8 *)Buffer);\r
a4ce9ffd
JJ
776}\r
777\r
778EFI_STATUS\r
779ValidateFvHeader (\r
780 EFI_FIRMWARE_VOLUME_HEADER *FwVolHeader\r
781 )\r
782/*++\r
783\r
ea0d111e
LE
784 Routine Description:\r
785 Check the integrity of firmware volume header\r
a4ce9ffd 786\r
ea0d111e
LE
787 Arguments:\r
788 FwVolHeader - A pointer to a firmware volume header\r
a4ce9ffd 789\r
ea0d111e
LE
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
a4ce9ffd
JJ
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
141f0c64 811\r
a4ce9ffd
JJ
812 //\r
813 // Verify the header checksum\r
814 //\r
815\r
ea0d111e
LE
816 Checksum = CalculateSum16 ((UINT16 *) FwVolHeader,\r
817 FwVolHeader->HeaderLength);\r
a4ce9ffd
JJ
818 if (Checksum != 0) {\r
819 UINT16 Expected;\r
820\r
c4046161
JJ
821 Expected =\r
822 (UINT16) (((UINTN) FwVolHeader->Checksum + 0x10000 - Checksum) & 0xffff);\r
a4ce9ffd
JJ
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
a4ce9ffd
JJ
832STATIC\r
833EFI_STATUS\r
834InitializeVariableFvHeader (\r
835 VOID\r
836 )\r
837{\r
838 EFI_STATUS Status;\r
839 EFI_FIRMWARE_VOLUME_HEADER *GoodFwVolHeader;\r
840 EFI_FIRMWARE_VOLUME_HEADER *FwVolHeader;\r
841 UINTN Length;\r
842 UINTN WriteLength;\r
843 UINTN BlockSize;\r
844\r
845 FwVolHeader =\r
846 (EFI_FIRMWARE_VOLUME_HEADER *) (UINTN)\r
847 PcdGet32 (PcdOvmfFlashNvStorageVariableBase);\r
848\r
141f0c64 849 Length =\r
a4ce9ffd
JJ
850 (FixedPcdGet32 (PcdFlashNvStorageVariableSize) +\r
851 FixedPcdGet32 (PcdFlashNvStorageFtwWorkingSize) +\r
852 FixedPcdGet32 (PcdFlashNvStorageFtwSpareSize) +\r
853 FixedPcdGet32 (PcdOvmfFlashNvStorageEventLogSize));\r
854\r
855 BlockSize = PcdGet32 (PcdOvmfFirmwareBlockSize);\r
856\r
857 Status = ValidateFvHeader (FwVolHeader);\r
858 if (!EFI_ERROR (Status)) {\r
859 if (FwVolHeader->FvLength != Length ||\r
860 FwVolHeader->BlockMap[0].Length != BlockSize) {\r
861 Status = EFI_VOLUME_CORRUPTED;\r
862 }\r
863 }\r
864 if (EFI_ERROR (Status)) {\r
865 UINTN Offset;\r
866 UINTN Start;\r
867\r
ea0d111e
LE
868 DEBUG ((EFI_D_INFO,\r
869 "Variable FV header is not valid. It will be reinitialized.\n"));\r
a4ce9ffd
JJ
870\r
871 //\r
872 // Get FvbInfo to provide in FwhInstance.\r
873 //\r
874 Status = GetFvbInfo (Length, &GoodFwVolHeader);\r
875 ASSERT (!EFI_ERROR (Status));\r
876\r
877 Start = (UINTN)(UINT8*) FwVolHeader - PcdGet32 (PcdOvmfFdBaseAddress);\r
878 ASSERT (Start % BlockSize == 0 && Length % BlockSize == 0);\r
879 ASSERT (GoodFwVolHeader->HeaderLength <= BlockSize);\r
880\r
881 //\r
882 // Erase all the blocks\r
883 //\r
884 for (Offset = Start; Offset < Start + Length; Offset += BlockSize) {\r
1c590152 885 Status = QemuFlashEraseBlock (Offset / BlockSize);\r
a4ce9ffd
JJ
886 ASSERT_EFI_ERROR (Status);\r
887 }\r
888\r
889 //\r
890 // Write good FV header\r
891 //\r
892 WriteLength = GoodFwVolHeader->HeaderLength;\r
893 Status = QemuFlashWrite (\r
1c590152 894 Start / BlockSize,\r
a4ce9ffd
JJ
895 0,\r
896 &WriteLength,\r
897 (UINT8 *) GoodFwVolHeader);\r
898 ASSERT_EFI_ERROR (Status);\r
899 ASSERT (WriteLength == GoodFwVolHeader->HeaderLength);\r
900 }\r
901\r
902 return Status;\r
903}\r
904\r
905EFI_STATUS\r
906EFIAPI\r
907FvbInitialize (\r
908 IN EFI_HANDLE ImageHandle,\r
909 IN EFI_SYSTEM_TABLE *SystemTable\r
910 )\r
911/*++\r
912\r
ea0d111e
LE
913 Routine Description:\r
914 This function does common initialization for FVB services\r
a4ce9ffd 915\r
ea0d111e 916 Arguments:\r
a4ce9ffd 917\r
ea0d111e 918 Returns:\r
a4ce9ffd
JJ
919\r
920--*/\r
921{\r
922 EFI_STATUS Status;\r
923 EFI_FW_VOL_INSTANCE *FwhInstance;\r
924 EFI_FIRMWARE_VOLUME_HEADER *FwVolHeader;\r
925 UINT32 BufferSize;\r
926 EFI_FV_BLOCK_MAP_ENTRY *PtrBlockMapEntry;\r
a4ce9ffd 927 EFI_FW_VOL_BLOCK_DEVICE *FvbDevice;\r
a4ce9ffd
JJ
928 UINT32 MaxLbaSize;\r
929 EFI_PHYSICAL_ADDRESS BaseAddress;\r
1e62c89c 930 UINTN Length;\r
a4ce9ffd 931 UINTN NumOfBlocks;\r
65157ade 932 RETURN_STATUS PcdStatus;\r
a4ce9ffd
JJ
933\r
934 if (EFI_ERROR (QemuFlashInitialize ())) {\r
935 //\r
936 // Return an error so image will be unloaded\r
937 //\r
ea0d111e
LE
938 DEBUG ((EFI_D_INFO,\r
939 "QEMU flash was not detected. Writable FVB is not being installed.\n"));\r
a4ce9ffd
JJ
940 return EFI_WRITE_PROTECTED;\r
941 }\r
942\r
943 //\r
944 // Allocate runtime services data for global variable, which contains\r
945 // the private data of all firmware volume block instances\r
946 //\r
947 mFvbModuleGlobal = AllocateRuntimePool (sizeof (ESAL_FWB_GLOBAL));\r
948 ASSERT (mFvbModuleGlobal != NULL);\r
949\r
950 BaseAddress = (UINTN) PcdGet32 (PcdOvmfFdBaseAddress);\r
951 Length = PcdGet32 (PcdOvmfFirmwareFdSize);\r
952\r
953 Status = InitializeVariableFvHeader ();\r
954 if (EFI_ERROR (Status)) {\r
ea0d111e
LE
955 DEBUG ((EFI_D_INFO,\r
956 "QEMU Flash: Unable to initialize variable FV header\n"));\r
a4ce9ffd
JJ
957 return EFI_WRITE_PROTECTED;\r
958 }\r
959\r
960 FwVolHeader = (EFI_FIRMWARE_VOLUME_HEADER *) (UINTN) BaseAddress;\r
961 Status = ValidateFvHeader (FwVolHeader);\r
962 if (EFI_ERROR (Status)) {\r
963 //\r
964 // Get FvbInfo\r
965 //\r
966 Status = GetFvbInfo (Length, &FwVolHeader);\r
967 if (EFI_ERROR (Status)) {\r
968 DEBUG ((EFI_D_INFO, "EFI_ERROR (GetFvbInfo (Length, &FwVolHeader))\n"));\r
969 return EFI_WRITE_PROTECTED;\r
970 }\r
971 }\r
972\r
ea0d111e
LE
973 BufferSize = (sizeof (EFI_FW_VOL_INSTANCE) +\r
974 FwVolHeader->HeaderLength -\r
975 sizeof (EFI_FIRMWARE_VOLUME_HEADER)\r
976 );\r
109301e5
LE
977 mFvbModuleGlobal->FvInstance = AllocateRuntimePool (BufferSize);\r
978 ASSERT (mFvbModuleGlobal->FvInstance != NULL);\r
a4ce9ffd 979\r
109301e5 980 FwhInstance = mFvbModuleGlobal->FvInstance;\r
a4ce9ffd
JJ
981\r
982 mFvbModuleGlobal->NumFv = 0;\r
983 MaxLbaSize = 0;\r
984\r
985 FwVolHeader =\r
986 (EFI_FIRMWARE_VOLUME_HEADER *) (UINTN)\r
987 PcdGet32 (PcdOvmfFlashNvStorageVariableBase);\r
988\r
109301e5 989 FwhInstance->FvBase = (UINTN) BaseAddress;\r
a4ce9ffd 990\r
ea0d111e
LE
991 CopyMem ((UINTN *) &(FwhInstance->VolumeHeader), (UINTN *) FwVolHeader,\r
992 FwVolHeader->HeaderLength);\r
a4ce9ffd 993 FwVolHeader = &(FwhInstance->VolumeHeader);\r
a4ce9ffd
JJ
994\r
995 NumOfBlocks = 0;\r
996\r
ea0d111e
LE
997 for (PtrBlockMapEntry = FwVolHeader->BlockMap;\r
998 PtrBlockMapEntry->NumBlocks != 0;\r
999 PtrBlockMapEntry++) {\r
a4ce9ffd
JJ
1000 //\r
1001 // Get the maximum size of a block.\r
1002 //\r
1003 if (MaxLbaSize < PtrBlockMapEntry->Length) {\r
1004 MaxLbaSize = PtrBlockMapEntry->Length;\r
1005 }\r
1006\r
1007 NumOfBlocks = NumOfBlocks + PtrBlockMapEntry->NumBlocks;\r
1008 }\r
1009\r
1010 //\r
1011 // The total number of blocks in the FV.\r
1012 //\r
1013 FwhInstance->NumOfBlocks = NumOfBlocks;\r
1014\r
1015 //\r
1016 // Add a FVB Protocol Instance\r
1017 //\r
1018 FvbDevice = AllocateRuntimePool (sizeof (EFI_FW_VOL_BLOCK_DEVICE));\r
1019 ASSERT (FvbDevice != NULL);\r
1020\r
1021 CopyMem (FvbDevice, &mFvbDeviceTemplate, sizeof (EFI_FW_VOL_BLOCK_DEVICE));\r
1022\r
1023 FvbDevice->Instance = mFvbModuleGlobal->NumFv;\r
1024 mFvbModuleGlobal->NumFv++;\r
1025\r
1026 //\r
1027 // Set up the devicepath\r
1028 //\r
1029 if (FwVolHeader->ExtHeaderOffset == 0) {\r
ea0d111e
LE
1030 FV_MEMMAP_DEVICE_PATH *FvMemmapDevicePath;\r
1031\r
a4ce9ffd
JJ
1032 //\r
1033 // FV does not contains extension header, then produce MEMMAP_DEVICE_PATH\r
1034 //\r
ea0d111e
LE
1035 FvMemmapDevicePath = AllocateCopyPool (sizeof (FV_MEMMAP_DEVICE_PATH),\r
1036 &mFvMemmapDevicePathTemplate);\r
1037 FvMemmapDevicePath->MemMapDevPath.StartingAddress = BaseAddress;\r
1038 FvMemmapDevicePath->MemMapDevPath.EndingAddress =\r
1039 BaseAddress + FwVolHeader->FvLength - 1;\r
1040 FvbDevice->DevicePath = (EFI_DEVICE_PATH_PROTOCOL *)FvMemmapDevicePath;\r
a4ce9ffd 1041 } else {\r
ea0d111e
LE
1042 FV_PIWG_DEVICE_PATH *FvPiwgDevicePath;\r
1043\r
1044 FvPiwgDevicePath = AllocateCopyPool (sizeof (FV_PIWG_DEVICE_PATH),\r
1045 &mFvPIWGDevicePathTemplate);\r
a4ce9ffd 1046 CopyGuid (\r
ea0d111e 1047 &FvPiwgDevicePath->FvDevPath.FvName,\r
a4ce9ffd
JJ
1048 (GUID *)(UINTN)(BaseAddress + FwVolHeader->ExtHeaderOffset)\r
1049 );\r
ea0d111e 1050 FvbDevice->DevicePath = (EFI_DEVICE_PATH_PROTOCOL *)FvPiwgDevicePath;\r
a4ce9ffd
JJ
1051 }\r
1052\r
1053 //\r
1767877a 1054 // Module type specific hook.\r
a4ce9ffd 1055 //\r
1767877a 1056 InstallProtocolInterfaces (FvbDevice);\r
a4ce9ffd 1057\r
966363d5 1058 MarkIoMemoryRangeForRuntimeAccess (BaseAddress, Length);\r
a4ce9ffd
JJ
1059\r
1060 //\r
1061 // Set several PCD values to point to flash\r
1062 //\r
65157ade 1063 PcdStatus = PcdSet64S (\r
a4ce9ffd
JJ
1064 PcdFlashNvStorageVariableBase64,\r
1065 (UINTN) PcdGet32 (PcdOvmfFlashNvStorageVariableBase)\r
1066 );\r
65157ade
LE
1067 ASSERT_RETURN_ERROR (PcdStatus);\r
1068 PcdStatus = PcdSet32S (\r
a4ce9ffd
JJ
1069 PcdFlashNvStorageFtwWorkingBase,\r
1070 PcdGet32 (PcdOvmfFlashNvStorageFtwWorkingBase)\r
1071 );\r
65157ade
LE
1072 ASSERT_RETURN_ERROR (PcdStatus);\r
1073 PcdStatus = PcdSet32S (\r
a4ce9ffd
JJ
1074 PcdFlashNvStorageFtwSpareBase,\r
1075 PcdGet32 (PcdOvmfFlashNvStorageFtwSpareBase)\r
1076 );\r
65157ade 1077 ASSERT_RETURN_ERROR (PcdStatus);\r
a4ce9ffd
JJ
1078\r
1079 FwhInstance = (EFI_FW_VOL_INSTANCE *)\r
1080 (\r
1081 (UINTN) ((UINT8 *) FwhInstance) + FwVolHeader->HeaderLength +\r
1082 (sizeof (EFI_FW_VOL_INSTANCE) - sizeof (EFI_FIRMWARE_VOLUME_HEADER))\r
1083 );\r
1084\r
1767877a
LE
1085 //\r
1086 // Module type specific hook.\r
1087 //\r
1088 InstallVirtualAddressChangeHandler ();\r
a4ce9ffd 1089\r
65157ade
LE
1090 PcdStatus = PcdSetBoolS (PcdOvmfFlashVariablesEnable, TRUE);\r
1091 ASSERT_RETURN_ERROR (PcdStatus);\r
a4ce9ffd
JJ
1092 return EFI_SUCCESS;\r
1093}\r