1 /**@file
2   Platform PEI driver
3 
4   Copyright (c) 2006 - 2014, Intel Corporation. All rights reserved.<BR>
5   Copyright (c) 2011, Andrei Warkentin <andreiw@motorola.com>
6 
7   This program and the accompanying materials
8   are licensed and made available under the terms and conditions of the BSD License
9   which accompanies this distribution.  The full text of the license may be found at
10   http://opensource.org/licenses/bsd-license.php
11 
12   THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
13   WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
14 
15 **/
16 
17 //
18 // The package level header files this module uses
19 //
20 #include <PiPei.h>
21 
22 //
23 // The Library classes this module consumes
24 //
25 #include <Library/BaseLib.h>
26 #include <Library/DebugLib.h>
27 #include <Library/HobLib.h>
28 #include <Library/IoLib.h>
29 #include <Library/MemoryAllocationLib.h>
30 #include <Library/PcdLib.h>
31 #include <Library/PciLib.h>
32 #include <Library/PeimEntryPoint.h>
33 #include <Library/PeiServicesLib.h>
34 #include <Library/QemuFwCfgLib.h>
35 #include <Library/ResourcePublicationLib.h>
36 #include <Guid/MemoryTypeInformation.h>
37 #include <Ppi/MasterBootMode.h>
38 #include <IndustryStandard/Pci22.h>
39 #include <OvmfPlatforms.h>
40 
41 #include "Platform.h"
42 #include "Cmos.h"
43 
44 EFI_MEMORY_TYPE_INFORMATION mDefaultMemoryTypeInformation[] = {
45   { EfiACPIMemoryNVS,       0x004 },
46   { EfiACPIReclaimMemory,   0x008 },
47   { EfiReservedMemoryType,  0x004 },
48   { EfiRuntimeServicesData, 0x024 },
49   { EfiRuntimeServicesCode, 0x030 },
50   { EfiBootServicesCode,    0x180 },
51   { EfiBootServicesData,    0xF00 },
52   { EfiMaxMemoryType,       0x000 }
53 };
54 
55 
56 EFI_PEI_PPI_DESCRIPTOR   mPpiBootMode[] = {
57   {
58     EFI_PEI_PPI_DESCRIPTOR_PPI | EFI_PEI_PPI_DESCRIPTOR_TERMINATE_LIST,
59     &gEfiPeiMasterBootModePpiGuid,
60     NULL
61   }
62 };
63 
64 
65 UINT16 mHostBridgeDevId;
66 
67 EFI_BOOT_MODE mBootMode = BOOT_WITH_FULL_CONFIGURATION;
68 
69 BOOLEAN mS3Supported = FALSE;
70 
71 
72 VOID
AddIoMemoryBaseSizeHob(EFI_PHYSICAL_ADDRESS MemoryBase,UINT64 MemorySize)73 AddIoMemoryBaseSizeHob (
74   EFI_PHYSICAL_ADDRESS        MemoryBase,
75   UINT64                      MemorySize
76   )
77 {
78   BuildResourceDescriptorHob (
79     EFI_RESOURCE_MEMORY_MAPPED_IO,
80       EFI_RESOURCE_ATTRIBUTE_PRESENT     |
81       EFI_RESOURCE_ATTRIBUTE_INITIALIZED |
82       EFI_RESOURCE_ATTRIBUTE_UNCACHEABLE |
83       EFI_RESOURCE_ATTRIBUTE_TESTED,
84     MemoryBase,
85     MemorySize
86     );
87 }
88 
89 VOID
AddReservedMemoryBaseSizeHob(EFI_PHYSICAL_ADDRESS MemoryBase,UINT64 MemorySize,BOOLEAN Cacheable)90 AddReservedMemoryBaseSizeHob (
91   EFI_PHYSICAL_ADDRESS        MemoryBase,
92   UINT64                      MemorySize,
93   BOOLEAN                     Cacheable
94   )
95 {
96   BuildResourceDescriptorHob (
97     EFI_RESOURCE_MEMORY_RESERVED,
98       EFI_RESOURCE_ATTRIBUTE_PRESENT     |
99       EFI_RESOURCE_ATTRIBUTE_INITIALIZED |
100       EFI_RESOURCE_ATTRIBUTE_UNCACHEABLE |
101       (Cacheable ?
102        EFI_RESOURCE_ATTRIBUTE_WRITE_COMBINEABLE |
103        EFI_RESOURCE_ATTRIBUTE_WRITE_THROUGH_CACHEABLE |
104        EFI_RESOURCE_ATTRIBUTE_WRITE_BACK_CACHEABLE :
105        0
106        ) |
107       EFI_RESOURCE_ATTRIBUTE_TESTED,
108     MemoryBase,
109     MemorySize
110     );
111 }
112 
113 VOID
AddIoMemoryRangeHob(EFI_PHYSICAL_ADDRESS MemoryBase,EFI_PHYSICAL_ADDRESS MemoryLimit)114 AddIoMemoryRangeHob (
115   EFI_PHYSICAL_ADDRESS        MemoryBase,
116   EFI_PHYSICAL_ADDRESS        MemoryLimit
117   )
118 {
119   AddIoMemoryBaseSizeHob (MemoryBase, (UINT64)(MemoryLimit - MemoryBase));
120 }
121 
122 
123 VOID
AddMemoryBaseSizeHob(EFI_PHYSICAL_ADDRESS MemoryBase,UINT64 MemorySize)124 AddMemoryBaseSizeHob (
125   EFI_PHYSICAL_ADDRESS        MemoryBase,
126   UINT64                      MemorySize
127   )
128 {
129   BuildResourceDescriptorHob (
130     EFI_RESOURCE_SYSTEM_MEMORY,
131       EFI_RESOURCE_ATTRIBUTE_PRESENT |
132       EFI_RESOURCE_ATTRIBUTE_INITIALIZED |
133       EFI_RESOURCE_ATTRIBUTE_UNCACHEABLE |
134       EFI_RESOURCE_ATTRIBUTE_WRITE_COMBINEABLE |
135       EFI_RESOURCE_ATTRIBUTE_WRITE_THROUGH_CACHEABLE |
136       EFI_RESOURCE_ATTRIBUTE_WRITE_BACK_CACHEABLE |
137       EFI_RESOURCE_ATTRIBUTE_TESTED,
138     MemoryBase,
139     MemorySize
140     );
141 }
142 
143 
144 VOID
AddMemoryRangeHob(EFI_PHYSICAL_ADDRESS MemoryBase,EFI_PHYSICAL_ADDRESS MemoryLimit)145 AddMemoryRangeHob (
146   EFI_PHYSICAL_ADDRESS        MemoryBase,
147   EFI_PHYSICAL_ADDRESS        MemoryLimit
148   )
149 {
150   AddMemoryBaseSizeHob (MemoryBase, (UINT64)(MemoryLimit - MemoryBase));
151 }
152 
153 
154 VOID
AddUntestedMemoryBaseSizeHob(EFI_PHYSICAL_ADDRESS MemoryBase,UINT64 MemorySize)155 AddUntestedMemoryBaseSizeHob (
156   EFI_PHYSICAL_ADDRESS        MemoryBase,
157   UINT64                      MemorySize
158   )
159 {
160   BuildResourceDescriptorHob (
161     EFI_RESOURCE_SYSTEM_MEMORY,
162       EFI_RESOURCE_ATTRIBUTE_PRESENT |
163       EFI_RESOURCE_ATTRIBUTE_INITIALIZED |
164       EFI_RESOURCE_ATTRIBUTE_UNCACHEABLE |
165       EFI_RESOURCE_ATTRIBUTE_WRITE_COMBINEABLE |
166       EFI_RESOURCE_ATTRIBUTE_WRITE_THROUGH_CACHEABLE |
167       EFI_RESOURCE_ATTRIBUTE_WRITE_BACK_CACHEABLE,
168     MemoryBase,
169     MemorySize
170     );
171 }
172 
173 
174 VOID
AddUntestedMemoryRangeHob(EFI_PHYSICAL_ADDRESS MemoryBase,EFI_PHYSICAL_ADDRESS MemoryLimit)175 AddUntestedMemoryRangeHob (
176   EFI_PHYSICAL_ADDRESS        MemoryBase,
177   EFI_PHYSICAL_ADDRESS        MemoryLimit
178   )
179 {
180   AddUntestedMemoryBaseSizeHob (MemoryBase, (UINT64)(MemoryLimit - MemoryBase));
181 }
182 
183 VOID
MemMapInitialization(VOID)184 MemMapInitialization (
185   VOID
186   )
187 {
188   //
189   // Create Memory Type Information HOB
190   //
191   BuildGuidDataHob (
192     &gEfiMemoryTypeInformationGuid,
193     mDefaultMemoryTypeInformation,
194     sizeof(mDefaultMemoryTypeInformation)
195     );
196 
197   //
198   // Add PCI IO Port space available for PCI resource allocations.
199   //
200   BuildResourceDescriptorHob (
201     EFI_RESOURCE_IO,
202     EFI_RESOURCE_ATTRIBUTE_PRESENT     |
203     EFI_RESOURCE_ATTRIBUTE_INITIALIZED,
204     0xC000,
205     0x4000
206     );
207 
208   //
209   // Video memory + Legacy BIOS region
210   //
211   AddIoMemoryRangeHob (0x0A0000, BASE_1MB);
212 
213   if (!mXen) {
214     UINT32  TopOfLowRam;
215     UINT32  PciBase;
216 
217     TopOfLowRam = GetSystemMemorySizeBelow4gb ();
218     if (mHostBridgeDevId == INTEL_Q35_MCH_DEVICE_ID) {
219       //
220       // A 3GB base will always fall into Q35's 32-bit PCI host aperture,
221       // regardless of the Q35 MMCONFIG BAR. Correspondingly, QEMU never lets
222       // the RAM below 4 GB exceed it.
223       //
224       PciBase = BASE_2GB + BASE_1GB;
225       ASSERT (TopOfLowRam <= PciBase);
226     } else {
227       PciBase = (TopOfLowRam < BASE_2GB) ? BASE_2GB : TopOfLowRam;
228     }
229 
230     //
231     // address       purpose   size
232     // ------------  --------  -------------------------
233     // max(top, 2g)  PCI MMIO  0xFC000000 - max(top, 2g)
234     // 0xFC000000    gap                           44 MB
235     // 0xFEC00000    IO-APIC                        4 KB
236     // 0xFEC01000    gap                         1020 KB
237     // 0xFED00000    HPET                           1 KB
238     // 0xFED00400    gap                          111 KB
239     // 0xFED1C000    gap (PIIX4) / RCRB (ICH9)     16 KB
240     // 0xFED20000    gap                          896 KB
241     // 0xFEE00000    LAPIC                          1 MB
242     //
243     AddIoMemoryRangeHob (PciBase, 0xFC000000);
244     AddIoMemoryBaseSizeHob (0xFEC00000, SIZE_4KB);
245     AddIoMemoryBaseSizeHob (0xFED00000, SIZE_1KB);
246     if (mHostBridgeDevId == INTEL_Q35_MCH_DEVICE_ID) {
247       AddIoMemoryBaseSizeHob (ICH9_ROOT_COMPLEX_BASE, SIZE_16KB);
248     }
249     AddIoMemoryBaseSizeHob (PcdGet32(PcdCpuLocalApicBaseAddress), SIZE_1MB);
250   }
251 }
252 
253 EFI_STATUS
GetNamedFwCfgBoolean(IN CHAR8 * FwCfgFileName,OUT BOOLEAN * Setting)254 GetNamedFwCfgBoolean (
255   IN  CHAR8   *FwCfgFileName,
256   OUT BOOLEAN *Setting
257   )
258 {
259   EFI_STATUS           Status;
260   FIRMWARE_CONFIG_ITEM FwCfgItem;
261   UINTN                FwCfgSize;
262   UINT8                Value[3];
263 
264   Status = QemuFwCfgFindFile (FwCfgFileName, &FwCfgItem, &FwCfgSize);
265   if (EFI_ERROR (Status)) {
266     return Status;
267   }
268   if (FwCfgSize > sizeof Value) {
269     return EFI_BAD_BUFFER_SIZE;
270   }
271   QemuFwCfgSelectItem (FwCfgItem);
272   QemuFwCfgReadBytes (FwCfgSize, Value);
273 
274   if ((FwCfgSize == 1) ||
275       (FwCfgSize == 2 && Value[1] == '\n') ||
276       (FwCfgSize == 3 && Value[1] == '\r' && Value[2] == '\n')) {
277     switch (Value[0]) {
278       case '0':
279       case 'n':
280       case 'N':
281         *Setting = FALSE;
282         return EFI_SUCCESS;
283 
284       case '1':
285       case 'y':
286       case 'Y':
287         *Setting = TRUE;
288         return EFI_SUCCESS;
289 
290       default:
291         break;
292     }
293   }
294   return EFI_PROTOCOL_ERROR;
295 }
296 
297 #define UPDATE_BOOLEAN_PCD_FROM_FW_CFG(TokenName)                   \
298           do {                                                      \
299             BOOLEAN Setting;                                        \
300                                                                     \
301             if (!EFI_ERROR (GetNamedFwCfgBoolean (                  \
302                               "opt/ovmf/" #TokenName, &Setting))) { \
303               PcdSetBool (TokenName, Setting);                      \
304             }                                                       \
305           } while (0)
306 
307 VOID
NoexecDxeInitialization(VOID)308 NoexecDxeInitialization (
309   VOID
310   )
311 {
312   UPDATE_BOOLEAN_PCD_FROM_FW_CFG (PcdPropertiesTableEnable);
313   UPDATE_BOOLEAN_PCD_FROM_FW_CFG (PcdSetNxForStack);
314 }
315 
316 VOID
MiscInitialization(VOID)317 MiscInitialization (
318   VOID
319   )
320 {
321   UINTN  PmCmd;
322   UINTN  Pmba;
323   UINTN  AcpiCtlReg;
324   UINT8  AcpiEnBit;
325 
326   //
327   // Disable A20 Mask
328   //
329   IoOr8 (0x92, BIT1);
330 
331   //
332   // Build the CPU HOB with guest RAM size dependent address width and 16-bits
333   // of IO space. (Side note: unlike other HOBs, the CPU HOB is needed during
334   // S3 resume as well, so we build it unconditionally.)
335   //
336   BuildCpuHob (mPhysMemAddressWidth, 16);
337 
338   //
339   // Determine platform type and save Host Bridge DID to PCD
340   //
341   switch (mHostBridgeDevId) {
342     case INTEL_82441_DEVICE_ID:
343       PmCmd      = POWER_MGMT_REGISTER_PIIX4 (PCI_COMMAND_OFFSET);
344       Pmba       = POWER_MGMT_REGISTER_PIIX4 (PIIX4_PMBA);
345       AcpiCtlReg = POWER_MGMT_REGISTER_PIIX4 (PIIX4_PMREGMISC);
346       AcpiEnBit  = PIIX4_PMREGMISC_PMIOSE;
347       break;
348     case INTEL_Q35_MCH_DEVICE_ID:
349       PmCmd      = POWER_MGMT_REGISTER_Q35 (PCI_COMMAND_OFFSET);
350       Pmba       = POWER_MGMT_REGISTER_Q35 (ICH9_PMBASE);
351       AcpiCtlReg = POWER_MGMT_REGISTER_Q35 (ICH9_ACPI_CNTL);
352       AcpiEnBit  = ICH9_ACPI_CNTL_ACPI_EN;
353       break;
354     default:
355       DEBUG ((EFI_D_ERROR, "%a: Unknown Host Bridge Device ID: 0x%04x\n",
356         __FUNCTION__, mHostBridgeDevId));
357       ASSERT (FALSE);
358       return;
359   }
360   PcdSet16 (PcdOvmfHostBridgePciDevId, mHostBridgeDevId);
361 
362   //
363   // If the appropriate IOspace enable bit is set, assume the ACPI PMBA
364   // has been configured (e.g., by Xen) and skip the setup here.
365   // This matches the logic in AcpiTimerLibConstructor ().
366   //
367   if ((PciRead8 (AcpiCtlReg) & AcpiEnBit) == 0) {
368     //
369     // The PEI phase should be exited with fully accessibe ACPI PM IO space:
370     // 1. set PMBA
371     //
372     PciAndThenOr32 (Pmba, (UINT32) ~0xFFC0, PcdGet16 (PcdAcpiPmBaseAddress));
373 
374     //
375     // 2. set PCICMD/IOSE
376     //
377     PciOr8 (PmCmd, EFI_PCI_COMMAND_IO_SPACE);
378 
379     //
380     // 3. set ACPI PM IO enable bit (PMREGMISC:PMIOSE or ACPI_CNTL:ACPI_EN)
381     //
382     PciOr8 (AcpiCtlReg, AcpiEnBit);
383   }
384 
385   if (mHostBridgeDevId == INTEL_Q35_MCH_DEVICE_ID) {
386     //
387     // Set Root Complex Register Block BAR
388     //
389     PciWrite32 (
390       POWER_MGMT_REGISTER_Q35 (ICH9_RCBA),
391       ICH9_ROOT_COMPLEX_BASE | ICH9_RCBA_EN
392       );
393   }
394 }
395 
396 
397 VOID
BootModeInitialization(VOID)398 BootModeInitialization (
399   VOID
400   )
401 {
402   EFI_STATUS    Status;
403 
404   if (CmosRead8 (0xF) == 0xFE) {
405     mBootMode = BOOT_ON_S3_RESUME;
406   }
407   CmosWrite8 (0xF, 0x00);
408 
409   Status = PeiServicesSetBootMode (mBootMode);
410   ASSERT_EFI_ERROR (Status);
411 
412   Status = PeiServicesInstallPpi (mPpiBootMode);
413   ASSERT_EFI_ERROR (Status);
414 }
415 
416 
417 VOID
ReserveEmuVariableNvStore()418 ReserveEmuVariableNvStore (
419   )
420 {
421   EFI_PHYSICAL_ADDRESS VariableStore;
422 
423   //
424   // Allocate storage for NV variables early on so it will be
425   // at a consistent address.  Since VM memory is preserved
426   // across reboots, this allows the NV variable storage to survive
427   // a VM reboot.
428   //
429   VariableStore =
430     (EFI_PHYSICAL_ADDRESS)(UINTN)
431       AllocateAlignedRuntimePages (
432         EFI_SIZE_TO_PAGES (2 * PcdGet32 (PcdFlashNvStorageFtwSpareSize)),
433         PcdGet32 (PcdFlashNvStorageFtwSpareSize)
434         );
435   DEBUG ((EFI_D_INFO,
436           "Reserved variable store memory: 0x%lX; size: %dkb\n",
437           VariableStore,
438           (2 * PcdGet32 (PcdFlashNvStorageFtwSpareSize)) / 1024
439         ));
440   PcdSet64 (PcdEmuVariableNvStoreReserved, VariableStore);
441 }
442 
443 
444 VOID
DebugDumpCmos(VOID)445 DebugDumpCmos (
446   VOID
447   )
448 {
449   UINT32 Loop;
450 
451   DEBUG ((EFI_D_INFO, "CMOS:\n"));
452 
453   for (Loop = 0; Loop < 0x80; Loop++) {
454     if ((Loop % 0x10) == 0) {
455       DEBUG ((EFI_D_INFO, "%02x:", Loop));
456     }
457     DEBUG ((EFI_D_INFO, " %02x", CmosRead8 (Loop)));
458     if ((Loop % 0x10) == 0xf) {
459       DEBUG ((EFI_D_INFO, "\n"));
460     }
461   }
462 }
463 
464 
465 VOID
S3Verification(VOID)466 S3Verification (
467   VOID
468   )
469 {
470 #if defined (MDE_CPU_X64)
471   if (FeaturePcdGet (PcdSmmSmramRequire) && mS3Supported) {
472     DEBUG ((EFI_D_ERROR,
473       "%a: S3Resume2Pei doesn't support X64 PEI + SMM yet.\n", __FUNCTION__));
474     DEBUG ((EFI_D_ERROR,
475       "%a: Please disable S3 on the QEMU command line (see the README),\n",
476       __FUNCTION__));
477     DEBUG ((EFI_D_ERROR,
478       "%a: or build OVMF with \"OvmfPkgIa32X64.dsc\".\n", __FUNCTION__));
479     ASSERT (FALSE);
480     CpuDeadLoop ();
481   }
482 #endif
483 }
484 
485 
486 /**
487   Perform Platform PEI initialization.
488 
489   @param  FileHandle      Handle of the file being invoked.
490   @param  PeiServices     Describes the list of possible PEI Services.
491 
492   @return EFI_SUCCESS     The PEIM initialized successfully.
493 
494 **/
495 EFI_STATUS
496 EFIAPI
InitializePlatform(IN EFI_PEI_FILE_HANDLE FileHandle,IN CONST EFI_PEI_SERVICES ** PeiServices)497 InitializePlatform (
498   IN       EFI_PEI_FILE_HANDLE  FileHandle,
499   IN CONST EFI_PEI_SERVICES     **PeiServices
500   )
501 {
502   DEBUG ((EFI_D_ERROR, "Platform PEIM Loaded\n"));
503 
504   DebugDumpCmos ();
505 
506   XenDetect ();
507 
508   if (QemuFwCfgS3Enabled ()) {
509     DEBUG ((EFI_D_INFO, "S3 support was detected on QEMU\n"));
510     mS3Supported = TRUE;
511   }
512 
513   S3Verification ();
514   BootModeInitialization ();
515   AddressWidthInitialization ();
516 
517   PublishPeiMemory ();
518 
519   InitializeRamRegions ();
520 
521   if (mXen) {
522     DEBUG ((EFI_D_INFO, "Xen was detected\n"));
523     InitializeXen ();
524   }
525 
526   //
527   // Query Host Bridge DID
528   //
529   mHostBridgeDevId = PciRead16 (OVMF_HOSTBRIDGE_DID);
530 
531   if (mBootMode != BOOT_ON_S3_RESUME) {
532     ReserveEmuVariableNvStore ();
533     PeiFvInitialization ();
534     MemMapInitialization ();
535     NoexecDxeInitialization ();
536   }
537 
538   MiscInitialization ();
539 
540   return EFI_SUCCESS;
541 }
542