]> git.proxmox.com Git - mirror_edk2.git/blob - OvmfPkg/XenPlatformPei/Platform.c
OvmfPkg/OvmfXen: set PcdAcpiS3Enable at initialization
[mirror_edk2.git] / OvmfPkg / XenPlatformPei / Platform.c
1 /**@file
2 Platform PEI driver
3
4 Copyright (c) 2006 - 2016, Intel Corporation. All rights reserved.<BR>
5 Copyright (c) 2011, Andrei Warkentin <andreiw@motorola.com>
6 Copyright (c) 2019, Citrix Systems, Inc.
7
8 SPDX-License-Identifier: BSD-2-Clause-Patent
9
10 **/
11
12 //
13 // The package level header files this module uses
14 //
15 #include <PiPei.h>
16
17 //
18 // The Library classes this module consumes
19 //
20 #include <Library/BaseLib.h>
21 #include <Library/DebugLib.h>
22 #include <Library/HobLib.h>
23 #include <Library/IoLib.h>
24 #include <Library/MemoryAllocationLib.h>
25 #include <Library/PcdLib.h>
26 #include <Library/PciLib.h>
27 #include <Library/PeimEntryPoint.h>
28 #include <Library/PeiServicesLib.h>
29 #include <Library/QemuFwCfgS3Lib.h>
30 #include <Library/ResourcePublicationLib.h>
31 #include <Guid/MemoryTypeInformation.h>
32 #include <Ppi/MasterBootMode.h>
33 #include <IndustryStandard/Pci22.h>
34 #include <OvmfPlatforms.h>
35
36 #include "Platform.h"
37 #include "Cmos.h"
38
39 EFI_MEMORY_TYPE_INFORMATION mDefaultMemoryTypeInformation[] = {
40 { EfiACPIMemoryNVS, 0x004 },
41 { EfiACPIReclaimMemory, 0x008 },
42 { EfiReservedMemoryType, 0x004 },
43 { EfiRuntimeServicesData, 0x024 },
44 { EfiRuntimeServicesCode, 0x030 },
45 { EfiBootServicesCode, 0x180 },
46 { EfiBootServicesData, 0xF00 },
47 { EfiMaxMemoryType, 0x000 }
48 };
49
50
51 EFI_PEI_PPI_DESCRIPTOR mPpiBootMode[] = {
52 {
53 EFI_PEI_PPI_DESCRIPTOR_PPI | EFI_PEI_PPI_DESCRIPTOR_TERMINATE_LIST,
54 &gEfiPeiMasterBootModePpiGuid,
55 NULL
56 }
57 };
58
59
60 UINT16 mHostBridgeDevId;
61
62 EFI_BOOT_MODE mBootMode = BOOT_WITH_FULL_CONFIGURATION;
63
64
65 VOID
66 AddIoMemoryBaseSizeHob (
67 EFI_PHYSICAL_ADDRESS MemoryBase,
68 UINT64 MemorySize
69 )
70 {
71 BuildResourceDescriptorHob (
72 EFI_RESOURCE_MEMORY_MAPPED_IO,
73 EFI_RESOURCE_ATTRIBUTE_PRESENT |
74 EFI_RESOURCE_ATTRIBUTE_INITIALIZED |
75 EFI_RESOURCE_ATTRIBUTE_UNCACHEABLE |
76 EFI_RESOURCE_ATTRIBUTE_TESTED,
77 MemoryBase,
78 MemorySize
79 );
80 }
81
82 VOID
83 AddReservedMemoryBaseSizeHob (
84 EFI_PHYSICAL_ADDRESS MemoryBase,
85 UINT64 MemorySize,
86 BOOLEAN Cacheable
87 )
88 {
89 BuildResourceDescriptorHob (
90 EFI_RESOURCE_MEMORY_RESERVED,
91 EFI_RESOURCE_ATTRIBUTE_PRESENT |
92 EFI_RESOURCE_ATTRIBUTE_INITIALIZED |
93 EFI_RESOURCE_ATTRIBUTE_UNCACHEABLE |
94 (Cacheable ?
95 EFI_RESOURCE_ATTRIBUTE_WRITE_COMBINEABLE |
96 EFI_RESOURCE_ATTRIBUTE_WRITE_THROUGH_CACHEABLE |
97 EFI_RESOURCE_ATTRIBUTE_WRITE_BACK_CACHEABLE :
98 0
99 ) |
100 EFI_RESOURCE_ATTRIBUTE_TESTED,
101 MemoryBase,
102 MemorySize
103 );
104 }
105
106 VOID
107 AddReservedMemoryRangeHob (
108 EFI_PHYSICAL_ADDRESS MemoryBase,
109 EFI_PHYSICAL_ADDRESS MemoryLimit,
110 BOOLEAN Cacheable
111 )
112 {
113 AddReservedMemoryBaseSizeHob (MemoryBase,
114 (UINT64)(MemoryLimit - MemoryBase), Cacheable);
115 }
116
117 VOID
118 AddIoMemoryRangeHob (
119 EFI_PHYSICAL_ADDRESS MemoryBase,
120 EFI_PHYSICAL_ADDRESS MemoryLimit
121 )
122 {
123 AddIoMemoryBaseSizeHob (MemoryBase, (UINT64)(MemoryLimit - MemoryBase));
124 }
125
126
127 VOID
128 AddMemoryBaseSizeHob (
129 EFI_PHYSICAL_ADDRESS MemoryBase,
130 UINT64 MemorySize
131 )
132 {
133 BuildResourceDescriptorHob (
134 EFI_RESOURCE_SYSTEM_MEMORY,
135 EFI_RESOURCE_ATTRIBUTE_PRESENT |
136 EFI_RESOURCE_ATTRIBUTE_INITIALIZED |
137 EFI_RESOURCE_ATTRIBUTE_UNCACHEABLE |
138 EFI_RESOURCE_ATTRIBUTE_WRITE_COMBINEABLE |
139 EFI_RESOURCE_ATTRIBUTE_WRITE_THROUGH_CACHEABLE |
140 EFI_RESOURCE_ATTRIBUTE_WRITE_BACK_CACHEABLE |
141 EFI_RESOURCE_ATTRIBUTE_TESTED,
142 MemoryBase,
143 MemorySize
144 );
145 }
146
147
148 VOID
149 AddMemoryRangeHob (
150 EFI_PHYSICAL_ADDRESS MemoryBase,
151 EFI_PHYSICAL_ADDRESS MemoryLimit
152 )
153 {
154 AddMemoryBaseSizeHob (MemoryBase, (UINT64)(MemoryLimit - MemoryBase));
155 }
156
157
158 VOID
159 MemMapInitialization (
160 VOID
161 )
162 {
163 UINT64 PciIoBase;
164 UINT64 PciIoSize;
165 RETURN_STATUS PcdStatus;
166
167 PciIoBase = 0xC000;
168 PciIoSize = 0x4000;
169
170 //
171 // Create Memory Type Information HOB
172 //
173 BuildGuidDataHob (
174 &gEfiMemoryTypeInformationGuid,
175 mDefaultMemoryTypeInformation,
176 sizeof(mDefaultMemoryTypeInformation)
177 );
178
179 //
180 // Video memory + Legacy BIOS region
181 //
182 AddIoMemoryRangeHob (0x0A0000, BASE_1MB);
183
184 //
185 // Add PCI IO Port space available for PCI resource allocations.
186 //
187 BuildResourceDescriptorHob (
188 EFI_RESOURCE_IO,
189 EFI_RESOURCE_ATTRIBUTE_PRESENT |
190 EFI_RESOURCE_ATTRIBUTE_INITIALIZED,
191 PciIoBase,
192 PciIoSize
193 );
194 PcdStatus = PcdSet64S (PcdPciIoBase, PciIoBase);
195 ASSERT_RETURN_ERROR (PcdStatus);
196 PcdStatus = PcdSet64S (PcdPciIoSize, PciIoSize);
197 ASSERT_RETURN_ERROR (PcdStatus);
198 }
199
200 VOID
201 PciExBarInitialization (
202 VOID
203 )
204 {
205 union {
206 UINT64 Uint64;
207 UINT32 Uint32[2];
208 } PciExBarBase;
209
210 //
211 // We only support the 256MB size for the MMCONFIG area:
212 // 256 buses * 32 devices * 8 functions * 4096 bytes config space.
213 //
214 // The masks used below enforce the Q35 requirements that the MMCONFIG area
215 // be (a) correctly aligned -- here at 256 MB --, (b) located under 64 GB.
216 //
217 // Note that (b) also ensures that the minimum address width we have
218 // determined in AddressWidthInitialization(), i.e., 36 bits, will suffice
219 // for DXE's page tables to cover the MMCONFIG area.
220 //
221 PciExBarBase.Uint64 = FixedPcdGet64 (PcdPciExpressBaseAddress);
222 ASSERT ((PciExBarBase.Uint32[1] & MCH_PCIEXBAR_HIGHMASK) == 0);
223 ASSERT ((PciExBarBase.Uint32[0] & MCH_PCIEXBAR_LOWMASK) == 0);
224
225 //
226 // Clear the PCIEXBAREN bit first, before programming the high register.
227 //
228 PciWrite32 (DRAMC_REGISTER_Q35 (MCH_PCIEXBAR_LOW), 0);
229
230 //
231 // Program the high register. Then program the low register, setting the
232 // MMCONFIG area size and enabling decoding at once.
233 //
234 PciWrite32 (DRAMC_REGISTER_Q35 (MCH_PCIEXBAR_HIGH), PciExBarBase.Uint32[1]);
235 PciWrite32 (
236 DRAMC_REGISTER_Q35 (MCH_PCIEXBAR_LOW),
237 PciExBarBase.Uint32[0] | MCH_PCIEXBAR_BUS_FF | MCH_PCIEXBAR_EN
238 );
239 }
240
241 VOID
242 MiscInitialization (
243 VOID
244 )
245 {
246 UINTN PmCmd;
247 UINTN Pmba;
248 UINT32 PmbaAndVal;
249 UINT32 PmbaOrVal;
250 UINTN AcpiCtlReg;
251 UINT8 AcpiEnBit;
252 RETURN_STATUS PcdStatus;
253
254 //
255 // Disable A20 Mask
256 //
257 IoOr8 (0x92, BIT1);
258
259 //
260 // Build the CPU HOB with guest RAM size dependent address width and 16-bits
261 // of IO space. (Side note: unlike other HOBs, the CPU HOB is needed during
262 // S3 resume as well, so we build it unconditionally.)
263 //
264 BuildCpuHob (mPhysMemAddressWidth, 16);
265
266 //
267 // Determine platform type and save Host Bridge DID to PCD
268 //
269 switch (mHostBridgeDevId) {
270 case INTEL_82441_DEVICE_ID:
271 PmCmd = POWER_MGMT_REGISTER_PIIX4 (PCI_COMMAND_OFFSET);
272 Pmba = POWER_MGMT_REGISTER_PIIX4 (PIIX4_PMBA);
273 PmbaAndVal = ~(UINT32)PIIX4_PMBA_MASK;
274 PmbaOrVal = PIIX4_PMBA_VALUE;
275 AcpiCtlReg = POWER_MGMT_REGISTER_PIIX4 (PIIX4_PMREGMISC);
276 AcpiEnBit = PIIX4_PMREGMISC_PMIOSE;
277 break;
278 case INTEL_Q35_MCH_DEVICE_ID:
279 PmCmd = POWER_MGMT_REGISTER_Q35 (PCI_COMMAND_OFFSET);
280 Pmba = POWER_MGMT_REGISTER_Q35 (ICH9_PMBASE);
281 PmbaAndVal = ~(UINT32)ICH9_PMBASE_MASK;
282 PmbaOrVal = ICH9_PMBASE_VALUE;
283 AcpiCtlReg = POWER_MGMT_REGISTER_Q35 (ICH9_ACPI_CNTL);
284 AcpiEnBit = ICH9_ACPI_CNTL_ACPI_EN;
285 break;
286 default:
287 if (XenPvhDetected ()) {
288 //
289 // There is no PCI bus in this case
290 //
291 return;
292 }
293 DEBUG ((DEBUG_ERROR, "%a: Unknown Host Bridge Device ID: 0x%04x\n",
294 __FUNCTION__, mHostBridgeDevId));
295 ASSERT (FALSE);
296 return;
297 }
298 PcdStatus = PcdSet16S (PcdOvmfHostBridgePciDevId, mHostBridgeDevId);
299 ASSERT_RETURN_ERROR (PcdStatus);
300
301 //
302 // If the appropriate IOspace enable bit is set, assume the ACPI PMBA
303 // has been configured (e.g., by Xen) and skip the setup here.
304 // This matches the logic in AcpiTimerLibConstructor ().
305 //
306 if ((PciRead8 (AcpiCtlReg) & AcpiEnBit) == 0) {
307 //
308 // The PEI phase should be exited with fully accessibe ACPI PM IO space:
309 // 1. set PMBA
310 //
311 PciAndThenOr32 (Pmba, PmbaAndVal, PmbaOrVal);
312
313 //
314 // 2. set PCICMD/IOSE
315 //
316 PciOr8 (PmCmd, EFI_PCI_COMMAND_IO_SPACE);
317
318 //
319 // 3. set ACPI PM IO enable bit (PMREGMISC:PMIOSE or ACPI_CNTL:ACPI_EN)
320 //
321 PciOr8 (AcpiCtlReg, AcpiEnBit);
322 }
323
324 if (mHostBridgeDevId == INTEL_Q35_MCH_DEVICE_ID) {
325 //
326 // Set Root Complex Register Block BAR
327 //
328 PciWrite32 (
329 POWER_MGMT_REGISTER_Q35 (ICH9_RCBA),
330 ICH9_ROOT_COMPLEX_BASE | ICH9_RCBA_EN
331 );
332
333 //
334 // Set PCI Express Register Range Base Address
335 //
336 PciExBarInitialization ();
337 }
338 }
339
340
341 VOID
342 BootModeInitialization (
343 VOID
344 )
345 {
346 EFI_STATUS Status;
347
348 if (CmosRead8 (0xF) == 0xFE) {
349 mBootMode = BOOT_ON_S3_RESUME;
350 }
351 CmosWrite8 (0xF, 0x00);
352
353 Status = PeiServicesSetBootMode (mBootMode);
354 ASSERT_EFI_ERROR (Status);
355
356 Status = PeiServicesInstallPpi (mPpiBootMode);
357 ASSERT_EFI_ERROR (Status);
358 }
359
360
361 VOID
362 ReserveEmuVariableNvStore (
363 )
364 {
365 EFI_PHYSICAL_ADDRESS VariableStore;
366 RETURN_STATUS PcdStatus;
367
368 //
369 // Allocate storage for NV variables early on so it will be
370 // at a consistent address. Since VM memory is preserved
371 // across reboots, this allows the NV variable storage to survive
372 // a VM reboot.
373 //
374 VariableStore =
375 (EFI_PHYSICAL_ADDRESS)(UINTN)
376 AllocateRuntimePages (
377 EFI_SIZE_TO_PAGES (2 * PcdGet32 (PcdFlashNvStorageFtwSpareSize))
378 );
379 DEBUG ((DEBUG_INFO,
380 "Reserved variable store memory: 0x%lX; size: %dkb\n",
381 VariableStore,
382 (2 * PcdGet32 (PcdFlashNvStorageFtwSpareSize)) / 1024
383 ));
384 PcdStatus = PcdSet64S (PcdEmuVariableNvStoreReserved, VariableStore);
385 ASSERT_RETURN_ERROR (PcdStatus);
386 }
387
388
389 VOID
390 DebugDumpCmos (
391 VOID
392 )
393 {
394 UINT32 Loop;
395
396 DEBUG ((DEBUG_INFO, "CMOS:\n"));
397
398 for (Loop = 0; Loop < 0x80; Loop++) {
399 if ((Loop % 0x10) == 0) {
400 DEBUG ((DEBUG_INFO, "%02x:", Loop));
401 }
402 DEBUG ((DEBUG_INFO, " %02x", CmosRead8 (Loop)));
403 if ((Loop % 0x10) == 0xf) {
404 DEBUG ((DEBUG_INFO, "\n"));
405 }
406 }
407 }
408
409
410
411 /**
412 Perform Platform PEI initialization.
413
414 @param FileHandle Handle of the file being invoked.
415 @param PeiServices Describes the list of possible PEI Services.
416
417 @return EFI_SUCCESS The PEIM initialized successfully.
418
419 **/
420 EFI_STATUS
421 EFIAPI
422 InitializeXenPlatform (
423 IN EFI_PEI_FILE_HANDLE FileHandle,
424 IN CONST EFI_PEI_SERVICES **PeiServices
425 )
426 {
427 EFI_STATUS Status;
428
429 DEBUG ((DEBUG_INFO, "Platform PEIM Loaded\n"));
430
431 DebugDumpCmos ();
432
433 if (!XenDetect ()) {
434 DEBUG ((DEBUG_ERROR, "ERROR: Xen isn't detected\n"));
435 ASSERT (FALSE);
436 CpuDeadLoop ();
437 }
438
439 //
440 // This S3 conditional test is mainly for HVM Direct Kernel Boot since
441 // QEMU fwcfg isn't really supported other than that.
442 //
443 if (QemuFwCfgS3Enabled ()) {
444 DEBUG ((DEBUG_INFO, "S3 support was detected on QEMU\n"));
445 Status = PcdSetBoolS (PcdAcpiS3Enable, TRUE);
446 ASSERT_EFI_ERROR (Status);
447 }
448
449 XenConnect ();
450
451 BootModeInitialization ();
452 AddressWidthInitialization ();
453
454 //
455 // Query Host Bridge DID
456 //
457 mHostBridgeDevId = PciRead16 (OVMF_HOSTBRIDGE_DID);
458
459 PublishPeiMemory ();
460
461 InitializeRamRegions ();
462
463 CalibrateLapicTimer ();
464
465 if (mBootMode != BOOT_ON_S3_RESUME) {
466 ReserveEmuVariableNvStore ();
467 PeiFvInitialization ();
468 MemMapInitialization ();
469 }
470
471 InstallClearCacheCallback ();
472 AmdSevInitialize ();
473 MiscInitialization ();
474
475 return EFI_SUCCESS;
476 }