Linux内核从原理到代码详解

滚动学习,坐班辅导
(0人)

345.00 元 5 折

全场5折优惠,咨询QQ810476411

段机制从8086引入,解决16位地址访问20位的地址空间的问题,为了兼容就保留下来了

分段、分页机制对x86是都有的,段机制是必选的。

 

 

[展开全文]

x86体系结构

寄存器

objdump

MMU: 与cpu一起,把虚拟内存地址转换为物理内存地址 

段页机制是x86 MMU硬件设计时固定好的(虚拟[逻辑]地址->线性地址->物理地址),其中段机制是必选的,分页机制是可选。

操作系统如何应对硬件提供的这种机制(一些系统上不支持段机制, 如arm)。大多数操作系统绕过了段机制,只实现了分页机制。

GDT(全局描述符表): 只在启动时用

LDT(局部描述符表)

IDT(中断描述符表)

保护模式:段寄存器存放索引(选择符)

提供了四个特权级,0表示最高级,对应内核态;3表示最低级,对应用户态。

 

linux如何处理段机制?

将段基地址设置为0,启动时用到了GDT,启动之后就不会再用到段机制。

分页机制

虚拟地址=逻辑地址=线性地址

线性地址空间划分为若干个大小相等的页(page)

物理地址空间划分成与页大小相等的若干存储块 (page frame)

页的大小谁确定?

硬件设计人员与OS设计人员协商确定的,x86有4K、2M页等

页表是把线性地址映射到物理地址的一种数据结构,包含物理页面基地址、页的属性

4K的页,物理页面基地址需要20位表示,(4G/4K)

一级页表

二级页表

页目录、页表放在物理内存

页高速缓存(TLB)

三级页表

GCC手册

linux可执行文件ELF, ld从0x8000000开始安排程序代码段

i386体系结构

[展开全文]

Posix标准

GCC手册

GNU | GPL

订阅邮件列表

源码目录:/usr/src/kernel, 如果没有目录为空,需要执行:yum install kernel-devel;

头文件目录:/usr/src/kernels/3.10.0-514.2.2.el7.x86_64/include/linux

用户态头文件目录:/usr/include?

Makefile

kdebug | kdb | kgdb 

insmod | lsmod | rmmod

demsg

 

 

[展开全文]

进程调度算法:和管理中的考虑是一样的

 

时间片轮转调度算法:平均主义、公平

优先权调度算法:vip。非抢占:除非是我主动放弃CPU,否则你不能抢占。抢占:优先级高,把你从CPU上拉下来。

多级反馈队列调度: 时间片+优先权的结合?

实时调度:

提高交互式进程的优先级:ps看的时候TTY是?的是后台进程。

调度时机: {

sched.c

sched.h

schedule()-调度函数

为什么在这些时机返回?->调度一定是发生在内核态

}

2.4 {

need_resched:通知系统CPU已经空闲,是否真的发生调度有很多因素决定,并不是立马调度。

工程实践中的具体问题:时间片大小、优先级

基于大原则来改进

goodness(描述进程,描述进程地址空间)

内核代码是一个公共区(就绪队列)-会有很多锁

switch_to(prev,next,prev)-嵌入式汇编,放在/arch下

edsionte-2.6的进程调度分析

}

 

上下文指的是CPU的运行环境

 

fork()之后父进程执行还是子进程-不确定

fork()两个子进程-兄弟/父子孙

[展开全文]

OS是对硬件管理

进程概念源于对CPU的管理(管理者的角度)

 

这里讨论的是如何去管理系统数据段-我在这个阶段学的是什么东西?

为什么要引入进程的状态:进程诞生后就是一个活物,一个活物每一刻是不一样的。从生存到死亡这样一个生命历程里怎么去管理它?对一个连续的事情抓住它的点-用状态来描述它。

进程什么时候运行不是你控制的,是调度程序控制的(调度程序也要有一定规则)。

三种基本状态-其他OS衍生的状态是根据三种基本状态衍生来得。

父进程和子进程有各自的地址空间。

Linux-task_struct->这样的数据结构被叫做进程控制块PCB(process control block)-PCB是进程存在和运行的惟一标志。

sched.h

kernel coding style

进程控制块-信息分类

如果是我自己去设计,去描述进程;我怎么描述?

把人和进程对应起来。把进程学活,技术这个东西一定要搞活了。思维活了,很多信息就关联起来了。OS的复杂就复杂在各种关系。

 

上下文环境:各种寄存器。进程执行过程中被中断了或者发生调度了,要把上下文保存下来,把各种寄存器信息压栈。把它和我们生活环境联系起来。

 

2.4:8个状态(应对变中的不变-3个基本状态)

状态的转化和进程调度密切相关

你怎么样去描述一个进程的状态?

写应用程序代码像内核代码学习-用了长整型,设计目标是想用位操作。逻辑运算和算数运算间肯定逻辑运算快。

