内核引导启动程序.ppt

上传人:小飞机 文档编号:6243665 上传时间:2023-10-09 格式:PPT 页数:90 大小:584KB
返回 下载 相关 举报
内核引导启动程序.ppt_第1页
第1页 / 共90页
内核引导启动程序.ppt_第2页
第2页 / 共90页
内核引导启动程序.ppt_第3页
第3页 / 共90页
内核引导启动程序.ppt_第4页
第4页 / 共90页
内核引导启动程序.ppt_第5页
第5页 / 共90页
点击查看更多>>
资源描述

《内核引导启动程序.ppt》由会员分享,可在线阅读,更多相关《内核引导启动程序.ppt(90页珍藏版)》请在三一办公上搜索。

1、Linux操作系统内核分析,湘潭大学信息工程学院,讲课内容,bootsect.s程序分析setup.s程序分析head.s程序分析要求大家知道每个程序的作用!,操作系统引导,应用程序,操作系统,引导程序,BIOS,装载,装载,装载,?,?,磁盘结构,磁道:不同半径的同心圆称为磁道,扇区:512B,磁头:每个磁盘有两个面,每个面都有一个磁头,使用磁头号、柱面号、扇区号可唯一确定一个扇区,引导扇区,引导扇区是磁盘的第一个扇区(0磁头0磁道1扇区)。引导扇区中的程序是负责装载操作系统的程序,被成为自举程序或引导程序(bootstrap)。限制:自举程序的大小为512B,且最后两个字节必须为0 xaa

2、55。,开机过程,开机BIOS完成加电自检将引导盘的引导扇区读入到物理内存0 x7c00处检查0 x7c00+510开始的两个字节是否是0 xaa55跳到0 x7c00执行,P36,实模式内存寻址,+,物理地址,逻辑地址,基地址,64K,1M,段地址:段内偏移,bootsect程序,bootsect程序就是一个引导程序,负责把Linux操作系统内核从存储设备装入内存。用汇编语言编写,遵循Intel汇编语法,装载过程,0 x000000,0 x007c00,0 x010000,0 x090000,0 x090200,0 x100000,setup,bootsect,system,移动自己,mov

3、w指令:从ds:si移动一个字到es:di,然后根据标志寄存器中direct标志位,把si和di分别加2(d=0)或减2(d=1)。rep:重复执行后面的命令,重复次数放在cx寄存器中,每执行一次后面的命令则把cx中的值减1,直到cx为0。,移动自己,ds=0 x7c0;si=0;/0 x7c0:0es=0 x9000;di=0;/0 x9000:0cx=256;While(cx0)从ds:si移动一个字到es:di;if(d=0)si+=2;di+=2;else si-=2;di-=2;cx-;,移动自己,0 x7c0,0 x9000,go,go,Jumpi go,initseg,装载中断,

4、0 x13中断,2号功能类似于函数:int load(驱动器号,磁头号,磁道号,扇区号,要读扇区数量,读入内存地址),P39第67,装载setup,驱动器号:软盘磁头号:0磁头磁道号:0磁道开始扇区号:2(?)要读扇区数量:4读入内存地址:0:0 x90200,装载System,限制13中断一次只能读同一磁道上的扇区实模式下内存段大小不能超过64K解决方法一次读一个扇区读完后检测磁道是否读完,是则调整到下一个磁道;检测内存段是否满了,是则调整到下一个内存段。,装载System,未读入,已读入,Min(未读入扇区字节大小,内存段空余字节大小),装载System,磁盘读取规则:当0磁头的某个磁道读

5、完,下一次就读1磁头的相同磁道;当1磁头的某个磁道读完,下一次就读0磁头的下一个磁道。例如:0磁头0磁道,1磁头0磁道,0磁头1磁道,1磁头的1磁道。,装载system,1、if(已读大小=64K)then 段地址+=64K;已读大小=0;2、可读入的扇区数量=(64k-已读大小)/512B;3、if(可读入的扇区数量+当前扇区号=磁道扇区总量)then 可读入的扇区数量=磁道扇区总量-当前扇区号;4、读入5、if(磁道上无剩余扇区)then if(磁头号为0)then 磁头号=1;扇区号=1;else 磁头号=0;磁道号+;扇区号=1;,跳入setup,139行jmpi 0,SETUPSEG

