From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: from mail-wm0-x22a.google.com (mail-wm0-x22a.google.com [IPv6:2a00:1450:400c:c09::22a]) (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 94C9380313 for ; Mon, 6 Mar 2017 08:03:29 -0800 (PST) Received: by mail-wm0-x22a.google.com with SMTP id n11so67841535wma.1 for ; Mon, 06 Mar 2017 08:03:29 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=linaro.org; s=google; h=date:from:to:cc:subject:message-id:references:mime-version :content-disposition:in-reply-to:user-agent; bh=OOUL5uiA8WhzZ0WbW9mbLq/9Nn4SQwkXV8rrubgQaOM=; b=XXkAqtXpI86UNBCCh1T8+E1sUq+ZacWF9yVqdjLqHyGr+ioFqk0znTLlXySZHnlx5S 3I3vtvkLO9WjQGRlMn+IaVkhuZCG9vMbxeM+z46e/1MOV1jMDwgx90IUnO2D/XfEle1Y 7+/PW1tmyoSTW7XmXQaz+E7Jnq9hOvsmtqDQ0= X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:date:from:to:cc:subject:message-id:references :mime-version:content-disposition:in-reply-to:user-agent; bh=OOUL5uiA8WhzZ0WbW9mbLq/9Nn4SQwkXV8rrubgQaOM=; b=m46UTvv2nRTZ6v26y7a7Ns4RHnokkk8VjQdS/Gy4w1LVkyg1FxgGGGTNJNkVF0GMeT LOM7b21w0GLDC9H+gHCJ1fdTmiOWqaU3OQoPSP2lkqjvqTpcwzWZX9gcmjGlWxedwec7 skg0zplYrqTPESLUUwUUDb4vBqeHbWcTlZlbwo71CgX1B8m1wQTSXBdro38wPAIr8n2n hD5MNMGcsr43JUXVAujQ6USseRn0mNbPi8dH1DC4//y64z1ZXpErdgA62CfkPrnhn8mR EfKpccmCH9IAK7VKj3BDcvZeWC8i9m6Yo8x15faLR5GrTKmYQz+BmJoIATwvP/NkFqqN QqiQ== X-Gm-Message-State: AMke39nOTFzVrgoIRrJHEGwo+gLVX2kfbFvVFh/1lbmC07gq+63u8H3xCP17hAbKZO3E0jRX X-Received: by 10.28.128.209 with SMTP id b200mr14558682wmd.140.1488816207594; Mon, 06 Mar 2017 08:03:27 -0800 (PST) Received: from bivouac.eciton.net (bivouac.eciton.net. [2a00:1098:0:86:1000:23:0:2]) by smtp.gmail.com with ESMTPSA id u198sm15351773wmf.9.2017.03.06.08.03.26 (version=TLS1_2 cipher=ECDHE-RSA-AES128-GCM-SHA256 bits=128/128); Mon, 06 Mar 2017 08:03:26 -0800 (PST) Date: Mon, 6 Mar 2017 16:03:25 +0000 From: Leif Lindholm To: Ard Biesheuvel Cc: edk2-devel@lists.01.org, lersek@redhat.com Message-ID: <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> MIME-Version: 1.0 In-Reply-To: <1488385903-30267-3-git-send-email-ard.biesheuvel@linaro.org> User-Agent: Mutt/1.5.23 (2014-03-12) 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:03:30 -0000 Content-Type: text/plain; charset=us-ascii Content-Disposition: inline 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. / Leif > 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 >