TianoCore EDK2 master
Loading...
Searching...
No Matches
SmmAccessPei.c
Go to the documentation of this file.
1
18#include <Library/BaseLib.h>
20#include <Library/DebugLib.h>
21#include <Library/IoLib.h>
22#include <Library/PcdLib.h>
23#include <Library/PciLib.h>
25#include <Ppi/SmmAccess.h>
26
27#include <OvmfPlatforms.h>
28
29#include "SmramInternal.h"
30
31//
32// PEI_SMM_ACCESS_PPI implementation.
33//
34
56EFIAPI
58 IN EFI_PEI_SERVICES **PeiServices,
60 IN UINTN DescriptorIndex
61 )
62{
63 EFI_HOB_GUID_TYPE *GuidHob;
64 EFI_SMRAM_HOB_DESCRIPTOR_BLOCK *DescriptorBlock;
65
66 //
67 // Get the number of regions in the system that can be usable for SMRAM
68 //
69 GuidHob = GetFirstGuidHob (&gEfiSmmSmramMemoryGuid);
70 DescriptorBlock = GET_GUID_HOB_DATA (GuidHob);
71 ASSERT (DescriptorBlock);
72
73 if (DescriptorIndex >= DescriptorBlock->NumberOfSmmReservedRegions) {
74 return EFI_INVALID_PARAMETER;
75 }
76
77 //
78 // According to current practice, DescriptorIndex is not considered at all,
79 // beyond validating it.
80 //
81 return SmramAccessOpen (&This->LockState, &This->OpenState);
82}
83
102STATIC
104EFIAPI
106 IN EFI_PEI_SERVICES **PeiServices,
108 IN UINTN DescriptorIndex
109 )
110{
111 EFI_HOB_GUID_TYPE *GuidHob;
112 EFI_SMRAM_HOB_DESCRIPTOR_BLOCK *DescriptorBlock;
113
114 //
115 // Get the number of regions in the system that can be usable for SMRAM
116 //
117 GuidHob = GetFirstGuidHob (&gEfiSmmSmramMemoryGuid);
118 DescriptorBlock = GET_GUID_HOB_DATA (GuidHob);
119 ASSERT (DescriptorBlock);
120
121 if (DescriptorIndex >= DescriptorBlock->NumberOfSmmReservedRegions) {
122 return EFI_INVALID_PARAMETER;
123 }
124
125 //
126 // According to current practice, DescriptorIndex is not considered at all,
127 // beyond validating it.
128 //
129 return SmramAccessClose (&This->LockState, &This->OpenState);
130}
131
149STATIC
151EFIAPI
153 IN EFI_PEI_SERVICES **PeiServices,
155 IN UINTN DescriptorIndex
156 )
157{
158 EFI_HOB_GUID_TYPE *GuidHob;
159 EFI_SMRAM_HOB_DESCRIPTOR_BLOCK *DescriptorBlock;
160
161 //
162 // Get the number of regions in the system that can be usable for SMRAM
163 //
164 GuidHob = GetFirstGuidHob (&gEfiSmmSmramMemoryGuid);
165 DescriptorBlock = GET_GUID_HOB_DATA (GuidHob);
166 ASSERT (DescriptorBlock);
167
168 if (DescriptorIndex >= DescriptorBlock->NumberOfSmmReservedRegions) {
169 return EFI_INVALID_PARAMETER;
170 }
171
172 //
173 // According to current practice, DescriptorIndex is not considered at all,
174 // beyond validating it.
175 //
176 return SmramAccessLock (&This->LockState, &This->OpenState);
177}
178
196STATIC
198EFIAPI
200 IN EFI_PEI_SERVICES **PeiServices,
202 IN OUT UINTN *SmramMapSize,
203 IN OUT EFI_SMRAM_DESCRIPTOR *SmramMap
204 )
205{
206 return SmramAccessGetCapabilities (
207 SmramMapSize,
208 SmramMap
209 );
210}
211
212//
213// LockState and OpenState will be filled in by the entry point.
214//
215STATIC PEI_SMM_ACCESS_PPI mAccess = {
220};
221
222STATIC EFI_PEI_PPI_DESCRIPTOR mPpiList[] = {
223 {
224 EFI_PEI_PPI_DESCRIPTOR_PPI | EFI_PEI_PPI_DESCRIPTOR_TERMINATE_LIST,
225 &gPeiSmmAccessPpiGuid, &mAccess
226 }
227};
228
229//
230// Utility functions.
231//
232STATIC
233UINT8
234CmosRead8 (
235 IN UINT8 Index
236 )
237{
238 IoWrite8 (0x70, Index);
239 return IoRead8 (0x71);
240}
241
242STATIC
243UINT32
244GetSystemMemorySizeBelow4gb (
245 VOID
246 )
247{
248 UINT32 Cmos0x34;
249 UINT32 Cmos0x35;
250
251 Cmos0x34 = CmosRead8 (0x34);
252 Cmos0x35 = CmosRead8 (0x35);
253
254 return ((Cmos0x35 << 8 | Cmos0x34) << 16) + SIZE_16MB;
255}
256
257//
258// Entry point of this driver.
259//
261EFIAPI
262SmmAccessPeiEntryPoint (
263 IN EFI_PEI_FILE_HANDLE FileHandle,
264 IN CONST EFI_PEI_SERVICES **PeiServices
265 )
266{
267 UINT16 HostBridgeDevId;
268 UINT8 EsmramcVal;
269 UINT8 RegMask8;
270 UINT32 TopOfLowRam, TopOfLowRamMb;
271
272 //
273 // This module should only be included if SMRAM support is required.
274 //
275 ASSERT (FeaturePcdGet (PcdSmmSmramRequire));
276
277 //
278 // Verify if we're running on a Q35 machine type.
279 //
280 HostBridgeDevId = PciRead16 (OVMF_HOSTBRIDGE_DID);
281 if (HostBridgeDevId != INTEL_Q35_MCH_DEVICE_ID) {
282 DEBUG ((
283 DEBUG_ERROR,
284 "%a: no SMRAM with host bridge DID=0x%04x; only "
285 "DID=0x%04x (Q35) is supported\n",
286 __func__,
287 HostBridgeDevId,
288 INTEL_Q35_MCH_DEVICE_ID
289 ));
290 goto WrongConfig;
291 }
292
293 //
294 // Confirm if QEMU supports SMRAM.
295 //
296 // With no support for it, the ESMRAMC (Extended System Management RAM
297 // Control) register reads as zero. If there is support, the cache-enable
298 // bits are hard-coded as 1 by QEMU.
299 //
300 EsmramcVal = PciRead8 (DRAMC_REGISTER_Q35 (MCH_ESMRAMC));
301 RegMask8 = MCH_ESMRAMC_SM_CACHE | MCH_ESMRAMC_SM_L1 | MCH_ESMRAMC_SM_L2;
302 if ((EsmramcVal & RegMask8) != RegMask8) {
303 DEBUG ((
304 DEBUG_ERROR,
305 "%a: this Q35 implementation lacks SMRAM\n",
306 __func__
307 ));
308 goto WrongConfig;
309 }
310
311 TopOfLowRam = GetSystemMemorySizeBelow4gb ();
312 ASSERT ((TopOfLowRam & (SIZE_1MB - 1)) == 0);
313 TopOfLowRamMb = TopOfLowRam >> 20;
314
315 //
316 // Some of the following registers are no-ops for QEMU at the moment, but it
317 // is recommended to set them correctly, since the ESMRAMC that we ultimately
318 // care about is in the same set of registers.
319 //
320 // First, we disable the integrated VGA, and set both the GTT Graphics Memory
321 // Size and the Graphics Mode Select memory pre-allocation fields to zero.
322 // This takes just one write to the Graphics Control Register.
323 //
324 PciWrite16 (DRAMC_REGISTER_Q35 (MCH_GGC), MCH_GGC_IVD);
325
326 //
327 // Set Top of Low Usable DRAM.
328 //
329 PciWrite16 (
330 DRAMC_REGISTER_Q35 (MCH_TOLUD),
331 (UINT16)(TopOfLowRamMb << MCH_TOLUD_MB_SHIFT)
332 );
333
334 //
335 // Given the zero graphics memory sizes configured above, set the
336 // graphics-related stolen memory bases to the same as TOLUD.
337 //
338 PciWrite32 (
339 DRAMC_REGISTER_Q35 (MCH_GBSM),
340 TopOfLowRamMb << MCH_GBSM_MB_SHIFT
341 );
342 PciWrite32 (
343 DRAMC_REGISTER_Q35 (MCH_BGSM),
344 TopOfLowRamMb << MCH_BGSM_MB_SHIFT
345 );
346
347 //
348 // Set TSEG Memory Base.
349 //
351 PciWrite32 (
352 DRAMC_REGISTER_Q35 (MCH_TSEGMB),
353 (TopOfLowRamMb - mQ35TsegMbytes) << MCH_TSEGMB_MB_SHIFT
354 );
355
356 //
357 // Set TSEG size, and disable TSEG visibility outside of SMM. Note that the
358 // T_EN bit has inverse meaning; when T_EN is set, then TSEG visibility is
359 // *restricted* to SMM.
360 //
361 EsmramcVal &= ~(UINT32)MCH_ESMRAMC_TSEG_MASK;
362 EsmramcVal |= mQ35TsegMbytes == 8 ? MCH_ESMRAMC_TSEG_8MB :
363 mQ35TsegMbytes == 2 ? MCH_ESMRAMC_TSEG_2MB :
364 mQ35TsegMbytes == 1 ? MCH_ESMRAMC_TSEG_1MB :
365 MCH_ESMRAMC_TSEG_EXT;
366 EsmramcVal |= MCH_ESMRAMC_T_EN;
367 PciWrite8 (DRAMC_REGISTER_Q35 (MCH_ESMRAMC), EsmramcVal);
368
369 //
370 // TSEG should be closed (see above), but unlocked, initially. Set G_SMRAME
371 // (Global SMRAM Enable) too, as both D_LCK and T_EN depend on it.
372 //
374 DRAMC_REGISTER_Q35 (MCH_SMRAM),
375 (UINT8)((~(UINT32)MCH_SMRAM_D_LCK) & 0xff),
376 MCH_SMRAM_G_SMRAME
377 );
378
379 GetStates (&mAccess.LockState, &mAccess.OpenState);
380
381 //
382 // SmramAccessLock() depends on "mQ35SmramAtDefaultSmbase"; init the latter
383 // just before exposing the former via PEI_SMM_ACCESS_PPI.Lock().
384 //
386
387 //
388 // We're done. The next step should succeed, but even if it fails, we can't
389 // roll back the above BuildGuidHob() allocation, because PEI doesn't support
390 // releasing memory.
391 //
392 return PeiServicesInstallPpi (mPpiList);
393
394WrongConfig:
395 //
396 // We really don't want to continue in this case.
397 //
398 ASSERT (FALSE);
399 CpuDeadLoop ();
400 return EFI_UNSUPPORTED;
401}
UINT64 UINTN
VOID *EFIAPI GetFirstGuidHob(IN CONST EFI_GUID *Guid)
Definition: HobLib.c:215
VOID EFIAPI CpuDeadLoop(VOID)
Definition: CpuDeadLoop.c:25
UINT8 EFIAPI CmosRead8(IN UINTN Index)
Definition: Cmos.c:25
EFI_STATUS EFIAPI PeiServicesInstallPpi(IN CONST EFI_PEI_PPI_DESCRIPTOR *PpiList)
UINT8 EFIAPI IoWrite8(IN UINTN Port, IN UINT8 Value)
Definition: IoLibArmVirt.c:200
UINT8 EFIAPI IoRead8(IN UINTN Port)
Definition: IoLibArmVirt.c:175
#define CONST
Definition: Base.h:259
#define STATIC
Definition: Base.h:264
#define FALSE
Definition: Base.h:307
#define IN
Definition: Base.h:279
#define OUT
Definition: Base.h:284
#define DEBUG(Expression)
Definition: DebugLib.h:434
UINT8 EFIAPI PciRead8(IN UINTN Address)
Definition: PciLib.c:62
UINT32 EFIAPI PciWrite32(IN UINTN Address, IN UINT32 Value)
Definition: PciLib.c:765
UINT8 EFIAPI PciAndThenOr8(IN UINTN Address, IN UINT8 AndData, IN UINT8 OrData)
Definition: PciLib.c:179
UINT8 EFIAPI PciWrite8(IN UINTN Address, IN UINT8 Value)
Definition: PciLib.c:87
UINT16 EFIAPI PciWrite16(IN UINTN Address, IN UINT16 Value)
Definition: PciLib.c:422
UINT16 EFIAPI PciRead16(IN UINTN Address)
Definition: PciLib.c:396
#define FeaturePcdGet(TokenName)
Definition: PcdLib.h:50
VOID * EFI_PEI_FILE_HANDLE
Definition: PiPeiCis.h:26
STATIC EFI_STATUS EFIAPI SmmAccessPeiGetCapabilities(IN EFI_PEI_SERVICES **PeiServices, IN PEI_SMM_ACCESS_PPI *This, IN OUT UINTN *SmramMapSize, IN OUT EFI_SMRAM_DESCRIPTOR *SmramMap)
Definition: SmmAccessPei.c:199
STATIC EFI_STATUS EFIAPI SmmAccessPeiClose(IN EFI_PEI_SERVICES **PeiServices, IN PEI_SMM_ACCESS_PPI *This, IN UINTN DescriptorIndex)
Definition: SmmAccessPei.c:105
STATIC EFI_STATUS EFIAPI SmmAccessPeiOpen(IN EFI_PEI_SERVICES **PeiServices, IN PEI_SMM_ACCESS_PPI *This, IN UINTN DescriptorIndex)
Definition: SmmAccessPei.c:57
STATIC EFI_STATUS EFIAPI SmmAccessPeiLock(IN EFI_PEI_SERVICES **PeiServices, IN PEI_SMM_ACCESS_PPI *This, IN UINTN DescriptorIndex)
Definition: SmmAccessPei.c:152
VOID InitQ35SmramAtDefaultSmbase(VOID)
Definition: SmramInternal.c:44
VOID GetStates(OUT BOOLEAN *LockState, OUT BOOLEAN *OpenState)
Definition: SmramInternal.c:66
VOID InitQ35TsegMbytes(VOID)
Definition: SmramInternal.c:33
RETURN_STATUS EFI_STATUS
Definition: UefiBaseType.h:29