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