Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit b6113038 authored by James Morse's avatar James Morse Committed by Will Deacon
Browse files

arm64: vmlinux.ld: Add mmuoff data sections and move mmuoff text into idmap



Resume from hibernate needs to clean any text executed by the kernel with
the MMU off to the PoC. Collect these functions together into the
.idmap.text section as all this code is tightly coupled and also needs
the same cleaning after resume.

Data is more complicated, secondary_holding_pen_release is written with
the MMU on, clean and invalidated, then read with the MMU off. In contrast
__boot_cpu_mode is written with the MMU off, the corresponding cache line
is invalidated, so when we read it with the MMU on we don't get stale data.
These cache maintenance operations conflict with each other if the values
are within a Cache Writeback Granule (CWG) of each other.
Collect the data into two sections .mmuoff.data.read and .mmuoff.data.write,
the linker script ensures mmuoff.data.write section is aligned to the
architectural maximum CWG of 2KB.

Signed-off-by: default avatarJames Morse <james.morse@arm.com>
Cc: Ard Biesheuvel <ard.biesheuvel@linaro.org>
Cc: Mark Rutland <mark.rutland@arm.com>
Reviewed-by: default avatarCatalin Marinas <catalin.marinas@arm.com>
Signed-off-by: default avatarWill Deacon <will.deacon@arm.com>
parent ee78fdc7
Loading
Loading
Loading
Loading
+1 −0
Original line number Original line Diff line number Diff line
@@ -25,5 +25,6 @@ extern char __hyp_idmap_text_start[], __hyp_idmap_text_end[];
extern char __hyp_text_start[], __hyp_text_end[];
extern char __hyp_text_start[], __hyp_text_end[];
extern char __idmap_text_start[], __idmap_text_end[];
extern char __idmap_text_start[], __idmap_text_end[];
extern char __irqentry_text_start[], __irqentry_text_end[];
extern char __irqentry_text_start[], __irqentry_text_end[];
extern char __mmuoff_data_start[], __mmuoff_data_end[];


#endif /* __ASM_SECTIONS_H */
#endif /* __ASM_SECTIONS_H */
+15 −10
Original line number Original line Diff line number Diff line
@@ -463,7 +463,7 @@ ENDPROC(__primary_switched)
 * end early head section, begin head code that is also used for
 * end early head section, begin head code that is also used for
 * hotplug and needs to have the same protections as the text region
 * hotplug and needs to have the same protections as the text region
 */
 */
	.section ".text","ax"
	.section ".idmap.text","ax"


ENTRY(kimage_vaddr)
ENTRY(kimage_vaddr)
	.quad		_text - TEXT_OFFSET
	.quad		_text - TEXT_OFFSET
@@ -618,6 +618,13 @@ set_cpu_boot_mode_flag:
	ret
	ret
ENDPROC(set_cpu_boot_mode_flag)
ENDPROC(set_cpu_boot_mode_flag)


/*
 * These values are written with the MMU off, but read with the MMU on.
 * Writers will invalidate the corresponding address, discarding up to a
 * 'Cache Writeback Granule' (CWG) worth of data. The linker script ensures
 * sufficient alignment that the CWG doesn't overlap another section.
 */
	.pushsection ".mmuoff.data.write", "aw"
/*
/*
 * We need to find out the CPU boot mode long after boot, so we need to
 * We need to find out the CPU boot mode long after boot, so we need to
 * store it in a writable variable.
 * store it in a writable variable.
@@ -625,11 +632,16 @@ ENDPROC(set_cpu_boot_mode_flag)
 * This is not in .bss, because we set it sufficiently early that the boot-time
 * This is not in .bss, because we set it sufficiently early that the boot-time
 * zeroing of .bss would clobber it.
 * zeroing of .bss would clobber it.
 */
 */
	.pushsection	.data..cacheline_aligned
	.align	L1_CACHE_SHIFT
ENTRY(__boot_cpu_mode)
ENTRY(__boot_cpu_mode)
	.long	BOOT_CPU_MODE_EL2
	.long	BOOT_CPU_MODE_EL2
	.long	BOOT_CPU_MODE_EL1
	.long	BOOT_CPU_MODE_EL1
/*
 * The booting CPU updates the failed status @__early_cpu_boot_status,
 * with MMU turned off.
 */
