VirtualBox

source: vbox/trunk/src/VBox/Devices/EFI/FirmwareNew/OvmfPkg/SmmAccess/SmmAccessPei.c@ 105670

Last change on this file since 105670 was 105670, checked in by vboxsync, 7 months ago

Devices/EFI/FirmwareNew: Merge edk2-stable-202405 and make it build on aarch64, bugref:4643

  • Property svn:eol-style set to native
File size: 11.1 KB
Line 
1/** @file
2
3 A PEIM with the following responsibilities:
4
5 - verify & configure the Q35 TSEG in the entry point,
6 - provide SMRAM access by producing PEI_SMM_ACCESS_PPI
7
8 This PEIM runs from RAM, so we can write to variables with static storage
9 duration.
10
11 Copyright (C) 2013, 2015, Red Hat, Inc.<BR>
12 Copyright (c) 2010 - 2024, Intel Corporation. All rights reserved.<BR>
13
14 SPDX-License-Identifier: BSD-2-Clause-Patent
15
16**/
17
18#include <Library/BaseLib.h>
19#include <Library/BaseMemoryLib.h>
20#include <Library/DebugLib.h>
21#include <Library/IoLib.h>
22#include <Library/PcdLib.h>
23#include <Library/PciLib.h>
24#include <Library/PeiServicesLib.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
35/**
36 Opens the SMRAM area to be accessible by a PEIM driver.
37
38 This function "opens" SMRAM so that it is visible while not inside of SMM.
39 The function should return EFI_UNSUPPORTED if the hardware does not support
40 hiding of SMRAM. The function should return EFI_DEVICE_ERROR if the SMRAM
41 configuration is locked.
42
43 @param PeiServices General purpose services available to every
44 PEIM.
45 @param This The pointer to the SMM Access Interface.
46 @param DescriptorIndex The region of SMRAM to Open.
47
48 @retval EFI_SUCCESS The region was successfully opened.
49 @retval EFI_DEVICE_ERROR The region could not be opened because locked
50 by chipset.
51 @retval EFI_INVALID_PARAMETER The descriptor index was out of bounds.
52
53**/
54STATIC
55EFI_STATUS
56EFIAPI
57SmmAccessPeiOpen (
58 IN EFI_PEI_SERVICES **PeiServices,
59 IN PEI_SMM_ACCESS_PPI *This,
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
84/**
85 Inhibits access to the SMRAM.
86
87 This function "closes" SMRAM so that it is not visible while outside of SMM.
88 The function should return EFI_UNSUPPORTED if the hardware does not support
89 hiding of SMRAM.
90
91 @param PeiServices General purpose services available to every
92 PEIM.
93 @param This The pointer to the SMM Access Interface.
94 @param DescriptorIndex The region of SMRAM to Close.
95
96 @retval EFI_SUCCESS The region was successfully closed.
97 @retval EFI_DEVICE_ERROR The region could not be closed because
98 locked by chipset.
99 @retval EFI_INVALID_PARAMETER The descriptor index was out of bounds.
100
101**/
102STATIC
103EFI_STATUS
104EFIAPI
105SmmAccessPeiClose (
106 IN EFI_PEI_SERVICES **PeiServices,
107 IN PEI_SMM_ACCESS_PPI *This,
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
132/**
133 Inhibits access to the SMRAM.
134
135 This function prohibits access to the SMRAM region. This function is usually
136 implemented such that it is a write-once operation.
137
138 @param PeiServices General purpose services available to every
139 PEIM.
140 @param This The pointer to the SMM Access Interface.
141 @param DescriptorIndex The region of SMRAM to Close.
142
143 @retval EFI_SUCCESS The region was successfully locked.
144 @retval EFI_DEVICE_ERROR The region could not be locked because at
145 least one range is still open.
146 @retval EFI_INVALID_PARAMETER The descriptor index was out of bounds.
147
148**/
149STATIC
150EFI_STATUS
151EFIAPI
152SmmAccessPeiLock (
153 IN EFI_PEI_SERVICES **PeiServices,
154 IN PEI_SMM_ACCESS_PPI *This,
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
179/**
180 Queries the memory controller for the possible regions that will support
181 SMRAM.
182
183 @param PeiServices General purpose services available to every
184 PEIM.
185 @param This The pointer to the SmmAccessPpi Interface.
186 @param SmramMapSize The pointer to the variable containing size of
187 the buffer to contain the description
188 information.
189 @param SmramMap The buffer containing the data describing the
190 Smram region descriptors.
191
192 @retval EFI_BUFFER_TOO_SMALL The user did not provide a sufficient buffer.
193 @retval EFI_SUCCESS The user provided a sufficiently-sized buffer.
194
195**/
196STATIC
197EFI_STATUS
198EFIAPI
199SmmAccessPeiGetCapabilities (
200 IN EFI_PEI_SERVICES **PeiServices,
201 IN PEI_SMM_ACCESS_PPI *This,
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 = {
216 &SmmAccessPeiOpen,
217 &SmmAccessPeiClose,
218 &SmmAccessPeiLock,
219 &SmmAccessPeiGetCapabilities
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//
260EFI_STATUS
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 //
350 InitQ35TsegMbytes ();
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 //
373 PciAndThenOr8 (
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 //
385 InitQ35SmramAtDefaultSmbase ();
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}
Note: See TracBrowser for help on using the repository browser.

© 2024 Oracle Support Privacy / Do Not Sell My Info Terms of Use Trademark Policy Automated Access Etiquette