]> git.proxmox.com Git - mirror_edk2.git/blame - EdkNt32Pkg/RuntimeDxe/FvbServices/Common/FWBlockService.c
Introduce a new property INCLUDE_PATHS. This property can used by customized build...
[mirror_edk2.git] / EdkNt32Pkg / RuntimeDxe / FvbServices / Common / FWBlockService.c
CommitLineData
878ddf1f 1/*++\r
2\r
3Copyright (c) 2006, Intel Corporation \r
4All rights reserved. This program and the accompanying materials \r
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
22#include "FWBlockService.h"\r
23#include "EfiFlashMap.h"\r
24#include EFI_GUID_DEFINITION (FlashMapHob)\r
25\r
26ESAL_FWB_GLOBAL *mFvbModuleGlobal;\r
27\r
28EFI_FW_VOL_BLOCK_DEVICE mFvbDeviceTemplate = {\r
29 FVB_DEVICE_SIGNATURE,\r
30 {\r
31 {\r
32 {\r
33 HARDWARE_DEVICE_PATH,\r
34 HW_MEMMAP_DP,\r
35 {\r
36 sizeof (MEMMAP_DEVICE_PATH),\r
37 0\r
38 }\r
39 },\r
40 EfiMemoryMappedIO,\r
41 0,\r
42 0,\r
43 },\r
44 {\r
45 END_DEVICE_PATH_TYPE,\r
46 END_ENTIRE_DEVICE_PATH_SUBTYPE,\r
47 {\r
48 sizeof (EFI_DEVICE_PATH_PROTOCOL),\r
49 0\r
50 }\r
51 }\r
52 },\r
53 0,\r
54 {\r
55 FvbProtocolGetAttributes,\r
56 FvbProtocolSetAttributes,\r
57 FvbProtocolGetPhysicalAddress,\r
58 FvbProtocolGetBlockSize,\r
59 FvbProtocolRead,\r
60 FvbProtocolWrite,\r
61 FvbProtocolEraseBlocks,\r
62 NULL\r
63 },\r
64 {\r
65 FvbExtendProtocolEraseCustomBlockRange\r
66 }\r
67};\r
68\r
69EFI_DRIVER_ENTRY_POINT (FvbInitialize)\r
70\r
71\r
72VOID\r
73EFIAPI\r
74FvbVirtualddressChangeEvent (\r
75 IN EFI_EVENT Event,\r
76 IN VOID *Context\r
77 )\r
78/*++\r
79\r
80Routine Description:\r
81\r
82 Fixup internal data so that EFI and SAL can be call in virtual mode.\r
83 Call the passed in Child Notify event and convert the mFvbModuleGlobal\r
84 date items to there virtual address.\r
85\r
86 mFvbModuleGlobal->FvInstance[FVB_PHYSICAL] - Physical copy of instance data\r
87 mFvbModuleGlobal->FvInstance[FVB_VIRTUAL] - Virtual pointer to common \r
88 instance data.\r
89\r
90Arguments:\r
91\r
92 (Standard EFI notify event - EFI_EVENT_NOTIFY)\r
93\r
94Returns: \r
95\r
96 None\r
97\r
98--*/\r
99{\r
100 EFI_FW_VOL_INSTANCE *FwhInstance;\r
101 UINTN Index;\r
102\r
103 EfiConvertPointer (EFI_INTERNAL_POINTER, (VOID **) &mFvbModuleGlobal->FvInstance[FVB_VIRTUAL]);\r
104\r
105 //\r
106 // Convert the base address of all the instances\r
107 //\r
108 Index = 0;\r
109 FwhInstance = mFvbModuleGlobal->FvInstance[FVB_PHYSICAL];\r
110 while (Index < mFvbModuleGlobal->NumFv) {\r
111 EfiConvertPointer (EFI_INTERNAL_POINTER, (VOID **) &FwhInstance->FvBase[FVB_VIRTUAL]);\r
112 EfiConvertPointer (EFI_INTERNAL_POINTER, (VOID **) &FwhInstance->FvWriteBase[FVB_VIRTUAL]);\r
113 FwhInstance = (EFI_FW_VOL_INSTANCE *) ((UINTN)((UINT8 *)FwhInstance) + FwhInstance->VolumeHeader.HeaderLength\r
114 + (sizeof (EFI_FW_VOL_INSTANCE) - sizeof (EFI_FIRMWARE_VOLUME_HEADER)));\r
115 Index++;\r
116 }\r
117\r
118 EfiConvertPointer (EFI_INTERNAL_POINTER, (VOID **) &mFvbModuleGlobal->FvbScratchSpace[FVB_VIRTUAL]);\r
119 EfiConvertPointer (EFI_INTERNAL_POINTER, (VOID **) &mFvbModuleGlobal);\r
120}\r
121\r
122VOID\r
123FvbMemWrite8 (\r
124 IN UINT64 Dest,\r
125 IN UINT8 Byte\r
126 )\r
127{\r
128 EfiMemWrite (EfiCpuIoWidthUint8, Dest, 1, &Byte);\r
129\r
130 return ;\r
131}\r
132\r
133EFI_STATUS\r
134GetFvbInstance (\r
135 IN UINTN Instance,\r
136 IN ESAL_FWB_GLOBAL *Global,\r
137 OUT EFI_FW_VOL_INSTANCE **FwhInstance,\r
138 IN BOOLEAN Virtual\r
139 )\r
140/*++\r
141\r
142Routine Description:\r
143 Retrieves the physical address of a memory mapped FV\r
144\r
145Arguments:\r
146 Instance - The FV instance whose base address is going to be\r
147 returned\r
148 Global - Pointer to ESAL_FWB_GLOBAL that contains all\r
149 instance data\r
150 FwhInstance - The EFI_FW_VOL_INSTANCE fimrware instance structure\r
151 Virtual - Whether CPU is in virtual or physical mode\r
152\r
153Returns: \r
154 EFI_SUCCESS - Successfully returns\r
155 EFI_INVALID_PARAMETER - Instance not found\r
156\r
157--*/\r
158{\r
159 EFI_FW_VOL_INSTANCE *FwhRecord;\r
160\r
161 if (Instance >= Global->NumFv) {\r
162 return EFI_INVALID_PARAMETER;\r
163 }\r
164 //\r
165 // Find the right instance of the FVB private data\r
166 //\r
167 FwhRecord = Global->FvInstance[Virtual];\r
168 while (Instance > 0) {\r
169 FwhRecord = (EFI_FW_VOL_INSTANCE *) ((UINTN)((UINT8 *)FwhRecord) + FwhRecord->VolumeHeader.HeaderLength \r
170 + (sizeof (EFI_FW_VOL_INSTANCE) - sizeof (EFI_FIRMWARE_VOLUME_HEADER)));\r
171 Instance--;\r
172 }\r
173\r
174 *FwhInstance = FwhRecord;\r
175\r
176 return EFI_SUCCESS;\r
177}\r
178\r
179EFI_STATUS\r
180FvbGetPhysicalAddress (\r
181 IN UINTN Instance,\r
182 OUT EFI_PHYSICAL_ADDRESS *Address,\r
183 IN ESAL_FWB_GLOBAL *Global,\r
184 IN BOOLEAN Virtual\r
185 )\r
186/*++\r
187\r
188Routine Description:\r
189 Retrieves the physical address of a memory mapped FV\r
190\r
191Arguments:\r
192 Instance - The FV instance whose base address is going to be\r
193 returned\r
194 Address - Pointer to a caller allocated EFI_PHYSICAL_ADDRESS \r
195 that on successful return, contains the base address\r
196 of the firmware volume. \r
197 Global - Pointer to ESAL_FWB_GLOBAL that contains all\r
198 instance data\r
199 Virtual - Whether CPU is in virtual or physical mode\r
200\r
201Returns: \r
202 EFI_SUCCESS - Successfully returns\r
203 EFI_INVALID_PARAMETER - Instance not found\r
204\r
205--*/\r
206{\r
207 EFI_FW_VOL_INSTANCE *FwhInstance;\r
208 EFI_STATUS Status;\r
209\r
210 //\r
211 // Find the right instance of the FVB private data\r
212 //\r
213 Status = GetFvbInstance (Instance, Global, &FwhInstance, Virtual);\r
214 ASSERT_EFI_ERROR (Status);\r
215 *Address = FwhInstance->FvBase[Virtual];\r
216\r
217 return EFI_SUCCESS;\r
218}\r
219\r
220EFI_STATUS\r
221FvbGetVolumeAttributes (\r
222 IN UINTN Instance,\r
223 OUT EFI_FVB_ATTRIBUTES *Attributes,\r
224 IN ESAL_FWB_GLOBAL *Global,\r
225 IN BOOLEAN Virtual\r
226 )\r
227/*++\r
228\r
229Routine Description:\r
230 Retrieves attributes, insures positive polarity of attribute bits, returns\r
231 resulting attributes in output parameter\r
232\r
233Arguments:\r
234 Instance - The FV instance whose attributes is going to be \r
235 returned\r
236 Attributes - Output buffer which contains attributes\r
237 Global - Pointer to ESAL_FWB_GLOBAL that contains all\r
238 instance data\r
239 Virtual - Whether CPU is in virtual or physical mode\r
240\r
241Returns: \r
242 EFI_SUCCESS - Successfully returns\r
243 EFI_INVALID_PARAMETER - Instance not found\r
244\r
245--*/\r
246{\r
247 EFI_FW_VOL_INSTANCE *FwhInstance;\r
248 EFI_STATUS Status;\r
249\r
250 //\r
251 // Find the right instance of the FVB private data\r
252 //\r
253 Status = GetFvbInstance (Instance, Global, &FwhInstance, Virtual);\r
254 ASSERT_EFI_ERROR (Status);\r
255 *Attributes = FwhInstance->VolumeHeader.Attributes;\r
256\r
257 return EFI_SUCCESS;\r
258}\r
259\r
260EFI_STATUS\r
261FvbGetLbaAddress (\r
262 IN UINTN Instance,\r
263 IN EFI_LBA Lba,\r
264 OUT UINTN *LbaAddress,\r
265 OUT UINTN *LbaWriteAddress,\r
266 OUT UINTN *LbaLength,\r
267 OUT UINTN *NumOfBlocks,\r
268 IN ESAL_FWB_GLOBAL *Global,\r
269 IN BOOLEAN Virtual\r
270 )\r
271/*++\r
272\r
273Routine Description:\r
274 Retrieves the starting address of an LBA in an FV\r
275\r
276Arguments:\r
277 Instance - The FV instance which the Lba belongs to\r
278 Lba - The logical block address\r
279 LbaAddress - On output, contains the physical starting address \r
280 of the Lba\r
281 LbaWriteAddress - On output, contains the physical starting address\r
282 of the Lba for writing\r
283 LbaLength - On output, contains the length of the block\r
284 NumOfBlocks - A pointer to a caller allocated UINTN in which the\r
285 number of consecutive blocks starting with Lba is\r
286 returned. All blocks in this range have a size of\r
287 BlockSize\r
288 Global - Pointer to ESAL_FWB_GLOBAL that contains all\r
289 instance data\r
290 Virtual - Whether CPU is in virtual or physical mode\r
291\r
292Returns: \r
293 EFI_SUCCESS - Successfully returns\r
294 EFI_INVALID_PARAMETER - Instance not found\r
295\r
296--*/\r
297{\r
298 UINT32 NumBlocks;\r
299 UINT32 BlockLength;\r
300 UINTN Offset;\r
301 EFI_LBA StartLba;\r
302 EFI_LBA NextLba;\r
303 EFI_FW_VOL_INSTANCE *FwhInstance;\r
304 EFI_FV_BLOCK_MAP_ENTRY *BlockMap;\r
305 EFI_STATUS Status;\r
306\r
307 //\r
308 // Find the right instance of the FVB private data\r
309 //\r
310 Status = GetFvbInstance (Instance, Global, &FwhInstance, Virtual);\r
311 ASSERT_EFI_ERROR (Status);\r
312\r
313 StartLba = 0;\r
314 Offset = 0;\r
315 BlockMap = &(FwhInstance->VolumeHeader.FvBlockMap[0]);\r
316\r
317 //\r
318 // Parse the blockmap of the FV to find which map entry the Lba belongs to\r
319 //\r
320 while (TRUE) {\r
321 NumBlocks = BlockMap->NumBlocks;\r
322 BlockLength = BlockMap->BlockLength;\r
323\r
324 if (NumBlocks == 0 || BlockLength == 0) {\r
325 return EFI_INVALID_PARAMETER;\r
326 }\r
327\r
328 NextLba = StartLba + NumBlocks;\r
329\r
330 //\r
331 // The map entry found\r
332 //\r
333 if (Lba >= StartLba && Lba < NextLba) {\r
334 Offset = Offset + (UINTN) MultU64x32 ((Lba - StartLba), BlockLength);\r
335 if (LbaAddress) {\r
336 *LbaAddress = FwhInstance->FvBase[Virtual] + Offset;\r
337 }\r
338\r
339 if (LbaWriteAddress) {\r
340 *LbaWriteAddress = FwhInstance->FvWriteBase[Virtual] + Offset;\r
341 }\r
342\r
343 if (LbaLength) {\r
344 *LbaLength = BlockLength;\r
345 }\r
346\r
347 if (NumOfBlocks) {\r
348 *NumOfBlocks = (UINTN) (NextLba - Lba);\r
349 }\r
350\r
351 return EFI_SUCCESS;\r
352 }\r
353\r
354 StartLba = NextLba;\r
355 Offset = Offset + NumBlocks * BlockLength;\r
356 BlockMap++;\r
357 }\r
358}\r
359\r
360EFI_STATUS\r
361FvbReadBlock (\r
362 IN UINTN Instance,\r
363 IN EFI_LBA Lba,\r
364 IN UINTN BlockOffset,\r
365 IN OUT UINTN *NumBytes,\r
366 IN UINT8 *Buffer,\r
367 IN ESAL_FWB_GLOBAL *Global,\r
368 IN BOOLEAN Virtual\r
369 )\r
370/*++\r
371\r
372Routine Description:\r
373 Reads specified number of bytes into a buffer from the specified block\r
374\r
375Arguments:\r
376 Instance - The FV instance to be read from\r
377 Lba - The logical block address to be read from\r
378 BlockOffset - Offset into the block at which to begin reading\r
379 NumBytes - Pointer that on input contains the total size of\r
380 the buffer. On output, it contains the total number\r
381 of bytes read\r
382 Buffer - Pointer to a caller allocated buffer that will be\r
383 used to hold the data read\r
384 Global - Pointer to ESAL_FWB_GLOBAL that contains all\r
385 instance data\r
386 Virtual - Whether CPU is in virtual or physical mode\r
387\r
388Returns: \r
389 EFI_SUCCESS - The firmware volume was read successfully and \r
390 contents are in Buffer\r
391 EFI_BAD_BUFFER_SIZE - Read attempted across a LBA boundary. On output,\r
392 NumBytes contains the total number of bytes returned\r
393 in Buffer\r
394 EFI_ACCESS_DENIED - The firmware volume is in the ReadDisabled state\r
395 EFI_DEVICE_ERROR - The block device is not functioning correctly and \r
396 could not be read\r
397 EFI_INVALID_PARAMETER - Instance not found, or NumBytes, Buffer are NULL\r
398\r
399--*/\r
400{\r
401 EFI_FVB_ATTRIBUTES Attributes;\r
402 UINTN LbaAddress;\r
403 UINTN LbaLength;\r
404 EFI_STATUS Status;\r
405\r
406 //\r
407 // Check for invalid conditions\r
408 //\r
409 if ((NumBytes == NULL) || (Buffer == NULL)) {\r
410 return EFI_INVALID_PARAMETER;\r
411 }\r
412\r
413 if (*NumBytes == 0) {\r
414 return EFI_INVALID_PARAMETER;\r
415 }\r
416\r
417 Status = FvbGetLbaAddress (Instance, Lba, &LbaAddress, NULL, &LbaLength, NULL, Global, Virtual);\r
418 if (EFI_ERROR (Status)) {\r
419 return Status;\r
420 }\r
421 //\r
422 // Check if the FV is read enabled\r
423 //\r
424 FvbGetVolumeAttributes (Instance, &Attributes, Global, Virtual);\r
425\r
426 if ((Attributes & EFI_FVB_READ_STATUS) == 0) {\r
427 return EFI_ACCESS_DENIED;\r
428 }\r
429 //\r
430 // Perform boundary checks and adjust NumBytes\r
431 //\r
432 if (BlockOffset > LbaLength) {\r
433 return EFI_INVALID_PARAMETER;\r
434 }\r
435\r
436 if (LbaLength < (*NumBytes + BlockOffset)) {\r
437 *NumBytes = (UINT32) (LbaLength - BlockOffset);\r
438 Status = EFI_BAD_BUFFER_SIZE;\r
439 }\r
440\r
441 EfiMemRead (EfiCpuIoWidthUint8, LbaAddress + BlockOffset, (UINTN) *NumBytes, Buffer);\r
442\r
443 return Status;\r
444}\r
445\r
446EFI_STATUS\r
447FlashFdWrite (\r
448 IN UINTN WriteAddress,\r
449 IN UINTN Address,\r
450 IN OUT UINTN *NumBytes,\r
451 IN UINT8 *Buffer,\r
452 IN UINTN LbaLength\r
453 )\r
454/*++\r
455\r
456Routine Description:\r
457 Writes specified number of bytes from the input buffer to the address\r
458\r
459Arguments:\r
460\r
461Returns: \r
462\r
463--*/\r
464{\r
465 UINT8 *Src;\r
466 UINT8 *Dest;\r
467 UINTN Count;\r
468 EFI_STATUS Status;\r
469 UINT8 HubCommand;\r
470 UINT8 HubData;\r
471 UINTN RetryTimes;\r
472\r
473 Status = EFI_SUCCESS;\r
474\r
475 EnableFvbWrites (TRUE);\r
476\r
477 //\r
478 // Grab the lock before entering critical code section\r
479 //\r
480 // bugbug\r
481 // Commented out since locking mechanisium is not correctly implemented\r
482 // on IA32 so that it will assert in runtime environment.\r
483 //\r
484 // EfiAcquireLock(&(FwhInstance->FvbDevLock));\r
485 //\r
486 // Write data one byte at a time, don't write if the src and dest bytes match\r
487 //\r
488 Dest = (UINT8 *) WriteAddress;\r
489 Src = Buffer;\r
490\r
491 for (Count = 0; Count < *NumBytes; Count++, Dest++, Src++) {\r
492\r
493 HubCommand = FWH_WRITE_SETUP_COMMAND;\r
494 FvbMemWrite8 ((UINT64) ((UINTN) Dest), HubCommand);\r
495 FvbMemWrite8 ((UINT64) ((UINTN) Dest), *Src);\r
496 HubCommand = FWH_READ_STATUS_COMMAND;\r
497 FvbMemWrite8 ((UINT64) ((UINTN) Dest), HubCommand);\r
498\r
499 //\r
500 // Device error if time out occurs\r
501 //\r
502 RetryTimes = 0;\r
503 while (RetryTimes < FVB_MAX_RETRY_TIMES) {\r
504 EfiMemRead (EfiCpuIoWidthUint8, (UINT64) ((UINTN) Dest), 0x1, &HubData);\r
505 if (HubData & FWH_WRITE_STATE_STATUS) {\r
506 break;\r
507 }\r
508\r
509 RetryTimes++;\r
510 }\r
511\r
512 if (RetryTimes >= FVB_MAX_RETRY_TIMES) {\r
513 *NumBytes = Count;\r
514 Status = EFI_DEVICE_ERROR;\r
515 break;\r
516 }\r
517 }\r
518 //\r
519 // Clear status register\r
520 //\r
521 HubCommand = FWH_CLEAR_STATUS_COMMAND;\r
522 FvbMemWrite8 ((UINT64) ((UINTN) Dest), HubCommand);\r
523\r
524 //\r
525 // Issue read array command to return the FWH state machine to the\r
526 // normal operational state\r
527 //\r
528 HubCommand = FWH_READ_ARRAY_COMMAND;\r
529 FvbMemWrite8 ((UINT64) ((UINTN) WriteAddress), HubCommand);\r
530 //\r
531 // Flush the changed area to make the cache consistent\r
532 //\r
533 EfiCpuFlushCache (WriteAddress, *NumBytes);\r
534\r
535 //\r
536 // End of critical code section, release lock.\r
537 //\r
538 // EfiReleaseLock(&(FwhInstance->FvbDevLock));\r
539 //\r
540 EnableFvbWrites (FALSE);\r
541\r
542 return Status;\r
543}\r
544\r
545EFI_STATUS\r
546FlashFdErase (\r
547 IN UINTN WriteAddress,\r
548 IN UINTN Address,\r
549 IN UINTN LbaLength\r
550 )\r
551/*++\r
552\r
553Routine Description:\r
554 Erase a certain block from address LbaWriteAddress\r
555\r
556Arguments:\r
557\r
558Returns: \r
559\r
560--*/\r
561{\r
562 EFI_STATUS Status;\r
563 UINT8 HubCommand;\r
564 UINT8 HubData;\r
565 UINTN RetryTimes;\r
566\r
567 Status = EFI_SUCCESS;\r
568\r
569 EnableFvbWrites (TRUE);\r
570\r
571 //\r
572 // Grab the lock before entering critical code section\r
573 //\r
574 // EfiAcquireLock(&(FwhInstance->FvbDevLock));\r
575 //\r
576 // Send erase commands to FWH\r
577 //\r
578 HubCommand = FWH_BLOCK_ERASE_SETUP_COMMAND;\r
579 FvbMemWrite8 ((UINT64) WriteAddress, HubCommand);\r
580 HubCommand = FWH_BLOCK_ERASE_CONFIRM_COMMAND;\r
581 FvbMemWrite8 ((UINT64) WriteAddress, HubCommand);\r
582 HubCommand = FWH_READ_STATUS_COMMAND;\r
583 FvbMemWrite8 ((UINT64) WriteAddress, HubCommand);\r
584\r
585 //\r
586 // Wait for completion. Indicated by FWH_WRITE_STATE_STATUS bit becoming 0\r
587 // Device error if time out occurs\r
588 //\r
589 RetryTimes = 0;\r
590 while (RetryTimes < FVB_MAX_RETRY_TIMES) {\r
591 EfiMemRead (EfiCpuIoWidthUint8, (UINT64) WriteAddress, 0x1, &HubData);\r
592 if (HubData & FWH_WRITE_STATE_STATUS) {\r
593 break;\r
594 }\r
595\r
596 RetryTimes++;\r
597 }\r
598\r
599 if (RetryTimes >= FVB_MAX_RETRY_TIMES) {\r
600 Status = EFI_DEVICE_ERROR;\r
601 }\r
602 //\r
603 // Clear status register\r
604 //\r
605 HubCommand = FWH_CLEAR_STATUS_COMMAND;\r
606 FvbMemWrite8 ((UINT64) WriteAddress, HubCommand);\r
607\r
608 //\r
609 // Issue read array command to return the FWH state machine to the normal op state\r
610 //\r
611 HubCommand = FWH_READ_ARRAY_COMMAND;\r
612 FvbMemWrite8 ((UINT64) ((UINTN) WriteAddress), HubCommand);\r
613\r
614 EfiCpuFlushCache (Address, LbaLength);\r
615\r
616 //\r
617 // End of critical code section, release lock.\r
618 //\r
619 // EfiReleaseLock(&(FwhInstance->FvbDevLock));\r
620 //\r
621 EnableFvbWrites (FALSE);\r
622\r
623 return Status;\r
624}\r
625\r
626EFI_STATUS\r
627FvbWriteBlock (\r
628 IN UINTN Instance,\r
629 IN EFI_LBA Lba,\r
630 IN UINTN BlockOffset,\r
631 IN OUT UINTN *NumBytes,\r
632 IN UINT8 *Buffer,\r
633 IN ESAL_FWB_GLOBAL *Global,\r
634 IN BOOLEAN Virtual\r
635 )\r
636/*++\r
637\r
638Routine Description:\r
639 Writes specified number of bytes from the input buffer to the block\r
640\r
641Arguments:\r
642 Instance - The FV instance to be written to\r
643 Lba - The starting logical block index to write to\r
644 BlockOffset - Offset into the block at which to begin writing\r
645 NumBytes - Pointer that on input contains the total size of\r
646 the buffer. On output, it contains the total number\r
647 of bytes actually written\r
648 Buffer - Pointer to a caller allocated buffer that contains\r
649 the source for the write\r
650 Global - Pointer to ESAL_FWB_GLOBAL that contains all\r
651 instance data\r
652 Virtual - Whether CPU is in virtual or physical mode\r
653\r
654Returns: \r
655 EFI_SUCCESS - The firmware volume was written successfully\r
656 EFI_BAD_BUFFER_SIZE - Write attempted across a LBA boundary. On output,\r
657 NumBytes contains the total number of bytes\r
658 actually written\r
659 EFI_ACCESS_DENIED - The firmware volume is in the WriteDisabled state\r
660 EFI_DEVICE_ERROR - The block device is not functioning correctly and \r
661 could not be written\r
662 EFI_INVALID_PARAMETER - Instance not found, or NumBytes, Buffer are NULL\r
663\r
664--*/\r
665{\r
666 EFI_FVB_ATTRIBUTES Attributes;\r
667 UINTN LbaAddress;\r
668 UINTN LbaWriteAddress;\r
669 UINTN LbaLength;\r
670 EFI_FW_VOL_INSTANCE *FwhInstance;\r
671 EFI_STATUS Status;\r
672 EFI_STATUS ReturnStatus;\r
673\r
674 //\r
675 // Find the right instance of the FVB private data\r
676 //\r
677 Status = GetFvbInstance (Instance, Global, &FwhInstance, Virtual);\r
678 ASSERT_EFI_ERROR (Status);\r
679\r
680 //\r
681 // Writes are enabled in the init routine itself\r
682 //\r
683 if (!FwhInstance->WriteEnabled) {\r
684 return EFI_ACCESS_DENIED;\r
685 }\r
686 //\r
687 // Check for invalid conditions\r
688 //\r
689 if ((NumBytes == NULL) || (Buffer == NULL)) {\r
690 return EFI_INVALID_PARAMETER;\r
691 }\r
692\r
693 if (*NumBytes == 0) {\r
694 return EFI_INVALID_PARAMETER;\r
695 }\r
696\r
697 Status = FvbGetLbaAddress (Instance, Lba, &LbaAddress, &LbaWriteAddress, &LbaLength, NULL, Global, Virtual);\r
698 if (EFI_ERROR (Status)) {\r
699 return Status;\r
700 }\r
701 //\r
702 // Check if the FV is write enabled\r
703 //\r
704 FvbGetVolumeAttributes (Instance, &Attributes, Global, Virtual);\r
705\r
706 if ((Attributes & EFI_FVB_WRITE_STATUS) == 0) {\r
707 return EFI_ACCESS_DENIED;\r
708 }\r
709 //\r
710 // Perform boundary checks and adjust NumBytes\r
711 //\r
712 if (BlockOffset > LbaLength) {\r
713 return EFI_INVALID_PARAMETER;\r
714 }\r
715\r
716 if (LbaLength < (*NumBytes + BlockOffset)) {\r
717 *NumBytes = (UINT32) (LbaLength - BlockOffset);\r
718 Status = EFI_BAD_BUFFER_SIZE;\r
719 }\r
720\r
721 ReturnStatus = FlashFdWrite (\r
722 LbaWriteAddress + BlockOffset,\r
723 LbaAddress,\r
724 NumBytes,\r
725 Buffer,\r
726 LbaLength\r
727 );\r
728 if (EFI_ERROR (ReturnStatus)) {\r
729 return ReturnStatus;\r
730 }\r
731\r
732 return Status;\r
733}\r
734\r
735EFI_STATUS\r
736FvbEraseBlock (\r
737 IN UINTN Instance,\r
738 IN EFI_LBA Lba,\r
739 IN ESAL_FWB_GLOBAL *Global,\r
740 IN BOOLEAN Virtual\r
741 )\r
742/*++\r
743\r
744Routine Description:\r
745 Erases and initializes a firmware volume block\r
746\r
747Arguments:\r
748 Instance - The FV instance to be erased\r
749 Lba - The logical block index to be erased\r
750 Global - Pointer to ESAL_FWB_GLOBAL that contains all\r
751 instance data\r
752 Virtual - Whether CPU is in virtual or physical mode\r
753\r
754Returns: \r
755 EFI_SUCCESS - The erase request was successfully completed\r
756 EFI_ACCESS_DENIED - The firmware volume is in the WriteDisabled state\r
757 EFI_DEVICE_ERROR - The block device is not functioning correctly and \r
758 could not be written. Firmware device may have been\r
759 partially erased\r
760 EFI_INVALID_PARAMETER - Instance not found\r
761\r
762--*/\r
763{\r
764\r
765 EFI_FVB_ATTRIBUTES Attributes;\r
766 UINTN LbaAddress;\r
767 UINTN LbaWriteAddress;\r
768 EFI_FW_VOL_INSTANCE *FwhInstance;\r
769 UINTN LbaLength;\r
770 EFI_STATUS Status;\r
771\r
772 //\r
773 // Find the right instance of the FVB private data\r
774 //\r
775 Status = GetFvbInstance (Instance, Global, &FwhInstance, Virtual);\r
776 ASSERT_EFI_ERROR (Status);\r
777\r
778 //\r
779 // Writes are enabled in the init routine itself\r
780 //\r
781 if (!FwhInstance->WriteEnabled) {\r
782 return EFI_ACCESS_DENIED;\r
783 }\r
784 //\r
785 // Check if the FV is write enabled\r
786 //\r
787 FvbGetVolumeAttributes (Instance, &Attributes, Global, Virtual);\r
788\r
789 if ((Attributes & EFI_FVB_WRITE_STATUS) == 0) {\r
790 return EFI_ACCESS_DENIED;\r
791 }\r
792 //\r
793 // Get the starting address of the block for erase. For debug reasons,\r
794 // LbaWriteAddress may not be the same as LbaAddress.\r
795 //\r
796 Status = FvbGetLbaAddress (Instance, Lba, &LbaAddress, &LbaWriteAddress, &LbaLength, NULL, Global, Virtual);\r
797 if (EFI_ERROR (Status)) {\r
798 return Status;\r
799 }\r
800\r
801 return FlashFdErase (\r
802 LbaWriteAddress,\r
803 LbaAddress,\r
804 LbaLength\r
805 );\r
806}\r
807\r
808EFI_STATUS\r
809FvbEraseCustomBlockRange (\r
810 IN UINTN Instance,\r
811 IN EFI_LBA StartLba,\r
812 IN UINTN OffsetStartLba,\r
813 IN EFI_LBA LastLba,\r
814 IN UINTN OffsetLastLba,\r
815 IN ESAL_FWB_GLOBAL *Global,\r
816 IN BOOLEAN Virtual\r
817 )\r
818/*++\r
819\r
820Routine Description:\r
821 Erases and initializes a specified range of a firmware volume\r
822\r
823Arguments:\r
824 Instance - The FV instance to be erased\r
825 StartLba - The starting logical block index to be erased\r
826 OffsetStartLba - Offset into the starting block at which to \r
827 begin erasing\r
828 LastLba - The last logical block index to be erased\r
829 OffsetStartLba - Offset into the last block at which to end erasing\r
830 Global - Pointer to ESAL_FWB_GLOBAL that contains all\r
831 instance data\r
832 Virtual - Whether CPU is in virtual or physical mode\r
833\r
834Returns: \r
835 EFI_SUCCESS - The firmware volume was erased successfully\r
836 EFI_ACCESS_DENIED - The firmware volume is in the WriteDisabled state\r
837 EFI_DEVICE_ERROR - The block device is not functioning correctly and \r
838 could not be written. Firmware device may have been\r
839 partially erased\r
840 EFI_INVALID_PARAMETER - Instance not found\r
841\r
842--*/\r
843{\r
844 EFI_LBA Index;\r
845 UINTN LbaSize;\r
846 UINTN ScratchLbaSizeData;\r
847\r
848 //\r
849 // First LBA.\r
850 //\r
851 FvbGetLbaAddress (Instance, StartLba, NULL, NULL, &LbaSize, NULL, Global, Virtual);\r
852\r
853 //\r
854 // Use the scratch space as the intermediate buffer to transfer data\r
855 // Back up the first LBA in scratch space.\r
856 //\r
857 FvbReadBlock (Instance, StartLba, 0, &LbaSize, Global->FvbScratchSpace[Virtual], Global, Virtual);\r
858\r
859 //\r
860 // erase now\r
861 //\r
862 FvbEraseBlock (Instance, StartLba, Global, Virtual);\r
863 ScratchLbaSizeData = OffsetStartLba;\r
864\r
865 //\r
866 // write the data back to the first block\r
867 //\r
868 if (ScratchLbaSizeData > 0) {\r
869 FvbWriteBlock (Instance, StartLba, 0, &ScratchLbaSizeData, Global->FvbScratchSpace[Virtual], Global, Virtual);\r
870 }\r
871 //\r
872 // Middle LBAs\r
873 //\r
874 if (LastLba > (StartLba + 1)) {\r
875 for (Index = (StartLba + 1); Index <= (LastLba - 1); Index++) {\r
876 FvbEraseBlock (Instance, Index, Global, Virtual);\r
877 }\r
878 }\r
879 //\r
880 // Last LBAs, the same as first LBAs\r
881 //\r
882 if (LastLba > StartLba) {\r
883 FvbGetLbaAddress (Instance, LastLba, NULL, NULL, &LbaSize, NULL, Global, Virtual);\r
884 FvbReadBlock (Instance, LastLba, 0, &LbaSize, Global->FvbScratchSpace[Virtual], Global, Virtual);\r
885 FvbEraseBlock (Instance, LastLba, Global, Virtual);\r
886 }\r
887\r
888 ScratchLbaSizeData = LbaSize - (OffsetStartLba + 1);\r
889\r
890 return FvbWriteBlock (\r
891 Instance,\r
892 LastLba,\r
893 (OffsetLastLba + 1),\r
894 &ScratchLbaSizeData,\r
895 Global->FvbScratchSpace[Virtual],\r
896 Global,\r
897 Virtual\r
898 );\r
899}\r
900\r
901EFI_STATUS\r
902FvbSetVolumeAttributes (\r
903 IN UINTN Instance,\r
904 IN OUT EFI_FVB_ATTRIBUTES *Attributes,\r
905 IN ESAL_FWB_GLOBAL *Global,\r
906 IN BOOLEAN Virtual\r
907 )\r
908/*++\r
909\r
910Routine Description:\r
911 Modifies the current settings of the firmware volume according to the \r
912 input parameter, and returns the new setting of the volume\r
913\r
914Arguments:\r
915 Instance - The FV instance whose attributes is going to be \r
916 modified\r
917 Attributes - On input, it is a pointer to EFI_FVB_ATTRIBUTES \r
918 containing the desired firmware volume settings.\r
919 On successful return, it contains the new settings\r
920 of the firmware volume\r
921 Global - Pointer to ESAL_FWB_GLOBAL that contains all\r
922 instance data\r
923 Virtual - Whether CPU is in virtual or physical mode\r
924\r
925Returns: \r
926 EFI_SUCCESS - Successfully returns\r
927 EFI_ACCESS_DENIED - The volume setting is locked and cannot be modified\r
928 EFI_INVALID_PARAMETER - Instance not found, or The attributes requested are\r
929 in conflict with the capabilities as declared in the\r
930 firmware volume header\r
931\r
932--*/\r
933{\r
934 EFI_FW_VOL_INSTANCE *FwhInstance;\r
935 EFI_FVB_ATTRIBUTES OldAttributes;\r
936 EFI_FVB_ATTRIBUTES *AttribPtr;\r
937 UINT32 Capabilities;\r
938 UINT32 OldStatus;\r
939 UINT32 NewStatus;\r
940 EFI_STATUS Status;\r
941\r
942 //\r
943 // Find the right instance of the FVB private data\r
944 //\r
945 Status = GetFvbInstance (Instance, Global, &FwhInstance, Virtual);\r
946 ASSERT_EFI_ERROR (Status);\r
947\r
948 AttribPtr = (EFI_FVB_ATTRIBUTES *) &(FwhInstance->VolumeHeader.Attributes);\r
949 OldAttributes = *AttribPtr;\r
950 Capabilities = OldAttributes & EFI_FVB_CAPABILITIES;\r
951 OldStatus = OldAttributes & EFI_FVB_STATUS;\r
952 NewStatus = *Attributes & EFI_FVB_STATUS;\r
953\r
954 //\r
955 // If firmware volume is locked, no status bit can be updated\r
956 //\r
957 if (OldAttributes & EFI_FVB_LOCK_STATUS) {\r
958 if (OldStatus ^ NewStatus) {\r
959 return EFI_ACCESS_DENIED;\r
960 }\r
961 }\r
962 //\r
963 // Test read disable\r
964 //\r
965 if ((Capabilities & EFI_FVB_READ_DISABLED_CAP) == 0) {\r
966 if ((NewStatus & EFI_FVB_READ_STATUS) == 0) {\r
967 return EFI_INVALID_PARAMETER;\r
968 }\r
969 }\r
970 //\r
971 // Test read enable\r
972 //\r
973 if ((Capabilities & EFI_FVB_READ_ENABLED_CAP) == 0) {\r
974 if (NewStatus & EFI_FVB_READ_STATUS) {\r
975 return EFI_INVALID_PARAMETER;\r
976 }\r
977 }\r
978 //\r
979 // Test write disable\r
980 //\r
981 if ((Capabilities & EFI_FVB_WRITE_DISABLED_CAP) == 0) {\r
982 if ((NewStatus & EFI_FVB_WRITE_STATUS) == 0) {\r
983 return EFI_INVALID_PARAMETER;\r
984 }\r
985 }\r
986 //\r
987 // Test write enable\r
988 //\r
989 if ((Capabilities & EFI_FVB_WRITE_ENABLED_CAP) == 0) {\r
990 if (NewStatus & EFI_FVB_WRITE_STATUS) {\r
991 return EFI_INVALID_PARAMETER;\r
992 }\r
993 }\r
994 //\r
995 // Test lock\r
996 //\r
997 if ((Capabilities & EFI_FVB_LOCK_CAP) == 0) {\r
998 if (NewStatus & EFI_FVB_LOCK_STATUS) {\r
999 return EFI_INVALID_PARAMETER;\r
1000 }\r
1001 }\r
1002\r
1003 *AttribPtr = (*AttribPtr) & (0xFFFFFFFF & (~EFI_FVB_STATUS));\r
1004 *AttribPtr = (*AttribPtr) | NewStatus;\r
1005 *Attributes = *AttribPtr;\r
1006\r
1007 return EFI_SUCCESS;\r
1008}\r
1009//\r
1010// FVB protocol APIs\r
1011//\r
1012EFI_STATUS\r
1013EFIAPI\r
1014FvbProtocolGetPhysicalAddress (\r
1015 IN EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL *This,\r
1016 OUT EFI_PHYSICAL_ADDRESS *Address\r
1017 )\r
1018/*++\r
1019\r
1020Routine Description:\r
1021\r
1022 Retrieves the physical address of the device.\r
1023\r
1024Arguments:\r
1025\r
1026 This - Calling context\r
1027 Address - Output buffer containing the address.\r
1028\r
1029Returns:\r
1030\r
1031Returns: \r
1032 EFI_SUCCESS - Successfully returns\r
1033\r
1034--*/\r
1035{\r
1036 EFI_FW_VOL_BLOCK_DEVICE *FvbDevice;\r
1037\r
1038 FvbDevice = FVB_DEVICE_FROM_THIS (This);\r
1039\r
1040 return FvbGetPhysicalAddress (FvbDevice->Instance, Address, mFvbModuleGlobal, EfiGoneVirtual ());\r
1041}\r
1042\r
1043EFI_STATUS\r
1044EFIAPI\r
1045FvbProtocolGetBlockSize (\r
1046 IN EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL *This,\r
1047 IN EFI_LBA Lba,\r
1048 OUT UINTN *BlockSize,\r
1049 OUT UINTN *NumOfBlocks\r
1050 )\r
1051/*++\r
1052\r
1053Routine Description:\r
1054 Retrieve the size of a logical block\r
1055\r
1056Arguments:\r
1057 This - Calling context\r
1058 Lba - Indicates which block to return the size for.\r
1059 BlockSize - A pointer to a caller allocated UINTN in which\r
1060 the size of the block is returned\r
1061 NumOfBlocks - a pointer to a caller allocated UINTN in which the\r
1062 number of consecutive blocks starting with Lba is\r
1063 returned. All blocks in this range have a size of\r
1064 BlockSize\r
1065\r
1066Returns: \r
1067 EFI_SUCCESS - The firmware volume was read successfully and \r
1068 contents are in Buffer\r
1069\r
1070--*/\r
1071{\r
1072 EFI_FW_VOL_BLOCK_DEVICE *FvbDevice;\r
1073\r
1074 FvbDevice = FVB_DEVICE_FROM_THIS (This);\r
1075\r
1076 return FvbGetLbaAddress (\r
1077 FvbDevice->Instance,\r
1078 Lba,\r
1079 NULL,\r
1080 NULL,\r
1081 BlockSize,\r
1082 NumOfBlocks,\r
1083 mFvbModuleGlobal,\r
1084 EfiGoneVirtual ()\r
1085 );\r
1086}\r
1087\r
1088EFI_STATUS\r
1089EFIAPI\r
1090FvbProtocolGetAttributes (\r
1091 IN EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL *This,\r
1092 OUT EFI_FVB_ATTRIBUTES *Attributes\r
1093 )\r
1094/*++\r
1095\r
1096Routine Description:\r
1097 Retrieves Volume attributes. No polarity translations are done.\r
1098\r
1099Arguments:\r
1100 This - Calling context\r
1101 Attributes - output buffer which contains attributes\r
1102\r
1103Returns: \r
1104 EFI_SUCCESS - Successfully returns\r
1105\r
1106--*/\r
1107{\r
1108 EFI_FW_VOL_BLOCK_DEVICE *FvbDevice;\r
1109\r
1110 FvbDevice = FVB_DEVICE_FROM_THIS (This);\r
1111\r
1112 return FvbGetVolumeAttributes (FvbDevice->Instance, Attributes, mFvbModuleGlobal, EfiGoneVirtual ());\r
1113}\r
1114\r
1115EFI_STATUS\r
1116EFIAPI\r
1117FvbProtocolSetAttributes (\r
1118 IN EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL *This,\r
1119 IN OUT EFI_FVB_ATTRIBUTES *Attributes\r
1120 )\r
1121/*++\r
1122\r
1123Routine Description:\r
1124 Sets Volume attributes. No polarity translations are done.\r
1125\r
1126Arguments:\r
1127 This - Calling context\r
1128 Attributes - output buffer which contains attributes\r
1129\r
1130Returns: \r
1131 EFI_SUCCESS - Successfully returns\r
1132\r
1133--*/\r
1134{\r
1135 EFI_FW_VOL_BLOCK_DEVICE *FvbDevice;\r
1136\r
1137 FvbDevice = FVB_DEVICE_FROM_THIS (This);\r
1138\r
1139 return FvbSetVolumeAttributes (FvbDevice->Instance, Attributes, mFvbModuleGlobal, EfiGoneVirtual ());\r
1140}\r
1141\r
1142EFI_STATUS\r
1143EFIAPI\r
1144FvbProtocolEraseBlocks (\r
1145 IN EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL *This,\r
1146 ... \r
1147 )\r
1148/*++\r
1149\r
1150Routine Description:\r
1151\r
1152 The EraseBlock() function erases one or more blocks as denoted by the \r
1153 variable argument list. The entire parameter list of blocks must be verified\r
1154 prior to erasing any blocks. If a block is requested that does not exist \r
1155 within the associated firmware volume (it has a larger index than the last \r
1156 block of the firmware volume), the EraseBlock() function must return\r
1157 EFI_INVALID_PARAMETER without modifying the contents of the firmware volume.\r
1158\r
1159Arguments:\r
1160 This - Calling context\r
1161 ... - Starting LBA followed by Number of Lba to erase. \r
1162 a -1 to terminate the list.\r
1163\r
1164Returns: \r
1165 EFI_SUCCESS - The erase request was successfully completed\r
1166 EFI_ACCESS_DENIED - The firmware volume is in the WriteDisabled state\r
1167 EFI_DEVICE_ERROR - The block device is not functioning correctly and \r
1168 could not be written. Firmware device may have been\r
1169 partially erased\r
1170\r
1171--*/\r
1172{\r
1173 EFI_FW_VOL_BLOCK_DEVICE *FvbDevice;\r
1174 EFI_FW_VOL_INSTANCE *FwhInstance;\r
1175 UINTN NumOfBlocks;\r
1176 VA_LIST args;\r
1177 EFI_LBA StartingLba;\r
1178 UINTN NumOfLba;\r
1179 EFI_STATUS Status;\r
1180\r
1181 FvbDevice = FVB_DEVICE_FROM_THIS (This);\r
1182\r
1183 Status = GetFvbInstance (FvbDevice->Instance, mFvbModuleGlobal, &FwhInstance, EfiGoneVirtual ());\r
1184 ASSERT_EFI_ERROR (Status);\r
1185\r
1186 NumOfBlocks = FwhInstance->NumOfBlocks;\r
1187\r
1188 VA_START (args, This);\r
1189\r
1190 do {\r
1191 StartingLba = VA_ARG (args, EFI_LBA);\r
1192 if (StartingLba == EFI_LBA_LIST_TERMINATOR) {\r
1193 break;\r
1194 }\r
1195\r
1196 NumOfLba = VA_ARG (args, UINT32);\r
1197\r
1198 //\r
1199 // Check input parameters\r
1200 //\r
1201 if ((NumOfLba == 0) || ((StartingLba + NumOfLba) > NumOfBlocks)) {\r
1202 VA_END (args);\r
1203 return EFI_INVALID_PARAMETER;\r
1204 }\r
1205 } while (1);\r
1206\r
1207 VA_END (args);\r
1208\r
1209 VA_START (args, This);\r
1210 do {\r
1211 StartingLba = VA_ARG (args, EFI_LBA);\r
1212 if (StartingLba == EFI_LBA_LIST_TERMINATOR) {\r
1213 break;\r
1214 }\r
1215\r
1216 NumOfLba = VA_ARG (args, UINT32);\r
1217\r
1218 while (NumOfLba > 0) {\r
1219 Status = FvbEraseBlock (FvbDevice->Instance, StartingLba, mFvbModuleGlobal, EfiGoneVirtual ());\r
1220 if (EFI_ERROR (Status)) {\r
1221 VA_END (args);\r
1222 return Status;\r
1223 }\r
1224\r
1225 StartingLba++;\r
1226 NumOfLba--;\r
1227 }\r
1228\r
1229 } while (1);\r
1230\r
1231 VA_END (args);\r
1232\r
1233 return EFI_SUCCESS;\r
1234}\r
1235\r
1236EFI_STATUS\r
1237EFIAPI\r
1238FvbProtocolWrite (\r
1239 IN EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL *This,\r
1240 IN EFI_LBA Lba,\r
1241 IN UINTN Offset,\r
1242 IN OUT UINTN *NumBytes,\r
1243 IN UINT8 *Buffer\r
1244 )\r
1245/*++\r
1246\r
1247Routine Description:\r
1248\r
1249 Writes data beginning at Lba:Offset from FV. The write terminates either\r
1250 when *NumBytes of data have been written, or when a block boundary is\r
1251 reached. *NumBytes is updated to reflect the actual number of bytes\r
1252 written. The write opertion does not include erase. This routine will\r
1253 attempt to write only the specified bytes. If the writes do not stick,\r
1254 it will return an error.\r
1255\r
1256Arguments:\r
1257 This - Calling context\r
1258 Lba - Block in which to begin write\r
1259 Offset - Offset in the block at which to begin write\r
1260 NumBytes - On input, indicates the requested write size. On\r
1261 output, indicates the actual number of bytes written\r
1262 Buffer - Buffer containing source data for the write.\r
1263\r
1264Returns: \r
1265 EFI_SUCCESS - The firmware volume was written successfully\r
1266 EFI_BAD_BUFFER_SIZE - Write attempted across a LBA boundary. On output,\r
1267 NumBytes contains the total number of bytes\r
1268 actually written\r
1269 EFI_ACCESS_DENIED - The firmware volume is in the WriteDisabled state\r
1270 EFI_DEVICE_ERROR - The block device is not functioning correctly and \r
1271 could not be written\r
1272 EFI_INVALID_PARAMETER - NumBytes or Buffer are NULL\r
1273\r
1274--*/\r
1275{\r
1276\r
1277 EFI_FW_VOL_BLOCK_DEVICE *FvbDevice;\r
1278\r
1279 FvbDevice = FVB_DEVICE_FROM_THIS (This);\r
1280\r
1281 return FvbWriteBlock (FvbDevice->Instance, Lba, Offset, NumBytes, Buffer, mFvbModuleGlobal, EfiGoneVirtual ());\r
1282}\r
1283\r
1284EFI_STATUS\r
1285EFIAPI\r
1286FvbProtocolRead (\r
1287 IN EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL *This,\r
1288 IN EFI_LBA Lba,\r
1289 IN UINTN Offset,\r
1290 IN OUT UINTN *NumBytes,\r
1291 IN UINT8 *Buffer\r
1292 )\r
1293/*++\r
1294\r
1295Routine Description:\r
1296\r
1297 Reads data beginning at Lba:Offset from FV. The Read terminates either\r
1298 when *NumBytes of data have been read, or when a block boundary is\r
1299 reached. *NumBytes is updated to reflect the actual number of bytes\r
1300 written. The write opertion does not include erase. This routine will\r
1301 attempt to write only the specified bytes. If the writes do not stick,\r
1302 it will return an error.\r
1303\r
1304Arguments:\r
1305 This - Calling context\r
1306 Lba - Block in which to begin Read\r
1307 Offset - Offset in the block at which to begin Read\r
1308 NumBytes - On input, indicates the requested write size. On\r
1309 output, indicates the actual number of bytes Read\r
1310 Buffer - Buffer containing source data for the Read.\r
1311\r
1312Returns: \r
1313 EFI_SUCCESS - The firmware volume was read successfully and \r
1314 contents are in Buffer\r
1315 EFI_BAD_BUFFER_SIZE - Read attempted across a LBA boundary. On output,\r
1316 NumBytes contains the total number of bytes returned\r
1317 in Buffer\r
1318 EFI_ACCESS_DENIED - The firmware volume is in the ReadDisabled state\r
1319 EFI_DEVICE_ERROR - The block device is not functioning correctly and \r
1320 could not be read\r
1321 EFI_INVALID_PARAMETER - NumBytes or Buffer are NULL\r
1322\r
1323--*/\r
1324{\r
1325\r
1326 EFI_FW_VOL_BLOCK_DEVICE *FvbDevice;\r
1327\r
1328 FvbDevice = FVB_DEVICE_FROM_THIS (This);\r
1329\r
1330 return FvbReadBlock (FvbDevice->Instance, Lba, Offset, NumBytes, Buffer, mFvbModuleGlobal, EfiGoneVirtual ());\r
1331}\r
1332//\r
1333// FVB Extension Protocols\r
1334//\r
1335EFI_STATUS\r
1336EFIAPI\r
1337FvbExtendProtocolEraseCustomBlockRange (\r
1338 IN EFI_FVB_EXTENSION_PROTOCOL *This,\r
1339 IN EFI_LBA StartLba,\r
1340 IN UINTN OffsetStartLba,\r
1341 IN EFI_LBA LastLba,\r
1342 IN UINTN OffsetLastLba\r
1343 )\r
1344/*++\r
1345\r
1346Routine Description:\r
1347 Erases and initializes a specified range of a firmware volume\r
1348\r
1349Arguments:\r
1350 This - Calling context\r
1351 StartLba - The starting logical block index to be erased\r
1352 OffsetStartLba - Offset into the starting block at which to \r
1353 begin erasing\r
1354 LastLba - The last logical block index to be erased\r
1355 OffsetStartLba - Offset into the last block at which to end erasing\r
1356\r
1357Returns: \r
1358 EFI_SUCCESS - The firmware volume was erased successfully\r
1359 EFI_ACCESS_DENIED - The firmware volume is in the WriteDisabled state\r
1360 EFI_DEVICE_ERROR - The block device is not functioning correctly and \r
1361 could not be written. Firmware device may have been\r
1362 partially erased\r
1363\r
1364--*/\r
1365{\r
1366 EFI_FW_VOL_BLOCK_DEVICE *FvbDevice;\r
1367\r
1368 FvbDevice = FVB_EXTEND_DEVICE_FROM_THIS (This);\r
1369\r
1370 return FvbEraseCustomBlockRange (\r
1371 FvbDevice->Instance,\r
1372 StartLba,\r
1373 OffsetStartLba,\r
1374 LastLba,\r
1375 OffsetLastLba,\r
1376 mFvbModuleGlobal,\r
1377 EfiGoneVirtual ()\r
1378 );\r
1379}\r
1380\r
1381STATIC\r
1382EFI_STATUS\r
1383ValidateFvHeader (\r
1384 EFI_FIRMWARE_VOLUME_HEADER *FwVolHeader\r
1385 )\r
1386/*++\r
1387\r
1388Routine Description:\r
1389 Check the integrity of firmware volume header\r
1390\r
1391Arguments:\r
1392 FwVolHeader - A pointer to a firmware volume header\r
1393\r
1394Returns: \r
1395 EFI_SUCCESS - The firmware volume is consistent\r
1396 EFI_NOT_FOUND - The firmware volume has corrupted. So it is not an FV\r
1397\r
1398--*/\r
1399{\r
1400 UINT16 *Ptr;\r
1401 UINT16 HeaderLength;\r
1402 UINT16 Checksum;\r
1403\r
1404 //\r
1405 // Verify the header revision, header signature, length\r
1406 // Length of FvBlock cannot be 2**64-1\r
1407 // HeaderLength cannot be an odd number\r
1408 //\r
1409 if ((FwVolHeader->Revision != EFI_FVH_REVISION) ||\r
1410 (FwVolHeader->Signature != EFI_FVH_SIGNATURE) ||\r
1411 (FwVolHeader->FvLength == ((UINTN) -1)) ||\r
1412 ((FwVolHeader->HeaderLength & 0x01) != 0)\r
1413 ) {\r
1414 return EFI_NOT_FOUND;\r
1415 }\r
1416 //\r
1417 // Verify the header checksum\r
1418 //\r
1419 HeaderLength = (UINT16) (FwVolHeader->HeaderLength / 2);\r
1420 Ptr = (UINT16 *) FwVolHeader;\r
1421 Checksum = 0;\r
1422 while (HeaderLength > 0) {\r
1423 Checksum = *Ptr++;\r
1424 HeaderLength--;\r
1425 }\r
1426\r
1427 if (Checksum != 0) {\r
1428 return EFI_NOT_FOUND;\r
1429 }\r
1430\r
1431 return EFI_SUCCESS;\r
1432}\r
1433\r
1434BOOLEAN\r
1435FvbGetCfiSupported (\r
1436 IN UINTN LbaAddress\r
1437 )\r
1438/*++\r
1439\r
1440Routine Description:\r
1441 Check if the firmware volume is CFI typed flash\r
1442\r
1443Arguments:\r
1444 LbaAddress - The physical address of the firmware volume\r
1445\r
1446Returns: \r
1447 TRUE - CFI supported\r
1448 FALSE - CFI un-supported\r
1449\r
1450--*/\r
1451{\r
1452 UINT8 HubData[8];\r
1453 UINT8 HubCommand;\r
1454 BOOLEAN Supported;\r
1455\r
1456 Supported = TRUE;\r
1457\r
1458 //\r
1459 // Issue CFI Query (98h) to address 55h\r
1460 //\r
1461 HubCommand = CFI_QUERY;\r
1462 FvbMemWrite8 ((LbaAddress + 0x55), HubCommand);\r
1463 //\r
1464 // x8 device in 8-bit mode?\r
1465 //\r
1466 EfiMemRead (EfiCpuIoWidthUint8, (LbaAddress + 0x10), 0x3, &HubData);\r
1467 if (!EfiCompareMem (HubData, "QRY", 3)) {\r
1468 goto Done;\r
1469 }\r
1470 //\r
1471 // paired x8 devices?\r
1472 //\r
1473 EfiMemRead (EfiCpuIoWidthUint8, (LbaAddress + 0x20), 0x6, &HubData);\r
1474 if (!EfiCompareMem (HubData, "QQRRYY", 6)) {\r
1475 goto Done;\r
1476 }\r
1477 //\r
1478 // x16 device in 16-bit mode?\r
1479 //\r
1480 EfiMemRead (EfiCpuIoWidthUint8, (LbaAddress + 0x20), 0x4, &HubData);\r
1481 if ((!EfiCompareMem (&HubData[0], "R", 2)) && (!EfiCompareMem (&HubData[2], "Q", 2))) {\r
1482 goto Done;\r
1483 }\r
1484 //\r
1485 // x16 device in 8-bit mode?\r
1486 //\r
1487 EfiMemRead (EfiCpuIoWidthUint8, (LbaAddress + 0x20), 0x3, &HubData);\r
1488 if (!EfiCompareMem (HubData, "QQR", 3)) {\r
1489 goto Done;\r
1490 }\r
1491 //\r
1492 // 2 x16 devices in 8-bit mode (paired chip configuration)?\r
1493 //\r
1494 EfiMemRead (EfiCpuIoWidthUint8, (LbaAddress + 0x40), 0x6, &HubData);\r
1495 if (!EfiCompareMem (HubData, "QQQQRR", 6)) {\r
1496 goto Done;\r
1497 }\r
1498 //\r
1499 // x32 device in 8-bit mode\r
1500 //\r
1501 EfiMemRead (EfiCpuIoWidthUint8, (LbaAddress + 0x40), 0x5, &HubData);\r
1502 if (!EfiCompareMem (HubData, "QQQQR", 5)) {\r
1503 goto Done;\r
1504 }\r
1505 //\r
1506 // x32 device in 32-bit mode\r
1507 //\r
1508 if ((!EfiCompareMem (&HubData[0], "R", 2)) && (((UINT16) HubData[2]) == 0) && (HubData[4] == 'Q')) {\r
1509 goto Done;\r
1510 }\r
1511 //\r
1512 // If it got to here, CFI is not supported\r
1513 //\r
1514 Supported = FALSE;\r
1515\r
1516Done:\r
1517 //\r
1518 // Bug Fix #4071:\r
1519 // Issue command FWH_READ_ARRAY_COMMAND (0xff) at the end of this service to\r
1520 // guarantee that the FWH is back in read mode again\r
1521 //\r
1522 HubCommand = FWH_READ_ARRAY_COMMAND;\r
1523 FvbMemWrite8 (LbaAddress, HubCommand);\r
1524\r
1525 return Supported;\r
1526}\r
1527\r
1528EFI_STATUS\r
1529GetFvbHeader (\r
1530 VOID **HobList,\r
1531 EFI_FIRMWARE_VOLUME_HEADER **FwVolHeader,\r
1532 EFI_PHYSICAL_ADDRESS *BaseAddress,\r
1533 BOOLEAN *WriteBack\r
1534 )\r
1535{\r
1536 EFI_STATUS Status;\r
1537 VOID *Buffer;\r
1538 EFI_FLASH_MAP_ENTRY_DATA *FlashMapEntry;\r
1539 EFI_FLASH_SUBAREA_ENTRY *FlashMapSubEntry;\r
1540\r
1541 Status = EFI_SUCCESS;\r
1542 *FwVolHeader = NULL;\r
1543 *WriteBack = FALSE;\r
1544\r
1545 Status = GetNextGuidHob (HobList, &gEfiFlashMapHobGuid, &Buffer, NULL);\r
1546 if (EFI_ERROR (Status)) {\r
1547 return EFI_NOT_FOUND;\r
1548 }\r
1549\r
1550 FlashMapEntry = (EFI_FLASH_MAP_ENTRY_DATA *) Buffer;\r
1551 FlashMapSubEntry = &FlashMapEntry->Entries[0];\r
1552 //\r
1553 // Check if it is a "FVB" area\r
1554 //\r
1555 if (!EfiCompareGuid (&FlashMapSubEntry->FileSystem, &gEfiFirmwareVolumeBlockProtocolGuid)) {\r
1556 return Status;\r
1557 }\r
1558 //\r
1559 // Check if it is a "real" flash\r
1560 //\r
1561 if (FlashMapSubEntry->Attributes != (EFI_FLASH_AREA_FV | EFI_FLASH_AREA_MEMMAPPED_FV)) {\r
1562 return Status;\r
1563 }\r
1564\r
1565 *BaseAddress = FlashMapSubEntry->Base;\r
1566 DEBUG ((EFI_D_ERROR, "FlashMap HOB: BaseAddress = 0x%lx\n", *BaseAddress));\r
1567\r
1568 *FwVolHeader = (EFI_FIRMWARE_VOLUME_HEADER *) (UINTN) (*BaseAddress);\r
1569 Status = ValidateFvHeader (*FwVolHeader);\r
1570 if (EFI_ERROR (Status)) {\r
1571 //\r
1572 // Get FvbInfo\r
1573 //\r
1574 *WriteBack = TRUE;\r
1575 DEBUG ((EFI_D_ERROR, "BaseAddress = 0x%lx\n", BaseAddress));\r
1576 Status = GetFvbInfo (*BaseAddress, FwVolHeader);\r
1577 DEBUG ((EFI_D_ERROR, "Fvb: FV header invalid, GetFvbInfo - %r\n", Status));\r
1578 ASSERT_EFI_ERROR (Status);\r
1579 }\r
1580\r
1581 return EFI_SUCCESS;\r
1582}\r
1583\r
1584EFI_STATUS\r
1585EFIAPI\r
1586FvbInitialize (\r
1587 IN EFI_HANDLE ImageHandle,\r
1588 IN EFI_SYSTEM_TABLE *SystemTable\r
1589 )\r
1590/*++\r
1591\r
1592Routine Description:\r
1593 This function does common initialization for FVB services\r
1594\r
1595Arguments:\r
1596\r
1597Returns:\r
1598\r
1599--*/\r
1600{\r
1601 EFI_STATUS Status;\r
1602 EFI_FW_VOL_INSTANCE *FwhInstance;\r
1603 EFI_FIRMWARE_VOLUME_HEADER *FwVolHeader;\r
1604 VOID *HobList;\r
1605 VOID *FirmwareVolumeHobList;\r
1606 UINT32 BufferSize;\r
1607 EFI_FV_BLOCK_MAP_ENTRY *PtrBlockMapEntry;\r
1608 UINTN LbaAddress;\r
1609 UINT8 Data;\r
1610 UINTN BlockIndex2;\r
1611 BOOLEAN WriteEnabled;\r
1612 BOOLEAN WriteLocked;\r
1613 EFI_HANDLE FwbHandle;\r
1614 EFI_FW_VOL_BLOCK_DEVICE *FvbDevice;\r
1615 EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL *OldFwbInterface;\r
1616 EFI_DEVICE_PATH_PROTOCOL *TempFwbDevicePath;\r
1617 FV_DEVICE_PATH TempFvbDevicePathData;\r
1618 UINT32 MaxLbaSize;\r
1619 BOOLEAN CfiEnabled;\r
1620 EFI_PHYSICAL_ADDRESS BaseAddress;\r
1621 BOOLEAN WriteBack;\r
1622 UINTN NumOfBlocks;\r
1623 UINTN HeaderLength;\r
1624\r
1625 INITIALIZE_SCRIPT (ImageHandle, SystemTable);\r
1626\r
1627 EfiInitializeRuntimeDriverLib (ImageHandle, SystemTable, FvbVirtualddressChangeEvent);\r
1628\r
1629 Status = EfiGetSystemConfigurationTable (&gEfiHobListGuid, &HobList);\r
1630 HeaderLength = 0;\r
1631 //\r
1632 // No FV HOBs found\r
1633 //\r
1634 ASSERT_EFI_ERROR (Status);\r
1635\r
1636 //\r
1637 // Allocate runtime services data for global variable, which contains\r
1638 // the private data of all firmware volume block instances\r
1639 //\r
1640 Status = gBS->AllocatePool (\r
1641 EfiRuntimeServicesData,\r
1642 sizeof (ESAL_FWB_GLOBAL),\r
1643 &mFvbModuleGlobal\r
1644 );\r
1645 ASSERT_EFI_ERROR (Status);\r
1646\r
1647 EnablePlatformFvb ();\r
1648 EnableFvbWrites (TRUE);\r
1649\r
1650 //\r
1651 // Calculate the total size for all firmware volume block instances\r
1652 //\r
1653 BufferSize = 0;\r
1654 FirmwareVolumeHobList = HobList;\r
1655 do {\r
1656 Status = GetFvbHeader (&FirmwareVolumeHobList, &FwVolHeader, &BaseAddress, &WriteBack);\r
1657 if (EFI_ERROR (Status)) {\r
1658 break;\r
1659 }\r
1660\r
1661 if (FwVolHeader) {\r
1662 BufferSize += (FwVolHeader->HeaderLength + sizeof (EFI_FW_VOL_INSTANCE) - sizeof (EFI_FIRMWARE_VOLUME_HEADER));\r
1663 }\r
1664 } while (TRUE);\r
1665\r
1666 //\r
1667 // Only need to allocate once. There is only one copy of physical memory for\r
1668 // the private data of each FV instance. But in virtual mode or in physical\r
1669 // mode, the address of the the physical memory may be different.\r
1670 //\r
1671 Status = gBS->AllocatePool (\r
1672 EfiRuntimeServicesData,\r
1673 BufferSize,\r
1674 &mFvbModuleGlobal->FvInstance[FVB_PHYSICAL]\r
1675 );\r
1676 ASSERT_EFI_ERROR (Status);\r
1677\r
1678 //\r
1679 // Make a virtual copy of the FvInstance pointer.\r
1680 //\r
1681 FwhInstance = mFvbModuleGlobal->FvInstance[FVB_PHYSICAL];\r
1682 mFvbModuleGlobal->FvInstance[FVB_VIRTUAL] = FwhInstance;\r
1683\r
1684 mFvbModuleGlobal->NumFv = 0;\r
1685 FirmwareVolumeHobList = HobList;\r
1686\r
1687 MaxLbaSize = 0;\r
1688\r
1689 //\r
1690 // Fill in the private data of each firmware volume block instance\r
1691 //\r
1692 do {\r
1693 Status = GetFvbHeader (&FirmwareVolumeHobList, &FwVolHeader, &BaseAddress, &WriteBack);\r
1694 if (EFI_ERROR (Status)) {\r
1695 break;\r
1696 }\r
1697\r
1698 if (!FwVolHeader) {\r
1699 continue;\r
1700 }\r
1701\r
1702 EfiCopyMem ((UINTN *) &(FwhInstance->VolumeHeader), (UINTN *) FwVolHeader, FwVolHeader->HeaderLength);\r
1703 FwVolHeader = &(FwhInstance->VolumeHeader);\r
1704\r
1705 FwhInstance->FvBase[FVB_PHYSICAL] = (UINTN) BaseAddress;\r
1706 FwhInstance->FvBase[FVB_VIRTUAL] = (UINTN) BaseAddress;\r
1707\r
1708 //\r
1709 // FwhInstance->FvWriteBase may not be the same as FwhInstance->FvBase\r
1710 //\r
1711 PlatformGetFvbWriteBase (\r
1712 (UINTN) BaseAddress,\r
1713 (UINTN *) &(FwhInstance->FvWriteBase[FVB_PHYSICAL]),\r
1714 &WriteEnabled\r
1715 );\r
1716 //\r
1717 // Every pointer should have a virtual copy.\r
1718 //\r
1719 FwhInstance->FvWriteBase[FVB_VIRTUAL] = FwhInstance->FvWriteBase[FVB_PHYSICAL];\r
1720\r
1721 FwhInstance->WriteEnabled = WriteEnabled;\r
1722 EfiInitializeLock (&(FwhInstance->FvbDevLock), EFI_TPL_HIGH_LEVEL);\r
1723\r
1724 LbaAddress = (UINTN) FwhInstance->FvWriteBase[0];\r
1725 NumOfBlocks = 0;\r
1726 WriteLocked = FALSE;\r
1727\r
1728 if (WriteEnabled) {\r
1729 CfiEnabled = FvbGetCfiSupported (LbaAddress);\r
1730 for (PtrBlockMapEntry = FwVolHeader->FvBlockMap; PtrBlockMapEntry->NumBlocks != 0; PtrBlockMapEntry++) {\r
1731\r
1732 for (BlockIndex2 = 0; BlockIndex2 < PtrBlockMapEntry->NumBlocks; BlockIndex2++) {\r
1733\r
1734 if (SetPlatformFvbLock (LbaAddress)) {\r
1735 //\r
1736 // Clear all write-lock and read-lock HW bits\r
1737 // For sync3, the software will enforce the protection\r
1738 //\r
1739 if (CfiEnabled) {\r
1740 Data = CFI_BLOCK_LOCK_UNLOCK;\r
1741 FvbMemWrite8 (LbaAddress, Data);\r
1742 Data = CFI_BLOCK_UNLOCK_CONFIRM;\r
1743 FvbMemWrite8 (LbaAddress, Data);\r
1744 while (TRUE) {\r
1745 EfiMemRead (EfiCpuIoWidthUint8, (LbaAddress + 2), 1, &Data);\r
1746 if (Data & 0x80) {\r
1747 break;\r
1748 }\r
1749 }\r
1750\r
1751 Data = FWH_READ_ARRAY_COMMAND;\r
1752 FvbMemWrite8 (LbaAddress, Data);\r
1753 } else {\r
1754 EfiMemRead (EfiCpuIoWidthUint8, (LbaAddress - 0x400000 + 2), 0x1, &Data);\r
1755 //\r
1756 // bugbug: lock down is block based, not FV based. Here we assume that\r
1757 // the FV is locked if one of its block is locked\r
1758 //\r
1759 if ((Data & FWH_WRITE_LOCK) && (Data & FWH_LOCK_DOWN)) {\r
1760 //\r
1761 // the flash is locked and locked down\r
1762 //\r
1763 WriteLocked = TRUE;\r
1764 } else {\r
1765 Data &= ~(FWH_WRITE_LOCK | FWH_READ_LOCK | FWH_LOCK_DOWN);\r
1766\r
1767 //\r
1768 // Save boot script for S3 resume\r
1769 //\r
1770 SCRIPT_MEM_WRITE (\r
1771 EFI_ACPI_S3_RESUME_SCRIPT_TABLE,\r
1772 EfiBootScriptWidthUint8,\r
1773 (UINT64) (LbaAddress - 0x400000 + 2),\r
1774 1,\r
1775 &Data\r
1776 );\r
1777\r
1778 FvbMemWrite8 ((LbaAddress - 0x400000 + 2), Data);\r
1779 }\r
1780 }\r
1781 }\r
1782\r
1783 LbaAddress += PtrBlockMapEntry->BlockLength;\r
1784 }\r
1785 //\r
1786 // Get the maximum size of a block. The size will be used to allocate\r
1787 // buffer for Scratch space, the intermediate buffer for FVB extension\r
1788 // protocol\r
1789 //\r
1790 if (MaxLbaSize < PtrBlockMapEntry->BlockLength) {\r
1791 MaxLbaSize = PtrBlockMapEntry->BlockLength;\r
1792 }\r
1793\r
1794 NumOfBlocks = NumOfBlocks + PtrBlockMapEntry->NumBlocks;\r
1795 }\r
1796 //\r
1797 // Write back a healthy FV header\r
1798 //\r
1799 if (WriteBack && (!WriteLocked)) {\r
1800 Status = FlashFdErase (\r
1801 (UINTN) FwhInstance->FvWriteBase[0],\r
1802 (UINTN) BaseAddress,\r
1803 FwVolHeader->FvBlockMap->BlockLength\r
1804 );\r
1805\r
1806 HeaderLength = (UINTN) FwVolHeader->HeaderLength;\r
1807 Status = FlashFdWrite (\r
1808 (UINTN) FwhInstance->FvWriteBase[0],\r
1809 (UINTN) BaseAddress,\r
1810 (UINTN *) &HeaderLength,\r
1811 (UINT8 *) FwVolHeader,\r
1812 FwVolHeader->FvBlockMap->BlockLength\r
1813 );\r
1814 \r
1815 FwVolHeader->HeaderLength = (UINT16) HeaderLength; \r
1816 DEBUG ((EFI_D_ERROR, "Fvb: FV header invalid, write back - %r\n", Status));\r
1817 }\r
1818 }\r
1819 //\r
1820 // The total number of blocks in the FV.\r
1821 //\r
1822 FwhInstance->NumOfBlocks = NumOfBlocks;\r
1823\r
1824 //\r
1825 // If the FV is write locked, set the appropriate attributes\r
1826 //\r
1827 if (WriteLocked) {\r
1828 //\r
1829 // write disabled\r
1830 //\r
1831 FwhInstance->VolumeHeader.Attributes &= ~EFI_FVB_WRITE_STATUS;\r
1832 //\r
1833 // lock enabled\r
1834 //\r
1835 FwhInstance->VolumeHeader.Attributes |= EFI_FVB_LOCK_STATUS;\r
1836 }\r
1837 //\r
1838 // Add a FVB Protocol Instance\r
1839 //\r
1840 Status = gBS->AllocatePool (\r
1841 EfiRuntimeServicesData,\r
1842 sizeof (EFI_FW_VOL_BLOCK_DEVICE),\r
1843 &FvbDevice\r
1844 );\r
1845 ASSERT_EFI_ERROR (Status);\r
1846\r
1847 EfiCopyMem (FvbDevice, &mFvbDeviceTemplate, sizeof (EFI_FW_VOL_BLOCK_DEVICE));\r
1848\r
1849 FvbDevice->Instance = mFvbModuleGlobal->NumFv;\r
1850 mFvbModuleGlobal->NumFv++;\r
1851\r
1852 //\r
1853 // Set up the devicepath\r
1854 //\r
1855 FvbDevice->DevicePath.MemMapDevPath.StartingAddress = BaseAddress;\r
1856 FvbDevice->DevicePath.MemMapDevPath.EndingAddress = BaseAddress + (FwVolHeader->FvLength - 1);\r
1857\r
1858 //\r
1859 // Find a handle with a matching device path that has supports FW Block protocol\r
1860 //\r
1861 TempFwbDevicePath = (EFI_DEVICE_PATH_PROTOCOL *) &TempFvbDevicePathData;\r
1862 EfiCopyMem (TempFwbDevicePath, &FvbDevice->DevicePath, sizeof (FV_DEVICE_PATH));\r
1863 Status = gBS->LocateDevicePath (&gEfiFirmwareVolumeBlockProtocolGuid, &TempFwbDevicePath, &FwbHandle);\r
1864 if (EFI_ERROR (Status)) {\r
1865 //\r
1866 // LocateDevicePath fails so install a new interface and device path\r
1867 //\r
1868 FwbHandle = NULL;\r
1869 Status = gBS->InstallMultipleProtocolInterfaces (\r
1870 &FwbHandle,\r
1871 &gEfiFirmwareVolumeBlockProtocolGuid,\r
1872 &FvbDevice->FwVolBlockInstance,\r
1873 &gEfiDevicePathProtocolGuid,\r
1874 &FvbDevice->DevicePath,\r
1875 NULL\r
1876 );\r
1877 ASSERT_EFI_ERROR (Status);\r
1878 } else if (EfiIsDevicePathEnd (TempFwbDevicePath)) {\r
1879 //\r
1880 // Device allready exists, so reinstall the FVB protocol\r
1881 //\r
1882 Status = gBS->HandleProtocol (\r
1883 FwbHandle,\r
1884 &gEfiFirmwareVolumeBlockProtocolGuid,\r
1885 &OldFwbInterface\r
1886 );\r
1887 ASSERT_EFI_ERROR (Status);\r
1888\r
1889 Status = gBS->ReinstallProtocolInterface (\r
1890 FwbHandle,\r
1891 &gEfiFirmwareVolumeBlockProtocolGuid,\r
1892 OldFwbInterface,\r
1893 &FvbDevice->FwVolBlockInstance\r
1894 );\r
1895 ASSERT_EFI_ERROR (Status);\r
1896\r
1897 } else {\r
1898 //\r
1899 // There was a FVB protocol on an End Device Path node\r
1900 //\r
1901 ASSERT (FALSE);\r
1902 }\r
1903 //\r
1904 // Install FVB Extension Protocol on the same handle\r
1905 //\r
1906 Status = gBS->InstallMultipleProtocolInterfaces (\r
1907 &FwbHandle,\r
1908 &gEfiFvbExtensionProtocolGuid,\r
1909 &FvbDevice->FvbExtension,\r
1910 &gEfiAlternateFvBlockGuid,\r
1911 NULL,\r
1912 NULL\r
1913 );\r
1914\r
1915 ASSERT_EFI_ERROR (Status);\r
1916\r
1917 FwhInstance = (EFI_FW_VOL_INSTANCE *)\r
1918 (\r
1919 (UINTN) ((UINT8 *) FwhInstance) + FwVolHeader->HeaderLength +\r
1920 (sizeof (EFI_FW_VOL_INSTANCE) - sizeof (EFI_FIRMWARE_VOLUME_HEADER))\r
1921 );\r
1922 } while (TRUE);\r
1923\r
1924 //\r
1925 // Allocate for scratch space, an intermediate buffer for FVB extention\r
1926 //\r
1927 Status = gBS->AllocatePool (\r
1928 EfiRuntimeServicesData,\r
1929 MaxLbaSize,\r
1930 &mFvbModuleGlobal->FvbScratchSpace[FVB_PHYSICAL]\r
1931 );\r
1932 ASSERT_EFI_ERROR (Status);\r
1933\r
1934 mFvbModuleGlobal->FvbScratchSpace[FVB_VIRTUAL] = mFvbModuleGlobal->FvbScratchSpace[FVB_PHYSICAL];\r
1935\r
1936 FvbSpecificInitialize (mFvbModuleGlobal);\r
1937\r
1938 return EnableFvbWrites (FALSE);\r
1939}\r