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