/** Reads a bit field of a PCI configuration register. Reads the bit field in a 32-bit PCI configuration register. The bit field is specified by the StartBit and the EndBit. The value of the bit field is returned. If any reserved bits in Address are set, then ASSERT(). If StartBit is greater than 31, then ASSERT(). If EndBit is greater than 31, then ASSERT(). If EndBit is less than StartBit, then ASSERT(). @param Address PCI configuration register to read. @param StartBit The ordinal of the least significant bit in the bit field. Range 0..31. @param EndBit The ordinal of the most significant bit in the bit field. Range 0..31. @return The value of the bit field read from the PCI configuration register. **/ UINT32 EFIAPI PciSegmentBitFieldRead32 ( IN UINT64 Address, IN UINTN StartBit, IN UINTN EndBit ) { return BitFieldRead32 (PciSegmentRead32 (Address), StartBit, EndBit); }
/** Reads a bit field of a PCI configuration register. Reads the bit field in a 32-bit PCI configuration register. The bit field is specified by the StartBit and the EndBit. The value of the bit field is returned. If Address > 0x0FFFFFFF, then ASSERT(). If Address is not aligned on a 32-bit boundary, then ASSERT(). If StartBit is greater than 31, then ASSERT(). If EndBit is greater than 31, then ASSERT(). If EndBit is less than StartBit, then ASSERT(). @param Address The PCI configuration register to read. @param StartBit The ordinal of the least significant bit in the bit field. Range 0..31. @param EndBit The ordinal of the most significant bit in the bit field. Range 0..31. @return The value of the bit field read from the PCI configuration register. **/ UINT32 EFIAPI PciBitFieldRead32 ( IN UINTN Address, IN UINTN StartBit, IN UINTN EndBit ) { return BitFieldRead32 (PciRead32 (Address), StartBit, EndBit); }
/** Detect capability of XD feature for specified processor. This function detects capability of XD feature for specified processor. @param ProcessorNumber The handle number of specified processor. **/ VOID XdDetect ( UINTN ProcessorNumber ) { EFI_CPUID_REGISTER *CpuidRegisters; // // Check whether 0x80000001 is supported by CPUID // if (GetNumberOfCpuidLeafs (ProcessorNumber, ExtendedCpuidLeaf) > 2) { // // Check CPUID(0x80000001).EDX[20] // CpuidRegisters = GetProcessorCpuid (ProcessorNumber, EFI_CPUID_EXTENDED_CPU_SIG); ASSERT (CpuidRegisters != NULL); if (BitFieldRead32 (CpuidRegisters->RegEdx, N_CPUID_XD_BIT_AVAILABLE, N_CPUID_XD_BIT_AVAILABLE) == 1) { SetProcessorFeatureCapability (ProcessorNumber, ExecuteDisableBit, NULL); } } }
/** Create 4G PageTable in SMRAM. @param ExtraPages Additional page numbers besides for 4G memory @return PageTable Address **/ UINT32 Gen4GPageTable ( IN UINTN ExtraPages ) { VOID *PageTable; UINTN Index; UINT64 *Pte; UINTN PagesNeeded; UINTN Low2MBoundary; UINTN High2MBoundary; UINTN Pages; UINTN GuardPage; UINT64 *Pdpte; UINTN PageIndex; UINTN PageAddress; Low2MBoundary = 0; High2MBoundary = 0; PagesNeeded = 0; if (FeaturePcdGet (PcdCpuSmmStackGuard)) { // // Add one more page for known good stack, then find the lower 2MB aligned address. // Low2MBoundary = (mSmmStackArrayBase + EFI_PAGE_SIZE) & ~(SIZE_2MB-1); // // Add two more pages for known good stack and stack guard page, // then find the lower 2MB aligned address. // High2MBoundary = (mSmmStackArrayEnd - mSmmStackSize + EFI_PAGE_SIZE * 2) & ~(SIZE_2MB-1); PagesNeeded = ((High2MBoundary - Low2MBoundary) / SIZE_2MB) + 1; } // // Allocate the page table // PageTable = AllocatePages (ExtraPages + 5 + PagesNeeded); ASSERT (PageTable != NULL); PageTable = (VOID *)((UINTN)PageTable + EFI_PAGES_TO_SIZE (ExtraPages)); Pte = (UINT64*)PageTable; // // Zero out all page table entries first // ZeroMem (Pte, EFI_PAGES_TO_SIZE (1)); // // Set Page Directory Pointers // for (Index = 0; Index < 4; Index++) { Pte[Index] = (UINTN)PageTable + EFI_PAGE_SIZE * (Index + 1) + IA32_PG_P; } Pte += EFI_PAGE_SIZE / sizeof (*Pte); // // Fill in Page Directory Entries // for (Index = 0; Index < EFI_PAGE_SIZE * 4 / sizeof (*Pte); Index++) { Pte[Index] = (Index << 21) + IA32_PG_PS + IA32_PG_RW + IA32_PG_P; } if (FeaturePcdGet (PcdCpuSmmStackGuard)) { Pages = (UINTN)PageTable + EFI_PAGES_TO_SIZE (5); GuardPage = mSmmStackArrayBase + EFI_PAGE_SIZE; Pdpte = (UINT64*)PageTable; for (PageIndex = Low2MBoundary; PageIndex <= High2MBoundary; PageIndex += SIZE_2MB) { Pte = (UINT64*)(UINTN)(Pdpte[BitFieldRead32 ((UINT32)PageIndex, 30, 31)] & ~(EFI_PAGE_SIZE - 1)); Pte[BitFieldRead32 ((UINT32)PageIndex, 21, 29)] = (UINT64)Pages + IA32_PG_RW + IA32_PG_P; // // Fill in Page Table Entries // Pte = (UINT64*)Pages; PageAddress = PageIndex; for (Index = 0; Index < EFI_PAGE_SIZE / sizeof (*Pte); Index++) { if (PageAddress == GuardPage) { // // Mark the guard page as non-present // Pte[Index] = PageAddress; GuardPage += mSmmStackSize; if (GuardPage > mSmmStackArrayEnd) { GuardPage = 0; } } else { Pte[Index] = PageAddress + IA32_PG_RW + IA32_PG_P; } PageAddress+= EFI_PAGE_SIZE; } Pages += EFI_PAGE_SIZE; } } return (UINT32)(UINTN)PageTable; }
/** Create 4G PageTable in SMRAM. @param[in] Is32BitPageTable Whether the page table is 32-bit PAE @return PageTable Address **/ UINT32 Gen4GPageTable ( IN BOOLEAN Is32BitPageTable ) { VOID *PageTable; UINTN Index; UINT64 *Pte; UINTN PagesNeeded; UINTN Low2MBoundary; UINTN High2MBoundary; UINTN Pages; UINTN GuardPage; UINT64 *Pdpte; UINTN PageIndex; UINTN PageAddress; Low2MBoundary = 0; High2MBoundary = 0; PagesNeeded = 0; if (FeaturePcdGet (PcdCpuSmmStackGuard)) { // // Add one more page for known good stack, then find the lower 2MB aligned address. // Low2MBoundary = (mSmmStackArrayBase + EFI_PAGE_SIZE) & ~(SIZE_2MB-1); // // Add two more pages for known good stack and stack guard page, // then find the lower 2MB aligned address. // High2MBoundary = (mSmmStackArrayEnd - mSmmStackSize + EFI_PAGE_SIZE * 2) & ~(SIZE_2MB-1); PagesNeeded = ((High2MBoundary - Low2MBoundary) / SIZE_2MB) + 1; } // // Allocate the page table // PageTable = AllocatePageTableMemory (5 + PagesNeeded); ASSERT (PageTable != NULL); PageTable = (VOID *)((UINTN)PageTable); Pte = (UINT64*)PageTable; // // Zero out all page table entries first // ZeroMem (Pte, EFI_PAGES_TO_SIZE (1)); // // Set Page Directory Pointers // for (Index = 0; Index < 4; Index++) { Pte[Index] = ((UINTN)PageTable + EFI_PAGE_SIZE * (Index + 1)) | mAddressEncMask | (Is32BitPageTable ? IA32_PAE_PDPTE_ATTRIBUTE_BITS : PAGE_ATTRIBUTE_BITS); } Pte += EFI_PAGE_SIZE / sizeof (*Pte); // // Fill in Page Directory Entries // for (Index = 0; Index < EFI_PAGE_SIZE * 4 / sizeof (*Pte); Index++) { Pte[Index] = (Index << 21) | mAddressEncMask | IA32_PG_PS | PAGE_ATTRIBUTE_BITS; } Pdpte = (UINT64*)PageTable; if (FeaturePcdGet (PcdCpuSmmStackGuard)) { Pages = (UINTN)PageTable + EFI_PAGES_TO_SIZE (5); GuardPage = mSmmStackArrayBase + EFI_PAGE_SIZE; for (PageIndex = Low2MBoundary; PageIndex <= High2MBoundary; PageIndex += SIZE_2MB) { Pte = (UINT64*)(UINTN)(Pdpte[BitFieldRead32 ((UINT32)PageIndex, 30, 31)] & ~mAddressEncMask & ~(EFI_PAGE_SIZE - 1)); Pte[BitFieldRead32 ((UINT32)PageIndex, 21, 29)] = (UINT64)Pages | mAddressEncMask | PAGE_ATTRIBUTE_BITS; // // Fill in Page Table Entries // Pte = (UINT64*)Pages; PageAddress = PageIndex; for (Index = 0; Index < EFI_PAGE_SIZE / sizeof (*Pte); Index++) { if (PageAddress == GuardPage) { // // Mark the guard page as non-present // Pte[Index] = PageAddress | mAddressEncMask; GuardPage += mSmmStackSize; if (GuardPage > mSmmStackArrayEnd) { GuardPage = 0; } } else { Pte[Index] = PageAddress | mAddressEncMask | PAGE_ATTRIBUTE_BITS; } PageAddress+= EFI_PAGE_SIZE; } Pages += EFI_PAGE_SIZE; } } if ((PcdGet8 (PcdNullPointerDetectionPropertyMask) & BIT1) != 0) { Pte = (UINT64*)(UINTN)(Pdpte[0] & ~mAddressEncMask & ~(EFI_PAGE_SIZE - 1)); if ((Pte[0] & IA32_PG_PS) == 0) { // 4K-page entries are already mapped. Just hide the first one anyway. Pte = (UINT64*)(UINTN)(Pte[0] & ~mAddressEncMask & ~(EFI_PAGE_SIZE - 1)); Pte[0] &= ~(UINT64)IA32_PG_P; // Hide page 0 } else { // Create 4K-page entries Pages = (UINTN)AllocatePageTableMemory (1); ASSERT (Pages != 0); Pte[0] = (UINT64)(Pages | mAddressEncMask | PAGE_ATTRIBUTE_BITS); Pte = (UINT64*)Pages; PageAddress = 0; Pte[0] = PageAddress | mAddressEncMask; // Hide page 0 but present left for (Index = 1; Index < EFI_PAGE_SIZE / sizeof (*Pte); Index++) { PageAddress += EFI_PAGE_SIZE; Pte[Index] = PageAddress | mAddressEncMask | PAGE_ATTRIBUTE_BITS; } } } return (UINT32)(UINTN)PageTable; }