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