EFI_STATUS EFIAPI BoardDetectionCallback ( IN CONST EFI_PEI_SERVICES **PeiServices, IN EFI_PEI_NOTIFY_DESCRIPTOR *NotifyDescriptor, IN VOID *Ppi ) { EFI_STATUS Status; VOID *Instance; DEBUG ((EFI_D_INFO, "Detecting Galileo ...\n")); // // Check if board detection is finished. // Status = PeiServicesLocatePpi ( &gBoardDetectedPpiGuid, 0, NULL, &Instance ); if (!EFI_ERROR(Status)) { return EFI_SUCCESS; } // // In most real platform, here should be the code to detect board type. // // For galileo, we only support build time board selection, so use PCD to do the fake detection. // if (PcdGet16(PcdPlatformType) != Galileo) { return EFI_UNSUPPORTED; } DEBUG ((EFI_D_INFO, "Detected Galileo!\n")); Status = PcdSet64S (PcdBoardInitPreMem, (UINT64)(UINTN)BoarInitPreMem); ASSERT_EFI_ERROR(Status); Status = PcdSet64S (PcdBoardInitPostMem, (UINT64)(UINTN)BoarInitPostMem); ASSERT_EFI_ERROR(Status); Status = PcdSet32S (PcdPciExpPerstResumeWellGpio, PCIEXP_PERST_RESUMEWELL_GPIO); ASSERT_EFI_ERROR(Status); Status = PcdSet32S (PcdFlashUpdateLedResumeWellGpio, GALILEO_FLASH_UPDATE_LED_RESUMEWELL_GPIO); ASSERT_EFI_ERROR(Status); Status = PeiServicesInstallPpi(&mDetectedPpi); ASSERT_EFI_ERROR(Status); return Status; }
VOID ReserveEmuVariableNvStore ( ) { EFI_PHYSICAL_ADDRESS VariableStore; RETURN_STATUS PcdStatus; // // Allocate storage for NV variables early on so it will be // at a consistent address. Since VM memory is preserved // across reboots, this allows the NV variable storage to survive // a VM reboot. // VariableStore = (EFI_PHYSICAL_ADDRESS)(UINTN) AllocateRuntimePages ( EFI_SIZE_TO_PAGES (2 * PcdGet32 (PcdFlashNvStorageFtwSpareSize)) ); DEBUG ((EFI_D_INFO, "Reserved variable store memory: 0x%lX; size: %dkb\n", VariableStore, (2 * PcdGet32 (PcdFlashNvStorageFtwSpareSize)) / 1024 )); PcdStatus = PcdSet64S (PcdEmuVariableNvStoreReserved, VariableStore); ASSERT_RETURN_ERROR (PcdStatus); }
/** Performs platform specific initialization required for the CPU to access the hardware associated with a SerialPortLib instance. This function does not intiailzie the serial port hardware itself. Instead, it initializes hardware devices that are required for the CPU to access the serial port hardware. This function may be called more than once. @retval RETURN_SUCCESS The platform specific initialization succeeded. @retval RETURN_DEVICE_ERROR The platform specific initialization could not be completed. **/ RETURN_STATUS EFIAPI PlatformHookSerialPortInitialize ( VOID ) { RETURN_STATUS Status; UINT32 SerialRegBase; UINT32 SerialRegAccessType; Status = CbParseSerialInfo (&SerialRegBase, &SerialRegAccessType, NULL); if (RETURN_ERROR (Status)) { return Status; } if (SerialRegAccessType == 2) { //MMIO Status = PcdSetBoolS (PcdSerialUseMmio, TRUE); } else { //IO Status = PcdSetBoolS (PcdSerialUseMmio, FALSE); } if (RETURN_ERROR (Status)) { return Status; } Status = PcdSet64S (PcdSerialRegisterBase, (UINT64) SerialRegBase); if (RETURN_ERROR (Status)) { return Status; } return RETURN_SUCCESS; }
/** Main entry point. @param[in] ImageHandle The firmware allocated handle for the EFI image. @param[in] SystemTable A pointer to the EFI System Table. @retval EFI_SUCCESS Successfully initialized. **/ EFI_STATUS EFIAPI FvbInitialize ( IN EFI_HANDLE ImageHandle, IN EFI_SYSTEM_TABLE *SystemTable ) { EFI_STATUS Status; VOID *Ptr; VOID *SubPtr; BOOLEAN Initialize; EFI_HANDLE Handle; EFI_PHYSICAL_ADDRESS Address; RETURN_STATUS PcdStatus; DEBUG ((EFI_D_INFO, "EMU Variable FVB Started\n")); // // Verify that the PCD's are set correctly. // if ( (PcdGet32 (PcdVariableStoreSize) + PcdGet32 (PcdFlashNvStorageFtwWorkingSize) ) > EMU_FVB_BLOCK_SIZE ) { DEBUG ((EFI_D_ERROR, "EMU Variable invalid PCD sizes\n")); return EFI_INVALID_PARAMETER; } if (PcdGet64 (PcdFlashNvStorageVariableBase64) != 0) { DEBUG ((EFI_D_INFO, "Disabling EMU Variable FVB since " "flash variables appear to be supported.\n")); return EFI_ABORTED; } // // By default we will initialize the FV contents. But, if // PcdEmuVariableNvStoreReserved is non-zero, then we will // use this location for our buffer. // // If this location does not have a proper FV header, then // we will initialize it. // Initialize = TRUE; if (PcdGet64 (PcdEmuVariableNvStoreReserved) != 0) { Ptr = (VOID*)(UINTN) PcdGet64 (PcdEmuVariableNvStoreReserved); DEBUG (( EFI_D_INFO, "EMU Variable FVB: Using pre-reserved block at %p\n", Ptr )); Status = ValidateFvHeader (Ptr); if (!EFI_ERROR (Status)) { DEBUG ((EFI_D_INFO, "EMU Variable FVB: Found valid pre-existing FV\n")); Initialize = FALSE; } } else { Ptr = AllocateAlignedRuntimePages ( EFI_SIZE_TO_PAGES (EMU_FVB_SIZE), SIZE_64KB ); } mEmuVarsFvb.BufferPtr = Ptr; // // Initialize the main FV header and variable store header // if (Initialize) { SetMem (Ptr, EMU_FVB_SIZE, ERASED_UINT8); InitializeFvAndVariableStoreHeaders (Ptr); } PcdStatus = PcdSet64S (PcdFlashNvStorageVariableBase64, (UINT32)(UINTN) Ptr); ASSERT_RETURN_ERROR (PcdStatus); // // Initialize the Fault Tolerant Write data area // SubPtr = (VOID*) ((UINT8*) Ptr + PcdGet32 (PcdVariableStoreSize)); PcdStatus = PcdSet32S (PcdFlashNvStorageFtwWorkingBase, (UINT32)(UINTN) SubPtr); ASSERT_RETURN_ERROR (PcdStatus); // // Initialize the Fault Tolerant Write spare block // SubPtr = (VOID*) ((UINT8*) Ptr + EMU_FVB_BLOCK_SIZE); PcdStatus = PcdSet32S (PcdFlashNvStorageFtwSpareBase, (UINT32)(UINTN) SubPtr); ASSERT_RETURN_ERROR (PcdStatus); // // Setup FVB device path // Address = (EFI_PHYSICAL_ADDRESS)(UINTN) Ptr; mEmuVarsFvb.DevicePath.MemMapDevPath.StartingAddress = Address; mEmuVarsFvb.DevicePath.MemMapDevPath.EndingAddress = Address + EMU_FVB_SIZE - 1; // // Install the protocols // DEBUG ((EFI_D_INFO, "Installing FVB for EMU Variable support\n")); Handle = 0; Status = gBS->InstallMultipleProtocolInterfaces ( &Handle, &gEfiFirmwareVolumeBlock2ProtocolGuid, &mEmuVarsFvb.FwVolBlockInstance, &gEfiDevicePathProtocolGuid, &mEmuVarsFvb.DevicePath, NULL ); ASSERT_EFI_ERROR (Status); // // Register for the virtual address change event // Status = gBS->CreateEventEx ( EVT_NOTIFY_SIGNAL, TPL_NOTIFY, FvbVirtualAddressChangeEvent, NULL, &gEfiEventVirtualAddressChangeGuid, &mEmuVarsFvbAddrChangeEvent ); ASSERT_EFI_ERROR (Status); return EFI_SUCCESS; }
VOID MemMapInitialization ( VOID ) { UINT64 PciIoBase; UINT64 PciIoSize; RETURN_STATUS PcdStatus; PciIoBase = 0xC000; PciIoSize = 0x4000; // // Create Memory Type Information HOB // BuildGuidDataHob ( &gEfiMemoryTypeInformationGuid, mDefaultMemoryTypeInformation, sizeof(mDefaultMemoryTypeInformation) ); // // Video memory + Legacy BIOS region // AddIoMemoryRangeHob (0x0A0000, BASE_1MB); if (!mXen) { UINT32 TopOfLowRam; UINT64 PciExBarBase; UINT32 PciBase; UINT32 PciSize; TopOfLowRam = GetSystemMemorySizeBelow4gb (); PciExBarBase = 0; if (mHostBridgeDevId == INTEL_Q35_MCH_DEVICE_ID) { // // The MMCONFIG area is expected to fall between the top of low RAM and // the base of the 32-bit PCI host aperture. // PciExBarBase = FixedPcdGet64 (PcdPciExpressBaseAddress); ASSERT (TopOfLowRam <= PciExBarBase); ASSERT (PciExBarBase <= MAX_UINT32 - SIZE_256MB); PciBase = (UINT32)(PciExBarBase + SIZE_256MB); } else { PciBase = (TopOfLowRam < BASE_2GB) ? BASE_2GB : TopOfLowRam; } // // address purpose size // ------------ -------- ------------------------- // max(top, 2g) PCI MMIO 0xFC000000 - max(top, 2g) // 0xFC000000 gap 44 MB // 0xFEC00000 IO-APIC 4 KB // 0xFEC01000 gap 1020 KB // 0xFED00000 HPET 1 KB // 0xFED00400 gap 111 KB // 0xFED1C000 gap (PIIX4) / RCRB (ICH9) 16 KB // 0xFED20000 gap 896 KB // 0xFEE00000 LAPIC 1 MB // PciSize = 0xFC000000 - PciBase; AddIoMemoryBaseSizeHob (PciBase, PciSize); PcdStatus = PcdSet64S (PcdPciMmio32Base, PciBase); ASSERT_RETURN_ERROR (PcdStatus); PcdStatus = PcdSet64S (PcdPciMmio32Size, PciSize); ASSERT_RETURN_ERROR (PcdStatus); AddIoMemoryBaseSizeHob (0xFEC00000, SIZE_4KB); AddIoMemoryBaseSizeHob (0xFED00000, SIZE_1KB); if (mHostBridgeDevId == INTEL_Q35_MCH_DEVICE_ID) { AddIoMemoryBaseSizeHob (ICH9_ROOT_COMPLEX_BASE, SIZE_16KB); // // Note: there should be an // // AddIoMemoryBaseSizeHob (PciExBarBase, SIZE_256MB); // // call below, just like the one above for RCBA. However, Linux insists // that the MMCONFIG area be marked in the E820 or UEFI memory map as // "reserved memory" -- Linux does not content itself with a simple gap // in the memory map wherever the MCFG ACPI table points to. // // This appears to be a safety measure. The PCI Firmware Specification // (rev 3.1) says in 4.1.2. "MCFG Table Description": "The resources can // *optionally* be returned in [...] EFIGetMemoryMap as reserved memory // [...]". (Emphasis added here.) // // Normally we add memory resource descriptor HOBs in // QemuInitializeRam(), and pre-allocate from those with memory // allocation HOBs in InitializeRamRegions(). However, the MMCONFIG area // is most definitely not RAM; so, as an exception, cover it with // uncacheable reserved memory right here. // AddReservedMemoryBaseSizeHob (PciExBarBase, SIZE_256MB, FALSE); BuildMemoryAllocationHob (PciExBarBase, SIZE_256MB, EfiReservedMemoryType); } AddIoMemoryBaseSizeHob (PcdGet32(PcdCpuLocalApicBaseAddress), SIZE_1MB); // // On Q35, the IO Port space is available for PCI resource allocations from // 0x6000 up. // if (mHostBridgeDevId == INTEL_Q35_MCH_DEVICE_ID) { PciIoBase = 0x6000; PciIoSize = 0xA000; ASSERT ((ICH9_PMBASE_VALUE & 0xF000) < PciIoBase); } } // // Add PCI IO Port space available for PCI resource allocations. // BuildResourceDescriptorHob ( EFI_RESOURCE_IO, EFI_RESOURCE_ATTRIBUTE_PRESENT | EFI_RESOURCE_ATTRIBUTE_INITIALIZED, PciIoBase, PciIoSize ); PcdStatus = PcdSet64S (PcdPciIoBase, PciIoBase); ASSERT_RETURN_ERROR (PcdStatus); PcdStatus = PcdSet64S (PcdPciIoSize, PciIoSize); ASSERT_RETURN_ERROR (PcdStatus); }
/** The entry function of the CpuS3Data driver. Allocate and initialize all fields of the ACPI_CPU_DATA structure except the MTRR settings. Register an event notification on gEfiEndOfDxeEventGroupGuid to capture the ACPI_CPU_DATA MTRR settings. The PcdCpuS3DataAddress is set to the address that ACPI_CPU_DATA is allocated at. @param[in] ImageHandle The firmware allocated handle for the EFI image. @param[in] SystemTable A pointer to the EFI System Table. @retval EFI_SUCCESS The entry point is executed successfully. @retval EFI_UNSUPPORTED Do not support ACPI S3. @retval other Some error occurs when executing this entry point. **/ EFI_STATUS EFIAPI CpuS3DataInitialize ( IN EFI_HANDLE ImageHandle, IN EFI_SYSTEM_TABLE *SystemTable ) { EFI_STATUS Status; ACPI_CPU_DATA_EX *AcpiCpuDataEx; ACPI_CPU_DATA *AcpiCpuData; EFI_MP_SERVICES_PROTOCOL *MpServices; UINTN NumberOfCpus; UINTN NumberOfEnabledProcessors; VOID *Stack; UINTN TableSize; CPU_REGISTER_TABLE *RegisterTable; UINTN Index; EFI_PROCESSOR_INFORMATION ProcessorInfoBuffer; UINTN GdtSize; UINTN IdtSize; VOID *Gdt; VOID *Idt; EFI_EVENT Event; ACPI_CPU_DATA *OldAcpiCpuData; if (!PcdGetBool (PcdAcpiS3Enable)) { return EFI_UNSUPPORTED; } // // Set PcdCpuS3DataAddress to the base address of the ACPI_CPU_DATA structure // OldAcpiCpuData = (ACPI_CPU_DATA *) (UINTN) PcdGet64 (PcdCpuS3DataAddress); AcpiCpuDataEx = AllocateZeroPages (sizeof (ACPI_CPU_DATA_EX)); ASSERT (AcpiCpuDataEx != NULL); AcpiCpuData = &AcpiCpuDataEx->AcpiCpuData; // // Get MP Services Protocol // Status = gBS->LocateProtocol ( &gEfiMpServiceProtocolGuid, NULL, (VOID **)&MpServices ); ASSERT_EFI_ERROR (Status); // // Get the number of CPUs // Status = MpServices->GetNumberOfProcessors ( MpServices, &NumberOfCpus, &NumberOfEnabledProcessors ); ASSERT_EFI_ERROR (Status); AcpiCpuData->NumberOfCpus = (UINT32)NumberOfCpus; // // Initialize ACPI_CPU_DATA fields // AcpiCpuData->StackSize = PcdGet32 (PcdCpuApStackSize); AcpiCpuData->ApMachineCheckHandlerBase = 0; AcpiCpuData->ApMachineCheckHandlerSize = 0; AcpiCpuData->GdtrProfile = (EFI_PHYSICAL_ADDRESS)(UINTN)&AcpiCpuDataEx->GdtrProfile; AcpiCpuData->IdtrProfile = (EFI_PHYSICAL_ADDRESS)(UINTN)&AcpiCpuDataEx->IdtrProfile; AcpiCpuData->MtrrTable = (EFI_PHYSICAL_ADDRESS)(UINTN)&AcpiCpuDataEx->MtrrTable; // // Allocate stack space for all CPUs. // Use ACPI NVS memory type because this data will be directly used by APs // in S3 resume phase in long mode. Also during S3 resume, the stack buffer // will only be used as scratch space. i.e. we won't read anything from it // before we write to it, in PiSmmCpuDxeSmm. // Stack = AllocateAcpiNvsMemory (NumberOfCpus * AcpiCpuData->StackSize); ASSERT (Stack != NULL); AcpiCpuData->StackAddress = (EFI_PHYSICAL_ADDRESS)(UINTN)Stack; // // Get the boot processor's GDT and IDT // AsmReadGdtr (&AcpiCpuDataEx->GdtrProfile); AsmReadIdtr (&AcpiCpuDataEx->IdtrProfile); // // Allocate GDT and IDT and copy current GDT and IDT contents // GdtSize = AcpiCpuDataEx->GdtrProfile.Limit + 1; IdtSize = AcpiCpuDataEx->IdtrProfile.Limit + 1; Gdt = AllocateZeroPages (GdtSize + IdtSize); ASSERT (Gdt != NULL); Idt = (VOID *)((UINTN)Gdt + GdtSize); CopyMem (Gdt, (VOID *)AcpiCpuDataEx->GdtrProfile.Base, GdtSize); CopyMem (Idt, (VOID *)AcpiCpuDataEx->IdtrProfile.Base, IdtSize); AcpiCpuDataEx->GdtrProfile.Base = (UINTN)Gdt; AcpiCpuDataEx->IdtrProfile.Base = (UINTN)Idt; if (OldAcpiCpuData != NULL) { AcpiCpuData->RegisterTable = OldAcpiCpuData->RegisterTable; AcpiCpuData->PreSmmInitRegisterTable = OldAcpiCpuData->PreSmmInitRegisterTable; AcpiCpuData->ApLocation = OldAcpiCpuData->ApLocation; CopyMem (&AcpiCpuData->CpuStatus, &OldAcpiCpuData->CpuStatus, sizeof (CPU_STATUS_INFORMATION)); } else { // // Allocate buffer for empty RegisterTable and PreSmmInitRegisterTable for all CPUs // TableSize = 2 * NumberOfCpus * sizeof (CPU_REGISTER_TABLE); RegisterTable = (CPU_REGISTER_TABLE *)AllocateZeroPages (TableSize); ASSERT (RegisterTable != NULL); for (Index = 0; Index < NumberOfCpus; Index++) { Status = MpServices->GetProcessorInfo ( MpServices, Index, &ProcessorInfoBuffer ); ASSERT_EFI_ERROR (Status); RegisterTable[Index].InitialApicId = (UINT32)ProcessorInfoBuffer.ProcessorId; RegisterTable[Index].TableLength = 0; RegisterTable[Index].AllocatedSize = 0; RegisterTable[Index].RegisterTableEntry = 0; RegisterTable[NumberOfCpus + Index].InitialApicId = (UINT32)ProcessorInfoBuffer.ProcessorId; RegisterTable[NumberOfCpus + Index].TableLength = 0; RegisterTable[NumberOfCpus + Index].AllocatedSize = 0; RegisterTable[NumberOfCpus + Index].RegisterTableEntry = 0; } AcpiCpuData->RegisterTable = (EFI_PHYSICAL_ADDRESS)(UINTN)RegisterTable; AcpiCpuData->PreSmmInitRegisterTable = (EFI_PHYSICAL_ADDRESS)(UINTN)(RegisterTable + NumberOfCpus); } // // Set PcdCpuS3DataAddress to the base address of the ACPI_CPU_DATA structure // Status = PcdSet64S (PcdCpuS3DataAddress, (UINT64)(UINTN)AcpiCpuData); ASSERT_EFI_ERROR (Status); // // Register EFI_END_OF_DXE_EVENT_GROUP_GUID event. // The notification function allocates StartupVector and saves MTRRs for ACPI_CPU_DATA // Status = gBS->CreateEventEx ( EVT_NOTIFY_SIGNAL, TPL_CALLBACK, CpuS3DataOnEndOfDxe, AcpiCpuData, &gEfiEndOfDxeEventGroupGuid, &Event ); ASSERT_EFI_ERROR (Status); return EFI_SUCCESS; }