Skip to content

Commit 3b5f4eb

Browse files
James MorseAlex Shi
authored andcommitted
arm64: Change cpu_resume() to enable mmu early then access sleep_sp by va
By enabling the MMU early in cpu_resume(), the sleep_save_sp and stack can be accessed by VA, which avoids the need to convert-addresses and clean to PoC on the suspend path. MMU setup is shared with the boot path, meaning the swapper_pg_dir is restored directly: ttbr1_el1 is no longer saved/restored. struct sleep_save_sp is removed, replacing it with a single array of pointers. cpu_do_{suspend,resume} could be further reduced to not restore: cpacr_el1, mdscr_el1, tcr_el1, vbar_el1 and sctlr_el1, all of which are set by __cpu_setup(). However these values all contain res0 bits that may be used to enable future features. Signed-off-by: James Morse <james.morse@arm.com> Reviewed-by: Lorenzo Pieralisi <lorenzo.pieralisi@arm.com> Reviewed-by: Catalin Marinas <catalin.marinas@arm.com> Signed-off-by: Will Deacon <will.deacon@arm.com> (cherry picked from commit cabe1c81ea5be983425d117912d7883e252a3b09) Signed-off-by: Alex Shi <alex.shi@linaro.org> Conflicts: arch/arm64/kernel/head.S remove KASAN change in arch/arm64/kernel/sleep.S
1 parent be5d6aa commit 3b5f4eb

7 files changed

Lines changed: 52 additions & 111 deletions

File tree

arch/arm64/include/asm/suspend.h

Lines changed: 3 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
#ifndef __ASM_SUSPEND_H
22
#define __ASM_SUSPEND_H
33

4-
#define NR_CTX_REGS 11
4+
#define NR_CTX_REGS 10
55
#define NR_CALLEE_SAVED_REGS 12
66

77
/*
@@ -17,11 +17,6 @@ struct cpu_suspend_ctx {
1717
u64 sp;
1818
} __aligned(16);
1919

20-
struct sleep_save_sp {
21-
phys_addr_t *save_ptr_stash;
22-
phys_addr_t save_ptr_stash_phys;
23-
};
24-
2520
/*
2621
* Memory to save the cpu state is allocated on the stack by
2722
* __cpu_suspend_enter()'s caller, and populated by __cpu_suspend_enter().
@@ -39,6 +34,8 @@ struct sleep_stack_data {
3934
unsigned long callee_saved_regs[NR_CALLEE_SAVED_REGS];
4035
};
4136

37+
extern unsigned long *sleep_save_stash;
38+
4239
extern int cpu_suspend(unsigned long arg, int (*fn)(unsigned long));
4340
extern void cpu_resume(void);
4441
int __cpu_suspend_enter(struct sleep_stack_data *state);

arch/arm64/kernel/asm-offsets.c

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -132,9 +132,6 @@ int main(void)
132132
DEFINE(CPU_CTX_SP, offsetof(struct cpu_suspend_ctx, sp));
133133
DEFINE(MPIDR_HASH_MASK, offsetof(struct mpidr_hash, mask));
134134
DEFINE(MPIDR_HASH_SHIFTS, offsetof(struct mpidr_hash, shift_aff));
135-
DEFINE(SLEEP_SAVE_SP_SZ, sizeof(struct sleep_save_sp));
136-
DEFINE(SLEEP_SAVE_SP_PHYS, offsetof(struct sleep_save_sp, save_ptr_stash_phys));
137-
DEFINE(SLEEP_SAVE_SP_VIRT, offsetof(struct sleep_save_sp, save_ptr_stash));
138135
DEFINE(SLEEP_STACK_DATA_SYSTEM_REGS, offsetof(struct sleep_stack_data, system_regs));
139136
DEFINE(SLEEP_STACK_DATA_CALLEE_REGS, offsetof(struct sleep_stack_data, callee_saved_regs));
140137
#endif

arch/arm64/kernel/head.S

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -627,7 +627,7 @@ ENDPROC(__secondary_switched)
627627
* If it isn't, park the CPU
628628
*/
629629
.section ".idmap.text", "ax"
630-
__enable_mmu:
630+
ENTRY(__enable_mmu)
631631
mrs x1, ID_AA64MMFR0_EL1
632632
ubfx x2, x1, #ID_AA64MMFR0_TGRAN_SHIFT, 4
633633
cmp x2, #ID_AA64MMFR0_TGRAN_SUPPORTED

