ARM Linux内核初始化是系统从上电到能够运行用户空间程序的关键过程,涉及硬件启动、内核组件初始化、设备驱动加载等多个阶段,其设计旨在确保内核以稳定、高效的状态接管硬件资源,为上层应用提供运行基础,整个过程可划分为体系结构相关初始化、内核核心初始化、设备驱动初始化及用户空间启动准备四个主要阶段,各阶段逻辑紧密衔接,共同完成内核的“自我构建”。

启动入口与体系结构相关初始化
内核初始化的起点始于硬件上电后Bootloader(如U-Boot)的引导,Bootloader负责将内核映像加载到内存指定区域,并通过参数块(传统ATAGS或现代设备树DTB)向内核传递硬件信息,如内存布局、启动模式、命令行参数等,对于ARM架构,内核入口位于arch/arm/kernel/head.S,该文件中的汇编代码首先完成CPU基本设置:关闭中断、禁用MMU(内存管理单元)和缓存,确保内核在干净的硬件环境下运行;随后初始化页表,建立临时映射,使内核能够访问必要的数据结构;最后通过机器描述符(machine_desc)定位硬件平台信息,为后续体系结构相关初始化提供支持。
体系结构初始化的核心函数是start_kernel之前的setup_arch(),该函数解析设备树(若使用)或ATAGS,获取物理内存起始地址和大小,初始化memblock内存分配器(替代早期的bootmem),并完成早期控制台(如串口)的初始化——控制台的启动对内核调试至关重要,允许开发者实时观察初始化日志。
内核核心初始化
进入start_kernel()(位于init/main.c)后,内核正式进入C语言层面的核心初始化阶段,这是内核“骨架”搭建的关键环节,该函数按固定顺序调用一系列初始化函数,涵盖内存管理、进程调度、中断处理、同步机制等核心子系统。
内存管理子系统:mm_init()完成页高速缓存(page cache)、slab分配器等核心内存管理结构的初始化,为后续内核内存分配奠定基础;随后是进程调度器,sched_init()初始化运行队列(runqueue)和调度类(如CFS完全公平调度器),确保CPU资源能够被合理分配给进程。
中断和同步机制紧随其后:trap_init()设置ARM异常向量表,初始化系统中断控制器(如GIC)的驱动,使内核能够响应硬件中断;rcu_init()初始化RCU(Read-Copy-Update)同步机制,这是现代内核中实现高效读锁定的核心组件,timekeeping_init()负责初始化系统时间,console_init()完成控制台的最终初始化,printk()函数此时可正常输出日志信息。

核心初始化还包括文件系统、网络等子系统的早期准备,例如vfs_caches_init()初始化虚拟文件系统的inode和dentry缓存,net_ns_init()初始化网络命名空间,为后续网络协议栈加载做准备。
设备驱动初始化
当内核核心子系统就绪后,初始化重点转向设备驱动模型,目标是发现、初始化并注册所有硬件设备,这一阶段的核心是驱动模型框架的搭建:driver_init()初始化设备模型的核心结构(如kobject、kset),为设备和驱动的动态管理提供基础;随后,platform总线初始化(platform_bus_init)完成,这是ARM架构中最常用的设备抽象方式,用于挂载platform设备(如串口、GPIO控制器等)。
设备驱动加载分为“设备发现”和“驱动绑定”两步:设备发现依赖设备树(Device Tree),内核通过of_platform_populate()遍历设备树中的设备节点,为每个节点创建platform_device;驱动绑定则通过driver_match_device()实现,当驱动注册时(platform_driver_register),系统会自动寻找与之匹配的设备(通过设备树中的compatible属性),并调用驱动的probe函数完成设备初始化。
特定总线的驱动(如I2C、SPI、USB)也会在这一阶段初始化,例如i2c_init()初始化I2C核心控制器,USB子系统通过usb_init()加载主机控制器驱动(如EHCI、OHCI),最终使外设能够被内核识别和管理。
用户空间启动准备
当所有核心设备和驱动初始化完成后,内核准备将控制权移交给用户空间,最后一步是启动第一个用户空间进程——init进程,内核通过execute_process()执行用户空间的init程序(传统上是/sbin/init,现代系统中可能是systemd、init或其他兼容实现),该进程负责进一步初始化系统服务、挂载文件系统、启动守护进程等。

在启动init进程前,内核会完成最后的清理工作:开启中断(enable_irq()),激活RCU(rcu_scheduler_starting()),并将CPU切换到用户模式(通过ret_to_user()),至此,内核初始化全部结束,系统进入正常运行状态,用户空间程序开始接管系统资源。
FAQs
Q1:ARM Linux内核初始化与x86架构的主要区别是什么?
A1:两者在启动流程和体系结构相关初始化上存在显著差异,ARM架构依赖Bootloader传递设备树(DTB)或ATAGS描述硬件,而x86通过BIOS/EFI提供ACPI表;ARM的入口代码(head.S)需处理ARMv7/v8等不同架构的页表和异常向量,x86则从实模式进入保护模式,通过head_32.S/head_64.S初始化;ARM的中断控制器(如GIC)与x86的APIC/IO-APIC驱动完全不同,设备树机制也是ARM的特色,x86多使用ACPI描述设备。
Q2:设备树在ARM Linux内核初始化中扮演什么角色?
A2:设备树(Device Tree)是描述硬件资源(如内存地址、中断号、外设寄存器映射)的数据结构,替代了传统的硬编码和ATAGS,内核通过解析设备树中的节点和属性,自动发现并初始化设备(如串口、网卡),无需为每个硬件平台修改内核代码,它实现了内核与硬件的解耦,使同一内核可适配不同ARM开发板,极大提升了内核的可移植性。
【版权声明】:本站所有内容均来自网络,若无意侵犯到您的权利,请及时与我们联系将尽快删除相关内容!
发表回复