From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: from mail-it0-x232.google.com (mail-it0-x232.google.com [IPv6:2607:f8b0:4001:c0b::232]) (using TLSv1.2 with cipher ECDHE-RSA-AES128-GCM-SHA256 (128/128 bits)) (No client certificate requested) by ml01.01.org (Postfix) with ESMTPS id 5365080289 for ; Mon, 6 Mar 2017 08:06:00 -0800 (PST) Received: by mail-it0-x232.google.com with SMTP id 203so52008672ith.0 for ; Mon, 06 Mar 2017 08:06:00 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=linaro.org; s=google; h=mime-version:in-reply-to:references:from:date:message-id:subject:to :cc; bh=RegNUKwOW+Qe/SDrFNutRidQZRP9kM9AiL33lUa1XiU=; b=Xed/b3E3BGeBwBIibHTXpqQUtN6lnjt6F+QU4rfLE/5RS+ovAvbQuJxPlb572OA/FR t49mzL1uGSTfY/1g20ZPhdqxk87aaLU6LVRxwHM4HWYPrp3ZF1jnpMCMmaGsp0Nl52v+ w9GhtQb9Q4DEHebzCx0xT4uodFooulhsWiQ80= X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:mime-version:in-reply-to:references:from:date :message-id:subject:to:cc; bh=RegNUKwOW+Qe/SDrFNutRidQZRP9kM9AiL33lUa1XiU=; b=sC+iXAy4LYQKrifz98KcTGFSMwVCVPtFzmQagg71akhDaCGEhHQEnNC4nwmJmGiKIx dIZhu5gLu9mB1W2JSSfL6dLFzidCvA45NmkEs6BjCxumjxzVj8XFSlizMyQNG3suoXyD xYv2zvTTG35aMnYyWICRmNXnrTrmLjCQkwT3KSaSubCz/D/JCbhSgK+5QXah7dFhB+Qj yTQxyAirCI+OEiiakKjEuvJO73ceidS/4IqDq1Go586n7RD8upXshTmNkq4C74WN5ZBI kWY4/M4X5bpxES/pW8+ZbH7Hvotp6bchJ9yoCZLfFydrVbivZkFa8LAxF7k2YwcIB4KK aKhw== X-Gm-Message-State: AMke39nv2qHdrpaddFrNB9UCYRb9y3y4O61s1A46QM9o7d4syyuCyrMxj8au87O91APyUt/hKcnCYo+kusRZZIQ9 X-Received: by 10.36.23.74 with SMTP id 71mr15488664ith.37.1488816359059; Mon, 06 Mar 2017 08:05:59 -0800 (PST) MIME-Version: 1.0 Received: by 10.107.10.27 with HTTP; Mon, 6 Mar 2017 08:05:58 -0800 (PST) In-Reply-To: <20170306160325.GX16034@bivouac.eciton.net> References: <1488385903-30267-1-git-send-email-ard.biesheuvel@linaro.org> <1488385903-30267-3-git-send-email-ard.biesheuvel@linaro.org> <20170306160325.GX16034@bivouac.eciton.net> From: Ard Biesheuvel Date: Mon, 6 Mar 2017 17:05:58 +0100 Message-ID: To: Leif Lindholm Cc: "edk2-devel@lists.01.org" , Laszlo Ersek Subject: Re: [PATCH 2/5] ArmPkg: move ARM version of SetMemoryAttributes to ArmMmuLib X-BeenThere: edk2-devel@lists.01.org X-Mailman-Version: 2.1.21 Precedence: list List-Id: EDK II Development List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Mon, 06 Mar 2017 16:06:00 -0000 Content-Type: text/plain; charset=UTF-8 On 6 March 2017 at 17:03, Leif Lindholm wrote: > n Wed, Mar 01, 2017 at 04:31:40PM +0000, Ard Biesheuvel wrote: >> ... where it belongs, since AARCH64 already keeps it there, and >> non DXE users of ArmMmuLib (such as DxeIpl, for the non-executable >> stack) may need its functionality as well. >> >> While at it, rename SetMemoryAttributes to ArmSetMemoryAttributes, >> and make any functions that are not exported STATIC. Also, replace >> an explicit gBS->AllocatePages() call [which is DXE specific] with >> MemoryAllocationLib::AllocatePages(). >> >> Contributed-under: TianoCore Contribution Agreement 1.0 >> Signed-off-by: Ard Biesheuvel >> --- >> ArmPkg/Drivers/CpuDxe/Arm/Mmu.c | 368 -------------------- >> ArmPkg/Drivers/CpuDxe/CpuDxe.h | 14 +- >> ArmPkg/Drivers/CpuDxe/CpuMmuCommon.c | 2 +- >> ArmPkg/Include/Library/ArmMmuLib.h | 8 + >> ArmPkg/Library/ArmMmuLib/AArch64/ArmMmuLibCore.c | 2 +- >> ArmPkg/Library/ArmMmuLib/Arm/ArmMmuLibCore.c | 368 ++++++++++++++++++++ >> 6 files changed, 379 insertions(+), 383 deletions(-) >> >> diff --git a/ArmPkg/Drivers/CpuDxe/Arm/Mmu.c b/ArmPkg/Drivers/CpuDxe/Arm/Mmu.c >> index 6322d301060e..b985dd743f02 100644 >> --- a/ArmPkg/Drivers/CpuDxe/Arm/Mmu.c >> +++ b/ArmPkg/Drivers/CpuDxe/Arm/Mmu.c >> @@ -343,374 +343,6 @@ SyncCacheConfig ( >> return EFI_SUCCESS; >> } >> >> - >> - >> -EFI_STATUS >> -UpdatePageEntries ( >> - IN EFI_PHYSICAL_ADDRESS BaseAddress, >> - IN UINT64 Length, >> - IN UINT64 Attributes, >> - IN EFI_PHYSICAL_ADDRESS VirtualMask >> - ) >> -{ >> - EFI_STATUS Status; >> - UINT32 EntryValue; >> - UINT32 EntryMask; >> - UINT32 FirstLevelIdx; >> - UINT32 Offset; >> - UINT32 NumPageEntries; >> - UINT32 Descriptor; >> - UINT32 p; >> - UINT32 PageTableIndex; >> - UINT32 PageTableEntry; >> - UINT32 CurrentPageTableEntry; >> - VOID *Mva; >> - >> - volatile ARM_FIRST_LEVEL_DESCRIPTOR *FirstLevelTable; >> - volatile ARM_PAGE_TABLE_ENTRY *PageTable; >> - >> - Status = EFI_SUCCESS; >> - >> - // EntryMask: bitmask of values to change (1 = change this value, 0 = leave alone) >> - // EntryValue: values at bit positions specified by EntryMask >> - EntryMask = TT_DESCRIPTOR_PAGE_TYPE_MASK | TT_DESCRIPTOR_PAGE_AP_MASK; >> - if ((Attributes & EFI_MEMORY_XP) != 0) { >> - EntryValue = TT_DESCRIPTOR_PAGE_TYPE_PAGE_XN; >> - } else { >> - EntryValue = TT_DESCRIPTOR_PAGE_TYPE_PAGE; >> - } >> - >> - // Although the PI spec is unclear on this the GCD guarantees that only >> - // one Attribute bit is set at a time, so we can safely use a switch statement >> - if ((Attributes & EFI_MEMORY_UC) != 0) { >> - // modify cacheability attributes >> - EntryMask |= TT_DESCRIPTOR_PAGE_CACHE_POLICY_MASK; >> - // map to strongly ordered >> - EntryValue |= TT_DESCRIPTOR_PAGE_CACHE_POLICY_STRONGLY_ORDERED; // TEX[2:0] = 0, C=0, B=0 >> - } else if ((Attributes & EFI_MEMORY_WC) != 0) { >> - // modify cacheability attributes >> - EntryMask |= TT_DESCRIPTOR_PAGE_CACHE_POLICY_MASK; >> - // map to normal non-cachable >> - EntryValue |= TT_DESCRIPTOR_PAGE_CACHE_POLICY_NON_CACHEABLE; // TEX [2:0]= 001 = 0x2, B=0, C=0 >> - } else if ((Attributes & EFI_MEMORY_WT) != 0) { >> - // modify cacheability attributes >> - EntryMask |= TT_DESCRIPTOR_PAGE_CACHE_POLICY_MASK; >> - // write through with no-allocate >> - EntryValue |= TT_DESCRIPTOR_PAGE_CACHE_POLICY_WRITE_THROUGH_NO_ALLOC; // TEX [2:0] = 0, C=1, B=0 >> - } else if ((Attributes & EFI_MEMORY_WB) != 0) { >> - // modify cacheability attributes >> - EntryMask |= TT_DESCRIPTOR_PAGE_CACHE_POLICY_MASK; >> - // write back (with allocate) >> - EntryValue |= TT_DESCRIPTOR_PAGE_CACHE_POLICY_WRITE_BACK_ALLOC; // TEX [2:0] = 001, C=1, B=1 >> - } >> - >> - if ((Attributes & EFI_MEMORY_RO) != 0) { >> - EntryValue |= TT_DESCRIPTOR_PAGE_AP_RO_RO; >> - } else { >> - EntryValue |= TT_DESCRIPTOR_PAGE_AP_RW_RW; >> - } >> - >> - // Obtain page table base >> - FirstLevelTable = (ARM_FIRST_LEVEL_DESCRIPTOR *)ArmGetTTBR0BaseAddress (); >> - >> - // Calculate number of 4KB page table entries to change >> - NumPageEntries = Length / TT_DESCRIPTOR_PAGE_SIZE; >> - >> - // Iterate for the number of 4KB pages to change >> - Offset = 0; >> - for(p = 0; p < NumPageEntries; p++) { >> - // Calculate index into first level translation table for page table value >> - >> - FirstLevelIdx = TT_DESCRIPTOR_SECTION_BASE_ADDRESS(BaseAddress + Offset) >> TT_DESCRIPTOR_SECTION_BASE_SHIFT; >> - ASSERT (FirstLevelIdx < TRANSLATION_TABLE_SECTION_COUNT); >> - >> - // Read the descriptor from the first level page table >> - Descriptor = FirstLevelTable[FirstLevelIdx]; >> - >> - // Does this descriptor need to be converted from section entry to 4K pages? >> - if (!TT_DESCRIPTOR_SECTION_TYPE_IS_PAGE_TABLE(Descriptor)) { >> - Status = ConvertSectionToPages (FirstLevelIdx << TT_DESCRIPTOR_SECTION_BASE_SHIFT); >> - if (EFI_ERROR(Status)) { >> - // Exit for loop >> - break; >> - } >> - >> - // Re-read descriptor >> - Descriptor = FirstLevelTable[FirstLevelIdx]; >> - } >> - >> - // Obtain page table base address >> - PageTable = (ARM_PAGE_TABLE_ENTRY *)TT_DESCRIPTOR_PAGE_BASE_ADDRESS(Descriptor); >> - >> - // Calculate index into the page table >> - PageTableIndex = ((BaseAddress + Offset) & TT_DESCRIPTOR_PAGE_INDEX_MASK) >> TT_DESCRIPTOR_PAGE_BASE_SHIFT; >> - ASSERT (PageTableIndex < TRANSLATION_TABLE_PAGE_COUNT); >> - >> - // Get the entry >> - CurrentPageTableEntry = PageTable[PageTableIndex]; >> - >> - // Mask off appropriate fields >> - PageTableEntry = CurrentPageTableEntry & ~EntryMask; >> - >> - // Mask in new attributes and/or permissions >> - PageTableEntry |= EntryValue; >> - >> - if (VirtualMask != 0) { >> - // Make this virtual address point at a physical page >> - PageTableEntry &= ~VirtualMask; >> - } >> - >> - if (CurrentPageTableEntry != PageTableEntry) { >> - Mva = (VOID *)(UINTN)((((UINTN)FirstLevelIdx) << TT_DESCRIPTOR_SECTION_BASE_SHIFT) + (PageTableIndex << TT_DESCRIPTOR_PAGE_BASE_SHIFT)); >> - if ((CurrentPageTableEntry & TT_DESCRIPTOR_PAGE_CACHEABLE_MASK) == TT_DESCRIPTOR_PAGE_CACHEABLE_MASK) { >> - // The current section mapping is cacheable so Clean/Invalidate the MVA of the page >> - // Note assumes switch(Attributes), not ARMv7 possibilities >> - WriteBackInvalidateDataCacheRange (Mva, TT_DESCRIPTOR_PAGE_SIZE); >> - } >> - >> - // Only need to update if we are changing the entry >> - PageTable[PageTableIndex] = PageTableEntry; >> - ArmUpdateTranslationTableEntry ((VOID *)&PageTable[PageTableIndex], Mva); >> - } >> - >> - Status = EFI_SUCCESS; >> - Offset += TT_DESCRIPTOR_PAGE_SIZE; >> - >> - } // End first level translation table loop >> - >> - return Status; >> -} >> - >> - >> - >> -EFI_STATUS >> -UpdateSectionEntries ( >> - IN EFI_PHYSICAL_ADDRESS BaseAddress, >> - IN UINT64 Length, >> - IN UINT64 Attributes, >> - IN EFI_PHYSICAL_ADDRESS VirtualMask >> - ) >> -{ >> - EFI_STATUS Status = EFI_SUCCESS; >> - UINT32 EntryMask; >> - UINT32 EntryValue; >> - UINT32 FirstLevelIdx; >> - UINT32 NumSections; >> - UINT32 i; >> - UINT32 CurrentDescriptor; >> - UINT32 Descriptor; >> - VOID *Mva; >> - volatile ARM_FIRST_LEVEL_DESCRIPTOR *FirstLevelTable; >> - >> - // EntryMask: bitmask of values to change (1 = change this value, 0 = leave alone) >> - // EntryValue: values at bit positions specified by EntryMask >> - >> - // Make sure we handle a section range that is unmapped >> - EntryMask = TT_DESCRIPTOR_SECTION_TYPE_MASK | TT_DESCRIPTOR_SECTION_XN_MASK | >> - TT_DESCRIPTOR_SECTION_AP_MASK; >> - EntryValue = TT_DESCRIPTOR_SECTION_TYPE_SECTION; >> - >> - // Although the PI spec is unclear on this the GCD guarantees that only >> - // one Attribute bit is set at a time, so we can safely use a switch statement >> - if ((Attributes & EFI_MEMORY_UC) != 0) { >> - // modify cacheability attributes >> - EntryMask |= TT_DESCRIPTOR_SECTION_CACHE_POLICY_MASK; >> - // map to strongly ordered >> - EntryValue |= TT_DESCRIPTOR_SECTION_CACHE_POLICY_STRONGLY_ORDERED; // TEX[2:0] = 0, C=0, B=0 >> - } else if ((Attributes & EFI_MEMORY_WC) != 0) { >> - // modify cacheability attributes >> - EntryMask |= TT_DESCRIPTOR_SECTION_CACHE_POLICY_MASK; >> - // map to normal non-cachable >> - EntryValue |= TT_DESCRIPTOR_SECTION_CACHE_POLICY_NON_CACHEABLE; // TEX [2:0]= 001 = 0x2, B=0, C=0 >> - } else if ((Attributes & EFI_MEMORY_WT) != 0) { >> - // modify cacheability attributes >> - EntryMask |= TT_DESCRIPTOR_SECTION_CACHE_POLICY_MASK; >> - // write through with no-allocate >> - EntryValue |= TT_DESCRIPTOR_SECTION_CACHE_POLICY_WRITE_THROUGH_NO_ALLOC; // TEX [2:0] = 0, C=1, B=0 >> - } else if ((Attributes & EFI_MEMORY_WB) != 0) { >> - // modify cacheability attributes >> - EntryMask |= TT_DESCRIPTOR_SECTION_CACHE_POLICY_MASK; >> - // write back (with allocate) >> - EntryValue |= TT_DESCRIPTOR_SECTION_CACHE_POLICY_WRITE_BACK_ALLOC; // TEX [2:0] = 001, C=1, B=1 >> - } >> - >> - if ((Attributes & EFI_MEMORY_RO) != 0) { >> - EntryValue |= TT_DESCRIPTOR_SECTION_AP_RO_RO; >> - } else { >> - EntryValue |= TT_DESCRIPTOR_SECTION_AP_RW_RW; >> - } >> - >> - if ((Attributes & EFI_MEMORY_XP) != 0) { >> - EntryValue |= TT_DESCRIPTOR_SECTION_XN_MASK; >> - } >> - >> - // obtain page table base >> - FirstLevelTable = (ARM_FIRST_LEVEL_DESCRIPTOR *)ArmGetTTBR0BaseAddress (); >> - >> - // calculate index into first level translation table for start of modification >> - FirstLevelIdx = TT_DESCRIPTOR_SECTION_BASE_ADDRESS(BaseAddress) >> TT_DESCRIPTOR_SECTION_BASE_SHIFT; >> - ASSERT (FirstLevelIdx < TRANSLATION_TABLE_SECTION_COUNT); >> - >> - // calculate number of 1MB first level entries this applies to >> - NumSections = Length / TT_DESCRIPTOR_SECTION_SIZE; >> - >> - // iterate through each descriptor >> - for(i=0; i> - CurrentDescriptor = FirstLevelTable[FirstLevelIdx + i]; >> - >> - // has this descriptor already been coverted to pages? >> - if (TT_DESCRIPTOR_SECTION_TYPE_IS_PAGE_TABLE(CurrentDescriptor)) { >> - // forward this 1MB range to page table function instead >> - Status = UpdatePageEntries ((FirstLevelIdx + i) << TT_DESCRIPTOR_SECTION_BASE_SHIFT, TT_DESCRIPTOR_SECTION_SIZE, Attributes, VirtualMask); >> - } else { >> - // still a section entry >> - >> - // mask off appropriate fields >> - Descriptor = CurrentDescriptor & ~EntryMask; >> - >> - // mask in new attributes and/or permissions >> - Descriptor |= EntryValue; >> - if (VirtualMask != 0) { >> - Descriptor &= ~VirtualMask; >> - } >> - >> - if (CurrentDescriptor != Descriptor) { >> - Mva = (VOID *)(UINTN)(((UINTN)FirstLevelTable) << TT_DESCRIPTOR_SECTION_BASE_SHIFT); >> - if ((CurrentDescriptor & TT_DESCRIPTOR_SECTION_CACHEABLE_MASK) == TT_DESCRIPTOR_SECTION_CACHEABLE_MASK) { >> - // The current section mapping is cacheable so Clean/Invalidate the MVA of the section >> - // Note assumes switch(Attributes), not ARMv7 possabilities >> - WriteBackInvalidateDataCacheRange (Mva, SIZE_1MB); >> - } >> - >> - // Only need to update if we are changing the descriptor >> - FirstLevelTable[FirstLevelIdx + i] = Descriptor; >> - ArmUpdateTranslationTableEntry ((VOID *)&FirstLevelTable[FirstLevelIdx + i], Mva); >> - } >> - >> - Status = EFI_SUCCESS; >> - } >> - } >> - >> - return Status; >> -} >> - >> -EFI_STATUS >> -ConvertSectionToPages ( >> - IN EFI_PHYSICAL_ADDRESS BaseAddress >> - ) >> -{ >> - EFI_STATUS Status; >> - EFI_PHYSICAL_ADDRESS PageTableAddr; >> - UINT32 FirstLevelIdx; >> - UINT32 SectionDescriptor; >> - UINT32 PageTableDescriptor; >> - UINT32 PageDescriptor; >> - UINT32 Index; >> - >> - volatile ARM_FIRST_LEVEL_DESCRIPTOR *FirstLevelTable; >> - volatile ARM_PAGE_TABLE_ENTRY *PageTable; >> - >> - DEBUG ((EFI_D_PAGE, "Converting section at 0x%x to pages\n", (UINTN)BaseAddress)); >> - >> - // Obtain page table base >> - FirstLevelTable = (ARM_FIRST_LEVEL_DESCRIPTOR *)ArmGetTTBR0BaseAddress (); >> - >> - // Calculate index into first level translation table for start of modification >> - FirstLevelIdx = TT_DESCRIPTOR_SECTION_BASE_ADDRESS(BaseAddress) >> TT_DESCRIPTOR_SECTION_BASE_SHIFT; >> - ASSERT (FirstLevelIdx < TRANSLATION_TABLE_SECTION_COUNT); >> - >> - // Get section attributes and convert to page attributes >> - SectionDescriptor = FirstLevelTable[FirstLevelIdx]; >> - PageDescriptor = TT_DESCRIPTOR_PAGE_TYPE_PAGE | ConvertSectionAttributesToPageAttributes (SectionDescriptor, FALSE); >> - >> - // Allocate a page table for the 4KB entries (we use up a full page even though we only need 1KB) >> - Status = gBS->AllocatePages (AllocateAnyPages, EfiBootServicesData, 1, &PageTableAddr); >> - if (EFI_ERROR(Status)) { >> - return Status; >> - } >> - >> - PageTable = (volatile ARM_PAGE_TABLE_ENTRY *)(UINTN)PageTableAddr; >> - >> - // Write the page table entries out >> - for (Index = 0; Index < TRANSLATION_TABLE_PAGE_COUNT; Index++) { >> - PageTable[Index] = TT_DESCRIPTOR_PAGE_BASE_ADDRESS(BaseAddress + (Index << 12)) | PageDescriptor; >> - } >> - >> - // Flush d-cache so descriptors make it back to uncached memory for subsequent table walks >> - WriteBackInvalidateDataCacheRange ((VOID *)(UINTN)PageTableAddr, TT_DESCRIPTOR_PAGE_SIZE); >> - >> - // Formulate page table entry, Domain=0, NS=0 >> - PageTableDescriptor = (((UINTN)PageTableAddr) & TT_DESCRIPTOR_SECTION_PAGETABLE_ADDRESS_MASK) | TT_DESCRIPTOR_SECTION_TYPE_PAGE_TABLE; >> - >> - // Write the page table entry out, replacing section entry >> - FirstLevelTable[FirstLevelIdx] = PageTableDescriptor; >> - >> - return EFI_SUCCESS; >> -} >> - >> - >> - >> -EFI_STATUS >> -SetMemoryAttributes ( >> - IN EFI_PHYSICAL_ADDRESS BaseAddress, >> - IN UINT64 Length, >> - IN UINT64 Attributes, >> - IN EFI_PHYSICAL_ADDRESS VirtualMask >> - ) >> -{ >> - EFI_STATUS Status; >> - UINT64 ChunkLength; >> - BOOLEAN FlushTlbs; >> - >> - FlushTlbs = FALSE; >> - while (Length > 0) { >> - if ((BaseAddress % TT_DESCRIPTOR_SECTION_SIZE == 0) && >> - Length >= TT_DESCRIPTOR_SECTION_SIZE) { >> - >> - ChunkLength = Length - Length % TT_DESCRIPTOR_SECTION_SIZE; >> - >> - DEBUG ((DEBUG_PAGE | DEBUG_INFO, >> - "SetMemoryAttributes(): MMU section 0x%lx length 0x%lx to %lx\n", >> - BaseAddress, ChunkLength, Attributes)); >> - >> - Status = UpdateSectionEntries (BaseAddress, ChunkLength, Attributes, >> - VirtualMask); >> - >> - FlushTlbs = TRUE; >> - } else { >> - >> - // >> - // Process page by page until the next section boundary, but only if >> - // we have more than a section's worth of area to deal with after that. >> - // >> - ChunkLength = TT_DESCRIPTOR_SECTION_SIZE - >> - (BaseAddress % TT_DESCRIPTOR_SECTION_SIZE); >> - if (ChunkLength + TT_DESCRIPTOR_SECTION_SIZE > Length) { >> - ChunkLength = Length; >> - } >> - >> - DEBUG ((DEBUG_PAGE | DEBUG_INFO, >> - "SetMemoryAttributes(): MMU page 0x%lx length 0x%lx to %lx\n", >> - BaseAddress, ChunkLength, Attributes)); >> - >> - Status = UpdatePageEntries (BaseAddress, ChunkLength, Attributes, >> - VirtualMask); >> - } >> - >> - if (EFI_ERROR (Status)) { >> - break; >> - } >> - >> - BaseAddress += ChunkLength; >> - Length -= ChunkLength; >> - } >> - >> - if (FlushTlbs) { >> - ArmInvalidateTlb (); >> - } >> - return Status; >> -} >> - >> UINT64 >> EfiAttributeToArmAttribute ( >> IN UINT64 EfiAttributes >> diff --git a/ArmPkg/Drivers/CpuDxe/CpuDxe.h b/ArmPkg/Drivers/CpuDxe/CpuDxe.h >> index a46db8d25754..a0f71e69ec09 100644 >> --- a/ArmPkg/Drivers/CpuDxe/CpuDxe.h >> +++ b/ArmPkg/Drivers/CpuDxe/CpuDxe.h >> @@ -19,6 +19,7 @@ >> #include >> >> #include >> +#include >> #include >> #include >> #include >> @@ -112,11 +113,6 @@ SyncCacheConfig ( >> IN EFI_CPU_ARCH_PROTOCOL *CpuProtocol >> ); >> >> -EFI_STATUS >> -ConvertSectionToPages ( >> - IN EFI_PHYSICAL_ADDRESS BaseAddress >> - ); >> - >> /** >> * Publish ARM Processor Data table in UEFI SYSTEM Table. >> * @param HobStart Pointer to the beginning of the HOB List from PEI. >> @@ -132,14 +128,6 @@ PublishArmProcessorTable( >> VOID >> ); >> >> -EFI_STATUS >> -SetMemoryAttributes ( >> - IN EFI_PHYSICAL_ADDRESS BaseAddress, >> - IN UINT64 Length, >> - IN UINT64 Attributes, >> - IN EFI_PHYSICAL_ADDRESS VirtualMask >> - ); >> - >> // The ARM Attributes might be defined on 64-bit (case of the long format description table) >> UINT64 >> EfiAttributeToArmAttribute ( >> diff --git a/ArmPkg/Drivers/CpuDxe/CpuMmuCommon.c b/ArmPkg/Drivers/CpuDxe/CpuMmuCommon.c >> index 0f36a058407a..d0a3fedd3aa7 100644 >> --- a/ArmPkg/Drivers/CpuDxe/CpuMmuCommon.c >> +++ b/ArmPkg/Drivers/CpuDxe/CpuMmuCommon.c >> @@ -210,7 +210,7 @@ CpuSetMemoryAttributes ( >> if (EFI_ERROR (Status) || (RegionArmAttributes != ArmAttributes) || >> ((BaseAddress + Length) > (RegionBaseAddress + RegionLength))) >> { >> - return SetMemoryAttributes (BaseAddress, Length, EfiAttributes, 0); >> + return ArmSetMemoryAttributes (BaseAddress, Length, EfiAttributes, 0); >> } else { >> return EFI_SUCCESS; >> } >> diff --git a/ArmPkg/Include/Library/ArmMmuLib.h b/ArmPkg/Include/Library/ArmMmuLib.h >> index c1d43872d548..d3a302fa8125 100644 >> --- a/ArmPkg/Include/Library/ArmMmuLib.h >> +++ b/ArmPkg/Include/Library/ArmMmuLib.h >> @@ -62,4 +62,12 @@ ArmReplaceLiveTranslationEntry ( >> IN UINT64 Value >> ); >> >> +EFI_STATUS >> +ArmSetMemoryAttributes ( >> + IN EFI_PHYSICAL_ADDRESS BaseAddress, >> + IN UINT64 Length, >> + IN UINT64 Attributes, >> + IN EFI_PHYSICAL_ADDRESS VirtualMask >> + ); >> + >> #endif >> diff --git a/ArmPkg/Library/ArmMmuLib/AArch64/ArmMmuLibCore.c b/ArmPkg/Library/ArmMmuLib/AArch64/ArmMmuLibCore.c >> index df170d20a2c2..77f108971f3e 100644 >> --- a/ArmPkg/Library/ArmMmuLib/AArch64/ArmMmuLibCore.c >> +++ b/ArmPkg/Library/ArmMmuLib/AArch64/ArmMmuLibCore.c >> @@ -447,7 +447,7 @@ GcdAttributeToPageAttribute ( >> } >> >> EFI_STATUS >> -SetMemoryAttributes ( >> +ArmSetMemoryAttributes ( >> IN EFI_PHYSICAL_ADDRESS BaseAddress, >> IN UINT64 Length, >> IN UINT64 Attributes, >> diff --git a/ArmPkg/Library/ArmMmuLib/Arm/ArmMmuLibCore.c b/ArmPkg/Library/ArmMmuLib/Arm/ArmMmuLibCore.c >> index 4b6f4ce392b7..93980d6d12db 100644 >> --- a/ArmPkg/Library/ArmMmuLib/Arm/ArmMmuLibCore.c >> +++ b/ArmPkg/Library/ArmMmuLib/Arm/ArmMmuLibCore.c >> @@ -16,6 +16,7 @@ >> #include >> #include >> #include >> +#include >> #include >> #include >> #include >> @@ -36,6 +37,12 @@ >> #define ID_MMFR0_SHR_IMP_HW_COHERENT 1 >> #define ID_MMFR0_SHR_IGNORED 0xf >> >> +// First Level Descriptors >> +typedef UINT32 ARM_FIRST_LEVEL_DESCRIPTOR; >> + >> +// Second Level Descriptors >> +typedef UINT32 ARM_PAGE_TABLE_ENTRY; >> + > > Copied from ArmPkg/Drivers/CpuDxe/Arm/Mmu.c, but not deleted there. > Can it be, or can it be moved out into a header somewhere? > > No other comments. > It is used in both places, so I'd need to put in in a header file ArmPkg/Include/Chipset/ArmV7Mmu.h comes to mind ... >> UINTN >> EFIAPI >> ArmReadIdMmfr0 ( >> @@ -406,6 +413,367 @@ ArmConfigureMmu ( >> return RETURN_SUCCESS; >> } >> >> +STATIC >> +EFI_STATUS >> +ConvertSectionToPages ( >> + IN EFI_PHYSICAL_ADDRESS BaseAddress >> + ) >> +{ >> + UINT32 FirstLevelIdx; >> + UINT32 SectionDescriptor; >> + UINT32 PageTableDescriptor; >> + UINT32 PageDescriptor; >> + UINT32 Index; >> + >> + volatile ARM_FIRST_LEVEL_DESCRIPTOR *FirstLevelTable; >> + volatile ARM_PAGE_TABLE_ENTRY *PageTable; >> + >> + DEBUG ((EFI_D_PAGE, "Converting section at 0x%x to pages\n", (UINTN)BaseAddress)); >> + >> + // Obtain page table base >> + FirstLevelTable = (ARM_FIRST_LEVEL_DESCRIPTOR *)ArmGetTTBR0BaseAddress (); >> + >> + // Calculate index into first level translation table for start of modification >> + FirstLevelIdx = TT_DESCRIPTOR_SECTION_BASE_ADDRESS(BaseAddress) >> TT_DESCRIPTOR_SECTION_BASE_SHIFT; >> + ASSERT (FirstLevelIdx < TRANSLATION_TABLE_SECTION_COUNT); >> + >> + // Get section attributes and convert to page attributes >> + SectionDescriptor = FirstLevelTable[FirstLevelIdx]; >> + PageDescriptor = TT_DESCRIPTOR_PAGE_TYPE_PAGE | ConvertSectionAttributesToPageAttributes (SectionDescriptor, FALSE); >> + >> + // Allocate a page table for the 4KB entries (we use up a full page even though we only need 1KB) >> + PageTable = (volatile ARM_PAGE_TABLE_ENTRY *)AllocatePages (1); >> + if (PageTable == NULL) { >> + return EFI_OUT_OF_RESOURCES; >> + } >> + >> + // Write the page table entries out >> + for (Index = 0; Index < TRANSLATION_TABLE_PAGE_COUNT; Index++) { >> + PageTable[Index] = TT_DESCRIPTOR_PAGE_BASE_ADDRESS(BaseAddress + (Index << 12)) | PageDescriptor; >> + } >> + >> + // Flush d-cache so descriptors make it back to uncached memory for subsequent table walks >> + WriteBackInvalidateDataCacheRange ((VOID *)PageTable, TT_DESCRIPTOR_PAGE_SIZE); >> + >> + // Formulate page table entry, Domain=0, NS=0 >> + PageTableDescriptor = (((UINTN)PageTable) & TT_DESCRIPTOR_SECTION_PAGETABLE_ADDRESS_MASK) | TT_DESCRIPTOR_SECTION_TYPE_PAGE_TABLE; >> + >> + // Write the page table entry out, replacing section entry >> + FirstLevelTable[FirstLevelIdx] = PageTableDescriptor; >> + >> + return EFI_SUCCESS; >> +} >> + >> +STATIC >> +EFI_STATUS >> +UpdatePageEntries ( >> + IN EFI_PHYSICAL_ADDRESS BaseAddress, >> + IN UINT64 Length, >> + IN UINT64 Attributes, >> + IN EFI_PHYSICAL_ADDRESS VirtualMask >> + ) >> +{ >> + EFI_STATUS Status; >> + UINT32 EntryValue; >> + UINT32 EntryMask; >> + UINT32 FirstLevelIdx; >> + UINT32 Offset; >> + UINT32 NumPageEntries; >> + UINT32 Descriptor; >> + UINT32 p; >> + UINT32 PageTableIndex; >> + UINT32 PageTableEntry; >> + UINT32 CurrentPageTableEntry; >> + VOID *Mva; >> + >> + volatile ARM_FIRST_LEVEL_DESCRIPTOR *FirstLevelTable; >> + volatile ARM_PAGE_TABLE_ENTRY *PageTable; >> + >> + Status = EFI_SUCCESS; >> + >> + // EntryMask: bitmask of values to change (1 = change this value, 0 = leave alone) >> + // EntryValue: values at bit positions specified by EntryMask >> + EntryMask = TT_DESCRIPTOR_PAGE_TYPE_MASK | TT_DESCRIPTOR_PAGE_AP_MASK; >> + if ((Attributes & EFI_MEMORY_XP) != 0) { >> + EntryValue = TT_DESCRIPTOR_PAGE_TYPE_PAGE_XN; >> + } else { >> + EntryValue = TT_DESCRIPTOR_PAGE_TYPE_PAGE; >> + } >> + >> + // Although the PI spec is unclear on this the GCD guarantees that only >> + // one Attribute bit is set at a time, so we can safely use a switch statement >> + if ((Attributes & EFI_MEMORY_UC) != 0) { >> + // modify cacheability attributes >> + EntryMask |= TT_DESCRIPTOR_PAGE_CACHE_POLICY_MASK; >> + // map to strongly ordered >> + EntryValue |= TT_DESCRIPTOR_PAGE_CACHE_POLICY_STRONGLY_ORDERED; // TEX[2:0] = 0, C=0, B=0 >> + } else if ((Attributes & EFI_MEMORY_WC) != 0) { >> + // modify cacheability attributes >> + EntryMask |= TT_DESCRIPTOR_PAGE_CACHE_POLICY_MASK; >> + // map to normal non-cachable >> + EntryValue |= TT_DESCRIPTOR_PAGE_CACHE_POLICY_NON_CACHEABLE; // TEX [2:0]= 001 = 0x2, B=0, C=0 >> + } else if ((Attributes & EFI_MEMORY_WT) != 0) { >> + // modify cacheability attributes >> + EntryMask |= TT_DESCRIPTOR_PAGE_CACHE_POLICY_MASK; >> + // write through with no-allocate >> + EntryValue |= TT_DESCRIPTOR_PAGE_CACHE_POLICY_WRITE_THROUGH_NO_ALLOC; // TEX [2:0] = 0, C=1, B=0 >> + } else if ((Attributes & EFI_MEMORY_WB) != 0) { >> + // modify cacheability attributes >> + EntryMask |= TT_DESCRIPTOR_PAGE_CACHE_POLICY_MASK; >> + // write back (with allocate) >> + EntryValue |= TT_DESCRIPTOR_PAGE_CACHE_POLICY_WRITE_BACK_ALLOC; // TEX [2:0] = 001, C=1, B=1 >> + } >> + >> + if ((Attributes & EFI_MEMORY_RO) != 0) { >> + EntryValue |= TT_DESCRIPTOR_PAGE_AP_RO_RO; >> + } else { >> + EntryValue |= TT_DESCRIPTOR_PAGE_AP_RW_RW; >> + } >> + >> + // Obtain page table base >> + FirstLevelTable = (ARM_FIRST_LEVEL_DESCRIPTOR *)ArmGetTTBR0BaseAddress (); >> + >> + // Calculate number of 4KB page table entries to change >> + NumPageEntries = Length / TT_DESCRIPTOR_PAGE_SIZE; >> + >> + // Iterate for the number of 4KB pages to change >> + Offset = 0; >> + for(p = 0; p < NumPageEntries; p++) { >> + // Calculate index into first level translation table for page table value >> + >> + FirstLevelIdx = TT_DESCRIPTOR_SECTION_BASE_ADDRESS(BaseAddress + Offset) >> TT_DESCRIPTOR_SECTION_BASE_SHIFT; >> + ASSERT (FirstLevelIdx < TRANSLATION_TABLE_SECTION_COUNT); >> + >> + // Read the descriptor from the first level page table >> + Descriptor = FirstLevelTable[FirstLevelIdx]; >> + >> + // Does this descriptor need to be converted from section entry to 4K pages? >> + if (!TT_DESCRIPTOR_SECTION_TYPE_IS_PAGE_TABLE(Descriptor)) { >> + Status = ConvertSectionToPages (FirstLevelIdx << TT_DESCRIPTOR_SECTION_BASE_SHIFT); >> + if (EFI_ERROR(Status)) { >> + // Exit for loop >> + break; >> + } >> + >> + // Re-read descriptor >> + Descriptor = FirstLevelTable[FirstLevelIdx]; >> + } >> + >> + // Obtain page table base address >> + PageTable = (ARM_PAGE_TABLE_ENTRY *)TT_DESCRIPTOR_PAGE_BASE_ADDRESS(Descriptor); >> + >> + // Calculate index into the page table >> + PageTableIndex = ((BaseAddress + Offset) & TT_DESCRIPTOR_PAGE_INDEX_MASK) >> TT_DESCRIPTOR_PAGE_BASE_SHIFT; >> + ASSERT (PageTableIndex < TRANSLATION_TABLE_PAGE_COUNT); >> + >> + // Get the entry >> + CurrentPageTableEntry = PageTable[PageTableIndex]; >> + >> + // Mask off appropriate fields >> + PageTableEntry = CurrentPageTableEntry & ~EntryMask; >> + >> + // Mask in new attributes and/or permissions >> + PageTableEntry |= EntryValue; >> + >> + if (VirtualMask != 0) { >> + // Make this virtual address point at a physical page >> + PageTableEntry &= ~VirtualMask; >> + } >> + >> + if (CurrentPageTableEntry != PageTableEntry) { >> + Mva = (VOID *)(UINTN)((((UINTN)FirstLevelIdx) << TT_DESCRIPTOR_SECTION_BASE_SHIFT) + (PageTableIndex << TT_DESCRIPTOR_PAGE_BASE_SHIFT)); >> + if ((CurrentPageTableEntry & TT_DESCRIPTOR_PAGE_CACHEABLE_MASK) == TT_DESCRIPTOR_PAGE_CACHEABLE_MASK) { >> + // The current section mapping is cacheable so Clean/Invalidate the MVA of the page >> + // Note assumes switch(Attributes), not ARMv7 possibilities >> + WriteBackInvalidateDataCacheRange (Mva, TT_DESCRIPTOR_PAGE_SIZE); >> + } >> + >> + // Only need to update if we are changing the entry >> + PageTable[PageTableIndex] = PageTableEntry; >> + ArmUpdateTranslationTableEntry ((VOID *)&PageTable[PageTableIndex], Mva); >> + } >> + >> + Status = EFI_SUCCESS; >> + Offset += TT_DESCRIPTOR_PAGE_SIZE; >> + >> + } // End first level translation table loop >> + >> + return Status; >> +} >> + >> +STATIC >> +EFI_STATUS >> +UpdateSectionEntries ( >> + IN EFI_PHYSICAL_ADDRESS BaseAddress, >> + IN UINT64 Length, >> + IN UINT64 Attributes, >> + IN EFI_PHYSICAL_ADDRESS VirtualMask >> + ) >> +{ >> + EFI_STATUS Status = EFI_SUCCESS; >> + UINT32 EntryMask; >> + UINT32 EntryValue; >> + UINT32 FirstLevelIdx; >> + UINT32 NumSections; >> + UINT32 i; >> + UINT32 CurrentDescriptor; >> + UINT32 Descriptor; >> + VOID *Mva; >> + volatile ARM_FIRST_LEVEL_DESCRIPTOR *FirstLevelTable; >> + >> + // EntryMask: bitmask of values to change (1 = change this value, 0 = leave alone) >> + // EntryValue: values at bit positions specified by EntryMask >> + >> + // Make sure we handle a section range that is unmapped >> + EntryMask = TT_DESCRIPTOR_SECTION_TYPE_MASK | TT_DESCRIPTOR_SECTION_XN_MASK | >> + TT_DESCRIPTOR_SECTION_AP_MASK; >> + EntryValue = TT_DESCRIPTOR_SECTION_TYPE_SECTION; >> + >> + // Although the PI spec is unclear on this the GCD guarantees that only >> + // one Attribute bit is set at a time, so we can safely use a switch statement >> + if ((Attributes & EFI_MEMORY_UC) != 0) { >> + // modify cacheability attributes >> + EntryMask |= TT_DESCRIPTOR_SECTION_CACHE_POLICY_MASK; >> + // map to strongly ordered >> + EntryValue |= TT_DESCRIPTOR_SECTION_CACHE_POLICY_STRONGLY_ORDERED; // TEX[2:0] = 0, C=0, B=0 >> + } else if ((Attributes & EFI_MEMORY_WC) != 0) { >> + // modify cacheability attributes >> + EntryMask |= TT_DESCRIPTOR_SECTION_CACHE_POLICY_MASK; >> + // map to normal non-cachable >> + EntryValue |= TT_DESCRIPTOR_SECTION_CACHE_POLICY_NON_CACHEABLE; // TEX [2:0]= 001 = 0x2, B=0, C=0 >> + } else if ((Attributes & EFI_MEMORY_WT) != 0) { >> + // modify cacheability attributes >> + EntryMask |= TT_DESCRIPTOR_SECTION_CACHE_POLICY_MASK; >> + // write through with no-allocate >> + EntryValue |= TT_DESCRIPTOR_SECTION_CACHE_POLICY_WRITE_THROUGH_NO_ALLOC; // TEX [2:0] = 0, C=1, B=0 >> + } else if ((Attributes & EFI_MEMORY_WB) != 0) { >> + // modify cacheability attributes >> + EntryMask |= TT_DESCRIPTOR_SECTION_CACHE_POLICY_MASK; >> + // write back (with allocate) >> + EntryValue |= TT_DESCRIPTOR_SECTION_CACHE_POLICY_WRITE_BACK_ALLOC; // TEX [2:0] = 001, C=1, B=1 >> + } >> + >> + if ((Attributes & EFI_MEMORY_RO) != 0) { >> + EntryValue |= TT_DESCRIPTOR_SECTION_AP_RO_RO; >> + } else { >> + EntryValue |= TT_DESCRIPTOR_SECTION_AP_RW_RW; >> + } >> + >> + if ((Attributes & EFI_MEMORY_XP) != 0) { >> + EntryValue |= TT_DESCRIPTOR_SECTION_XN_MASK; >> + } >> + >> + // obtain page table base >> + FirstLevelTable = (ARM_FIRST_LEVEL_DESCRIPTOR *)ArmGetTTBR0BaseAddress (); >> + >> + // calculate index into first level translation table for start of modification >> + FirstLevelIdx = TT_DESCRIPTOR_SECTION_BASE_ADDRESS(BaseAddress) >> TT_DESCRIPTOR_SECTION_BASE_SHIFT; >> + ASSERT (FirstLevelIdx < TRANSLATION_TABLE_SECTION_COUNT); >> + >> + // calculate number of 1MB first level entries this applies to >> + NumSections = Length / TT_DESCRIPTOR_SECTION_SIZE; >> + >> + // iterate through each descriptor >> + for(i=0; i> + CurrentDescriptor = FirstLevelTable[FirstLevelIdx + i]; >> + >> + // has this descriptor already been coverted to pages? >> + if (TT_DESCRIPTOR_SECTION_TYPE_IS_PAGE_TABLE(CurrentDescriptor)) { >> + // forward this 1MB range to page table function instead >> + Status = UpdatePageEntries ((FirstLevelIdx + i) << TT_DESCRIPTOR_SECTION_BASE_SHIFT, TT_DESCRIPTOR_SECTION_SIZE, Attributes, VirtualMask); >> + } else { >> + // still a section entry >> + >> + // mask off appropriate fields >> + Descriptor = CurrentDescriptor & ~EntryMask; >> + >> + // mask in new attributes and/or permissions >> + Descriptor |= EntryValue; >> + if (VirtualMask != 0) { >> + Descriptor &= ~VirtualMask; >> + } >> + >> + if (CurrentDescriptor != Descriptor) { >> + Mva = (VOID *)(UINTN)(((UINTN)FirstLevelTable) << TT_DESCRIPTOR_SECTION_BASE_SHIFT); >> + if ((CurrentDescriptor & TT_DESCRIPTOR_SECTION_CACHEABLE_MASK) == TT_DESCRIPTOR_SECTION_CACHEABLE_MASK) { >> + // The current section mapping is cacheable so Clean/Invalidate the MVA of the section >> + // Note assumes switch(Attributes), not ARMv7 possabilities >> + WriteBackInvalidateDataCacheRange (Mva, SIZE_1MB); >> + } >> + >> + // Only need to update if we are changing the descriptor >> + FirstLevelTable[FirstLevelIdx + i] = Descriptor; >> + ArmUpdateTranslationTableEntry ((VOID *)&FirstLevelTable[FirstLevelIdx + i], Mva); >> + } >> + >> + Status = EFI_SUCCESS; >> + } >> + } >> + >> + return Status; >> +} >> + >> +EFI_STATUS >> +ArmSetMemoryAttributes ( >> + IN EFI_PHYSICAL_ADDRESS BaseAddress, >> + IN UINT64 Length, >> + IN UINT64 Attributes, >> + IN EFI_PHYSICAL_ADDRESS VirtualMask >> + ) >> +{ >> + EFI_STATUS Status; >> + UINT64 ChunkLength; >> + BOOLEAN FlushTlbs; >> + >> + FlushTlbs = FALSE; >> + while (Length > 0) { >> + if ((BaseAddress % TT_DESCRIPTOR_SECTION_SIZE == 0) && >> + Length >= TT_DESCRIPTOR_SECTION_SIZE) { >> + >> + ChunkLength = Length - Length % TT_DESCRIPTOR_SECTION_SIZE; >> + >> + DEBUG ((DEBUG_PAGE | DEBUG_INFO, >> + "SetMemoryAttributes(): MMU section 0x%lx length 0x%lx to %lx\n", >> + BaseAddress, ChunkLength, Attributes)); >> + >> + Status = UpdateSectionEntries (BaseAddress, ChunkLength, Attributes, >> + VirtualMask); >> + >> + FlushTlbs = TRUE; >> + } else { >> + >> + // >> + // Process page by page until the next section boundary, but only if >> + // we have more than a section's worth of area to deal with after that. >> + // >> + ChunkLength = TT_DESCRIPTOR_SECTION_SIZE - >> + (BaseAddress % TT_DESCRIPTOR_SECTION_SIZE); >> + if (ChunkLength + TT_DESCRIPTOR_SECTION_SIZE > Length) { >> + ChunkLength = Length; >> + } >> + >> + DEBUG ((DEBUG_PAGE | DEBUG_INFO, >> + "SetMemoryAttributes(): MMU page 0x%lx length 0x%lx to %lx\n", >> + BaseAddress, ChunkLength, Attributes)); >> + >> + Status = UpdatePageEntries (BaseAddress, ChunkLength, Attributes, >> + VirtualMask); >> + } >> + >> + if (EFI_ERROR (Status)) { >> + break; >> + } >> + >> + BaseAddress += ChunkLength; >> + Length -= ChunkLength; >> + } >> + >> + if (FlushTlbs) { >> + ArmInvalidateTlb (); >> + } >> + return Status; >> +} >> + >> RETURN_STATUS >> ArmSetMemoryRegionNoExec ( >> IN EFI_PHYSICAL_ADDRESS BaseAddress, >> -- >> 2.7.4 >>