aarch64架构secondary cpu的内核入口函数为secondary_entry(arch/arm64/kernel/head.S),以下为其执行主流程:
由于其底层相关初始化流程与primary cpu类似,因此此处不再介绍。我们这里主要看一下它是如何通过secondary_start_kernel启动idle线程的:
asmlinkage notrace void secondary_start_kernel(void)
{
struct mm_struct *mm = &init_mm;
…
current- >active_mm = mm; (1)
cpu_uninstall_idmap(); (2)
…
ops = get_cpu_ops(cpu);
if (ops- >cpu_postboot)
ops- >cpu_postboot(); (3)
…
set_cpu_online(cpu, true); (4)
complete(&cpu_running); (5)
…
cpu_startup_entry(CPUHP_AP_ONLINE_IDLE); (6)
}
(1)由于内核线程并没有用于地址空间,因此其active_mm通常指向上一个用户进程的地址空间。而cpu初始化时,由于之前并没有运行过用户进程,因此将其初始化为init_mm
(2)idmap地址映射仅仅是用于mmu使能时地址空间的平滑切换,在mmu使能完成后已经没有作用。更进一步,由于idmap页表所使用的ttbr0_elx页表基地址寄存器,正常情况下是用于用户空间页表的,在调度器接管该cpu之前也必须要将其归还给用户空间
(3)执行cpu_postboot回调
(4)由secondary cpu已经启动成功,故将其设置为online状态
(5)唤醒cpu hotplug线程
(6)让cpu执行idle线程,其代码实现如下:
void cpu_startup_entry(enum cpuhp_state state)
{
arch_cpu_idle_prepare();
cpuhp_online_idle(state);
while (1)
do_idle();
}
至此,cpu已经启动完成,并开始执行idle线程了。最后当然是要通知调度器,将该cpu的管理权限移交给调度器了。它是通过cpu hotplug的以下回调实现的:
static struct cpuhp_step cpuhp_hp_states[] = {
…
[CPUHP_AP_SCHED_STARTING] = {
.name = "sched:starting",
.startup.single = sched_cpu_starting,
.teardown.single = sched_cpu_dying,
}
…
}
以下为该函数的实现:
int sched_cpu_starting(unsigned int cpu)
{
…
sched_rq_cpu_starting(cpu); (1)
sched_tick_start(cpu); (2)
…
}
(1)用于初始化负载均衡相关参数,此后该cpu就可以在其后的负载均衡流程中拉取进程
(2)tick时钟是内核调度器的脉搏,启动了该时钟之后,cpu就会在时钟中断中执行调度操作,从而让cpu参与到系统的调度流程中
全部0条评论
快来发表一下你的评论吧 !