从这个函数开始,boot_cpu_init,开始正式初始化CPU。
这是一个位于/kernel/cpu.c处展开的函数:
void __init boot_cpu_init(void)
{
int cpu = smp_processor_id();
/* Mark the boot cpu "present", "online" etc for SMP and UP case */
set_cpu_online(cpu, true);
set_cpu_active(cpu, true);
set_cpu_present(cpu, true);
set_cpu_possible(cpu, true);
#ifdef CONFIG_SMP
__boot_cpu_id = cpu;
#endif
}其中,smp_processor_id函数在/include/linux/smp.h中被展开为raw_smp_processor_id函数:

然后会在具体的arm64文件夹中展开为偏移量计算函数:

或者是直接给0
这里的smp id机制其实及其迷惑,并没有看懂具体的关联关系。
总之,在此时根据cpu值0进行四个操作
set_cpu_online(cpu, true);
set_cpu_active(cpu, true);
set_cpu_present(cpu, true);
set_cpu_possible(cpu, true);
它的代码为:
void set_cpu_online(unsigned int cpu, bool online)
{
if (online) {
if (!cpumask_test_and_set_cpu(cpu, &__cpu_online_mask)) // 这就是一个简单的判断标准
atomic_inc(&__num_online_cpus); // 这就是一个简单的原子位+1
} else {
if (cpumask_test_and_clear_cpu(cpu, &__cpu_online_mask))
atomic_dec(&__num_online_cpus);
}
}
set_cpu_active(unsigned int cpu, bool active)
{
if (active)
cpumask_set_cpu(cpu, &__cpu_active_mask);
else
cpumask_clear_cpu(cpu, &__cpu_active_mask);
}
static inline void
set_cpu_present(unsigned int cpu, bool present)
{
if (present)
cpumask_set_cpu(cpu, &__cpu_present_mask);
else
cpumask_clear_cpu(cpu, &__cpu_present_mask);
}
static inline void
set_cpu_possible(unsigned int cpu, bool possible)
{
if (possible)
cpumask_set_cpu(cpu, &__cpu_possible_mask);
else
cpumask_clear_cpu(cpu, &__cpu_possible_mask);
}看上去是很简单的,首先进行依次cpu的online检测,如果没在位,旧把__num_online_cpus+1。
其他的函数也几乎执行的是一模一样的动作,似乎就是针对对应的mask做了一个维护。
CPU子系统
上文提及的针对boot_cpu_init函数的动作,应该理解为一种软件上的标识准备。具体来说就是,这是一个针对CPU Subsystem资源池进行的,CPU0的一种初始化设置。
Subsystem本身包含了core层与Driver层两层,其中Core层主要提供一系列的API接口,用于被调用,而Driver层则是进行一系列的函数实例化。注意,只要是子系统,就一定会在虚拟文件系统中生成对应的file句柄,层级结构也将直接依托虚拟文件系统产生。
cpu mask定义在/kernel/cpu.c文件中:

相应的struct cpumask,则是一个直白的无穷长数组:

目前暂时没有什么好办法进一步确认里面的东西。