]> git.proxmox.com Git - mirror_edk2.git/blame - UnixPkg/FvbServicesRuntimeDxe/FWBlockService.c
Add Missing invocations to VA_END() for VA_START().
[mirror_edk2.git] / UnixPkg / FvbServicesRuntimeDxe / FWBlockService.c
CommitLineData
804405e7 1/*++\r
2\r
3bbe68a3 3Copyright (c) 2006 - 2012, Intel Corporation. All rights reserved.<BR>\r
f9b8ab56 4This program and the accompanying materials \r
804405e7 5are licensed and made available under the terms and conditions of the BSD License \r
6which accompanies this distribution. The full text of the license may be found at \r
7http://opensource.org/licenses/bsd-license.php \r
8 \r
9THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, \r
10WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. \r
11\r
12Module Name:\r
13\r
14 FWBlockService.c\r
15 \r
16Abstract:\r
17\r
18Revision History\r
19\r
20--*/\r
21\r
e89bb669 22#include "PiDxe.h"\r
804405e7 23#include <Guid/EventGroup.h>\r
804405e7 24#include <Protocol/FirmwareVolumeBlock.h>\r
804405e7 25#include <Protocol/DevicePath.h>\r
26\r
27#include <Library/UefiLib.h>\r
28#include <Library/UefiDriverEntryPoint.h>\r
29#include <Library/BaseLib.h>\r
30#include <Library/DxeServicesTableLib.h>\r
31#include <Library/UefiRuntimeLib.h>\r
32#include <Library/DebugLib.h>\r
33#include <Library/HobLib.h>\r
34#include <Library/BaseMemoryLib.h>\r
35#include <Library/MemoryAllocationLib.h>\r
ccd55824 36#include <Library/UefiBootServicesTableLib.h>\r
37#include <Library/DevicePathLib.h>\r
9f0b86b7 38\r
804405e7 39#include "FwBlockService.h"\r
40\r
41ESAL_FWB_GLOBAL *mFvbModuleGlobal;\r
42\r
43#define EFI_FVB2_STATUS (EFI_FVB2_READ_STATUS | EFI_FVB2_WRITE_STATUS | EFI_FVB2_LOCK_STATUS)\r
44\r
45EFI_FW_VOL_BLOCK_DEVICE mFvbDeviceTemplate = {\r
46 FVB_DEVICE_SIGNATURE,\r
47 {\r
48 {\r
49 {\r
50 HARDWARE_DEVICE_PATH,\r
51 HW_MEMMAP_DP,\r
52 {\r
53 sizeof (MEMMAP_DEVICE_PATH),\r
54 0\r
55 }\r
56 },\r
57 EfiMemoryMappedIO,\r
58 0,\r
59 0,\r
60 },\r
61 {\r
62 END_DEVICE_PATH_TYPE,\r
63 END_ENTIRE_DEVICE_PATH_SUBTYPE,\r
64 {\r
65 sizeof (EFI_DEVICE_PATH_PROTOCOL),\r
66 0\r
67 }\r
68 }\r
69 },\r
70 0,\r
71 {\r
72 FvbProtocolGetAttributes,\r
73 FvbProtocolSetAttributes,\r
74 FvbProtocolGetPhysicalAddress,\r
75 FvbProtocolGetBlockSize,\r
76 FvbProtocolRead,\r
77 FvbProtocolWrite,\r
78 FvbProtocolEraseBlocks,\r
79 NULL\r
804405e7 80 }\r
81};\r
82\r
83\r
84\r
85VOID\r
86EFIAPI\r
87FvbVirtualddressChangeEvent (\r
88 IN EFI_EVENT Event,\r
89 IN VOID *Context\r
90 )\r
91/*++\r
92\r
93Routine Description:\r
94\r
95 Fixup internal data so that EFI and SAL can be call in virtual mode.\r
96 Call the passed in Child Notify event and convert the mFvbModuleGlobal\r
97 date items to there virtual address.\r
98\r
99 mFvbModuleGlobal->FvInstance[FVB_PHYSICAL] - Physical copy of instance data\r
100 mFvbModuleGlobal->FvInstance[FVB_VIRTUAL] - Virtual pointer to common \r
101 instance data.\r
102\r
103Arguments:\r
104\r
105 (Standard EFI notify event - EFI_EVENT_NOTIFY)\r
106\r
107Returns: \r
108\r
109 None\r
110\r
111--*/\r
112{\r
113 EFI_FW_VOL_INSTANCE *FwhInstance;\r
114 UINTN Index;\r
115\r
116 EfiConvertPointer (0x0, (VOID **) &mFvbModuleGlobal->FvInstance[FVB_VIRTUAL]);\r
117\r
118 //\r
119 // Convert the base address of all the instances\r
120 //\r
121 Index = 0;\r
122 FwhInstance = mFvbModuleGlobal->FvInstance[FVB_PHYSICAL];\r
123 while (Index < mFvbModuleGlobal->NumFv) {\r
124 EfiConvertPointer (0x0, (VOID **) &FwhInstance->FvBase[FVB_VIRTUAL]);\r
125 FwhInstance = (EFI_FW_VOL_INSTANCE *)\r
126 (\r
127 (UINTN) ((UINT8 *) FwhInstance) + FwhInstance->VolumeHeader.HeaderLength +\r
128 (sizeof (EFI_FW_VOL_INSTANCE) - sizeof (EFI_FIRMWARE_VOLUME_HEADER))\r
129 );\r
130 Index++;\r
131 }\r
132\r
804405e7 133 EfiConvertPointer (0x0, (VOID **) &mFvbModuleGlobal);\r
134}\r
135\r
136EFI_STATUS\r
137GetFvbInstance (\r
138 IN UINTN Instance,\r
139 IN ESAL_FWB_GLOBAL *Global,\r
140 OUT EFI_FW_VOL_INSTANCE **FwhInstance,\r
141 IN BOOLEAN Virtual\r
142 )\r
143/*++\r
144\r
145Routine Description:\r
146 Retrieves the physical address of a memory mapped FV\r
147\r
148Arguments:\r
149 Instance - The FV instance whose base address is going to be\r
150 returned\r
151 Global - Pointer to ESAL_FWB_GLOBAL that contains all\r
152 instance data\r
153 FwhInstance - The EFI_FW_VOL_INSTANCE fimrware instance structure\r
154 Virtual - Whether CPU is in virtual or physical mode\r
155\r
156Returns: \r
157 EFI_SUCCESS - Successfully returns\r
158 EFI_INVALID_PARAMETER - Instance not found\r
159\r
160--*/\r
161{\r
162 EFI_FW_VOL_INSTANCE *FwhRecord;\r
163\r
164 if (Instance >= Global->NumFv) {\r
165 return EFI_INVALID_PARAMETER;\r
166 }\r
167 //\r
168 // Find the right instance of the FVB private data\r
169 //\r
170 FwhRecord = Global->FvInstance[Virtual];\r
171 while (Instance > 0) {\r
172 FwhRecord = (EFI_FW_VOL_INSTANCE *)\r
173 (\r
174 (UINTN) ((UINT8 *) FwhRecord) + FwhRecord->VolumeHeader.HeaderLength +\r
175 (sizeof (EFI_FW_VOL_INSTANCE) - sizeof (EFI_FIRMWARE_VOLUME_HEADER))\r
176 );\r
177 Instance--;\r
178 }\r
179\r
180 *FwhInstance = FwhRecord;\r
181\r
182 return EFI_SUCCESS;\r
183}\r
184\r
185EFI_STATUS\r
186FvbGetPhysicalAddress (\r
187 IN UINTN Instance,\r
188 OUT EFI_PHYSICAL_ADDRESS *Address,\r
189 IN ESAL_FWB_GLOBAL *Global,\r
190 IN BOOLEAN Virtual\r
191 )\r
192/*++\r
193\r
194Routine Description:\r
195 Retrieves the physical address of a memory mapped FV\r
196\r
197Arguments:\r
198 Instance - The FV instance whose base address is going to be\r
199 returned\r
200 Address - Pointer to a caller allocated EFI_PHYSICAL_ADDRESS \r
201 that on successful return, contains the base address\r
202 of the firmware volume. \r
203 Global - Pointer to ESAL_FWB_GLOBAL that contains all\r
204 instance data\r
205 Virtual - Whether CPU is in virtual or physical mode\r
206\r
207Returns: \r
208 EFI_SUCCESS - Successfully returns\r
209 EFI_INVALID_PARAMETER - Instance not found\r
210\r
211--*/\r
212{\r
ccd55824 213 EFI_FW_VOL_INSTANCE *FwhInstance = NULL;\r
804405e7 214 EFI_STATUS Status;\r
215\r
216 //\r
217 // Find the right instance of the FVB private data\r
218 //\r
219 Status = GetFvbInstance (Instance, Global, &FwhInstance, Virtual);\r
220 ASSERT_EFI_ERROR (Status);\r
221 *Address = FwhInstance->FvBase[Virtual];\r
222\r
223 return EFI_SUCCESS;\r
224}\r
225\r
226EFI_STATUS\r
227FvbGetVolumeAttributes (\r
228 IN UINTN Instance,\r
7ee3b613 229 OUT EFI_FVB_ATTRIBUTES_2 *Attributes,\r
804405e7 230 IN ESAL_FWB_GLOBAL *Global,\r
231 IN BOOLEAN Virtual\r
232 )\r
233/*++\r
234\r
235Routine Description:\r
236 Retrieves attributes, insures positive polarity of attribute bits, returns\r
237 resulting attributes in output parameter\r
238\r
239Arguments:\r
240 Instance - The FV instance whose attributes is going to be \r
241 returned\r
242 Attributes - Output buffer which contains attributes\r
243 Global - Pointer to ESAL_FWB_GLOBAL that contains all\r
244 instance data\r
245 Virtual - Whether CPU is in virtual or physical mode\r
246\r
247Returns: \r
248 EFI_SUCCESS - Successfully returns\r
249 EFI_INVALID_PARAMETER - Instance not found\r
250\r
251--*/\r
252{\r
ccd55824 253 EFI_FW_VOL_INSTANCE *FwhInstance = NULL;\r
804405e7 254 EFI_STATUS Status;\r
255\r
256 //\r
257 // Find the right instance of the FVB private data\r
258 //\r
259 Status = GetFvbInstance (Instance, Global, &FwhInstance, Virtual);\r
260 ASSERT_EFI_ERROR (Status);\r
261 *Attributes = FwhInstance->VolumeHeader.Attributes;\r
262\r
263 return EFI_SUCCESS;\r
264}\r
265\r
266EFI_STATUS\r
267FvbGetLbaAddress (\r
268 IN UINTN Instance,\r
269 IN EFI_LBA Lba,\r
270 OUT UINTN *LbaAddress,\r
271 OUT UINTN *LbaLength,\r
272 OUT UINTN *NumOfBlocks,\r
273 IN ESAL_FWB_GLOBAL *Global,\r
274 IN BOOLEAN Virtual\r
275 )\r
276/*++\r
277\r
278Routine Description:\r
279 Retrieves the starting address of an LBA in an FV\r
280\r
281Arguments:\r
282 Instance - The FV instance which the Lba belongs to\r
283 Lba - The logical block address\r
284 LbaAddress - On output, contains the physical starting address \r
285 of the Lba\r
286 LbaLength - On output, contains the length of the block\r
287 NumOfBlocks - A pointer to a caller allocated UINTN in which the\r
288 number of consecutive blocks starting with Lba is\r
289 returned. All blocks in this range have a size of\r
290 BlockSize\r
291 Global - Pointer to ESAL_FWB_GLOBAL that contains all\r
292 instance data\r
293 Virtual - Whether CPU is in virtual or physical mode\r
294\r
295Returns: \r
296 EFI_SUCCESS - Successfully returns\r
297 EFI_INVALID_PARAMETER - Instance not found\r
298\r
299--*/\r
300{\r
301 UINT32 NumBlocks;\r
302 UINT32 BlockLength;\r
303 UINTN Offset;\r
304 EFI_LBA StartLba;\r
305 EFI_LBA NextLba;\r
ccd55824 306 EFI_FW_VOL_INSTANCE *FwhInstance = NULL;\r
804405e7 307 EFI_FV_BLOCK_MAP_ENTRY *BlockMap;\r
308 EFI_STATUS Status;\r
309\r
310 //\r
311 // Find the right instance of the FVB private data\r
312 //\r
313 Status = GetFvbInstance (Instance, Global, &FwhInstance, Virtual);\r
314 ASSERT_EFI_ERROR (Status);\r
315\r
316 StartLba = 0;\r
317 Offset = 0;\r
318 BlockMap = &(FwhInstance->VolumeHeader.BlockMap[0]);\r
319\r
320 //\r
321 // Parse the blockmap of the FV to find which map entry the Lba belongs to\r
322 //\r
323 while (TRUE) {\r
324 NumBlocks = BlockMap->NumBlocks;\r
325 BlockLength = BlockMap->Length;\r
326\r
327 if (NumBlocks == 0 || BlockLength == 0) {\r
328 return EFI_INVALID_PARAMETER;\r
329 }\r
330\r
331 NextLba = StartLba + NumBlocks;\r
332\r
333 //\r
334 // The map entry found\r
335 //\r
336 if (Lba >= StartLba && Lba < NextLba) {\r
337 Offset = Offset + (UINTN) MultU64x32 ((Lba - StartLba), BlockLength);\r
338 if (LbaAddress != NULL) {\r
339 *LbaAddress = FwhInstance->FvBase[Virtual] + Offset;\r
340 }\r
341\r
342 if (LbaLength != NULL) {\r
343 *LbaLength = BlockLength;\r
344 }\r
345\r
346 if (NumOfBlocks != NULL) {\r
347 *NumOfBlocks = (UINTN) (NextLba - Lba);\r
348 }\r
349\r
350 return EFI_SUCCESS;\r
351 }\r
352\r
353 StartLba = NextLba;\r
354 Offset = Offset + NumBlocks * BlockLength;\r
355 BlockMap++;\r
356 }\r
357}\r
358\r
359EFI_STATUS\r
360FvbReadBlock (\r
361 IN UINTN Instance,\r
362 IN EFI_LBA Lba,\r
363 IN UINTN BlockOffset,\r
364 IN OUT UINTN *NumBytes,\r
365 IN UINT8 *Buffer,\r
366 IN ESAL_FWB_GLOBAL *Global,\r
367 IN BOOLEAN Virtual\r
368 )\r
369/*++\r
370\r
371Routine Description:\r
372 Reads specified number of bytes into a buffer from the specified block\r
373\r
374Arguments:\r
375 Instance - The FV instance to be read from\r
376 Lba - The logical block address to be read from\r
377 BlockOffset - Offset into the block at which to begin reading\r
378 NumBytes - Pointer that on input contains the total size of\r
379 the buffer. On output, it contains the total number\r
380 of bytes read\r
381 Buffer - Pointer to a caller allocated buffer that will be\r
382 used to hold the data read\r
383 Global - Pointer to ESAL_FWB_GLOBAL that contains all\r
384 instance data\r
385 Virtual - Whether CPU is in virtual or physical mode\r
386\r
387Returns: \r
388 EFI_SUCCESS - The firmware volume was read successfully and \r
389 contents are in Buffer\r
390 EFI_BAD_BUFFER_SIZE - Read attempted across a LBA boundary. On output,\r
391 NumBytes contains the total number of bytes returned\r
392 in Buffer\r
393 EFI_ACCESS_DENIED - The firmware volume is in the ReadDisabled state\r
394 EFI_DEVICE_ERROR - The block device is not functioning correctly and \r
395 could not be read\r
396 EFI_INVALID_PARAMETER - Instance not found, or NumBytes, Buffer are NULL\r
397\r
398--*/\r
399{\r
dfb8993c 400 EFI_FVB_ATTRIBUTES_2 Attributes;\r
804405e7 401 UINTN LbaAddress;\r
402 UINTN LbaLength;\r
403 EFI_STATUS Status;\r
404\r
405 //\r
406 // Check for invalid conditions\r
407 //\r
408 if ((NumBytes == NULL) || (Buffer == NULL)) {\r
409 return EFI_INVALID_PARAMETER;\r
410 }\r
411\r
412 if (*NumBytes == 0) {\r
413 return EFI_INVALID_PARAMETER;\r
414 }\r
415\r
416 Status = FvbGetLbaAddress (Instance, Lba, &LbaAddress, &LbaLength, NULL, Global, Virtual);\r
417 if (EFI_ERROR (Status)) {\r
418 return Status;\r
419 }\r
420 //\r
421 // Check if the FV is read enabled\r
422 //\r
423 FvbGetVolumeAttributes (Instance, &Attributes, Global, Virtual);\r
424\r
425 if ((Attributes & EFI_FVB2_READ_STATUS) == 0) {\r
426 return EFI_ACCESS_DENIED;\r
427 }\r
428 //\r
429 // Perform boundary checks and adjust NumBytes\r
430 //\r
431 if (BlockOffset > LbaLength) {\r
432 return EFI_INVALID_PARAMETER;\r
433 }\r
434\r
435 if (LbaLength < (*NumBytes + BlockOffset)) {\r
436 *NumBytes = (UINT32) (LbaLength - BlockOffset);\r
437 Status = EFI_BAD_BUFFER_SIZE;\r
438 }\r
439\r
440 CopyMem (Buffer, (UINT8 *) (LbaAddress + BlockOffset), (UINTN) (*NumBytes));\r
441\r
442 return Status;\r
443}\r
444\r
445EFI_STATUS\r
446FvbWriteBlock (\r
447 IN UINTN Instance,\r
448 IN EFI_LBA Lba,\r
449 IN UINTN BlockOffset,\r
450 IN OUT UINTN *NumBytes,\r
451 IN UINT8 *Buffer,\r
452 IN ESAL_FWB_GLOBAL *Global,\r
453 IN BOOLEAN Virtual\r
454 )\r
455/*++\r
456\r
457Routine Description:\r
458 Writes specified number of bytes from the input buffer to the block\r
459\r
460Arguments:\r
461 Instance - The FV instance to be written to\r
462 Lba - The starting logical block index to write to\r
463 BlockOffset - Offset into the block at which to begin writing\r
464 NumBytes - Pointer that on input contains the total size of\r
465 the buffer. On output, it contains the total number\r
466 of bytes actually written\r
467 Buffer - Pointer to a caller allocated buffer that contains\r
468 the source for the write\r
469 Global - Pointer to ESAL_FWB_GLOBAL that contains all\r
470 instance data\r
471 Virtual - Whether CPU is in virtual or physical mode\r
472\r
473Returns: \r
474 EFI_SUCCESS - The firmware volume was written successfully\r
475 EFI_BAD_BUFFER_SIZE - Write attempted across a LBA boundary. On output,\r
476 NumBytes contains the total number of bytes\r
477 actually written\r
478 EFI_ACCESS_DENIED - The firmware volume is in the WriteDisabled state\r
479 EFI_DEVICE_ERROR - The block device is not functioning correctly and \r
480 could not be written\r
481 EFI_INVALID_PARAMETER - Instance not found, or NumBytes, Buffer are NULL\r
482\r
483--*/\r
484{\r
dfb8993c 485 EFI_FVB_ATTRIBUTES_2 Attributes;\r
804405e7 486 UINTN LbaAddress;\r
487 UINTN LbaLength;\r
488 EFI_STATUS Status;\r
489\r
490 //\r
491 // Check for invalid conditions\r
492 //\r
493 if ((NumBytes == NULL) || (Buffer == NULL)) {\r
494 return EFI_INVALID_PARAMETER;\r
495 }\r
496\r
497 if (*NumBytes == 0) {\r
498 return EFI_INVALID_PARAMETER;\r
499 }\r
500\r
501 Status = FvbGetLbaAddress (Instance, Lba, &LbaAddress, &LbaLength, NULL, Global, Virtual);\r
502 if (EFI_ERROR (Status)) {\r
503 return Status;\r
504 }\r
505 //\r
506 // Check if the FV is write enabled\r
507 //\r
508 FvbGetVolumeAttributes (Instance, &Attributes, Global, Virtual);\r
509\r
510 if ((Attributes & EFI_FVB2_WRITE_STATUS) == 0) {\r
511 return EFI_ACCESS_DENIED;\r
512 }\r
513 //\r
514 // Perform boundary checks and adjust NumBytes\r
515 //\r
516 if (BlockOffset > LbaLength) {\r
517 return EFI_INVALID_PARAMETER;\r
518 }\r
519\r
520 if (LbaLength < (*NumBytes + BlockOffset)) {\r
521 *NumBytes = (UINT32) (LbaLength - BlockOffset);\r
522 Status = EFI_BAD_BUFFER_SIZE;\r
523 }\r
524 //\r
525 // Write data\r
526 //\r
527 CopyMem ((UINT8 *) (LbaAddress + BlockOffset), Buffer, (UINTN) (*NumBytes));\r
528\r
529 return Status;\r
530}\r
531\r
532EFI_STATUS\r
533FvbEraseBlock (\r
534 IN UINTN Instance,\r
535 IN EFI_LBA Lba,\r
536 IN ESAL_FWB_GLOBAL *Global,\r
537 IN BOOLEAN Virtual\r
538 )\r
539/*++\r
540\r
541Routine Description:\r
542 Erases and initializes a firmware volume block\r
543\r
544Arguments:\r
545 Instance - The FV instance to be erased\r
546 Lba - The logical block index to be erased\r
547 Global - Pointer to ESAL_FWB_GLOBAL that contains all\r
548 instance data\r
549 Virtual - Whether CPU is in virtual or physical mode\r
550\r
551Returns: \r
552 EFI_SUCCESS - The erase request was successfully completed\r
553 EFI_ACCESS_DENIED - The firmware volume is in the WriteDisabled state\r
554 EFI_DEVICE_ERROR - The block device is not functioning correctly and \r
555 could not be written. Firmware device may have been\r
556 partially erased\r
557 EFI_INVALID_PARAMETER - Instance not found\r
558\r
559--*/\r
560{\r
561\r
dfb8993c 562 EFI_FVB_ATTRIBUTES_2 Attributes;\r
7ee3b613
A
563 UINTN LbaAddress;\r
564 UINTN LbaLength;\r
565 EFI_STATUS Status;\r
566 UINT8 Data;\r
804405e7 567\r
568 //\r
569 // Check if the FV is write enabled\r
570 //\r
571 FvbGetVolumeAttributes (Instance, &Attributes, Global, Virtual);\r
572\r
573 if ((Attributes & EFI_FVB2_WRITE_STATUS) == 0) {\r
574 return EFI_ACCESS_DENIED;\r
575 }\r
576 //\r
577 // Get the starting address of the block for erase.\r
578 //\r
579 Status = FvbGetLbaAddress (Instance, Lba, &LbaAddress, &LbaLength, NULL, Global, Virtual);\r
580\r
581 if (EFI_ERROR (Status)) {\r
582 return Status;\r
583 }\r
584\r
585 if ((Attributes & EFI_FVB2_ERASE_POLARITY) != 0) {\r
586 Data = 0xFF;\r
587 } else {\r
588 Data = 0x0;\r
589 }\r
590\r
591 SetMem ((UINT8 *) LbaAddress, LbaLength, Data);\r
592\r
593 return EFI_SUCCESS;\r
594}\r
595\r
804405e7 596EFI_STATUS\r
597FvbSetVolumeAttributes (\r
598 IN UINTN Instance,\r
7ee3b613 599 IN OUT EFI_FVB_ATTRIBUTES_2 *Attributes,\r
804405e7 600 IN ESAL_FWB_GLOBAL *Global,\r
601 IN BOOLEAN Virtual\r
602 )\r
603/*++\r
604\r
605Routine Description:\r
606 Modifies the current settings of the firmware volume according to the \r
607 input parameter, and returns the new setting of the volume\r
608\r
609Arguments:\r
610 Instance - The FV instance whose attributes is going to be \r
611 modified\r
dfb8993c 612 Attributes - On input, it is a pointer to EFI_FVB_ATTRIBUTES_2 \r
804405e7 613 containing the desired firmware volume settings.\r
614 On successful return, it contains the new settings\r
615 of the firmware volume\r
616 Global - Pointer to ESAL_FWB_GLOBAL that contains all\r
617 instance data\r
618 Virtual - Whether CPU is in virtual or physical mode\r
619\r
620Returns: \r
621 EFI_SUCCESS - Successfully returns\r
622 EFI_ACCESS_DENIED - The volume setting is locked and cannot be modified\r
623 EFI_INVALID_PARAMETER - Instance not found, or The attributes requested are\r
624 in conflict with the capabilities as declared in the\r
625 firmware volume header\r
626\r
627--*/\r
628{\r
ccd55824 629 EFI_FW_VOL_INSTANCE *FwhInstance = NULL;\r
dfb8993c 630 EFI_FVB_ATTRIBUTES_2 OldAttributes;\r
631 EFI_FVB_ATTRIBUTES_2 *AttribPtr;\r
7ee3b613
A
632 UINT32 Capabilities;\r
633 UINT32 OldStatus;\r
634 UINT32 NewStatus;\r
635 EFI_STATUS Status;\r
dfb8993c 636 EFI_FVB_ATTRIBUTES_2 UnchangedAttributes;\r
804405e7 637\r
638\r
639 //\r
640 // Find the right instance of the FVB private data\r
641 //\r
642 Status = GetFvbInstance (Instance, Global, &FwhInstance, Virtual);\r
643 ASSERT_EFI_ERROR (Status);\r
644\r
dfb8993c 645 AttribPtr = (EFI_FVB_ATTRIBUTES_2 *) &(FwhInstance->VolumeHeader.Attributes);\r
804405e7 646 OldAttributes = *AttribPtr;\r
647 Capabilities = OldAttributes & (EFI_FVB2_READ_DISABLED_CAP | \\r
648 EFI_FVB2_READ_ENABLED_CAP | \\r
649 EFI_FVB2_WRITE_DISABLED_CAP | \\r
650 EFI_FVB2_WRITE_ENABLED_CAP | \\r
651 EFI_FVB2_LOCK_CAP \\r
652 );\r
653\r
654 OldStatus = OldAttributes & EFI_FVB2_STATUS;\r
655 NewStatus = *Attributes & EFI_FVB2_STATUS;\r
656 UnchangedAttributes = EFI_FVB2_READ_DISABLED_CAP | \\r
657 EFI_FVB2_READ_ENABLED_CAP | \\r
658 EFI_FVB2_WRITE_DISABLED_CAP | \\r
659 EFI_FVB2_WRITE_ENABLED_CAP | \\r
660 EFI_FVB2_LOCK_CAP | \\r
661 EFI_FVB2_STICKY_WRITE | \\r
662 EFI_FVB2_MEMORY_MAPPED | \\r
663 EFI_FVB2_ERASE_POLARITY | \\r
664 EFI_FVB2_READ_LOCK_CAP | \\r
665 EFI_FVB2_WRITE_LOCK_CAP | \\r
666 EFI_FVB2_ALIGNMENT;\r
667\r
668 //\r
669 // Some attributes of FV is read only can *not* be set\r
670 //\r
671 if ((OldAttributes & UnchangedAttributes) ^ (*Attributes & UnchangedAttributes)) {\r
672 return EFI_INVALID_PARAMETER;\r
673 }\r
674\r
675 //\r
676 // If firmware volume is locked, no status bit can be updated\r
677 //\r
678 if (OldAttributes & EFI_FVB2_LOCK_STATUS) {\r
679 if (OldStatus ^ NewStatus) {\r
680 return EFI_ACCESS_DENIED;\r
681 }\r
682 }\r
683 //\r
684 // Test read disable\r
685 //\r
686 if ((Capabilities & EFI_FVB2_READ_DISABLED_CAP) == 0) {\r
687 if ((NewStatus & EFI_FVB2_READ_STATUS) == 0) {\r
688 return EFI_INVALID_PARAMETER;\r
689 }\r
690 }\r
691 //\r
692 // Test read enable\r
693 //\r
694 if ((Capabilities & EFI_FVB2_READ_ENABLED_CAP) == 0) {\r
695 if (NewStatus & EFI_FVB2_READ_STATUS) {\r
696 return EFI_INVALID_PARAMETER;\r
697 }\r
698 }\r
699 //\r
700 // Test write disable\r
701 //\r
702 if ((Capabilities & EFI_FVB2_WRITE_DISABLED_CAP) == 0) {\r
703 if ((NewStatus & EFI_FVB2_WRITE_STATUS) == 0) {\r
704 return EFI_INVALID_PARAMETER;\r
705 }\r
706 }\r
707 //\r
708 // Test write enable\r
709 //\r
710 if ((Capabilities & EFI_FVB2_WRITE_ENABLED_CAP) == 0) {\r
711 if (NewStatus & EFI_FVB2_WRITE_STATUS) {\r
712 return EFI_INVALID_PARAMETER;\r
713 }\r
714 }\r
715 //\r
716 // Test lock\r
717 //\r
718 if ((Capabilities & EFI_FVB2_LOCK_CAP) == 0) {\r
719 if (NewStatus & EFI_FVB2_LOCK_STATUS) {\r
720 return EFI_INVALID_PARAMETER;\r
721 }\r
722 }\r
723\r
724 *AttribPtr = (*AttribPtr) & (0xFFFFFFFF & (~EFI_FVB2_STATUS));\r
725 *AttribPtr = (*AttribPtr) | NewStatus;\r
726 *Attributes = *AttribPtr;\r
727\r
728 return EFI_SUCCESS;\r
729}\r
730//\r
731// FVB protocol APIs\r
732//\r
733EFI_STATUS\r
734EFIAPI\r
735FvbProtocolGetPhysicalAddress (\r
ccd55824 736 IN CONST EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL *This,\r
804405e7 737 OUT EFI_PHYSICAL_ADDRESS *Address\r
738 )\r
739/*++\r
740\r
741Routine Description:\r
742\r
743 Retrieves the physical address of the device.\r
744\r
745Arguments:\r
746\r
747 This - Calling context\r
748 Address - Output buffer containing the address.\r
749\r
750Returns:\r
751\r
752Returns: \r
753 EFI_SUCCESS - Successfully returns\r
754\r
755--*/\r
756{\r
757 EFI_FW_VOL_BLOCK_DEVICE *FvbDevice;\r
758\r
759 FvbDevice = FVB_DEVICE_FROM_THIS (This);\r
760\r
761 return FvbGetPhysicalAddress (FvbDevice->Instance, Address, mFvbModuleGlobal, EfiGoneVirtual ());\r
762}\r
763\r
764EFI_STATUS\r
765EFIAPI\r
766FvbProtocolGetBlockSize (\r
ccd55824 767 IN CONST EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL *This,\r
e89bb669 768 IN EFI_LBA Lba,\r
804405e7 769 OUT UINTN *BlockSize,\r
770 OUT UINTN *NumOfBlocks\r
771 )\r
772/*++\r
773\r
774Routine Description:\r
775 Retrieve the size of a logical block\r
776\r
777Arguments:\r
778 This - Calling context\r
779 Lba - Indicates which block to return the size for.\r
780 BlockSize - A pointer to a caller allocated UINTN in which\r
781 the size of the block is returned\r
782 NumOfBlocks - a pointer to a caller allocated UINTN in which the\r
783 number of consecutive blocks starting with Lba is\r
784 returned. All blocks in this range have a size of\r
785 BlockSize\r
786\r
787Returns: \r
788 EFI_SUCCESS - The firmware volume was read successfully and \r
789 contents are in Buffer\r
790\r
791--*/\r
792{\r
793 EFI_FW_VOL_BLOCK_DEVICE *FvbDevice;\r
794\r
795 FvbDevice = FVB_DEVICE_FROM_THIS (This);\r
796\r
797 return FvbGetLbaAddress (\r
798 FvbDevice->Instance,\r
799 Lba,\r
800 NULL,\r
801 BlockSize,\r
802 NumOfBlocks,\r
803 mFvbModuleGlobal,\r
804 EfiGoneVirtual ()\r
805 );\r
806}\r
807\r
808EFI_STATUS\r
809EFIAPI\r
810FvbProtocolGetAttributes (\r
ccd55824 811 IN CONST EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL *This,\r
7ee3b613 812 OUT EFI_FVB_ATTRIBUTES_2 *Attributes\r
804405e7 813 )\r
814/*++\r
815\r
816Routine Description:\r
817 Retrieves Volume attributes. No polarity translations are done.\r
818\r
819Arguments:\r
820 This - Calling context\r
821 Attributes - output buffer which contains attributes\r
822\r
823Returns: \r
824 EFI_SUCCESS - Successfully returns\r
825\r
826--*/\r
827{\r
828 EFI_FW_VOL_BLOCK_DEVICE *FvbDevice;\r
829\r
830 FvbDevice = FVB_DEVICE_FROM_THIS (This);\r
831\r
832 return FvbGetVolumeAttributes (FvbDevice->Instance, Attributes, mFvbModuleGlobal, EfiGoneVirtual ());\r
833}\r
834\r
835EFI_STATUS\r
836EFIAPI\r
837FvbProtocolSetAttributes (\r
ccd55824 838 IN CONST EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL *This,\r
7ee3b613 839 IN OUT EFI_FVB_ATTRIBUTES_2 *Attributes\r
804405e7 840 )\r
841/*++\r
842\r
843Routine Description:\r
844 Sets Volume attributes. No polarity translations are done.\r
845\r
846Arguments:\r
847 This - Calling context\r
848 Attributes - output buffer which contains attributes\r
849\r
850Returns: \r
851 EFI_SUCCESS - Successfully returns\r
852\r
853--*/\r
854{\r
855 EFI_FW_VOL_BLOCK_DEVICE *FvbDevice;\r
856\r
857 FvbDevice = FVB_DEVICE_FROM_THIS (This);\r
858\r
859 return FvbSetVolumeAttributes (FvbDevice->Instance, Attributes, mFvbModuleGlobal, EfiGoneVirtual ());\r
860}\r
861\r
862EFI_STATUS\r
863EFIAPI\r
864FvbProtocolEraseBlocks (\r
ccd55824 865 IN CONST EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL *This,\r
804405e7 866 ... \r
867 )\r
868/*++\r
869\r
870Routine Description:\r
871\r
872 The EraseBlock() function erases one or more blocks as denoted by the \r
873 variable argument list. The entire parameter list of blocks must be verified\r
874 prior to erasing any blocks. If a block is requested that does not exist \r
875 within the associated firmware volume (it has a larger index than the last \r
876 block of the firmware volume), the EraseBlock() function must return\r
877 EFI_INVALID_PARAMETER without modifying the contents of the firmware volume.\r
878\r
879Arguments:\r
880 This - Calling context\r
881 ... - Starting LBA followed by Number of Lba to erase. \r
882 a -1 to terminate the list.\r
883\r
884Returns: \r
885 EFI_SUCCESS - The erase request was successfully completed\r
886 EFI_ACCESS_DENIED - The firmware volume is in the WriteDisabled state\r
887 EFI_DEVICE_ERROR - The block device is not functioning correctly and \r
888 could not be written. Firmware device may have been\r
889 partially erased\r
890\r
891--*/\r
892{\r
893 EFI_FW_VOL_BLOCK_DEVICE *FvbDevice;\r
ccd55824 894 EFI_FW_VOL_INSTANCE *FwhInstance = NULL;\r
804405e7 895 UINTN NumOfBlocks;\r
896 VA_LIST args;\r
897 EFI_LBA StartingLba;\r
898 UINTN NumOfLba;\r
899 EFI_STATUS Status;\r
900\r
901 FvbDevice = FVB_DEVICE_FROM_THIS (This);\r
902\r
903 Status = GetFvbInstance (FvbDevice->Instance, mFvbModuleGlobal, &FwhInstance, EfiGoneVirtual ());\r
904 ASSERT_EFI_ERROR (Status);\r
905\r
906 NumOfBlocks = FwhInstance->NumOfBlocks;\r
907\r
908 VA_START (args, This);\r
909\r
910 do {\r
911 StartingLba = VA_ARG (args, EFI_LBA);\r
912 if (StartingLba == EFI_LBA_LIST_TERMINATOR) {\r
913 break;\r
914 }\r
915\r
916 NumOfLba = VA_ARG (args, UINT32);\r
917\r
918 //\r
919 // Check input parameters\r
920 //\r
3bbe68a3 921 if (NumOfLba == 0 || (StartingLba + NumOfLba) > NumOfBlocks) {\r
804405e7 922 VA_END (args);\r
923 return EFI_INVALID_PARAMETER;\r
924 }\r
804405e7 925 } while (1);\r
926\r
927 VA_END (args);\r
928\r
929 VA_START (args, This);\r
930 do {\r
931 StartingLba = VA_ARG (args, EFI_LBA);\r
932 if (StartingLba == EFI_LBA_LIST_TERMINATOR) {\r
933 break;\r
934 }\r
935\r
936 NumOfLba = VA_ARG (args, UINT32);\r
937\r
938 while (NumOfLba > 0) {\r
939 Status = FvbEraseBlock (FvbDevice->Instance, StartingLba, mFvbModuleGlobal, EfiGoneVirtual ());\r
940 if (EFI_ERROR (Status)) {\r
941 VA_END (args);\r
942 return Status;\r
943 }\r
944\r
945 StartingLba++;\r
946 NumOfLba--;\r
947 }\r
948\r
949 } while (1);\r
950\r
951 VA_END (args);\r
952\r
953 return EFI_SUCCESS;\r
954}\r
955\r
956EFI_STATUS\r
957EFIAPI\r
958FvbProtocolWrite (\r
ccd55824 959 IN CONST EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL *This,\r
804405e7 960 IN EFI_LBA Lba,\r
961 IN UINTN Offset,\r
962 IN OUT UINTN *NumBytes,\r
963 IN UINT8 *Buffer\r
964 )\r
965/*++\r
966\r
967Routine Description:\r
968\r
969 Writes data beginning at Lba:Offset from FV. The write terminates either\r
970 when *NumBytes of data have been written, or when a block boundary is\r
971 reached. *NumBytes is updated to reflect the actual number of bytes\r
972 written. The write opertion does not include erase. This routine will\r
973 attempt to write only the specified bytes. If the writes do not stick,\r
974 it will return an error.\r
975\r
976Arguments:\r
977 This - Calling context\r
978 Lba - Block in which to begin write\r
979 Offset - Offset in the block at which to begin write\r
980 NumBytes - On input, indicates the requested write size. On\r
981 output, indicates the actual number of bytes written\r
982 Buffer - Buffer containing source data for the write.\r
983\r
984Returns: \r
985 EFI_SUCCESS - The firmware volume was written successfully\r
986 EFI_BAD_BUFFER_SIZE - Write attempted across a LBA boundary. On output,\r
987 NumBytes contains the total number of bytes\r
988 actually written\r
989 EFI_ACCESS_DENIED - The firmware volume is in the WriteDisabled state\r
990 EFI_DEVICE_ERROR - The block device is not functioning correctly and \r
991 could not be written\r
992 EFI_INVALID_PARAMETER - NumBytes or Buffer are NULL\r
993\r
994--*/\r
995{\r
996\r
997 EFI_FW_VOL_BLOCK_DEVICE *FvbDevice;\r
998\r
999 FvbDevice = FVB_DEVICE_FROM_THIS (This);\r
1000\r
e89bb669 1001 return FvbWriteBlock (FvbDevice->Instance, Lba, Offset, NumBytes, Buffer, mFvbModuleGlobal, EfiGoneVirtual ());\r
804405e7 1002}\r
1003\r
1004EFI_STATUS\r
1005EFIAPI\r
1006FvbProtocolRead (\r
ccd55824 1007 IN CONST EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL *This,\r
e89bb669 1008 IN EFI_LBA Lba,\r
1009 IN UINTN Offset,\r
804405e7 1010 IN OUT UINTN *NumBytes,\r
1011 IN UINT8 *Buffer\r
1012 )\r
1013/*++\r
1014\r
1015Routine Description:\r
1016\r
1017 Reads data beginning at Lba:Offset from FV. The Read terminates either\r
1018 when *NumBytes of data have been read, or when a block boundary is\r
1019 reached. *NumBytes is updated to reflect the actual number of bytes\r
1020 written. The write opertion does not include erase. This routine will\r
1021 attempt to write only the specified bytes. If the writes do not stick,\r
1022 it will return an error.\r
1023\r
1024Arguments:\r
1025 This - Calling context\r
1026 Lba - Block in which to begin Read\r
1027 Offset - Offset in the block at which to begin Read\r
1028 NumBytes - On input, indicates the requested write size. On\r
1029 output, indicates the actual number of bytes Read\r
1030 Buffer - Buffer containing source data for the Read.\r
1031\r
1032Returns: \r
1033 EFI_SUCCESS - The firmware volume was read successfully and \r
1034 contents are in Buffer\r
1035 EFI_BAD_BUFFER_SIZE - Read attempted across a LBA boundary. On output,\r
1036 NumBytes contains the total number of bytes returned\r
1037 in Buffer\r
1038 EFI_ACCESS_DENIED - The firmware volume is in the ReadDisabled state\r
1039 EFI_DEVICE_ERROR - The block device is not functioning correctly and \r
1040 could not be read\r
1041 EFI_INVALID_PARAMETER - NumBytes or Buffer are NULL\r
1042\r
1043--*/\r
1044{\r
1045\r
1046 EFI_FW_VOL_BLOCK_DEVICE *FvbDevice;\r
1047\r
1048 FvbDevice = FVB_DEVICE_FROM_THIS (This);\r
1049\r
1050 return FvbReadBlock (FvbDevice->Instance, Lba, Offset, NumBytes, Buffer, mFvbModuleGlobal, EfiGoneVirtual ());\r
1051}\r
804405e7 1052EFI_STATUS\r
1053ValidateFvHeader (\r
1054 EFI_FIRMWARE_VOLUME_HEADER *FwVolHeader\r
1055 )\r
1056/*++\r
1057\r
1058Routine Description:\r
1059 Check the integrity of firmware volume header\r
1060\r
1061Arguments:\r
1062 FwVolHeader - A pointer to a firmware volume header\r
1063\r
1064Returns: \r
1065 EFI_SUCCESS - The firmware volume is consistent\r
1066 EFI_NOT_FOUND - The firmware volume has corrupted. So it is not an FV\r
1067\r
1068--*/\r
1069{\r
1070 UINT16 *Ptr;\r
1071 UINT16 HeaderLength;\r
1072 UINT16 Checksum;\r
1073\r
1074 //\r
1075 // Verify the header revision, header signature, length\r
1076 // Length of FvBlock cannot be 2**64-1\r
1077 // HeaderLength cannot be an odd number\r
1078 //\r
1079 if ((FwVolHeader->Revision != EFI_FVH_REVISION) ||\r
1080 (FwVolHeader->Signature != EFI_FVH_SIGNATURE) ||\r
1081 (FwVolHeader->FvLength == ((UINTN) -1)) ||\r
1082 ((FwVolHeader->HeaderLength & 0x01) != 0)\r
1083 ) {\r
1084 return EFI_NOT_FOUND;\r
1085 }\r
1086 //\r
1087 // Verify the header checksum\r
1088 //\r
1089 HeaderLength = (UINT16) (FwVolHeader->HeaderLength / 2);\r
1090 Ptr = (UINT16 *) FwVolHeader;\r
1091 Checksum = 0;\r
1092 while (HeaderLength > 0) {\r
e89bb669 1093 Checksum = Checksum + (*Ptr);\r
804405e7 1094 HeaderLength--;\r
1095 Ptr++;\r
1096 }\r
1097\r
1098 if (Checksum != 0) {\r
1099 return EFI_NOT_FOUND;\r
1100 }\r
1101\r
1102 return EFI_SUCCESS;\r
1103}\r
1104\r
1105EFI_STATUS\r
1106EFIAPI\r
1107FvbInitialize (\r
1108 IN EFI_HANDLE ImageHandle,\r
1109 IN EFI_SYSTEM_TABLE *SystemTable\r
1110 )\r
1111/*++\r
1112\r
1113Routine Description:\r
1114 This function does common initialization for FVB services\r
1115\r
1116Arguments:\r
1117\r
1118Returns:\r
1119\r
1120--*/\r
1121{\r
1122 EFI_STATUS Status;\r
ccd55824 1123 EFI_FW_VOL_INSTANCE *FwhInstance = NULL;\r
804405e7 1124 EFI_FIRMWARE_VOLUME_HEADER *FwVolHeader;\r
1125 EFI_DXE_SERVICES *DxeServices;\r
1126 EFI_GCD_MEMORY_SPACE_DESCRIPTOR Descriptor;\r
1127 UINT32 BufferSize;\r
1128 EFI_FV_BLOCK_MAP_ENTRY *PtrBlockMapEntry;\r
1129 EFI_HANDLE FwbHandle;\r
1130 EFI_FW_VOL_BLOCK_DEVICE *FvbDevice;\r
1131 EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL *OldFwbInterface;\r
1132 EFI_DEVICE_PATH_PROTOCOL *TempFwbDevicePath;\r
1133 FV_DEVICE_PATH TempFvbDevicePathData;\r
1134 UINT32 MaxLbaSize;\r
1135 EFI_PHYSICAL_ADDRESS BaseAddress;\r
1136 UINT64 Length;\r
1137 UINTN NumOfBlocks;\r
1138 EFI_PEI_HOB_POINTERS FvHob;\r
1139\r
1140 //\r
1141 // Get the DXE services table\r
1142 //\r
1143 DxeServices = gDS;\r
1144\r
1145 //\r
1146 // Allocate runtime services data for global variable, which contains\r
1147 // the private data of all firmware volume block instances\r
1148 //\r
e89bb669 1149 Status = gBS->AllocatePool (\r
1150 EfiRuntimeServicesData,\r
1151 sizeof (ESAL_FWB_GLOBAL),\r
1152 (VOID**) &mFvbModuleGlobal\r
1153 );\r
1154 ASSERT_EFI_ERROR (Status);\r
804405e7 1155\r
1156 //\r
1157 // Calculate the total size for all firmware volume block instances\r
1158 //\r
1159 BufferSize = 0;\r
1160\r
1161 FvHob.Raw = GetHobList ();\r
1162 while ((FvHob.Raw = GetNextHob (EFI_HOB_TYPE_FV, FvHob.Raw)) != NULL) {\r
1163 BaseAddress = FvHob.FirmwareVolume->BaseAddress;\r
1164 Length = FvHob.FirmwareVolume->Length;\r
1165 //\r
1166 // Check if it is a "real" flash\r
1167 //\r
1168 Status = DxeServices->GetMemorySpaceDescriptor (\r
1169 BaseAddress,\r
1170 &Descriptor\r
1171 );\r
1172 if (EFI_ERROR (Status)) {\r
1173 break;\r
1174 }\r
1175\r
1176 if (Descriptor.GcdMemoryType != EfiGcdMemoryTypeMemoryMappedIo) {\r
1177 FvHob.Raw = GET_NEXT_HOB (FvHob);\r
1178 continue;\r
1179 }\r
1180\r
1181 FwVolHeader = (EFI_FIRMWARE_VOLUME_HEADER *) (UINTN) BaseAddress;\r
1182 Status = ValidateFvHeader (FwVolHeader);\r
1183 if (EFI_ERROR (Status)) {\r
1184 //\r
1185 // Get FvbInfo\r
1186 //\r
1187 Status = GetFvbInfo (Length, &FwVolHeader);\r
1188 if (EFI_ERROR (Status)) {\r
1189 FvHob.Raw = GET_NEXT_HOB (FvHob);\r
1190 continue;\r
1191 }\r
1192 }\r
1193\r
1194 BufferSize += (sizeof (EFI_FW_VOL_INSTANCE) + FwVolHeader->HeaderLength - sizeof (EFI_FIRMWARE_VOLUME_HEADER));\r
1195 FvHob.Raw = GET_NEXT_HOB (FvHob);\r
1196 }\r
1197\r
1198 //\r
1199 // Only need to allocate once. There is only one copy of physical memory for\r
1200 // the private data of each FV instance. But in virtual mode or in physical\r
1201 // mode, the address of the the physical memory may be different.\r
1202 //\r
e89bb669 1203 Status = gBS->AllocatePool (\r
1204 EfiRuntimeServicesData,\r
1205 BufferSize,\r
1206 (VOID**) &mFvbModuleGlobal->FvInstance[FVB_PHYSICAL]\r
1207 );\r
1208 ASSERT_EFI_ERROR (Status);\r
804405e7 1209\r
1210 //\r
1211 // Make a virtual copy of the FvInstance pointer.\r
1212 //\r
1213 FwhInstance = mFvbModuleGlobal->FvInstance[FVB_PHYSICAL];\r
1214 mFvbModuleGlobal->FvInstance[FVB_VIRTUAL] = FwhInstance;\r
1215\r
1216 mFvbModuleGlobal->NumFv = 0;\r
1217 MaxLbaSize = 0;\r
1218\r
1219 FvHob.Raw = GetHobList ();\r
1220 while (NULL != (FvHob.Raw = GetNextHob (EFI_HOB_TYPE_FV, FvHob.Raw))) {\r
1221 BaseAddress = FvHob.FirmwareVolume->BaseAddress;\r
1222 Length = FvHob.FirmwareVolume->Length;\r
1223 //\r
1224 // Check if it is a "real" flash\r
1225 //\r
1226 Status = DxeServices->GetMemorySpaceDescriptor (\r
1227 BaseAddress,\r
1228 &Descriptor\r
1229 );\r
1230 if (EFI_ERROR (Status)) {\r
1231 break;\r
1232 }\r
1233\r
1234 if (Descriptor.GcdMemoryType != EfiGcdMemoryTypeMemoryMappedIo) {\r
1235 FvHob.Raw = GET_NEXT_HOB (FvHob);\r
1236 continue;\r
1237 }\r
1238\r
1239 FwVolHeader = (EFI_FIRMWARE_VOLUME_HEADER *) (UINTN) BaseAddress;\r
1240 Status = ValidateFvHeader (FwVolHeader);\r
1241 if (EFI_ERROR (Status)) {\r
1242 //\r
1243 // Get FvbInfo to provide in FwhInstance.\r
1244 //\r
1245 Status = GetFvbInfo (Length, &FwVolHeader);\r
1246 if (EFI_ERROR (Status)) {\r
1247 FvHob.Raw = GET_NEXT_HOB (FvHob);\r
1248 continue;\r
1249 }\r
1250 //\r
1251 // Write healthy FV header back.\r
1252 //\r
1253 CopyMem (\r
1254 (VOID *) (UINTN) BaseAddress,\r
1255 (VOID *) FwVolHeader,\r
1256 FwVolHeader->HeaderLength\r
1257 );\r
1258 }\r
1259\r
1260 FwhInstance->FvBase[FVB_PHYSICAL] = (UINTN) BaseAddress;\r
1261 FwhInstance->FvBase[FVB_VIRTUAL] = (UINTN) BaseAddress;\r
1262\r
1263 CopyMem ((UINTN *) &(FwhInstance->VolumeHeader), (UINTN *) FwVolHeader, FwVolHeader->HeaderLength);\r
1264 FwVolHeader = &(FwhInstance->VolumeHeader);\r
1265 EfiInitializeLock (&(FwhInstance->FvbDevLock), TPL_HIGH_LEVEL);\r
1266\r
1267 NumOfBlocks = 0;\r
1268\r
1269 for (PtrBlockMapEntry = FwVolHeader->BlockMap; PtrBlockMapEntry->NumBlocks != 0; PtrBlockMapEntry++) {\r
1270 //\r
1271 // Get the maximum size of a block. The size will be used to allocate\r
1272 // buffer for Scratch space, the intermediate buffer for FVB extension\r
1273 // protocol\r
1274 //\r
1275 if (MaxLbaSize < PtrBlockMapEntry->Length) {\r
1276 MaxLbaSize = PtrBlockMapEntry->Length;\r
1277 }\r
1278\r
1279 NumOfBlocks = NumOfBlocks + PtrBlockMapEntry->NumBlocks;\r
1280 }\r
1281 //\r
1282 // The total number of blocks in the FV.\r
1283 //\r
1284 FwhInstance->NumOfBlocks = NumOfBlocks;\r
1285\r
1286 //\r
1287 // Add a FVB Protocol Instance\r
1288 //\r
e89bb669 1289 Status = gBS->AllocatePool (\r
1290 EfiRuntimeServicesData,\r
1291 sizeof (EFI_FW_VOL_BLOCK_DEVICE),\r
1292 (VOID**) &FvbDevice\r
1293 );\r
1294 ASSERT_EFI_ERROR (Status);\r
804405e7 1295\r
1296 CopyMem (FvbDevice, &mFvbDeviceTemplate, sizeof (EFI_FW_VOL_BLOCK_DEVICE));\r
1297\r
1298 FvbDevice->Instance = mFvbModuleGlobal->NumFv;\r
1299 mFvbModuleGlobal->NumFv++;\r
1300\r
1301 //\r
1302 // Set up the devicepath\r
1303 //\r
1304 FvbDevice->DevicePath.MemMapDevPath.StartingAddress = BaseAddress;\r
1305 FvbDevice->DevicePath.MemMapDevPath.EndingAddress = BaseAddress + (FwVolHeader->FvLength - 1);\r
1306\r
1307 //\r
1308 // Find a handle with a matching device path that has supports FW Block protocol\r
1309 //\r
1310 TempFwbDevicePath = (EFI_DEVICE_PATH_PROTOCOL *) &TempFvbDevicePathData;\r
1311 CopyMem (TempFwbDevicePath, &FvbDevice->DevicePath, sizeof (FV_DEVICE_PATH));\r
1312 Status = gBS->LocateDevicePath (&gEfiFirmwareVolumeBlockProtocolGuid, &TempFwbDevicePath, &FwbHandle);\r
1313 if (EFI_ERROR (Status)) {\r
1314 //\r
1315 // LocateDevicePath fails so install a new interface and device path\r
1316 //\r
1317 FwbHandle = NULL;\r
1318 Status = gBS->InstallMultipleProtocolInterfaces (\r
1319 &FwbHandle,\r
1320 &gEfiFirmwareVolumeBlockProtocolGuid,\r
1321 &FvbDevice->FwVolBlockInstance,\r
1322 &gEfiDevicePathProtocolGuid,\r
1323 &FvbDevice->DevicePath,\r
1324 NULL\r
1325 );\r
1326 ASSERT_EFI_ERROR (Status);\r
9f0b86b7 1327 } else if (IsDevicePathEnd (TempFwbDevicePath)) {\r
804405e7 1328 //\r
1329 // Device allready exists, so reinstall the FVB protocol\r
1330 //\r
1331 Status = gBS->HandleProtocol (\r
1332 FwbHandle,\r
1333 &gEfiFirmwareVolumeBlockProtocolGuid,\r
1334 (VOID**)&OldFwbInterface\r
1335 );\r
1336 ASSERT_EFI_ERROR (Status);\r
1337\r
1338 Status = gBS->ReinstallProtocolInterface (\r
1339 FwbHandle,\r
1340 &gEfiFirmwareVolumeBlockProtocolGuid,\r
1341 OldFwbInterface,\r
1342 &FvbDevice->FwVolBlockInstance\r
1343 );\r
1344 ASSERT_EFI_ERROR (Status);\r
1345\r
1346 } else {\r
1347 //\r
1348 // There was a FVB protocol on an End Device Path node\r
1349 //\r
1350 ASSERT (FALSE);\r
1351 }\r
e9cf53f2 1352\r
804405e7 1353 FwhInstance = (EFI_FW_VOL_INSTANCE *)\r
1354 (\r
1355 (UINTN) ((UINT8 *) FwhInstance) + FwVolHeader->HeaderLength +\r
1356 (sizeof (EFI_FW_VOL_INSTANCE) - sizeof (EFI_FIRMWARE_VOLUME_HEADER))\r
1357 );\r
1358\r
1359 FvHob.Raw = GET_NEXT_HOB (FvHob);\r
1360 }\r
1361\r
804405e7 1362 return EFI_SUCCESS;\r
1363}\r