linux 4.1设备树解析源码跟踪

asmlinkage __visible void __init start_kernel(void)
{
char *command_line;
setup_arch(&command_line);
setup_command_line(command_line);
}

//这个setup_arch就是各个架构自己的设置函数,哪个参与了编译就调用哪个,arm架构应当是arch/arm/kernel/setup.c中的 setup_arch。void __init setup_arch(char **cmdline_p)
{
const struct machine_desc *mdesc;

setup_processor();

setup_machine_fdt函数获取内核前期初始化所需的bootargs,cmd_line等系统引导参数
//__atags_pointer是bootloader传递参数的物理地址
mdesc = setup_machine_fdt(__atags_pointer);
if (!mdesc)
mdesc = setup_machine_tags(__atags_pointer, __machine_arch_type);

/* populate cmd_line too for later use, preserving boot_command_line */
strlcpy(cmd_line, boot_command_line, COMMAND_LINE_SIZE);

//这是setup_arch的参数出参赋值
*cmdline_p = cmd_line;

parse_early_param();

解析设备树
unflatten_device_tree();

arm_dt_init_cpu_maps();
psci_init();

if (!is_smp())
    hyp_mode_check();

reserve_crashkernel();


if (mdesc->init_early)
    mdesc->init_early();

}

/**

  • unflatten_device_tree - create tree of device_nodes from flat blob

  • unflattens the device-tree passed by the firmware, creating the

  • tree of struct device_node. It also fills the “name” and “type”

  • pointers of the nodes so the normal device-tree walking functions

  • can be used.
    */
    void __init unflatten_device_tree(void)
    {
    __unflatten_device_tree(initial_boot_params, &of_root,
    early_init_dt_alloc_memory_arch);

    /* Get pointer to “/chosen” and “/aliases” nodes for use everywhere */
    of_alias_scan(early_init_dt_alloc_memory_arch);
    }

///

/*

  • arm_dt_init_cpu_maps - Function retrieves cpu nodes from the device tree

  • and builds the cpu logical map array containing MPIDR values related to

  • logical cpus

  • Updates the cpu possible mask with the number of parsed cpu nodes
    /
    void __init arm_dt_init_cpu_maps(void)
    {
    /

    • Temp logical map is initialized with UINT_MAX values that are
    • considered invalid logical map entries since the logical map must
    • contain a list of MPIDR[23:0] values where MPIDR[31:24] must
    • read as 0.
      */
      struct device_node *cpu, *cpus;
      int found_method = 0;
      u32 i, j, cpuidx = 1;
      u32 mpidr = is_smp() ? read_cpuid_mpidr() & MPIDR_HWID_BITMASK : 0;

    u32 tmp_map[NR_CPUS] = { [0 … NR_CPUS-1] = MPIDR_INVALID };
    bool bootcpu_valid = false;
    cpus = of_find_node_by_path(“/cpus”);

    if (!cpus)
    return;

    for_each_child_of_node(cpus, cpu) {
    u32 hwid;

     if (of_node_cmp(cpu->type, "cpu"))
         continue;
    
     pr_debug(" * %s...\n", cpu->full_name);
     /*
      * A device tree containing CPU nodes with missing "reg"
      * properties is considered invalid to build the
      * cpu_logical_map.
      */
     if (of_property_read_u32(cpu, "reg", &hwid)) {
         pr_debug(" * %s missing reg property\n",
                  cpu->full_name);
         return;
     }
    
     /*
      * 8 MSBs must be set to 0 in the DT since the reg property
      * defines the MPIDR[23:0].
      */
     if (hwid & ~MPIDR_HWID_BITMASK)
         return;
    
     /*
      * Duplicate MPIDRs are a recipe for disaster.
      * Scan all initialized entries and check for
      * duplicates. If any is found just bail out.
      * temp values were initialized to UINT_MAX
      * to avoid matching valid MPIDR[23:0] values.
      */
     for (j = 0; j < cpuidx; j++)
         if (WARN(tmp_map[j] == hwid, "Duplicate /cpu reg "
                          "properties in the DT\n"))
             return;
    
     /*
      * Build a stashed array of MPIDR values. Numbering scheme
      * requires that if detected the boot CPU must be assigned
      * logical id 0. Other CPUs get sequential indexes starting
      * from 1. If a CPU node with a reg property matching the
      * boot CPU MPIDR is detected, this is recorded so that the
      * logical map built from DT is validated and can be used
      * to override the map created in smp_setup_processor_id().
      */
     if (hwid == mpidr) {
         i = 0;
         bootcpu_valid = true;
     } else {
         i = cpuidx++;
     }
    
     if (WARN(cpuidx > nr_cpu_ids, "DT /cpu %u nodes greater than "
                        "max cores %u, capping them\n",
                        cpuidx, nr_cpu_ids)) {
         cpuidx = nr_cpu_ids;
         break;
     }
    
     tmp_map[i] = hwid;
    
     if (!found_method)
         found_method = set_smp_ops_by_method(cpu);
    

    }

    /*

    • Fallback to an enable-method in the cpus node if nothing found in
    • a cpu node.
      */
      if (!found_method)
      set_smp_ops_by_method(cpus);

    if (!bootcpu_valid) {
    pr_warn(“DT missing boot CPU MPIDR[23:0], fall back to default cpu_logical_map\n”);
    return;
    }

    /*

    • Since the boot CPU node contains proper data, and all nodes have
    • a reg property, the DT CPU list can be considered valid and the
    • logical map created in smp_setup_processor_id() can be overridden
      */
      for (i = 0; i < cpuidx; i++) {
      set_cpu_possible(i, true);
      cpu_logical_map(i) = tmp_map[i];
      pr_debug(“cpu logical map 0x%x\n”, cpu_logical_map(i));
      }
      }
      ///

static const struct of_device_id psci_of_match[] __initconst = {
{ .compatible = “arm,psci”, .data = psci_0_1_init},
{ .compatible = “arm,psci-0.2”, .data = psci_0_2_init},
{},
};

int __init psci_init(void)
{
struct device_node *np;
const struct of_device_id *matched_np;
psci_initcall_t init_fn;

np = of_find_matching_node_and_match(NULL, psci_of_match, &matched_np);
if (!np)
    return -ENODEV;

init_fn = (psci_initcall_t)matched_np->data;
return init_fn(np);

}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

xx-xx-xxx-xxx

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值