搜档网
当前位置:搜档网 › Linux内核架构和工作原理详解

Linux内核架构和工作原理详解

Linux内核架构和工作原理详解
Linux内核架构和工作原理详解

Linux内核架构和工作原理详解

作用是将应用层序的请求传递给硬件,并充当底层驱动程序,对系统中的各种设备和组件进行寻址。目前支持模块的动态装卸(裁剪)。Linux内核就是基于这个策略实现的。Linux 进程采用层次结构,每个进程都依赖于一个父进程。内核启动init程序作为第一个进程。该进程负责进一步的系统初始化操作。init进程是进程树的根,所有的进程都直接或者间接起源于该进程。virt/ ---- 提供虚拟机技术的支持。

Linux内核预备工作

理解Linux内核最好预备的知识点:

懂C语言

懂一点操作系统的知识

熟悉少量相关算法

懂计算机体系结构

Linux内核的特点:

结合了unix操作系统的一些基础概念

Linux内核的任务:

1.从技术层面讲,内核是硬件与软件之间的一个中间层。作用是将应用层序的请求传递给硬件,并充当底层驱动程序,对系统中的各种设备和组件进行寻址。

2.从应用程序的层面讲,应用程序与硬件没有联系,只与内核有联系,内核是应用程序知道的层次中的最底层。在实际工作中内核抽象了相关细节。

3.内核是一个资源管理程序。负责将可用的共享资源(CPU时间、磁盘空间、网络连接等)分配得到各个系统进程。

4.内核就像一个库,提供了一组面向系统的命令。系统调用对于应用程序来说,就像调用普通函数一样。

内核实现策略:

1.微内核。最基本的功能由中央内核(微内核)实现。所有其他的功能都委托给一些独立进程,这些进程通过明确定义的通信接口与中心内核通信。

2.宏内核。内核的所有代码,包括子系统(如内存管理、文件管理、设备驱动程序)都打包到一个文件中。内核中的每一个函数都可以访问到内核中所有其他部分。目前支持模块的动态装卸(裁剪)。Linux内核就是基于这个策略实现的。

哪些地方用到了内核机制?

1.进程(在cpu的虚拟内存中分配地址空间,各个进程的地址空间完全独立;同时执行的进程数最多不超过cpu数目)之间进行通信,需要使用特定的内核机制。

2.进程间切换(同时执行的进程数最多不超过cpu数目),也需要用到内核机制。进程切换也需要像FreeRTOS任务切换一样保存状态,并将进程置于闲置状态/恢复状态。

3.进程的调度。确认哪个进程运行多长的时间。

Linux进程

1.采用层次结构,每个进程都依赖于一个父进程。内核启动init程序作为第一个进程。该进程负责进一步的系统初始化操作。init进程是进程树的根,所有的进程都直接或者间接起源于该进程。

2.通过pstree命令查询。实际上得系统第一个进程是systemd,而不是init(这也是疑问点)

3.系统中每一个进程都有一个唯一标识符(ID),用户(或其他进程)可以使用ID来访问进程。

Linux内核源代码的目录结构

Linux内核源代码包括三个主要部分:

1.内核核心代码,包括第3章所描述的各个子系统和子模块,以及其它的支撑子系统,例如电源管理、Linux初始化等。

2.其它非核心代码,例如库文件(因为Linux内核是一个自包含的内核,即内核不依赖其它的任何软件,自己就可以编译通过)、固件集合、KVM(虚拟机技术)等。

3.编译脚本、配置文件、帮助文档、版权说明等辅助性文件。

使用ls命令看到的内核源代码的顶层目录结构,具体描述如下。

include/---- 内核头文件,需要提供给外部模块(例如用户空间代码)使用。

kernel/---- Linux内核的核心代码,包含了3.2小节所描述的进程调度子系统,以及和进程调度相关的模块。

mm/ ---- 内存管理子系统(3.3小节)。

fs/ ---- VFS子系统(3.4小节)。

net/ ---- 不包括网络设备驱动的网络子系统(3.5小节)。

ipc/ ---- IPC(进程间通信)子系统。

arch// ---- 体系结构相关的代码,例如arm, x86等等。

arch//mach- ---- 具体的machine/board相关的代码。

arch//include/asm ---- 体系结构相关的头文件。

arch//boot/dts ---- 设备树(Device Tree)文件。

init/---- Linux系统启动初始化相关的代码。

block/---- 提供块设备的层次。

sound/---- 音频相关的驱动及子系统,可以看作“音频子系统”。

drivers/---- 设备驱动(在Linux kernel 3.10中,设备驱动占了49.4的代码量)。

lib/---- 实现需要在内核中使用的库函数,例如CRC、FIFO、list、MD5等。

crypto/ ----- 加密、解密相关的库函数。

security/ ---- 提供安全特性(SELinux)。

virt/ ---- 提供虚拟机技术(KVM等)的支持。

usr/ ---- 用于生成initramfs的代码。

firmware/ ---- 保存用于驱动第三方设备的固件。

samples/ ---- 一些示例代码。

tools/ ---- 一些常用工具,如性能剖析、自测试等。

Kconfig, Kbuild, Makefile, scripts/ ---- 用于内核编译的配置文件、脚本等。

COPYING ---- 版权声明。

MAINTAINERS ----维护者名单。

CREDITS ---- Linux主要的贡献者名单。

REPORTING-BUGS ---- Bug上报的指南。

Documentation, README ---- 帮助、说明文档。

Linux内核体系结构简析简析

图1 Linux系统层次结构

最上面是用户(或应用程序)空间。这是用户应用程序执行的地方。用户空间之下是内核空间,Linux 内核正是位于这里。GNU C Library (glibc)也在这里。它提供了连接内核的系统调用接口,还提供了在用户空间应用程序和内核之间进行转换的机制。这点非常重要,因为内核和用户空间的应用程序使用的是不同的保护地址空间。每个用户空间的进程都使用自己的虚拟地址空间,而内核则占用单独的地址空间。

Linux内核可以进一步划分成3层。最上面是系统调用接口,它实现了一些基本的功能,例如read 和write。系统调用接口之下是内核代码,可以更精确地定义为独立于体系结构的内核代码。这些代码是Linux所支持的所有处理器体系结构所通用的。在这些代码之下是依赖于体系结构的代码,构成了通常称为BSP(Board Support Package)的部分。这些代码用作给定体系结构的处理器和特定于平台的代码。

