]> git.proxmox.com Git - mirror_edk2.git/blame - QuarkPlatformPkg/Platform/SpiFvbServices/FwBlockService.c
QuarkPlatformPkg/SpiFvbServices: correct NumOfLba vararg type in EraseBlocks()
[mirror_edk2.git] / QuarkPlatformPkg / Platform / SpiFvbServices / FwBlockService.c
CommitLineData
b303605e
MK
1/** @file\r
2\r
0c5d4079 3Copyright (c) 2013-2016 Intel Corporation.\r
b303605e
MK
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
b303605e
MK
593\r
594 WriteAddress -= (PcdGet32 (PcdFlashAreaBaseAddress));\r
595 if (mInSmmMode == 0 ) { // !(EfiInManagementInterrupt ())) {\r
596 Status = mFvbModuleGlobal->SpiProtocol->Execute (\r
597 mFvbModuleGlobal->SpiProtocol,\r
598 SPI_OPCODE_ERASE_INDEX, // OpcodeIndex\r
599 0, // PrefixOpcodeIndex\r
600 FALSE, // DataCycle\r
601 TRUE, // Atomic\r
602 FALSE, // ShiftOut\r
603 WriteAddress, // Address\r
604 0, // Data Number\r
605 NULL,\r
606 EnumSpiRegionBios // SPI_REGION_TYPE\r
607 );\r
608 } else {\r
609 Status = mFvbModuleGlobal->SmmSpiProtocol->Execute (\r
610 mFvbModuleGlobal->SmmSpiProtocol,\r
611 SPI_OPCODE_ERASE_INDEX, // OpcodeIndex\r
612 0, // PrefixOpcodeIndex\r
613 FALSE, // DataCycle\r
614 TRUE, // Atomic\r
615 FALSE, // ShiftOut\r
616 WriteAddress, // Address\r
617 0, // Data Number\r
618 NULL,\r
619 EnumSpiRegionBios // SPI_REGION_TYPE\r
620 );\r
621 }\r
622\r
623 AsmWbinvd ();\r
624\r
625 return Status;\r
626}\r
627\r
628EFI_STATUS\r
629FvbWriteBlock (\r
630 IN UINTN Instance,\r
631 IN EFI_LBA Lba,\r
632 IN UINTN BlockOffset,\r
633 IN OUT UINTN *NumBytes,\r
634 IN UINT8 *Buffer,\r
635 IN ESAL_FWB_GLOBAL *Global,\r
636 IN BOOLEAN Virtual\r
637 )\r
638/*++\r
639\r
640Routine Description:\r
641 Writes specified number of bytes from the input buffer to the block\r
642\r
643Arguments:\r
644 Instance - The FV instance to be written to\r
645 Lba - The starting logical block index to write to\r
646 BlockOffset - Offset into the block at which to begin writing\r
647 NumBytes - Pointer that on input contains the total size of\r
648 the buffer. On output, it contains the total number\r
649 of bytes actually written\r
650 Buffer - Pointer to a caller allocated buffer that contains\r
651 the source for the write\r
652 Global - Pointer to ESAL_FWB_GLOBAL that contains all\r
653 instance data\r
654 Virtual - Whether CPU is in virtual or physical mode\r
655\r
656Returns:\r
657 EFI_SUCCESS - The firmware volume was written successfully\r
658 EFI_BAD_BUFFER_SIZE - Write attempted across a LBA boundary. On output,\r
659 NumBytes contains the total number of bytes\r
660 actually written\r
661 EFI_ACCESS_DENIED - The firmware volume is in the WriteDisabled state\r
662 EFI_DEVICE_ERROR - The block device is not functioning correctly and\r
663 could not be written\r
664 EFI_INVALID_PARAMETER - Instance not found, or NumBytes, Buffer are NULL\r
665\r
666--*/\r
667{\r
668 EFI_FVB_ATTRIBUTES_2 Attributes;\r
669 UINTN LbaAddress;\r
670 UINTN LbaWriteAddress;\r
671 UINTN LbaLength;\r
672 EFI_FW_VOL_INSTANCE *FwhInstance;\r
673 EFI_STATUS Status;\r
674 EFI_STATUS ReturnStatus;\r
675\r
676 FwhInstance = NULL;\r
677\r
678 //\r
679 // Find the right instance of the FVB private data\r
680 //\r
681 Status = GetFvbInstance (Instance, Global, &FwhInstance, Virtual);\r
682 ASSERT_EFI_ERROR (Status);\r
683\r
684 //\r
685 // Writes are enabled in the init routine itself\r
686 //\r
687 if (!FwhInstance->WriteEnabled) {\r
688 return EFI_ACCESS_DENIED;\r
689 }\r
690 //\r
691 // Check for invalid conditions\r
692 //\r
693 if ((NumBytes == NULL) || (Buffer == NULL)) {\r
694 return EFI_INVALID_PARAMETER;\r
695 }\r
696\r
697 if (*NumBytes == 0) {\r
698 return EFI_INVALID_PARAMETER;\r
699 }\r
700\r
701 Status = FvbGetLbaAddress (Instance, Lba, &LbaAddress, &LbaWriteAddress, &LbaLength, NULL, Global, Virtual);\r
702 if (EFI_ERROR (Status)) {\r
703 return Status;\r
704 }\r
705 //\r
706 // Check if the FV is write enabled\r
707 //\r
708 FvbGetVolumeAttributes (Instance, &Attributes, Global, Virtual);\r
709\r
710 if ((Attributes & EFI_FVB2_WRITE_STATUS) == 0) {\r
711 return EFI_ACCESS_DENIED;\r
712 }\r
713 //\r
714 // Perform boundary checks and adjust NumBytes\r
715 //\r
716 if (BlockOffset > LbaLength) {\r
717 return EFI_INVALID_PARAMETER;\r
718 }\r
719\r
720 if (LbaLength < (*NumBytes + BlockOffset)) {\r
721 *NumBytes = (UINT32) (LbaLength - BlockOffset);\r
722 Status = EFI_BAD_BUFFER_SIZE;\r
723 }\r
724\r
725 ReturnStatus = FlashFdWrite (\r
726 LbaWriteAddress + BlockOffset,\r
727 LbaAddress,\r
728 NumBytes,\r
729 Buffer,\r
730 LbaLength\r
731 );\r
732 if (EFI_ERROR (ReturnStatus)) {\r
733 return ReturnStatus;\r
734 }\r
735\r
736 return Status;\r
737}\r
738\r
739EFI_STATUS\r
740FvbEraseBlock (\r
741 IN UINTN Instance,\r
742 IN EFI_LBA Lba,\r
743 IN ESAL_FWB_GLOBAL *Global,\r
744 IN BOOLEAN Virtual\r
745 )\r
746/*++\r
747\r
748Routine Description:\r
749 Erases and initializes a firmware volume block\r
750\r
751Arguments:\r
752 Instance - The FV instance to be erased\r
753 Lba - The logical block index to be erased\r
754 Global - Pointer to ESAL_FWB_GLOBAL that contains all\r
755 instance data\r
756 Virtual - Whether CPU is in virtual or physical mode\r
757\r
758Returns:\r
759 EFI_SUCCESS - The erase request was successfully completed\r
760 EFI_ACCESS_DENIED - The firmware volume is in the WriteDisabled state\r
761 EFI_DEVICE_ERROR - The block device is not functioning correctly and\r
762 could not be written. Firmware device may have been\r
763 partially erased\r
764 EFI_INVALID_PARAMETER - Instance not found\r
765\r
766--*/\r
767{\r
768\r
769 EFI_FVB_ATTRIBUTES_2 Attributes;\r
770 UINTN LbaAddress;\r
771 UINTN LbaWriteAddress;\r
772 EFI_FW_VOL_INSTANCE *FwhInstance;\r
773 UINTN LbaLength;\r
774 EFI_STATUS Status;\r
775 UINTN SectorNum;\r
776 UINTN Index;\r
777\r
778 FwhInstance = NULL;\r
779\r
780 //\r
781 // Find the right instance of the FVB private data\r
782 //\r
783 Status = GetFvbInstance (Instance, Global, &FwhInstance, Virtual);\r
784 ASSERT_EFI_ERROR (Status);\r
785\r
786 //\r
787 // Writes are enabled in the init routine itself\r
788 //\r
789 if (!FwhInstance->WriteEnabled) {\r
790 return EFI_ACCESS_DENIED;\r
791 }\r
792 //\r
793 // Check if the FV is write enabled\r
794 //\r
795 FvbGetVolumeAttributes (Instance, &Attributes, Global, Virtual);\r
796\r
797 if ((Attributes & EFI_FVB2_WRITE_STATUS) == 0) {\r
798 return EFI_ACCESS_DENIED;\r
799 }\r
800 //\r
801 // Get the starting address of the block for erase. For debug reasons,\r
802 // LbaWriteAddress may not be the same as LbaAddress.\r
803 //\r
804 Status = FvbGetLbaAddress (Instance, Lba, &LbaAddress, &LbaWriteAddress, &LbaLength, NULL, Global, Virtual);\r
805 if (EFI_ERROR (Status)) {\r
806 return Status;\r
807 }\r
808\r
809 SectorNum = LbaLength / SPI_ERASE_SECTOR_SIZE;\r
810 for (Index = 0; Index < SectorNum; Index++){\r
811 Status = FlashFdErase (\r
812 LbaWriteAddress + Index * SPI_ERASE_SECTOR_SIZE,\r
813 LbaAddress,\r
814 SPI_ERASE_SECTOR_SIZE\r
815 );\r
816 if (Status != EFI_SUCCESS){\r
817 break;\r
818 }\r
819 }\r
820\r
821 return Status;\r
822}\r
823\r
824EFI_STATUS\r
825FvbEraseCustomBlockRange (\r
826 IN UINTN Instance,\r
827 IN EFI_LBA StartLba,\r
828 IN UINTN OffsetStartLba,\r
829 IN EFI_LBA LastLba,\r
830 IN UINTN OffsetLastLba,\r
831 IN ESAL_FWB_GLOBAL *Global,\r
832 IN BOOLEAN Virtual\r
833 )\r
834/*++\r
835\r
836Routine Description:\r
837 Erases and initializes a specified range of a firmware volume\r
838\r
839Arguments:\r
840 Instance - The FV instance to be erased\r
841 StartLba - The starting logical block index to be erased\r
842 OffsetStartLba - Offset into the starting block at which to\r
843 begin erasing\r
844 LastLba - The last logical block index to be erased\r
845 OffsetStartLba - Offset into the last block at which to end erasing\r
846 Global - Pointer to ESAL_FWB_GLOBAL that contains all\r
847 instance data\r
848 Virtual - Whether CPU is in virtual or physical mode\r
849\r
850Returns:\r
851 EFI_SUCCESS - The firmware volume was erased successfully\r
852 EFI_ACCESS_DENIED - The firmware volume is in the WriteDisabled state\r
853 EFI_DEVICE_ERROR - The block device is not functioning correctly and\r
854 could not be written. Firmware device may have been\r
855 partially erased\r
856 EFI_INVALID_PARAMETER - Instance not found\r
857\r
858--*/\r
859{\r
860 EFI_LBA Index;\r
861 UINTN LbaSize;\r
862 UINTN ScratchLbaSizeData;\r
863\r
864 //\r
865 // First LBA.\r
866 //\r
867 FvbGetLbaAddress (Instance, StartLba, NULL, NULL, &LbaSize, NULL, Global, Virtual);\r
868\r
869 //\r
870 // Use the scratch space as the intermediate buffer to transfer data\r
871 // Back up the first LBA in scratch space.\r
872 //\r
873 FvbReadBlock (Instance, StartLba, 0, &LbaSize, Global->FvbScratchSpace[Virtual], Global, Virtual);\r
874\r
875 //\r
876 // erase now\r
877 //\r
878 FvbEraseBlock (Instance, StartLba, Global, Virtual);\r
879 ScratchLbaSizeData = OffsetStartLba;\r
880\r
881 //\r
882 // write the data back to the first block\r
883 //\r
884 if (ScratchLbaSizeData > 0) {\r
885 FvbWriteBlock (Instance, StartLba, 0, &ScratchLbaSizeData, Global->FvbScratchSpace[Virtual], Global, Virtual);\r
886 }\r
887 //\r
888 // Middle LBAs\r
889 //\r
890 if (LastLba > (StartLba + 1)) {\r
891 for (Index = (StartLba + 1); Index <= (LastLba - 1); Index++) {\r
892 FvbEraseBlock (Instance, Index, Global, Virtual);\r
893 }\r
894 }\r
895 //\r
896 // Last LBAs, the same as first LBAs\r
897 //\r
898 if (LastLba > StartLba) {\r
899 FvbGetLbaAddress (Instance, LastLba, NULL, NULL, &LbaSize, NULL, Global, Virtual);\r
900 FvbReadBlock (Instance, LastLba, 0, &LbaSize, Global->FvbScratchSpace[Virtual], Global, Virtual);\r
901 FvbEraseBlock (Instance, LastLba, Global, Virtual);\r
902 }\r
903\r
904 ScratchLbaSizeData = LbaSize - (OffsetStartLba + 1);\r
905\r
906 return FvbWriteBlock (\r
907 Instance,\r
908 LastLba,\r
909 (OffsetLastLba + 1),\r
910 &ScratchLbaSizeData,\r
911 Global->FvbScratchSpace[Virtual],\r
912 Global,\r
913 Virtual\r
914 );\r
915}\r
916\r
917EFI_STATUS\r
918FvbSetVolumeAttributes (\r
919 IN UINTN Instance,\r
920 IN OUT EFI_FVB_ATTRIBUTES_2 *Attributes,\r
921 IN ESAL_FWB_GLOBAL *Global,\r
922 IN BOOLEAN Virtual\r
923 )\r
924/*++\r
925\r
926Routine Description:\r
927 Modifies the current settings of the firmware volume according to the\r
928 input parameter, and returns the new setting of the volume\r
929\r
930Arguments:\r
931 Instance - The FV instance whose attributes is going to be\r
932 modified\r
933 Attributes - On input, it is a pointer to EFI_FVB_ATTRIBUTES_2\r
934 containing the desired firmware volume settings.\r
935 On successful return, it contains the new settings\r
936 of the firmware volume\r
937 Global - Pointer to ESAL_FWB_GLOBAL that contains all\r
938 instance data\r
939 Virtual - Whether CPU is in virtual or physical mode\r
940\r
941Returns:\r
942 EFI_SUCCESS - Successfully returns\r
943 EFI_ACCESS_DENIED - The volume setting is locked and cannot be modified\r
944 EFI_INVALID_PARAMETER - Instance not found, or The attributes requested are\r
945 in conflict with the capabilities as declared in the\r
946 firmware volume header\r
947\r
948--*/\r
949{\r
950 EFI_FW_VOL_INSTANCE *FwhInstance;\r
951 EFI_FVB_ATTRIBUTES_2 OldAttributes;\r
952 EFI_FVB_ATTRIBUTES_2 *AttribPtr;\r
953 UINT32 Capabilities;\r
954 UINT32 OldStatus;\r
955 UINT32 NewStatus;\r
956 EFI_STATUS Status;\r
957\r
958 FwhInstance = NULL;\r
959\r
960 //\r
961 // Find the right instance of the FVB private data\r
962 //\r
963 Status = GetFvbInstance (Instance, Global, &FwhInstance, Virtual);\r
964 ASSERT_EFI_ERROR (Status);\r
965\r
966 AttribPtr = (EFI_FVB_ATTRIBUTES_2 *) &(FwhInstance->VolumeHeader.Attributes);\r
967 OldAttributes = *AttribPtr;\r
968 Capabilities = OldAttributes & EFI_FVB2_CAPABILITIES;\r
969 OldStatus = OldAttributes & EFI_FVB2_STATUS;\r
970 NewStatus = *Attributes & EFI_FVB2_STATUS;\r
971\r
972 //\r
973 // If firmware volume is locked, no status bit can be updated\r
974 //\r
975 if (OldAttributes & EFI_FVB2_LOCK_STATUS) {\r
976 if (OldStatus ^ NewStatus) {\r
977 return EFI_ACCESS_DENIED;\r
978 }\r
979 }\r
980 //\r
981 // Test read disable\r
982 //\r
983 if ((Capabilities & EFI_FVB2_READ_DISABLED_CAP) == 0) {\r
984 if ((NewStatus & EFI_FVB2_READ_STATUS) == 0) {\r
985 return EFI_INVALID_PARAMETER;\r
986 }\r
987 }\r
988 //\r
989 // Test read enable\r
990 //\r
991 if ((Capabilities & EFI_FVB2_READ_ENABLED_CAP) == 0) {\r
992 if (NewStatus & EFI_FVB2_READ_STATUS) {\r
993 return EFI_INVALID_PARAMETER;\r
994 }\r
995 }\r
996 //\r
997 // Test write disable\r
998 //\r
999 if ((Capabilities & EFI_FVB2_WRITE_DISABLED_CAP) == 0) {\r
1000 if ((NewStatus & EFI_FVB2_WRITE_STATUS) == 0) {\r
1001 return EFI_INVALID_PARAMETER;\r
1002 }\r
1003 }\r
1004 //\r
1005 // Test write enable\r
1006 //\r
1007 if ((Capabilities & EFI_FVB2_WRITE_ENABLED_CAP) == 0) {\r
1008 if (NewStatus & EFI_FVB2_WRITE_STATUS) {\r
1009 return EFI_INVALID_PARAMETER;\r
1010 }\r
1011 }\r
1012 //\r
1013 // Test lock\r
1014 //\r
1015 if ((Capabilities & EFI_FVB2_LOCK_CAP) == 0) {\r
1016 if (NewStatus & EFI_FVB2_LOCK_STATUS) {\r
1017 return EFI_INVALID_PARAMETER;\r
1018 }\r
1019 }\r
1020\r
1021 *AttribPtr = (*AttribPtr) & (0xFFFFFFFF & (~EFI_FVB2_STATUS));\r
1022 *AttribPtr = (*AttribPtr) | NewStatus;\r
1023 *Attributes = *AttribPtr;\r
1024\r
1025 return EFI_SUCCESS;\r
1026}\r
1027//\r
1028// FVB protocol APIs\r
1029//\r
1030EFI_STATUS\r
1031EFIAPI\r
1032FvbProtocolGetPhysicalAddress (\r
1033 IN CONST EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL *This,\r
1034 OUT EFI_PHYSICAL_ADDRESS *Address\r
1035 )\r
1036/*++\r
1037\r
1038Routine Description:\r
1039\r
1040 Retrieves the physical address of the device.\r
1041\r
1042Arguments:\r
1043\r
1044 This - Calling context\r
1045 Address - Output buffer containing the address.\r
1046\r
1047Returns:\r
1048\r
1049Returns:\r
1050 EFI_SUCCESS - Successfully returns\r
1051\r
1052--*/\r
1053{\r
1054 EFI_FW_VOL_BLOCK_DEVICE *FvbDevice;\r
1055\r
1056 FvbDevice = FVB_DEVICE_FROM_THIS (This);\r
1057\r
1058 return FvbGetPhysicalAddress (FvbDevice->Instance, Address, mFvbModuleGlobal, EfiGoneVirtual ());\r
1059}\r
1060\r
1061EFI_STATUS\r
1062FvbProtocolGetBlockSize (\r
1063 IN CONST EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL *This,\r
1064 IN EFI_LBA Lba,\r
1065 OUT UINTN *BlockSize,\r
1066 OUT UINTN *NumOfBlocks\r
1067 )\r
1068/*++\r
1069\r
1070Routine Description:\r
1071 Retrieve the size of a logical block\r
1072\r
1073Arguments:\r
1074 This - Calling context\r
1075 Lba - Indicates which block to return the size for.\r
1076 BlockSize - A pointer to a caller allocated UINTN in which\r
1077 the size of the block is returned\r
1078 NumOfBlocks - a pointer to a caller allocated UINTN in which the\r
1079 number of consecutive blocks starting with Lba is\r
1080 returned. All blocks in this range have a size of\r
1081 BlockSize\r
1082\r
1083Returns:\r
1084 EFI_SUCCESS - The firmware volume was read successfully and\r
1085 contents are in Buffer\r
1086\r
1087--*/\r
1088{\r
1089 EFI_FW_VOL_BLOCK_DEVICE *FvbDevice;\r
1090\r
1091 FvbDevice = FVB_DEVICE_FROM_THIS (This);\r
1092\r
1093 return FvbGetLbaAddress (\r
1094 FvbDevice->Instance,\r
1095 Lba,\r
1096 NULL,\r
1097 NULL,\r
1098 BlockSize,\r
1099 NumOfBlocks,\r
1100 mFvbModuleGlobal,\r
1101 EfiGoneVirtual ()\r
1102 );\r
1103}\r
1104\r
1105EFI_STATUS\r
1106EFIAPI\r
1107FvbProtocolGetAttributes (\r
1108 IN CONST EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL *This,\r
1109 OUT EFI_FVB_ATTRIBUTES_2 *Attributes\r
1110 )\r
1111/*++\r
1112\r
1113Routine Description:\r
1114 Retrieves Volume attributes. No polarity translations are done.\r
1115\r
1116Arguments:\r
1117 This - Calling context\r
1118 Attributes - output buffer which contains attributes\r
1119\r
1120Returns:\r
1121 EFI_SUCCESS - Successfully returns\r
1122\r
1123--*/\r
1124{\r
1125 EFI_FW_VOL_BLOCK_DEVICE *FvbDevice;\r
1126\r
1127 FvbDevice = FVB_DEVICE_FROM_THIS (This);\r
1128\r
1129 return FvbGetVolumeAttributes (FvbDevice->Instance, Attributes, mFvbModuleGlobal, EfiGoneVirtual ());\r
1130}\r
1131\r
1132EFI_STATUS\r
1133EFIAPI\r
1134FvbProtocolSetAttributes (\r
1135 IN CONST EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL *This,\r
1136 IN OUT EFI_FVB_ATTRIBUTES_2 *Attributes\r
1137 )\r
1138/*++\r
1139\r
1140Routine Description:\r
1141 Sets Volume attributes. No polarity translations are done.\r
1142\r
1143Arguments:\r
1144 This - Calling context\r
1145 Attributes - output buffer which contains attributes\r
1146\r
1147Returns:\r
1148 EFI_SUCCESS - Successfully returns\r
1149\r
1150--*/\r
1151{\r
1152 EFI_FW_VOL_BLOCK_DEVICE *FvbDevice;\r
1153\r
1154 FvbDevice = FVB_DEVICE_FROM_THIS (This);\r
1155\r
1156 return FvbSetVolumeAttributes (FvbDevice->Instance, Attributes, mFvbModuleGlobal, EfiGoneVirtual ());\r
1157}\r
1158\r
1159EFI_STATUS\r
1160EFIAPI\r
1161FvbProtocolEraseBlocks (\r
1162 IN CONST EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL *This,\r
1163 ...\r
1164 )\r
1165/*++\r
1166\r
1167Routine Description:\r
1168\r
1169 The EraseBlock() function erases one or more blocks as denoted by the\r
1170 variable argument list. The entire parameter list of blocks must be verified\r
1171 prior to erasing any blocks. If a block is requested that does not exist\r
1172 within the associated firmware volume (it has a larger index than the last\r
1173 block of the firmware volume), the EraseBlock() function must return\r
1174 EFI_INVALID_PARAMETER without modifying the contents of the firmware volume.\r
1175\r
1176Arguments:\r
1177 This - Calling context\r
1178 ... - Starting LBA followed by Number of Lba to erase.\r
1179 a -1 to terminate the list.\r
1180\r
1181Returns:\r
1182 EFI_SUCCESS - The erase request was successfully completed\r
1183 EFI_ACCESS_DENIED - The firmware volume is in the WriteDisabled state\r
1184 EFI_DEVICE_ERROR - The block device is not functioning correctly and\r
1185 could not be written. Firmware device may have been\r
1186 partially erased\r
1187\r
1188--*/\r
1189{\r
1190 EFI_FW_VOL_BLOCK_DEVICE *FvbDevice;\r
1191 EFI_FW_VOL_INSTANCE *FwhInstance;\r
1192 UINTN NumOfBlocks;\r
1193 VA_LIST args;\r
1194 EFI_LBA StartingLba;\r
1195 UINTN NumOfLba;\r
1196 EFI_STATUS Status;\r
1197\r
1198 FwhInstance = NULL;\r
1199 FvbDevice = FVB_DEVICE_FROM_THIS (This);\r
1200\r
1201 Status = GetFvbInstance (FvbDevice->Instance, mFvbModuleGlobal, &FwhInstance, EfiGoneVirtual ());\r
1202 ASSERT_EFI_ERROR (Status);\r
1203\r
1204 NumOfBlocks = FwhInstance->NumOfBlocks;\r
1205\r
1206 VA_START (args, This);\r
1207\r
1208 do {\r
1209 StartingLba = VA_ARG (args, EFI_LBA);\r
1210 if (StartingLba == EFI_LBA_LIST_TERMINATOR) {\r
1211 break;\r
1212 }\r
1213\r
b9036ebe 1214 NumOfLba = VA_ARG (args, UINTN);\r
b303605e
MK
1215\r
1216 //\r
1217 // Check input parameters\r
1218 //\r
1219 if (NumOfLba == 0) {\r
1220 VA_END (args);\r
1221 return EFI_INVALID_PARAMETER;\r
1222 }\r
1223\r
1224 if ((StartingLba + NumOfLba) > NumOfBlocks) {\r
1225 return EFI_INVALID_PARAMETER;\r
1226 }\r
1227 } while (TRUE);\r
1228\r
1229 VA_END (args);\r
1230\r
1231 VA_START (args, This);\r
1232 do {\r
1233 StartingLba = VA_ARG (args, EFI_LBA);\r
1234 if (StartingLba == EFI_LBA_LIST_TERMINATOR) {\r
1235 break;\r
1236 }\r
1237\r
b9036ebe 1238 NumOfLba = VA_ARG (args, UINTN);\r
b303605e
MK
1239\r
1240 while (NumOfLba > 0) {\r
1241 Status = FvbEraseBlock (FvbDevice->Instance, StartingLba, mFvbModuleGlobal, EfiGoneVirtual ());\r
1242 if (EFI_ERROR (Status)) {\r
1243 VA_END (args);\r
1244 return Status;\r
1245 }\r
1246\r
1247 StartingLba++;\r
1248 NumOfLba--;\r
1249 }\r
1250\r
1251 } while (TRUE);\r
1252\r
1253 VA_END (args);\r
1254\r
1255 return EFI_SUCCESS;\r
1256}\r
1257\r
1258EFI_STATUS\r
1259EFIAPI\r
1260FvbProtocolWrite (\r
1261 IN CONST EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL *This,\r
1262 IN EFI_LBA Lba,\r
1263 IN UINTN Offset,\r
1264 IN OUT UINTN *NumBytes,\r
1265 IN UINT8 *Buffer\r
1266 )\r
1267/*++\r
1268\r
1269Routine Description:\r
1270\r
1271 Writes data beginning at Lba:Offset from FV. The write terminates either\r
1272 when *NumBytes of data have been written, or when a block boundary is\r
1273 reached. *NumBytes is updated to reflect the actual number of bytes\r
1274 written. The write opertion does not include erase. This routine will\r
1275 attempt to write only the specified bytes. If the writes do not stick,\r
1276 it will return an error.\r
1277\r
1278Arguments:\r
1279 This - Calling context\r
1280 Lba - Block in which to begin write\r
1281 Offset - Offset in the block at which to begin write\r
1282 NumBytes - On input, indicates the requested write size. On\r
1283 output, indicates the actual number of bytes written\r
1284 Buffer - Buffer containing source data for the write.\r
1285\r
1286Returns:\r
1287 EFI_SUCCESS - The firmware volume was written successfully\r
1288 EFI_BAD_BUFFER_SIZE - Write attempted across a LBA boundary. On output,\r
1289 NumBytes contains the total number of bytes\r
1290 actually written\r
1291 EFI_ACCESS_DENIED - The firmware volume is in the WriteDisabled state\r
1292 EFI_DEVICE_ERROR - The block device is not functioning correctly and\r
1293 could not be written\r
1294 EFI_INVALID_PARAMETER - NumBytes or Buffer are NULL\r
1295\r
1296--*/\r
1297{\r
1298\r
1299 EFI_FW_VOL_BLOCK_DEVICE *FvbDevice;\r
1300\r
1301 FvbDevice = FVB_DEVICE_FROM_THIS (This);\r
1302\r
1303 return FvbWriteBlock (FvbDevice->Instance, Lba, Offset, NumBytes, Buffer, mFvbModuleGlobal, EfiGoneVirtual ());\r
1304}\r
1305\r
1306EFI_STATUS\r
1307EFIAPI\r
1308FvbProtocolRead (\r
1309 IN CONST EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL *This,\r
1310 IN EFI_LBA Lba,\r
1311 IN UINTN Offset,\r
1312 IN OUT UINTN *NumBytes,\r
1313 IN UINT8 *Buffer\r
1314 )\r
1315/*++\r
1316\r
1317Routine Description:\r
1318\r
1319 Reads data beginning at Lba:Offset from FV. The Read terminates either\r
1320 when *NumBytes of data have been read, or when a block boundary is\r
1321 reached. *NumBytes is updated to reflect the actual number of bytes\r
1322 written. The write opertion does not include erase. This routine will\r
1323 attempt to write only the specified bytes. If the writes do not stick,\r
1324 it will return an error.\r
1325\r
1326Arguments:\r
1327 This - Calling context\r
1328 Lba - Block in which to begin Read\r
1329 Offset - Offset in the block at which to begin Read\r
1330 NumBytes - On input, indicates the requested write size. On\r
1331 output, indicates the actual number of bytes Read\r
1332 Buffer - Buffer containing source data for the Read.\r
1333\r
1334Returns:\r
1335 EFI_SUCCESS - The firmware volume was read successfully and\r
1336 contents are in Buffer\r
1337 EFI_BAD_BUFFER_SIZE - Read attempted across a LBA boundary. On output,\r
1338 NumBytes contains the total number of bytes returned\r
1339 in Buffer\r
1340 EFI_ACCESS_DENIED - The firmware volume is in the ReadDisabled state\r
1341 EFI_DEVICE_ERROR - The block device is not functioning correctly and\r
1342 could not be read\r
1343 EFI_INVALID_PARAMETER - NumBytes or Buffer are NULL\r
1344\r
1345--*/\r
1346{\r
1347\r
1348 EFI_FW_VOL_BLOCK_DEVICE *FvbDevice;\r
1349 EFI_STATUS Status;\r
1350\r
1351 FvbDevice = FVB_DEVICE_FROM_THIS (This);\r
1352 Status = FvbReadBlock (FvbDevice->Instance, Lba, Offset, NumBytes, Buffer, mFvbModuleGlobal, EfiGoneVirtual ());\r
1353\r
1354 return Status;\r
1355}\r
1356\r
1357EFI_STATUS\r
1358ValidateFvHeader (\r
1359 EFI_FIRMWARE_VOLUME_HEADER *FwVolHeader\r
1360 )\r
1361/*++\r
1362\r
1363Routine Description:\r
1364 Check the integrity of firmware volume header\r
1365\r
1366Arguments:\r
1367 FwVolHeader - A pointer to a firmware volume header\r
1368\r
1369Returns:\r
1370 EFI_SUCCESS - The firmware volume is consistent\r
1371 EFI_NOT_FOUND - The firmware volume has corrupted. So it is not an FV\r
1372\r
1373--*/\r
1374{\r
1375 UINT16 *Ptr;\r
1376 UINT16 HeaderLength;\r
1377 UINT16 Checksum;\r
1378\r
1379 //\r
1380 // Verify the header revision, header signature, length\r
1381 // Length of FvBlock cannot be 2**64-1\r
1382 // HeaderLength cannot be an odd number\r
1383 //\r
1384 #ifndef R864_BUILD\r
1385 if (((FwVolHeader->Revision != EFI_FVH_REVISION) && (FwVolHeader->Revision != EFI_FVH_REVISION)) ||\r
1386 #else\r
1387 if ((FwVolHeader->Revision != EFI_FVH_REVISION) ||\r
1388 #endif\r
1389 (FwVolHeader->Signature != EFI_FVH_SIGNATURE) ||\r
1390 (FwVolHeader->FvLength == ((UINTN) -1)) ||\r
1391 ((FwVolHeader->HeaderLength & 0x01) != 0)\r
1392 ) {\r
1393 return EFI_NOT_FOUND;\r
1394 }\r
1395 //\r
1396 // Verify the header checksum\r
1397 //\r
1398 HeaderLength = (UINT16) (FwVolHeader->HeaderLength / 2);\r
1399 Ptr = (UINT16 *) FwVolHeader;\r
1400 Checksum = 0;\r
1401 while (HeaderLength > 0) {\r
1402 Checksum = Checksum + (*Ptr);\r
1403 Ptr++;\r
1404 HeaderLength--;\r
1405 }\r
1406\r
1407 if (Checksum != 0) {\r
1408 return EFI_NOT_FOUND;\r
1409 }\r
1410\r
1411 return EFI_SUCCESS;\r
1412}\r
1413\r
1414EFI_STATUS\r
1415GetFvbHeader (\r
1416 VOID **HobList,\r
1417 OUT EFI_FIRMWARE_VOLUME_HEADER **FwVolHeader,\r
1418 OUT EFI_PHYSICAL_ADDRESS *BaseAddress,\r
1419 OUT BOOLEAN *WriteBack\r
1420 )\r
1421{\r
1422 EFI_STATUS Status;\r
1423\r
1424 Status = EFI_SUCCESS;\r
1425 *WriteBack = FALSE;\r
1426\r
1427 if (*FwVolHeader == NULL) {\r
1428 *BaseAddress = PcdGet32 (PcdFlashFvRecoveryBase);\r
1429 } else if (*FwVolHeader == (VOID *)(UINTN)PcdGet32 (PcdFlashFvRecoveryBase)) {\r
1430 *BaseAddress = PcdGet32 (PcdFlashFvMainBase);\r
1431 } else if (*FwVolHeader == (VOID *)(UINTN)PcdGet32 (PcdFlashFvMainBase)) {\r
1432 *BaseAddress = PcdGet32 (PcdFlashNvStorageVariableBase);\r
1433 } else {\r
1434 return EFI_NOT_FOUND;\r
1435 }\r
1436\r
1437 DEBUG((EFI_D_INFO, "Fvb base : %08x\n",*BaseAddress));\r
1438\r
1439 *FwVolHeader = (EFI_FIRMWARE_VOLUME_HEADER *) (UINTN) (*BaseAddress);\r
1440 Status = ValidateFvHeader (*FwVolHeader);\r
1441 if (EFI_ERROR (Status)) {\r
1442 //\r
1443 // Get FvbInfo\r
1444 //\r
1445 *WriteBack = TRUE;\r
1446\r
1447 Status = GetFvbInfo (*BaseAddress, FwVolHeader);\r
1448 DEBUG(( DEBUG_ERROR, "Through GetFvbInfo: %08x!\n",*BaseAddress));\r
1449\r
1450 ASSERT_EFI_ERROR (Status);\r
1451 }\r
1452\r
1453 return EFI_SUCCESS;\r
1454}\r
1455\r
1456\r
1457EFI_STATUS\r
1458SmmSpiInit (\r
1459 VOID\r
1460 )\r
1461{\r
1462 UINT8 SpiStatus;\r
1463 UINT8 FlashIndex;\r
1464 UINT8 FlashID[3];\r
1465 EFI_STATUS Status;\r
1466\r
1467 //\r
1468 // Obtain a handle for ICH SPI Protocol\r
1469 //\r
1470 ASSERT(mSmst != NULL);\r
1471 if (mFvbModuleGlobal->SmmSpiProtocol == NULL){\r
1472 Status = mSmst->SmmLocateProtocol (&gEfiSmmSpiProtocolGuid, NULL, (VOID **) &mFvbModuleGlobal->SmmSpiProtocol);\r
1473 ASSERT_EFI_ERROR(Status);\r
1474 }\r
1475 //\r
1476 // attempt to identify flash part and initialize spi table\r
1477 //\r
1478 for (FlashIndex = 0; FlashIndex < EnumSpiFlashMax; FlashIndex++) {\r
1479 Status = mFvbModuleGlobal->SmmSpiProtocol->Init (\r
1480 mFvbModuleGlobal->SmmSpiProtocol,\r
1481 &(mSpiInitTable[FlashIndex])\r
1482 );\r
1483 if (!EFI_ERROR (Status)) {\r
1484 //\r
1485 // read vendor/device IDs to check if flash device is supported\r
1486 //\r
1487 Status = mFvbModuleGlobal->SmmSpiProtocol->Execute (\r
1488 mFvbModuleGlobal->SmmSpiProtocol,\r
1489 SPI_OPCODE_JEDEC_ID_INDEX,\r
1490 SPI_WREN_INDEX,\r
1491 TRUE,\r
1492 FALSE,\r
1493 FALSE,\r
1494 0,\r
1495 3,\r
1496 FlashID,\r
1497 EnumSpiRegionAll\r
1498 );\r
1499 if (!EFI_ERROR (Status)) {\r
1500 if (((FlashID[0] == mSpiInitTable[FlashIndex].VendorId) &&\r
1501 (FlashID[2] == mSpiInitTable[FlashIndex].DeviceId1)) ||\r
1502 ((FlashID[0] == SPI_AT26DF321_ID1) &&\r
1503 (FlashID[0] == mSpiInitTable[FlashIndex].VendorId) &&\r
1504 (FlashID[1] == mSpiInitTable[FlashIndex].DeviceId0))) {\r
1505 //\r
1506 // Supported SPI device found\r
1507 //\r
1508 DEBUG (\r
1509 ((EFI_D_INFO),\r
1510 "Smm Mode: Supported SPI Flash device found, Vendor Id: 0x%02x, Device ID: 0x%02x%02x!\n",\r
1511 FlashID[0],\r
1512 FlashID[1],\r
1513 FlashID[2])\r
1514 );\r
1515 break;\r
1516 }\r
1517 }\r
1518 }\r
1519 }\r
1520\r
1521 if (FlashIndex >= EnumSpiFlashMax) {\r
1522 Status = EFI_UNSUPPORTED;\r
1523 DEBUG (\r
1524 (EFI_D_ERROR,\r
1525 "ERROR - Unknown SPI Flash Device, Vendor Id: 0x%02x, Device ID: 0x%02x%02x!\n",\r
1526 FlashID[0],\r
1527 FlashID[1],\r
1528 FlashID[2])\r
1529 );\r
1530 ASSERT_EFI_ERROR (Status);\r
1531 }\r
1532\r
1533 SpiStatus = 0;\r
1534 Status = mFvbModuleGlobal->SmmSpiProtocol->Execute (\r
1535 mFvbModuleGlobal->SmmSpiProtocol,\r
1536 SPI_OPCODE_WRITE_S_INDEX, // OpcodeIndex\r
1537 1, // PrefixOpcodeIndex\r
1538 TRUE, // DataCycle\r
1539 TRUE, // Atomic\r
1540 TRUE, // ShiftOut\r
1541 0, // Address\r
1542 1, // Data Number\r
1543 &SpiStatus,\r
1544 EnumSpiRegionAll // SPI_REGION_TYPE\r
1545 );\r
1546 return Status;\r
1547}\r
1548\r
1549EFI_STATUS\r
1550SmmSpiNotificationFunction (\r
1551 IN CONST EFI_GUID *Protocol,\r
1552 IN VOID *Interface,\r
1553 IN EFI_HANDLE Handle\r
1554 )\r
1555{\r
1556 return SmmSpiInit();\r
1557}\r
1558\r
1559\r
1560VOID\r
1561EFIAPI\r
1562GetFullDriverPath (\r
1563 IN EFI_HANDLE ImageHandle,\r
1564 IN EFI_SYSTEM_TABLE *SystemTable,\r
1565 OUT EFI_DEVICE_PATH_PROTOCOL **CompleteFilePath\r
1566 )\r
1567/*++\r
1568\r
1569Routine Description:\r
1570\r
1571 Function is used to get the full device path for this driver.\r
1572\r
1573Arguments:\r
1574\r
1575 ImageHandle - The loaded image handle of this driver.\r
1576 SystemTable - The pointer of system table.\r
1577 CompleteFilePath - The pointer of returned full file path\r
1578\r
1579Returns:\r
1580\r
1581 none\r
1582\r
1583--*/\r
1584{\r
1585 EFI_STATUS Status;\r
1586 EFI_LOADED_IMAGE_PROTOCOL *LoadedImage;\r
1587 EFI_DEVICE_PATH_PROTOCOL *ImageDevicePath;\r
1588\r
1589\r
1590 Status = gBS->HandleProtocol (\r
1591 ImageHandle,\r
1592 &gEfiLoadedImageProtocolGuid,\r
1593 (VOID **) &LoadedImage\r
1594 );\r
1595 ASSERT_EFI_ERROR (Status);\r
1596\r
1597 Status = gBS->HandleProtocol (\r
1598 LoadedImage->DeviceHandle,\r
1599 &gEfiDevicePathProtocolGuid,\r
1600 (VOID *) &ImageDevicePath\r
1601 );\r
1602 ASSERT_EFI_ERROR (Status);\r
1603\r
1604 *CompleteFilePath = AppendDevicePath (\r
1605 ImageDevicePath,\r
1606 LoadedImage->FilePath\r
1607 );\r
1608\r
1609 return ;\r
1610}\r
1611\r
1612\r
1613\r
1614EFI_STATUS\r
1615FvbInitialize (\r
1616 IN EFI_HANDLE ImageHandle,\r
1617 IN EFI_SYSTEM_TABLE *SystemTable\r
1618 )\r
1619/*++\r
1620\r
1621Routine Description:\r
1622 This function does common initialization for FVB services\r
1623\r
1624Arguments:\r
1625\r
1626Returns:\r
1627\r
1628--*/\r
1629{\r
1630 EFI_STATUS Status;\r
1631 EFI_FW_VOL_INSTANCE *FwhInstance;\r
1632 EFI_FIRMWARE_VOLUME_HEADER *FwVolHeader;\r
1633 EFI_FIRMWARE_VOLUME_HEADER *TempFwVolHeader;\r
1634 VOID *HobList;\r
1635 VOID *FirmwareVolumeHobList;\r
1636 UINT32 BufferSize;\r
1637 EFI_FV_BLOCK_MAP_ENTRY *PtrBlockMapEntry;\r
b303605e
MK
1638 BOOLEAN WriteEnabled;\r
1639 BOOLEAN WriteLocked;\r
1640 EFI_HANDLE FwbHandle;\r
1641 EFI_FW_VOL_BLOCK_DEVICE *FvbDevice;\r
1642 EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL *OldFwbInterface;\r
1643 EFI_DEVICE_PATH_PROTOCOL *FwbDevicePath;\r
1644 EFI_DEVICE_PATH_PROTOCOL *TempFwbDevicePath;\r
1645 UINT32 MaxLbaSize;\r
1646 EFI_PHYSICAL_ADDRESS BaseAddress;\r
1647 BOOLEAN WriteBack;\r
1648 UINTN NumOfBlocks;\r
1649 UINTN HeaderLength;\r
1650 UINT8 SpiStatus;\r
1651 UINT8 FlashIndex;\r
1652 UINT8 FlashID[3];\r
1653 EFI_DEVICE_PATH_PROTOCOL *CompleteFilePath;\r
1654 UINT8 PrefixOpcodeIndex;\r
1655 BOOLEAN InSmm;\r
1656 EFI_SMM_BASE2_PROTOCOL *mSmmBase2;\r
1657 EFI_HANDLE Handle;\r
1658\r
1659 VOID *Registration;\r
1660 EFI_EVENT Event;\r
1661\r
1662 CompleteFilePath = NULL;\r
1663 GetFullDriverPath (ImageHandle, SystemTable, &CompleteFilePath);\r
1664\r
1665 Status = EfiGetSystemConfigurationTable (&gEfiHobListGuid, &HobList);\r
1666\r
1667 //\r
1668 // No FV HOBs found\r
1669 //\r
1670 ASSERT_EFI_ERROR (Status);\r
1671\r
1672\r
1673 //\r
1674 // Allocate runtime services data for global variable, which contains\r
1675 // the private data of all firmware volume block instances\r
1676 //\r
1677 mFvbModuleGlobal = (ESAL_FWB_GLOBAL *)AllocateRuntimeZeroPool(sizeof (ESAL_FWB_GLOBAL ));\r
1678 ASSERT(mFvbModuleGlobal);\r
1679 mSmmBase2 = NULL;\r
1680 Status = gBS->LocateProtocol (\r
1681 &gEfiSmmBase2ProtocolGuid,\r
1682 NULL,\r
1683 (VOID **) &mSmmBase2\r
1684 );\r
1685\r
1686 if (mSmmBase2 == NULL) {\r
1687 InSmm = FALSE;\r
1688 } else {\r
1689 mSmmBase2->InSmm (mSmmBase2, &InSmm);\r
1690 mSmmBase2->GetSmstLocation (mSmmBase2, &mSmst);\r
1691\r
1692 }\r
1693\r
1694 if (!InSmm) {\r
1695 mInSmmMode = 0;\r
1696 //\r
1697 // Obtain a handle for ICH SPI Protocol\r
1698 //\r
1699 Status = gBS->LocateProtocol (&gEfiSpiProtocolGuid, NULL, (VOID **) &mFvbModuleGlobal->SpiProtocol);\r
1700 ASSERT_EFI_ERROR (Status);\r
1701\r
1702 //\r
1703 // attempt to identify flash part and initialize spi table\r
1704 //\r
1705 for (FlashIndex = 0; FlashIndex < EnumSpiFlashMax; FlashIndex++) {\r
1706 Status = mFvbModuleGlobal->SpiProtocol->Init (\r
1707 mFvbModuleGlobal->SpiProtocol,\r
1708 &(mSpiInitTable[FlashIndex])\r
1709 );\r
1710 if (!EFI_ERROR (Status)) {\r
1711 //\r
1712 // read vendor/device IDs to check if flash device is supported\r
1713 //\r
1714 Status = mFvbModuleGlobal->SpiProtocol->Execute (\r
1715 mFvbModuleGlobal->SpiProtocol,\r
1716 SPI_OPCODE_JEDEC_ID_INDEX,\r
1717 SPI_WREN_INDEX,\r
1718 TRUE,\r
1719 FALSE,\r
1720 FALSE,\r
1721 0,\r
1722 3,\r
1723 FlashID,\r
1724 EnumSpiRegionAll\r
1725 );\r
1726 if (!EFI_ERROR (Status)) {\r
1727 if (((FlashID[0] == mSpiInitTable[FlashIndex].VendorId) &&\r
1728 (FlashID[2] == mSpiInitTable[FlashIndex].DeviceId1)) ||\r
1729 ((FlashID[0] == SPI_AT26DF321_ID1) &&\r
1730 (FlashID[0] == mSpiInitTable[FlashIndex].VendorId) &&\r
1731 (FlashID[1] == mSpiInitTable[FlashIndex].DeviceId0))) {\r
1732 //\r
1733 // Supported SPI device found\r
1734 //\r
1735 DEBUG (\r
1736 ((EFI_D_INFO),\r
1737 "Supported SPI Flash device found, Vendor Id: 0x%02x, Device ID: 0x%02x%02x!\n",\r
1738 FlashID[0],\r
1739 FlashID[1],\r
1740 FlashID[2])\r
1741 );\r
1742\r
1743 PublishFlashDeviceInfo (&mSpiInitTable[FlashIndex]);\r
1744 break;\r
1745 }\r
1746 }\r
1747 }\r
1748 }\r
1749\r
1750 if (FlashIndex >= EnumSpiFlashMax) {\r
1751 Status = EFI_UNSUPPORTED;\r
1752 DEBUG (\r
1753 (DEBUG_ERROR,\r
1754 "ERROR - Unknown SPI Flash Device, Vendor Id: 0x%02x, Device ID: 0x%02x%02x!\n",\r
1755 FlashID[0],\r
1756 FlashID[1],\r
1757 FlashID[2])\r
1758 );\r
1759 ASSERT_EFI_ERROR (Status);\r
1760 }\r
1761\r
1762 //\r
1763 // Unlock all regions by writing to status register\r
1764 // This could be SPI device specific, need to follow the datasheet\r
1765 // To write to Write Status Register the Spi PrefixOpcode needs to be:\r
1766 // 0 for Atmel parts\r
1767 // 0 for Intel parts\r
1768 // 0 for Macronix parts\r
1769 // 0 for Winbond parts\r
1770 // 1 for SST parts\r
1771 SpiStatus = 0;\r
1772 if (FlashID[0] == SPI_SST25VF016B_ID1) {\r
1773 PrefixOpcodeIndex = 1;\r
1774 } else {\r
1775 PrefixOpcodeIndex = 0;\r
1776 }\r
1777 Status = mFvbModuleGlobal->SpiProtocol->Execute (\r
1778 mFvbModuleGlobal->SpiProtocol,\r
1779 SPI_OPCODE_WRITE_S_INDEX, // OpcodeIndex\r
1780 PrefixOpcodeIndex, // PrefixOpcodeIndex\r
1781 TRUE, // DataCycle\r
1782 TRUE, // Atomic\r
1783 TRUE, // ShiftOut\r
1784 0, // Address\r
1785 1, // Data Number\r
1786 &SpiStatus,\r
1787 EnumSpiRegionAll // SPI_REGION_TYPE\r
1788 );\r
1789\r
1790\r
1791 } else {\r
1792 mInSmmMode = 1;\r
1793\r
1794 Status = mSmst->SmmLocateProtocol (&gEfiSmmSpiProtocolGuid, NULL, (VOID **) &mFvbModuleGlobal->SmmSpiProtocol);\r
1795 if (EFI_ERROR(Status)) {\r
1796 Registration = NULL;\r
1797 Status = mSmst->SmmRegisterProtocolNotify (\r
1798 &gEfiSmmSpiProtocolGuid,\r
1799 SmmSpiNotificationFunction,\r
1800 &Registration\r
1801 );\r
1802 } else {\r
1803 Status = SmmSpiInit();\r
1804 }\r
1805\r
1806 }\r
1807\r
1808 //\r
1809 // Calculate the total size for all firmware volume block instances\r
1810 //\r
1811 BufferSize = 0;\r
1812 FirmwareVolumeHobList = HobList;\r
1813 FwVolHeader = NULL;\r
1814 do {\r
1815 Status = GetFvbHeader (&FirmwareVolumeHobList, &FwVolHeader, &BaseAddress, &WriteBack);\r
1816 if (EFI_ERROR (Status)) {\r
1817 break;\r
1818 }\r
1819\r
1820 if (FwVolHeader) {\r
1821 BufferSize += (FwVolHeader->HeaderLength + sizeof (EFI_FW_VOL_INSTANCE) - sizeof (EFI_FIRMWARE_VOLUME_HEADER));\r
1822 }\r
1823 } while (TRUE);\r
1824\r
1825 //\r
1826 // Only need to allocate once. There is only one copy of physical memory for\r
1827 // the private data of each FV instance. But in virtual mode or in physical\r
1828 // mode, the address of the the physical memory may be different.\r
1829 //\r
1830 mFvbModuleGlobal->FvInstance[FVB_PHYSICAL] = (EFI_FW_VOL_INSTANCE *) AllocateRuntimeZeroPool (BufferSize);\r
1831 ASSERT(mFvbModuleGlobal->FvInstance[FVB_PHYSICAL]);\r
1832 //\r
1833 // Make a virtual copy of the FvInstance pointer.\r
1834 //\r
1835 FwhInstance = mFvbModuleGlobal->FvInstance[FVB_PHYSICAL];\r
1836 mFvbModuleGlobal->FvInstance[FVB_VIRTUAL] = FwhInstance;\r
1837\r
1838 mFvbModuleGlobal->NumFv = 0;\r
1839 FirmwareVolumeHobList = HobList;\r
1840 TempFwVolHeader = NULL;\r
1841\r
1842 MaxLbaSize = 0;\r
1843\r
1844 //\r
1845 // Fill in the private data of each firmware volume block instance\r
1846 //\r
1847 // Foreach Fv HOB in the FirmwareVolumeHobList, loop\r
1848 //\r
1849 do {\r
1850 Status = GetFvbHeader (&FirmwareVolumeHobList, &TempFwVolHeader, &BaseAddress, &WriteBack);\r
1851 if (EFI_ERROR (Status)) {\r
1852 break;\r
1853 }\r
1854 FwVolHeader = TempFwVolHeader;\r
1855\r
1856 if (!FwVolHeader) {\r
1857 continue;\r
1858 }\r
1859\r
1860\r
1861 CopyMem ((UINTN *) &(FwhInstance->VolumeHeader), (UINTN *) FwVolHeader, FwVolHeader->HeaderLength);\r
1862 FwVolHeader = &(FwhInstance->VolumeHeader);\r
1863\r
1864 FwhInstance->FvBase[FVB_PHYSICAL] = (UINTN) BaseAddress;\r
1865 FwhInstance->FvBase[FVB_VIRTUAL] = (UINTN) BaseAddress;\r
1866\r
1867 //\r
1868 // FwhInstance->FvWriteBase may not be the same as FwhInstance->FvBase\r
1869 //\r
1870 FwhInstance->FvWriteBase[FVB_PHYSICAL] = (UINTN) BaseAddress;\r
1871 WriteEnabled = TRUE;\r
1872\r
1873 //\r
1874 // Every pointer should have a virtual copy.\r
1875 //\r
1876 FwhInstance->FvWriteBase[FVB_VIRTUAL] = FwhInstance->FvWriteBase[FVB_PHYSICAL];\r
1877\r
1878 FwhInstance->WriteEnabled = WriteEnabled;\r
1879 EfiInitializeLock (&(FwhInstance->FvbDevLock), TPL_HIGH_LEVEL);\r
1880\r
b303605e
MK
1881 NumOfBlocks = 0;\r
1882 WriteLocked = FALSE;\r
1883\r
1884 if (WriteEnabled) {\r
1885 for (PtrBlockMapEntry = FwVolHeader->BlockMap; PtrBlockMapEntry->NumBlocks != 0; PtrBlockMapEntry++) {\r
1886 //\r
1887 // Get the maximum size of a block. The size will be used to allocate\r
1888 // buffer for Scratch space, the intermediate buffer for FVB extension\r
1889 // protocol\r
1890 //\r
1891 if (MaxLbaSize < PtrBlockMapEntry->Length) {\r
1892 MaxLbaSize = PtrBlockMapEntry->Length;\r
1893 }\r
1894\r
1895 NumOfBlocks = NumOfBlocks + PtrBlockMapEntry->NumBlocks;\r
1896 }\r
1897 //\r
1898 // Write back a healthy FV header\r
1899 //\r
1900 if (WriteBack && (!WriteLocked)) {\r
1901\r
1902 Status = FlashFdErase (\r
1903 (UINTN) FwhInstance->FvWriteBase[0],\r
1904 (UINTN) BaseAddress,\r
1905 FwVolHeader->BlockMap->Length\r
1906 );\r
1907\r
1908 HeaderLength = (UINTN) FwVolHeader->HeaderLength;\r
1909 Status = FlashFdWrite (\r
1910 (UINTN) FwhInstance->FvWriteBase[0],\r
1911 (UINTN) BaseAddress,\r
1912 &HeaderLength,\r
1913 (UINT8 *) FwVolHeader,\r
1914 FwVolHeader->BlockMap->Length\r
1915 );\r
1916\r
1917 }\r
1918 }\r
1919 //\r
1920 // The total number of blocks in the FV.\r
1921 //\r
1922 FwhInstance->NumOfBlocks = NumOfBlocks;\r
1923\r
1924 //\r
1925 // If the FV is write locked, set the appropriate attributes\r
1926 //\r
1927 if (WriteLocked) {\r
1928 //\r
1929 // write disabled\r
1930 //\r
1931 FwhInstance->VolumeHeader.Attributes &= ~EFI_FVB2_WRITE_STATUS;\r
1932 //\r
1933 // lock enabled\r
1934 //\r
1935 FwhInstance->VolumeHeader.Attributes |= EFI_FVB2_LOCK_STATUS;\r
1936 }\r
1937\r
1938 //\r
1939 // Allocate and initialize FVB Device in a runtime data buffer\r
1940 //\r
1941 FvbDevice = AllocateRuntimeCopyPool (sizeof (EFI_FW_VOL_BLOCK_DEVICE), &mFvbDeviceTemplate);\r
1942 ASSERT (FvbDevice);\r
1943\r
1944 FvbDevice->Instance = mFvbModuleGlobal->NumFv;\r
1945 mFvbModuleGlobal->NumFv++;\r
1946\r
1947 //\r
1948 // FV does not contains extension header, then produce MEMMAP_DEVICE_PATH\r
1949 //\r
1950 if (FwVolHeader->ExtHeaderOffset == 0) {\r
1951 FvbDevice->FvDevicePath.MemMapDevPath.StartingAddress = BaseAddress;\r
1952 FvbDevice->FvDevicePath.MemMapDevPath.EndingAddress = BaseAddress + (FwVolHeader->FvLength - 1);\r
1953 FwbDevicePath = (EFI_DEVICE_PATH_PROTOCOL *)&FvbDevice->FvDevicePath;\r
1954 } else {\r
1955 CopyGuid (\r
1956 &FvbDevice->UefiFvDevicePath.FvDevPath.FvName,\r
1957 (EFI_GUID *)(UINTN)(BaseAddress + FwVolHeader->ExtHeaderOffset)\r
1958 );\r
1959 FwbDevicePath = (EFI_DEVICE_PATH_PROTOCOL *)&FvbDevice->UefiFvDevicePath;\r
1960 }\r
1961\r
1962 if (!InSmm) {\r
1963 //\r
1964 // Find a handle with a matching device path that has supports FW Block protocol\r
1965 //\r
1966 TempFwbDevicePath = FwbDevicePath;\r
1967 Status = gBS->LocateDevicePath (&gEfiFirmwareVolumeBlockProtocolGuid, &TempFwbDevicePath, &FwbHandle);\r
1968 if (EFI_ERROR (Status)) {\r
1969 //\r
1970 // LocateDevicePath fails so install a new interface and device path\r
1971 //\r
1972 FwbHandle = NULL;\r
1973 Status = gBS->InstallMultipleProtocolInterfaces (\r
1974 &FwbHandle,\r
1975 &gEfiFirmwareVolumeBlockProtocolGuid,\r
1976 &FvbDevice->FwVolBlockInstance,\r
1977 &gEfiDevicePathProtocolGuid,\r
1978 FwbDevicePath,\r
1979 NULL\r
1980 );\r
1981 ASSERT_EFI_ERROR (Status);\r
1982 } else if (EfiIsDevicePathEnd (TempFwbDevicePath)) {\r
1983 //\r
1984 // Device already exists, so reinstall the FVB protocol\r
1985 //\r
1986 Status = gBS->HandleProtocol (\r
1987 FwbHandle,\r
1988 &gEfiFirmwareVolumeBlockProtocolGuid,\r
1989 (VOID **) &OldFwbInterface\r
1990 );\r
1991 ASSERT_EFI_ERROR (Status);\r
1992\r
1993 Status = gBS->ReinstallProtocolInterface (\r
1994 FwbHandle,\r
1995 &gEfiFirmwareVolumeBlockProtocolGuid,\r
1996 OldFwbInterface,\r
1997 &FvbDevice->FwVolBlockInstance\r
1998 );\r
1999 ASSERT_EFI_ERROR (Status);\r
2000\r
2001 } else {\r
2002 //\r
2003 // There was a FVB protocol on an End Device Path node\r
2004 //\r
2005 ASSERT (FALSE);\r
2006 }\r
2007 } else {\r
2008 FwbHandle = NULL;\r
2009 Status = mSmst->SmmInstallProtocolInterface (\r
2010 &FwbHandle,\r
2011 &gEfiSmmFirmwareVolumeBlockProtocolGuid,\r
2012 EFI_NATIVE_INTERFACE,\r
2013 &FvbDevice->FwVolBlockInstance\r
2014 );\r
2015 ASSERT_EFI_ERROR (Status);\r
2016 }\r
2017\r
2018 FwhInstance = (EFI_FW_VOL_INSTANCE *)\r
2019 (\r
2020 (UINTN) ((UINT8 *) FwhInstance) + FwVolHeader->HeaderLength +\r
2021 (sizeof (EFI_FW_VOL_INSTANCE) - sizeof (EFI_FIRMWARE_VOLUME_HEADER))\r
2022 );\r
2023 } while (TRUE);\r
2024\r
2025 //\r
2026 // Allocate for scratch space, an intermediate buffer for FVB extention\r
2027 //\r
2028\r
2029 mFvbModuleGlobal->FvbScratchSpace[FVB_PHYSICAL] = AllocateRuntimeZeroPool (MaxLbaSize);\r
2030\r
2031 ASSERT (mFvbModuleGlobal->FvbScratchSpace[FVB_PHYSICAL]);\r
2032\r
2033 mFvbModuleGlobal->FvbScratchSpace[FVB_VIRTUAL] = mFvbModuleGlobal->FvbScratchSpace[FVB_PHYSICAL];\r
2034\r
2035 if (!InSmm) {\r
2036 Status = gBS->CreateEventEx (\r
2037 EVT_NOTIFY_SIGNAL,\r
2038 TPL_NOTIFY,\r
2039 FvbVirtualddressChangeEvent,\r
2040 NULL,\r
2041 &gEfiEventVirtualAddressChangeGuid,\r
2042 &Event\r
2043 );\r
2044 ASSERT_EFI_ERROR (Status);\r
2045 } else {\r
2046 //\r
2047 // Inform other platform drivers that SPI device discovered and\r
2048 // SPI interface ready for use.\r
2049 //\r
2050 Handle = NULL;\r
2051 Status = gBS->InstallProtocolInterface (\r
2052 &Handle,\r
2053 &gEfiSmmSpiReadyProtocolGuid,\r
2054 EFI_NATIVE_INTERFACE,\r
2055 NULL\r
2056 );\r
2057 }\r
2058 return EFI_SUCCESS;\r
2059}\r