内核的核心代码包括第3章中描述的各个子系统和子模块,以及其他非核心代码如电源管理、Linux初始化和库文件(因为Linux内核是一个自内核)。例如- 包含的内核(即内核不依赖于其他软件,可以自行编译)、固件集合、KVM(虚拟机技术)以及其他如编译脚本、配置文件、帮助文档、版权声明、等。使用辅助文件ls命令查看内核源代码。下面详细介绍顶级目录结构。
我。 ninclude/—- 内核文件。必须提供给外部模块(例如用户空间代码)。 kernel/—- Linux 内核的核心代码。它包括3.2节中描述的进程调度子系统以及与进程调度相关的模块。 mm/—- 内存管理子系统(第3.3节)。 fs/—- VFS 子系统(第3.4 节)。 net/—- 不包含网络设备驱动程序的网络子系统(第3.5 节)。 ipc/—- IPC(进程间通信)子系统。 Arch//—-架构相关代码如arm、x86等Arch//mach—–具体机器/板相关代码。 arch//include/asm—-架构相关文件。 arch//boot/dts—-设备树文件。 init/—- Linux系统引导初始化相关的代码。 block/—- 提供块设备的层次结构。 sound/—- 音频相关的驱动程序和子系统可以被认为是“音频子系统”。 drivers/—- 设备驱动程序(在Linux内核3.10中,设备驱动程序占代码的49.4%)。 lib/—- 实现内核需要使用的库函数,如CRC、FIFO、lists、MD5等。 crypto/—– 盘点加密、解密相关的函数。 security/—- 提供安全功能(SELinux)。 virt/—- 提供对虚拟机技术(如KVM)的支持。 usr/—- 用于生成initramfs 的代码。 Firmware/—- 存储用于为第三方设备供电的固件。 Sample/—- 示例代码。 tools/—- 一些常用的性能分析、自动化测试等工具。 Kconfig、Kbuild、Makefile、scripts/—- 用于编译内核的配置文件、脚本等。复制—-版权声明。维护者—- 维护者列表。致谢—- Linux 主要贡献者列表。 REPORTING-BUGS —- 报告错误的指南。文档、自述文件—- 帮助、文档
简介
图1 Linux 系统层次结构
顶部是用户(或应用程序)空间。这是用户应用程序运行的地方。用户空间下面是内核空间,Linux 内核驻留在其中。 GNU C 库(glibc) 也位于此处。它为内核提供了系统调用接口以及在用户空间应用程序和内核之间进行转换的机制。这很重要,因为内核应用程序和用户空间应用程序使用不同的受保护地址空间。每个用户空间进程都使用自己的虚拟地址空间,而内核则占用单独的地址空间。
Linux内核可以进一步分为三层。最上面是系统调用接口,实现了读写等一些基本功能。系统调用接口下面是内核代码,可以更准确地定义为与体系结构无关的内核代码。这些代码对于Linux 支持的所有处理器架构都是通用的。该代码下面是依赖于体系结构的代码,它们构成了所谓的BSP(板支持包)。这些代码充当特定架构的处理器和平台特定代码。
Linux 内核实现了许多重要的架构特征。在更高或更低的级别上,内核分为子系统。 Linux 也可以被视为一个整体,因为它将所有这些基本服务集成到了内核中。这与微内核架构不同,微内核架构提供一些基础服务,如通信、I/O、内存、进程管理等,而更具体的服务则插入微内核层。每个核心都有自己的优点,我们在这里不讨论。
Linux 内核的内存和CPU 效率很高,并且随着时间的推移非常稳定。但Linux 最有趣的一点是,尽管它规模庞大且复杂,但它是可移植的。 Linux 被编译为在具有不同架构约束和要求的许多处理器和平台上运行。例如,Linux 可以在带有或不带有内存管理单元(MMU) 的处理器上运行。
Linux 内核的uClinux 端口提供非MMU 支持。
图2 Linux 内核架构
Linux内核的主要组成部分是系统调用接口、进程管理、内存管理、虚拟文件系统、网络堆栈、设备驱动程序和硬件架构相关代码。
Linux内核预备工作
SCI 层提供了一种用于执行从用户空间到内核的函数调用的特定机制。如前所述,该接口依赖于体系结构,即使在同一处理器系列中也是如此。 SCI实际上是一个非常有用的函数调用复用和解复用服务。 SCI 实现位于./linux/kernel 中,与体系结构相关的部分位于./linux/arch 中。
Linux内核的任务:
流程管理的重点是流程的执行。在内核中,这些进程称为线程,代表各个处理器虚拟化(线程代码、数据、堆栈和CPU 寄存器)。尽管术语“进程”经常在用户空间中使用,但Linux 实现并不区分进程和线程这两个概念。内核通过SCI 提供应用程序编程接口(API)来创建新进程(fork、run 或可移植操作系统接口(POSIX)函数)、停止进程(kill、terminate)以及进程之间的通信和同步(信号)。 )。或POSIX 机制)。
进程管理还包括处理活动进程之间共享CPU 的需要。内核实现了一种新的调度算法,无论竞争CPU 的线程数量如何,该算法都会以恒定的时间运行。这一算法称为O(1) 调度程序,其名称意味着调度多个线程所需的时间与调度一个线程所需的时间相同。 O(1) 调度程序还可以支持多个处理器(称为对称多处理器或SMP)。进程管理源代码位于./linux/kernel,架构相关源代码位于./linux/arch。
内核实现策略:
内核管理的另一个重要资源是内存。为了提高效率,当虚拟内存由硬件管理时,内存以所谓的内存页(大多数架构上为4KB)进行管理。 Linux 包括用于物理和虚拟映射的硬件机制,以及管理可用内存的方法。然而,内存管理不仅仅涉及管理4KB 缓冲区。 Linux 提供4KB 缓冲区抽象,例如板分配器。这种内存管理模式使用4KB 缓冲区作为基础,并从中分配结构,跟踪内存,例如哪些内存页已满、哪些页未完全使用以及哪些页为空。这允许该模式根据系统需求动态调整内存使用情况。可能会消耗可用内存来支持多个用户的内存使用。这可能会导致页面从内存移动到磁盘。这个过程称为交换,因为页面从内存交换到硬盘。内存管理源代码位于./linux/mm。
哪些地方用到了内核机制?
虚拟文件系统(VFS) 是Linux 内核的一个非常有用的功能,因为它为文件系统提供了通用接口抽象。 VFS 在SCI 和内核支持的文件系统之间提供交换层(参见图4)。
图3 Linux 文件系统层次结构
在VFS中,这是一个常见的API抽象,用于打开、关闭、读取和写入等功能。 VFS下面是一个文件系统抽象,定义了上层的功能是如何实现的。这些是针对特定文件系统(超过50 个)的插件。文件系统源代码位于./linux/fs。文件系统层下面是缓冲区高速缓存,它为文件系统层提供一组通用的功能(独立于任何特定的文件系统)。该缓存层通过将数据保留一段固定的时间(或立即预取数据以便在需要时立即可用)来优化对物理设备的访问。缓冲区高速缓存下面是实现特定物理设备接口的设备驱动程序。
Linux进程
网络堆栈的设计遵循仿真协议本身的分层架构。回想一下,互联网协议(IP) 是传输协议(通常称为传输控制协议或TCP)底层的核心网络层协议。 TCP 之上是通过SCI 调用的套接字层。套接字层是网络子系统的标准API,为各种网络协议提供用户界面。从原始帧访问到IP 协议数据单元(PDU),再到TCP 和用户数据报协议(UDP),套接字层管理连接并提供在端点之间移动数据的标准化方法。内核网络的源代码位于./linux/net。
Linux内核源代码的目录结构
Linux 内核中的大量代码包含在可以运行特定硬件设备的设备驱动程序中。 Linux 源代码树有一个驱动程序子目录,该子目录进一步分为各种支持的设备,例如蓝牙、I2C 和串行。设备驱动程序代码位于./linux/drivers。
Linux内核体系结构简析简析
Linux 在很大程度上独立于其运行的体系结构,但需要考虑一些体系结构因素才能使其正常工作和高效。/linux/arch 子目录定义了内核源代码的体系结构相关部分。这包括各种特定于体系结构的子目录(组成BSP)。典型的桌面系统使用x86 目录。每个体系结构子目录都包含许多其他子目录,每个子目录都专注于内核的特定方面,例如引导、内核、内存管理等。依赖于这些架构的代码位于./linux/arch。
如果Linux 内核的可移植性和效率不够高,Linux 还提供了不属于上述类别的其他功能。作为生产操作系统和开源软件,Linux 是测试新协议及其扩展的优秀平台。 Linux 支持许多网络协议,包括传统的TCP/IP 和高速网络的扩展(1 千兆位以太网[GbE] 和10 GbE 及以上)。 Linux 还支持流控制传输协议(SCTP) 等协议,它是传输层协议的后继者,提供了许多比TCP 更高级的功能。
Linux也是一个动态内核,支持动态添加或删除软件组件。它们被称为动态可加载内核模块,可以在启动时或用户随时按需插入(根据特定设备当前的需要)。
Linux 的最新增强功能之一是它能够充当其他操作系统的操作系统(称为虚拟机管理程序)。最近,内核发生了变化,称为基于内核的虚拟机(KVM)。此更改启用了用户空间的新接口,并允许其他操作系统在支持KVM 的内核之上运行。除了运行Linux 的其他实例之外,您还可以虚拟化Microsoft Windows。唯一的限制是底层处理器必须支持新的虚拟化指令。
(1)系统调用接口
1.当你被问及Linux架构(即Linux系统是如何配置的)时,你可以参考下图来回答。 从广义上讲,Linux架构可以分为两部分。
(1)用户空间:用户空间还包括用户应用程序和C库。
(2)内核空间:内核空间包含与系统调用、内核和平台架构相关的代码。
2、Linux架构分为用户空间和内核空间,因为:
1) 现代CPU通常实现不同的操作模式。
以ARM为例。 ARM 实现了七种操作模式,每种模式都决定了CPU 可以执行哪些指令以及可以访问哪些寄存器。
(1) 用户模式usr (2) 系统模式sys (3) 管理模式svc (4) 快速中断fiq (5) 外部中断irq (6) 数据访问结束abt (7) 未定义指令异常(2) X86 示例: 实现四种不同的权限级别:X86 Ring0 到Ring3。 Ring0可以执行特权指令并访问IO设备。 Ring3有很多限制。
2)因此,从CPU的角度来看,Linux将系统分为两部分,以保护内核的安全。
3.用户空间和内核空间是程序执行的两种不同状态,从用户空间到内核空间的转移可以通过“系统调用”和“硬件中断”来完成。
四。 Linux内核结构(注意LInux架构和Linux内核结构的区别)
(2)进程管理
相比传统的device_driver机制,Linux中的这种平台驱动机制的优点是平台机制向内核注册自己的资源,这些资源在驱动使用时由内核管理,有非常明显的优势。通过platform_device 提供。应用和使用标准接口。这提高了驱动程序和资源管理的独立性,提高了可移植性和安全性。下面是SPI 驱动程序层次结构的示意图。 Linux SPI总线可以理解为从SPI控制器派生出来的总线。
iz=58558&from=article.pc_detail&lk3s=953192f4&x-expires=1717879210&x-signature=98rieDZDQkNSZhp2be97vT1Ug2I%3D” />
和传统的驱动一样,platform机制也分为三个步骤:
1、总线注册阶段:
内核启动初始化时的main.c文件中的kernel_init()→do_basic_setup()→driver_init()→platform_bus_init()→bus_register(&platform_bus_type),注册了一条platform总线(虚拟总线,platform_bus)。
2、添加设备阶段:
设备注册的时候Platform_device_register()→platform_device_add()→(pdev→dev.bus = &platform_bus_type)→device_add(),就这样把设备给挂到虚拟的总线上。
3、驱动注册阶段:
Platform_driver_register()→driver_register()→bus_add_driver()→driver_attach()→bus_for_each_dev(), 对在每个挂在虚拟的platform bus的设备作__driver_attach()→driver_probe_device(),判断drv→bus→match()是否执行成功,此时通过指针执行platform_match→strncmp(pdev→name , drv→name , BUS_ID_SIZE),如果相符就调用really_probe(实际就是执行相应设备的platform_driver→probe(platform_device)。)开始真正的探测,如果probe成功,则绑定设备到该驱动。
从上面可以看出,platform机制最后还是调用了bus_register() , device_add() , driver_register()这三个关键的函数。
下面看几个结构体:
struct platform_device (/include/linux/Platform_device.h){ const char * name; int id; struct device dev; u32 num_resources; struct resource * resource;};Platform_device结构体描述了一个platform结构的设备,在其中包含了一般设备的结构体struct device dev;设备的资源结构体struct resource * resource;还有设备的名字const char * name。(注意,这个名字一定要和后面platform_driver.driver àname相同,原因会在后面说明。)
该结构体中最重要的就是resource结构,这也是之所以引入platform机制的原因。
struct resource ( /include/linux/ioport.h){ resource_size_t start; resource_size_t end; const char *name; unsigned long flags; struct resource *parent, *sibling, *child;};其中 flags位表示该资源的类型,start和end分别表示该资源的起始地址和结束地址(/include/linux/Platform_device.h):
struct platform_driver { int (*probe)(struct platform_device *); int (*remove)(struct platform_device *); void (*shutdown)(struct platform_device *); int (*suspend)(struct platform_device *, pm_message_t state); int (*suspend_late)(struct platform_device *, pm_message_t state); int (*resume_early)(struct platform_device *); int (*resume)(struct platform_device *); struct device_driver driver;};Platform_driver结构体描述了一个platform结构的驱动。其中除了一些函数指针外,还有一个一般驱动的device_driver结构。 名字要一致的原因:
上面说的驱动在注册的时候会调用函数bus_for_each_dev(), 对在每个挂在虚拟的platform bus的设备作__driver_attach()→driver_probe_device(),在此函数中会对dev和drv做初步的匹配,调用的是drv->bus->match所指向的函数。platform_driver_register函数中drv->driver.bus = &platform_bus_type,所以drv->bus->match就为platform_bus_type→match,为platform_match函数,该函数如下:
static int platform_match(struct device * dev, struct device_driver * drv) { struct platform_device *pdev = container_of(dev, struct platform_device, dev);return (strncmp(pdev->name, drv->name, BUS_ID_SIZE) == 0);}是比较dev和drv的name,相同则会进入really_probe()函数,从而进入自己写的probe函数做进一步的匹配。所以dev→name和driver→drv→name在初始化时一定要填一样的。
不同类型的驱动,其match函数是不一样的,这个platform的驱动,比较的是dev和drv的名字,还记得usb类驱动里的match吗?它比较的是Product ID和Vendor ID。
个人总结Platform机制的好处:
1、提供platform_bus_type类型的总线,把那些不是总线型的soc设备都添加到这条虚拟总线上。使得,总线——设备——驱动的模式可以得到普及。
2、提供platform_device和platform_driver类型的数据结构,将传统的device和driver数据结构嵌入其中,并且加入resource成员,以便于和Open Firmware这种动态传递设备资源的新型bootloader和kernel 接轨。
Linux内核体系结构
因为Linux内核是单片的,所以它比其他类型的内核占用空间最大,复杂度也最高。这是一个设计特性,在Linux早期引起了相当多的争论,并且仍然带有一些与单内核固有的相同的设计缺陷。
为了解决这些缺陷,Linux内核开发人员所做的一件事就是使内核模块可以在运行时加载和卸载,这意味着您可以动态地添加或删除内核的特性。这不仅可以向内核添加硬件功能,还可以包括运行服务器进程的模块,比如低级别虚拟化,但也可以替换整个内核,而不需要在某些情况下重启计算机。 想象一下,如果您可以升级到Windows服务包,而不需要重新启动……
内核模块
如果Windows已经安装了所有可用的驱动程序,而您只需要打开所需的驱动程序怎么办?这本质上就是内核模块为Linux所做的。内核模块,也称为可加载内核模块(LKM),对于保持内核在不消耗所有可用内存的情况下与所有硬件一起工作是必不可少的。
模块通常向基本内核添加设备、文件系统和系统调用等功能。lkm的文件扩展名是.ko,通常存储在/lib/modules目录中。由于模块的特性,您可以通过在启动时使用menuconfig命令将模块设置为load或not load,或者通过编辑/boot/config文件,或者使用modprobe命令动态地加载和卸载模块,轻松定制内核。
第三方和封闭源码模块在一些发行版中是可用的,比如Ubuntu,默认情况下可能无法安装,因为这些模块的源代码是不可用的。该软件的开发人员(即nVidia、ATI等)不提供源代码,而是构建自己的模块并编译所需的.ko文件以便分发。虽然这些模块像beer一样是免费的,但它们不像speech那样是免费的,因此不包括在一些发行版中,因为维护人员认为它通过提供非免费软件“污染”了内核。
内核并不神奇,但对于任何正常运行的计算机来说,它都是必不可少的。Linux内核不同于OS X和Windows,因为它包含内核级别的驱动程序,并使许多东西“开箱即用”。希望您能对软件和硬件如何协同工作以及启动计算机所需的文件有更多的了解。
原创文章,作者:小条,如若转载,请注明出处:https://www.sudun.com/ask/86771.html