6、,在37行定义为0 x9020,虚拟地址:0 x9020:0物理地址:0 x90200,setup的开始地址,讲课内容,bootsect.s程序分析setup.s程序分析head.s程序分析,程序功能,1-106行:获取并保存系统参数113-126行:移动system130-193行:进入保护模式,获得并保存系统参数,通过BIOS中断调用获得系统参数把获得的系统参数保存在0 x90000开始的内存块中,还记得0 x90000地址上的内容吗?,程序举例,38行读光标位置:0 x10中断0 x03功能:输入参数:ah:0 x03bh:页号输出参数:dh:行号dl:列号,mov ax,0 x9000

7、mov ds,axmov ah,0 x03xor bh,bhint 0 x10mov 0,dx,ds:,程序举例,获得内存大小:0 x15中断0 x88功能:输入参数:ah:0 x88输出参数:ax:扩展内存大小,单位KB,movah,#0 x88int0 x15mov2,ax,系统参数保存布局,程序功能,1-106行:获取并保存系统参数113-126行:移动system130-193行:进入保护模式,移动system,把System从0 x10000(64K)移到0 x00000为什么一开始不把system装载到物理内存0 x00000处?在bootsect和setup前一段程序中用到了实模

8、式下的中断调用,而这些中断的处理函数地址(中断向量表)调用被安排在物理内存0 x00000开始的内存中,移动system,0,0中断处理函数的地址,1中断处理函数的地址,4,中断向量表,移动system,0 x0000:0,0 x1000:0,0 x2000:0,0 x3000:0,0 x4000:0,0 x5000:0,0 x6000:0,0 x7000:0,0 x8000:0,0 x9000:0,es:di,ds:si,程序功能,1-106行:获取并保存系统参数113-126行:移动system130-193行:进入保护模式,保护模式寻址,寻址就是逻辑地址到物理地址的转换。在保护模式下有两

9、种内存管理机制:分段和分页,其中分页是可选的。三种不同地址逻辑地址:包含在机器语言指令中的地址,由一个段:段内偏移组成。线性地址:逻辑地址到物理地址变换间的中间层。物理地址:内存单元的地址。,P16第2.5节,保护模式寻址,分段,分页,分段,分段段描述符,保护模式下把内存分为多个段,每个段用一个描述符(数据结构)用来描述它的属性,包括段的开始地址、段长度、类型、访问权限等。段描述符由8个字节组成。,段描述符的结构,BASE 字段:指向段的基地址粒度标志G:段大小的单位。G=0时以字节为单位,否则以4096B为单位。LIMIT字段:段的大小,段的长度=段大小*1(G=0)或 段大小*4k(G=1

10、)系统标志S:系统段(S=0),用于存储内核数据;否则是普通代码段或数据段TYPE字段:描述段的类型DPL字段:描述符特权级别,表示为访问这个段而要求的CPU最小特权级。Present字段:段不在内存中(S=0),否则段在内存中。Linux总是把此标志设为1,因为Linux从来不把段交换到磁盘上去。D或B字段:段偏移量的地址是32位(D=1),否则是16位。AVL字段:Linux不使用保留字段,总是为0,BASE(0-15),LIMIT(0-15),BASE(16-23),TYPE,S,DPL,1,BASE(24-31),LIMIT(16-19),AVL,0,B/D,G,描述符表,保存有多个段