Linux内核实现了很多重要的体系结构属性。在或高或低的层次上,内核被划分为多个子系统。Linux也可以看作是一个整体,因为它会将所有这些基本服务都集成到内核中。这与微内核的体系结构不同,后者会提供一些基本的服务,例如通信、I/O、内存和进程管理,更具体的服务都是插入到微内核层中的。每种内核都有自己的优点,不过这里并不对此进行讨论。

随着时间的流逝,Linux内核在内存和CPU使用方面具有较高的效率,并且非常稳定。但是对于Linux来说,最为有趣的是在这种大小和复杂性的前提下,依然具有良好的可移植性。Linux 编译后可在大量处理器和具有不同体系结构约束和需求的平台上运行。一个例子是Linux可以在一个具有内存管理单元(MMU)的处理器上运行,也可以在那些不提供MMU 的处理器上运行。

Linux 内核的uClinux 移植提供了对非MMU 的支持。

图2 Linux内核体系结构

Linux内核的主要组件有:系统调用接口、进程管理、内存管理、虚拟文件系统、网络堆栈、设备驱动程序、硬件架构的相关代码。

(1)系统调用接口

SCI 层提供了某些机制执行从用户空间到内核的函数调用。正如前面讨论的一样,这个接口依赖于体系结构,甚至在相同的处理器家族内也是如此。SCI 实际上是一个非常有用的函数调用多路复用和多路分解服务。在./linux/kernel中您可以找到SCI的实现,并

在./linux/arch中找到依赖于体系结构的部分。

(2)进程管理

进程管理的重点是进程的执行。在内核中,这些进程称为线程,代表了单独的处理器虚拟化(线程代码、数据、堆栈和CPU 寄存器)。在用户空间,通常使用进程这个术语,不过Linux实现并没有区分这两个概念(进程和线程)。内核通过SCI提供了一个应用程序编程接口(API)来创建一个新进程(fork、exec 或Portable Operating System Interface [POSIX] 函数),停止进程(kill、exit),并在它们之间进行通信和同步(signal 或者POSIX 机制)。进程管理还包括处理活动进程之间共享CPU 的需求。内核实现了一种新型的调度算法,不管有多少个线程在竞争CPU,这种算法都可以在固定时间内进行操作。这种算法就称为O(1) 调度程序,这个名字就表示它调度多个线程所使用的时间和调度一个线程所使用的时间是相同的。O(1) 调度程序也可以支持多处理器(称为对称多处理器或SMP)。您可以

在./linux/kernel中找到进程管理的源代码,在./linux/arch中可以找到依赖于体系结构的源代码。

(3)内存管理

内核所管理的另外一个重要资源是内存。为了提高效率,如果由硬件管理虚拟内存,内存是按照所谓的内存页方式进行管理的(对于大部分体系结构来说都是4KB)。Linux包括了管理可用内存的方式,以及物理和虚拟映射所使用的硬件机制。不过内存管理要管理的可不止4KB缓冲区。Linux提供了对4KB缓冲区的抽象,例如slab 分配器。这种内存管理模式使用4KB缓冲区为基数,然后从中分配结构,并跟踪内存页使用情况,比如哪些内存页

是满的,哪些页面没有完全使用,哪些页面为空。这样就允许该模式根据系统需要来动态调整内存使用。为了支持多个用户使用内存,有时会出现可用内存被消耗光的情况。由于这个原因,页面可以移出内存并放入磁盘中。这个过程称为交换,因为页面会被从内存交换到硬盘上。内存管理的源代码可以在 ./linux/mm 中找到。

(4)虚拟文件系统

虚拟文件系统(VFS)是Linux 内核中非常有用的一个方面,因为它为文件系统提供了一个通用的接口抽象。VFS在SCI和内核所支持的文件系统之间提供了一个交换层(请参看图4)。

图3 Linux文件系统层次结构

在VFS上面,是对诸如open、close、read和write之类的函数的一个通用API抽象。在VFS下面是文件系统抽象,它定义了上层函数的实现方式。它们是给定文件系统(超过50 个)的插件。文件系统的源代码可以在./linux/fs中找到。文件系统层之下是缓冲区缓存,它为文件系统层提供了一个通用函数集(与具体文件系统无关)。这个缓存层通过将数据保留一段时间(或者随即预先读取数据以便在需要是就可用)优化了对物理设备的访问。缓冲区缓存之下是设备驱动程序,它实现了特定物理设备的接口。

(5)网络堆栈

网络堆栈在设计上遵循模拟协议本身的分层体系结构。回想一下,Internet Protocol (IP)是传输协议(通常称为传输控制协议或TCP)下面的核心网络层协议。TCP上面是socket 层,它是通过SCI进行调用的。socket层是网络子系统的标准API,它为各种网络协议提供了一个用户接口。从原始帧访问到IP 协议数据单元(PDU),再到TCP 和User Datagram Protocol (UDP),socket 层提供了一种标准化的方法来管理连接,并在各个终点之间移动数据。内核中网络源代码可以在 ./linux/net 中找到。

(6)设备驱动程序

Linux 内核中有大量代码都在设备驱动程序中,它们能够运转特定的硬件设备。Linux 源码树提供了一个驱动程序子目录,这个目录又进一步划分为各种支持设备,例如Bluetooth、

I2C、serial 等。设备驱动程序的代码可以在./linux/drivers中找到。

(7)依赖体系结构的代码

尽管Linux很大程度上独立于所运行的体系结构,但是有些元素则必须考虑体系结构才能正常操作并实现更高效率。./linux/arch子目录定义了内核源代码中依赖于体系结构的部分,其中包含了各种特定于体系结构的子目录(共同组成了BSP)。对于一个典型的桌面系统来说,使用的是x86目录。每个体系结构子目录都包含了很多其他子目录,每个子目录都关注内核中的一个特定方面,例如引导、内核、内存管理等。这些依赖体系结构的代码可以在 ./linux/arch 中找到。

如果Linux内核的可移植性和效率还不够好,Linux还提供了其他一些特性,它们无法划分到上面的分类中。作为一个生产操作系统和开源软件,Linux是测试新协议及其增强的良好平台。Linux支持大量网络协议,包括典型的TCP/IP,以及高速网络的扩展(大于1 Gigabit Ethernet [GbE] 和10 GbE)。Linux也可以支持诸如流控制传输协议(SCTP)之类的协议,它提供了很多比TCP更高级的特性(是传输层协议的接替者)。

Linux还是一个动态内核,支持动态添加或删除软件组件。被称为动态可加载内核模块,它们可以在引导时根据需要(当前特定设备需要这个模块)或在任何时候由用户插入。

