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