核心游记之 setup_arch

本文深入剖析了在启动过程中,setup_arch函数如何在ARM平台上进行体系结构相关的初始化,包括处理器初始化、内存结构初始化和MMU配置。通过对不同参数的处理,如command_line,tags,以及machine_desc结构,该函数确保内核正确配置并为后续操作做好准备。

真正的代码来了,后后

调用 setup_arch()函数进行与体系结构相关的第一个初始化工作;
对不同的体系结构来说该函数有不同的定义。对于 ARM 平台而言,该函数定义在arch/arm/kernel/Setup.c。它首先通过检测出来的处理器类型进行处理器内核的初始化,然后通过 bootmem_init()函数根据系统定义的 meminfo 结构进行内存结构的初始化,最后调用paging_init()开启 MMU,创建内核页表,映射所有的物理内存和 IO空间。

 

 

start_kernel中调用:

char * command_line; // 普通字符指针,看来是要返回字符串的地址

setup_arch(&command_line);

 

函数实现在 arch/arm/kernel/Setup.c 对内核参数的解析

void __init setup_arch(char **cmdline_p)
{
    struct tag *tags = (struct tag *)&init_tags;
    struct machine_desc *mdesc;
    char *from = default_command_line; //定义了一个指向default_command_line的指针,arm中是1024 的字符数组

    setup_processor(); //设置处理器的类型,并进行初始化.
    mdesc = setup_machine(machine_arch_type);
    machine_name = mdesc->name;

    if (mdesc->soft_reboot)
        reboot_setup("s");

    if (mdesc->boot_params)
        tags = phys_to_virt(mdesc->boot_params);

    /*
     * If we have the old style parameters, convert them to
     * a tag list.
     */
    if (tags->hdr.tag != ATAG_CORE)
        convert_to_tag_list(tags);
    if (tags->hdr.tag != ATAG_CORE)
        tags = (struct tag *)&init_tags;

    if (mdesc->fixup)
        mdesc->fixup(mdesc, tags, &from, &meminfo);

    if (tags->hdr.tag == ATAG_CORE) {
        if (meminfo.nr_banks != 0)
            squash_mem_tags(tags);
        parse_tags(tags);
    }

    init_mm.start_code = (unsigned long) &_text;
    init_mm.end_code   = (unsigned long) &_etext;
    init_mm.end_data   = (unsigned long) &_edata;
    init_mm.brk       = (unsigned long) &_end;

    memcpy(saved_command_line, from, COMMAND_LINE_SIZE);
    saved_command_line[COMMAND_LINE_SIZE-1] = '/0';
    parse_cmdline(cmdline_p, from);
    paging_init(&meminfo, mdesc);
    request_standard_resources(&meminfo, mdesc);

    cpu_init();

    /*
     * Set up various architecture-specific pointers
     */
    init_arch_irq = mdesc->init_irq;
    system_timer = mdesc->timer;
    init_machine = mdesc->init_machine;

#ifdef CONFIG_VT
#if defined(CONFIG_VGA_CONSOLE)
    conswitchp = &vga_con;
#elif defined(CONFIG_DUMMY_CONSOLE)
    conswitchp = &dummy_con;
#endif
#endif
}