Linux最新的一个增强是可以用作其他操作系统的操作系统(称为系统管理程序)。最近,对内核进行了修改,称为基于内核的虚拟机(KVM)。这个修改为用户空间启用了一个新的接口,它可以允许其他操作系统在启用了KVM的内核之上运行。除了运行Linux的其他实例之外,Microsoft Windows也可以进行虚拟化。惟一的限制是底层处理器必须支持新的虚拟化指令。

Linux体系结构和内核结构区别

1.当被问到Linux体系结构(就是Linux系统是怎么构成的)时,我们可以参照下图这么回答:从大的方面讲,Linux体系结构可以分为两块:

(1)用户空间:用户空间中又包含了用户的应用程序,C库

(2)内核空间:内核空间包括系统调用,内核,以及与平台架构相关的代码

2.Linux体系结构要分成用户空间和内核空间的原因:

1)现代CPU通常都实现了不同的工作模式,

以ARM为例:ARM实现了7种工作模式,不同模式下CPU可以执行的指令或者访问的寄存器不同:

(1)用户模式usr

(2)系统模式sys

(3)管理模式svc

(4)快速中断fiq

(5)外部中断irq

(6)数据访问终止abt

(7)未定义指令异常

以(2)X86为例:X86实现了4个不同级别的权限,Ring0—Ring3 ;Ring0下可以执行特权指令,可以访问IO设备;Ring3则有很多的限制

2)所以,Linux从CPU的角度出发,为了保护内核的安全,把系统分成了2部分;

3.用户空间和内核空间是程序执行的两种不同状态,我们可以通过“系统调用”和“硬件中断“来完成用户空间到内核空间的转移

4.Linux的内核结构(注意区分LInux体系结构和Linux内核结构)

Linux驱动的platform机制

Linux的这种platform driver机制和传统的device_driver机制相比,一个十分明显的优势在于platform机制将本身的资源注册进内核,由内核统一管理,在驱动程序中使用这些资源时通过platform_device提供的标准接口进行申请并使用。这样提高了驱动和资源管理的独立性,并且拥有较好的可移植性和安全性。下面是SPI驱动层次示意图,Linux中的SPI 总线可理解为SPI控制器引出的总线:

和传统的驱动一样,platform机制也分为三个步骤:

1、总线注册阶段:

内核启动初始化时的main.c文件中的

