1 /** @file
2 MM driver source for several Serial Flash devices
3 which are compliant with the Intel(R) Serial Flash Interface Compatibility Specification.
4
5 Copyright (c) 2017, Intel Corporation. All rights reserved.<BR>
6 Copyright (c) Microsoft Corporation.<BR>
7 SPDX-License-Identifier: BSD-2-Clause-Patent
8
9 **/
10
11 #include "SpiFvbServiceCommon.h"
12 #include <Library/MmServicesTableLib.h>
13 #include <Library/UefiDriverEntryPoint.h>
14 #include <Protocol/SmmFirmwareVolumeBlock.h>
15
16 /**
17 The function installs EFI_FIRMWARE_VOLUME_BLOCK protocol
18 for each FV in the system.
19
20 @param[in] FvbInstance The pointer to a FW volume instance structure,
21 which contains the information about one FV.
22
23 @retval VOID
24
25 **/
26 VOID
InstallFvbProtocol(IN EFI_FVB_INSTANCE * FvbInstance)27 InstallFvbProtocol (
28 IN EFI_FVB_INSTANCE *FvbInstance
29 )
30 {
31 EFI_FIRMWARE_VOLUME_HEADER *FvHeader;
32 EFI_STATUS Status;
33 EFI_HANDLE FvbHandle;
34
35 ASSERT (FvbInstance != NULL);
36 if (FvbInstance == NULL) {
37 return;
38 }
39
40 CopyMem (&FvbInstance->FvbProtocol, &mFvbProtocolTemplate, sizeof (EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL));
41
42 FvHeader = &FvbInstance->FvHeader;
43 if (FvHeader == NULL) {
44 return;
45 }
46
47 //
48 // Set up the devicepath
49 //
50 DEBUG ((DEBUG_INFO, "FwBlockService.c: Setting up DevicePath for 0x%lx:\n", FvbInstance->FvBase));
51 if (FvHeader->ExtHeaderOffset == 0) {
52 //
53 // FV does not contains extension header, then produce MEMMAP_DEVICE_PATH
54 //
55 FvbInstance->DevicePath = (EFI_DEVICE_PATH_PROTOCOL *) AllocateRuntimeCopyPool (sizeof (FV_MEMMAP_DEVICE_PATH), &mFvMemmapDevicePathTemplate);
56 if (FvbInstance->DevicePath == NULL) {
57 DEBUG ((DEBUG_INFO, "SpiFvbServiceSmm.c: Memory allocation for MEMMAP_DEVICE_PATH failed\n"));
58 return;
59 }
60 ((FV_MEMMAP_DEVICE_PATH *) FvbInstance->DevicePath)->MemMapDevPath.StartingAddress = FvbInstance->FvBase;
61 ((FV_MEMMAP_DEVICE_PATH *) FvbInstance->DevicePath)->MemMapDevPath.EndingAddress = FvbInstance->FvBase + FvHeader->FvLength - 1;
62 } else {
63 FvbInstance->DevicePath = (EFI_DEVICE_PATH_PROTOCOL *) AllocateRuntimeCopyPool (sizeof (FV_PIWG_DEVICE_PATH), &mFvPIWGDevicePathTemplate);
64 if (FvbInstance->DevicePath == NULL) {
65 DEBUG ((DEBUG_INFO, "SpiFvbServiceSmm.c: Memory allocation for FV_PIWG_DEVICE_PATH failed\n"));
66 return;
67 }
68 CopyGuid (
69 &((FV_PIWG_DEVICE_PATH *)FvbInstance->DevicePath)->FvDevPath.FvName,
70 (GUID *)(UINTN)(FvbInstance->FvBase + FvHeader->ExtHeaderOffset)
71 );
72 }
73
74 //
75 // LocateDevicePath fails so install a new interface and device path
76 //
77 FvbHandle = NULL;
78
79 Status = gMmst->MmInstallProtocolInterface (
80 &FvbHandle,
81 &gEfiSmmFirmwareVolumeBlockProtocolGuid,
82 EFI_NATIVE_INTERFACE,
83 &(FvbInstance->FvbProtocol)
84 );
85 ASSERT_EFI_ERROR (Status);
86
87 Status = gMmst->MmInstallProtocolInterface (
88 &FvbHandle,
89 &gEfiDevicePathProtocolGuid,
90 EFI_NATIVE_INTERFACE,
91 &(FvbInstance->DevicePath)
92 );
93 ASSERT_EFI_ERROR (Status);
94 }
95
96 /**
97 The function does the necessary initialization work for
98 Firmware Volume Block Driver.
99
100 **/
101 VOID
FvbInitialize(VOID)102 FvbInitialize (
103 VOID
104 )
105 {
106 EFI_FVB_INSTANCE *FvbInstance;
107 EFI_FIRMWARE_VOLUME_HEADER *FvHeader;
108 EFI_FV_BLOCK_MAP_ENTRY *PtrBlockMapEntry;
109 EFI_PHYSICAL_ADDRESS BaseAddress;
110 EFI_STATUS Status;
111 UINTN BufferSize;
112 UINTN Idx;
113 UINT32 MaxLbaSize;
114 UINT32 BytesWritten;
115 UINTN BytesErased;
116
117 mPlatformFvBaseAddress[0].FvBase = PcdGet32(PcdFlashNvStorageVariableBase);
118 mPlatformFvBaseAddress[0].FvSize = PcdGet32(PcdFlashNvStorageVariableSize);
119 mPlatformFvBaseAddress[1].FvBase = PcdGet32(PcdFlashFvMicrocodeBase);
120 mPlatformFvBaseAddress[1].FvSize = PcdGet32(PcdFlashFvMicrocodeSize);
121 mPlatformDefaultBaseAddress[0].FvBase = PcdGet32(PcdFlashNvStorageVariableBase);
122 mPlatformDefaultBaseAddress[0].FvSize = PcdGet32(PcdFlashNvStorageVariableSize);
123 mPlatformDefaultBaseAddress[1].FvBase = PcdGet32(PcdFlashFvMicrocodeBase);
124 mPlatformDefaultBaseAddress[1].FvSize = PcdGet32(PcdFlashFvMicrocodeSize);
125
126 //
127 // We will only continue with FVB installation if the
128 // SPI is the active BIOS state
129 //
130 {
131 //
132 // Make sure all FVB are valid and/or fix if possible
133 //
134 for (Idx = 0;; Idx++) {
135 if (mPlatformFvBaseAddress[Idx].FvSize == 0 && mPlatformFvBaseAddress[Idx].FvBase == 0) {
136 break;
137 }
138
139 BaseAddress = mPlatformFvBaseAddress[Idx].FvBase;
140 FvHeader = (EFI_FIRMWARE_VOLUME_HEADER *) (UINTN) BaseAddress;
141
142 if (!IsFvHeaderValid (BaseAddress, FvHeader)) {
143 BytesWritten = 0;
144 BytesErased = 0;
145 DEBUG ((DEBUG_ERROR, "ERROR - The FV in 0x%x is invalid!\n", FvHeader));
146 Status = GetFvbInfo (BaseAddress, &FvHeader);
147 if (EFI_ERROR (Status)) {
148 DEBUG ((DEBUG_WARN, "ERROR - Can't recovery FV header at 0x%x. GetFvbInfo Status %r\n", BaseAddress, Status));
149 continue;
150 }
151 DEBUG ((DEBUG_INFO, "Rewriting FV header at 0x%X with static data\n", BaseAddress));
152 //
153 // Spi erase
154 //
155 BytesErased = (UINTN) FvHeader->BlockMap->Length;
156 Status = SpiFlashBlockErase( (UINTN) BaseAddress, &BytesErased);
157 if (EFI_ERROR (Status)) {
158 DEBUG ((DEBUG_WARN, "ERROR - SpiFlashBlockErase Error %r\n", Status));
159 continue;
160 }
161 if (BytesErased != FvHeader->BlockMap->Length) {
162 DEBUG ((DEBUG_WARN, "ERROR - BytesErased != FvHeader->BlockMap->Length\n"));
163 DEBUG ((DEBUG_INFO, " BytesErased = 0x%X\n Length = 0x%X\n", BytesErased, FvHeader->BlockMap->Length));
164 continue;
165 }
166 BytesWritten = FvHeader->HeaderLength;
167 Status = SpiFlashWrite ((UINTN)BaseAddress, &BytesWritten, (UINT8*)FvHeader);
168 if (EFI_ERROR (Status)) {
169 DEBUG ((DEBUG_WARN, "ERROR - SpiFlashWrite Error %r\n", Status));
170 continue;
171 }
172 if (BytesWritten != FvHeader->HeaderLength) {
173 DEBUG ((DEBUG_WARN, "ERROR - BytesWritten != HeaderLength\n"));
174 DEBUG ((DEBUG_INFO, " BytesWritten = 0x%X\n HeaderLength = 0x%X\n", BytesWritten, FvHeader->HeaderLength));
175 continue;
176 }
177 Status = SpiFlashLock ();
178 if (EFI_ERROR (Status)) {
179 DEBUG ((DEBUG_WARN, "ERROR - SpiFlashLock Error %r\n", Status));
180 continue;
181 }
182 DEBUG ((DEBUG_INFO, "FV Header @ 0x%X restored with static data\n", BaseAddress));
183 //
184 // Clear cache for this range.
185 //
186 WriteBackInvalidateDataCacheRange ( (VOID *) (UINTN) BaseAddress, FvHeader->BlockMap->Length);
187 }
188 }
189
190 //
191 // Calculate the total size for all firmware volume block instances
192 //
193 BufferSize = 0;
194 for (Idx = 0; ; Idx++) {
195 if (mPlatformFvBaseAddress[Idx].FvSize == 0 && mPlatformFvBaseAddress[Idx].FvBase == 0) {
196 break;
197 }
198 BaseAddress = mPlatformFvBaseAddress[Idx].FvBase;
199 FvHeader = (EFI_FIRMWARE_VOLUME_HEADER *) (UINTN) BaseAddress;
200
201 if (!IsFvHeaderValid (BaseAddress, FvHeader)) {
202 DEBUG ((DEBUG_WARN, "ERROR - The FV in 0x%x is invalid!\n", FvHeader));
203 continue;
204 }
205
206 BufferSize += (FvHeader->HeaderLength +
207 sizeof (EFI_FVB_INSTANCE) -
208 sizeof (EFI_FIRMWARE_VOLUME_HEADER)
209 );
210 }
211
212 mFvbModuleGlobal.FvbInstance = (EFI_FVB_INSTANCE *) AllocateRuntimeZeroPool (BufferSize);
213 if (mFvbModuleGlobal.FvbInstance == NULL) {
214 ASSERT (FALSE);
215 return;
216 }
217
218 MaxLbaSize = 0;
219 FvbInstance = mFvbModuleGlobal.FvbInstance;
220 mFvbModuleGlobal.NumFv = 0;
221
222 for (Idx = 0; ; Idx++) {
223 if (mPlatformFvBaseAddress[Idx].FvSize == 0 && mPlatformFvBaseAddress[Idx].FvBase == 0) {
224 break;
225 }
226 BaseAddress = mPlatformFvBaseAddress[Idx].FvBase;
227 FvHeader = (EFI_FIRMWARE_VOLUME_HEADER *) (UINTN) BaseAddress;
228
229 if (!IsFvHeaderValid (BaseAddress, FvHeader)) {
230 DEBUG ((DEBUG_WARN, "ERROR - The FV in 0x%x is invalid!\n", FvHeader));
231 continue;
232 }
233
234 FvbInstance->Signature = FVB_INSTANCE_SIGNATURE;
235 CopyMem (&(FvbInstance->FvHeader), FvHeader, FvHeader->HeaderLength);
236
237 FvHeader = &(FvbInstance->FvHeader);
238 FvbInstance->FvBase = (UINTN)BaseAddress;
239
240 //
241 // Process the block map for each FV
242 //
243 FvbInstance->NumOfBlocks = 0;
244 for (PtrBlockMapEntry = FvHeader->BlockMap;
245 PtrBlockMapEntry->NumBlocks != 0;
246 PtrBlockMapEntry++) {
247 //
248 // Get the maximum size of a block.
249 //
250 if (MaxLbaSize < PtrBlockMapEntry->Length) {
251 MaxLbaSize = PtrBlockMapEntry->Length;
252 }
253 FvbInstance->NumOfBlocks += PtrBlockMapEntry->NumBlocks;
254 }
255
256 //
257 // Add a FVB Protocol Instance
258 //
259 InstallFvbProtocol (FvbInstance);
260 mFvbModuleGlobal.NumFv++;
261
262 //
263 // Move on to the next FvbInstance
264 //
265 FvbInstance = (EFI_FVB_INSTANCE *) ((UINTN)((UINT8 *)FvbInstance) +
266 FvHeader->HeaderLength +
267 (sizeof (EFI_FVB_INSTANCE) - sizeof (EFI_FIRMWARE_VOLUME_HEADER)));
268
269 }
270 }
271 }
272