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