arm64: consistently use reserved_pg_dir
[ Upstream commit 833be850f1cabd0e3b5337c0fcab20a6e936dd48 ] Depending on configuration options and specific code paths, we either use the empty_zero_page or the configuration-dependent reserved_ttbr0 as a reserved value for TTBR{0,1}_EL1. To simplify this code, let's always allocate and use the same reserved_pg_dir, replacing reserved_ttbr0. Note that this is allocated (and hence pre-zeroed), and is also marked as read-only in the kernel Image mapping. Keeping this separate from the empty_zero_page potentially helps with robustness as the empty_zero_page is used in a number of cases where a failure to map it read-only could allow it to become corrupted. The (presently unused) swapper_pg_end symbol is also removed, and comments are added wherever we rely on the offsets between the pre-allocated pg_dirs to keep these cases easily identifiable. Signed-off-by: Mark Rutland <mark.rutland@arm.com> Cc: Will Deacon <will@kernel.org> Link: https://lore.kernel.org/r/20201103102229.8542-1-mark.rutland@arm.com Signed-off-by: Catalin Marinas <catalin.marinas@arm.com> Signed-off-by: Sasha Levin <sashal@kernel.org>
This commit is contained in:

committed by
Greg Kroah-Hartman

parent
f1f30b3373
commit
8d6acfe80d
@@ -15,10 +15,10 @@
|
|||||||
.macro __uaccess_ttbr0_disable, tmp1
|
.macro __uaccess_ttbr0_disable, tmp1
|
||||||
mrs \tmp1, ttbr1_el1 // swapper_pg_dir
|
mrs \tmp1, ttbr1_el1 // swapper_pg_dir
|
||||||
bic \tmp1, \tmp1, #TTBR_ASID_MASK
|
bic \tmp1, \tmp1, #TTBR_ASID_MASK
|
||||||
sub \tmp1, \tmp1, #RESERVED_TTBR0_SIZE // reserved_ttbr0 just before swapper_pg_dir
|
sub \tmp1, \tmp1, #PAGE_SIZE // reserved_pg_dir just before swapper_pg_dir
|
||||||
msr ttbr0_el1, \tmp1 // set reserved TTBR0_EL1
|
msr ttbr0_el1, \tmp1 // set reserved TTBR0_EL1
|
||||||
isb
|
isb
|
||||||
add \tmp1, \tmp1, #RESERVED_TTBR0_SIZE
|
add \tmp1, \tmp1, #PAGE_SIZE
|
||||||
msr ttbr1_el1, \tmp1 // set reserved ASID
|
msr ttbr1_el1, \tmp1 // set reserved ASID
|
||||||
isb
|
isb
|
||||||
.endm
|
.endm
|
||||||
|
@@ -89,12 +89,6 @@
|
|||||||
#define INIT_DIR_SIZE (PAGE_SIZE * EARLY_PAGES(KIMAGE_VADDR, _end))
|
#define INIT_DIR_SIZE (PAGE_SIZE * EARLY_PAGES(KIMAGE_VADDR, _end))
|
||||||
#define IDMAP_DIR_SIZE (IDMAP_PGTABLE_LEVELS * PAGE_SIZE)
|
#define IDMAP_DIR_SIZE (IDMAP_PGTABLE_LEVELS * PAGE_SIZE)
|
||||||
|
|
||||||
#ifdef CONFIG_ARM64_SW_TTBR0_PAN
|
|
||||||
#define RESERVED_TTBR0_SIZE (PAGE_SIZE)
|
|
||||||
#else
|
|
||||||
#define RESERVED_TTBR0_SIZE (0)
|
|
||||||
#endif
|
|
||||||
|
|
||||||
/* Initial memory map size */
|
/* Initial memory map size */
|
||||||
#if ARM64_SWAPPER_USES_SECTION_MAPS
|
#if ARM64_SWAPPER_USES_SECTION_MAPS
|
||||||
#define SWAPPER_BLOCK_SHIFT SECTION_SHIFT
|
#define SWAPPER_BLOCK_SHIFT SECTION_SHIFT
|
||||||
|
@@ -36,11 +36,11 @@ static inline void contextidr_thread_switch(struct task_struct *next)
|
|||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Set TTBR0 to empty_zero_page. No translations will be possible via TTBR0.
|
* Set TTBR0 to reserved_pg_dir. No translations will be possible via TTBR0.
|
||||||
*/
|
*/
|
||||||
static inline void cpu_set_reserved_ttbr0(void)
|
static inline void cpu_set_reserved_ttbr0(void)
|
||||||
{
|
{
|
||||||
unsigned long ttbr = phys_to_ttbr(__pa_symbol(empty_zero_page));
|
unsigned long ttbr = phys_to_ttbr(__pa_symbol(reserved_pg_dir));
|
||||||
|
|
||||||
write_sysreg(ttbr, ttbr0_el1);
|
write_sysreg(ttbr, ttbr0_el1);
|
||||||
isb();
|
isb();
|
||||||
@@ -192,7 +192,7 @@ static inline void update_saved_ttbr0(struct task_struct *tsk,
|
|||||||
return;
|
return;
|
||||||
|
|
||||||
if (mm == &init_mm)
|
if (mm == &init_mm)
|
||||||
ttbr = __pa_symbol(empty_zero_page);
|
ttbr = __pa_symbol(reserved_pg_dir);
|
||||||
else
|
else
|
||||||
ttbr = virt_to_phys(mm->pgd) | ASID(mm) << 48;
|
ttbr = virt_to_phys(mm->pgd) | ASID(mm) << 48;
|
||||||
|
|
||||||
|
@@ -530,6 +530,7 @@ extern pgd_t swapper_pg_dir[PTRS_PER_PGD];
|
|||||||
extern pgd_t idmap_pg_dir[PTRS_PER_PGD];
|
extern pgd_t idmap_pg_dir[PTRS_PER_PGD];
|
||||||
extern pgd_t idmap_pg_end[];
|
extern pgd_t idmap_pg_end[];
|
||||||
extern pgd_t tramp_pg_dir[PTRS_PER_PGD];
|
extern pgd_t tramp_pg_dir[PTRS_PER_PGD];
|
||||||
|
extern pgd_t reserved_pg_dir[PTRS_PER_PGD];
|
||||||
|
|
||||||
extern void set_swapper_pgd(pgd_t *pgdp, pgd_t pgd);
|
extern void set_swapper_pgd(pgd_t *pgdp, pgd_t pgd);
|
||||||
|
|
||||||
|
@@ -113,8 +113,8 @@ static inline void __uaccess_ttbr0_disable(void)
|
|||||||
local_irq_save(flags);
|
local_irq_save(flags);
|
||||||
ttbr = read_sysreg(ttbr1_el1);
|
ttbr = read_sysreg(ttbr1_el1);
|
||||||
ttbr &= ~TTBR_ASID_MASK;
|
ttbr &= ~TTBR_ASID_MASK;
|
||||||
/* reserved_ttbr0 placed before swapper_pg_dir */
|
/* reserved_pg_dir placed before swapper_pg_dir */
|
||||||
write_sysreg(ttbr - RESERVED_TTBR0_SIZE, ttbr0_el1);
|
write_sysreg(ttbr - PAGE_SIZE, ttbr0_el1);
|
||||||
isb();
|
isb();
|
||||||
/* Set reserved ASID */
|
/* Set reserved ASID */
|
||||||
write_sysreg(ttbr, ttbr1_el1);
|
write_sysreg(ttbr, ttbr1_el1);
|
||||||
|
@@ -770,9 +770,10 @@ SYM_CODE_END(ret_to_user)
|
|||||||
*/
|
*/
|
||||||
.pushsection ".entry.tramp.text", "ax"
|
.pushsection ".entry.tramp.text", "ax"
|
||||||
|
|
||||||
|
// Move from tramp_pg_dir to swapper_pg_dir
|
||||||
.macro tramp_map_kernel, tmp
|
.macro tramp_map_kernel, tmp
|
||||||
mrs \tmp, ttbr1_el1
|
mrs \tmp, ttbr1_el1
|
||||||
add \tmp, \tmp, #(PAGE_SIZE + RESERVED_TTBR0_SIZE)
|
add \tmp, \tmp, #(2 * PAGE_SIZE)
|
||||||
bic \tmp, \tmp, #USER_ASID_FLAG
|
bic \tmp, \tmp, #USER_ASID_FLAG
|
||||||
msr ttbr1_el1, \tmp
|
msr ttbr1_el1, \tmp
|
||||||
#ifdef CONFIG_QCOM_FALKOR_ERRATUM_1003
|
#ifdef CONFIG_QCOM_FALKOR_ERRATUM_1003
|
||||||
@@ -789,9 +790,10 @@ alternative_else_nop_endif
|
|||||||
#endif /* CONFIG_QCOM_FALKOR_ERRATUM_1003 */
|
#endif /* CONFIG_QCOM_FALKOR_ERRATUM_1003 */
|
||||||
.endm
|
.endm
|
||||||
|
|
||||||
|
// Move from swapper_pg_dir to tramp_pg_dir
|
||||||
.macro tramp_unmap_kernel, tmp
|
.macro tramp_unmap_kernel, tmp
|
||||||
mrs \tmp, ttbr1_el1
|
mrs \tmp, ttbr1_el1
|
||||||
sub \tmp, \tmp, #(PAGE_SIZE + RESERVED_TTBR0_SIZE)
|
sub \tmp, \tmp, #(2 * PAGE_SIZE)
|
||||||
orr \tmp, \tmp, #USER_ASID_FLAG
|
orr \tmp, \tmp, #USER_ASID_FLAG
|
||||||
msr ttbr1_el1, \tmp
|
msr ttbr1_el1, \tmp
|
||||||
/*
|
/*
|
||||||
|
@@ -366,7 +366,7 @@ void __init __no_sanitize_address setup_arch(char **cmdline_p)
|
|||||||
* faults in case uaccess_enable() is inadvertently called by the init
|
* faults in case uaccess_enable() is inadvertently called by the init
|
||||||
* thread.
|
* thread.
|
||||||
*/
|
*/
|
||||||
init_task.thread_info.ttbr0 = __pa_symbol(empty_zero_page);
|
init_task.thread_info.ttbr0 = __pa_symbol(reserved_pg_dir);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
if (boot_args[1] || boot_args[2] || boot_args[3]) {
|
if (boot_args[1] || boot_args[2] || boot_args[3]) {
|
||||||
|
@@ -164,13 +164,11 @@ SECTIONS
|
|||||||
. += PAGE_SIZE;
|
. += PAGE_SIZE;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#ifdef CONFIG_ARM64_SW_TTBR0_PAN
|
reserved_pg_dir = .;
|
||||||
reserved_ttbr0 = .;
|
. += PAGE_SIZE;
|
||||||
. += RESERVED_TTBR0_SIZE;
|
|
||||||
#endif
|
|
||||||
swapper_pg_dir = .;
|
swapper_pg_dir = .;
|
||||||
. += PAGE_SIZE;
|
. += PAGE_SIZE;
|
||||||
swapper_pg_end = .;
|
|
||||||
|
|
||||||
. = ALIGN(SEGMENT_ALIGN);
|
. = ALIGN(SEGMENT_ALIGN);
|
||||||
__init_begin = .;
|
__init_begin = .;
|
||||||
|
@@ -168,7 +168,7 @@ SYM_FUNC_END(cpu_do_resume)
|
|||||||
.pushsection ".idmap.text", "awx"
|
.pushsection ".idmap.text", "awx"
|
||||||
|
|
||||||
.macro __idmap_cpu_set_reserved_ttbr1, tmp1, tmp2
|
.macro __idmap_cpu_set_reserved_ttbr1, tmp1, tmp2
|
||||||
adrp \tmp1, empty_zero_page
|
adrp \tmp1, reserved_pg_dir
|
||||||
phys_to_ttbr \tmp2, \tmp1
|
phys_to_ttbr \tmp2, \tmp1
|
||||||
offset_ttbr1 \tmp2, \tmp1
|
offset_ttbr1 \tmp2, \tmp1
|
||||||
msr ttbr1_el1, \tmp2
|
msr ttbr1_el1, \tmp2
|
||||||
|
Reference in New Issue
Block a user