Reviewed-by: Chao Li <lichao@loongson.cn>
Optimize the process of converting huge pages to page table entries. Cc: Ard Biesheuvel <ardb+tianocore@kernel.org> Cc: Bibo Mao <maobibo@loongson.cn> Cc: Chao Li <lichao@loongson.cn> Cc: Leif Lindholm <quic_llindhol@quicinc.com> Cc: Liming Gao <gaoliming@byosoft.com.cn> Cc: Michael D Kinney <michael.d.kinney@intel.com> Signed-off-by: xianglai li <lixianglai@loongson.cn> --- .../Library/MmuLib/MmuLibCore.c | 109 +++++++++++++----- .../LoongArchQemuPkg/Library/MmuLib/page.h | 3 + 2 files changed, 82 insertions(+), 30 deletions(-) diff --git a/Platform/Loongson/LoongArchQemuPkg/Library/MmuLib/MmuLibCore.c b/Platform/Loongson/LoongArchQemuPkg/Library/MmuLib/MmuLibCore.c index 9e2bd3344a..dac38c63f2 100644 --- a/Platform/Loongson/LoongArchQemuPkg/Library/MmuLib/MmuLibCore.c +++ b/Platform/Loongson/LoongArchQemuPkg/Library/MmuLib/MmuLibCore.c @@ -449,6 +449,29 @@ GetPteAddress ( return PteOffset (Pmd, Address); } +/** + Gets the Attributes of Huge Page. + + @param Pmd A pointer to the page middle directory. + + @retval Value of Attributes. +**/ +UINTN +GetHugePageAttributes ( + IN PMD *Pmd + ) +{ + UINTN Attributes; + UINTN GlobalFlag; + UINTN HugeVal = PMD_VAL(*Pmd); + + Attributes = HugeVal & (~HUGEP_PAGE_MASK); + GlobalFlag = ((Attributes & (1 << PAGE_HGLOBAL_SHIFT)) >> PAGE_HGLOBAL_SHIFT) << PAGE_GLOBAL_SHIFT; + Attributes &= ~(1 << PAGE_HGLOBAL_SHIFT); + Attributes |= GlobalFlag; + return Attributes; +} + /** Establishes a page table entry based on the specified memory region. @@ -477,13 +500,13 @@ MemoryMapPteRange ( return EFI_OUT_OF_RESOURCES; } + DEBUG ((DEBUG_VERBOSE, + "%a %d Address %p End %p Attributes %llx\n", + __func__, __LINE__, Address, End, Attributes)); + do { UpDate = FALSE; PteVal = MAKE_PTE (Address, Attributes); - DEBUG ((DEBUG_VERBOSE, - "%a %d Address %p PGD_INDEX %p PUD_INDEX %p PMD_INDEX %p PTE_INDEX %p MAKE_PTE %p\n", - __func__, __LINE__, Address, PGD_INDEX (Address), PUD_INDEX (Address), PMD_INDEX (Address), - PTE_INDEX (Address), PteVal)); if ((!pte_none (*Pte)) && (PTE_VAL(*Pte) != PTE_VAL(PteVal))) @@ -500,6 +523,55 @@ MemoryMapPteRange ( return EFI_SUCCESS; } +/** + Convert Huge Page to Page. + + @param Pmd A pointer to the page middle directory. + @param Address The memory space start address. + @param End The end address of the memory space. + @param Attributes Memory space Attributes. + + @retval EFI_SUCCESS The page table entry was created successfully. + @retval EFI_OUT_OF_RESOURCES Page table entry establishment failed due to resource exhaustion. +**/ +EFI_STATUS +ConvertHugePageToPage ( + IN PMD *Pmd, + IN UINTN Address, + IN UINTN End, + IN UINTN Attributes + ) +{ + UINTN OldAttributes; + UINTN HugePageEnd; + UINTN HugePageStart; + EFI_STATUS Status; + + if ((pmd_none (*Pmd)) || + (!IS_HUGE_PAGE (Pmd->PmdVal))) + { + Status |= MemoryMapPteRange (Pmd, Address, End, Attributes); + } else { + OldAttributes = GetHugePageAttributes(Pmd); + SetPmd (Pmd, (PTE *)PcdGet64 (PcdInvalidPte)); + HugePageStart = Address & PMD_MASK; + HugePageEnd = HugePageStart + HUGE_PAGE_SIZE; + ASSERT (HugePageEnd >= End); + + if (Address > HugePageStart) { + Status |= MemoryMapPteRange (Pmd, HugePageStart, Address, OldAttributes); + } + + Status |= MemoryMapPteRange (Pmd, Address, End, Attributes); + + if (End < HugePageEnd) { + Status |= MemoryMapPteRange (Pmd, End, HugePageEnd, OldAttributes); + } + } + + return Status; +} + /** Establishes a page middle directory based on the specified memory region. @@ -520,10 +592,7 @@ MemoryMapPmdRange ( ) { PMD *Pmd; - PTE *Pte; UINTN Next; - UINTN AddressStart_HugePage; - UINTN AddressEnd_HugePage; Pmd = PmdAllocGet (Pud, Address); if (!Pmd) { @@ -534,7 +603,7 @@ MemoryMapPmdRange ( Next = PMD_ADDRESS_END (Address, End); if (((Address & (~PMD_MASK)) == 0) && ((Next & (~PMD_MASK)) == 0) && - (pmd_none (*Pmd))) + (pmd_none (*Pmd) || IS_HUGE_PAGE (Pmd->PmdVal))) { DEBUG ((DEBUG_VERBOSE, "%a %d Address %p PGD_INDEX %p PUD_INDEX %p PMD_INDEX %p MAKE_HUGE_PTE %p\n", @@ -543,28 +612,7 @@ MemoryMapPmdRange ( SetPmd (Pmd, (PTE *)MAKE_HUGE_PTE (Address, Attributes)); } else { - if ((pmd_none (*Pmd)) || - ((!pmd_none (*Pmd)) && - (!IS_HUGE_PAGE (Pmd->PmdVal)))) - { - if (MemoryMapPteRange (Pmd, Address, Next, Attributes)) { - return EFI_OUT_OF_RESOURCES; - } - } else { - SetPmd (Pmd, (PTE *)PcdGet64 (PcdInvalidPte)); - AddressStart_HugePage = Address & PMD_MASK; - AddressEnd_HugePage = AddressStart_HugePage + HUGE_PAGE_SIZE; - if (MemoryMapPteRange (Pmd, AddressStart_HugePage, AddressEnd_HugePage, Attributes)) { - return EFI_OUT_OF_RESOURCES; - } - Pte = GetPteAddress (AddressStart_HugePage); - if (Pte == NULL) { - continue ; - } - if (AddressEnd_HugePage > End) { - Next = End; - } - } + ConvertHugePageToPage (Pmd, Address, Next, Attributes); } } while (Pmd++, Address = Next, Address != End); @@ -788,6 +836,7 @@ LoongArchSetMemoryAttributes ( Attributes = EfiAttributeToLoongArchAttribute (Attributes); DEBUG ((DEBUG_VERBOSE, "%a %d %p %p %p.\n", __func__, __LINE__, BaseAddress , Length, Attributes)); MemoryMapPageRange (BaseAddress, BaseAddress + Length, Attributes); + DEBUG ((DEBUG_VERBOSE, "%a %d end.\n", __func__, __LINE__)); return EFI_SUCCESS; } diff --git a/Platform/Loongson/LoongArchQemuPkg/Library/MmuLib/page.h b/Platform/Loongson/LoongArchQemuPkg/Library/MmuLib/page.h index 84c7c13919..927aeb018d 100644 --- a/Platform/Loongson/LoongArchQemuPkg/Library/MmuLib/page.h +++ b/Platform/Loongson/LoongArchQemuPkg/Library/MmuLib/page.h @@ -42,6 +42,9 @@ #define PFN_MASK (~(((UINTN)(1) << (EFI_PAGE_SHIFT)) - 1) & \ (((UINTN)(1) << (PAGE_PFN_END_SHIFT)) - 1)) +#define HUGEP_PAGE_MASK (~(((UINTN)(1) << (PMD_SHIFT)) - 1) & \ + (((UINTN)(1) << (PAGE_PFN_END_SHIFT)) - 1)) + typedef struct { UINTN PgdVal; } PGD; typedef struct { UINTN PudVal; } PUD; typedef struct { UINTN PmdVal; } PMD;