Merge branch 'for-next/boot' into for-next/core

Boot path cleanups to enable early initialisation of per-cpu operations
needed by KCSAN.

* for-next/boot:
  arm64: scs: Drop unused 'tmp' argument to scs_{load, save} asm macros
  arm64: smp: initialize cpu offset earlier
  arm64: smp: unify task and sp setup
  arm64: smp: remove stack from secondary_data
  arm64: smp: remove pointless secondary_data maintenance
  arm64: assembler: add set_this_cpu_offset
This commit is contained in:
Will Deacon 2021-06-24 13:30:13 +01:00
commit e7cf636cba
9 changed files with 51 additions and 58 deletions

View File

@ -232,15 +232,23 @@ lr .req x30 // link register
* @dst: destination register * @dst: destination register
*/ */
#if defined(__KVM_NVHE_HYPERVISOR__) || defined(__KVM_VHE_HYPERVISOR__) #if defined(__KVM_NVHE_HYPERVISOR__) || defined(__KVM_VHE_HYPERVISOR__)
.macro this_cpu_offset, dst .macro get_this_cpu_offset, dst
mrs \dst, tpidr_el2 mrs \dst, tpidr_el2
.endm .endm
#else #else
.macro this_cpu_offset, dst .macro get_this_cpu_offset, dst
alternative_if_not ARM64_HAS_VIRT_HOST_EXTN alternative_if_not ARM64_HAS_VIRT_HOST_EXTN
mrs \dst, tpidr_el1 mrs \dst, tpidr_el1
alternative_else alternative_else
mrs \dst, tpidr_el2 mrs \dst, tpidr_el2
alternative_endif
.endm
.macro set_this_cpu_offset, src
alternative_if_not ARM64_HAS_VIRT_HOST_EXTN
msr tpidr_el1, \src
alternative_else
msr tpidr_el2, \src
alternative_endif alternative_endif
.endm .endm
#endif #endif
@ -253,7 +261,7 @@ alternative_endif
.macro adr_this_cpu, dst, sym, tmp .macro adr_this_cpu, dst, sym, tmp
adrp \tmp, \sym adrp \tmp, \sym
add \dst, \tmp, #:lo12:\sym add \dst, \tmp, #:lo12:\sym
this_cpu_offset \tmp get_this_cpu_offset \tmp
add \dst, \dst, \tmp add \dst, \dst, \tmp
.endm .endm
@ -264,7 +272,7 @@ alternative_endif
*/ */
.macro ldr_this_cpu dst, sym, tmp .macro ldr_this_cpu dst, sym, tmp
adr_l \dst, \sym adr_l \dst, \sym
this_cpu_offset \tmp get_this_cpu_offset \tmp
ldr \dst, [\dst, \tmp] ldr \dst, [\dst, \tmp]
.endm .endm
@ -745,7 +753,7 @@ USER(\label, ic ivau, \tmp2) // invalidate I line PoU
cbz \tmp, \lbl cbz \tmp, \lbl
#endif #endif
adr_l \tmp, irq_stat + IRQ_CPUSTAT_SOFTIRQ_PENDING adr_l \tmp, irq_stat + IRQ_CPUSTAT_SOFTIRQ_PENDING
this_cpu_offset \tmp2 get_this_cpu_offset \tmp2
ldr w\tmp, [\tmp, \tmp2] ldr w\tmp, [\tmp, \tmp2]
cbnz w\tmp, \lbl // yield on pending softirq in task context cbnz w\tmp, \lbl // yield on pending softirq in task context
.Lnoyield_\@: .Lnoyield_\@:

View File