<think>嗯,我现在需要理解Linux内核中setup_arch函数的调用逻辑。首先,我应该回忆一下内核启动的大致流程。内核启动通常从arch相关的汇编代码开始,然后跳转到C语言编写的初始化函数。setup_arch好像是其中一个重要的函数,但具体在哪个阶段调用呢? 我记得在内核启动过程中,start_kernel函数是C语言入口点,而setup_arch就是被start_kernel调用的。那setup_arch的作用是什么呢?应该是负责架构相关的初始化,比如解析设备树、初始化内存、设置处理器信息等。不同的架构(比如ARM、x86)会有不同的实现,对吗? 接下来,我需要理清setup_arch的具体调用流程。首先,start_kernel在init/main.c中定义,它会调用setup_arch(&command_line)。这里的参数是命令行参数,可能用于传递启动时的配置信息。setup_arch函数应该属于arch目录下的某个文件,比如ARM架构可能在arch/arm/kernel/setup.c里。 在setup_arch内部,可能会先进行早期内存管理初始化,比如解析设备树或者ACPI表,确定物理内存布局。然后设置处理器相关的信息,比如CPU型号、频率等。接着可能会保留某些内存区域,比如内核代码、数据段,初始化页表,建立虚拟内存映射。对于支持设备树的架构,可能还会解析设备树,获取硬件信息,比如中断控制器、定时器等。 可能还有其他步骤,比如初始化系统定时器,设置中断控制器,或者处理特定平台的设置。比如ARM的machine_desc结构,用来描述特定板级的配置,这个结构可能在setup_arch中被使用到,通过匹配设备树中的兼容性字符串来选择正确的初始化函数。 不过,我可能有些细节记不太清楚。比如,setup_arch是否直接调用解析设备树的函数,还是通过其他辅助函数?设备树的解析可能是在early_init_dt_scan之类的函数中完成的,而setup_arch会调用这些函数。另外,内存管理相关的初始化可能包括调用paging_init来设置页表,而mem_init可能用来初始化内存数据结构的其他部分。 不同的架构可能有不同的步骤,比如x86可能需要处理BIOS提供的信息,而ARM则更多依赖设备树。所以setup_arch的实现会根据架构的不同而有差异。但总体而言,它的主要职责是初始化硬件相关的部分,为后续的内核启动流程做好准备。 可能需要查阅一下Linux内核源码来确认这些步骤。比如,在ARM架构中,setup_arch函数会调用setup_processor来识别CPU类型,setup_machine_fdt来查找匹配的machine_desc,然后early_init_dt_scan_nodes来解析设备树的早期信息。接着,设置内存,包括解析内存节点,调用arm_memblock_init来保留内存区域,然后调用paging_init来初始化页表,之后可能还有设备树的进一步解析,比如unflatten_device_tree。 总结一下,setup_arch的主要调用逻辑可能包括以下几个步骤: 1. 解析设备树或ACPI信息,确定硬件配置。 2. 初始化处理器相关信息,如CPU型号、特性。 3. 设置内存布局,保留内核使用的内存区域。 4. 初始化页表,启用虚拟内存。 5. 解析和处理特定于板级的配置(如machine_desc结构)。 6. 为后续的驱动初始化和子系统启动准备硬件环境。 不过,可能会有遗漏或者顺序上的不同,需要进一步确认。比如,是否先初始化处理器信息再解析设备树?或者先确定内存布局再进行页表设置?这些细节可能需要参考具体的架构实现。</think>在Linux内核启动过程中,`setup_arch` 是一个关键的架构相关初始化函数。以下是其调用逻辑的逐步解析: --- ### **1. 调用入口** - **位置**: `start_kernel` 函数(位于 `init/main.c`)。 - **触发时机**: 内核完成早期汇编初始化后,进入C语言阶段的第一个重要步骤。 - **代码示例**: ```c asmlinkage __visible void __init start_kernel(void) { ... setup_arch(&command_line); ... } ``` --- ### **2. 核心职责** `setup_arch` 负责架构和硬件相关的初始化,主要任务包括: 1. **解析硬件信息**: - 通过设备树(DT)、ACPI或BIOS获取硬件配置。 - 示例:ARM架构调用 `setup_machine_fdt()` 解析设备树。 2. **初始化内存管理**: - 调用 `early_init_dt_scan_nodes()` 扫描设备树内存节点。 - 通过 `memblock` 保留内核代码、数据段和保留内存区域。 - 最终移交内存管理给伙伴系统(Buddy System)。 3. **处理器初始化**: - 识别CPU型号(如ARM的 `setup_processor()`)。 - 配置CPU特性(如浮点支持、多核信息)。 4. **页表与虚拟内存**: - 调用 `paging_init()` 初始化页表,启用虚拟内存(MMU)。 5. **板级特定配置**: - 匹配 `machine_desc` 结构体(描述板级硬件,如设备树中的 `compatible` 字段)。 - 调用 `init_machine` 回调函数(通常指向 `of_platform_populate()`,注册平台设备)。 --- ### **3. 典型执行流程(以ARM为例)** ```plaintext setup_arch() ├─ setup_processor() // 识别CPU型号和特性 ├─ setup_machine_fdt() // 匹配设备树到machine_desc ├─ early_init_dt_scan_nodes() // 解析设备树中的内存、命令行等 ├─ arm_memblock_init() // 保留内存区域(内核、保留区等) ├─ paging_init() // 初始化页表,启用MMU ├─ unflatten_device_tree() // 展开设备树为内核数据结构 ├─ platform_init() // 调用machine_desc->init_machine() └─ ... // 其他架构相关初始化(如定时器、中断控制器) ``` --- ### **4. 关键数据结构** - **`machine_desc`**: - 描述板级硬件信息,定义在 `arch/arm/include/asm/mach/arch.h`。 - 包含函数指针(如 `init_machine`)和板级属性(如物理内存布局)。 - **`memblock`**: - 早期内存管理器,管理保留内存和可用内存区域。 - **设备树节点**: - 通过 `of_*` 函数族(如 `of_property_read_u32()`)解析硬件信息。 --- ### **5. 与其他模块的交互** - **内存管理子系统**: - `memblock` → `bootmem` → Buddy System。 - **设备驱动**: - 通过 `of_platform_populate()` 注册设备树中的设备。 - **中断子系统**: - 初始化中断控制器(如GIC)和定时器。 --- ### **6. 架构差异性** - **ARM**: - 强依赖设备树,`machine_desc` 匹配设备树的 `compatible`。 - **x86**: - 通过BIOS或UEFI获取内存映射(E820表),初始化ACPI。 - **RISC-V**: - 类似ARM,使用设备树或OpenFirmware。 --- ### **总结** `setup_arch` 是内核启动过程中架构相关初始化的核心枢纽,通过解析硬件信息、配置内存和处理器,为后续驱动加载和子系统运行奠定基础。其实现细节高度依赖目标架构和硬件平台。
评论 1
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值