X-Git-Url: https://git.proxmox.com/?p=mirror_edk2.git;a=blobdiff_plain;f=MdeModulePkg%2FCore%2FDxeIplPeim%2FIa32%2FDxeLoadFunc.c;h=8a939b6c24870f03f6e9ce0f7de633afc03e279b;hp=8c5b37ced8685e6505d1e4e39d5b185712f3b26c;hb=98d20e44dc72d9858523687fda11ab8fc570fcec;hpb=df7aaeb9985df30bf9590a9591bedb60e01b4a54 diff --git a/MdeModulePkg/Core/DxeIplPeim/Ia32/DxeLoadFunc.c b/MdeModulePkg/Core/DxeIplPeim/Ia32/DxeLoadFunc.c index 8c5b37ced8..8a939b6c24 100644 --- a/MdeModulePkg/Core/DxeIplPeim/Ia32/DxeLoadFunc.c +++ b/MdeModulePkg/Core/DxeIplPeim/Ia32/DxeLoadFunc.c @@ -1,8 +1,10 @@ /** @file Ia32-specific functionality for DxeLoad. -Copyright (c) 2006 - 2010, Intel Corporation.
-All rights reserved. This program and the accompanying materials +Copyright (c) 2006 - 2018, Intel Corporation. All rights reserved.
+Copyright (c) 2017, AMD Incorporated. All rights reserved.
+ +This program and the accompanying materials are licensed and made available under the terms and conditions of the BSD License which accompanies this distribution. The full text of the license may be found at http://opensource.org/licenses/bsd-license.php @@ -17,6 +19,16 @@ WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. #define IDT_ENTRY_COUNT 32 +typedef struct _X64_IDT_TABLE { + // + // Reserved 4 bytes preceding PeiService and IdtTable, + // since IDT base address should be 8-byte alignment. + // + UINT32 Reserved; + CONST EFI_PEI_SERVICES **PeiService; + X64_IDT_GATE_DESCRIPTOR IdtTable[IDT_ENTRY_COUNT]; +} X64_IDT_TABLE; + // // Global Descriptor Table (GDT) // @@ -46,6 +58,200 @@ GLOBAL_REMOVE_IF_UNREFERENCED IA32_DESCRIPTOR gLidtDescriptor = { 0 }; +/** + Allocates and fills in the Page Directory and Page Table Entries to + establish a 4G page table. + + @param[in] StackBase Stack base address. + @param[in] StackSize Stack size. + + @return The address of page table. + +**/ +UINTN +Create4GPageTablesIa32Pae ( + IN EFI_PHYSICAL_ADDRESS StackBase, + IN UINTN StackSize + ) +{ + UINT8 PhysicalAddressBits; + EFI_PHYSICAL_ADDRESS PhysicalAddress; + UINTN IndexOfPdpEntries; + UINTN IndexOfPageDirectoryEntries; + UINT32 NumberOfPdpEntriesNeeded; + PAGE_MAP_AND_DIRECTORY_POINTER *PageMap; + PAGE_MAP_AND_DIRECTORY_POINTER *PageDirectoryPointerEntry; + PAGE_TABLE_ENTRY *PageDirectoryEntry; + UINTN TotalPagesNum; + UINTN PageAddress; + UINT64 AddressEncMask; + + // + // Make sure AddressEncMask is contained to smallest supported address field + // + AddressEncMask = PcdGet64 (PcdPteMemoryEncryptionAddressOrMask) & PAGING_1G_ADDRESS_MASK_64; + + PhysicalAddressBits = 32; + + // + // Calculate the table entries needed. + // + NumberOfPdpEntriesNeeded = (UINT32) LShiftU64 (1, (PhysicalAddressBits - 30)); + + TotalPagesNum = NumberOfPdpEntriesNeeded + 1; + PageAddress = (UINTN) AllocatePageTableMemory (TotalPagesNum); + ASSERT (PageAddress != 0); + + PageMap = (VOID *) PageAddress; + PageAddress += SIZE_4KB; + + PageDirectoryPointerEntry = PageMap; + PhysicalAddress = 0; + + for (IndexOfPdpEntries = 0; IndexOfPdpEntries < NumberOfPdpEntriesNeeded; IndexOfPdpEntries++, PageDirectoryPointerEntry++) { + // + // Each Directory Pointer entries points to a page of Page Directory entires. + // So allocate space for them and fill them in in the IndexOfPageDirectoryEntries loop. + // + PageDirectoryEntry = (VOID *) PageAddress; + PageAddress += SIZE_4KB; + + // + // Fill in a Page Directory Pointer Entries + // + PageDirectoryPointerEntry->Uint64 = (UINT64) (UINTN) PageDirectoryEntry | AddressEncMask; + PageDirectoryPointerEntry->Bits.Present = 1; + + for (IndexOfPageDirectoryEntries = 0; IndexOfPageDirectoryEntries < 512; IndexOfPageDirectoryEntries++, PageDirectoryEntry++, PhysicalAddress += SIZE_2MB) { + if ((IsNullDetectionEnabled () && PhysicalAddress == 0) + || ((PhysicalAddress < StackBase + StackSize) + && ((PhysicalAddress + SIZE_2MB) > StackBase))) { + // + // Need to split this 2M page that covers stack range. + // + Split2MPageTo4K (PhysicalAddress, (UINT64 *) PageDirectoryEntry, StackBase, StackSize); + } else { + // + // Fill in the Page Directory entries + // + PageDirectoryEntry->Uint64 = (UINT64) PhysicalAddress | AddressEncMask; + PageDirectoryEntry->Bits.ReadWrite = 1; + PageDirectoryEntry->Bits.Present = 1; + PageDirectoryEntry->Bits.MustBe1 = 1; + } + } + } + + for (; IndexOfPdpEntries < 512; IndexOfPdpEntries++, PageDirectoryPointerEntry++) { + ZeroMem ( + PageDirectoryPointerEntry, + sizeof (PAGE_MAP_AND_DIRECTORY_POINTER) + ); + } + + // + // Protect the page table by marking the memory used for page table to be + // read-only. + // + EnablePageTableProtection ((UINTN)PageMap, FALSE); + + return (UINTN) PageMap; +} + +/** + The function will check if IA32 PAE is supported. + + @retval TRUE IA32 PAE is supported. + @retval FALSE IA32 PAE is not supported. + +**/ +BOOLEAN +IsIa32PaeSupport ( + VOID + ) +{ + UINT32 RegEax; + UINT32 RegEdx; + BOOLEAN Ia32PaeSupport; + + Ia32PaeSupport = FALSE; + AsmCpuid (0x0, &RegEax, NULL, NULL, NULL); + if (RegEax >= 0x1) { + AsmCpuid (0x1, NULL, NULL, NULL, &RegEdx); + if ((RegEdx & BIT6) != 0) { + Ia32PaeSupport = TRUE; + } + } + + return Ia32PaeSupport; +} + +/** + The function will check if Execute Disable Bit is available. + + @retval TRUE Execute Disable Bit is available. + @retval FALSE Execute Disable Bit is not available. + +**/ +BOOLEAN +IsExecuteDisableBitAvailable ( + VOID + ) +{ + UINT32 RegEax; + UINT32 RegEdx; + BOOLEAN Available; + + Available = FALSE; + AsmCpuid (0x80000000, &RegEax, NULL, NULL, NULL); + if (RegEax >= 0x80000001) { + AsmCpuid (0x80000001, NULL, NULL, NULL, &RegEdx); + if ((RegEdx & BIT20) != 0) { + // + // Bit 20: Execute Disable Bit available. + // + Available = TRUE; + } + } + + return Available; +} + +/** + The function will check if page table should be setup or not. + + @retval TRUE Page table should be created. + @retval FALSE Page table should not be created. + +**/ +BOOLEAN +ToBuildPageTable ( + VOID + ) +{ + if (!IsIa32PaeSupport ()) { + return FALSE; + } + + if (IsNullDetectionEnabled ()) { + return TRUE; + } + + if (PcdGet8 (PcdHeapGuardPropertyMask) != 0) { + return TRUE; + } + + if (PcdGetBool (PcdCpuStackGuard)) { + return TRUE; + } + + if (PcdGetBool (PcdSetNxForStack) && IsExecuteDisableBitAvailable ()) { + return TRUE; + } + + return FALSE; +} + /** Transfers control to DxeCore. @@ -72,6 +278,14 @@ HandOffToDxeCore ( VOID *TemplateBase; EFI_PHYSICAL_ADDRESS VectorAddress; UINT32 Index; + X64_IDT_TABLE *IdtTableForX64; + EFI_VECTOR_HANDOFF_INFO *VectorInfo; + EFI_PEI_VECTOR_HANDOFF_INFO_PPI *VectorHandoffInfoPpi; + BOOLEAN BuildPageTablesIa32Pae; + + if (IsNullDetectionEnabled ()) { + ClearFirst4KPage (HobList.Raw); + } Status = PeiServicesAllocatePages (EfiBootServicesData, EFI_SIZE_TO_PAGES (STACK_SIZE), &BaseOfStack); ASSERT_EFI_ERROR (Status); @@ -101,12 +315,14 @@ HandOffToDxeCore ( // // Create page table and save PageMapLevel4 to CR3 // - PageTables = CreateIdentityMappingPageTables (); + PageTables = CreateIdentityMappingPageTables (BaseOfStack, STACK_SIZE); // // End of PEI phase signal // + PERF_EVENT_SIGNAL_BEGIN (gEndOfPeiSignalPpi.Guid); Status = PeiServicesInstallPpi (&gEndOfPeiSignalPpi); + PERF_EVENT_SIGNAL_END (gEndOfPeiSignalPpi.Guid); ASSERT_EFI_ERROR (Status); AsmWriteCr3 (PageTables); @@ -120,12 +336,20 @@ HandOffToDxeCore ( Status = PeiServicesAllocatePages ( EfiBootServicesData, - EFI_SIZE_TO_PAGES((SizeOfTemplate + sizeof (X64_IDT_GATE_DESCRIPTOR)) * IDT_ENTRY_COUNT), + EFI_SIZE_TO_PAGES(sizeof (X64_IDT_TABLE) + SizeOfTemplate * IDT_ENTRY_COUNT), &VectorAddress ); ASSERT_EFI_ERROR (Status); - IdtTable = (X64_IDT_GATE_DESCRIPTOR *) (UINTN) (VectorAddress + SizeOfTemplate * IDT_ENTRY_COUNT); + // + // Store EFI_PEI_SERVICES** in the 4 bytes immediately preceding IDT to avoid that + // it may not be gotten correctly after IDT register is re-written. + // + IdtTableForX64 = (X64_IDT_TABLE *) (UINTN) VectorAddress; + IdtTableForX64->PeiService = GetPeiServicesTablePointer (); + + VectorAddress = (EFI_PHYSICAL_ADDRESS) (UINTN) (IdtTableForX64 + 1); + IdtTable = IdtTableForX64->IdtTable; for (Index = 0; Index < IDT_ENTRY_COUNT; Index++) { IdtTable[Index].Ia32IdtEntry.Bits.GateType = 0x8e; IdtTable[Index].Ia32IdtEntry.Bits.Reserved_0 = 0; @@ -151,6 +375,14 @@ HandOffToDxeCore ( AsmWriteIdtr (&gLidtDescriptor); + DEBUG (( + DEBUG_INFO, + "%a() Stack Base: 0x%lx, Stack Size: 0x%x\n", + __FUNCTION__, + BaseOfStack, + STACK_SIZE + )); + // // Go to Long Mode and transfer control to DxeCore. // Interrupts will not get turned on until the CPU AP is loaded. @@ -164,6 +396,30 @@ HandOffToDxeCore ( TopOfStack ); } else { + // + // Get Vector Hand-off Info PPI and build Guided HOB + // + Status = PeiServicesLocatePpi ( + &gEfiVectorHandoffInfoPpiGuid, + 0, + NULL, + (VOID **)&VectorHandoffInfoPpi + ); + if (Status == EFI_SUCCESS) { + DEBUG ((EFI_D_INFO, "Vector Hand-off Info PPI is gotten, GUIDed HOB is created!\n")); + VectorInfo = VectorHandoffInfoPpi->Info; + Index = 1; + while (VectorInfo->Attribute != EFI_VECTOR_HANDOFF_LAST_ENTRY) { + VectorInfo ++; + Index ++; + } + BuildGuidDataHob ( + &gEfiVectorHandoffInfoPpiGuid, + VectorHandoffInfoPpi->Info, + sizeof (EFI_VECTOR_HANDOFF_INFO) * Index + ); + } + // // Compute the top of the stack we were allocated. Pre-allocate a UINTN // for safety. @@ -171,26 +427,62 @@ HandOffToDxeCore ( TopOfStack = BaseOfStack + EFI_SIZE_TO_PAGES (STACK_SIZE) * EFI_PAGE_SIZE - CPU_STACK_ALIGNMENT; TopOfStack = (EFI_PHYSICAL_ADDRESS) (UINTN) ALIGN_POINTER (TopOfStack, CPU_STACK_ALIGNMENT); + PageTables = 0; + BuildPageTablesIa32Pae = ToBuildPageTable (); + if (BuildPageTablesIa32Pae) { + PageTables = Create4GPageTablesIa32Pae (BaseOfStack, STACK_SIZE); + if (IsExecuteDisableBitAvailable ()) { + EnableExecuteDisableBit(); + } + } + // // End of PEI phase signal // + PERF_EVENT_SIGNAL_BEGIN (gEndOfPeiSignalPpi.Guid); Status = PeiServicesInstallPpi (&gEndOfPeiSignalPpi); + PERF_EVENT_SIGNAL_END (gEndOfPeiSignalPpi.Guid); ASSERT_EFI_ERROR (Status); + if (BuildPageTablesIa32Pae) { + AsmWriteCr3 (PageTables); + // + // Set Physical Address Extension (bit 5 of CR4). + // + AsmWriteCr4 (AsmReadCr4 () | BIT5); + } + // // Update the contents of BSP stack HOB to reflect the real stack info passed to DxeCore. // UpdateStackHob (BaseOfStack, STACK_SIZE); + DEBUG (( + DEBUG_INFO, + "%a() Stack Base: 0x%lx, Stack Size: 0x%x\n", + __FUNCTION__, + BaseOfStack, + STACK_SIZE + )); + // // Transfer the control to the entry point of DxeCore. // - SwitchStack ( - (SWITCH_STACK_ENTRY_POINT)(UINTN)DxeCoreEntryPoint, - HobList.Raw, - NULL, - (VOID *) (UINTN) TopOfStack - ); + if (BuildPageTablesIa32Pae) { + AsmEnablePaging32 ( + (SWITCH_STACK_ENTRY_POINT)(UINTN)DxeCoreEntryPoint, + HobList.Raw, + NULL, + (VOID *) (UINTN) TopOfStack + ); + } else { + SwitchStack ( + (SWITCH_STACK_ENTRY_POINT)(UINTN)DxeCoreEntryPoint, + HobList.Raw, + NULL, + (VOID *) (UINTN) TopOfStack + ); + } } }