加入收藏 | 设为首页 | 会员中心 | 我要投稿 晋中站长网 (https://www.0354zz.com/)- 科技、建站、经验、云计算、5G、大数据,站长网!
当前位置: 首页 > 服务器 > 搭建环境 > Linux > 正文

linux内核_Linux 内核深度剖析与实践

发布时间:2022-10-20 13:31:51 所属栏目:Linux 来源:未知
导读: Linux内核
最后有福利
在看一些 GNU 开源软件,或者阅读 Linux 内核、驱动源码时,相信大家和我一样,经常会遇到一些“看似熟悉”,但一仔细分析又不是很懂的 C 语言“稀奇古怪”的语法。其

Linux内核

最后有福利

在看一些 GNU 开源软件,或者阅读 Linux 内核、驱动源码时,相信大家和我一样,经常会遇到一些“看似熟悉”,但一仔细分析又不是很懂的 C 语言“稀奇古怪”的语法。其实这些都是 GNU C 对 C 语言语法的扩展。一般的教材中基本不会讲到这些,所以看不懂这些特殊的 C 语法应用也很正常。

此达人课将带领大家,一起学习 Linux 内核或 GNU 开源软件中对 C 语言各种扩展语法的使用,最终的目标是看懂 Linux 内核或 GNU 开源软件中这些“奇葩的语法”,扫除理解 Linux 内核驱动或 GNU 开源软件的语法障碍。

1《Linux内核设计与实现》

2《深入理解Linux内核》

3《Linux内核完全注释》

4《Linux内核源代码情景分析 》

一。《Linux内核设计与实现》

1. 单内核和微内核

a3c86f4abf6860583a2a7de9c144bdae.png

02c349989617f6afdca5b7ea759f4214.png

Linux的内核虽然是基于单内核的,但是经过这么多年的发展,也具备微内核的一些特征。(体现了Linux实用至上的原则)

主要有以下特征:

支持动态加载内核模块支持对称多处理(SMP)内核可以抢占(preemptive),允许内核运行的任务有优先执行的能力不区分线程和进程

2. 内核版本号

内核的版本号主要有四个数组组成。比如版本号:2.6.26.1 其中,

2 - 主版本号

6 - 从版本号或副版本号

26 - 修订版本号

1 - 稳定版本号

副版本号表示这个版本是稳定版(偶数)还是开发版(奇数),上面例子中的版本号是稳定版。

稳定的版本可用于企业级环境。

修订版本号的升级包括BUG修正,新的驱动以及新的特性的追加。

稳定版本号主要是一些关键性BUG的修改。

二,深入理解Linux内核

Linux 和一些商用unix的区别

1. Linux 主要是由 unix 内核加上 gnu的引用程序组成的 兼容IEEE POSIX 标准

2.linux 是传统上面的单块结构有逻辑上不同的部分组成

3.linux采用的是模块的方式(动态编译的方式)加载程序块。

4.Linux内核支持对称多处理器

5.Linux支持面向对象的虚拟文件系统,日志文集系统

优势:

1.免费

2.充分定制Linux系统 随时随地修改Linux代码

3.可以充分利用硬件平台 ,对硬件性能要求不高

4.Linux系统的代码运行时高效率的 ,而且没有商用的限制 。

5.内核精简

6.Linux系统兼容性好

7后台支持广泛

系统调用是 实现用户态到内核态的过程 , 特权模式由用户态转变为内核态 保存断点 ,最后 由硬件实现系统调用 返回进程断点

f99f49d71b4e4cba21aebda94e2d2739.png

三,《Linux内核完全注释》

1、选择《Linux内核完全注释》的理由

从现在起,我打算学习Linux内核,作一个基本的了解和入门吧。在网上也看了许多国内外的一些经典书籍的评价,最后我还是选择阅读《Linux内核完全注释》这本书,作为一个基础入门,这本书在网上的评价也还可以。

这本书讲解的Linux内核版本是Linux 0.11,虽然内核版本很低,但是作为学习来说应该还是可以的,该内核已经能够正常的编译运行,并且其中已经包括了Linux工作原理的精髓。由于Linux 0.11内核不超过2万行代码量,因此可以完全的通过一本书进行了解和学习。正是因为Linux 0.11内核代码量小,这本书对Linux 0.11内核的全部代码进行了注释,便于读者学习和理解。

为了让读者对所研究的系统有感性的了解,并能通过实验来加深对原来的理解,作者还专门重建了基于该内核的可运行的Linux 0.11系统,因为其中含有GNU gcc编译环境,因此使用该系统也能做一些简单的开发工作。

当然,使用早期内核作为学习的对象也有不足之处。所选用的Linux 0.11内核,不包含对虚拟文件系统VFS的支持、对网络系统的支持,仅支持a.out执行文件和对其他一些现有内核中复杂子系统的说明。

2、资料传送门

下面列举一下书中提供的一些资料链接,也方便以后自己的查找吧:

:该目录中含有已经制作好的内核映像文件bootimage和根文件系统映像文件rootimage。

:该目录中含有已经设置好的运行在计算机仿真系统bochs下的Linux系统。

:该目录中含有可以在Linux 0.11系统中使用的其他一些工具程序和原来发布的一些安装说明文档。

:可以在这里下载本书讲解的Linux 0.11内核源码,文件名:linux-0.11.tar.gz。

3、内核源码目录结构

整个Linux 0.11内核源代码的目录结构如下图所示:

a183147e14b96116400570c8a4355420.png

四。Linux内核源代码情景分析

1预备知识

1.1linux内核简介

linux发展史

linux源代码组成

linux内核版和发行版的命名方式

1.2 Intelx86的寻址方式

早期8086和8088处理器是16位,寻址方式为实模式,后来随着技术的发展,人们意识到实模式的不足(完全把计算机暴露在用户的眼皮下),就产生了保护模式,关于这两点的区别,主要在于对内存的访问是否有进行保护,主要是越界和越权。越界就是用户不能访问的地址范围不允许访问,用户没有权限的地址范围不能访问。所以早期计算机工作者们就在建立了段式内存管理,把内存地址进行分段(比如,16段,每段大小64k,刚好1M)然后cpu中设置了四个段寄存器:CS,DS,SS,ES,分别用于可执行代码的指令,数据,堆栈,其他。由于早期intel内存大小采用1M,而cpu确实16位,如果不做一定额处理,16位总线是不能访问超过64k的范围,所以每个段寄存器的内容作为内存地址的高16位,同时与段内偏移地址作为低16进行相加(重叠12位),这样就刚好形成了20位的内存地址,即1M。

由于这种管理机制无法提供对内存的保护,所以基于段式内存管理机制,到后来的386以后,人们采用保护模式,并且数据总线为32位了,人们在原来的四个段寄存器的基础上加上两个段寄存器FS,GS,为了实现保护模式的作用。所以数据总线的地址内容应该有如下设计思想

1根据指令的性质来确定应该使用哪个段寄存器

2根据段寄存器的内容,找到相应的地址段描述结构

3根据地址段描述结构得到基地址

4将指令发出的地址作为位移,与段描述结构中规定的段长度比较,是否越界

5根据地址段描述结构符中的访问权限来确定是否越权

6将指令发出的地址作为位移,与基地址相加得出实际的物理地址。

上面就是保护模式下段式内存管理的设计思想,下面就是实现过程。

1段寄存器,由于段地址描述结构栈8个字节,故地址为8的整数倍,所以段寄存器低三位可以用于其他作用。

ce0ebb1f082024064993170f12b32821.png

2段地址描述结构(GDTR,LDTR),其数据的主要作用在于描述基地址,权限,范围。

23ebba800332a56738f40ba2e887837f.png

通过上面的段寄存器映射到过渡的段地址描述结构,最后就是指令发出的地址与段地址描述结构提供的基地址来映射到最后的物理地址了(前提是没有采用分页内存管理)

1.3 i386页式管理机制

由于段式管理机制是实实在在的,没有抽象出来,不方便内存管理,人们就又在段式管理的基础上增加了分页式管理,从而由虚拟地址经过段式管理映射得到的地址不再是物理地址了,人们称为线性地址,在线性地址的基础上经过页面映射后得到的才是真正的物理地址。

在分页机制中,线性地址的结构被人为的划分为

2abaf4f75389d956047a65fc44215930.png

而整个页面映射的过程为

ff26094c5185c77dab401b0480941200.png

这里解释两点

1 记得前面我的每个段地址描述结构都占8个字节linux注释,所以地址一定按8的整数倍对其,这里我们的页面大小人为的划分为4k,即按4k对其,所以我们的目录项和页表同样可以拿出低12位用作他用。至于怎样实现,那是硬件上的问题。

2 为什么采用多级分页机制,而不简单直接的使用页表和页内偏移地址来进行分页,目的是在于节省内存,至于是怎么节省的,我当初上操作系统课程始终不明白,现在搞明白了。因为操作系统在创建进程时会为进程分配一个进程控制块,里面其中有一部分就是对虚存管理的页面数据结构,如果不采用多级分页机制的话,那么每个进程关页面表就占 个字节,即1M,即是进程用不着那么页表项(因为32位地址默认个用户的虚存空间是4G,但一个进程很难想象会用完这4G),但还是会占内存,但是采用多级分页的话,那么不需要的页表项就不进行分配,从而也就节省了内存,但是相反一个进程真的用完了4G的虚存,那么他需要的目录项和页表项占的内存就多了目录项这一部分了。

1.4linux内核源代码中C语言代码

Linux内核的主体是由GNU的C语言编写,CNU为此提供了编译器gcc,而gcc从C++语言中吸收了inline和const,其实GNU的C和C++是合为一体的,gcc既是C的编译器也是C++的编译器,所以linux中很多C语言代码自然就有C++风格在里面,所以需要一点C++基础。但这不是问题关键,关键在学习linux中C语言设计思想。

1常见的宏定义对简单函数的实现

#define DUMP_WRITE(addr,nr) do{ memcpy(bufp,addr,nr);bufp+=nr} while(0)

2使用结构体封装多个队列

be53a99a537d50af458ef02898fc8a04.png

3使用宏定义与函数实现简单初始化

bda8cb77055ab62bb9af4eecd34cccee.png

1.5linux内核源代码中的汇编语言代码

汇编语言有两套格式,在dos/windows领域中采用的汇编语言都是由intel定义的指令格式,也就是我们教材里面的汇编语言格式。另外一种就是UNIX领域使用的AT&T定义的格式,所以在linux内核中所使用的汇编格式是AT&T。尽管两种汇编语言指令不一样,但是指令的风格很类似,所以提供了一种互相学习的条件。而且AT&T汇编同样适用于gcc编译器,所以在c语言中可以嵌入式汇编语句,所以看懂linux内核代码,需要AT&T汇编基础以及嵌入式汇编基础。这里不详细介绍,后面在进程切换一节中借助一段内核中用来实现内存空间切换的汇编代码来介绍一下嵌入式AT&T汇编。

详细参见:需要相关资料的可以后台私信,资料,可MF领取 欢迎

(编辑:晋中站长网)

【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容!