kernel_init()→do_basic_setup()→driver_init()→platform_bus_init()→bus_register(&pl atform_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()→bu s_for_each_dev(),对在每个挂在虚拟的platform bus的设备作

__driver_attach()→driver_probe_device(),判断drv→bus→mat ch()是否执行成功,此时通过指针执行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 内核修改与编译图文教程 1

1、实验目的 针对Ubuntu10.04中,通过下载新的内核版本,并且修改新版本内核中的系统调用看,然后,在其系统中编译,加载新内核。 2、任务概述 2.1 下载新内核 https://www.sodocs.net/doc/6910736677.html,/ 2.2 修改新内核系统调用 添加新的系统调用函数,用来判断输入数据的奇偶性。 2.3 进行新内核编译 通过修改新版内核后,进行加载编译。最后通过编写测试程序进行测试 3、实验步骤 3.1 准备工作 查看系统先前内核版本: (终端下)使用命令:uname -r 2

3.2 下载最新内核 我这里使用的内核版本是 3.3 解压新版内核 将新版内核复制到“/usr/src”目录下 在终端下用命令:cd /usr/src进入到该文件目录 解压内核:linux-2.6.36.tar.bz2,在终端进入cd /usr/src目录输入一下命令: bzip2 -d linux-2.6.36.tar.bz2 tar -xvf linux-2.6.36.tar 文件将解压到/usr/src/linux目录中 3

使用命令: ln -s linux-2.6.36 linux 在终端下输入一下命令: sudo apt-get install build-essential kernel-package libncurses5-dev fakeroot sudo aptitude install libqt3-headers libqt3-mt-dev libqt3-compat-headers libqt3-mt 4

Linux内核—文件系统模块的设计和开发

Linux内核—文件系统模块的设计和开发 郑小辉 摘要:目前,Linux技术已经成为IT技术发展的热点,投身于Linux技术研究的社区、研究机构和软件企业越来越多,支持Linux的软件、硬件制造商和解决方案提供商也迅速增加,Linux在信息化建设中的应用范围也越来越广,Linux产业链已初步形成,并正在得到持续的完善。随着整个Linux产业的发展,Linux技术也处在快速的发展过程中,形成了若干技术热点。 本文介绍了Linux的发展和特点,以及与其他文件系统的区别。文中主要是对Linux2.4.0内核文件系统源代码的分析,并参考其文件格式设计一个简洁的文件系统。源代码的分析主要介绍了VFS文件系统的结构,Linux自己的Ext2文件系统结构,以及文件系统中的主要函数操作。 在设计的简洁文件系统中,通过调用一些系统函数实现了用户的登录、浏览目录、创建目录、更改目录、创建文件以及退出系统功能。 关键字:Linux 源代码分析文件系统Ext2 Linux内核

Linux kernel -Design and development for the File System Module Zheng xiaohui Abstract: Currently, Linux IT technology has become a hot development technology. Participating in Linux technology research communities, research institutes and software enterprises are in support of Linux more and more, software and hardware manufacturers and solution providers have increased rapidly, In the development of the information industry the Linux application is also increasing, Linux industry chain has taken shape, and is sustained improvemently. With the entire industry in the development of Linux, and Linux is also at the rapid development process, formed a number of technical points. This paper presents the development of Linux and features, and with other file system differences. The main text of the document is Linux2.4.0 system kernel source code analysis, and I reference its file format to design a simple file system. The analysis of the source code mainly on the VFS file system structure, Linux Ext2 its own file system structures, file systems and the main function operation. In the design of the file simple system, some system function is used to achieve function such as: the user's login, browse catalogs, create directories, Change directory, create documents and withdraw from the system function and etc. Key words: Linux, the source code, file system, Ext2, Linux kernel

Linux内核崩溃原因分析及错误跟踪技术

Linux内核崩溃原因分析及错误跟踪技术 随着嵌入式Linux系统的广泛应用,对系统的可靠性提出了更高的要求,尤其是涉及到生命财产等重要领域,要求系统达到安全完整性等级3级以上[1],故障率(每小时出现危险故障的可能性)为10-7以下,相当于系统的平均故障间隔时间(MTBF)至少要达到1141年以上,因此提高系统可靠性已成为一项艰巨的任务。对某公司在工业领域14 878个控制器系统的应用调查表明,从2004年初到2007年9月底,随着硬软件的不断改进,根据错误报告统计的故障率已降低到2004年的五分之一以下,但查找错误的时间却增加到原来的3倍以上。 这种解决问题所需时间呈上升的趋势固然有软件问题,但缺乏必要的手段以辅助解决问题才是主要的原因。通过对故障的统计跟踪发现,难以解决的软件错误和从发现到解决耗时较长的软件错误都集中在操作系统的核心部分,这其中又有很大比例集中在驱动程序部分[2]。因此,错误跟踪技术被看成是提高系统安全完整性等级的一个重要措施[1],大多数现代操作系统均为发展提供了操作系统内核“崩溃转储”机制,即在软件系统宕机时,将内存内容保存到磁盘[3],或者通过网络发送到故障服务器[3],或者直接启动内核调试器[4]等,以供事后分析改进。 基于Linux操作系统内核的崩溃转储机制近年来有以下几种: (1) LKCD(Linux Kernel Crash Dump)机制[3]; (2) KDUMP(Linux Kernel Dump)机制[4]; (3) KDB机制[5]; (4) KGDB机制[6]。 综合上述几种机制可以发现,这四种机制之间有以下三个共同点: (1) 适用于为运算资源丰富、存储空间充足的应用场合; (2) 发生系统崩溃后恢复时间无严格要求; (3) 主要针对较通用的硬件平台,如X86平台。 在嵌入式应用场合想要直接使用上列机制中的某一种,却遇到以下三个难点无法解决: (1) 存储空间不足 嵌入式系统一般采用Flash作为存储器,而Flash容量有限,且可能远远小于嵌入式系统中的内存容量。因此将全部内存内容保存到Flash不可行。

探究linux内核,超详细解析子系统

探究linux内核,超详细解析子系统 Perface 前面已经写过一篇《嵌入式linux内核的五个子系统》,概括性比较强,也比较简略,现在对其进行补充说明。 仅留此笔记,待日后查看及补充!Linux内核的子系统 内核是操作系统的核心。Linux内核提供很多基本功能,如虚拟内存、多任务、共享库、需求加载、共享写时拷贝(Copy-On-Write)以及网络功能等。增加各种不同功能导致内核代码不断增加。 Linux内核把不同功能分成不同的子系统的方法,通过一种整体的结构把各种功能集合在一起,提高了工作效率。同时还提供动态加载模块的方式,为动态修改内核功能提供了灵活性。系统调用接口用户程序通过软件中断后,调用系统内核提供的功能,这个在用户空间和内核提供的服务之间的接口称为系统调用。系统调用是Linux内核提供的,用户空间无法直接使用系统调用。在用户进程使用系统调用必须跨越应用程序和内核的界限。Linux内核向用户提供了统一的系统调用接口,但是在不同处理器上系统调用的方法

各不相同。Linux内核提供了大量的系统调用,现在从系统 调用的基本原理出发探究Linux系统调用的方法。这是在一个用户进程中通过GNU C库进行的系统调用示意图,系 统调用通过同一个入口点传入内核。以i386体系结构为例,约定使用EAX寄存器标记系统调用。 当加载了系统C库调用的索引和参数时,就会调用0x80软件中断,它将执行system_call函数,这个函数按照EAX 寄存器内容的标示处理所有的系统调用。经过几个单元测试,会使用EAX寄存器的内容的索引查system_call_table表得到系统调用的入口,然后执行系统调用。从系统调用返回后,最终执行system_exit,并调用resume_userspace函数返回用户空间。 linux内核系统调用的核心是系统多路分解表。最终通过EAX寄存器的系统调用标识和索引值从对应的系统调用表 中查出对应系统调用的入口地址,然后执行系统调用。 linux系统调用并不单层的调用关系,有的系统调用会由

linux内核的网络配置

文章来源 https://www.sodocs.net/doc/6910736677.html,/p/2088592067 第9节, Networking support 关于网络支持 上图 讲解; RF switch subsystem support 这个一般是要的,因为有些无线和蓝牙放在一张卡上 选m,wireless(无线)里面的一些选项随之会自动选m,上图 注意: cfg80211 wireless extensions compatibility 这个兼容选项要选择,3.7默认是没有选择

如果没有选择,iwconfig会报告没有扩展 Bluetooth subsystem support 蓝牙,可以自己选择,如果有m就行 还有子选项自己看下 如果还有红外线,无线电,对应选择,这个设备应该是很少networking option最上面的,全局网络选项,上图

Packet socket和Unix domain sockets 备必,而且不能成模块,不然udev会报一段信息给你 Transformation user configuration interface 选m,其实也很少用,像ipsec,下面的ipsec也可以选成模块 TCP/IP networking 要的,要的,子选项大部分不用,你也可以选上 IP: multicasting 多播 IP: advanced router 高级路由 你需要选上 IP: TCP syncookie support ~~sync flooding,同时还必须。。。个人没什么意义Large Receive Offload提高网络的东西,这个Y,如果你觉得现在不用,先m TCP: advanced congestion control这个你也可以Y The IPv6 protocol 很多要用到,虽然在兲现在没用,像systemd就要了 Security Marking和Network packet filtering framework (Netfilter) 个人没什么意义,你可以试下

linux内核IMQ源码实现分析

本文档的Copyleft归wwwlkk所有,使用GPL发布,可以自由拷贝、转载,转载时请保持文档的完整性,严禁用于任何商业用途。 E-mail: wwwlkk@https://www.sodocs.net/doc/6910736677.html, 来源: https://www.sodocs.net/doc/6910736677.html,/?business&aid=6&un=wwwlkk#7 linux2.6.35内核IMQ源码实现分析 (1)数据包截留并重新注入协议栈技术 (1) (2)及时处理数据包技术 (2) (3)IMQ设备数据包重新注入协议栈流程 (4) (4)IMQ截留数据包流程 (4) (5)IMQ在软中断中及时将数据包重新注入协议栈 (7) (6)结束语 (9) 前言:IMQ用于入口流量整形和全局的流量控制,IMQ的配置是很简单的,但很少人分析过IMQ的内核实现,网络上也没有IMQ的源码分析文档,为了搞清楚IMQ的性能,稳定性,以及借鉴IMQ的技术,本文分析了IMQ的内核实现机制。 首先揭示IMQ的核心技术: 1.如何从协议栈中截留数据包,并能把数据包重新注入协议栈。 2.如何做到及时的将数据包重新注入协议栈。 实际上linux的标准内核已经解决了以上2个技术难点,第1个技术可以在NF_QUEUE机制中看到,第二个技术可以在发包软中断中看到。下面先介绍这2个技术。 (1)数据包截留并重新注入协议栈技术

(2)及时处理数据包技术 QoS有个技术难点:将数据包入队,然后发送队列中合适的数据包,那么如何做到队列中的数

激活状态的队列是否能保证队列中的数据包被及时的发送吗?接下来看一下,激活状态的队列的 证了数据包会被及时的发送。 这是linux内核发送软中断的机制,IMQ就是利用了这个机制,不同点在于:正常的发送队列是将数据包发送给网卡驱动,而IMQ队列是将数据包发送给okfn函数。

如何安装Linux内核源代码

如何获取Linux内核源代码 下载Linux内核当然要去官方网站了,网站提供了两种文件下载,一种是完整的Linux 内核,另一种是内核增量补丁,它们都是tar归档压缩包。除非你有特别的原因需要使用旧版本的Linux内核,否则你应该总是升级到最新版本。 使用Git 由Linus领头的内核开发队伍从几年前就开始使用Git版本控制系统管理Linux内核了(参考阅读:什么是Git?),而Git项目本身也是由Linus创建的,它和传统的CVS不一样,Git是分布式的,因此它的用法和工作流程很多开发人员可能会感到很陌生,但我强烈建议使用Git下载和管理Linux内核源代码。 你可以使用下面的Git命令获取Linus内核代码树的最新“推送”版本: $ git clone git://https://www.sodocs.net/doc/6910736677.html,/pub/scm/linux/kernel/git/torvalds/linux-2.6.git 然后使用下面的命令将你的代码树与Linus的代码树最新状态同步: $ git pull 安装内核源代码 内核包有GNU zip(gzip)和bzip2格式。Bzip2是默认和首选格式,因为它的压缩比通常比gzip更好,bzip2格式的Linux内核包一般采用linux-x.y.z.tar.bz2形式的文件名,这里的x.y.z是内核源代码的具体版本号,下载到源代码包后,解压和抽取就很简单了,如果你下载的是bzip2包,运行: $ tar xvjf linux-x.y.z.tar.bz2 如果你下载的是gzip包,则运行: $ tar xvzf linux-x.y.z.tar.gz 无论执行上面哪一个命令,最后都会将源代码解压和抽取到linux-x.y.z目录下,如果你使用Git下载和管理内核源代码,你不需要下载tar包,只需要运行git clone命令,它就会自动下载和解压。 内核源代码通常都会安装到/usr/src/linux下,但在开发的时候最好不要使用这个源代码树,因为针对你的C库编译的内核版本通常也链接到这里的。 应用补丁

Linux内核结构详解教程

Linux内核结构详解教程 ─────Linux内核教程 linux内核就像人的心脏,灵魂,指挥中心。 内核是一个操作系统的核心,它负责管理系统的进程,内存,设备驱动程序,文件和网络系统,决定着系统的性能和稳定性。内核以独占的方式执行最底层任务,保证系统正常运行。协调多个并发进程,管理进程使用的内存,使它们相互之间不产生冲突,满足进程访问磁盘的请求等等. 严格说Linux并不能称做一个完整的操作系统.我们安装时通常所说的Linux,是有很多集合组成的.应称为GNU/Linux. 一个Linux内核很少1.2M左右,一张软盘就能放下. 内容基础,语言简短简洁 红联Linux论坛是致力于Linux技术讨论的站点,目前网站收录的文章及教程基本能满足不同水平的朋友学习。 红联Linux门户: https://www.sodocs.net/doc/6910736677.html, 红联Linux论坛: https://www.sodocs.net/doc/6910736677.html,/bbs 红联Linux 论坛大全,所有致力点都体现在这 https://www.sodocs.net/doc/6910736677.html,/bbs/rf/linux/07.htm

目录 Linux内核结构详解 Linux内核主要五个子系统详解 各个子系统之间的依赖关系 系统数据结构 Linux的具体结构 Linux内核源代码 Linux 内核源代码的结构 从何处开始阅读源代码 海量Linux技术文章

Linux内核结构详解 发布时间:2006-11-16 19:05:29 Linux内核主要由五个子系统组成:进程调度,内存管理,虚拟文件系统,网络接口,进程间通信。

Linux内核主要五个子系统详解 发布时间:2006-11-16 19:05:54 1.进程调度(SCHED):控制进程对CPU的访问。当需要选择下一个进程运行时,由调度程序选择最值得运行的进程。可运行进程实际上是仅等待CPU资源的进程,如果某个进程在等待其它资源,则该进程是不可运行进程。Linux使用了比较简单的基于优先级的进程调度算法选择新的进程。 2.内存管理(MM)允许多个进程安全的共享主内存区域。Linux的内存管理支持虚拟内存,即在计算机中运行的程序,其代码,数据,堆栈的总量可以超过实际内存的大小,操作系统只是把当前使用的程序块保留在内存中,其余的程序块则保留在磁盘中。必要时,操作系统负责在磁盘和内存间交换程序块。内存管理从逻辑上分为硬件无关部分和硬件有关部分。硬件无关部分提供了进程的映射和逻辑内存的对换;硬件相关的部分为内存管理硬件提供了虚拟接口。 3.虚拟文件系统(VirtualFileSystem,VFS)隐藏了各种硬件的具体细节,为所有的设备提供了统一的接口,VFS提供了多达数十种不同的文件系统。虚拟文件系统可以分为逻辑文件系统和设备驱动程序。逻辑文件系统指Linux所支持的文件系统,如ext2,fat等,设备驱动程序指为每一种硬件控制器所编写的设备驱动程序模块。 4.网络接口(NET)提供了对各种网络标准的存取和各种网络硬件的支持。网络接口可分为网络协议和网络驱动程序。网络协议部分负责实现每一种可能的网络传输协议。网络设备驱动程序负责与硬件设备通讯,每一种可能的硬件设备都有相应的设备驱动程序。 5.进程间通讯(IPC) 支持进程间各种通信机制。 处于中心位置的进程调度,所有其它的子系统都依赖它,因为每个子系统都需要挂起或恢复进程。一般情况下,当一个进程等待硬件操作完成时,它被挂起;当操作真正完成时,进程被恢复执行。例如,当一个进程通过网络发送一条消息时,网络接口需要挂起发送进程,直到硬件成功地完成消息的发送,当消息被成功的发送出去以后,网络接口给进程返回一个代码,表示操作的成功或失败。其他子系统以相似的理由依赖于进程调度。

Linux设置内核参数的方法

Linux设置内核参数的方法 1内核参数的查看方法 使用“sysctl -a”命令可以查看所有正在使用的内核参数。内核参数比较多(一般多达500项),按照前缀主要分为以下几大类:net.ipv4、net.ipv6、net.core、vm、fs、dev.parport、dev.cdrom 、dev.raid、kernel等等。相同的linux,安装的组件和使用的方式不一样,正在使用的内核参数是不一样的。 所有的内核参数的说明文档是放到/usr/src/linux/Documentation/sysctl中的,如果想知道对内核参数的说明,可以到该目录下查看相应的说明文档。 2内核参数的的设置方法 由于Linux的内核参数信息都存在内存中,因此可以通过命令直接修改,并且修改后直接生效。也可以通过文件的方式进行设置。下面就介绍这两种修改方法。 2.1命令设置的方式 可以用两种方法实现。 1、使用“sysctl -w 参数名=值”的方式 假设我们把net.ipv4.ip_forward的值修改为1,使用命令“sysctl -w net.ipv4.ip_forward=1”。 2、修改内核参数对应的proc文件 内核参数位于/proc/sys/之下,参数名称是以文件所在的路径,并将“/”以“.”来取代。举例来说,/proc/sys/net/ip_forward的参数名称为net.ipv4.ip_forward。 同样把net.ipv4.ip_forward的值修改为1,使用命令“echo “1”> /proc/sys/net/ipv4/ip_forward”。 注意,这里proc文件跟普通的文件不一样。一般一个文件用echo写入内容之后,会变成一个文本文件,但echo修改proc文件之后还是个空文件。 2.2文件设置的方式 更改的内核参数默认保存在/etc/sysctl.conf文件中。修改的时候可以直接用vi编辑sysctl.conf文件,增加要修改的内核参数内容,修改的格式为:参数名=值。例如,把net.ipv4.ip_forward的值修改为1,在sysctl.conf中增加下面这行内容:net.ipv4.ip_forward=1 文件修改好后,进行保存。然后使用“sysctl -p 配置文件名”来使配置生效,如果配置文件是默认的,可以不用输配置文件名,即使用“sysctl -p”。 通过文件设置的方式修改的内核参数是在系统重启后将失效(我之前认为修改后的内核参数放在文件中,系统启动的时候会读这个文件,重启后设置应该不会失效。但经过验证,一般会失效,但如果把将默认的boot.sysctl服务打开,所以系统启动时就会执行这个文件的设置)。把我们修改参数的命令写入启动执行脚本文件里/etc/rc.local,这样系统重启后配置就不会失效。 文件方式的好处是内核参数设置的值可以用文件保留下来,调用“sysctl -p”可以使文

史上最全linux内核配置详解

对于每一个配置选项,用户可以回答"y"、"m"或"n"。其中"y"表示将相应特性的支持或设备驱动程序编译进内核;"m"表示将相应特性的支持或设备驱动程序编译成可加载模块,在需要时,可由系统或用户自行加入到内核中去;"n"表示内核不提供相应特性或驱动程序的支持。只有<>才能选择M 1. General setup(通用选项) [*]Prompt for development and/or incomplete code/drivers,设置界面中显示还在开发或者还没有完成的代码与驱动,最好选上,许多设备都需要它才能配置。 [ ]Cross-compiler tool prefix,交叉编译工具前缀,如果你要使用交叉编译工具的话输入相关前缀。默认不使用。嵌入式linux更不需要。 [ ]Local version - append to kernel release,自定义版本,也就是uname -r可以看到的版本,可以自行修改,没多大意义。 [ ]Automatically append version information to the version string,自动生成版本信息。这个选项会自动探测你的内核并且生成相应的版本,使之不会和原先的重复。这需要Perl的支持。由于在编译的命令make-kpkg 中我们会加入- –append-to-version 选项来生成自定义版本,所以这里选N。 Kernel compression mode (LZMA),选择压缩方式。 [ ]Support for paging of anonymous memory (swap),交换分区支持,也就是虚拟内存支持,嵌入式不需要。 [*]System V IPC,为进程提供通信机制,这将使系统中各进程间有交换信息与保持同步的能力。有些程序只有在选Y的情况下才能运行,所以不用考虑,这里一定要选。 [*]POSIX Message Queues,这是POSIX的消息队列,它同样是一种IPC(进程间通讯)。建议你最好将它选上。 [*]BSD Process Accounting,允许进程访问内核,将账户信息写入文件中,主要包括进程的创建时间/创建者/内存占用等信息。可以选上,无所谓。 [*]BSD Process Accounting version 3 file format,选用的话统计信息将会以新的格式(V3)写入,注意这个格式和以前的v0/v1/v2 格式不兼容,选不选无所谓。 [ ]Export task/process statistics through netlink (EXPERIMENTAL),通过通用的网络输出工作/进程的相应数据,和BSD不同的是,这些数据在进程运行的时候就可以通过相关命令访问。和BSD类似,数据将在进程结束时送入用户空间。如果不清楚,选N(实验阶段功能,下同)。 [ ]Auditing support,审计功能,某些内核模块需要它(SELINUX),如果不知道,不用选。 [ ]RCU Subsystem,一个高性能的锁机制RCU 子系统,不懂不了解,按默认就行。 [ ]Kernel .config support,将.config配置信息保存在内核中,选上它及它的子项使得其它用户能从/proc/ config.gz中得到内核的配置,选上,重新配置内核时可以利用已有配置Enable access to .config through /proc/config.gz,上一项的子项,可以通过/proc/ config.gz访问.config配置,上一个选的话,建议选上。 (16)Kernel log buffer size (16 => 64KB, 17 => 128KB) ,内核日志缓存的大小,使用默认值即可。12 => 4 KB,13 => 8 KB,14 => 16 KB单处理器,15 => 32 KB多处理器,16 => 64 KB,17 => 128 KB。 [ ]Control Group support(有子项),使用默认即可,不清楚可以不选。 Example debug cgroup subsystem,cgroup子系统调试例子 Namespace cgroup subsystem,cgroup子系统命名空间 Device controller for cgroups,cgroups设备控制器

linux内核启动 Android系统启动过程详解

linux内核启动+Android系统启动过程详解 第一部分:汇编部分 Linux启动之 linux-rk3288-tchip/kernel/arch/arm/boot/compressed/ head.S分析这段代码是linux boot后执行的第一个程序,完成的主要工作是解压内核,然后跳转到相关执行地址。这部分代码在做驱动开发时不需要改动,但分析其执行流程对是理解android的第一步 开头有一段宏定义这是gnu arm汇编的宏定义。关于GUN 的汇编和其他编译器,在指令语法上有很大差别,具体可查询相关GUN汇编语法了解 另外此段代码必须不能包括重定位部分。因为这时一开始必须要立即运行的。所谓重定位,比如当编译时某个文件用到外部符号是用动态链接库的方式,那么该文件生成的目标文件将包含重定位信息,在加载时需要重定位该符号,否则执行时将因找不到地址而出错 #ifdef DEBUG//开始是调试用,主要是一些打印输出函数,不用关心 #if defined(CONFIG_DEBUG_ICEDCC)

……具体代码略 #endif 宏定义结束之后定义了一个段, .section ".start", #alloc, #execinstr 这个段的段名是 .start,#alloc表示Section contains allocated data, #execinstr表示Section contains executable instructions. 生成最终映像时,这段代码会放在最开头 .align start: .type start,#function /*.type指定start这个符号是函数类型*/ .rept 8 mov r0, r0 //将此命令重复8次,相当于nop,这里是为中断向量保存空间 .endr b 1f .word 0x016f2818 @ Magic numbers to help the loader

Linux内核分析-网络[五]:网桥

看完了路由表,重新回到netif_receive_skb ()函数,在提交给上层协议处理前,会执行下面一句,这就是网桥的相关操作,也是这篇要讲解的容。 view plaincopy to clipboardprint? 1. s kb = handle_bridge(skb, &pt_prev, &ret, orig_dev); 网桥可以简单理解为交换机,以下图为例,一台linux机器可以看作网桥和路由的结合,网桥将物理上的两个局域网LAN1、LAN2当作一个局域网处理,路由连接了两个子网1.0和2.0。从eth0和eth1网卡收到的报文在Bridge模块中会被处理成是由Bridge收到的,因此Bridge也相当于一个虚拟网卡。 STP五种状态 DISABLED BLOCKING LISTENING LEARNING FORWARDING 创建新的网桥br_add_bridge [net\bridge\br_if.c] 当使用SIOCBRADDBR调用ioctl时,会创建新的网桥br_add_bridge。 首先是创建新的网桥: view plaincopy to clipboardprint?

1. d ev = new_bridge_dev(net, name); 然后设置dev->dev.type为br_type,而br_type是个全局变量,只初始化了一个名字变量 view plaincopy to clipboardprint? 1. S ET_NETDEV_DEVTYPE(dev, &br_type); 2. s tatic struct device_type br_type = { 3. .name = "bridge", 4. }; 然后注册新创建的设备dev,网桥就相当一个虚拟网卡设备,注册过的设备用ifconfig 就可查看到: view plaincopy to clipboardprint? 1. r et = register_netdevice(dev); 最后在sysfs文件系统中也创建相应项,便于查看和管理: view plaincopy to clipboardprint? 1. r et = br_sysfs_addbr(dev); 将端口加入网桥br_add_if() [net\bridge\br_if.c] 当使用SIOCBRADDIF调用ioctl时,会向网卡加入新的端口br_add_if。 创建新的net_bridge_port p,会从br->port_list中分配一个未用的port_no,p->br会指向br,p->state设为BR_STATE_DISABLED。这里的p实际代表的就是网卡设备。 view plaincopy to clipboardprint? 1. p = new_nbp(br, dev); 将新创建的p加入CAM表中,CAM表是用来记录mac地址与物理端口的对应关系;而刚刚创建了p,因此也要加入CAM表中,并且该表项应是local的[关系如下图],可以看到,CAM表在实现中作为net_bridge的hash表,以addr作为hash值,链入 net_bridge_fdb_entry,再由它的dst指向net_bridge_port。

LINUX内核模块编程指南

第1章Hello, World 如果第一个程序员是一个山顶洞人,它在山洞壁(第一台计算机)上凿出的第一个程序应该是用羚羊图案构成的一个字符串“Hello, Wo r l d”。罗马的编程教科书也应该是以程序“S a l u t, M u n d i”开始的。我不知道如果打破这个传统会带来什么后果,至少我还没有勇气去做第一个吃螃蟹的人。 内核模块至少必须有两个函数:i n i t_m o d u l e和c l e a n u p_m o d u l e。第一个函数是在把模块插入内核时调用的;第二个函数则在删除该模块时调用。一般来说,i n i t_m o d u l e可以为内核的某些东西注册一个处理程序,或者也可以用自身的代码来取代某个内核函数(通常是先干点别的什么事,然后再调用原来的函数)。函数c l e a n u p_m o d u l e的任务是清除掉i n i t_m o d u l e所做的一切,这样,这个模块就可以安全地卸载了。

1.1 内核模块的Makefiles 文件 内核模块并不是一个独立的可执行文件,而是一个对象文件,在运行时内核模块被链接到内核中。因此,应该使用- c 命令参数来编译它们。还有一点需要注意,在编译所有内核模块时,都将需要定义好某些特定的符号。 ? _ _KERNEL_ _—这个符号告诉头文件:这个程序代码将在内核模式下运行,而不要作为用户进程的一部分来执行。 ? MODULE —这个符号告诉头文件向内核模块提供正确的定义。 ? L I N U X —从技术的角度讲,这个符号不是必需的。然而,如果程序员想要编写一个重要的内核模块,而且这个内核模块需要在多个操作系统上编译,在这种情况下,程序员将会很高兴自己定义了L I N U X 这个符号。这样一来,在那些依赖于操作系统的部分,这个符号就可以提供条件编译了。 还有其它的一些符号,是否包含它们要取决于在编译内核时使用了哪些命令参数。如果用户不太清楚内核是怎样编译的,可以查看文件/ u s r /i n c l u d e /l i n u x /c o n f i g .h 。 ? _ _SMP_ _—对称多处理。如果编译内核的目的是为了支持对称多处理,在编译时就需要定义这个符号(即使内核只是在一个C P U 上运行也需要定义它)。当然,如果用户使用对称多处理,那么还需要完成其它一些任务(参见第1 2章)。 ? C O N F I G _M O D V E R S I O N S —如果C O N F I G _M O D V E R S I O N S 可用,那么在编译内核模块时就需要定义它,并且包含头文件/ u s r /i n c l u d e /l i n u x /m o d v e r s i o n s .h 。还可以用代码自身来完成这个任务。 完成了以上这些任务以后,剩下唯一要做的事就是切换到根用户下(你不是以r o o t 身份编译内核模块的吧?别玩什么惊险动作哟!),然后根据自己的需要插入或删除h e l l o 模块。在执行完i n s m o d 命令以后,可以看到新的内核模块在/ p r o c /m o d u l e s 中。 顺便提一下,M a k e f i l e 建议用户不要从X 执行i n s m o d 命令的原因在于,当内核有个消息需要使用p r i n t k 命令打印出来时,内核会把该消息发送给控制台。当用户没有使用X 时,该消息146第二部分Linux 内核模块编程指南

Linux内核中的Kconfig用法与说明

Linux内核中的Kconfig文件 本节不对内核的Kconfig文件进行深入展开,更多Kconfig语法和说明请阅读 。 内核源码树每个目录下都还包含一个Kconfig文件,用于描述所在目录源代码相关的内核配置菜单,各个目录的Kconfig文件构成了一个分布式的内核配置数据库。通过make menuconfig(make xconfig或者make gconfig)命令配置内核的时候,从Kconfig文件读取菜单,配置完毕保存到文件名为.config的内核配置文件中,供Makefile文件在编译内核时使用。 1.1.1 Kconfig基本语法 如程序清单0.1所示代码摘自文件,是一个比较典型的Kconfig 文件片段,包含了Kconfig的基本语法。 程序清单0.1drivers/char/Kconfig片段 menu "Character devices" source "drivers/tty/Kconfig" config DEVKMEM bool "/dev/kmem virtual device support" default y help Say Y here if you want to support the /dev/kmem device. The /dev/kmem device is rarely used, but can be used for certain kind of kernel debugging operations. When in doubt, say "N". …… endmenu 1.子菜单 通过menu和endmenu来定义一个子菜单,程序清单0.1所示代码定义了一个“Character devices”子菜单,子菜单在界面中用“--->”表示,如图0.1所示。 图0.1menu定义的子菜单 子菜单的菜单项则由config来定义,随后的“bool”、“default”、“help”等都是该菜单 项的属性:

【IT专家】突破Linux内核模块校验机制

突破Linux 内核模块校验机制 1、为什么要突破模块验证Linux 内核版本很多,升级很快,2 个小内核版本 中内核函数的定义可能都不一样,为了确保不一致的驱动程序导致kernel oops,开 发者加入了模块验证机制。它在加载内核模块的时候对模块进行校验,如果模块与 主机的一些环境不一致,就会加载不成功。看下面一个例子,它简单的输出当期 系统中的模块列表:[root@localhost list]# uname -a Linux localhost.localdomain 2.6.18-128.el5 #1 SMP Wed Jan 21 10:44:23 EST 2009 i686 i686 i386 GNU/Linux 然后拷贝到另一台主机centos5.1xen 上:[root@localhost ~]# uname -a Linux localhost.localdomain 2.6.18-53.el5xen #1 SMP Mon Nov 12 03:26:12 EST 2007 i686 i686 i386 GNU/Linux 用insmod 加载:[root@localhost ~]# insmod list.ko insmod: error inserting ‘list.ko’: -1 Invalid module format 报错了,在看下dmesg 的信息:[root@localhost ~]# dmesg|tail -n 1 list: disagrees about version of symbol struct_module 先不管这是什么,总之我们的模块在另一台2.6.18 的主机中加载失 败。通常的做法et 下来,install 即可。但是它也有很多缺点,比如很不稳定,而 且在2.6.x 后内核已经取消了kmem 这个设备,mem 文件也做了映射和读写的限 制。rk 开发者没法继续sk 的神话了。反过来,如果我们的lkm 后门不需要编译环 境,也可以达到直接insmod 的目的,这是件多么美好的事情,而且lkm 后门更加稳 定,还不用像sk 在内核中添加了很多自己的数据结构。2、内核是怎么实现的 我们去看看内核在加载模块的时候都干了什么,或许我们可以发现点bug,然后 做点手脚,欺骗过去:)grep 下dmesg 里的关键字,看看它在哪个文件中:[root@localhost linux-2.6.18]# grep -r -i ‘disagrees about’kernel/ kernel/module.c: printk(“%s: disagrees about version of symbol %s\n”, 2.6.18/kernel/module.c: insmod 调用了sys_init_module 这个系统调用, 然后进入load_module 这个主函数,它解析 elf 格式的ko 文件,然后加载到内核中:/* Allocate and load the module: note that size of section 0 is always zero, and we rely on this for optional sections. */ static struct module *load_module(void __user *umod, unsigned long len, const char __user

实例解析linux内核I2C体系结构(2)

实例解析linux内核I2C体系结构(2) 华清远见刘洪涛四、在内核里写i2c设备驱动的两种方式 前文介绍了利用/dev/i2c-0在应用层完成对i2c设备的操作,但很多时候我们还是习惯为i2c设备在内核层编写驱动程序。目前内核支持两种编写i2c驱动程序的方式。下面分别介绍这两种方式的实现。这里分别称这两种方式为“Adapter方式(LEGACY)”和“Probe方式(new style)”。 (1)Adapter方式(LEGACY) (下面的实例代码是在2.6.27内核的pca953x.c基础上修改的,原始代码采用的是本文将要讨论的第2种方式,即Probe方式) ●构建i2c_driver static struct i2c_driver pca953x_driver = { .driver = { .name= "pca953x", //名称 }, .id= ID_PCA9555,//id号 .attach_adapter= pca953x_attach_adapter, //调用适配器连接设备 .detach_client= pca953x_detach_client,//让设备脱离适配器 }; ●注册i2c_driver static int __init pca953x_init(void) { return i2c_add_driver(&pca953x_driver); } module_init(pca953x_init); ●attach_adapter动作 执行i2c_add_driver(&pca953x_driver)后会,如果内核中已经注册了i2c适配器,则顺序调用这些适配器来连接我们的i2c设备。此过程是通过调用i2c_driver中的attach_adapter方法完成的。具体实现形式如下: static int pca953x_attach_adapter(struct i2c_adapter *adapter) { return i2c_probe(adapter, &addr_data, pca953x_detect); /* adapter:适配器 addr_data:地址信息 pca953x_detect:探测到设备后调用的函数 */ } 地址信息addr_data是由下面代码指定的。 /* Addresses to scan */ static unsigned short normal_i2c[] = {0x20,0x21,0x22,0x23,0x24,0x25,0x26,0x27,I2C_CLIENT_END}; I2C_CLIENT_INSMOD;

相关主题