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