⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 linux.txt

📁 一份精简的linux内核源代码
💻 TXT
📖 第 1 页 / 共 3 页
字号:
1.中断
当80X86启动时,ROM BIOS中的程序会在物理内存地址0X0000:0X0000处初始化并设置中断向量表,而各中断的默认中断服务程序则在BIOS中给出。
在BIOS执行初始化操作时,它设置了两个8259A芯片支持16个硬件中断向量和BIOS提供的中断号为0X10-0X1F的中断调用功能向量。对于实际没有使用的向量则填入零时的哑中断服务程序的地址。
对LINUX系统,除了在刚开始加载内核时需要用到BIOS提供的显示和磁盘读操作中断功能,在内核正常运行之前则会在SETUP.S中重新初始8259A芯片,并抛弃BIOS所提供的 功能,重新设置中断向量表。
当INTEL CPU运行在32位的保护模式下时,使用IDT(中断描述符表,除中断服务地址外,还有特权级和描述符等信息)来处理中断。
对于中断INT0--INT31(0X00--0X1F),由INTEL公司保留,称为异常,属于软中断。
LINUX系统中,将INT32--INT47(0X20--0X2F)对应于8259A中的IRQ0--IRQ15,将程序编程发出的系统调用中断设置为INT128(0X80),系统调用中断是用户程序使用操作系统资源的唯一界面接口。
初始化时,内核在HEAD.S中首先使用一个哑中断向量对IDT中的256个描述符进行默认设置(BOOT/HEAD.S,78)。这个哑中断向量指向一个默认的“无中断”处理过程(BOOT/HEAD.S,150)。内核在后续的初始化中,将重新置中断向量,通常,异常中段处理过程(INT0--INT31)都在KERNL/TRAPS.C,181。系统调用中断INT128在KERNEL/SCHED.C,385。
在设置中断描述符表IDT时,通过设置标志寄存器EFLAGS中的中断允许标志IF来屏蔽其它中断的干扰。
CLI  :复位标志寄存器EFLAGS中的中断允许标志IF,使得系统在执行CLI之后不会相应外部的中断。
STI  :使CPU能响应外部中断。


2.系统调用
用户程序通过调用INT128(INT0X80)中断,并在EAX寄存器中指定系统调用的功能号来使用内核资源,包括系统硬件资源。
通常系统调用使用函数调用的形式,其中寄存器EAX中存放着系统调用号,EBX、ECX、EDX中存放参数。返回值为负表示错误,0表示成功。出错时,错误的类型码被放在全局变量ERRNO中,通过调用PERROR()可以打印出出错信息。
处理系统能够调用的过程是是KERNEL/SYSTEM_CALL.S中的SYSTEM_CALL。
在LINUX内核中,每个系统调用都有唯一的一个系统调用功能号(INCLUDE/UNISTD.H,60)。如,WRITE()的系统调用红能号是4,定义为符号__NR_write。这些系统调用的功能号实际上对应于INCLUDE/LINUX/SYS.H中定义的系统调用处理程序指针数组表sys_call_table[]中的索引值。因此WRITE()系统调用的处理程序指针就位于该数组的项4处。
INCLUDE/UNISTD.H,133--183定义了4种系统调用宏函数(0参数,1参数,2参数,3参数),通过这些宏函数,用户程序可直接进行系统调用,实时上C函数中的函数调用系统调用的方式也是如此。

/*某一用户态进程执行系统调用时,堆栈中各寄存器的偏移位置*/
EAX		= 0x00 /* 这些为执行system_call时,中断处理程序手动压入堆栈的信息*/
EBX		= 0x04
ECX		= 0x08
EDX		= 0x0C
FS		= 0x10
ES		= 0x14
DS		= 0x18
EIP		= 0x1C /* 这些为用户态程序调用系统调用时自动压入堆栈的信息*/
CS		= 0x20
EFLAGS		= 0x24
OLDESP		= 0x28
OLDSS		= 0x2C

当一个内核态程序调用系统调用,执行完后直接返回;当一个用户态程序调用系统调用,执行完后将先进行信号处理然后再返回。

3.系统时间
初始化时,LINUX通过INIT/MAIN.C中的TIME_INIT()函数读取RT/CMOS RAM电路(存放时间)中的当前时间,并通过KERNEL/MKTIME.C中的KERNEL_MKTIME()函数转换成从1970年1月1日0:00开始的以秒为单位的时间(UNIX日历),并保存于全局变量STARTUP_TIME中,通过TIME()系统调用可读取STARTUP_TIME的值,超级用户可通过STIME()系统调用来修改该值。
通过将STARTUP_TIME(秒,从1970年1月1日0:00开始志开机为止)和JIFFIES(毫秒,从开机开始到现在)相加及为当前系统时间。
PC机的可编程定时芯片(INTEL 8254,每隔一段时间发出一个脉冲)的输出引脚被接在了中断控制芯片(8259A)的IRQ0(时钟中断请求)上,因此系统每过10毫秒就会收到一个时钟中断请求(IRQ0),我们称其为系统时钟周期,因此每过10毫秒,系统会调用一次时钟中断处理程序(TIMER_INTERRUPT,用于累加JIFFIES变量),然后调用C函数DO_TIMER作进一步的处理。
DO_TIMER()的参数CPL为被中断程序的段选择符中表当前代码特权级。若CPL=0表示进程运行在内核态时被中断,因此进程的内核态运行时间(STIME)增1;否则进程的用户态运行时间增1。
若某个定时器时间到(递减为0),则调用该定时器(软件,仅供内存使用,最多64个,在需要时动态创建,在到点时动态撤销,定时器的代码在SCHED.C,264--336)的处理程序,然后将当前进程运行时间片(一个进程在被切换之前所能持续运行的CPU时间,单位10毫秒)减1,若时间片仍大于0则退出DO_TIMER()继续运行当前进程;否则表示该进程已用完了此次使用CPU的时间片,此时如果当前进程工作在用户态,则DO_TIMER()会调用进程调度程序SCHEDULE()切换到其它进程中去,此时如果当前进程工作在内核态,则DO_TIMER()立即退出。


