smp启动-setup_nr_cpu_ids-smp_prepare_boot_cpu
上一篇: setup_arch->smp_init_cpus
https://www.cnblogs.com/zhangzhiwei122/p/16091111.html
start_kernel -> setup_nr_cpu_ids & smp_prepare_boot_cpu
848asmlinkage __visible void __init __no_sanitize_address start_kernel(void) 849{ 873 setup_nr_cpu_ids(); 874 setup_per_cpu_areas(); 875 smp_prepare_boot_cpu(); /* arch-specific boot-cpu hooks */ 876 boot_cpu_hotplug_init(); 877
873 - 设置 nr_cpu_ids 这个变量,表示真实存在的 possible cpus 。因为前面setup_arch 里面已经根据 dtb ,知道了设备的 cpu 信息。
874 - setup_pre_cpu_areas ,为每一个cpu , 设置 per cpu 变量存储空间 。
875 smp_prepare_boot_cpu , 将 boot cpu 的 信息 存储在 per cpu 变量 cpu_data 里面。
smp_prepare_boot_cpu
1、cpu_data 这个 per_cpu 结构体对象里面填充 cpu 寄存器的值。
2、根据cpu_data 值,初始化 cpu features 模块
3、根据cpu feature 模块初始化结果,再初始化 boot cpu alternatives
4、如果系统使用 irq prio mask, 调用 init_gic_priority_masking
arch/arm64/kernel/smp.c
450void __init smp_prepare_boot_cpu(void) 451{ 452 set_my_cpu_offset(per_cpu_offset(smp_processor_id())); 453 cpuinfo_store_boot_cpu(); 454 455 /* 456 * We now know enough about the boot CPU to apply the 457 * alternatives that cannot wait until interrupt handling 458 * and/or scheduling is enabled. 459 */ 460 apply_boot_alternatives(); 461 462 /* Conditionally switch to GIC PMR for interrupt masking */ 463 if (system_uses_irq_prio_masking()) 464 init_gic_priority_masking(); 465}
452 - set my cpu offset , 因为 在进入 smp_prepare_boot_cpu 前,使用setup_per_cpu_areas 真正 设置了 各个CPU 的per cpu data 区域和偏移。
后面,boot cpu 应使用自己的一份拷贝,而不是 原始的 per cpu data . 所以,使用 set_my_cpu_offset 设置 offset
相关信息: 前面设置 boot cpu offset 为 0 : https://www.cnblogs.com/zhangzhiwei122/p/16051676.html
per cpu 相关: https://www.cnblogs.com/zhangzhiwei122/p/16054141.html
453 设置 cpu info
arch/arm64/include/asm/cpu.h 中定义 struct cpuinfo_arm64
arch/arm64/kernel/cpuinfo.c 定义函数 cpuinfo_store_boot_cpu
414void __init cpuinfo_store_boot_cpu(void) 415{ 416 struct cpuinfo_arm64 *info = &per_cpu(cpu_data, 0); 417 __cpuinfo_store_cpu(info); 418 419 boot_cpu_data = *info; 420 init_cpu_features(&boot_cpu_data); 421}
416 - 取得 cpu_data 这个 struct cpuinfo_arm64 结构体对象的指针
417 - 指针传入 __cpuinfo_store_cpu ,在次函数中,读取 cpu 寄存器,将寄存器里面的值,写入 cpu_data 指向对象
419 拷贝一份 cpuinfo_arm64 对象,放在 boot_cpu_data 里面
420 调用 init_cpu_features ,这个在 arch/arm64/kernel/cpufeature.c 中,cpu feature ,cpu 特定的功能,根据寄存器某个bit 位的值,来判断某个feature 是否启用? 这个暂时略
在 arch/arm64/kernel/cpufeature.c 中,定义了 boot_capabilities ,init_cpu_features 初始化这个值, 然后 apply_boot_altenatives 依赖它里面的值。
102 DECLARE_BITMAP(boot_capabilities, ARM64_NPATCHABLE);
apply_boot_alternatives
arch/arm64/kernel/alternative.c
135static void __apply_alternatives(void *alt_region, bool is_module, 136 unsigned long *feature_mask) 137{ 232/* 233 * This is called very early in the boot process (directly after we run 234 * a feature detect on the boot CPU). No need to worry about other CPUs 235 * here. 236 */ 237void __init apply_boot_alternatives(void) 238{ 239 struct alt_region region = { 240 .begin = (struct alt_instr *)__alt_instructions, 241 .end = (struct alt_instr *)__alt_instructions_end, 242 }; 243 244 /* If called on non-boot cpu things could go wrong */ 245 WARN_ON(smp_processor_id() != 0); 246 247 __apply_alternatives(®ion, false, &boot_capabilities[0]); 248}
135 - 定义了 __apply_alternatives 函数,具体实现,需要 了解 alternative instruction 背景,暂时略。
237 定义 apply_boot_alternatives
239 ~ 242 取 kernel image 里面的 __alt_instructions 节的开始和结尾,组成 alt_region 对象,247 行,用这个对象调用 135 行定义的函数。
priority masking
检查 是否是否使用 irq priority masking ,这个在 arch/arm64/include/asm/cpufeature.h 中,根据 menuconfig 配置和 cpu 寄存器值共同决定
702static __always_inline bool system_uses_irq_prio_masking(void) 703{ 704 return IS_ENABLED(CONFIG_ARM64_PSEUDO_NMI) && 705 cpus_have_const_cap(ARM64_HAS_IRQ_PRIO_MASKING); 706}
Priority Masking(优先级屏蔽)
GICC_PMR定义了目标处理器的优先级阈值。GIC仅上报那些优先级高于这个阈值的pending中断。初始值为0,屏蔽所有的中断。
181static void init_gic_priority_masking(void) 182{ 192 gic_write_pmr(GIC_PRIO_IRQON | GIC_PRIO_PSR_I_SET); 193}
向 gic pmr 寄存器写入内容,初始化 priority masking
下一篇: boot_cpu_hotplug_init
https://www.cnblogs.com/zhangzhiwei122/p/16092269.html