lds
[TOC] arch/arm/Makefile: 32位ARM架构的构建总指挥arch/arm/Makefile 是 Linux 内核 Kbuild 系统中专门为 32 位 ARM 架构服务的顶级 Makefile。它不是一个独立的可执行脚本,而是被主 Makefile 包含(include)进去的。它的核心职责是定义 ARM 架构独有的构建规则、配置编译选项,并将 Kconfig 中选择的平台配置转化为实际的构建命令。 可以将其视为一个“总指挥官”,它接收来自 .config 文件的战略指令,然后向编译器、链接器等“部队”下达精确的战术命令,以确保最终能为特定的 ARM 平台构建出正确、高效的内核。 一、 核心角色与职责 定制化主构建流程: 内核的主 Makefile 定义了通用的构建目标(如 vmlinux, modules)。arch/arm/Makefile 则对这些目标进行“重载”或“定制”,添加 ARM 架构特有的依赖和命令。 配置翻译官: 将 .config 文件中由 Kconfig 系统生成的高层配置选项(例如 CONFIG_ARCH_BC...
lib
[TOC] arch/arm/include/asm/delay.h该文件的核心原理是提供一个可插拔的、分层的延迟实现机制。它设计了一个抽象的arm_delay_ops操作函数集, 允许在系统启动时根据可用的硬件资源来选择并注册最优的延迟方法。 对于没有精确硬件定时器的旧系统: 它会回退到一种基于”每秒循环数”(loops_per_jiffy)的校准循环方法。内核在启动时会测量在一个系统时钟节拍(jiffy)内, CPU能执行多少次空循环, 从而计算出一个近似值。udelay的实现会根据这个校准值来计算需要执行多少次循环才能达到指定的微秒延迟。 对于拥有高精度硬件定时器的新系统(如STM32H750): 系统启动代码(通常是特定于板卡的平台代码)可以使用register_current_timer_delay函数来注册一个高精度的定时器(例如ARM Cortex-M内核自带的DWT周期计数器CYCCNT)。一旦注册成功, arm_delay_ops中的函数指针就会被更新为指向基于这个硬件定时器的延迟实现。这种实现方式会读取当前定时器计数值...
mm
[TOC] arch/arm/mm: 解剖Linux的NOMMU内存模型arch/arm/mm 目录包含了 ARM 架构的内存管理代码。在典型的带 MMU 的系统中,它的主要职责是处理虚拟内存、页表、TLB 管理等。但是,当内核被配置为在没有 MMU 的处理器(如 ARM Cortex-M 系列)上运行时,这个目录的功能会发生根本性的变化。 在 NOMMU 模式下,arch/arm/mm 的核心任务不再是管理复杂的虚拟地址空间,而是直接管理一个扁平的、统一的物理地址空间。 一、 NOMMU 的核心概念在深入代码之前,必须理解 NOMMU 环境下的几个基本事实: 单一扁平地址空间: 内核、所有用户进程、I/O 内存都共享同一个物理地址空间。不存在虚拟地址到物理地址的转换。一个指针的值就是它在物理内存中的真实地址。 无内存保护: 由于没有 MMU,处理器无法在硬件层面阻止一个进程访问另一个进程或内核的内存。任何一个有缺陷的应用程序都可以直接读写内核内存,导致整个系统崩溃。 受限的进程模型: 传统的 fork() 系统调用(它依赖于写时复制技术,而这又...
process
[TOC] processarch/arm/include/asm/current.h 返回__current的值,__current是一个全局变量,在arch/arm/kernel/process.c中定义 __current是一个指向当前进程的指针,在内核中,每个进程都有一个task_struct结构体,该结构体包含了该进程的所有信息 12345678910111213141516171819202122//arch/arm/kernel/process.casmlinkage struct task_struct *__current;EXPORT_SYMBOL(__current);static __always_inline __attribute_const__ struct task_struct *get_current(void){ struct task_struct *cur;#if __has_builtin(__builtin_thread_pointer) && defined(CON...
kernel
[TOC] arch/arm/kernel/: Linux 32位ARM内核的体系结构特定实现arch/arm/kernel/ 目录是 Linux 内核中专门负责 32 位 ARM 架构体系结构相关代码实现的核心区域。它包含了将通用内核代码与 ARM 处理器及其外围硬件紧密结合的底层逻辑。简单来说,它是 Linux 内核在 ARM 平台上运行的“神经中枢和硬件适配器”。 一、 核心职责arch/arm/kernel/ 目录下的代码负责 Linux 内核在 ARM 架构上运行的所有关键底层功能,包括: 早期 CPU 初始化: 在主内核 C 代码开始执行后,进行更详细的 CPU 模式设置、缓存和 MMU (内存管理单元) 的初始化。 内存管理设置: 建立虚拟内存与物理内存的映射(页表),这是所有后续内存访问的基础。 异常与中断处理: 定义和处理 ARM 处理器产生的各种异常(如数据中止、预取中止、未定义指令、软件中断等)和中断请求。这是内核响应硬件事件和系统调用的核心机制。 系统调用分发: 提供用户空间应用程序通过软件中断(SWI/SVC ...
sys_call_table
Linux内核ARM架构下sys_call_table的自动化生成机制剖析1. 引言在Linux操作系统内核中,系统调用(System Call)构成了用户空间与内核空间交互的基础接口。为了高效地将用户空间传递的系统调用号(System Call Number, SCN)映射至内核中相应的服务例程,内核在内部维护了一个核心数据结构——系统调用表。对于ARM架构,此表定义为sys_call_table,其本质是一个函数指针数组。 维护这样一个包含数百个条目,且需兼容多种应用程序二进制接口(Application Binary Interface, ABI)的数组,是一项复杂且易错的任务。任何手动的编辑都可能引入调用号与函数指针不匹配、ABI兼容性层实现错误或表大小同步失败等严重问题。为规避此类风险,Linux内核采用了一套高度自动化的代码生成机制。本文旨在以严谨的技术视角,对ARM架构下sys_call_table从源定义文件到最终二进制镜像中符号的全过程,进行深入、详尽的剖析。 2. sys_call_table 自动化生成流程sys_call_table的构建并非在C代码层面进...
i2c
[TOC] drivers/i2c I2C总线子系统(I2C Bus Subsystem) 管理I2C总线控制器与设备历史与背景这项技术是为了解决什么特定问题而诞生的?drivers/i2c 目录中的代码实现了Linux内核的I2C(Inter-Integrated Circuit)总线子系统。这项技术的诞生是为了解决在Linux系统中管理和访问大量通过I2C总线连接的外设时面临的代码冗余、缺乏抽象和可移植性差的问题。 I2C是一种简单、低速的两线(SDA -串行数据线, SCL -串行时钟线)串行总线,广泛用于连接微控制器和各种外围芯片(如传感器、EEPROM、RTC、PMIC等)。在没有统一子系统的情况下: 驱动与硬件耦合:每个需要访问I2C设备的驱动程序,都必须包含直接操作特定I2C控制器硬件(即“总线主控器”)的代码。这意味着为一个I2C传感器编写的驱动,在更换了主控芯片(如从NXP的SoC换到Broadcom的SoC)后就无法工作,必须重写。 代码重复:访问I2C总线的基本协议(起始/停止信号、发送地址、读写数据、ACK/NACK)...
base
[TOC] drivers/basedrivers/base 是Linux内核源代码中的一个核心目录,它并非一项独立的技术,而是内核设备模型(Linux Device Model)的基础实现。这个模型是一个统一的、抽象的框架,用于管理系统中的所有设备、驱动程序以及它们之间的关系。理解drivers/base就是理解现代Linux内核如何看待和管理硬件。 历史与背景这项技术是为了解决什么特定问题而诞生的? 在Linux内核2.5版本之前,内核中没有一个统一的结构来表示设备和驱动程序。驱动程序的编写和管理方式较为混乱,存在诸多问题: 电源管理困难:没有统一的设备层级结构,很难以正确的顺序对设备进行挂起(suspend)或恢复(resume)操作。例如,USB主控制器必须在USB设备之前被挂起。 代码冗余:每个子系统(如PCI, USB)都需要自己实现一套管理设备和驱动的机制,导致了大量的重复代码,尤其是在对象生命周期管理(如引用计数)和列表管理方面。 系统信息不透明:缺乏一种简洁、一致的方式从用户空间查看系统中所有设备的拓扑结构和状态。当时的 /proc 文件系统虽...
class
[TOC] 介绍drivers/base/class.c 是Linux内核设备模型中一个至关重要的部分,它实现了类(Class)的概念。与根据物理连接对设备进行分组的总线(Bus)不同,类的作用是根据设备的功能对它们进行逻辑上的分组,并为用户空间提供一个统一、简洁的视图,同时它还是自动化创建设备文件(/dev 节点)的核心机制。 历史与背景这项技术是为了解决什么特定问题而诞生的? 在统一设备模型出现之前,Linux系统管理面临几个难题: 设备发现困难:用户或管理员很难找到所有功能相同的设备。例如,要列出系统中所有的硬盘,需要去检查不同总线(IDE, SCSI, USB)下的设备,没有统一的入口。 静态的 /dev 目录:系统中的设备文件(如 /dev/hda, /dev/ttyS0)通常是通过一个静态的 MAKEDEV 脚本在安装时创建的。这意味着无论硬件是否存在,设备文件都在那里,这造成了 /dev 目录的臃肿和混乱。对于U盘这种即插即用设备,这种方式完全无法工作。 主/次设备号管理:驱动程序需要手动管理和分配主设备号(Major Number),容易产生冲突...
container
容器设备(Container Device) 聚合与管理SoC内嵌设备drivers/base/container.c 是Linux内核设备模型中的一个辅助性组件。它的核心功能是提供一个标准的机制,用于将一组逻辑上相关、但不一定在同一物理总线上的设备,聚合到一个统一的“容器设备”之下。这种机制最主要的应用场景是为复杂的片上系统(SoC)创建一个顶层设备节点,从而将构成该SoC的所有独立功能块(如I2C控制器、DMA引擎等)组织成一个清晰的层次结构。 历史与背景这项技术是为了解决什么特定问题而诞生的? 随着嵌入式系统的发展,现代SoC集成了越来越多的功能单元。在Linux设备模型中,这些单元通常被表示为独立的平台设备(platform_device)。这导致了一个问题: 缺乏层次结构:在sysfs的设备树(/sys/devices)中,一个SoC上的所有平台设备可能都以扁平的方式挂载在 platform 总线下,无法直观地体现出它们都属于同一个物理芯片。 管理困难:当需要对整个SoC进行统一操作时(例如,作为一个整体进行电源管理或状态查询),缺乏一个代表SoC本身的顶层设备...








