]> git.proxmox.com Git - mirror_edk2.git/blame - UnixPkg/FvbServicesRuntimeDxe/FWBlockService.c
Update the copyright notice format
[mirror_edk2.git] / UnixPkg / FvbServicesRuntimeDxe / FWBlockService.c
CommitLineData
804405e7 1/*++\r
2\r
f9b8ab56
HT
3Copyright (c) 2006 - 2009, Intel Corporation. All rights reserved.<BR>\r
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
921 if (NumOfLba == 0) {\r
922 VA_END (args);\r
923 return EFI_INVALID_PARAMETER;\r
924 }\r
925\r
926 if ((StartingLba + NumOfLba) > NumOfBlocks) {\r
927 return EFI_INVALID_PARAMETER;\r
928 }\r
929 } while (1);\r
930\r
931 VA_END (args);\r
932\r
933 VA_START (args, This);\r
934 do {\r
935 StartingLba = VA_ARG (args, EFI_LBA);\r
936 if (StartingLba == EFI_LBA_LIST_TERMINATOR) {\r
937 break;\r
938 }\r
939\r
940 NumOfLba = VA_ARG (args, UINT32);\r
941\r
942 while (NumOfLba > 0) {\r
943 Status = FvbEraseBlock (FvbDevice->Instance, StartingLba, mFvbModuleGlobal, EfiGoneVirtual ());\r
944 if (EFI_ERROR (Status)) {\r
945 VA_END (args);\r
946 return Status;\r
947 }\r
948\r
949 StartingLba++;\r
950 NumOfLba--;\r
951 }\r
952\r
953 } while (1);\r
954\r
955 VA_END (args);\r
956\r
957 return EFI_SUCCESS;\r
958}\r
959\r
960EFI_STATUS\r
961EFIAPI\r
962FvbProtocolWrite (\r
ccd55824 963 IN CONST EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL *This,\r
804405e7 964 IN EFI_LBA Lba,\r
965 IN UINTN Offset,\r
966 IN OUT UINTN *NumBytes,\r
967 IN UINT8 *Buffer\r
968 )\r
969/*++\r
970\r
971Routine Description:\r
972\r
973 Writes data beginning at Lba:Offset from FV. The write terminates either\r
974 when *NumBytes of data have been written, or when a block boundary is\r
975 reached. *NumBytes is updated to reflect the actual number of bytes\r
976 written. The write opertion does not include erase. This routine will\r
977 attempt to write only the specified bytes. If the writes do not stick,\r
978 it will return an error.\r
979\r
980Arguments:\r
981 This - Calling context\r
982 Lba - Block in which to begin write\r
983 Offset - Offset in the block at which to begin write\r
984 NumBytes - On input, indicates the requested write size. On\r
985 output, indicates the actual number of bytes written\r
986 Buffer - Buffer containing source data for the write.\r
987\r
988Returns: \r
989 EFI_SUCCESS - The firmware volume was written successfully\r
990 EFI_BAD_BUFFER_SIZE - Write attempted across a LBA boundary. On output,\r
991 NumBytes contains the total number of bytes\r
992 actually written\r
993 EFI_ACCESS_DENIED - The firmware volume is in the WriteDisabled state\r
994 EFI_DEVICE_ERROR - The block device is not functioning correctly and \r
995 could not be written\r
996 EFI_INVALID_PARAMETER - NumBytes or Buffer are NULL\r
997\r
998--*/\r
999{\r
1000\r
1001 EFI_FW_VOL_BLOCK_DEVICE *FvbDevice;\r
1002\r
1003 FvbDevice = FVB_DEVICE_FROM_THIS (This);\r
1004\r
e89bb669 1005 return FvbWriteBlock (FvbDevice->Instance, Lba, Offset, NumBytes, Buffer, mFvbModuleGlobal, EfiGoneVirtual ());\r
804405e7 1006}\r
1007\r
1008EFI_STATUS\r
1009EFIAPI\r
1010FvbProtocolRead (\r
ccd55824 1011 IN CONST EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL *This,\r
e89bb669 1012 IN EFI_LBA Lba,\r
1013 IN UINTN Offset,\r
804405e7 1014 IN OUT UINTN *NumBytes,\r
1015 IN UINT8 *Buffer\r
1016 )\r
1017/*++\r
1018\r
1019Routine Description:\r
1020\r
1021 Reads data beginning at Lba:Offset from FV. The Read terminates either\r
1022 when *NumBytes of data have been read, or when a block boundary is\r
1023 reached. *NumBytes is updated to reflect the actual number of bytes\r
1024 written. The write opertion does not include erase. This routine will\r
1025 attempt to write only the specified bytes. If the writes do not stick,\r
1026 it will return an error.\r
1027\r
1028Arguments:\r
1029 This - Calling context\r
1030 Lba - Block in which to begin Read\r
1031 Offset - Offset in the block at which to begin Read\r
1032 NumBytes - On input, indicates the requested write size. On\r
1033 output, indicates the actual number of bytes Read\r
1034 Buffer - Buffer containing source data for the Read.\r
1035\r
1036Returns: \r
1037 EFI_SUCCESS - The firmware volume was read successfully and \r
1038 contents are in Buffer\r
1039 EFI_BAD_BUFFER_SIZE - Read attempted across a LBA boundary. On output,\r
1040 NumBytes contains the total number of bytes returned\r
1041 in Buffer\r
1042 EFI_ACCESS_DENIED - The firmware volume is in the ReadDisabled state\r
1043 EFI_DEVICE_ERROR - The block device is not functioning correctly and \r
1044 could not be read\r
1045 EFI_INVALID_PARAMETER - NumBytes or Buffer are NULL\r
1046\r
1047--*/\r
1048{\r
1049\r
1050 EFI_FW_VOL_BLOCK_DEVICE *FvbDevice;\r
1051\r
1052 FvbDevice = FVB_DEVICE_FROM_THIS (This);\r
1053\r
1054 return FvbReadBlock (FvbDevice->Instance, Lba, Offset, NumBytes, Buffer, mFvbModuleGlobal, EfiGoneVirtual ());\r
1055}\r
804405e7 1056EFI_STATUS\r
1057ValidateFvHeader (\r
1058 EFI_FIRMWARE_VOLUME_HEADER *FwVolHeader\r
1059 )\r
1060/*++\r
1061\r
1062Routine Description:\r
1063 Check the integrity of firmware volume header\r
1064\r
1065Arguments:\r
1066 FwVolHeader - A pointer to a firmware volume header\r
1067\r
1068Returns: \r
1069 EFI_SUCCESS - The firmware volume is consistent\r
1070 EFI_NOT_FOUND - The firmware volume has corrupted. So it is not an FV\r
1071\r
1072--*/\r
1073{\r
1074 UINT16 *Ptr;\r
1075 UINT16 HeaderLength;\r
1076 UINT16 Checksum;\r
1077\r
1078 //\r
1079 // Verify the header revision, header signature, length\r
1080 // Length of FvBlock cannot be 2**64-1\r
1081 // HeaderLength cannot be an odd number\r
1082 //\r
1083 if ((FwVolHeader->Revision != EFI_FVH_REVISION) ||\r
1084 (FwVolHeader->Signature != EFI_FVH_SIGNATURE) ||\r
1085 (FwVolHeader->FvLength == ((UINTN) -1)) ||\r
1086 ((FwVolHeader->HeaderLength & 0x01) != 0)\r
1087 ) {\r
1088 return EFI_NOT_FOUND;\r
1089 }\r
1090 //\r
1091 // Verify the header checksum\r
1092 //\r
1093 HeaderLength = (UINT16) (FwVolHeader->HeaderLength / 2);\r
1094 Ptr = (UINT16 *) FwVolHeader;\r
1095 Checksum = 0;\r
1096 while (HeaderLength > 0) {\r
e89bb669 1097 Checksum = Checksum + (*Ptr);\r
804405e7 1098 HeaderLength--;\r
1099 Ptr++;\r
1100 }\r
1101\r
1102 if (Checksum != 0) {\r
1103 return EFI_NOT_FOUND;\r
1104 }\r
1105\r
1106 return EFI_SUCCESS;\r
1107}\r
1108\r
1109EFI_STATUS\r
1110EFIAPI\r
1111FvbInitialize (\r
1112 IN EFI_HANDLE ImageHandle,\r
1113 IN EFI_SYSTEM_TABLE *SystemTable\r
1114 )\r
1115/*++\r
1116\r
1117Routine Description:\r
1118 This function does common initialization for FVB services\r
1119\r
1120Arguments:\r
1121\r
1122Returns:\r
1123\r
1124--*/\r
1125{\r
1126 EFI_STATUS Status;\r
ccd55824 1127 EFI_FW_VOL_INSTANCE *FwhInstance = NULL;\r
804405e7 1128 EFI_FIRMWARE_VOLUME_HEADER *FwVolHeader;\r
1129 EFI_DXE_SERVICES *DxeServices;\r
1130 EFI_GCD_MEMORY_SPACE_DESCRIPTOR Descriptor;\r
1131 UINT32 BufferSize;\r
1132 EFI_FV_BLOCK_MAP_ENTRY *PtrBlockMapEntry;\r
1133 EFI_HANDLE FwbHandle;\r
1134 EFI_FW_VOL_BLOCK_DEVICE *FvbDevice;\r
1135 EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL *OldFwbInterface;\r
1136 EFI_DEVICE_PATH_PROTOCOL *TempFwbDevicePath;\r
1137 FV_DEVICE_PATH TempFvbDevicePathData;\r
1138 UINT32 MaxLbaSize;\r
1139 EFI_PHYSICAL_ADDRESS BaseAddress;\r
1140 UINT64 Length;\r
1141 UINTN NumOfBlocks;\r
1142 EFI_PEI_HOB_POINTERS FvHob;\r
1143\r
1144 //\r
1145 // Get the DXE services table\r
1146 //\r
1147 DxeServices = gDS;\r
1148\r
1149 //\r
1150 // Allocate runtime services data for global variable, which contains\r
1151 // the private data of all firmware volume block instances\r
1152 //\r
e89bb669 1153 Status = gBS->AllocatePool (\r
1154 EfiRuntimeServicesData,\r
1155 sizeof (ESAL_FWB_GLOBAL),\r
1156 (VOID**) &mFvbModuleGlobal\r
1157 );\r
1158 ASSERT_EFI_ERROR (Status);\r
804405e7 1159\r
1160 //\r
1161 // Calculate the total size for all firmware volume block instances\r
1162 //\r
1163 BufferSize = 0;\r
1164\r
1165 FvHob.Raw = GetHobList ();\r
1166 while ((FvHob.Raw = GetNextHob (EFI_HOB_TYPE_FV, FvHob.Raw)) != NULL) {\r
1167 BaseAddress = FvHob.FirmwareVolume->BaseAddress;\r
1168 Length = FvHob.FirmwareVolume->Length;\r
1169 //\r
1170 // Check if it is a "real" flash\r
1171 //\r
1172 Status = DxeServices->GetMemorySpaceDescriptor (\r
1173 BaseAddress,\r
1174 &Descriptor\r
1175 );\r
1176 if (EFI_ERROR (Status)) {\r
1177 break;\r
1178 }\r
1179\r
1180 if (Descriptor.GcdMemoryType != EfiGcdMemoryTypeMemoryMappedIo) {\r
1181 FvHob.Raw = GET_NEXT_HOB (FvHob);\r
1182 continue;\r
1183 }\r
1184\r
1185 FwVolHeader = (EFI_FIRMWARE_VOLUME_HEADER *) (UINTN) BaseAddress;\r
1186 Status = ValidateFvHeader (FwVolHeader);\r
1187 if (EFI_ERROR (Status)) {\r
1188 //\r
1189 // Get FvbInfo\r
1190 //\r
1191 Status = GetFvbInfo (Length, &FwVolHeader);\r
1192 if (EFI_ERROR (Status)) {\r
1193 FvHob.Raw = GET_NEXT_HOB (FvHob);\r
1194 continue;\r
1195 }\r
1196 }\r
1197\r
1198 BufferSize += (sizeof (EFI_FW_VOL_INSTANCE) + FwVolHeader->HeaderLength - sizeof (EFI_FIRMWARE_VOLUME_HEADER));\r
1199 FvHob.Raw = GET_NEXT_HOB (FvHob);\r
1200 }\r
1201\r
1202 //\r
1203 // Only need to allocate once. There is only one copy of physical memory for\r
1204 // the private data of each FV instance. But in virtual mode or in physical\r
1205 // mode, the address of the the physical memory may be different.\r
1206 //\r
e89bb669 1207 Status = gBS->AllocatePool (\r
1208 EfiRuntimeServicesData,\r
1209 BufferSize,\r
1210 (VOID**) &mFvbModuleGlobal->FvInstance[FVB_PHYSICAL]\r
1211 );\r
1212 ASSERT_EFI_ERROR (Status);\r
804405e7 1213\r
1214 //\r
1215 // Make a virtual copy of the FvInstance pointer.\r
1216 //\r
1217 FwhInstance = mFvbModuleGlobal->FvInstance[FVB_PHYSICAL];\r
1218 mFvbModuleGlobal->FvInstance[FVB_VIRTUAL] = FwhInstance;\r
1219\r
1220 mFvbModuleGlobal->NumFv = 0;\r
1221 MaxLbaSize = 0;\r
1222\r
1223 FvHob.Raw = GetHobList ();\r
1224 while (NULL != (FvHob.Raw = GetNextHob (EFI_HOB_TYPE_FV, FvHob.Raw))) {\r
1225 BaseAddress = FvHob.FirmwareVolume->BaseAddress;\r
1226 Length = FvHob.FirmwareVolume->Length;\r
1227 //\r
1228 // Check if it is a "real" flash\r
1229 //\r
1230 Status = DxeServices->GetMemorySpaceDescriptor (\r
1231 BaseAddress,\r
1232 &Descriptor\r
1233 );\r
1234 if (EFI_ERROR (Status)) {\r
1235 break;\r
1236 }\r
1237\r
1238 if (Descriptor.GcdMemoryType != EfiGcdMemoryTypeMemoryMappedIo) {\r
1239 FvHob.Raw = GET_NEXT_HOB (FvHob);\r
1240 continue;\r
1241 }\r
1242\r
1243 FwVolHeader = (EFI_FIRMWARE_VOLUME_HEADER *) (UINTN) BaseAddress;\r
1244 Status = ValidateFvHeader (FwVolHeader);\r
1245 if (EFI_ERROR (Status)) {\r
1246 //\r
1247 // Get FvbInfo to provide in FwhInstance.\r
1248 //\r
1249 Status = GetFvbInfo (Length, &FwVolHeader);\r
1250 if (EFI_ERROR (Status)) {\r
1251 FvHob.Raw = GET_NEXT_HOB (FvHob);\r
1252 continue;\r
1253 }\r
1254 //\r
1255 // Write healthy FV header back.\r
1256 //\r
1257 CopyMem (\r
1258 (VOID *) (UINTN) BaseAddress,\r
1259 (VOID *) FwVolHeader,\r
1260 FwVolHeader->HeaderLength\r
1261 );\r
1262 }\r
1263\r
1264 FwhInstance->FvBase[FVB_PHYSICAL] = (UINTN) BaseAddress;\r
1265 FwhInstance->FvBase[FVB_VIRTUAL] = (UINTN) BaseAddress;\r
1266\r
1267 CopyMem ((UINTN *) &(FwhInstance->VolumeHeader), (UINTN *) FwVolHeader, FwVolHeader->HeaderLength);\r
1268 FwVolHeader = &(FwhInstance->VolumeHeader);\r
1269 EfiInitializeLock (&(FwhInstance->FvbDevLock), TPL_HIGH_LEVEL);\r
1270\r
1271 NumOfBlocks = 0;\r
1272\r
1273 for (PtrBlockMapEntry = FwVolHeader->BlockMap; PtrBlockMapEntry->NumBlocks != 0; PtrBlockMapEntry++) {\r
1274 //\r
1275 // Get the maximum size of a block. The size will be used to allocate\r
1276 // buffer for Scratch space, the intermediate buffer for FVB extension\r
1277 // protocol\r
1278 //\r
1279 if (MaxLbaSize < PtrBlockMapEntry->Length) {\r
1280 MaxLbaSize = PtrBlockMapEntry->Length;\r
1281 }\r
1282\r
1283 NumOfBlocks = NumOfBlocks + PtrBlockMapEntry->NumBlocks;\r
1284 }\r
1285 //\r
1286 // The total number of blocks in the FV.\r
1287 //\r
1288 FwhInstance->NumOfBlocks = NumOfBlocks;\r
1289\r
1290 //\r
1291 // Add a FVB Protocol Instance\r
1292 //\r
e89bb669 1293 Status = gBS->AllocatePool (\r
1294 EfiRuntimeServicesData,\r
1295 sizeof (EFI_FW_VOL_BLOCK_DEVICE),\r
1296 (VOID**) &FvbDevice\r
1297 );\r
1298 ASSERT_EFI_ERROR (Status);\r
804405e7 1299\r
1300 CopyMem (FvbDevice, &mFvbDeviceTemplate, sizeof (EFI_FW_VOL_BLOCK_DEVICE));\r
1301\r
1302 FvbDevice->Instance = mFvbModuleGlobal->NumFv;\r
1303 mFvbModuleGlobal->NumFv++;\r
1304\r
1305 //\r
1306 // Set up the devicepath\r
1307 //\r
1308 FvbDevice->DevicePath.MemMapDevPath.StartingAddress = BaseAddress;\r
1309 FvbDevice->DevicePath.MemMapDevPath.EndingAddress = BaseAddress + (FwVolHeader->FvLength - 1);\r
1310\r
1311 //\r
1312 // Find a handle with a matching device path that has supports FW Block protocol\r
1313 //\r
1314 TempFwbDevicePath = (EFI_DEVICE_PATH_PROTOCOL *) &TempFvbDevicePathData;\r
1315 CopyMem (TempFwbDevicePath, &FvbDevice->DevicePath, sizeof (FV_DEVICE_PATH));\r
1316 Status = gBS->LocateDevicePath (&gEfiFirmwareVolumeBlockProtocolGuid, &TempFwbDevicePath, &FwbHandle);\r
1317 if (EFI_ERROR (Status)) {\r
1318 //\r
1319 // LocateDevicePath fails so install a new interface and device path\r
1320 //\r
1321 FwbHandle = NULL;\r
1322 Status = gBS->InstallMultipleProtocolInterfaces (\r
1323 &FwbHandle,\r
1324 &gEfiFirmwareVolumeBlockProtocolGuid,\r
1325 &FvbDevice->FwVolBlockInstance,\r
1326 &gEfiDevicePathProtocolGuid,\r
1327 &FvbDevice->DevicePath,\r
1328 NULL\r
1329 );\r
1330 ASSERT_EFI_ERROR (Status);\r
9f0b86b7 1331 } else if (IsDevicePathEnd (TempFwbDevicePath)) {\r
804405e7 1332 //\r
1333 // Device allready exists, so reinstall the FVB protocol\r
1334 //\r
1335 Status = gBS->HandleProtocol (\r
1336 FwbHandle,\r
1337 &gEfiFirmwareVolumeBlockProtocolGuid,\r
1338 (VOID**)&OldFwbInterface\r
1339 );\r
1340 ASSERT_EFI_ERROR (Status);\r
1341\r
1342 Status = gBS->ReinstallProtocolInterface (\r
1343 FwbHandle,\r
1344 &gEfiFirmwareVolumeBlockProtocolGuid,\r
1345 OldFwbInterface,\r
1346 &FvbDevice->FwVolBlockInstance\r
1347 );\r
1348 ASSERT_EFI_ERROR (Status);\r
1349\r
1350 } else {\r
1351 //\r
1352 // There was a FVB protocol on an End Device Path node\r
1353 //\r
1354 ASSERT (FALSE);\r
1355 }\r
e9cf53f2 1356\r
804405e7 1357 FwhInstance = (EFI_FW_VOL_INSTANCE *)\r
1358 (\r
1359 (UINTN) ((UINT8 *) FwhInstance) + FwVolHeader->HeaderLength +\r
1360 (sizeof (EFI_FW_VOL_INSTANCE) - sizeof (EFI_FIRMWARE_VOLUME_HEADER))\r
1361 );\r
1362\r
1363 FvHob.Raw = GET_NEXT_HOB (FvHob);\r
1364 }\r
1365\r
804405e7 1366 return EFI_SUCCESS;\r
1367}\r