4.进程控制
LINUX中第一个进程是手工建立的,其它进程都是通过FORK()系统调用建立的。
内核通过进程表对进程进行管理,进程表项是一个TASK_STRUCT结构指针即PCB进程控制块(INCLUDE/LINUX/SCHED.H中)。
在系统初始化时,在第一次调用EXECVE()之前,系统创建的所有任务的EXECUTABLE都是0(即未打开任何执行文件)。
CPU的所有寄存器中的值、进程的状态及堆栈中的内容被称为该进程的上下文,当发生进程切换时,当前进程的上下文被保存在PCB中;当发生中断时,内核就在被中断进程的上下文中,在内核态下执行中断服务例程。
某一进程在内核态执行时,若需要等待某一资源,可通过调用sleep_on或interruptible_sleep_in()自愿放弃CPU使用权。此时,该进程处于"睡眠态",此时该进程才能被切换。在内核态下运行的进程不能被其它进程抢占,而且一个进程不能改变另一个进程的状态,内核在执行临界区代码时会禁止一切中断。

5.堆栈
linux中使用了4种堆栈。a.系统引导初始化是临时使用的堆栈。b.进入保护模式之后提供内核程序初始化使用的堆栈,位于内核代码地址空间固定位置。该堆栈也是后来任务0使用的用户态堆栈。在init/main.c中,在执行move_to_user_mode()把控制权移交给进程0之前,系统一直使用该堆栈,而在执行过move_to_user_mode()之后,main.c的代码被切换成进程0中执行。通过执行fork(),main.c中的init()将在进程1中执行,并使用进程1的堆栈。而main()本身则在被切换为进程0后,仍然继续使用该堆栈作为其用户态堆栈。(sched.c的user_stack[]数组)c.每个任务通过系统调用,执行内核程序时使用的堆栈(内核态堆栈),每个任务都有自己独立的内核态堆栈。当一个进程进入内核态运行时,就会使用其tss种给出的特权级0的堆栈指针tss.ss0,tss.esp0,即内核栈。d.任务的用户态堆栈,位于任务逻辑地址空间末端处。
用户态堆栈:0 代码 数据        堆栈 参数 环境变量 64mb
内核态堆栈:0 PCB   堆栈 1页
当进行特权级发生变化的控制权转移时,目的代码会使用新特权级的堆栈,而原特权级代码堆栈指针将保留在新堆栈中。
当一个进程从用户态转换为内核态时:首先,CPU会从当前进程的TSS中取得内核态的ss及esp,然后将当前用户态的SS及ESP压入内核堆栈,随后把eflags(标志寄存器)和cs,eip(返回地址)压入内核态堆栈中。
如果一个任务正在内核态运行,若此时响应中断,则只需压入eflags和cs,eip而无需压入ss,esp。
intel CPU先递减堆栈指针,然后再进行进出栈操作。

6.文件系统
linux引导启动时,默认使用的文件系统是根文件系统。其中包括一些配置文件和命令执行程序:
ect/目录主要含有一些系统配置文件
dev/含有设备特殊文件,用于使用文件操作语句操作设备
bin/存放系统执行程序,如sh,mkfs,fdisk
usr/存放库函数,手册和其它一些文件
user/bin常用命令
var/用于存放系统运行时可变的数据或日志
存放文件系统的设备就是文件系统设备。如windows2000的c盘就是文件系统设备,按一定规则窜坊文件就组成文件系统,如windows2000的ntfs或fat32。
当linux加载根文件系统时,会根据启动盘上引导扇区509,510字节处的一个字(ROOT_DEV)中的根文件系统设备号指定的设备中加载根文件系统,如c就会在c盘中加载。
make工具通过识别哪些文件被改过,从而决定哪些文件需要重新编译。
bootsects和setup.s为实地址模式需要as86来编译,head.s为需要GNUas来编译。
bootsect.s程序是磁盘引导块程序,编译后会驻留在磁盘的第一个扇区中。在PC加电ROM BIOS自检后,将被BIOS加载到内存0x7c00处并执行。
setup.s主要用于读取硬件配置,并把讷河模块system移动到适当位置。
head.s会被编译连接在system模块的最前部分,主要进行硬件设备的探测设置和内存管理页面的初始设置。

7.编译(p70认真看)
linux中经编译后的2进制文件格式:
执行头部分:目标文件的整体信息,如:代码和数据部分的长度,对应原文件的名称。内核使用这些参数把该文件加载到内存中执行;连接程序使用这些信息来连接各模块。
代码段部分:指令和数据。
数据段部分:指令和数据,含有已经被初始化的数据,总是被加载到可读写的内存总。

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -