arm64: mm: Offset TTBR1 to allow 52-bit PTRS_PER_PGD
Enabling 52-bit VAs on arm64 requires that the PGD table expands from 64 entries (for the 48-bit case) to 1024 entries. This quantity, PTRS_PER_PGD is used as follows to compute which PGD entry corresponds to a given virtual address, addr: pgd_index(addr) -> (addr >> PGDIR_SHIFT) & (PTRS_PER_PGD - 1) Userspace addresses are prefixed by 0's, so for a 48-bit userspace address, uva, the following is true: (uva >> PGDIR_SHIFT) & (1024 - 1) == (uva >> PGDIR_SHIFT) & (64 - 1) In other words, a 48-bit userspace address will have the same pgd_index when using PTRS_PER_PGD = 64 and 1024. Kernel addresses are prefixed by 1's so, given a 48-bit kernel address, kva, we have the following inequality: (kva >> PGDIR_SHIFT) & (1024 - 1) != (kva >> PGDIR_SHIFT) & (64 - 1) In other words a 48-bit kernel virtual address will have a different pgd_index when using PTRS_PER_PGD = 64 and 1024. If, however, we note that: kva = 0xFFFF << 48 + lower (where lower[63:48] == 0b) and, PGDIR_SHIFT = 42 (as we are dealing with 64KB PAGE_SIZE) We can consider: (kva >> PGDIR_SHIFT) & (1024 - 1) - (kva >> PGDIR_SHIFT) & (64 - 1) = (0xFFFF << 6) & 0x3FF - (0xFFFF << 6) & 0x3F // "lower" cancels out = 0x3C0 In other words, one can switch PTRS_PER_PGD to the 52-bit value globally provided that they increment ttbr1_el1 by 0x3C0 * 8 = 0x1E00 bytes when running with 48-bit kernel VAs (TCR_EL1.T1SZ = 16). For kernel configuration where 52-bit userspace VAs are possible, this patch offsets ttbr1_el1 and sets PTRS_PER_PGD corresponding to the 52-bit value. Reviewed-by: Catalin Marinas <catalin.marinas@arm.com> Reviewed-by: Suzuki K Poulose <suzuki.poulose@arm.com> Suggested-by: Catalin Marinas <catalin.marinas@arm.com> Signed-off-by: Steve Capper <steve.capper@arm.com> [will: added comment to TTBR1_BADDR_4852_OFFSET calculation] Signed-off-by: Will Deacon <will.deacon@arm.com>
This commit is contained in:
parent
e5d9915745
commit
e842dfb5a2
|
@ -543,6 +543,29 @@ USER(\label, ic ivau, \tmp2) // invalidate I line PoU
|
|||
mrs \rd, sp_el0
|
||||
.endm
|
||||
|
||||
/*
|
||||
* Offset ttbr1 to allow for 48-bit kernel VAs set with 52-bit PTRS_PER_PGD.
|
||||
* orr is used as it can cover the immediate value (and is idempotent).
|
||||
* In future this may be nop'ed out when dealing with 52-bit kernel VAs.
|
||||
* ttbr: Value of ttbr to set, modified.
|
||||
*/
|
||||
.macro offset_ttbr1, ttbr
|
||||
#ifdef CONFIG_ARM64_52BIT_VA
|
||||
orr \ttbr, \ttbr, #TTBR1_BADDR_4852_OFFSET
|
||||
#endif
|
||||
.endm
|
||||
|
||||
/*
|
||||
* Perform the reverse of offset_ttbr1.
|
||||
* bic is used as it can cover the immediate value and, in future, won't need
|
||||
* to be nop'ed out when dealing with 52-bit kernel VAs.
|
||||
*/
|
||||
.macro restore_ttbr1, ttbr
|
||||
#ifdef CONFIG_ARM64_52BIT_VA
|
||||
bic \ttbr, \ttbr, #TTBR1_BADDR_4852_OFFSET
|
||||
#endif
|
||||
.endm
|
||||
|
||||
/*
|
||||
* Arrange a physical address in a TTBR register, taking care of 52-bit
|
||||
* addresses.
|
||||
|
|
|
@ -80,7 +80,11 @@
|
|||
#define PGDIR_SHIFT ARM64_HW_PGTABLE_LEVEL_SHIFT(4 - CONFIG_PGTABLE_LEVELS)
|
||||
#define PGDIR_SIZE (_AC(1, UL) << PGDIR_SHIFT)
|
||||
#define PGDIR_MASK (~(PGDIR_SIZE-1))
|
||||
#ifdef CONFIG_ARM64_52BIT_VA
|
||||
#define PTRS_PER_PGD (1 << (52 - PGDIR_SHIFT))
|
||||
#else
|
||||
#define PTRS_PER_PGD (1 << (VA_BITS - PGDIR_SHIFT))
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Section address mask and size definitions.
|
||||
|
@ -306,4 +310,10 @@
|
|||
#define TTBR_BADDR_MASK_52 (((UL(1) << 46) - 1) << 2)
|
||||
#endif
|
||||
|
||||
#ifdef CONFIG_ARM64_52BIT_VA
|
||||
/* Must be at least 64-byte aligned to prevent corruption of the TTBR */
|
||||
#define TTBR1_BADDR_4852_OFFSET (((UL(1) << (52 - PGDIR_SHIFT)) - \
|
||||
(UL(1) << (48 - PGDIR_SHIFT))) * 8)
|
||||
#endif
|
||||
|
||||
#endif
|
||||
|
|
|
@ -769,6 +769,7 @@ ENTRY(__enable_mmu)
|
|||
phys_to_ttbr x1, x1
|
||||
phys_to_ttbr x2, x2
|
||||
msr ttbr0_el1, x2 // load TTBR0
|
||||
offset_ttbr1 x1
|
||||
msr ttbr1_el1, x1 // load TTBR1
|
||||
isb
|
||||
msr sctlr_el1, x0
|
||||
|
|
|
@ -40,6 +40,7 @@
|
|||
tlbi vmalle1
|
||||
dsb nsh
|
||||
phys_to_ttbr \tmp, \page_table
|
||||
offset_ttbr1 \tmp
|
||||
msr ttbr1_el1, \tmp
|
||||
isb
|
||||
.endm
|
||||
|
|
|
@ -182,6 +182,7 @@ ENDPROC(cpu_do_switch_mm)
|
|||
.macro __idmap_cpu_set_reserved_ttbr1, tmp1, tmp2
|
||||
adrp \tmp1, empty_zero_page
|
||||
phys_to_ttbr \tmp2, \tmp1
|
||||
offset_ttbr1 \tmp2
|
||||
msr ttbr1_el1, \tmp2
|
||||
isb
|
||||
tlbi vmalle1
|
||||
|
@ -200,6 +201,7 @@ ENTRY(idmap_cpu_replace_ttbr1)
|
|||
|
||||
__idmap_cpu_set_reserved_ttbr1 x1, x3
|
||||
|
||||
offset_ttbr1 x0
|
||||
msr ttbr1_el1, x0
|
||||
isb
|
||||
|
||||
|
@ -254,6 +256,7 @@ ENTRY(idmap_kpti_install_ng_mappings)
|
|||
pte .req x16
|
||||
|
||||
mrs swapper_ttb, ttbr1_el1
|
||||
restore_ttbr1 swapper_ttb
|
||||
adr flag_ptr, __idmap_kpti_flag
|
||||
|
||||
cbnz cpu, __idmap_kpti_secondary
|
||||
|
@ -373,6 +376,7 @@ __idmap_kpti_secondary:
|
|||
cbnz w18, 1b
|
||||
|
||||
/* All done, act like nothing happened */
|
||||
offset_ttbr1 swapper_ttb
|
||||
msr ttbr1_el1, swapper_ttb
|
||||
isb
|
||||
ret
|
||||
|
|
Loading…
Reference in New Issue