@ -9,18 +9,18 @@
#ifdef CONFIG_SHADOW_CALL_STACK #ifdef CONFIG_SHADOW_CALL_STACK
scs_sp .req x18 scs_sp .req x18
.macro scs_load tsk, tmp .macro scs_load tsk
ldr scs_sp, [\tsk, #TSK_TI_SCS_SP] ldr scs_sp, [\tsk, #TSK_TI_SCS_SP]
.endm .endm
.macro scs_save tsk, tmp .macro scs_save tsk
str scs_sp, [\tsk, #TSK_TI_SCS_SP] str scs_sp, [\tsk, #TSK_TI_SCS_SP]
.endm .endm
#else #else
.macro scs_load tsk, tmp .macro scs_load tsk
.endm .endm
.macro scs_save tsk, tmp .macro scs_save tsk
.endm .endm
#endif /* CONFIG_SHADOW_CALL_STACK */ #endif /* CONFIG_SHADOW_CALL_STACK */

View File

@ -73,12 +73,10 @@ asmlinkage void secondary_start_kernel(void);
/* /*
* Initial data for bringing up a secondary CPU. * Initial data for bringing up a secondary CPU.
* @stack - sp for the secondary CPU
* @status - Result passed back from the secondary CPU to * @status - Result passed back from the secondary CPU to
* indicate failure. * indicate failure.
*/ */
struct secondary_data { struct secondary_data {
void *stack;
struct task_struct *task; struct task_struct *task;
long status; long status;
}; };

View File

@ -27,6 +27,7 @@
int main(void) int main(void)
{ {
DEFINE(TSK_ACTIVE_MM, offsetof(struct task_struct, active_mm)); DEFINE(TSK_ACTIVE_MM, offsetof(struct task_struct, active_mm));
DEFINE(TSK_CPU, offsetof(struct task_struct, cpu));
BLANK(); BLANK();
DEFINE(TSK_TI_FLAGS, offsetof(struct task_struct, thread_info.flags)); DEFINE(TSK_TI_FLAGS, offsetof(struct task_struct, thread_info.flags));
DEFINE(TSK_TI_PREEMPT, offsetof(struct task_struct, thread_info.preempt_count)); DEFINE(TSK_TI_PREEMPT, offsetof(struct task_struct, thread_info.preempt_count));
@ -99,7 +100,6 @@ int main(void)
DEFINE(SOFTIRQ_SHIFT, SOFTIRQ_SHIFT); DEFINE(SOFTIRQ_SHIFT, SOFTIRQ_SHIFT);
DEFINE(IRQ_CPUSTAT_SOFTIRQ_PENDING, offsetof(irq_cpustat_t, __softirq_pending)); DEFINE(IRQ_CPUSTAT_SOFTIRQ_PENDING, offsetof(irq_cpustat_t, __softirq_pending));
BLANK(); BLANK();
DEFINE(CPU_BOOT_STACK, offsetof(struct secondary_data, stack));
DEFINE(CPU_BOOT_TASK, offsetof(struct secondary_data, task)); DEFINE(CPU_BOOT_TASK, offsetof(struct secondary_data, task));
BLANK(); BLANK();
DEFINE(FTR_OVR_VAL_OFFSET, offsetof(struct arm64_ftr_override, val)); DEFINE(FTR_OVR_VAL_OFFSET, offsetof(struct arm64_ftr_override, val));

View File

@ -275,7 +275,7 @@ alternative_else_nop_endif
mte_set_kernel_gcr x22, x23 mte_set_kernel_gcr x22, x23
scs_load tsk, x20 scs_load tsk
.else .else
add x21, sp, #PT_REGS_SIZE add x21, sp, #PT_REGS_SIZE
get_current_task tsk get_current_task tsk
@ -375,7 +375,7 @@ alternative_if ARM64_WORKAROUND_845719
alternative_else_nop_endif alternative_else_nop_endif
#endif #endif
3: 3:
scs_save tsk, x0 scs_save tsk
#ifdef CONFIG_ARM64_PTR_AUTH #ifdef CONFIG_ARM64_PTR_AUTH
alternative_if ARM64_HAS_ADDRESS_AUTH alternative_if ARM64_HAS_ADDRESS_AUTH
@ -979,8 +979,8 @@ SYM_FUNC_START(cpu_switch_to)
mov sp, x9 mov sp, x9
msr sp_el0, x1 msr sp_el0, x1
ptrauth_keys_install_kernel x1, x8, x9, x10 ptrauth_keys_install_kernel x1, x8, x9, x10
scs_save x0, x8 scs_save x0
scs_load x1, x8 scs_load x1
ret ret
SYM_FUNC_END(cpu_switch_to) SYM_FUNC_END(cpu_switch_to)
NOKPROBE(cpu_switch_to) NOKPROBE(cpu_switch_to)

View File

@ -395,15 +395,29 @@ SYM_FUNC_START_LOCAL(__create_page_tables)
SYM_FUNC_END(__create_page_tables) SYM_FUNC_END(__create_page_tables)
/* /*
* Initialize CPU registers with task-specific and cpu-specific context.
*
* Create a final frame record at task_pt_regs(current)->stackframe, so * Create a final frame record at task_pt_regs(current)->stackframe, so
* that the unwinder can identify the final frame record of any task by * that the unwinder can identify the final frame record of any task by
* its location in the task stack. We reserve the entire pt_regs space * its location in the task stack. We reserve the entire pt_regs space
* for consistency with user tasks and kthreads. * for consistency with user tasks and kthreads.
*/ */
.macro setup_final_frame .macro init_cpu_task tsk, tmp1, tmp2
msr sp_el0, \tsk
ldr \tmp1, [\tsk, #TSK_STACK]
add sp, \tmp1, #THREAD_SIZE
sub sp, sp, #PT_REGS_SIZE sub sp, sp, #PT_REGS_SIZE
stp xzr, xzr, [sp, #S_STACKFRAME] stp xzr, xzr, [sp, #S_STACKFRAME]
add x29, sp, #S_STACKFRAME add x29, sp, #S_STACKFRAME
scs_load \tsk
adr_l \tmp1, __per_cpu_offset
ldr w\tmp2, [\tsk, #TSK_CPU]
ldr \tmp1, [\tmp1, \tmp2, lsl #3]
set_this_cpu_offset \tmp1
.endm .endm
/* /*
@ -412,22 +426,16 @@ SYM_FUNC_END(__create_page_tables)
* x0 = __PHYS_OFFSET * x0 = __PHYS_OFFSET
*/ */
SYM_FUNC_START_LOCAL(__primary_switched) SYM_FUNC_START_LOCAL(__primary_switched)
adrp x4, init_thread_union adr_l x4, init_task
add sp, x4, #THREAD_SIZE init_cpu_task x4, x5, x6
adr_l x5, init_task
msr sp_el0, x5 // Save thread_info
adr_l x8, vectors // load VBAR_EL1 with virtual adr_l x8, vectors // load VBAR_EL1 with virtual
msr vbar_el1, x8 // vector table address msr vbar_el1, x8 // vector table address
isb isb
stp xzr, x30, [sp, #-16]! stp x29, x30, [sp, #-16]!
mov x29, sp mov x29, sp
#ifdef CONFIG_SHADOW_CALL_STACK
adr_l scs_sp, init_shadow_call_stack // Set shadow call stack
#endif
str_l x21, __fdt_pointer, x5 // Save FDT pointer str_l x21, __fdt_pointer, x5 // Save FDT pointer
ldr_l x4, kimage_vaddr // Save the offset between ldr_l x4, kimage_vaddr // Save the offset between
@ -459,8 +467,7 @@ SYM_FUNC_START_LOCAL(__primary_switched)
0: 0:
#endif #endif
bl switch_to_vhe // Prefer VHE if possible bl switch_to_vhe // Prefer VHE if possible
add sp, sp, #16 ldp x29, x30, [sp], #16
setup_final_frame
bl start_kernel bl start_kernel
ASM_BUG() ASM_BUG()
SYM_FUNC_END(__primary_switched) SYM_FUNC_END(__primary_switched)
@ -645,14 +652,10 @@ SYM_FUNC_START_LOCAL(__secondary_switched)
isb isb
adr_l x0, secondary_data adr_l x0, secondary_data
ldr x1, [x0, #CPU_BOOT_STACK] // get secondary_data.stack
cbz x1, __secondary_too_slow
mov sp, x1
ldr x2, [x0, #CPU_BOOT_TASK] ldr x2, [x0, #CPU_BOOT_TASK]
cbz x2, __secondary_too_slow cbz x2, __secondary_too_slow
msr sp_el0, x2
scs_load x2, x3 init_cpu_task x2, x1, x3
setup_final_frame
#ifdef CONFIG_ARM64_PTR_AUTH #ifdef CONFIG_ARM64_PTR_AUTH
ptrauth_keys_init_cpu x2, x3, x4, x5 ptrauth_keys_init_cpu x2, x3, x4, x5

View File

@ -87,12 +87,6 @@ void __init smp_setup_processor_id(void)
u64 mpidr = read_cpuid_mpidr() & MPIDR_HWID_BITMASK; u64 mpidr = read_cpuid_mpidr() & MPIDR_HWID_BITMASK;
set_cpu_logical_map(0, mpidr); set_cpu_logical_map(0, mpidr);
/*
* clear __my_cpu_offset on boot CPU to avoid hang caused by
* using percpu variable early, for example, lockdep will
* access percpu variable inside lock_release
*/
set_my_cpu_offset(0);
pr_info("Booting Linux on physical CPU 0x%010lx [0x%08x]\n", pr_info("Booting Linux on physical CPU 0x%010lx [0x%08x]\n",
(unsigned long)mpidr, read_cpuid_id()); (unsigned long)mpidr, read_cpuid_id());
} }

View File

@ -120,9 +120,7 @@ int __cpu_up(unsigned int cpu, struct task_struct *idle)
* page tables. * page tables.
*/ */
secondary_data.task = idle; secondary_data.task = idle;
secondary_data.stack = task_stack_page(idle) + THREAD_SIZE;
update_cpu_boot_status(CPU_MMU_OFF); update_cpu_boot_status(CPU_MMU_OFF);
__flush_dcache_area(&secondary_data, sizeof(secondary_data));
/* Now bring the CPU into our world */ /* Now bring the CPU into our world */
ret = boot_secondary(cpu, idle); ret = boot_secondary(cpu, idle);
@ -142,8 +140,6 @@ int __cpu_up(unsigned int cpu, struct task_struct *idle)
pr_crit("CPU%u: failed to come online\n", cpu); pr_crit("CPU%u: failed to come online\n", cpu);
secondary_data.task = NULL; secondary_data.task = NULL;
secondary_data.stack = NULL;
__flush_dcache_area(&secondary_data, sizeof(secondary_data));
status = READ_ONCE(secondary_data.status); status = READ_ONCE(secondary_data.status);
if (status == CPU_MMU_OFF) if (status == CPU_MMU_OFF)
status = READ_ONCE(__early_cpu_boot_status); status = READ_ONCE(__early_cpu_boot_status);
@ -202,10 +198,7 @@ asmlinkage notrace void secondary_start_kernel(void)
u64 mpidr = read_cpuid_mpidr() & MPIDR_HWID_BITMASK; u64 mpidr = read_cpuid_mpidr() & MPIDR_HWID_BITMASK;
struct mm_struct *mm = &init_mm; struct mm_struct *mm = &init_mm;
const struct cpu_operations *ops; const struct cpu_operations *ops;
unsigned int cpu; unsigned int cpu = smp_processor_id();
cpu = task_cpu(current);
set_my_cpu_offset(per_cpu_offset(cpu));
/* /*
* All kernel threads share the same mm context; grab a * All kernel threads share the same mm context; grab a
@ -452,6 +445,11 @@ void __init smp_cpus_done(unsigned int max_cpus)
void __init smp_prepare_boot_cpu(void) void __init smp_prepare_boot_cpu(void)
{ {
/*
* The runtime per-cpu areas have been allocated by
* setup_per_cpu_areas(), and CPU0's boot time per-cpu area will be
* freed shortly, so we must move over to the runtime per-cpu area.
*/
set_my_cpu_offset(per_cpu_offset(smp_processor_id())); set_my_cpu_offset(per_cpu_offset(smp_processor_id()));
cpuinfo_store_boot_cpu(); cpuinfo_store_boot_cpu();

View File

@ -83,11 +83,7 @@ SYM_FUNC_START(cpu_do_suspend)
mrs x9, mdscr_el1 mrs x9, mdscr_el1
mrs x10, oslsr_el1 mrs x10, oslsr_el1
mrs x11, sctlr_el1 mrs x11, sctlr_el1
alternative_if_not ARM64_HAS_VIRT_HOST_EXTN get_this_cpu_offset x12
mrs x12, tpidr_el1
alternative_else
mrs x12, tpidr_el2
alternative_endif
mrs x13, sp_el0 mrs x13, sp_el0
stp x2, x3, [x0] stp x2, x3, [x0]
stp x4, x5, [x0, #16] stp x4, x5, [x0, #16]
@ -145,11 +141,7 @@ SYM_FUNC_START(cpu_do_resume)
msr mdscr_el1, x10 msr mdscr_el1, x10
msr sctlr_el1, x12 msr sctlr_el1, x12
alternative_if_not ARM64_HAS_VIRT_HOST_EXTN set_this_cpu_offset x13
msr tpidr_el1, x13
alternative_else
msr tpidr_el2, x13
alternative_endif
msr sp_el0, x14 msr sp_el0, x14
/* /*
* Restore oslsr_el1 by writing oslar_el1 * Restore oslsr_el1 by writing oslar_el1