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