看源码-找到切入点-不要找难的,要找简单的。把层次关系理清楚,搞清楚为啥要形成这个代码才有意义。找到变的规律在什么地方。

通过位图来管理pid

UID、GID-权限管理(安全)

task_struct-人类的虚拟化描述,用代码来演戏。

PCB放在什么地方(空间存储的问题):在内核空间的数据段存放

性能问题:进程访问的问题,栈是从高地址到低地址。栈从下到上访问,PCB从下到上访问,内核栈和PCB要是碰上了也是中间给碰上了,公用一段内存空间。

代码设计上并不是那么简单,一定是要讲时效的。

系统多进程怎么组织(组织关系的问题)

 

cd /proc

OS启动时候这个目录不存在,cd或者执行ps命令的时候,这个文件系统就产生了。

虚(伪)文件系统->存放内核执行过程中所有有关进程的信息。给每个进程的进程号建了目录(每个目录对应一个pid)->为什么要以文件系统的方式来组织数据呢? 一般怎么样才能把内存的数据读出来呢?->写代码读出/用文件的方式来组织的时候,可以直接用查看文件的方式查看它。(coredump)

ps很多信息都是从/proc下面捞的

 

cd /proc

cat filesystems

 

如何快速地通过pid找到进程:哈希-不同的组织方式是为了管理的方便。

 

等待队列(include/linux/wait.h)

http://edsionte.com/techblog/

 

 

[展开全文]

段机制的引入->解决由16位地址能访问到20位地址的问题。后来为了兼容,段机制就延续下来了。-从用户的角度

保护模式->保护操作系统在自己的地址空间里/多任务系统-每一个进程在自己的地址空间。

分页机制->为了虚拟内存管理-对程序员来说是感觉不到的

 

在页里面才控制读写权限

段的保护主要是特权级的保护,而不是读写的保护-在硬件层支持(保护模式在段这一层)

程序报的段错误是指针出现问题。

 

保护模式真正含义

 

一般系统LDT不用,GDT用于启动过程,启动后,GDT也不用了,IDT在整个系统执行过程中一直在用。整个系统运行时,每个设备驱动都对应一个中断,需要在IDT中去注册。IDT是一个动态分配和回收的过程。

 

逻辑上段长为4G,其实地址为0。主要是为了绕过段机制,没有实际含义。真正给用户态空间为0-3G,内核为3-4G

 

页转换的时候用的是TLB,OS不管它

 

系统初始化:没有进程,所有硬件-时钟、内存都要初始化。初始化就是定义了一堆数据结构要给初值,要是硬件的话给寄存器也设初值,给表都填初值。

页表在什么时候被创建:进程起来以后->缺页机制-往内存装的时候就要建立页表。

 

kernel API

{

内核开辟了一块Public的地方,导出的这些函数是有限的,这些函数专门给模块调用,写内核模块时可以调用这些函数。

模块和内核通过内核函数形成衔接关系。

}

 

64位系统中的分页-对64位系统不同体系架构的分页级别是不一样的-ia64是3级,x86_64是4级,...现在Linux分页已经变成一个四级分页。

64位体系和32位改变大吗?-arch目录下代码都要改变,不变的是和体系结构无关的代码。

[展开全文]

虚拟内存管理的硬件机制

内存寻址的演变

段机制

分页机制

Linux中的分页机制

Linux中的汇编语言

Linux系统地址映射示例

 

P9

 

看代码一定要知道原理、模板

/arch/x86/include/asm-于汇编相关的代码

.segment.h-和体系结构相关的代码

 

4位-硬编码绝地地址,程序员没有被解放

16位-段的引入是为了扩大寻址空间

24位-引入保护模式

32位-解放了软件工程师

 

IA32寄存器简介

 

用于分页机制的控制寄存器

CR0最低位:实模式->保护模式

CR0最高位:支持分页机制(允许分页)

CR0最高位和最低位置一:支持分页机制

 

objdump -d [executable file]

 

intel开发手册(硬件)

 

地址之间的转换-保护模式下的寻址 //分段和分页一定要有硬件的支持-MMU机制

 

段机制

-三个方面:段基址、界限、保护属性

-虚拟-线性地址的装换

 

段描述符表:段表->段地址转换到线性地址

端描述符的一般格式:...

保护模式下的其他描述符表简介

 

保护模式下段寄存器中存放什么->存放索引或叫段号

RPL->出于安全性考虑(访问者、被访问者)

保护模式提供了四个特权级,用0~3四个数字表示

多任务的情况下,保护内存地址的访问

TI-全局/局部

 

Linux绕过了段机制->基地址=0,启动时采用全局描述符表

 

为什么进行分页? - 书如果一行、一字来管理?内存如果用字节来管理?

 

分页机制-页

-将线性地址空间划分为若干大小相等的片,称为页(Page)

-物理地址空间分成与页大小相等的若干存储块,称为(物理)块或页面(Page Frame)

-页的大小应该为多少?由谁确定?

 

分页机制-页表

分页机制-页表项结构