11、描述符的内存块(数组)叫做描述符表,分为全局描述符表(Global Descriptor Table,GDT)和局部描述符表(Local Descriptor Table,LDT)GDT中定义的内存段可以被所有进程使用,通常只定义一个;LDT中定义的内存段只被进程自己使用,通常每个进程一个LDT。GDT在内存中的地址存放在寄存器gdtr中,而当前进程使用的LDT的地址存放在寄存器ldtr中,段选择子,实模式中,段寄存器保存的是段的基地址保护模式中,段寄存器内容的含义发生了改变,它不再指向一个物理段的基地址了,而是一个段描述符的索引,通常把它称为段选择子13位索引,指定了放在GDT或LDT中的相

12、应段描述符TI指定了描述符是放在GDT(TI=0)中还是在LDT中(TI=1)两位RPL(Requestor Privilege Level)指定了进程的特权级别,RPL=DPL才能访问成功,Index,TI,RPL,0,2,3,1,15,分段的实现,给定一个逻辑地址检查段选择子中的TI标志,决定段描述符是保存在哪个描述符表中,并到相应的寄存器中取得描述符表的基地址把索引字段的值乘以8(段描述符的大小),加上描述符表的基地址,从而得到段描述符用段描述符中段的基地址加上逻辑地址中的偏移量,得到了线性地址,GDTR/LDTR,*,+,段描述符,+,线性地址,特权级别,IA32提供了03四个特权级别

13、,数字越小,级别越高高特权级可以访问低特权级和同一特权级,而低特权级不能随便访问高特权级,否则产生常规保护错误(GP)Linux只使用了其中的两个级别,即0级别,对应内核态;3级别,对应用户态,特权级别,Index,TI,RPL,0,2,3,1,15,BASE(0-15),LIMIT(0-15),BASE(16-23),TYPE,S,DPL,1,BASE(24-31),LIMIT(16-19),AVL,0,B/D,G,只有段选择子的RPL=段描述符中的DPL才允许访问该描述符所代表的内存段,一般只考虑CS选择子的RPL,要做的事,段机制由CPU自动实现,我们要做的事包括:定义好描述符表把描述符

14、表的基地址装入gdtr或ldtr使用正确的段选择子,gdt的定义,205行 gdt:.word0,0,0,0.word0 x07FF/8M.word0 x0000/基地址为0.word0 x9A00/可读可执行的代码段,dpl=0.word0 x00C0/粒度=4K.word0 x07FF/8M.word0 x0000/基地址为0.word0 x9200/可读写的数据段,dpl=0.word0 x00C0/粒度=4K,gdt的定义,BASE(0-15),LIMIT(0-15),BASE(16-23),TYPE,S,DPL,1,BASE(24-31),LIMIT(16-19),AVL,0,B/D

15、,G,0000000000000000,00000000,1010,1001,00000000,0000,1100,低字节,高字节,0 x0000,0 x07FF,0 x00C0,0 x9A00,装载gdtr,GDTR寄存器包括两部分:32位的物理地址,以及16位GDT大小(以字节为单位)设置好GDT之后,我们需要通过LGDT指令将设定的gdt的入口地址和gdt表的大小装入GDTR寄存器。可以使用LGDT指令来设置GDT。lgdt addr(保存gdt基地址和大小的地址),装载gdtr,134行:lgdt gdt_48222行:gdt_48:.word0 x800/gdt长度2kb,256项.

16、word512+gdt,0 x9/gdt的基地址,setup,进入保护模式,控制寄存器CR0PE:允许保护模式,PE=1切换到保护模式,PE,进入保护模式,191行 movax,#0 x0001lmsw ax/把ax的值装载到cr0中,执行完setup后的内存映像,跳到head中执行,jmpi 0,8,1,0,00,基地址为0,长度为8M,gpl为0的代码段,基地址为0,长度为8M,gpl为0的数据段,index,ti,rpl,段选择子0 x10指的是GDT中的数据段段选择子0 x08指的是GDT中的代码段,讲课内容,bootsect.s程序分析setup.s程序分析head.s程序分析,In

17、tel和AT&T语法,Intel语法操作符 目的操作数 源操作数AT&T语法操作符 源操作数 目的操作数寄存器前有%,程序功能,18-23行:设置数据段段选择子和堆栈24行:设置中断描述符表25行:设置全局描述符表135行:设置页表,启动分页并调用内核启动函数main,数据段段选择子,数据段段选择子包括ds、es、fs、gsmovl$0 x10,%eaxmov%ax,%dsmov%ax,%esmov%ax,%fsmov%ax,%gs,数据段段选择子,10,0,00,基地址为0,长度为8M,gpl为0的代码段,基地址为0,长度为8M,gpl为0的数据段,index,ti,rpl,代码段段选择子,

18、代码段段选择子包括cssetup中的最后一条语句已经将cs设置为8jmpi 0,8,设置GDT的效果,虚拟地址:0 x8:0 x5 或 0 x10:0 x100不论段选择子是什么,对应段的基地址都是0,所以线性地址=段的基地址+段内偏移=0+段内偏移=段内偏移未开启分页,所以段内偏移=线性地址=物理地址,程序功能,18-23行:设置数据段段选择子和堆栈24行:设置中断描述符表25行:设置全局描述符表135行:设置页表,启动分页并调用内核启动函数main,实模式下的中断处理,当中断发生时,用中断号检索中断表,得到中断处理程序的地址,然后进入中断处理程序进行处理,0号中断处理程序地址,1号中断处理

19、程序地址,2号中断处理程序地址,3号中断处理程序地址,0 x0,16位的段地址,16位的段内偏移,保护模式下的中断处理,用中断描述符来记录中断处理程序的属性,包括处理程序的地址,DPL等。每个描述符8个字节。,段选择子,段内偏移(0-15),000,D110,0,DPL,P,段内偏移(16-31),保留,中断描述符表,中断描述符表是中断描述符的集合,共256项。中断描述符表的基地址保存在寄存器idtr中,保护模式下中断处理,idtr,0号中断描述符,1号中断描述符,2号中断描述符,3号中断描述符,当中断发生时,用中断号和中断描述符表的基地址检索到中断描述符(描述符表的基地址+8*中断号),得到

20、中断处理程序的地址,然后进入中断处理程序进行处理,要做的事,中断处理由CPU自动实现,我们要做的事包括:定义好中断描述符表把中断描述符表的基地址装入idtr中,定义中断描述符表,在232行定义了一个256*8个字节的内存块作为中断描述符表,并且用0来初始化_idt:.fill 256,8,0/2k大小,分配256个8字节,并用0来初始化。,设置中断描述符,在78-91行设置这256个中断描述符ignor_int定义在150行,作用是打印一条消息“Unknown interrupt”,段选择子(0 x0008),段内偏移(ignor_int地址的底16位),000,1110,0,00,1,段内偏

21、移(ignor_int地址的高16位),保留,0 x8E00,设置中断描述符,ignore_int高16位,ignore_int低16位,edx,0 x08,0 x0,eax,ignore_int低16位,ignore_int低16位,edi,edi,装载中断描述符表基地址,第92行:lidt idt_descr第222行:idt_descr:.word 256*8-1/描述符表长度.long _idt/描述符表地址,程序功能,18-23行:设置数据段段选择子和堆栈24行:设置中断描述符表25行:设置全局描述符表135行:设置页表,启动分页并调用内核启动函数main,定义gdt,234行_gd

22、t:.quad 0 x0000000000000000/未用.quad 0 x00c09a0000000fff/16M.quad 0 x00c0920000000fff/16M.quad 0 x0000000000000000/未用.fill 252,8,0/预留共256项,256*8=2k大小,装载段描述符表基地址,106行lgdt gdt_descr227行gdt_descr:.word 256*8-1/GDT长度.long _gdt/GDT基地址,设置GDT,26行30行movl 0 x10,%eaxmov%ax,%dsmov%ax,%esmov%ax,%fsmov%ax,%gs,16,

