mirror of
git://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
synced 2025-08-05 16:54:27 +00:00

Define ptdesc_t type which describes the basic page table descriptor layout on arm64 platform. Subsequently all level specific pxxval_t descriptors are derived from ptdesc_t thus establishing a common original format, which can also be appropriate for page table entries, masks and protection values etc which are used at all page table levels. Link: https://lkml.kernel.org/r/20250407053113.746295-4-anshuman.khandual@arm.com Signed-off-by: Anshuman Khandual <anshuman.khandual@arm.com> Suggested-by: Ryan Roberts <ryan.roberts@arm.com> Cc: Catalin Marinas <catalin.marinas@arm.com> Cc: Will Deacon <will@kernel.org> Cc: Ard Biesheuvel <ardb@kernel.org> Cc: Mark Rutland <mark.rutland@arm.com> Cc: Dave Hansen <dave.hansen@linux.intel.com> Cc: Gerald Schaefer <gerald.schaefer@linux.ibm.com> Cc: Heiko Carstens <hca@linux.ibm.com> Cc: Ingo Molnar <mingo@redhat.com> Cc: Madhavan Srinivasan <maddy@linux.ibm.com> Cc: Nicholas Piggin <npiggin@gmail.com> Cc: Palmer Dabbelt <palmer@dabbelt.com> Cc: Paul Walmsley <paul.walmsley@sifive.com> Cc: Peter Zijlstra <peterz@infradead.org> Cc: Thomas Gleixner <tglx@linutronix.de> Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
105 lines
3.1 KiB
C
105 lines
3.1 KiB
C
// SPDX-License-Identifier: GPL-2.0-only
|
|
// Copyright 2023 Google LLC
|
|
// Author: Ard Biesheuvel <ardb@google.com>
|
|
|
|
#include <linux/types.h>
|
|
#include <linux/sizes.h>
|
|
|
|
#include <asm/memory.h>
|
|
#include <asm/pgalloc.h>
|
|
#include <asm/pgtable.h>
|
|
|
|
#include "pi.h"
|
|
|
|
/**
|
|
* map_range - Map a contiguous range of physical pages into virtual memory
|
|
*
|
|
* @pte: Address of physical pointer to array of pages to
|
|
* allocate page tables from
|
|
* @start: Virtual address of the start of the range
|
|
* @end: Virtual address of the end of the range (exclusive)
|
|
* @pa: Physical address of the start of the range
|
|
* @prot: Access permissions of the range
|
|
* @level: Translation level for the mapping
|
|
* @tbl: The level @level page table to create the mappings in
|
|
* @may_use_cont: Whether the use of the contiguous attribute is allowed
|
|
* @va_offset: Offset between a physical page and its current mapping
|
|
* in the VA space
|
|
*/
|
|
void __init map_range(u64 *pte, u64 start, u64 end, u64 pa, pgprot_t prot,
|
|
int level, pte_t *tbl, bool may_use_cont, u64 va_offset)
|
|
{
|
|
u64 cmask = (level == 3) ? CONT_PTE_SIZE - 1 : U64_MAX;
|
|
ptdesc_t protval = pgprot_val(prot) & ~PTE_TYPE_MASK;
|
|
int lshift = (3 - level) * PTDESC_TABLE_SHIFT;
|
|
u64 lmask = (PAGE_SIZE << lshift) - 1;
|
|
|
|
start &= PAGE_MASK;
|
|
pa &= PAGE_MASK;
|
|
|
|
/* Advance tbl to the entry that covers start */
|
|
tbl += (start >> (lshift + PAGE_SHIFT)) % PTRS_PER_PTE;
|
|
|
|
/*
|
|
* Set the right block/page bits for this level unless we are
|
|
* clearing the mapping
|
|
*/
|
|
if (protval)
|
|
protval |= (level == 2) ? PMD_TYPE_SECT : PTE_TYPE_PAGE;
|
|
|
|
while (start < end) {
|
|
u64 next = min((start | lmask) + 1, PAGE_ALIGN(end));
|
|
|
|
if (level < 2 || (level == 2 && (start | next | pa) & lmask)) {
|
|
/*
|
|
* This chunk needs a finer grained mapping. Create a
|
|
* table mapping if necessary and recurse.
|
|
*/
|
|
if (pte_none(*tbl)) {
|
|
*tbl = __pte(__phys_to_pte_val(*pte) |
|
|
PMD_TYPE_TABLE | PMD_TABLE_UXN);
|
|
*pte += PTRS_PER_PTE * sizeof(pte_t);
|
|
}
|
|
map_range(pte, start, next, pa, prot, level + 1,
|
|
(pte_t *)(__pte_to_phys(*tbl) + va_offset),
|
|
may_use_cont, va_offset);
|
|
} else {
|
|
/*
|
|
* Start a contiguous range if start and pa are
|
|
* suitably aligned
|
|
*/
|
|
if (((start | pa) & cmask) == 0 && may_use_cont)
|
|
protval |= PTE_CONT;
|
|
|
|
/*
|
|
* Clear the contiguous attribute if the remaining
|
|
* range does not cover a contiguous block
|
|
*/
|
|
if ((end & ~cmask) <= start)
|
|
protval &= ~PTE_CONT;
|
|
|
|
/* Put down a block or page mapping */
|
|
*tbl = __pte(__phys_to_pte_val(pa) | protval);
|
|
}
|
|
pa += next - start;
|
|
start = next;
|
|
tbl++;
|
|
}
|
|
}
|
|
|
|
asmlinkage u64 __init create_init_idmap(pgd_t *pg_dir, ptdesc_t clrmask)
|
|
{
|
|
u64 ptep = (u64)pg_dir + PAGE_SIZE;
|
|
pgprot_t text_prot = PAGE_KERNEL_ROX;
|
|
pgprot_t data_prot = PAGE_KERNEL;
|
|
|
|
pgprot_val(text_prot) &= ~clrmask;
|
|
pgprot_val(data_prot) &= ~clrmask;
|
|
|
|
map_range(&ptep, (u64)_stext, (u64)__initdata_begin, (u64)_stext,
|
|
text_prot, IDMAP_ROOT_LEVEL, (pte_t *)pg_dir, false, 0);
|
|
map_range(&ptep, (u64)__initdata_begin, (u64)_end, (u64)__initdata_begin,
|
|
data_prot, IDMAP_ROOT_LEVEL, (pte_t *)pg_dir, false, 0);
|
|
|
|
return ptep;
|
|
}
|