分页机制-两级页表

分页机制-线性地址结构

分页机制-硬件保护机制

分页机制-线性地址到物理地址的转换

 

objdump -d [file]

 

二级页表需要多次读取内存的,需要加页面高速缓存(TLB)。为什么需要二级页表?

Linux的3级页表

 

Linux中的C语言和汇编语言

-GNU的C语言

http://www.faqs.org/docs/learnc/

-AT&T的汇编:参见书

-GCC嵌入式汇编

 

Linux内核情景分析

 

P45

[展开全文]

认识操作系统

.从程序执行看

.从设计者角度看(管理的角度/服务的角度)

计算机的MBA

操作系统的定义

操作系统的组成

操作系统的发展

.硬件发展/软件发展

.讲究效率的单模块操作系统

.追求简洁的微内核操作系统(Mach)

 

开放源代码的Unix/Linux操作系统

。诞生于学生之手

。成长于Internet

。壮大于自由而开放的文化

 

用户态进程?-穿衣服和设计衣服

 

Linux得以流行的原因之一——遵循POSIX标准

Linux的肥沃土壤——GNU

GPL——开源软件的法律

Linux系统或发布版

开放与协作的开发模式

Linux内核

Linux内核的技术特点

整个系统的核心——内核

和用户态程序有什么区别?

Linux内核版本树

Linux内核源代码

。内核源代码结构

Linux内核源代码分析工具

Linux内核模块编程入门

insmod

dmesg

lsmod

rmmod

 

新手邮件列表

 

Linux内核中链表的实现及应用

 

/usr/src/linux-header-3.2.0-23

-./include/linux(编译程序的时候在这个位置下找文件)

vim+ctext

POSIX标准/gcc手册

[展开全文]

引言:

为什么要讲链表

Data structure two key points->store and organization

 

struct my_list {

    void *mydata; //可以代表任意的数据类型

    struct my_list *next;

    struct my_list *prev;

}

/usr/src/include/list.h

内核链表之插入

前面加双下划线为内核内部函数,如果不export,编写的模块无法使用该代码。

代码简单,设计思想不简单。

用户态下使用->LIST_POSITON1(2)=0

通常是通过结构体位置来查找字段,现在是通过字段来找结构体位置->知道儿子的位置要找父亲

内存地址编址是以字节编址的

内存地址编址以字节来编址

 

我们刚才一路走来,发现其实内核并不是我们想象的那么难,只是我们感悟其思想,赏析其源码,定能深入内核!内核所用的C语言也不是我们想象的那么难懂,也是我们平时所用到的C语言而已。

通过这样的讲解希望大家在平时要注意这些我们不屑一顾的数据结构,因为很多计算机科学问题最终的实现都会落在这些数据结构上。

 

19页例子

[展开全文]

在线检索工具:

lxr.linux.no

动态可加载内核模块:

LKM

[展开全文]

链表:链表是更本的数据结构,双向链表可以退化为队列和堆栈、图、树

选择双向循环链表,(如果我做的话我会怎么做?)

内核链表之定义:

为什么没有数据域?体现了抽象的观点,更加灵活

定义了链表头的结构体,就可以定义链表的数据结构

这样隐藏了链表的指针性质

内核链表的声明和初始化:采取大量的宏操作

初始化:使得头尾指向自己

 

链表的插入和删除:

如果是普通的函数

需要对原前驱、原头、现在的头的所有pre与next进行更新而且保证不在更新之前丢失地址

而且分头插尾插入,不利于对用户封装

链表的遍历:

正向遍历

  逆向遍历,从结构体的成员,找结构体的起始位置

(char*)ptr取得绝对地址 

(unsigned int)也即是size_t类型,代表相对地址

 

安全删除

因为释放的是指针指向的内存,而不是指针

 

 

[展开全文]

动态可加载内核模块 LKM

[展开全文]

第一章:老师在使用ubuntu讲解的时候,源码位置在/usr/src下,但是我本地是centos(linode),找了一下,发现在/usr/src/kernels/3.10.0-123.20.1.el7.x86_64.debug 下

[展开全文]

hello.c

hello.mod.c

hello.o

modules.order

hello.ko

hello.mod.o

Makefile

Module.symvers

[展开全文]

插入模块:insmod

日志文件:demesg

列出所有模块:lsmod

卸载模块:rmmod


[展开全文]

posix标准   GCC   手册

[展开全文]

软连接可以跨文件系统

跨分区

互联网http协议


super block

整个文件系统,已安装的文件系统

执行过程中

cat filesystem

fs.h

inode

directory detry

file

用户打开文件表,系统打开文件表

用户打开文件表从stdin3...

struct_file


fs_struct 进程与文件系统关系



[展开全文]

授课老师

西安邮电大学教授

学员动态

QQ客服: 810476411

QQ咨询: 810476411

QQ吐槽: 810476411

服务时间: 9:00 - 21:00

刘老师: 18516031455

微信公众号:开源力量