1/** @file
2This is the driver that publishes the SMM Access Ppi
3instance for the Quark SOC.
4
5Copyright (c) 2013-2015 Intel Corporation.
6
7This program and the accompanying materials
8are licensed and made available under the terms and conditions of the BSD License
9which accompanies this distribution.  The full text of the license may be found at
10http://opensource.org/licenses/bsd-license.php
11
12THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
13WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
14
15**/
16#include <PiPei.h>
17#include <Ppi/SmmAccess.h>
18#include <Guid/SmramMemoryReserve.h>
19#include <Library/BaseMemoryLib.h>
20#include <Library/MemoryAllocationLib.h>
21#include <Library/DebugLib.h>
22#include <Library/HobLib.h>
23#include <Library/PciLib.h>
24#include <Library/PeiServicesLib.h>
25#include <Library/QNCSmmLib.h>
26#include <QNCAccess.h>
27
28#define SMM_ACCESS_PRIVATE_DATA_FROM_THIS(a) \
29  CR ( \
30  a, \
31  SMM_ACCESS_PRIVATE_DATA, \
32  SmmAccess, \
33  SMM_ACCESS_PRIVATE_DATA_SIGNATURE \
34  )
35
36#define MAX_CPU_SOCKET      1
37#define MAX_SMRAM_RANGES    4
38
39typedef struct {
40  UINTN                            Signature;
41  EFI_HANDLE                       Handle;
42  PEI_SMM_ACCESS_PPI               SmmAccess;
43  UINTN                            NumberRegions;
44  EFI_SMRAM_DESCRIPTOR             SmramDesc[MAX_SMRAM_RANGES];
45  UINT8                            TsegSize;
46  UINT8                            MaxBusNumber;
47  UINT8                            SocketPopulated[MAX_CPU_SOCKET];
48  UINT8                            SocketBusNum[MAX_CPU_SOCKET];
49} SMM_ACCESS_PRIVATE_DATA;
50
51#define  SMM_ACCESS_PRIVATE_DATA_SIGNATURE SIGNATURE_32 ('i', 's', 'm', 'a')
52
53
54EFI_STATUS
55EFIAPI
56Open (
57  IN EFI_PEI_SERVICES           **PeiServices,
58  IN PEI_SMM_ACCESS_PPI         *This,
59  IN UINTN                      DescriptorIndex
60  )
61/*++
62
63Routine Description:
64
65  This routine accepts a request to "open" a region of SMRAM.  The
66  region could be legacy ABSEG, HSEG, or TSEG near top of physical memory.
67  The use of "open" means that the memory is visible from all PEIM
68  and SMM agents.
69
70Arguments:
71
72  PeiServices      - General purpose services available to every PEIM.
73  This             -  Pointer to the SMM Access Interface.
74  DescriptorIndex  -  Region of SMRAM to Open.
75
76Returns:
77
78  EFI_SUCCESS            -  The region was successfully opened.
79  EFI_DEVICE_ERROR       -  The region could not be opened because locked by
80                            chipset.
81  EFI_INVALID_PARAMETER  -  The descriptor index was out of bounds.
82
83--*/
84{
85  SMM_ACCESS_PRIVATE_DATA *SmmAccess;
86
87  SmmAccess = SMM_ACCESS_PRIVATE_DATA_FROM_THIS (This);
88
89  if (DescriptorIndex >= SmmAccess->NumberRegions) {
90    return EFI_INVALID_PARAMETER;
91  } else if (SmmAccess->SmramDesc[DescriptorIndex].RegionState & EFI_SMRAM_LOCKED) {
92    return EFI_DEVICE_ERROR;
93  }
94
95  //
96  // Open TSEG
97  //
98  if (!QNCOpenSmramRegion ()) {
99    SmmAccess->SmramDesc[DescriptorIndex].RegionState |= EFI_SMRAM_LOCKED;
100    return EFI_DEVICE_ERROR;
101  }
102
103  SmmAccess->SmramDesc[DescriptorIndex].RegionState &= ~(EFI_SMRAM_CLOSED | EFI_ALLOCATED);
104  SmmAccess->SmramDesc[DescriptorIndex].RegionState |= EFI_SMRAM_OPEN;
105  SmmAccess->SmmAccess.OpenState = TRUE;
106
107  return EFI_SUCCESS;
108}
109
110EFI_STATUS
111EFIAPI
112Close (
113  IN EFI_PEI_SERVICES        **PeiServices,
114  IN PEI_SMM_ACCESS_PPI      *This,
115  IN UINTN                   DescriptorIndex
116  )
117/*++
118
119Routine Description:
120
121  This routine accepts a request to "close" a region of SMRAM.  This is valid for
122  compatible SMRAM region.
123
124Arguments:
125
126  PeiServices      - General purpose services available to every PEIM.
127  This             -  Pointer to the SMM Access Interface.
128  DescriptorIndex  -  Region of SMRAM to Close.
129
130Returns:
131
132  EFI_SUCCESS            -  The region was successfully closed.
133  EFI_DEVICE_ERROR       -  The region could not be closed because locked by
134                            chipset.
135  EFI_INVALID_PARAMETER  -  The descriptor index was out of bounds.
136
137--*/
138{
139  SMM_ACCESS_PRIVATE_DATA *SmmAccess;
140  BOOLEAN                 OpenState;
141  UINTN                   Index;
142
143
144  SmmAccess     = SMM_ACCESS_PRIVATE_DATA_FROM_THIS (This);
145
146  if (DescriptorIndex >= SmmAccess->NumberRegions) {
147    return EFI_INVALID_PARAMETER;
148  } else if (SmmAccess->SmramDesc[DescriptorIndex].RegionState & EFI_SMRAM_LOCKED) {
149    return EFI_DEVICE_ERROR;
150  }
151
152  if (SmmAccess->SmramDesc[DescriptorIndex].RegionState & EFI_SMRAM_CLOSED) {
153    return EFI_DEVICE_ERROR;
154  }
155
156  //
157  // Close TSEG
158  //
159  if (!QNCCloseSmramRegion ()) {
160    SmmAccess->SmramDesc[DescriptorIndex].RegionState |= EFI_SMRAM_LOCKED;
161    return EFI_DEVICE_ERROR;
162  }
163
164  SmmAccess->SmramDesc[DescriptorIndex].RegionState &= ~EFI_SMRAM_OPEN;
165  SmmAccess->SmramDesc[DescriptorIndex].RegionState |= (EFI_SMRAM_CLOSED | EFI_ALLOCATED);
166
167  //
168  // Find out if any regions are still open
169  //
170  OpenState = FALSE;
171  for (Index = 0; Index < SmmAccess->NumberRegions; Index++) {
172    if ((SmmAccess->SmramDesc[Index].RegionState & EFI_SMRAM_OPEN) == EFI_SMRAM_OPEN) {
173      OpenState = TRUE;
174    }
175  }
176
177  SmmAccess->SmmAccess.OpenState = OpenState;
178
179  return EFI_SUCCESS;
180}
181
182EFI_STATUS
183EFIAPI
184Lock (
185  IN EFI_PEI_SERVICES          **PeiServices,
186  IN PEI_SMM_ACCESS_PPI        *This,
187  IN UINTN                     DescriptorIndex
188  )
189/*++
190
191Routine Description:
192
193  This routine accepts a request to "lock" SMRAM.  The
194  region could be legacy AB or TSEG near top of physical memory.
195  The use of "lock" means that the memory can no longer be opened
196  to PEIM.
197
198Arguments:
199
200  PeiServices      - General purpose services available to every PEIM.
201  This             -  Pointer to the SMM Access Interface.
202  DescriptorIndex  -  Region of SMRAM to Lock.
203
204Returns:
205
206  EFI_SUCCESS            -  The region was successfully locked.
207  EFI_DEVICE_ERROR       -  The region could not be locked because at least
208                            one range is still open.
209  EFI_INVALID_PARAMETER  -  The descriptor index was out of bounds.
210
211--*/
212{
213  SMM_ACCESS_PRIVATE_DATA *SmmAccess;
214
215  SmmAccess = SMM_ACCESS_PRIVATE_DATA_FROM_THIS (This);
216
217  if (DescriptorIndex >= SmmAccess->NumberRegions) {
218    return EFI_INVALID_PARAMETER;
219  } else if (SmmAccess->SmmAccess.OpenState) {
220    return EFI_DEVICE_ERROR;
221  }
222
223  SmmAccess->SmramDesc[DescriptorIndex].RegionState |= EFI_SMRAM_LOCKED;
224  SmmAccess->SmmAccess.LockState                     = TRUE;
225
226  //
227  // Lock TSEG
228  //
229  QNCLockSmramRegion ();
230
231  return EFI_SUCCESS;
232}
233
234EFI_STATUS
235EFIAPI
236GetCapabilities (
237  IN EFI_PEI_SERVICES                **PeiServices,
238  IN PEI_SMM_ACCESS_PPI              *This,
239  IN OUT UINTN                       *SmramMapSize,
240  IN OUT EFI_SMRAM_DESCRIPTOR        *SmramMap
241  )
242/*++
243
244Routine Description:
245
246  This routine services a user request to discover the SMRAM
247  capabilities of this platform.  This will report the possible
248  ranges that are possible for SMRAM access, based upon the
249  memory controller capabilities.
250
251Arguments:
252
253  PeiServices   - General purpose services available to every PEIM.
254  This          -  Pointer to the SMRAM Access Interface.
255  SmramMapSize  -  Pointer to the variable containing size of the
256                   buffer to contain the description information.
257  SmramMap      -  Buffer containing the data describing the Smram
258                   region descriptors.
259Returns:
260
261  EFI_BUFFER_TOO_SMALL  -  The user did not provide a sufficient buffer.
262  EFI_SUCCESS           -  The user provided a sufficiently-sized buffer.
263
264--*/
265{
266  EFI_STATUS                Status;
267  SMM_ACCESS_PRIVATE_DATA  *SmmAccess;
268  UINTN                     BufferSize;
269
270  SmmAccess           = SMM_ACCESS_PRIVATE_DATA_FROM_THIS (This);
271  BufferSize          = SmmAccess->NumberRegions * sizeof (EFI_SMRAM_DESCRIPTOR);
272
273  if (*SmramMapSize < BufferSize) {
274    Status = EFI_BUFFER_TOO_SMALL;
275  } else {
276    CopyMem (SmramMap, SmmAccess->SmramDesc, *SmramMapSize);
277    Status = EFI_SUCCESS;
278  }
279
280  *SmramMapSize = BufferSize;
281
282  return Status;
283}
284
285
286EFI_STATUS
287EFIAPI
288SmmAccessPeiEntryPoint (
289  IN       EFI_PEI_FILE_HANDLE  FileHandle,
290  IN CONST EFI_PEI_SERVICES     **PeiServices
291  )
292/*++
293
294Routine Description:
295
296    This is the constructor for the SMM Access Ppi
297
298Arguments:
299
300    FfsHeader       - FfsHeader.
301    PeiServices     - General purpose services available to every PEIM.
302
303Returns:
304
305  EFI_SUCCESS     -  Protocol successfully started and installed.
306  EFI_UNSUPPORTED -  Protocol can't be started.
307--*/
308{
309
310  EFI_STATUS                      Status;
311  UINTN                           Index;
312  EFI_SMRAM_HOB_DESCRIPTOR_BLOCK  *DescriptorBlock;
313  SMM_ACCESS_PRIVATE_DATA         *SmmAccessPrivate;
314  EFI_PEI_PPI_DESCRIPTOR          *PpiList;
315  EFI_HOB_GUID_TYPE               *GuidHob;
316
317  //
318  // Initialize private data
319  //
320  SmmAccessPrivate = AllocatePool (sizeof(*SmmAccessPrivate));
321  ASSERT(SmmAccessPrivate);
322
323  PpiList = AllocatePool (sizeof(*PpiList));
324  ASSERT (PpiList);
325
326  //
327  // Build SMM related information
328  //
329  SmmAccessPrivate->Signature = SMM_ACCESS_PRIVATE_DATA_SIGNATURE;
330
331  //
332  // Get Hob list
333  //
334  GuidHob    = GetFirstGuidHob (&gEfiSmmPeiSmramMemoryReserveGuid);
335  DescriptorBlock = GET_GUID_HOB_DATA (GuidHob);
336  ASSERT (DescriptorBlock);
337
338  // Get CPU Max bus number
339
340  SmmAccessPrivate->MaxBusNumber = PCI_BUS_NUMBER_QNC;
341  for (Index = 0; Index < MAX_CPU_SOCKET; Index++) {
342    SmmAccessPrivate->SocketPopulated[Index] = TRUE;
343    SmmAccessPrivate->SocketBusNum[Index]    = PCI_BUS_NUMBER_QNC;
344  }
345
346  //
347  // Use the hob to publish SMRAM capabilities
348  //
349  ASSERT (DescriptorBlock->NumberOfSmmReservedRegions <= MAX_SMRAM_RANGES);
350  for (Index = 0; Index < DescriptorBlock->NumberOfSmmReservedRegions; Index++) {
351    SmmAccessPrivate->SmramDesc[Index].PhysicalStart = DescriptorBlock->Descriptor[Index].PhysicalStart;
352    SmmAccessPrivate->SmramDesc[Index].CpuStart      = DescriptorBlock->Descriptor[Index].CpuStart;
353    SmmAccessPrivate->SmramDesc[Index].PhysicalSize  = DescriptorBlock->Descriptor[Index].PhysicalSize;
354    SmmAccessPrivate->SmramDesc[Index].RegionState   = DescriptorBlock->Descriptor[Index].RegionState;
355  }
356
357  SmmAccessPrivate->NumberRegions              = Index;
358  SmmAccessPrivate->SmmAccess.Open             = Open;
359  SmmAccessPrivate->SmmAccess.Close            = Close;
360  SmmAccessPrivate->SmmAccess.Lock             = Lock;
361  SmmAccessPrivate->SmmAccess.GetCapabilities  = GetCapabilities;
362  SmmAccessPrivate->SmmAccess.LockState        = FALSE;
363  SmmAccessPrivate->SmmAccess.OpenState        = FALSE;
364
365  PpiList->Flags = (EFI_PEI_PPI_DESCRIPTOR_PPI | EFI_PEI_PPI_DESCRIPTOR_TERMINATE_LIST);
366  PpiList->Guid  = &gPeiSmmAccessPpiGuid;
367  PpiList->Ppi   = &SmmAccessPrivate->SmmAccess;
368
369  Status      = (**PeiServices).InstallPpi (PeiServices, PpiList);
370  ASSERT_EFI_ERROR(Status);
371
372  DEBUG (
373    (EFI_D_INFO, "SMM Base:Size %08X:%08X\n",
374    (UINTN)(SmmAccessPrivate->SmramDesc[SmmAccessPrivate->NumberRegions-1].PhysicalStart),
375    (UINTN)(SmmAccessPrivate->SmramDesc[SmmAccessPrivate->NumberRegions-1].PhysicalSize)
376    ));
377
378  SmmAccessPrivate->TsegSize = (UINT8)(SmmAccessPrivate->SmramDesc[SmmAccessPrivate->NumberRegions-1].PhysicalSize);
379
380  return EFI_SUCCESS;
381}
382
383