What is the process of arm64 multicore startup in Linux
Today, I would like to share with you the relevant knowledge about the multi-core startup process of arm64 in Linux. The content is detailed and the logic is clear. I believe most people still know too much about this knowledge, so share this article for your reference. I hope you can get something after reading this article.
Kernel: 4.12.8
Arm64 multicore startup process
Smp_init_cpus () / / set multicore startup parameters and actions
= > static int _ _ init smp_cpu_setup (int cpu) / / located in arch/arm64/kenerl/smp.c
= > cpu_read_ops
= > cpu_get_ops
{ops = acpi_disabled? Dt_supported_cpu_ops: acpi_supported_cpu_ops;}
.cpu _ init = smp_spin_table_cpu_init
/ / analyze the two ways to get start-up multicore from dts: spin_table and psci
Static const struct cpu_operations * dt_supported_cpu_ops [] _ _ initconst = {
& smp_spin_table_ops
& cpu_psci_ops
NULL
}
/ / several action interfaces in spin_table mode
Const struct cpu_operations smp_spin_table_ops = {
.name = "spin-table"
.cpu _ init = smp_spin_table_cpu_init
.cpu _ prepare = smp_spin_table_cpu_prepare
.CPU _ boot = smp_spin_table_cpu_boot, / / bring up actual action
}
Bringup_cpu
= > int _ cpu_up (unsigned int cpu, struct task_struct * idle)
= > ret = boot_secondary (cpu, idle)
Cpu_ OPS [CPU]-> cpu_boot (cpu); / / actually call startup such as smp_spin_table_cpu_boot
= =
The process of how to execute cpu_boot is analyzed below.
= =
Static struct cpuhp_step cpuhp_bp_states [] =
/ * Kicks the plugged cpu into life * /
[CPUHP_BRINGUP_CPU] = {
.name = "cpu:bringup"
.startup.single = bringup_cpu
.teardown.single = NULL
.cant _ stop = true
}
Cpuhp_get_step () / / there are multiple steps to evoke a core, which selects the corresponding state action according to the state
Sp = cpuhp_is_ap_state (state)? Cpuhp_ap_states: cpuhp_bp_states
Return sp + state
Kernel_init () = > kernel_init_freeable ()
| | = > void _ init smp_prepare_cpus (unsigned int max_cpus) |
/ *
* Initialise the present map (which describes the set of CPUs
* actually populated at the present time) and release the
* secondaries from the bootloader.
, /
For_each_possible_cpu (cpu) {
Err = cpu_ OPS [CPU]-> cpu_prepare (cpu)
| | = > smp_init = > cpu_up= > do_cpu_up / / is also called from kernel_init_freeable () |
= > _ cpu_up (unsigned int cpu, int tasks_frozen, enum cpuhp_state target)
= > cpuhp_up_callbacks
= > cpuhp_invoke_callback (unsigned int cpu, enum cpuhp_state state
Bool bringup, struct hlist_node * node)
{
If (! step- > multi_instance) {
Cb = bringup? Step- > startup.single: step- > teardown.single
Ret = cb (cpu)
/ / the bringup_cpu is actually taken out here and called
}
Starting in spin table mode actually writes the address into spin table, and then issues sev (send envent, an instruction) to run from the core.
The call to smp_spin_table_cpu_prepare () in smp_prepare_cpus () starts running from the core, but the kernel sets wfe to wait for the real task to actually execute.
Calling smp_spin_table_cpu_boot () in smp_init () actually starts an idle task (to be confirmed)
Static int smp_spin_table_cpu_prepare (unsigned int cpu) {_ _ le64 _ _ iomem * release_addr; if (! cpu_release_ addr [CPU]) return-ENODEV; / * * The cpu-release-addr may or may not be inside the linear mapping. * As ioremap_cache will either give us a new mapping or reuse the * existing linear mapping, we can use it to cover both cases. In * either case the memory will be MT_NORMAL. * / release_addr = ioremap_cache (cpu_release_addr [cpu], sizeof (* release_addr)); if (! release_addr) return-ENOMEM; / * * We write the release address as LE regardless of the native * endianess of the kernel. Therefore, any boot-loaders that * read this address need to convert this address to the * boot-loader's endianess before jumping. This is mandated by * the boot protocol. * / writeq_relaxed (_ _ pa_symbol (secondary_holding_pen), release_addr); _ _ flush_dcache_area ((_ _ force void *) release_addr, sizeof (* release_addr)); / * Send an event to wake up the secondary CPU. * / sev (); iounmap (release_addr); return 0;} static int smp_spin_table_cpu_boot (unsigned int cpu) {/ * * Update the pen release flag. * / write_pen_release (cpu_logical_map (cpu)); / * * Send an event, causing the secondaries to read pen_release. * / sev (); return 0;} these are all the contents of the article "what is the multicore startup process of arm64 in Linux?" Thank you for reading! I believe you will gain a lot after reading this article. The editor will update different knowledge for you every day. If you want to learn more knowledge, please pay attention to the industry information channel.