1 /** @file
2 Implementation of helper routines for DXE environment.
3 
4 Copyright (c) 2013 - 2016 Intel Corporation.
5 
6 This program and the accompanying materials
7 are licensed and made available under the terms and conditions of the BSD License
8 which accompanies this distribution.  The full text of the license may be found at
9 http://opensource.org/licenses/bsd-license.php
10 
11 THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
12 WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
13 
14 **/
15 
16 #include <PiDxe.h>
17 
18 #include <Library/UefiBootServicesTableLib.h>
19 #include <Library/S3BootScriptLib.h>
20 #include <Library/DxeServicesLib.h>
21 #include <Library/UefiRuntimeServicesTableLib.h>
22 #include <Protocol/SmmBase2.h>
23 #include <Protocol/Spi.h>
24 #include <Protocol/VariableLock.h>
25 
26 #include <Guid/MemoryConfigData.h>
27 #include <Guid/QuarkVariableLock.h>
28 
29 #include "CommonHeader.h"
30 
31 #define FLASH_BLOCK_SIZE            SIZE_4KB
32 
33 //
34 // Global variables.
35 //
36 EFI_SPI_PROTOCOL                    *mPlatHelpSpiProtocolRef = NULL;
37 
38 //
39 // Routines defined in other source modules of this component.
40 //
41 
42 //
43 // Routines local to this component.
44 //
45 
46 //
47 // Routines shared with other souce modules in this component.
48 //
49 
50 EFI_SPI_PROTOCOL *
LocateSpiProtocol(IN EFI_SMM_SYSTEM_TABLE2 * Smst)51 LocateSpiProtocol (
52   IN  EFI_SMM_SYSTEM_TABLE2             *Smst
53   )
54 {
55   if (mPlatHelpSpiProtocolRef == NULL) {
56     if (Smst != NULL) {
57       Smst->SmmLocateProtocol (
58               &gEfiSmmSpiProtocolGuid,
59               NULL,
60               (VOID **) &mPlatHelpSpiProtocolRef
61               );
62     } else {
63       gBS->LocateProtocol (
64              &gEfiSpiProtocolGuid,
65              NULL,
66              (VOID **) &mPlatHelpSpiProtocolRef
67              );
68     }
69     ASSERT (mPlatHelpSpiProtocolRef != NULL);
70   }
71   return mPlatHelpSpiProtocolRef;
72 }
73 
74 //
75 // Routines exported by this source module.
76 //
77 
78 /**
79   Find pointer to RAW data in Firmware volume file.
80 
81   @param   FvNameGuid       Firmware volume to search. If == NULL search all.
82   @param   FileNameGuid     Firmware volume file to search for.
83   @param   SectionData      Pointer to RAW data section of found file.
84   @param   SectionDataSize  Pointer to UNITN to get size of RAW data.
85 
86   @retval  EFI_SUCCESS            Raw Data found.
87   @retval  EFI_INVALID_PARAMETER  FileNameGuid == NULL.
88   @retval  EFI_NOT_FOUND          Firmware volume file not found.
89   @retval  EFI_UNSUPPORTED        Unsupported in current enviroment (PEI or DXE).
90 
91 **/
92 EFI_STATUS
93 EFIAPI
PlatformFindFvFileRawDataSection(IN CONST EFI_GUID * FvNameGuid OPTIONAL,IN CONST EFI_GUID * FileNameGuid,OUT VOID ** SectionData,OUT UINTN * SectionDataSize)94 PlatformFindFvFileRawDataSection (
95   IN CONST EFI_GUID                 *FvNameGuid OPTIONAL,
96   IN CONST EFI_GUID                 *FileNameGuid,
97   OUT VOID                          **SectionData,
98   OUT UINTN                         *SectionDataSize
99   )
100 {
101   if (FileNameGuid == NULL || SectionData == NULL || SectionDataSize == NULL) {
102     return EFI_INVALID_PARAMETER;
103   }
104   if (FvNameGuid != NULL) {
105     return EFI_UNSUPPORTED;  // Searching in specific FV unsupported in DXE.
106   }
107 
108   return GetSectionFromAnyFv (FileNameGuid, EFI_SECTION_RAW, 0, SectionData, SectionDataSize);
109 }
110 
111 /**
112   Find free spi protect register and write to it to protect a flash region.
113 
114   @param   DirectValue      Value to directly write to register.
115                             if DirectValue == 0 the use Base & Length below.
116   @param   BaseAddress      Base address of region in Flash Memory Map.
117   @param   Length           Length of region to protect.
118 
119   @retval  EFI_SUCCESS      Free spi protect register found & written.
120   @retval  EFI_NOT_FOUND    Free Spi protect register not found.
121   @retval  EFI_DEVICE_ERROR Unable to write to spi protect register.
122 **/
123 EFI_STATUS
124 EFIAPI
PlatformWriteFirstFreeSpiProtect(IN CONST UINT32 DirectValue,IN CONST UINT32 BaseAddress,IN CONST UINT32 Length)125 PlatformWriteFirstFreeSpiProtect (
126   IN CONST UINT32                         DirectValue,
127   IN CONST UINT32                         BaseAddress,
128   IN CONST UINT32                         Length
129   )
130 {
131   UINT32                            FreeOffset;
132   UINT32                            PchRootComplexBar;
133   EFI_STATUS                        Status;
134 
135   PchRootComplexBar = QNC_RCRB_BASE;
136 
137   Status = WriteFirstFreeSpiProtect (
138              PchRootComplexBar,
139              DirectValue,
140              BaseAddress,
141              Length,
142              &FreeOffset
143              );
144 
145   if (!EFI_ERROR (Status)) {
146     S3BootScriptSaveMemWrite (
147       S3BootScriptWidthUint32,
148         (UINTN) (PchRootComplexBar + FreeOffset),
149         1,
150         (VOID *) (UINTN) (PchRootComplexBar + FreeOffset)
151         );
152   }
153 
154   return Status;
155 }
156 
157 /**
158   Lock legacy SPI static configuration information.
159 
160   Function will assert if unable to lock config.
161 
162 **/
163 VOID
164 EFIAPI
PlatformFlashLockConfig(VOID)165 PlatformFlashLockConfig (
166   VOID
167   )
168 {
169   EFI_STATUS        Status;
170   EFI_SPI_PROTOCOL  *SpiProtocol;
171 
172   //
173   // Enable lock of legacy SPI static configuration information.
174   //
175 
176   SpiProtocol = LocateSpiProtocol (NULL);  // This routine will not be called in SMM.
177   ASSERT_EFI_ERROR (SpiProtocol != NULL);
178   if (SpiProtocol != NULL) {
179     Status = SpiProtocol->Lock (SpiProtocol);
180 
181     if (!EFI_ERROR (Status)) {
182       DEBUG ((EFI_D_INFO, "Platform: Spi Config Locked Down\n"));
183     } else if (Status == EFI_ACCESS_DENIED) {
184       DEBUG ((EFI_D_INFO, "Platform: Spi Config already locked down\n"));
185     } else {
186       ASSERT_EFI_ERROR (Status);
187     }
188   }
189 }
190 
191 /**
192   Platform Variable Lock.
193 
194   @retval EFI_SUCCESS           Platform Variable Lock successful.
195   @retval EFI_NOT_FOUND         No protocol instances were found that match Protocol and
196                                 Registration.
197 
198 **/
199 VOID
200 EFIAPI
PlatformVariableLock()201 PlatformVariableLock (
202   )
203 {
204   EFI_STATUS                        Status;
205   EDKII_VARIABLE_LOCK_PROTOCOL      *VariableLockProtocol;
206 
207   Status = gBS->LocateProtocol (&gEdkiiVariableLockProtocolGuid, NULL, (VOID **)&VariableLockProtocol);
208   ASSERT_EFI_ERROR (Status);
209 
210   Status = VariableLockProtocol->RequestToLock (
211                                    VariableLockProtocol,
212                                    QUARK_VARIABLE_LOCK_NAME,
213                                    &gQuarkVariableLockGuid
214                                    );
215   ASSERT_EFI_ERROR (Status);
216 
217   // Memory Config Data shouldn't be writable when Quark Variable Lock is enabled.
218   Status = VariableLockProtocol->RequestToLock (
219                                    VariableLockProtocol,
220                                    EFI_MEMORY_CONFIG_DATA_NAME,
221                                    &gEfiMemoryConfigDataGuid
222                                    );
223   ASSERT_EFI_ERROR (Status);
224 }
225 
226 /**
227   Lock regions and config of SPI flash given the policy for this platform.
228 
229   Function will assert if unable to lock regions or config.
230 
231   @param   PreBootPolicy    If TRUE do Pre Boot Flash Lock Policy.
232 
233 **/
234 VOID
235 EFIAPI
PlatformFlashLockPolicy(IN CONST BOOLEAN PreBootPolicy)236 PlatformFlashLockPolicy (
237   IN CONST BOOLEAN                        PreBootPolicy
238   )
239 {
240   EFI_STATUS                        Status;
241   UINT64                            CpuAddressNvStorage;
242   UINT64                            CpuAddressFlashDevice;
243   UINT64                            SpiAddress;
244   EFI_BOOT_MODE                     BootMode;
245   UINTN                             SpiFlashDeviceSize;
246 
247   BootMode = GetBootModeHob ();
248 
249   SpiFlashDeviceSize = (UINTN) PcdGet32 (PcdSpiFlashDeviceSize);
250   CpuAddressFlashDevice = SIZE_4GB - SpiFlashDeviceSize;
251   DEBUG (
252       (EFI_D_INFO,
253       "Platform:FlashDeviceSize = 0x%08x Bytes\n",
254       SpiFlashDeviceSize)
255       );
256 
257   //
258   // If not in update or recovery mode, lock stuff down
259   //
260   if ((BootMode != BOOT_IN_RECOVERY_MODE) && (BootMode != BOOT_ON_FLASH_UPDATE)) {
261 
262     //
263     // Lock regions
264     //
265     CpuAddressNvStorage = (UINT64) PcdGet32 (PcdFlashNvStorageVariableBase);
266 
267     //
268     // Lock from start of flash device up to Smi writable flash storage areas.
269     //
270     SpiAddress = 0;
271     if (!PlatformIsSpiRangeProtected ((UINT32) SpiAddress, (UINT32) (CpuAddressNvStorage - CpuAddressFlashDevice))) {
272       DEBUG (
273         (EFI_D_INFO,
274         "Platform: Protect Region Base:Len 0x%08x:0x%08x\n",
275         (UINTN) SpiAddress, (UINTN)(CpuAddressNvStorage - CpuAddressFlashDevice))
276         );
277       Status = PlatformWriteFirstFreeSpiProtect (
278                   0,
279                   (UINT32) SpiAddress,
280                   (UINT32) (CpuAddressNvStorage - CpuAddressFlashDevice)
281                   );
282 
283       ASSERT_EFI_ERROR (Status);
284     }
285     //
286     // Move Spi Address to after Smi writable flash storage areas.
287     //
288     SpiAddress = CpuAddressNvStorage - CpuAddressFlashDevice;
289     SpiAddress += ((UINT64) PcdGet32 (PcdFlashNvStorageVariableSize));
290 
291     //
292     // Lock from end of OEM area to end of flash part.
293     //
294     if (!PlatformIsSpiRangeProtected ((UINT32) SpiAddress, SpiFlashDeviceSize - ((UINT32) SpiAddress))) {
295       DEBUG (
296         (EFI_D_INFO,
297         "Platform: Protect Region Base:Len 0x%08x:0x%08x\n",
298         (UINTN) SpiAddress,
299         (UINTN) (SpiFlashDeviceSize - ((UINT32) SpiAddress)))
300         );
301       ASSERT (SpiAddress < ((UINT64) SpiFlashDeviceSize));
302       Status = PlatformWriteFirstFreeSpiProtect (
303                   0,
304                   (UINT32) SpiAddress,
305                   SpiFlashDeviceSize - ((UINT32) SpiAddress)
306                   );
307 
308       ASSERT_EFI_ERROR (Status);
309     }
310   }
311 
312   //
313   // Always Lock flash config registers if about to boot a boot option
314   // else lock depending on boot mode.
315   //
316   if (PreBootPolicy || (BootMode != BOOT_ON_FLASH_UPDATE)) {
317     PlatformFlashLockConfig ();
318   }
319 
320   //
321   // Enable Quark Variable lock if PreBootPolicy.
322   //
323   if (PreBootPolicy) {
324     PlatformVariableLock ();
325   }
326 }
327 
328 /**
329   Erase and Write to platform flash.
330 
331   Routine accesses one flash block at a time, each access consists
332   of an erase followed by a write of FLASH_BLOCK_SIZE. One or both
333   of DoErase & DoWrite params must be TRUE.
334 
335   Limitations:-
336     CpuWriteAddress must be aligned to FLASH_BLOCK_SIZE.
337     DataSize must be a multiple of FLASH_BLOCK_SIZE.
338 
339   @param   Smst                   If != NULL then InSmm and use to locate
340                                   SpiProtocol.
341   @param   CpuWriteAddress        Address in CPU memory map of flash region.
342   @param   Data                   The buffer containing the data to be written.
343   @param   DataSize               Amount of data to write.
344   @param   DoErase                Earse each block.
345   @param   DoWrite                Write to each block.
346 
347   @retval  EFI_SUCCESS            Operation successful.
348   @retval  EFI_NOT_READY          Required resources not setup.
349   @retval  EFI_INVALID_PARAMETER  Invalid parameter.
350   @retval  Others                 Unexpected error happened.
351 
352 **/
353 EFI_STATUS
354 EFIAPI
PlatformFlashEraseWrite(IN VOID * Smst,IN UINTN CpuWriteAddress,IN UINT8 * Data,IN UINTN DataSize,IN BOOLEAN DoErase,IN BOOLEAN DoWrite)355 PlatformFlashEraseWrite (
356   IN  VOID                              *Smst,
357   IN  UINTN                             CpuWriteAddress,
358   IN  UINT8                             *Data,
359   IN  UINTN                             DataSize,
360   IN  BOOLEAN                           DoErase,
361   IN  BOOLEAN                           DoWrite
362   )
363 {
364   EFI_STATUS                        Status;
365   UINT64                            CpuBaseAddress;
366   SPI_INIT_INFO                     *SpiInfo;
367   UINT8                             *WriteBuf;
368   UINTN                             Index;
369   UINTN                             SpiWriteAddress;
370   EFI_SPI_PROTOCOL                  *SpiProtocol;
371 
372   if (!DoErase && !DoWrite) {
373     return EFI_INVALID_PARAMETER;
374   }
375   if (DoWrite && Data == NULL) {
376     return EFI_INVALID_PARAMETER;
377   }
378   if ((CpuWriteAddress % FLASH_BLOCK_SIZE) != 0) {
379     return EFI_INVALID_PARAMETER;
380   }
381   if ((DataSize % FLASH_BLOCK_SIZE) != 0) {
382     return EFI_INVALID_PARAMETER;
383   }
384   SpiProtocol = LocateSpiProtocol ((EFI_SMM_SYSTEM_TABLE2 *)Smst);
385   if (SpiProtocol == NULL) {
386     return EFI_NOT_READY;
387   }
388 
389   //
390   // Find info to allow usage of SpiProtocol->Execute.
391   //
392   Status = SpiProtocol->Info (
393              SpiProtocol,
394              &SpiInfo
395              );
396   if (EFI_ERROR(Status)) {
397     return Status;
398   }
399   ASSERT (SpiInfo->InitTable != NULL);
400   ASSERT (SpiInfo->EraseOpcodeIndex < SPI_NUM_OPCODE);
401   ASSERT (SpiInfo->ProgramOpcodeIndex < SPI_NUM_OPCODE);
402 
403   CpuBaseAddress = PcdGet32 (PcdFlashAreaBaseAddress) - (UINT32)SpiInfo->InitTable->BiosStartOffset;
404   ASSERT(CpuBaseAddress >= (SIZE_4GB - SIZE_8MB));
405   if (CpuWriteAddress < CpuBaseAddress) {
406     return (EFI_INVALID_PARAMETER);
407   }
408 
409   SpiWriteAddress = CpuWriteAddress - ((UINTN) CpuBaseAddress);
410   WriteBuf = Data;
411   DEBUG (
412     (EFI_D_INFO, "PlatformFlashWrite:SpiWriteAddress=%08x EraseIndex=%d WriteIndex=%d\n",
413     SpiWriteAddress,
414     (UINTN) SpiInfo->EraseOpcodeIndex,
415     (UINTN) SpiInfo->ProgramOpcodeIndex
416     ));
417   for (Index =0; Index < DataSize / FLASH_BLOCK_SIZE; Index++) {
418     if (DoErase) {
419       DEBUG (
420         (EFI_D_INFO, "PlatformFlashWrite:Erase[%04x] SpiWriteAddress=%08x\n",
421         Index,
422         SpiWriteAddress
423         ));
424       Status = SpiProtocol->Execute (
425                               SpiProtocol,
426                               SpiInfo->EraseOpcodeIndex,// OpcodeIndex
427                               0,                        // PrefixOpcodeIndex
428                               FALSE,                    // DataCycle
429                               TRUE,                     // Atomic
430                               FALSE,                    // ShiftOut
431                               SpiWriteAddress,          // Address
432                               0,                        // Data Number
433                               NULL,
434                               EnumSpiRegionAll          // SPI_REGION_TYPE
435                               );
436       if (EFI_ERROR(Status)) {
437         return Status;
438       }
439     }
440 
441     if (DoWrite) {
442       DEBUG (
443         (EFI_D_INFO, "PlatformFlashWrite:Write[%04x] SpiWriteAddress=%08x\n",
444         Index,
445         SpiWriteAddress
446         ));
447       Status = SpiProtocol->Execute (
448                               SpiProtocol,
449                               SpiInfo->ProgramOpcodeIndex,   // OpcodeIndex
450                               0,                             // PrefixOpcodeIndex
451                               TRUE,                          // DataCycle
452                               TRUE,                          // Atomic
453                               TRUE,                          // ShiftOut
454                               SpiWriteAddress,               // Address
455                               FLASH_BLOCK_SIZE,              // Data Number
456                               WriteBuf,
457                               EnumSpiRegionAll
458                               );
459       if (EFI_ERROR(Status)) {
460         return Status;
461       }
462       WriteBuf+=FLASH_BLOCK_SIZE;
463     }
464     SpiWriteAddress+=FLASH_BLOCK_SIZE;
465   }
466   return EFI_SUCCESS;
467 }
468 
469 /** Check if System booted with recovery Boot Stage1 image.
470 
471   @retval  TRUE    If system booted with recovery Boot Stage1 image.
472   @retval  FALSE   If system booted with normal stage1 image.
473 
474 **/
475 BOOLEAN
476 EFIAPI
PlatformIsBootWithRecoveryStage1(VOID)477 PlatformIsBootWithRecoveryStage1 (
478   VOID
479   )
480 {
481   ASSERT_EFI_ERROR (EFI_UNSUPPORTED);
482   return FALSE;
483 }
484 
485