X-Git-Url: https://git.proxmox.com/?p=mirror_edk2.git;a=blobdiff_plain;f=ArmPkg%2FDrivers%2FCpuDxe%2FArm%2FMmu.c;fp=ArmPkg%2FDrivers%2FCpuDxe%2FArm%2FMmu.c;h=12ca5b26673e834932e5a522d5e8b1e48943df39;hp=d3c307f4831788a0bb4a4ba944957d97f743ae2a;hb=521f3cedac4574c1431a3ad852ad160d9f849358;hpb=f49ea03de77d9928d2917e2594585919a51f6cff diff --git a/ArmPkg/Drivers/CpuDxe/Arm/Mmu.c b/ArmPkg/Drivers/CpuDxe/Arm/Mmu.c index d3c307f483..12ca5b2667 100644 --- a/ArmPkg/Drivers/CpuDxe/Arm/Mmu.c +++ b/ArmPkg/Drivers/CpuDxe/Arm/Mmu.c @@ -19,19 +19,6 @@ WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. #include #include "CpuDxe.h" -#define CACHE_ATTRIBUTE_MASK (EFI_MEMORY_UC | \ - EFI_MEMORY_WC | \ - EFI_MEMORY_WT | \ - EFI_MEMORY_WB | \ - EFI_MEMORY_UCE | \ - EFI_MEMORY_WP) - -// First Level Descriptors -typedef UINT32 ARM_FIRST_LEVEL_DESCRIPTOR; - -// Second Level Descriptors -typedef UINT32 ARM_PAGE_TABLE_ENTRY; - EFI_STATUS SectionToGcdAttributes ( IN UINT32 SectionAttributes, @@ -350,403 +337,6 @@ SyncCacheConfig ( return EFI_SUCCESS; } - - -EFI_STATUS -UpdatePageEntries ( - IN EFI_PHYSICAL_ADDRESS BaseAddress, - IN UINT64 Length, - IN UINT64 Attributes, - IN EFI_PHYSICAL_ADDRESS VirtualMask, - OUT BOOLEAN *FlushTlbs OPTIONAL - ) -{ - 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 the order of the conditionals below - // is irrelevant. If no memory attribute is specified, we preserve whatever - // memory type is set in the page tables, and update the permission attributes - // only. - if (Attributes & EFI_MEMORY_UC) { - // 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) { - // 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) { - // 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) { - // 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 - } else if (Attributes & CACHE_ATTRIBUTE_MASK) { - // catch unsupported memory type attributes - ASSERT (FALSE); - return EFI_UNSUPPORTED; - } - - 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]; - if (FlushTlbs != NULL) { - *FlushTlbs = TRUE; - } - } - - // 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)); - - // Only need to update if we are changing the entry - PageTable[PageTableIndex] = PageTableEntry; - ArmUpdateTranslationTableEntry ((VOID *)&PageTable[PageTableIndex], Mva); - - // Clean/invalidate the cache for this page, but only - // if we are modifying the memory type attributes - if (((CurrentPageTableEntry ^ PageTableEntry) & TT_DESCRIPTOR_PAGE_CACHE_POLICY_MASK) != 0) { - WriteBackInvalidateDataCacheRange (Mva, TT_DESCRIPTOR_PAGE_SIZE); - } - } - - 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 the order of the conditionals below - // is irrelevant. If no memory attribute is specified, we preserve whatever - // memory type is set in the page tables, and update the permission attributes - // only. - if (Attributes & EFI_MEMORY_UC) { - // 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) { - // 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) { - // 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) { - // 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 - } else if (Attributes & CACHE_ATTRIBUTE_MASK) { - // catch unsupported memory type attributes - ASSERT (FALSE); - return EFI_UNSUPPORTED; - } - - if (Attributes & EFI_MEMORY_RO) { - EntryValue |= TT_DESCRIPTOR_SECTION_AP_RO_RO; - } else { - EntryValue |= TT_DESCRIPTOR_SECTION_AP_RW_RW; - } - - if (Attributes & EFI_MEMORY_XP) { - 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> 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; - - if (Length == 0) { - return EFI_SUCCESS; - } - - 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, - "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, - "SetMemoryAttributes(): MMU page 0x%lx length 0x%lx to %lx\n", - BaseAddress, ChunkLength, Attributes)); - - Status = UpdatePageEntries (BaseAddress, ChunkLength, Attributes, - VirtualMask, &FlushTlbs); - } - - if (EFI_ERROR (Status)) { - break; - } - - BaseAddress += ChunkLength; - Length -= ChunkLength; - } - - if (FlushTlbs) { - ArmInvalidateTlb (); - } - return Status; -} - UINT64 EfiAttributeToArmAttribute ( IN UINT64 EfiAttributes