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