基于arm64的linux kernel cpu 初始化分析

从start_kernel开始分析

init/main.c

start_kernel
    |
    smp_setup_processor_id
    |
    setup_arch
    |
    setup_nr_cpu_ids
    |
    setup_per_cpu_areas
    |
    smp_prepare_boot_cpu
    |
    boot_cpu_hotplug_init
    |
    arch_call_rest_init
    

smp_setup_processor_id, 以arm64为例:

arch/arm64/kernel/setup.c
void __init smp_setup_processor_id(void)
{
        // 读取mpidr寄存器并通过掩码获取affinity值
        u64 mpidr = read_cpuid_mpidr() & MPIDR_HWID_BITMASK;
        //给boot cpu设置mpidr affinity,因为当前函数是初始化时调用的,所以cpu number一定是0
        set_cpu_logical_map(0, mpidr);

        pr_info("Booting Linux on physical CPU 0x%010lx [0x%08x]\n",
                (unsigned long)mpidr, read_cpuid_id());
}

分析setup_arch

void __init __no_sanitize_address setup_arch(char **cmdline_p)
{
...
/* Parse the ACPI tables for possible boot-time configuration */
//初始化acpi 表
	acpi_boot_table_init();
...
    //给bootcpu,一般是cpu0, 初始化boot方式,从dt或者acpi表中获取,acpi的方法有psci和parking-protocol
    init_bootcpu_ops();
    //从dt或者acpi的madt表中获取cpu信息,填充逻辑cpu map并setup cpu
	smp_init_cpus();
    //压缩cpu mpidr的信息到mpidr_hash结构体中
	smp_build_mpidr_hash();
...
}

分析smp_init_cpus

arch/arm64/kernel/smp.c

void __init smp_init_cpus(void)
{
    int i;

    //获取cpu信息并初始化cpu_logical_map
	if (acpi_disabled)
		of_parse_and_init_cpus();
	else
		acpi_parse_and_init_cpus();
...
    //setup cpu,这里设置的cpu的数量是机器上已有的cpu数量,从dt或qcpi表中获取,和nr_cpus的较小的值
    for (i = 1; i < nr_cpu_ids; i++) {
		if (cpu_logical_map(i) != INVALID_HWID) {
			if (smp_cpu_setup(i))
				set_cpu_logical_map(i, INVALID_HWID);
		}
	}
}

cpu_logical_map是一个位图,index是cpu counter,从0到NR_CPUS,这个值是config_nr_cpus确定的,也就是编译时确定的。value是cpu的hwid,从dt或acpi的madt表中获取。初始化cpu_logical_map的路径是:acpi_parse_and_init_cpus->acpi_parse_gic_cpu_interface->acpi_map_gic_cpu_interface->set_cpu_logical_map

来看看acpi_map_gic_cpu_interface这个函数干了啥

static void __init
acpi_map_gic_cpu_interface(struct acpi_madt_generic_interrupt *processor)
{
    //从madt表获得cpu mpidr信息
	u64 hwid = processor->arm_mpidr;

    //这个地方对于cpu hotplug有意义,对于还没有enable但是可以在之后enable的cpu可以在这里进行处理。可以认为acpi给未来插入的cpu留了位置
	if (!(processor->flags & ACPI_MADT_ENABLED)) {
		pr_debug("skipping disabled CPU entry with 0x%llx MPIDR\n", hwid);
		return;
	}
......

	if (cpu_count >= NR_CPUS)
		return;

	//建立hwid和cpu counter的映射
	set_cpu_logical_map(cpu_count, hwid);

	cpu_madt_gicc[cpu_count] = *processor;

	//跟AP(除boot cpu之外的cpu)启动有关
	acpi_set_mailbox_entry(cpu_count, processor);

	cpu_count++;
}

未完待续。。。

arch_call_rest_init差不多是start_kernel最后做的事情了。

arch_call_rest_init->rest_init->kernel_init

kernel_init是pid为1的线程.

kernel_init_freeable->smp_prepare_cpus

  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值