arch/arm64/kernel/setup.c

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -175,7 +175,6 @@ static void __init smp_build_mpidr_hash(void)
175175
*/
176176
if (mpidr_hash_size() > 4 * num_possible_cpus())
177177
pr_warn("Large number of MPIDR hash buckets detected\n");
178-
__flush_dcache_area(&mpidr_hash, sizeof(struct mpidr_hash));
179178
}
180179

181180
static void __init setup_machine_fdt(phys_addr_t dt_phys)

arch/arm64/kernel/sleep.S

Lines changed: 21 additions & 36 deletions
Original file line numberDiff line numberDiff line change
@@ -73,8 +73,8 @@ ENTRY(__cpu_suspend_enter)
7373
str x2, [x0, #SLEEP_STACK_DATA_SYSTEM_REGS + CPU_CTX_SP]
7474

7575
/* find the mpidr_hash */
76-
ldr x1, =sleep_save_sp
77-
ldr x1, [x1, #SLEEP_SAVE_SP_VIRT]
76+
ldr x1, =sleep_save_stash
77+
ldr x1, [x1]
7878
mrs x7, mpidr_el1
7979
ldr x9, =mpidr_hash
8080
ldr x10, [x9, #MPIDR_HASH_MASK]
@@ -87,40 +87,27 @@ ENTRY(__cpu_suspend_enter)
8787
compute_mpidr_hash x8, x3, x4, x5, x6, x7, x10
8888
add x1, x1, x8, lsl #3
8989

90+
str x0, [x1]
91+
add x0, x0, #SLEEP_STACK_DATA_SYSTEM_REGS
9092
stp x29, lr, [sp, #-16]!
91-
bl __cpu_suspend_save
93+
bl cpu_do_suspend
9294
ldp x29, lr, [sp], #16
9395
mov x0, #1
9496
ret
9597
ENDPROC(__cpu_suspend_enter)
9698
.ltorg
9799

98-
/*
99-
* x0 must contain the sctlr value retrieved from restored context
100-
*/
101-
.pushsection ".idmap.text", "ax"
102-
ENTRY(cpu_resume_mmu)
103-
ldr x3, =cpu_resume_after_mmu
104-
msr sctlr_el1, x0 // restore sctlr_el1
105-
isb
106-
/*
107-
* Invalidate the local I-cache so that any instructions fetched
108-
* speculatively from the PoC are discarded, since they may have
109-
* been dynamically patched at the PoU.
110-
*/
111-
ic iallu
112-
dsb nsh
113-
isb
114-
br x3 // global jump to virtual address
115-
ENDPROC(cpu_resume_mmu)
116-
.popsection
117-
cpu_resume_after_mmu:
118-
mov x0, #0 // return zero on success
119-
ret
120-
ENDPROC(cpu_resume_after_mmu)
121-
122100
ENTRY(cpu_resume)
123101
bl el2_setup // if in EL2 drop to EL1 cleanly
102+
/* enable the MMU early - so we can access sleep_save_stash by va */
103+
adr_l lr, __enable_mmu /* __cpu_setup will return here */
104+
ldr x27, =_cpu_resume /* __enable_mmu will branch here */
105+
adrp x25, idmap_pg_dir
106+
adrp x26, swapper_pg_dir
107+
b __cpu_setup
108+
ENDPROC(cpu_resume)
109+
110+
ENTRY(_cpu_resume)
124111
mrs x1, mpidr_el1
125112
adrp x8, mpidr_hash
126113
add x8, x8, #:lo12:mpidr_hash // x8 = struct mpidr_hash phys address
@@ -130,26 +117,24 @@ ENTRY(cpu_resume)
130117
ldp w5, w6, [x8, #(MPIDR_HASH_SHIFTS + 8)]
131118
compute_mpidr_hash x7, x3, x4, x5, x6, x1, x2
132119
/* x7 contains hash index, let's use it to grab context pointer */
133-
ldr_l x0, sleep_save_sp + SLEEP_SAVE_SP_PHYS
120+
ldr_l x0, sleep_save_stash
134121
ldr x0, [x0, x7, lsl #3]
135122
add x29, x0, #SLEEP_STACK_DATA_CALLEE_REGS
136123
add x0, x0, #SLEEP_STACK_DATA_SYSTEM_REGS
137124
/* load sp from context */
138125
ldr x2, [x0, #CPU_CTX_SP]
139-
/* load physical address of identity map page table in x1 */
140-
adrp x1, idmap_pg_dir
141126
mov sp, x2
142127
/*
143-
* cpu_do_resume expects x0 to contain context physical address
144-
* pointer and x1 to contain physical address of 1:1 page tables
128+
* cpu_do_resume expects x0 to contain context address pointer
145129
*/
146-
bl cpu_do_resume // PC relative jump, MMU off
147-
/* Can't access these by physical address once the MMU is on */
130+
bl cpu_do_resume
131+
148132
ldp x19, x20, [x29, #16]
149133
ldp x21, x22, [x29, #32]
150134
ldp x23, x24, [x29, #48]
151135
ldp x25, x26, [x29, #64]
152136
ldp x27, x28, [x29, #80]
153137
ldp x29, lr, [x29]
154-
b cpu_resume_mmu // Resume MMU, never returns
155-
ENDPROC(cpu_resume)
138+
mov x0, #0
139+
ret
140+
ENDPROC(_cpu_resume)

arch/arm64/kernel/suspend.c

Lines changed: 6 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -10,30 +10,11 @@
1010
#include <asm/suspend.h>
1111
#include <asm/tlbflush.h>
1212

13-
1413
/*
15-
* This is called by __cpu_suspend_enter() to save the state, and do whatever
16-
* flushing is required to ensure that when the CPU goes to sleep we have
17-
* the necessary data available when the caches are not searched.
18-
*
19-
* ptr: sleep_stack_data containing cpu state virtual address.
20-
* save_ptr: address of the location where the context physical address
21-
* must be saved
14+
* This is allocated by cpu_suspend_init(), and used to store a pointer to
15+
* the 'struct sleep_stack_data' the contains a particular CPUs state.
2216
*/
23-
void notrace __cpu_suspend_save(struct sleep_stack_data *ptr,
24-
phys_addr_t *save_ptr)
25-
{
26-
*save_ptr = virt_to_phys(ptr);
27-
28-
cpu_do_suspend(&ptr->system_regs);
29-
/*
30-
* Only flush the context that must be retrieved with the MMU
31-
* off. VA primitives ensure the flush is applied to all
32-
* cache levels so context is pushed to DRAM.
33-
*/
34-
__flush_dcache_area(ptr, sizeof(*ptr));
35-
__flush_dcache_area(save_ptr, sizeof(*save_ptr));
36-
}
17+
unsigned long *sleep_save_stash;
3718

3819
/*
3920
* This hook is provided so that cpu_suspend code can restore HW
@@ -131,22 +112,15 @@ int cpu_suspend(unsigned long arg, int (*fn)(unsigned long))
131112
return ret;
132113
}
133114

134-
struct sleep_save_sp sleep_save_sp;
135-
136115
static int __init cpu_suspend_init(void)
137116
{
138-
void *ctx_ptr;
139-
140117
/* ctx_ptr is an array of physical addresses */
141-
ctx_ptr = kcalloc(mpidr_hash_size(), sizeof(phys_addr_t), GFP_KERNEL);
118+
sleep_save_stash = kcalloc(mpidr_hash_size(), sizeof(*sleep_save_stash),
119+
GFP_KERNEL);
142120

143-
if (WARN_ON(!ctx_ptr))
121+
if (WARN_ON(!sleep_save_stash))
144122
return -ENOMEM;
145123

146-
sleep_save_sp.save_ptr_stash = ctx_ptr;
147-
sleep_save_sp.save_ptr_stash_phys = virt_to_phys(ctx_ptr);
148-
__flush_dcache_area(&sleep_save_sp, sizeof(struct sleep_save_sp));
149-
150124
return 0;
151125
}
152126
early_initcall(cpu_suspend_init);

arch/arm64/mm/proc.S

Lines changed: 21 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@
2424
#include <asm/asm-offsets.h>
2525
#include <asm/hwcap.h>
2626
#include <asm/pgtable.h>
27+
#include <asm/pgtable-hwdef.h>
2728
#include <asm/cpufeature.h>
2829
#include <asm/alternative.h>
2930

@@ -63,62 +64,50 @@ ENTRY(cpu_do_suspend)
6364
mrs x2, tpidr_el0
6465
mrs x3, tpidrro_el0
6566
mrs x4, contextidr_el1
66-
mrs x5, mair_el1
67-
mrs x6, cpacr_el1
68-
mrs x7, ttbr1_el1
69-
mrs x8, tcr_el1
70-
mrs x9, vbar_el1
71-
mrs x10, mdscr_el1
72-
mrs x11, oslsr_el1
73-
mrs x12, sctlr_el1
67+
mrs x5, cpacr_el1
68+
mrs x6, tcr_el1
69+
mrs x7, vbar_el1
70+
mrs x8, mdscr_el1
71+
mrs x9, oslsr_el1
72+
mrs x10, sctlr_el1
7473
stp x2, x3, [x0]
75-
stp x4, x5, [x0, #16]
76-
stp x6, x7, [x0, #32]
77-
stp x8, x9, [x0, #48]
78-
stp x10, x11, [x0, #64]
79-
str x12, [x0, #80]
74+
stp x4, xzr, [x0, #16]
75+
stp x5, x6, [x0, #32]
76+
stp x7, x8, [x0, #48]
77+
stp x9, x10, [x0, #64]
8078
ret
8179
ENDPROC(cpu_do_suspend)
8280

8381
/**
8482
* cpu_do_resume - restore CPU register context
8583
*
86-
* x0: Physical address of context pointer
87-
* x1: ttbr0_el1 to be restored
88-
*
89-
* Returns:
90-
* sctlr_el1 value in x0
84+
* x0: Address of context pointer
9185
*/
9286
ENTRY(cpu_do_resume)
93-
/*
94-
* Invalidate local tlb entries before turning on MMU
95-
*/
96-
tlbi vmalle1
9787
ldp x2, x3, [x0]
9888
ldp x4, x5, [x0, #16]
99-
ldp x6, x7, [x0, #32]
100-
ldp x8, x9, [x0, #48]
101-
ldp x10, x11, [x0, #64]
102-
ldr x12, [x0, #80]
89+
ldp x6, x8, [x0, #32]
90+
ldp x9, x10, [x0, #48]
91+
ldp x11, x12, [x0, #64]
10392
msr tpidr_el0, x2
10493
msr tpidrro_el0, x3
10594
msr contextidr_el1, x4
106-
msr mair_el1, x5
10795
msr cpacr_el1, x6
108-
msr ttbr0_el1, x1
109-
msr ttbr1_el1, x7
110-
tcr_set_idmap_t0sz x8, x7
96+
97+
/* Don't change t0sz here, mask those bits when restoring */
98+
mrs x5, tcr_el1
99+
bfi x8, x5, TCR_T0SZ_OFFSET, TCR_TxSZ_WIDTH
100+
111101
msr tcr_el1, x8
112102
msr vbar_el1, x9
113103
msr mdscr_el1, x10
104+
msr sctlr_el1, x12
114105
/*
115106
* Restore oslsr_el1 by writing oslar_el1
116107
*/
117108
ubfx x11, x11, #1, #1
118109
msr oslar_el1, x11
119110
reset_pmuserenr_el0 x0 // Disable PMU access from EL0
120-
mov x0, x12
121-
dsb nsh // Make sure local tlb invalidation completed
122111
isb
123112
ret
124113
ENDPROC(cpu_do_resume)

0 commit comments

Comments
 (0)