1/** @file
2
3  Copyright (c) 2014 - 2015, Intel Corporation. All rights reserved.<BR>
4  This program and the accompanying materials
5  are licensed and made available under the terms and conditions of the BSD License
6  which accompanies this distribution.  The full text of the license may be found at
7  http://opensource.org/licenses/bsd-license.php.
8
9  THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
10  WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
11
12**/
13
14#include "SecFsp.h"
15
16/**
17
18  Calculate the FSP IDT gate descriptor.
19
20  @param[in] IdtEntryTemplate     IDT gate descriptor template.
21
22  @return                     FSP specific IDT gate descriptor.
23
24**/
25UINT64
26FspGetExceptionHandler(
27  IN  UINT64  IdtEntryTemplate
28  )
29{
30  UINT32                    Entry;
31  UINT64                    ExceptionHandler;
32  IA32_IDT_GATE_DESCRIPTOR *IdtGateDescriptor;
33  FSP_INFO_HEADER          *FspInfoHeader;
34
35  FspInfoHeader     = (FSP_INFO_HEADER *)AsmGetFspInfoHeader();
36  ExceptionHandler  = IdtEntryTemplate;
37  IdtGateDescriptor = (IA32_IDT_GATE_DESCRIPTOR *)&ExceptionHandler;
38  Entry = (IdtGateDescriptor->Bits.OffsetHigh << 16) | IdtGateDescriptor->Bits.OffsetLow;
39  Entry = FspInfoHeader->ImageBase + FspInfoHeader->ImageSize - (~Entry + 1);
40  IdtGateDescriptor->Bits.OffsetHigh = (UINT16)(Entry >> 16);
41  IdtGateDescriptor->Bits.OffsetLow  = (UINT16)Entry;
42
43  return ExceptionHandler;
44}
45
46/**
47  This function gets the FSP UPD region offset in flash.
48
49  @return the offset of the UPD region.
50
51**/
52UINT32
53EFIAPI
54GetFspUpdRegionOffset (
55  VOID
56  )
57{
58  FSP_GLOBAL_DATA                   *FspData;
59  UINT32                            *Offset;
60
61  FspData       = GetFspGlobalDataPointer ();
62
63  //
64  // It is required to put PcdUpdRegionOffset at offset 0x000C
65  // for all FSPs.
66  // gPlatformFspPkgTokenSpaceGuid.PcdUpdRegionOffset       | 0x000C | 0x12345678
67  //
68  Offset        = (UINT32 *)(FspData->FspInfoHeader->ImageBase + \
69                             FspData->FspInfoHeader->CfgRegionOffset + 0x0C);
70
71  return  *Offset;
72}
73
74/**
75  This interface fills platform specific data.
76
77  @param[in,out]  FspData           Pointer to the FSP global data.
78
79**/
80VOID
81EFIAPI
82SecGetPlatformData (
83  IN OUT  FSP_GLOBAL_DATA    *FspData
84  )
85{
86  FSP_PLAT_DATA    *FspPlatformData;
87  UINT32            TopOfCar;
88  UINT32           *StackPtr;
89  UINT32            DwordSize;
90
91  FspPlatformData = &FspData->PlatformData;
92
93  //
94  // The entries of platform information, together with the number of them,
95  // reside in the bottom of stack, left untouched by normal stack operation.
96  //
97  TopOfCar = PcdGet32 (PcdTemporaryRamBase) + PcdGet32 (PcdTemporaryRamSize);
98
99  FspPlatformData->DataPtr   = NULL;
100  FspPlatformData->MicrocodeRegionBase = 0;
101  FspPlatformData->MicrocodeRegionSize = 0;
102  FspPlatformData->CodeRegionBase      = 0;
103  FspPlatformData->CodeRegionSize      = 0;
104
105  //
106  // Pointer to the size field
107  //
108  StackPtr  = (UINT32 *)(TopOfCar - sizeof(UINT32));
109
110  while (*StackPtr != 0) {
111    if (*(StackPtr - 1) == FSP_MCUD_SIGNATURE) {
112      //
113      // This following data was pushed onto stack after TempRamInit API
114      //
115      DwordSize = 4;
116      StackPtr  = StackPtr - 1 - DwordSize;
117      CopyMem (&(FspPlatformData->MicrocodeRegionBase), StackPtr, (DwordSize << 2));
118      StackPtr--;
119    } else if (*(StackPtr - 1) == FSP_PER0_SIGNATURE) {
120      //
121      // This is the performance data for InitTempMemory API entry/exit
122      //
123      DwordSize = 4;
124      StackPtr  = StackPtr - 1 - DwordSize;
125      CopyMem (FspData->PerfData, StackPtr, (DwordSize << 2));
126      ((UINT8 *)(&FspData->PerfData[0]))[7] = FSP_PERF_ID_API_TMPRAMINIT_ENTRY;
127      ((UINT8 *)(&FspData->PerfData[1]))[7] = FSP_PERF_ID_API_TMPRAMINIT_EXIT;
128      StackPtr--;
129    } else {
130      StackPtr -= (*StackPtr);
131    }
132  }
133}
134
135/**
136
137  Initialize the FSP global data region.
138  It needs to be done as soon as possible after the stack is setup.
139
140  @param[in,out] PeiFspData             Pointer of the FSP global data.
141  @param[in]     BootLoaderStack        BootLoader stack.
142  @param[in]     ApiIdx                 The index of the FSP API.
143
144**/
145VOID
146FspGlobalDataInit (
147  IN OUT  FSP_GLOBAL_DATA    *PeiFspData,
148  IN UINT32                   BootLoaderStack,
149  IN UINT8                    ApiIdx
150  )
151{
152  VOID              *UpdDataRgnPtr;
153  FSP_INIT_PARAMS   *FspInitParams;
154  CHAR8              ImageId[9];
155  UINTN              Idx;
156
157  //
158  // Init PCIE_BAR with value and set global FSP data pointer.
159  // PciExpress Base should have been programmed by platform already.
160  //
161  SetFspGlobalDataPointer    (PeiFspData);
162  ZeroMem  ((VOID *)PeiFspData, sizeof(FSP_GLOBAL_DATA));
163
164  PeiFspData->Signature          = FSP_GLOBAL_DATA_SIGNATURE;
165  PeiFspData->CoreStack          = BootLoaderStack;
166  PeiFspData->PerfIdx            = 2;
167
168  SetFspMeasurePoint (FSP_PERF_ID_API_FSPINIT_ENTRY);
169
170  //
171  // Get FSP Header offset
172  // It may have multiple FVs, so look into the last one for FSP header
173  //
174  PeiFspData->FspInfoHeader      = (FSP_INFO_HEADER *)AsmGetFspInfoHeader();
175  SecGetPlatformData (PeiFspData);
176
177  //
178  // Set API calling mode
179  //
180  SetFspApiCallingMode (ApiIdx == 1 ? 0 : 1);
181
182  //
183  // Initialize UPD pointer.
184  //
185  FspInitParams = (FSP_INIT_PARAMS *)GetFspApiParameter ();
186  UpdDataRgnPtr = ((FSP_INIT_RT_COMMON_BUFFER *)FspInitParams->RtBufferPtr)->UpdDataRgnPtr;
187  if (UpdDataRgnPtr == NULL) {
188    UpdDataRgnPtr = (VOID *)(PeiFspData->FspInfoHeader->ImageBase + GetFspUpdRegionOffset());
189  }
190  SetFspUpdDataPointer (UpdDataRgnPtr);
191
192  //
193  // Initialize serial port
194  // It might have been done in ProcessLibraryConstructorList(), however,
195  // the FSP global data is not initialized at that time. So do it again
196  // for safe.
197  //
198  SerialPortInitialize ();
199
200  //
201  // Ensure the golbal data pointer is valid
202  //
203  ASSERT (GetFspGlobalDataPointer () == PeiFspData);
204
205  for (Idx = 0; Idx < 8; Idx++) {
206    ImageId[Idx] = PeiFspData->FspInfoHeader->ImageId[Idx];
207  }
208  ImageId[Idx] = 0;
209
210  DEBUG ((DEBUG_INFO | DEBUG_INIT, "\n============= PEIM FSP v1.%x (%a v%x.%x.%x.%x) =============\n", \
211         PeiFspData->FspInfoHeader->HeaderRevision - 1, \
212         ImageId, \
213         (PeiFspData->FspInfoHeader->ImageRevision >> 24) & 0xff, \
214         (PeiFspData->FspInfoHeader->ImageRevision >> 16) & 0xff, \
215         (PeiFspData->FspInfoHeader->ImageRevision >> 8) & 0xff, \
216         (PeiFspData->FspInfoHeader->ImageRevision >> 0) & 0xff));
217
218}
219
220/**
221
222  Adjust the FSP data pointers after the stack is migrated to memory.
223
224  @param[in] OffsetGap             The offset gap between the old stack and the new stack.
225
226**/
227VOID
228FspDataPointerFixUp (
229  IN UINT32   OffsetGap
230  )
231{
232  FSP_GLOBAL_DATA  *NewFspData;
233
234  NewFspData = (FSP_GLOBAL_DATA *)((UINTN)GetFspGlobalDataPointer() + (UINTN)OffsetGap);
235  SetFspGlobalDataPointer (NewFspData);
236}
237
238/**
239  This function check the FSP API calling condition.
240
241  @param[in]  ApiIdx           Internal index of the FSP API.
242  @param[in]  ApiParam         Parameter of the FSP API.
243
244**/
245EFI_STATUS
246EFIAPI
247FspApiCallingCheck (
248  IN UINT32   ApiIdx,
249  IN VOID     *ApiParam
250  )
251{
252  EFI_STATUS                Status;
253  FSP_GLOBAL_DATA           *FspData;
254  FSP_INIT_PARAMS           *FspInitParams;
255  FSP_INIT_RT_COMMON_BUFFER *FspRtBuffer;
256
257  FspInitParams = (FSP_INIT_PARAMS *) ApiParam;
258  FspRtBuffer = ((FSP_INIT_RT_COMMON_BUFFER *)FspInitParams->RtBufferPtr);
259
260  Status = EFI_SUCCESS;
261  FspData = GetFspGlobalDataPointer ();
262  if (ApiIdx == 1) {
263    //
264    // FspInit check
265    //
266    if ((UINT32)FspData != 0xFFFFFFFF) {
267      Status = EFI_UNSUPPORTED;
268    } else if ((FspRtBuffer == NULL) || ((FspRtBuffer->BootLoaderTolumSize % EFI_PAGE_SIZE) != 0) || (EFI_ERROR(FspUpdSignatureCheck(ApiIdx, ApiParam)))) {
269      Status = EFI_INVALID_PARAMETER;
270    }
271  } else if (ApiIdx == 2) {
272    //
273    // NotifyPhase check
274    //
275    if ((FspData == NULL) || ((UINT32)FspData == 0xFFFFFFFF)) {
276      Status = EFI_UNSUPPORTED;
277    } else {
278      if (FspData->Signature != FSP_GLOBAL_DATA_SIGNATURE) {
279        Status = EFI_UNSUPPORTED;
280      }
281    }
282  } else if (ApiIdx == 3) {
283    //
284    // FspMemoryInit check
285    //
286    if ((UINT32)FspData != 0xFFFFFFFF) {
287      Status = EFI_UNSUPPORTED;
288    } else if ((FspRtBuffer == NULL) || ((FspRtBuffer->BootLoaderTolumSize % EFI_PAGE_SIZE) != 0) || (EFI_ERROR(FspUpdSignatureCheck(ApiIdx, ApiParam)))) {
289      Status = EFI_INVALID_PARAMETER;
290    }
291  } else if (ApiIdx == 4) {
292    //
293    // TempRamExit check
294    //
295    if ((FspData == NULL) || ((UINT32)FspData == 0xFFFFFFFF)) {
296      Status = EFI_UNSUPPORTED;
297    } else {
298      if (FspData->Signature != FSP_GLOBAL_DATA_SIGNATURE) {
299        Status = EFI_UNSUPPORTED;
300      }
301    }
302  } else if (ApiIdx == 5) {
303    //
304    // FspSiliconInit check
305    //
306    if ((FspData == NULL) || ((UINT32)FspData == 0xFFFFFFFF)) {
307      Status = EFI_UNSUPPORTED;
308    } else {
309      if (FspData->Signature != FSP_GLOBAL_DATA_SIGNATURE) {
310        Status = EFI_UNSUPPORTED;
311      } else if (EFI_ERROR(FspUpdSignatureCheck(ApiIdx, ApiParam))) {
312        Status = EFI_INVALID_PARAMETER;
313      }
314    }
315  } else {
316    Status = EFI_UNSUPPORTED;
317  }
318
319  return Status;
320}
321
322/**
323  This function gets the boot FV offset in FSP.
324  @return the boot firmware volumen offset inside FSP binary
325
326**/
327UINT32
328EFIAPI
329GetBootFirmwareVolumeOffset (
330  VOID
331  )
332{
333  return PcdGet32 (PcdFspBootFirmwareVolumeBase) - PcdGet32 (PcdFspAreaBaseAddress);
334}
335