ENTRY(__early_cpu_boot_status)
	.long 	0

	.popsection
	.popsection


	/*
	/*
@@ -702,12 +714,6 @@ ENDPROC(__secondary_switched)
	dc	ivac, \tmp1			// Invalidate potentially stale cache line
	dc	ivac, \tmp1			// Invalidate potentially stale cache line
	.endm
	.endm


	.pushsection	.data..cacheline_aligned
	.align	L1_CACHE_SHIFT
ENTRY(__early_cpu_boot_status)
	.long 	0
	.popsection

/*
/*
 * Enable the MMU.
 * Enable the MMU.
 *
 *
@@ -719,7 +725,6 @@ ENTRY(__early_cpu_boot_status)
 * Checks if the selected granule size is supported by the CPU.
 * Checks if the selected granule size is supported by the CPU.
 * If it isn't, park the CPU
 * If it isn't, park the CPU
 */
 */
	.section	".idmap.text", "ax"
ENTRY(__enable_mmu)
ENTRY(__enable_mmu)
	mrs	x22, sctlr_el1			// preserve old SCTLR_EL1 value
	mrs	x22, sctlr_el1			// preserve old SCTLR_EL1 value
	mrs	x1, ID_AA64MMFR0_EL1
	mrs	x1, ID_AA64MMFR0_EL1
+1 −1
Original line number Original line Diff line number Diff line
@@ -97,6 +97,7 @@ ENTRY(__cpu_suspend_enter)
ENDPROC(__cpu_suspend_enter)
ENDPROC(__cpu_suspend_enter)
	.ltorg
	.ltorg


	.pushsection ".idmap.text", "ax"
ENTRY(cpu_resume)
ENTRY(cpu_resume)
	bl	el2_setup		// if in EL2 drop to EL1 cleanly
	bl	el2_setup		// if in EL2 drop to EL1 cleanly
	/* enable the MMU early - so we can access sleep_save_stash by va */
	/* enable the MMU early - so we can access sleep_save_stash by va */
@@ -105,7 +106,6 @@ ENTRY(cpu_resume)
	b	__cpu_setup
	b	__cpu_setup
ENDPROC(cpu_resume)
ENDPROC(cpu_resume)


	.pushsection	".idmap.text", "ax"
_resume_switched:
_resume_switched:
	ldr	x8, =_cpu_resume
	ldr	x8, =_cpu_resume
	br	x8
	br	x8
+2 −1
Original line number Original line Diff line number Diff line
@@ -29,7 +29,8 @@
#include <asm/smp_plat.h>
#include <asm/smp_plat.h>


extern void secondary_holding_pen(void);
extern void secondary_holding_pen(void);
volatile unsigned long secondary_holding_pen_release = INVALID_HWID;
volatile unsigned long __section(".mmuoff.data.read")
secondary_holding_pen_release = INVALID_HWID;


static phys_addr_t cpu_release_addr[NR_CPUS];
static phys_addr_t cpu_release_addr[NR_CPUS];


+19 −0
Original line number Original line Diff line number Diff line
@@ -185,6 +185,25 @@ SECTIONS
	_data = .;
	_data = .;
	_sdata = .;
	_sdata = .;
	RW_DATA_SECTION(L1_CACHE_BYTES, PAGE_SIZE, THREAD_SIZE)
	RW_DATA_SECTION(L1_CACHE_BYTES, PAGE_SIZE, THREAD_SIZE)

	/*
	 * Data written with the MMU off but read with the MMU on requires
	 * cache lines to be invalidated, discarding up to a Cache Writeback
	 * Granule (CWG) of data from the cache. Keep the section that
	 * requires this type of maintenance to be in its own Cache Writeback
	 * Granule (CWG) area so the cache maintenance operations don't
	 * interfere with adjacent data.
	 */
	.mmuoff.data.write : ALIGN(SZ_2K) {
		__mmuoff_data_start = .;
		*(.mmuoff.data.write)
	}
	. = ALIGN(SZ_2K);
	.mmuoff.data.read : {
		*(.mmuoff.data.read)
		__mmuoff_data_end = .;
	}

	PECOFF_EDATA_PADDING
	PECOFF_EDATA_PADDING
	_edata = .;
	_edata = .;


Loading