23、64,看不见部分,程序功能,18-23行:设置数据段段选择子和堆栈24行:设置中断描述符表25行:设置全局描述符表135行:设置页表,启动分页并调用内核启动函数main,保护模式寻址启动分页,分段机制,分页机制,保护模式寻址启动分页,线性地址空间,物理内存,保护模式寻址启动分页,线性地址空间,物理内存,页目录,页表,CR3,P329,保护模式寻址启动分页,线性地址空间4G,0M,4M,8M,16M,页目录,1024项,index=线性地址/4M,保护模式寻址启动分页,线性地址空间,0M,4M,页目录,页表,1024项,4K,8K,12K,16K,index=(线性地址 mod 4M)/4K,分

24、页机制实现原理,把线性地址分成3部分directory(10位)table(10位)offset(12位)页目录的地址存放在寄存器CR3中线性地址的directory决定页目录中的目录项从页目录的目录项的基地址中找到页表的基地址线性地址的table决定页表中的目录项从页表的目录项的基地址中找到物理页的基地址线性地址的offset决定物理地址在物理页中的编移位置,CR3,+,页目录项,页表项,+,+,*,*,要做的事,分页机制由CPU自动实现,我们要做的事包括:定义好页目录表和页表设置页目录表和页表把页目录表的基地址装入CR3中启动分页,定义页目录和页表,第16行:_pg_dir:第114行:.

25、org 0 x1000 pg0:第117行:.org 0 x2000 pg1:第120行:.org 0 x3000 pg2:第123行:.org 0 x4000 pg3:,页表3,页表2,页表1,页表0,页目录,0 x0000,0 x1000,0 x2000,0 x3000,0 x4000,包含有部分head代码,启动分页,清0(198202行)stosl 把eax的值保存到ds:edi中,然后修改edi。(d=0时加4;否则减4)设置页目录(203206行)设置页表(207212行),设置页目录表和页表,第4095个4k,第0个4k(pg_dir),第1个4k(pg0),第2个4k(pg1)

26、,第3个4k(pg2),页目录,页表0,页表1,页表2,页表3,第4094个4k,第4093个4k,第4092个4k,物理地址16M,第4个4k(pg3),pg_dir,pg0,pg1,pg2,pg3,0 xFFF000,装载页目录地址,第213-214行xorl%eax,%eaxmovl%eax,%cr3,页目录地址在0 x0处,启动分页,控制寄存器CR0PG:PG=1允许分页,PE,PG,启动分页,第215-217行movl%cr0,%eax/把cr0的值保存到eaxorl$0 x80000000,%eax/eax最高位置1movl%eax,%cr0/把eax的值写入cr0,设置页表的效果

27、,第0个4k,第1个4k,第2个4k,第3个4k,第4个4k,pg_dir,pg0,pg1,pg2,pg3,线性地址,物理地址,0000000000,0000000000,000000000010,线性地址=物理地址,0 x2,0 x0,0 x400,设置页表的效果,第1024个4k,第1025个4k,第1026个4k,pg_dir,pg0,pg1,pg2,pg3,线性地址,物理地址,0000000001,0000000001,000000000010,线性地址=物理地址,0 x401002,0 x400000,0 x401000,Linux内核寻址,在分段时有x=seg(x)即 逻辑地址偏移

28、=线性地址在分页时有x=pg(x)即 线性地址=物理地址总体看有x=pg(seg(x)即 逻辑地址偏移=线性地址=物理地址,Linux内核寻址,自己编写的代码和数据,内核代码与数据,16M,进程,物理内存,16M,?,逻辑地址偏移=线性地址=物理地址,函数调用时的堆栈,void func(int a,int b).return;,b,a,retAddr,Linux模拟main函数调用,第136行:pushl$0pushl$0pushl$0pushl$L6pushl$_mainjmp setup_pagingsetup_paging:ret,0,0,0,L6的地址,main的地址,调用main的参数,调用main后的返回地址,void main(int argc,char*argv,char*env),程序执行后的内存布局,

展开阅读全文
相关资源
猜你喜欢
相关搜索
资源标签

当前位置:首页 > 生活休闲 > 在线阅读


备案号:宁ICP备20000045号-2

经营许可证:宁B2-20210002

宁公网安备 64010402000987号