]> git.proxmox.com Git - mirror_edk2.git/blob - OvmfPkg/Bhyve/PlatformPei/Platform.c
OvmfPkg: Apply uncrustify changes
[mirror_edk2.git] / OvmfPkg / Bhyve / PlatformPei / Platform.c
1 /**@file
2 Platform PEI driver
3
4 Copyright (c) 2020, Rebecca Cran <rebecca@bsdio.com>
5 Copyright (c) 2006 - 2016, Intel Corporation. All rights reserved.<BR>
6 Copyright (c) 2011, Andrei Warkentin <andreiw@motorola.com>
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/LocalApicLib.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/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 BOOLEAN mS3Supported = FALSE;
63
64 UINT32 mMaxCpuCount;
65
66 VOID
67 AddIoMemoryBaseSizeHob (
68 EFI_PHYSICAL_ADDRESS MemoryBase,
69 UINT64 MemorySize
70 )
71 {
72 BuildResourceDescriptorHob (
73 EFI_RESOURCE_MEMORY_MAPPED_IO,
74 EFI_RESOURCE_ATTRIBUTE_PRESENT |
75 EFI_RESOURCE_ATTRIBUTE_INITIALIZED |
76 EFI_RESOURCE_ATTRIBUTE_UNCACHEABLE |
77 EFI_RESOURCE_ATTRIBUTE_TESTED,
78 MemoryBase,
79 MemorySize
80 );
81 }
82
83 VOID
84 AddReservedMemoryBaseSizeHob (
85 EFI_PHYSICAL_ADDRESS MemoryBase,
86 UINT64 MemorySize,
87 BOOLEAN Cacheable
88 )
89 {
90 BuildResourceDescriptorHob (
91 EFI_RESOURCE_MEMORY_RESERVED,
92 EFI_RESOURCE_ATTRIBUTE_PRESENT |
93 EFI_RESOURCE_ATTRIBUTE_INITIALIZED |
94 EFI_RESOURCE_ATTRIBUTE_UNCACHEABLE |
95 (Cacheable ?
96 EFI_RESOURCE_ATTRIBUTE_WRITE_COMBINEABLE |
97 EFI_RESOURCE_ATTRIBUTE_WRITE_THROUGH_CACHEABLE |
98 EFI_RESOURCE_ATTRIBUTE_WRITE_BACK_CACHEABLE :
99 0
100 ) |
101 EFI_RESOURCE_ATTRIBUTE_TESTED,
102 MemoryBase,
103 MemorySize
104 );
105 }
106
107 VOID
108 AddIoMemoryRangeHob (
109 EFI_PHYSICAL_ADDRESS MemoryBase,
110 EFI_PHYSICAL_ADDRESS MemoryLimit
111 )
112 {
113 AddIoMemoryBaseSizeHob (MemoryBase, (UINT64)(MemoryLimit - MemoryBase));
114 }
115
116 VOID
117 AddMemoryBaseSizeHob (
118 EFI_PHYSICAL_ADDRESS MemoryBase,
119 UINT64 MemorySize
120 )
121 {
122 BuildResourceDescriptorHob (
123 EFI_RESOURCE_SYSTEM_MEMORY,
124 EFI_RESOURCE_ATTRIBUTE_PRESENT |
125 EFI_RESOURCE_ATTRIBUTE_INITIALIZED |
126 EFI_RESOURCE_ATTRIBUTE_UNCACHEABLE |
127 EFI_RESOURCE_ATTRIBUTE_WRITE_COMBINEABLE |
128 EFI_RESOURCE_ATTRIBUTE_WRITE_THROUGH_CACHEABLE |
129 EFI_RESOURCE_ATTRIBUTE_WRITE_BACK_CACHEABLE |
130 EFI_RESOURCE_ATTRIBUTE_TESTED,
131 MemoryBase,
132 MemorySize
133 );
134 }
135
136 VOID
137 AddMemoryRangeHob (
138 EFI_PHYSICAL_ADDRESS MemoryBase,
139 EFI_PHYSICAL_ADDRESS MemoryLimit
140 )
141 {
142 AddMemoryBaseSizeHob (MemoryBase, (UINT64)(MemoryLimit - MemoryBase));
143 }
144
145 VOID
146 MemMapInitialization (
147 VOID
148 )
149 {
150 UINT64 PciIoBase;
151 UINT64 PciIoSize;
152 RETURN_STATUS PcdStatus;
153
154 PciIoBase = 0xC000;
155 PciIoSize = 0x4000;
156
157 //
158 // Create Memory Type Information HOB
159 //
160 BuildGuidDataHob (
161 &gEfiMemoryTypeInformationGuid,
162 mDefaultMemoryTypeInformation,
163 sizeof (mDefaultMemoryTypeInformation)
164 );
165
166 //
167 // Video memory + Legacy BIOS region
168 //
169 AddIoMemoryRangeHob (0x0A0000, BASE_1MB);
170
171 if (TRUE) {
172 UINT32 TopOfLowRam;
173 UINT64 PciExBarBase;
174 UINT32 PciBase;
175 UINT32 PciSize;
176
177 TopOfLowRam = GetSystemMemorySizeBelow4gb ();
178 PciExBarBase = 0;
179 if (mHostBridgeDevId == INTEL_Q35_MCH_DEVICE_ID) {
180 //
181 // The MMCONFIG area is expected to fall between the top of low RAM and
182 // the base of the 32-bit PCI host aperture.
183 //
184 PciExBarBase = FixedPcdGet64 (PcdPciExpressBaseAddress);
185 ASSERT (TopOfLowRam <= PciExBarBase);
186 ASSERT (PciExBarBase <= MAX_UINT32 - SIZE_256MB);
187 PciBase = (UINT32)(PciExBarBase + SIZE_256MB);
188 } else {
189 PciBase = (UINT32)PcdGet64 (PcdPciMmio32Base);
190 if (PciBase == 0) {
191 PciBase = (TopOfLowRam < BASE_2GB) ? BASE_2GB : TopOfLowRam;
192 }
193 }
194
195 //
196 // address purpose size
197 // ------------ -------- -------------------------
198 // max(top, 2g) PCI MMIO 0xFC000000 - max(top, 2g)
199 // 0xFC000000 gap 44 MB
200 // 0xFEC00000 IO-APIC 4 KB
201 // 0xFEC01000 gap 1020 KB
202 // 0xFED00000 HPET 1 KB
203 // 0xFED00400 gap 111 KB
204 // 0xFED1C000 gap (PIIX4) / RCRB (ICH9) 16 KB
205 // 0xFED20000 gap 896 KB
206 // 0xFEE00000 LAPIC 1 MB
207 //
208 PciSize = 0xFC000000 - PciBase;
209 AddIoMemoryBaseSizeHob (PciBase, PciSize);
210 PcdStatus = PcdSet64S (PcdPciMmio32Base, PciBase);
211 ASSERT_RETURN_ERROR (PcdStatus);
212 PcdStatus = PcdSet64S (PcdPciMmio32Size, PciSize);
213 ASSERT_RETURN_ERROR (PcdStatus);
214
215 AddIoMemoryBaseSizeHob (0xFEC00000, SIZE_4KB);
216 AddIoMemoryBaseSizeHob (0xFED00000, SIZE_1KB);
217 if (mHostBridgeDevId == INTEL_Q35_MCH_DEVICE_ID) {
218 AddIoMemoryBaseSizeHob (ICH9_ROOT_COMPLEX_BASE, SIZE_16KB);
219 //
220 // Note: there should be an
221 //
222 // AddIoMemoryBaseSizeHob (PciExBarBase, SIZE_256MB);
223 //
224 // call below, just like the one above for RCBA. However, Linux insists
225 // that the MMCONFIG area be marked in the E820 or UEFI memory map as
226 // "reserved memory" -- Linux does not content itself with a simple gap
227 // in the memory map wherever the MCFG ACPI table points to.
228 //
229 // This appears to be a safety measure. The PCI Firmware Specification
230 // (rev 3.1) says in 4.1.2. "MCFG Table Description": "The resources can
231 // *optionally* be returned in [...] EFIGetMemoryMap as reserved memory
232 // [...]". (Emphasis added here.)
233 //
234 // Normally we add memory resource descriptor HOBs in
235 // QemuInitializeRam(), and pre-allocate from those with memory
236 // allocation HOBs in InitializeRamRegions(). However, the MMCONFIG area
237 // is most definitely not RAM; so, as an exception, cover it with
238 // uncacheable reserved memory right here.
239 //
240 AddReservedMemoryBaseSizeHob (PciExBarBase, SIZE_256MB, FALSE);
241 BuildMemoryAllocationHob (
242 PciExBarBase,
243 SIZE_256MB,
244 EfiReservedMemoryType
245 );
246 }
247
248 AddIoMemoryBaseSizeHob (PcdGet32 (PcdCpuLocalApicBaseAddress), SIZE_1MB);
249
250 //
251 // On Q35, the IO Port space is available for PCI resource allocations from
252 // 0x6000 up.
253 //
254 if (mHostBridgeDevId == INTEL_Q35_MCH_DEVICE_ID) {
255 PciIoBase = 0x6000;
256 PciIoSize = 0xA000;
257 ASSERT ((ICH9_PMBASE_VALUE & 0xF000) < PciIoBase);
258 }
259 }
260
261 //
262 // Add PCI IO Port space available for PCI resource allocations.
263 //
264 BuildResourceDescriptorHob (
265 EFI_RESOURCE_IO,
266 EFI_RESOURCE_ATTRIBUTE_PRESENT |
267 EFI_RESOURCE_ATTRIBUTE_INITIALIZED,
268 PciIoBase,
269 PciIoSize
270 );
271 PcdStatus = PcdSet64S (PcdPciIoBase, PciIoBase);
272 ASSERT_RETURN_ERROR (PcdStatus);
273 PcdStatus = PcdSet64S (PcdPciIoSize, PciIoSize);
274 ASSERT_RETURN_ERROR (PcdStatus);
275 }
276
277 VOID
278 NoexecDxeInitialization (
279 VOID
280 )
281 {
282 }
283
284 VOID
285 PciExBarInitialization (
286 VOID
287 )
288 {
289 union {
290 UINT64 Uint64;
291 UINT32 Uint32[2];
292 } PciExBarBase;
293
294 //
295 // We only support the 256MB size for the MMCONFIG area:
296 // 256 buses * 32 devices * 8 functions * 4096 bytes config space.
297 //
298 // The masks used below enforce the Q35 requirements that the MMCONFIG area
299 // be (a) correctly aligned -- here at 256 MB --, (b) located under 64 GB.
300 //
301 // Note that (b) also ensures that the minimum address width we have
302 // determined in AddressWidthInitialization(), i.e., 36 bits, will suffice
303 // for DXE's page tables to cover the MMCONFIG area.
304 //
305 PciExBarBase.Uint64 = FixedPcdGet64 (PcdPciExpressBaseAddress);
306 ASSERT ((PciExBarBase.Uint32[1] & MCH_PCIEXBAR_HIGHMASK) == 0);
307 ASSERT ((PciExBarBase.Uint32[0] & MCH_PCIEXBAR_LOWMASK) == 0);
308
309 //
310 // Clear the PCIEXBAREN bit first, before programming the high register.
311 //
312 PciWrite32 (DRAMC_REGISTER_Q35 (MCH_PCIEXBAR_LOW), 0);
313
314 //
315 // Program the high register. Then program the low register, setting the
316 // MMCONFIG area size and enabling decoding at once.
317 //
318 PciWrite32 (DRAMC_REGISTER_Q35 (MCH_PCIEXBAR_HIGH), PciExBarBase.Uint32[1]);
319 PciWrite32 (
320 DRAMC_REGISTER_Q35 (MCH_PCIEXBAR_LOW),
321 PciExBarBase.Uint32[0] | MCH_PCIEXBAR_BUS_FF | MCH_PCIEXBAR_EN
322 );
323 }
324
325 VOID
326 MiscInitialization (
327 VOID
328 )
329 {
330 UINTN PmCmd;
331 UINTN Pmba;
332 UINT32 PmbaAndVal;
333 UINT32 PmbaOrVal;
334 UINTN AcpiCtlReg;
335 UINT8 AcpiEnBit;
336 RETURN_STATUS PcdStatus;
337
338 //
339 // Disable A20 Mask
340 //
341 IoOr8 (0x92, BIT1);
342
343 //
344 // Build the CPU HOB with guest RAM size dependent address width and 16-bits
345 // of IO space. (Side note: unlike other HOBs, the CPU HOB is needed during
346 // S3 resume as well, so we build it unconditionally.)
347 //
348 BuildCpuHob (mPhysMemAddressWidth, 16);
349
350 //
351 // Determine platform type and save Host Bridge DID to PCD
352 //
353 switch (mHostBridgeDevId) {
354 case 0x7432: // BHYVE (AMD hostbridge)
355 case 0x1275: // BHYVE (Intel hostbridge)
356 case INTEL_82441_DEVICE_ID:
357 PmCmd = POWER_MGMT_REGISTER_PIIX4 (PCI_COMMAND_OFFSET);
358 Pmba = POWER_MGMT_REGISTER_PIIX4 (PIIX4_PMBA);
359 PmbaAndVal = ~(UINT32)PIIX4_PMBA_MASK;
360 PmbaOrVal = PIIX4_PMBA_VALUE;
361 AcpiCtlReg = POWER_MGMT_REGISTER_PIIX4 (PIIX4_PMREGMISC);
362 AcpiEnBit = PIIX4_PMREGMISC_PMIOSE;
363 break;
364 case INTEL_Q35_MCH_DEVICE_ID:
365 PmCmd = POWER_MGMT_REGISTER_Q35 (PCI_COMMAND_OFFSET);
366 Pmba = POWER_MGMT_REGISTER_Q35 (ICH9_PMBASE);
367 PmbaAndVal = ~(UINT32)ICH9_PMBASE_MASK;
368 PmbaOrVal = ICH9_PMBASE_VALUE;
369 AcpiCtlReg = POWER_MGMT_REGISTER_Q35 (ICH9_ACPI_CNTL);
370 AcpiEnBit = ICH9_ACPI_CNTL_ACPI_EN;
371 break;
372 default:
373 DEBUG ((
374 DEBUG_ERROR,
375 "%a: Unknown Host Bridge Device ID: 0x%04x\n",
376 __FUNCTION__,
377 mHostBridgeDevId
378 ));
379 ASSERT (FALSE);
380 return;
381 }
382
383 PcdStatus = PcdSet16S (PcdOvmfHostBridgePciDevId, mHostBridgeDevId);
384 ASSERT_RETURN_ERROR (PcdStatus);
385
386 //
387 // If the appropriate IOspace enable bit is set, assume the ACPI PMBA
388 // has been configured (e.g., by Xen) and skip the setup here.
389 // This matches the logic in AcpiTimerLibConstructor ().
390 //
391 if ((PciRead8 (AcpiCtlReg) & AcpiEnBit) == 0) {
392 //
393 // The PEI phase should be exited with fully accessibe ACPI PM IO space:
394 // 1. set PMBA
395 //
396 PciAndThenOr32 (Pmba, PmbaAndVal, PmbaOrVal);
397
398 //
399 // 2. set PCICMD/IOSE
400 //
401 PciOr8 (PmCmd, EFI_PCI_COMMAND_IO_SPACE);
402
403 //
404 // 3. set ACPI PM IO enable bit (PMREGMISC:PMIOSE or ACPI_CNTL:ACPI_EN)
405 //
406 PciOr8 (AcpiCtlReg, AcpiEnBit);
407 }
408
409 if (mHostBridgeDevId == INTEL_Q35_MCH_DEVICE_ID) {
410 //
411 // Set Root Complex Register Block BAR
412 //
413 PciWrite32 (
414 POWER_MGMT_REGISTER_Q35 (ICH9_RCBA),
415 ICH9_ROOT_COMPLEX_BASE | ICH9_RCBA_EN
416 );
417
418 //
419 // Set PCI Express Register Range Base Address
420 //
421 PciExBarInitialization ();
422 }
423 }
424
425 VOID
426 BootModeInitialization (
427 VOID
428 )
429 {
430 EFI_STATUS Status;
431
432 if (CmosRead8 (0xF) == 0xFE) {
433 mBootMode = BOOT_ON_S3_RESUME;
434 }
435
436 CmosWrite8 (0xF, 0x00);
437
438 Status = PeiServicesSetBootMode (mBootMode);
439 ASSERT_EFI_ERROR (Status);
440
441 Status = PeiServicesInstallPpi (mPpiBootMode);
442 ASSERT_EFI_ERROR (Status);
443 }
444
445 VOID
446 ReserveEmuVariableNvStore (
447 )
448 {
449 EFI_PHYSICAL_ADDRESS VariableStore;
450 RETURN_STATUS PcdStatus;
451
452 //
453 // Allocate storage for NV variables early on so it will be
454 // at a consistent address. Since VM memory is preserved
455 // across reboots, this allows the NV variable storage to survive
456 // a VM reboot.
457 //
458 VariableStore =
459 (EFI_PHYSICAL_ADDRESS)(UINTN)
460 AllocateRuntimePages (
461 EFI_SIZE_TO_PAGES (2 * PcdGet32 (PcdFlashNvStorageFtwSpareSize))
462 );
463 DEBUG ((
464 DEBUG_INFO,
465 "Reserved variable store memory: 0x%lX; size: %dkb\n",
466 VariableStore,
467 (2 * PcdGet32 (PcdFlashNvStorageFtwSpareSize)) / 1024
468 ));
469 PcdStatus = PcdSet64S (PcdEmuVariableNvStoreReserved, VariableStore);
470 ASSERT_RETURN_ERROR (PcdStatus);
471 }
472
473 VOID
474 DebugDumpCmos (
475 VOID
476 )
477 {
478 UINT32 Loop;
479
480 DEBUG ((DEBUG_INFO, "CMOS:\n"));
481
482 for (Loop = 0; Loop < 0x80; Loop++) {
483 if ((Loop % 0x10) == 0) {
484 DEBUG ((DEBUG_INFO, "%02x:", Loop));
485 }
486
487 DEBUG ((DEBUG_INFO, " %02x", CmosRead8 (Loop)));
488 if ((Loop % 0x10) == 0xf) {
489 DEBUG ((DEBUG_INFO, "\n"));
490 }
491 }
492 }
493
494 VOID
495 S3Verification (
496 VOID
497 )
498 {
499 #if defined (MDE_CPU_X64)
500 if (FeaturePcdGet (PcdSmmSmramRequire) && mS3Supported) {
501 DEBUG ((
502 DEBUG_ERROR,
503 "%a: S3Resume2Pei doesn't support X64 PEI + SMM yet.\n",
504 __FUNCTION__
505 ));
506 DEBUG ((
507 DEBUG_ERROR,
508 "%a: Please disable S3 on the QEMU command line (see the README),\n",
509 __FUNCTION__
510 ));
511 DEBUG ((
512 DEBUG_ERROR,
513 "%a: or build OVMF with \"OvmfPkgIa32X64.dsc\".\n",
514 __FUNCTION__
515 ));
516 ASSERT (FALSE);
517 CpuDeadLoop ();
518 }
519
520 #endif
521 }
522
523 /**
524 Fetch the number of boot CPUs from QEMU and expose it to UefiCpuPkg modules.
525 Set the mMaxCpuCount variable.
526 **/
527 VOID
528 MaxCpuCountInitialization (
529 VOID
530 )
531 {
532 UINT16 ProcessorCount = 0;
533 RETURN_STATUS PcdStatus;
534
535 //
536 // If the fw_cfg key or fw_cfg entirely is unavailable, load mMaxCpuCount
537 // from the PCD default. No change to PCDs.
538 //
539 if (ProcessorCount == 0) {
540 mMaxCpuCount = PcdGet32 (PcdCpuMaxLogicalProcessorNumber);
541 return;
542 }
543
544 //
545 // Otherwise, set mMaxCpuCount to the value reported by QEMU.
546 //
547 mMaxCpuCount = ProcessorCount;
548 //
549 // Additionally, tell UefiCpuPkg modules (a) the exact number of VCPUs, (b)
550 // to wait, in the initial AP bringup, exactly as long as it takes for all of
551 // the APs to report in. For this, we set the longest representable timeout
552 // (approx. 71 minutes).
553 //
554 PcdStatus = PcdSet32S (PcdCpuMaxLogicalProcessorNumber, ProcessorCount);
555 ASSERT_RETURN_ERROR (PcdStatus);
556 PcdStatus = PcdSet32S (PcdCpuApInitTimeOutInMicroSeconds, MAX_UINT32);
557 ASSERT_RETURN_ERROR (PcdStatus);
558 DEBUG ((
559 DEBUG_INFO,
560 "%a: QEMU reports %d processor(s)\n",
561 __FUNCTION__,
562 ProcessorCount
563 ));
564 }
565
566 /**
567 Perform Platform PEI initialization.
568
569 @param FileHandle Handle of the file being invoked.
570 @param PeiServices Describes the list of possible PEI Services.
571
572 @return EFI_SUCCESS The PEIM initialized successfully.
573
574 **/
575 EFI_STATUS
576 EFIAPI
577 InitializePlatform (
578 IN EFI_PEI_FILE_HANDLE FileHandle,
579 IN CONST EFI_PEI_SERVICES **PeiServices
580 )
581 {
582 DEBUG ((DEBUG_INFO, "Platform PEIM Loaded\n"));
583
584 //
585 // Initialize Local APIC Timer hardware and disable Local APIC Timer
586 // interrupts before initializing the Debug Agent and the debug timer is
587 // enabled.
588 //
589 InitializeApicTimer (0, MAX_UINT32, TRUE, 5);
590 DisableApicTimerInterrupt ();
591
592 DebugDumpCmos ();
593
594 BootModeInitialization ();
595 AddressWidthInitialization ();
596 MaxCpuCountInitialization ();
597
598 //
599 // Query Host Bridge DID
600 //
601 mHostBridgeDevId = PciRead16 (OVMF_HOSTBRIDGE_DID);
602
603 if (FeaturePcdGet (PcdSmmSmramRequire)) {
604 Q35TsegMbytesInitialization ();
605 }
606
607 PublishPeiMemory ();
608
609 InitializeRamRegions ();
610
611 if (mBootMode != BOOT_ON_S3_RESUME) {
612 if (!FeaturePcdGet (PcdSmmSmramRequire)) {
613 ReserveEmuVariableNvStore ();
614 }
615
616 PeiFvInitialization ();
617 MemMapInitialization ();
618 NoexecDxeInitialization ();
619 }
620
621 InstallClearCacheCallback ();
622 AmdSevInitialize ();
623 MiscInitialization ();
624 InstallFeatureControlCallback ();
625
626 return EFI_SUCCESS;
627 }