Kernel启动流程源码解析 6 setup_arch


一 setup_arch

setup_arch顾名思义就是架构相关的初始化函数,这里选取arm64结构进行分析。

1.0 setup_arch

定义在arch/arm64/kernel/setup.c中
void __init setup_arch(char **cmdline_p)
{
    setup_processor(); // 检测处理器类型,并初始化处理器相关的底层变量

    setup_machine_fdt(__fdt_pointer); // 获取device tree信息,并设置一些device tree相关全局变量信息
    init_mm.start_code = (unsigned long) _text; // 记录kernel代码段的虚拟启始地址
    init_mm.end_code   = (unsigned long) _etext; // 记录kernel代码段的虚拟结束地址
    init_mm.end_data   = (unsigned long) _edata; // 记录kernel数据段的虚拟结束地址
    init_mm.brk       = (unsigned long) _end; // brk指向kernel全部段的虚拟结束地址

    *cmdline_p = boot_command_line; // 将boot_command_line的地址保存到start_kernel局部指针变量cmdline_p中

    parse_early_param(); // 解析需要'早期'处理的启动参数用

    arm64_memblock_init(); // 初始化memblock,用于引导阶段的内存管理

    paging_init(); // 初始化分页机制
    request_standard_resources(); // 申请内核代码段和数据段内存资源

    unflatten_device_tree(); // DTB转换成节点是device_node的树状结构

    psci_init(); // Power State Coordination Interface,和多核启动相关,暂时没有用到

    cpu_logical_map(0) = read_cpuid_mpidr() & MPIDR_HWID_BITMASK;
    cpu_read_bootcpu_ops(); // 获取cpu0的enable method
#ifdef CONFIG_SMP
    smp_init_cpus(); // 获取除cpu0外的其他cpu信息,并将它们设为possible状态
    smp_build_mpidr_hash(); // 生成MPIDR(cpu id) hash
#endif

#ifdef CONFIG_VT // 虚拟终端
#if defined(CONFIG_VGA_CONSOLE)
    conswitchp = &vga_con;
#elif defined(CONFIG_DUMMY_CONSOLE)
    conswitchp = &dummy_con;
#endif
#endif
}



1.1 setup_processor

定义在arch/arm64/kernel/setup.c中
static void __init setup_processor(void)
{
    struct cpu_info *cpu_info;

    /*
     * locate processor in the list of supported processor
     * types.  The linker builds this table for us from the
     * entries in arch/arm/mm/proc.S
     */
    cpu_info = lookup_processor_type(read_cpuid_id());
    if (!cpu_info) {
        printk("CPU configuration botched (ID %08x), unable to continue.\n",
               read_cpuid_id());
        while (1);
    }

    cpu_name = cpu_info->cpu_name;

    printk("CPU: %s [%08x] revision %d\n",
           cpu_name, read_cpuid_id(), read_cpuid_id() & 15);

    sprintf(init_utsname()->machine, "aarch64");
    elf_hwcap = 0;
}

struct cpu_info cpu_table[] = {
    {
        .cpu_id_val = 0x000f0000,
        .cpu_id_mask    = 0x000f0000,
        .cpu_name   = "AArch64 Processor",
        .cpu_setup  = __cpu_setup,
    },
    { /* Empty */ },
};

1.2 setup_machine_fdt

定义在arch/arm64/kernel/setup.c中
static void __init setup_machine_fdt(phys_addr_t dt_phys)
{
    struct boot_param_header *devtree;
    unsigned long dt_root;

    /* Check we have a non-NULL DT pointer */
    if (!dt_phys) {
        early_print("\n"
            "Error: NULL or invalid device tree blob\n"
            "The dtb must be 8-byte aligned and passed in the first 512MB of memory\n"
            "\nPlease check your bootloader.\n");

        while (true)
            cpu_relax();

    }

    devtree = phys_to_virt(dt_phys);

    /* Check device tree validity */
    if (be32_to_cpu(devtree->magic) != OF_DT_HEADER) {
        early_print("\n"
            "Error: invalid device tree blob at physical address 0x%p (virtual address 0x%p)\n"
            "Expected 0x%x, found 0x%x\n"
            "\nPlease check your bootloader.\n",
            dt_phys, devtree, OF_DT_HEADER,
            be32_to_cpu(devtre
  • 0
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
kernel 5.10 的启动流程可以通过以下几个步骤来描述: 1. U-Boot 加载 kernel:U-Boot 是一个开源的引导加载程序,它负责从设备存储器中加载 kernel 到内存中。 2. start_kernel():在 kernel 的启动过程中,会调用 start_kernel() 函数,该函数位于 init/main.c 文件中。start_kernel() 函数主要负责处理 U-Boot 传递给 kernel 的参数,并调用 setup_arch() 函数进行架构的初始化。 3. setup_arch():setup_arch() 函数位于 arch/arm/kernel/Setup.c 文件中,它主要负责设置系统的硬件架构相关的参数,如设置页表等。 4. rest_init():rest_init() 函数位于 init/main.c 文件中,它是初始化过程的核心函数之一。在 rest_init() 中,会调用 kernel_init() 函数来进行进一步的初始化。 5. kernel_init():kernel_init() 函数位于 init/main.c 文件中,它是整个系统初始化的入口函数。在 kernel_init() 函数中,会进行各种初始化操作,如初始化调度器、内存管理、设备驱动等。 6. prepare_namespace():prepare_namespace() 函数位于 init/main.c 文件中,它负责设置系统的命名空间,并挂载根文件系统。 7. mount_root():mount_root() 函数位于 init/do_mounts.c 文件中,它负责挂载根文件系统。 8. init_post():init_post() 函数位于 init/main.c 文件中,它是系统初始化的最后一步。在 init_post() 函数中,会执行 run_init_process() 函数来启动 init 进程,它可以是 /sbin/init、/etc/init、/bin/init 或 /bin/sh 等。 以上是 kernel 5.10 的启动流程,包括了 U-Boot 加载 kernel、start_kernel()、setup_arch()、rest_init()、kernel_init()、prepare_namespace()、mount_root() 和 init_post() 等关键步骤。

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值