mirror of
https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
synced 2026-02-24 11:16:29 -05:00
Address bytes shifted with a single 64 bit page table entry (any page table level) has been always hard coded as 3 (aka 2^3 = 8). Although intuitive it is not very readable or easy to reason about. Besides it is going to change with D128, where each 128 bit page table entry will shift address bytes by 4 (aka 2^4 = 16) instead. Let's just formalise this address bytes shift value into a new macro called PTDESC_ORDER establishing a logical abstraction, thus improving readability as well. While here re-organize EARLY_LEVEL macro along with its dependents for better clarity. This does not cause any functional change. Also replace all (PAGE_SHIFT - PTDESC_ORDER) instances with PTDESC_TABLE_SHIFT. Cc: Will Deacon <will@kernel.org> Cc: Mark Rutland <mark.rutland@arm.com> Cc: Andrey Ryabinin <ryabinin.a.a@gmail.com> Cc: Alexander Potapenko <glider@google.com> Cc: Andrey Konovalov <andreyknvl@gmail.com> Cc: Dmitry Vyukov <dvyukov@google.com> Cc: Ard Biesheuvel <ardb@kernel.org> Cc: Ryan Roberts <ryan.roberts@arm.com> Cc: linux-arm-kernel@lists.infradead.org Cc: linux-kernel@vger.kernel.org Cc: kasan-dev@googlegroups.com Acked-by: Ard Biesheuvel <ardb@kernel.org> Reviewed-by: Ryan Roberts <ryan.roberts@arm.com> Signed-off-by: Anshuman Khandual <anshuman.khandual@arm.com> Link: https://lore.kernel.org/r/20250311045710.550625-1-anshuman.khandual@arm.com Signed-off-by: Catalin Marinas <catalin.marinas@arm.com>
106 lines
3.1 KiB
C
106 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;
|
|
pteval_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, pteval_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;
|
|
}
|