EFIAPI AllocateAcpiNvsPool ( IN UINTN AllocationSize ) { return AllocateMemoryBelow4G (EfiACPIMemoryNVS, AllocationSize); }
/** Hook point for AcpiVariableThunkPlatform for S3Ready. @param AcpiS3Context ACPI s3 context **/ VOID S3ReadyThunkPlatform ( IN ACPI_S3_CONTEXT *AcpiS3Context ) { EFI_PHYSICAL_ADDRESS AcpiMemoryBase; UINT32 AcpiMemorySize; EFI_PEI_HOB_POINTERS Hob; UINT64 MemoryLength; DEBUG ((EFI_D_INFO, "S3ReadyThunkPlatform\n")); if (mAcpiVariableSetCompatibility == NULL) { return; } // // Allocate ACPI reserved memory under 4G // AcpiMemoryBase = (EFI_PHYSICAL_ADDRESS)(UINTN)AllocateMemoryBelow4G (EfiReservedMemoryType, PcdGet32 (PcdS3AcpiReservedMemorySize)); ASSERT (AcpiMemoryBase != 0); AcpiMemorySize = PcdGet32 (PcdS3AcpiReservedMemorySize); // // Calculate the system memory length by memory hobs // MemoryLength = 0x100000; Hob.Raw = GetFirstHob (EFI_HOB_TYPE_RESOURCE_DESCRIPTOR); ASSERT (Hob.Raw != NULL); while ((Hob.Raw != NULL) && (!END_OF_HOB_LIST (Hob))) { if (Hob.ResourceDescriptor->ResourceType == EFI_RESOURCE_SYSTEM_MEMORY) { // // Skip the memory region below 1MB // if (Hob.ResourceDescriptor->PhysicalStart >= 0x100000) { MemoryLength += Hob.ResourceDescriptor->ResourceLength; } } Hob.Raw = GET_NEXT_HOB (Hob); Hob.Raw = GetNextHob (EFI_HOB_TYPE_RESOURCE_DESCRIPTOR, Hob.Raw); } mAcpiVariableSetCompatibility->AcpiReservedMemoryBase = AcpiMemoryBase; mAcpiVariableSetCompatibility->AcpiReservedMemorySize = AcpiMemorySize; mAcpiVariableSetCompatibility->SystemMemoryLength = MemoryLength; DEBUG((EFI_D_INFO, "AcpiVariableThunkPlatform: AcpiMemoryBase is 0x%8x\n", mAcpiVariableSetCompatibility->AcpiReservedMemoryBase)); DEBUG((EFI_D_INFO, "AcpiVariableThunkPlatform: AcpiMemorySize is 0x%8x\n", mAcpiVariableSetCompatibility->AcpiReservedMemorySize)); DEBUG((EFI_D_INFO, "AcpiVariableThunkPlatform: SystemMemoryLength is 0x%8x\n", mAcpiVariableSetCompatibility->SystemMemoryLength)); return ; }
/** Hook point for AcpiVariableThunkPlatform for InstallAcpiS3Save. **/ VOID InstallAcpiS3SaveThunk ( VOID ) { EFI_STATUS Status; FRAMEWORK_EFI_MP_SERVICES_PROTOCOL *FrameworkMpService; UINTN VarSize; Status = gBS->LocateProtocol ( &gFrameworkEfiMpServiceProtocolGuid, NULL, (VOID**) &FrameworkMpService ); if (!EFI_ERROR (Status)) { // // On ECP platform, if framework CPU drivers are in use, The compatible version of ACPI variable set // should be produced by CPU driver. // VarSize = sizeof (mAcpiVariableSetCompatibility); Status = gRT->GetVariable ( ACPI_GLOBAL_VARIABLE, &gEfiAcpiVariableCompatiblityGuid, NULL, &VarSize, &mAcpiVariableSetCompatibility ); ASSERT_EFI_ERROR (Status); } else { // // Allocate/initialize the compatible version of Acpi Variable Set since Framework chipset/platform // driver need this variable // mAcpiVariableSetCompatibility = AllocateMemoryBelow4G (EfiACPIMemoryNVS, sizeof(ACPI_VARIABLE_SET_COMPATIBILITY)); Status = gRT->SetVariable ( ACPI_GLOBAL_VARIABLE, &gEfiAcpiVariableCompatiblityGuid, EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS | EFI_VARIABLE_NON_VOLATILE, sizeof(mAcpiVariableSetCompatibility), &mAcpiVariableSetCompatibility ); ASSERT_EFI_ERROR (Status); } DEBUG((EFI_D_INFO, "AcpiVariableSetCompatibility is 0x%8x\n", mAcpiVariableSetCompatibility)); }
/** Prepares all information that is needed in the S3 resume boot path. Allocate the resources or prepare informations and save in ACPI variable set for S3 resume boot path @param This A pointer to the EFI_ACPI_S3_SAVE_PROTOCOL instance. @param LegacyMemoryAddress The base address of legacy memory. @retval EFI_NOT_FOUND Some necessary information cannot be found. @retval EFI_SUCCESS All information was saved successfully. @retval EFI_OUT_OF_RESOURCES Resources were insufficient to save all the information. @retval EFI_INVALID_PARAMETER The memory range is not located below 1 MB. **/ EFI_STATUS EFIAPI S3Ready ( IN EFI_ACPI_S3_SAVE_PROTOCOL *This, IN VOID *LegacyMemoryAddress ) { EFI_STATUS Status; EFI_PHYSICAL_ADDRESS AcpiS3ContextBuffer; ACPI_S3_CONTEXT *AcpiS3Context; STATIC BOOLEAN AlreadyEntered; IA32_DESCRIPTOR *Idtr; IA32_IDT_GATE_DESCRIPTOR *IdtGate; DEBUG ((EFI_D_INFO, "S3Ready!\n")); // // Platform may invoke AcpiS3Save->S3Save() before ExitPmAuth, because we need save S3 information there, while BDS ReadyToBoot may invoke it again. // So if 2nd S3Save() is triggered later, we need ignore it. // if (AlreadyEntered) { return EFI_SUCCESS; } AlreadyEntered = TRUE; AcpiS3Context = AllocateMemoryBelow4G (EfiReservedMemoryType, sizeof(*AcpiS3Context)); ASSERT (AcpiS3Context != NULL); AcpiS3ContextBuffer = (EFI_PHYSICAL_ADDRESS)(UINTN)AcpiS3Context; // // Get ACPI Table because we will save its position to variable // AcpiS3Context->AcpiFacsTable = (EFI_PHYSICAL_ADDRESS)(UINTN)FindAcpiFacsTable (); ASSERT (AcpiS3Context->AcpiFacsTable != 0); IdtGate = AllocateMemoryBelow4G (EfiReservedMemoryType, sizeof(IA32_IDT_GATE_DESCRIPTOR) * 0x100 + sizeof(IA32_DESCRIPTOR)); Idtr = (IA32_DESCRIPTOR *)(IdtGate + 0x100); Idtr->Base = (UINTN)IdtGate; Idtr->Limit = (UINT16)(sizeof(IA32_IDT_GATE_DESCRIPTOR) * 0x100 - 1); AcpiS3Context->IdtrProfile = (EFI_PHYSICAL_ADDRESS)(UINTN)Idtr; Status = SaveLockBox ( &mAcpiS3IdtrProfileGuid, (VOID *)(UINTN)Idtr, (UINTN)sizeof(IA32_DESCRIPTOR) ); ASSERT_EFI_ERROR (Status); Status = SetLockBoxAttributes (&mAcpiS3IdtrProfileGuid, LOCK_BOX_ATTRIBUTE_RESTORE_IN_PLACE); ASSERT_EFI_ERROR (Status); // // Allocate page table // AcpiS3Context->S3NvsPageTableAddress = S3CreateIdentityMappingPageTables (); // // Allocate stack // AcpiS3Context->BootScriptStackSize = PcdGet32 (PcdS3BootScriptStackSize); AcpiS3Context->BootScriptStackBase = (EFI_PHYSICAL_ADDRESS)(UINTN)AllocateMemoryBelow4G (EfiReservedMemoryType, PcdGet32 (PcdS3BootScriptStackSize)); ASSERT (AcpiS3Context->BootScriptStackBase != 0); // // Allocate a code buffer < 4G for S3 debug to load external code // AcpiS3Context->S3DebugBufferAddress = (EFI_PHYSICAL_ADDRESS)(UINTN)AllocateMemoryBelow4G (EfiReservedMemoryType, EFI_PAGE_SIZE); DEBUG((EFI_D_INFO, "AcpiS3Context: AcpiFacsTable is 0x%8x\n", AcpiS3Context->AcpiFacsTable)); DEBUG((EFI_D_INFO, "AcpiS3Context: IdtrProfile is 0x%8x\n", AcpiS3Context->IdtrProfile)); DEBUG((EFI_D_INFO, "AcpiS3Context: S3NvsPageTableAddress is 0x%8x\n", AcpiS3Context->S3NvsPageTableAddress)); DEBUG((EFI_D_INFO, "AcpiS3Context: S3DebugBufferAddress is 0x%8x\n", AcpiS3Context->S3DebugBufferAddress)); Status = SaveLockBox ( &gEfiAcpiVariableGuid, &AcpiS3ContextBuffer, sizeof(AcpiS3ContextBuffer) ); ASSERT_EFI_ERROR (Status); Status = SaveLockBox ( &gEfiAcpiS3ContextGuid, (VOID *)(UINTN)AcpiS3Context, (UINTN)sizeof(*AcpiS3Context) ); ASSERT_EFI_ERROR (Status); Status = SetLockBoxAttributes (&gEfiAcpiS3ContextGuid, LOCK_BOX_ATTRIBUTE_RESTORE_IN_PLACE); ASSERT_EFI_ERROR (Status); if (FeaturePcdGet(PcdFrameworkCompatibilitySupport)) { S3ReadyThunkPlatform (AcpiS3Context); } return EFI_SUCCESS; }
/** Allocates and fills in the Page Directory and Page Table Entries to establish a 1:1 Virtual to Physical mapping. If BootScriptExector driver will run in 64-bit mode, this function will establish the 1:1 virtual to physical mapping page table. If BootScriptExector driver will not run in 64-bit mode, this function will do nothing. @return the 1:1 Virtual to Physical identity mapping page table base address. **/ EFI_PHYSICAL_ADDRESS S3CreateIdentityMappingPageTables ( VOID ) { if (FeaturePcdGet (PcdDxeIplSwitchToLongMode)) { UINT32 RegEax; UINT32 RegEdx; UINT8 PhysicalAddressBits; UINT32 NumberOfPml4EntriesNeeded; UINT32 NumberOfPdpEntriesNeeded; EFI_PHYSICAL_ADDRESS S3NvsPageTableAddress; UINTN TotalPageTableSize; VOID *Hob; BOOLEAN Page1GSupport; Page1GSupport = FALSE; if (PcdGetBool(PcdUse1GPageTable)) { AsmCpuid (0x80000000, &RegEax, NULL, NULL, NULL); if (RegEax >= 0x80000001) { AsmCpuid (0x80000001, NULL, NULL, NULL, &RegEdx); if ((RegEdx & BIT26) != 0) { Page1GSupport = TRUE; } } } // // Get physical address bits supported. // Hob = GetFirstHob (EFI_HOB_TYPE_CPU); if (Hob != NULL) { PhysicalAddressBits = ((EFI_HOB_CPU *) Hob)->SizeOfMemorySpace; } else { AsmCpuid (0x80000000, &RegEax, NULL, NULL, NULL); if (RegEax >= 0x80000008) { AsmCpuid (0x80000008, &RegEax, NULL, NULL, NULL); PhysicalAddressBits = (UINT8) RegEax; } else { PhysicalAddressBits = 36; } } // // IA-32e paging translates 48-bit linear addresses to 52-bit physical addresses. // ASSERT (PhysicalAddressBits <= 52); if (PhysicalAddressBits > 48) { PhysicalAddressBits = 48; } // // Calculate the table entries needed. // if (PhysicalAddressBits <= 39 ) { NumberOfPml4EntriesNeeded = 1; NumberOfPdpEntriesNeeded = (UINT32)LShiftU64 (1, (PhysicalAddressBits - 30)); } else { NumberOfPml4EntriesNeeded = (UINT32)LShiftU64 (1, (PhysicalAddressBits - 39)); NumberOfPdpEntriesNeeded = 512; } // // We need calculate whole page size then allocate once, because S3 restore page table does not know each page in Nvs. // if (!Page1GSupport) { TotalPageTableSize = (UINTN)(1 + NumberOfPml4EntriesNeeded + NumberOfPml4EntriesNeeded * NumberOfPdpEntriesNeeded); } else { TotalPageTableSize = (UINTN)(1 + NumberOfPml4EntriesNeeded); } DEBUG ((EFI_D_ERROR, "TotalPageTableSize - %x pages\n", TotalPageTableSize)); // // By architecture only one PageMapLevel4 exists - so lets allocate storage for it. // S3NvsPageTableAddress = (EFI_PHYSICAL_ADDRESS)(UINTN)AllocateMemoryBelow4G (EfiReservedMemoryType, EFI_PAGES_TO_SIZE(TotalPageTableSize)); ASSERT (S3NvsPageTableAddress != 0); return S3NvsPageTableAddress; } else { // // If DXE is running 32-bit mode, no need to establish page table. // return (EFI_PHYSICAL_ADDRESS) 0; } }
/** Prepares all information that is needed in the S3 resume boot path. Allocate the resources or prepare informations and save in ACPI variable set for S3 resume boot path @retval EFI_SUCCESS All information was saved successfully. **/ STATIC EFI_STATUS EFIAPI S3Ready ( VOID ) { EFI_STATUS Status; EFI_PHYSICAL_ADDRESS AcpiS3ContextBuffer; ACPI_S3_CONTEXT *AcpiS3Context; STATIC BOOLEAN AlreadyEntered; IA32_DESCRIPTOR *Idtr; IA32_IDT_GATE_DESCRIPTOR *IdtGate; DEBUG ((EFI_D_INFO, "S3Ready!\n")); ASSERT (!AlreadyEntered); if (AlreadyEntered) { return EFI_SUCCESS; } AlreadyEntered = TRUE; AcpiS3Context = AllocateMemoryBelow4G (EfiReservedMemoryType, sizeof(*AcpiS3Context)); ASSERT (AcpiS3Context != NULL); AcpiS3ContextBuffer = (EFI_PHYSICAL_ADDRESS)(UINTN)AcpiS3Context; // // Get ACPI Table because we will save its position to variable // AcpiS3Context->AcpiFacsTable = (EFI_PHYSICAL_ADDRESS)(UINTN)FindAcpiFacsTable (); ASSERT (AcpiS3Context->AcpiFacsTable != 0); IdtGate = AllocateMemoryBelow4G (EfiReservedMemoryType, sizeof(IA32_IDT_GATE_DESCRIPTOR) * 0x100 + sizeof(IA32_DESCRIPTOR)); Idtr = (IA32_DESCRIPTOR *)(IdtGate + 0x100); Idtr->Base = (UINTN)IdtGate; Idtr->Limit = (UINT16)(sizeof(IA32_IDT_GATE_DESCRIPTOR) * 0x100 - 1); AcpiS3Context->IdtrProfile = (EFI_PHYSICAL_ADDRESS)(UINTN)Idtr; Status = SaveLockBox ( &mAcpiS3IdtrProfileGuid, (VOID *)(UINTN)Idtr, (UINTN)sizeof(IA32_DESCRIPTOR) ); ASSERT_EFI_ERROR (Status); Status = SetLockBoxAttributes (&mAcpiS3IdtrProfileGuid, LOCK_BOX_ATTRIBUTE_RESTORE_IN_PLACE); ASSERT_EFI_ERROR (Status); // // Allocate page table // AcpiS3Context->S3NvsPageTableAddress = S3CreateIdentityMappingPageTables (); // // Allocate stack // AcpiS3Context->BootScriptStackSize = PcdGet32 (PcdS3BootScriptStackSize); AcpiS3Context->BootScriptStackBase = (EFI_PHYSICAL_ADDRESS)(UINTN)AllocateMemoryBelow4G (EfiReservedMemoryType, PcdGet32 (PcdS3BootScriptStackSize)); ASSERT (AcpiS3Context->BootScriptStackBase != 0); // // Allocate a code buffer < 4G for S3 debug to load external code, set invalid code instructions in it. // AcpiS3Context->S3DebugBufferAddress = (EFI_PHYSICAL_ADDRESS)(UINTN)AllocateMemoryBelow4G (EfiReservedMemoryType, EFI_PAGE_SIZE); SetMem ((VOID *)(UINTN)AcpiS3Context->S3DebugBufferAddress, EFI_PAGE_SIZE, 0xff); DEBUG ((EFI_D_INFO, "AcpiS3Context: AcpiFacsTable is 0x%8Lx\n", AcpiS3Context->AcpiFacsTable)); DEBUG ((EFI_D_INFO, "AcpiS3Context: IdtrProfile is 0x%8Lx\n", AcpiS3Context->IdtrProfile)); DEBUG ((EFI_D_INFO, "AcpiS3Context: S3NvsPageTableAddress is 0x%8Lx\n", AcpiS3Context->S3NvsPageTableAddress)); DEBUG ((EFI_D_INFO, "AcpiS3Context: S3DebugBufferAddress is 0x%8Lx\n", AcpiS3Context->S3DebugBufferAddress)); Status = SaveLockBox ( &gEfiAcpiVariableGuid, &AcpiS3ContextBuffer, sizeof(AcpiS3ContextBuffer) ); ASSERT_EFI_ERROR (Status); Status = SaveLockBox ( &gEfiAcpiS3ContextGuid, (VOID *)(UINTN)AcpiS3Context, (UINTN)sizeof(*AcpiS3Context) ); ASSERT_EFI_ERROR (Status); Status = SetLockBoxAttributes (&gEfiAcpiS3ContextGuid, LOCK_BOX_ATTRIBUTE_RESTORE_IN_PLACE); ASSERT_EFI_ERROR (Status); return EFI_SUCCESS; }
/** Hook point for AcpiVariableThunkPlatform for InstallAcpiS3Save. **/ VOID InstallAcpiS3SaveThunk ( VOID ) { EFI_STATUS Status; FRAMEWORK_EFI_MP_SERVICES_PROTOCOL *FrameworkMpService; UINTN VarSize; VOID *Registration; Status = gBS->LocateProtocol ( &gFrameworkEfiMpServiceProtocolGuid, NULL, (VOID**) &FrameworkMpService ); if (!EFI_ERROR (Status)) { // // On ECP platform, if framework CPU drivers are in use, The compatible version of ACPI variable set // should be produced by CPU driver. // VarSize = sizeof (mAcpiVariableSetCompatibility); Status = gRT->GetVariable ( ACPI_GLOBAL_VARIABLE, &gEfiAcpiVariableCompatiblityGuid, NULL, &VarSize, &mAcpiVariableSetCompatibility ); if (EFI_ERROR (Status) || (VarSize != sizeof (mAcpiVariableSetCompatibility))) { DEBUG ((EFI_D_ERROR, "FATAL ERROR: AcpiVariableSetCompatibility was not saved by CPU driver correctly. OS S3 may fail!\n")); mAcpiVariableSetCompatibility = NULL; } } else { // // Allocate/initialize the compatible version of Acpi Variable Set since Framework chipset/platform // driver need this variable. ACPI_GLOBAL_VARIABLE variable is not used in runtime phase, // so RT attribute is not needed for it. // mAcpiVariableSetCompatibility = AllocateMemoryBelow4G (EfiACPIMemoryNVS, sizeof(ACPI_VARIABLE_SET_COMPATIBILITY)); Status = gRT->SetVariable ( ACPI_GLOBAL_VARIABLE, &gEfiAcpiVariableCompatiblityGuid, EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_NON_VOLATILE, sizeof(mAcpiVariableSetCompatibility), &mAcpiVariableSetCompatibility ); if (!EFI_ERROR (Status)) { // // Register callback function upon VariableLockProtocol // to lock ACPI_GLOBAL_VARIABLE variable to avoid malicious code to update it. // EfiCreateProtocolNotifyEvent ( &gEdkiiVariableLockProtocolGuid, TPL_CALLBACK, VariableLockAcpiGlobalVariable, NULL, &Registration ); } else { DEBUG ((EFI_D_ERROR, "FATAL ERROR: AcpiVariableSetCompatibility cannot be saved: %r. OS S3 may fail!\n", Status)); gBS->FreePages ( (EFI_PHYSICAL_ADDRESS) (UINTN) mAcpiVariableSetCompatibility, EFI_SIZE_TO_PAGES (sizeof (ACPI_VARIABLE_SET_COMPATIBILITY)) ); mAcpiVariableSetCompatibility = NULL; } } DEBUG((EFI_D_INFO, "AcpiVariableSetCompatibility is 0x%8x\n", mAcpiVariableSetCompatibility)); }