linux011中setup.s文件分析

来源:互联网 发布:狼道seo 编辑:程序博客网 时间:2024/05/16 02:01
INITSEG = 0x9000 !原来bootsect所在的段SYSSEG  = 0x1000 !system所在的段SETUPSEG= 0x9020 !setup所在的段.globl begtext,begdata,begbss,endtext,enddata,endbss.textbegtext:.databegdata:.bssbegbss:.textentry startstart:mov ax,#INITSEG  !将ds设置成0x9000mov ds,ax        !mov ah,#0x03     !读取cursor pos.BIOS中断0x10读取光标功能号ah=0x03 !输入:bh = 页号 !返回:ch = 扫描开始线   cl=扫描结束线  ! dh = 行号(0x00是顶端) dl=列好(0x00是左边)xor bh,bh        !int 0x10         !mov [0],dx       !把光标位置信息存放在0x90000处,控制台初始化时来取! get memory size(extended mem kb)下面三句取扩展内存的大小值mov ah,#0x88     !调用中断0x15,功能号ah=0x88int 0x15         !返回:ax=从0x100000(1M)处开始的扩展内存大小 !出错则CF置位,ax=出错码mov [2],ax       !将扩展内存存储在0x90002处!get video-card data 下面这段用于取显卡当前显示功能号mov ah,#0x0f     !调用BIOS中断0x10,功能号ah=0x0f !返回:ah=字符列数 al=显示模式  bh=当前显示页int 0x10         !0x90004(1字)存放当前页,0x90006显示模式,0x90007字符列数mov [4],bx       !bh=display pagemov [6],ax       !al=video mode   ah=window width!check for VGA/EGA and some config parameters检查显示方式并取参数 !掉用BIOS中断0x10 !功能号:ah=0x12  bl=0x10mov ah,#0x12     !返回:bh=显示状态 (0x01-单色模式,I/O端口=0x3bx) !(0x00-彩色模式 I/O端口=0x3dx)mov bl,#0x10     !bl=安装的显示内存 !(0x00-64k,0x01-128k,0x02-192k,0x03-256k)int 0x10         !cx=显卡特性参数mov [8],ax       !???mov [10],bx      !0x9000A=安装显卡内存,0x9000B=显示状态(彩色/单色)mov [12],cx      !0x9000c=显卡特性参数!get hd0 data 取第一硬盘的信息。第一个硬盘的参数表的首地址是中断向量0x41的向量值!而!第二个硬盘的参数表紧接着第一个表的后面,中断向量0x46的向量值也指向这第二个硬盘的参数首地!址。表的长度是16个字节!下面两段程序分别复制BIOS有关两个硬盘的参数表,0x90080处存放第一个硬盘的表!0x90090存放第二个硬盘的表mov ax,#0x0000   !mov ds,ax        !lds si,[4*0x41]  !取中断向量0x41的值,也即hd0参数表的地址->ds:simov ax,#INITSEG  !mov es,ax        !mov di,#0x0080   !传输目的地址:0x9000:0x0080->es:dimov cx,#0x10     !共传输0x10字节rep              !movsb            !                 !mov ax,#0x0000   !mov ds,ax        !lds si,[4*0x46]  !mov ax,#INITSEG  !mov es,ax        !mov di,#0x0090   !mov cx,#0x10     !rep              !movsb            !!检查系统是否存在第二个硬盘,如果不存在则第二个硬盘表清零!利用BIOS中断调用0x13的取盘类型功能!功能号ah=0x15!输入dl=驱动器号(0x8X是硬盘,0x80第一个硬盘,0x81第二个)!输出:ah=类型码 00--没有这个盘  CF置位,01--软驱,没有change-line支持!02--软驱(或其他科移动设备),有change-line支持,03--硬盘mov ax,#0x01500  !mov dl,#0x81     !int 0x13         !jc no_disk1      !cmp ah,#3        !是硬盘吗?je is_disk1      !                 !no_disk1:            !mov ax,#INITSEG  !不存在则清零mov es,ax        !mov di,#0x0090   !mov cx,#0x10     !mov ax,#0x00     !rep              !stosb            !                 !is_disk1:            !cli            !关中断!首先将system模块移到正确位置.bootsect引导程序是将system读取到0x1000开始的位置!当时假设system最大长度不会超过0x80000(512k),也即末端不会超过内存地址0x90000,所以!bootsect将自己移动到0x90000开始的地方,并把setup加载到它的后面.下面程序是再把整个system!移动到0x0000位置,即把从0x10000到0x8ffff的内存数据块,整块的向内存低端移动了0x10000(64K)!的位置mov ax,#0x0000 !cld            !向前移动。设置复制方向do_move:             !mov es,ax      !目的地址 es:di  0x0000:0x0add ax,#0x1000 !cmp ax,#0x9000 !已经移动完成?jz end_move    !mov ds,ax      !源地址 ds:si  0x1000:0x0sub di,di      !sub,si,si      !mov cx,#0x8000 !移动0x8000字节rep            !movsw          !jmp do_move    !!lidt指令用于加载中断描述符表寄存器,它的操作数是6个字节,0-1是描述符表的长度值!(字节),2-5字节是描述符表的32位线性地址(首地址).中断描述符表中的每一个表项(8字节)!指出发生中断时需要调用的代码的信息,与中断向量有些相似,但包含更多的信息!lgdt指令用于加载全局描述符寄存器,其操作数格式与lidt指令相同。全局描述符表中的!每个描述符项(8字节)描述了保护模式下的数据和代码段的信息。包括段的最大长度限制,段的线性!基址(32位)段特权级,段是否在内存,读写许可以及其他一些保护模式运行的标志!end_move:mov ax,#SETUPSEG  !mov ds,ax         !ds指向本程序段lidt idt_48       !加载中断描述符寄存器idt_48是6字节操作数的位置.前2字节表示idt!限长,后4字节表示idt表所处的基地址。lgdt gdt_48       !加载全局描述符表寄存器                  !call empty_8042   !等待输入缓冲器空mov al,#0xD1      !只有当缓冲器为空时才可以对其写命令out 0x64,al       !??8042的p2端口.p2端口的位1用于A20线选通.数据要写到0x60端口call empty_8042   !等待输入缓冲器为空,看命令是否被接受mov al,#0xDF!A20 on,选通A20地址线的参数out #0x60,al      !call empty_8042   !输入缓冲器为空,表示A20线已经选通mov al,#0x11!0x11表示初始化命令开始,是ICW1命令字,表示边沿触发 多片级联 最out #0x20,al!后要发送ICW4命令。发送到8259主片!下面定义的两个字是直接使用机器码表示的两条相对跳转指令,起延时作用。!0xeb是直接近跳转指令的操作码,带1个字节的相对位移值。因此跳转范围是-127到127.CPU通过吧!这个相对位移值加到EIP寄存器中就形成一个新的有效地址,此时EIP指向下一条被执行的指令。执!行时所花费的cpu时钟周期是7-10个。0x00eb表示跳转值是0的一条指令,因此还时直接执行下一条!指令.这两条指令共可提供17-20个cpu时钟周期的延迟。另外每个空操作指令NOP的时钟周期是3个,!因此要达到相同的延迟效果就需要6-7个NOP指令!.word 0x00eb,0x00eb !jmp $+2,jmp$+2  $表示当前指令地址out #0xA0,al        !发送到8259从芯片.word 0x00eb,0x00eb !mov al,#0x20        !送主芯片ICW2命令字,起始中断号,要送奇地址out #0x21,al        !.word 0x00eb,0x00eb !mov al,#0x28        !送从芯片ICW2命令字,从芯片起始中断号out #0xA1,al        !.word 0x00eb,0x00eb !mov al,#0x04        !主芯片ICW3命令字,out #0x21,al        !.word 0x00eb,0x00eb !mov al,#0x02        !从芯片ICW3out #0xA1,al        !.word 0x00eb,0x00eb !mov al,#0x01        !主芯片ICW4out #0x21,al        !.word 0x00eb,0x00eb !out #0xA1,al        !从芯片ICW4命令字.word 0x00eb,0x0eb  !mov al,#0xff        !屏蔽主芯片所有中断请求out #0x21,al        !.word 0x00eb,0x00eb !out #0xA1,al        !屏蔽从片中断请求                    !mov ax,#0x0001      !保护模式比特位(PE)lmsw ax             !加载机器状态字jmpi 0,8            !跳转至cs段8,偏移0处!已经将system模块移动到0x00000开始地方,所以这里的偏移地址是0,这里的段值8已经是保护模式!下的段选择符了,用于选择描述符表和描述符表项以及所要求的特权级。段选择符长度为16位,!位0-1表示特权级,位2用于选择全局描述符表(0)还是局部描述符表(1),位3-15是描述符表项的!索引,指出选择第几项描述符。所以段选择符8(0b0000 0000 0000 1000)表示特权级0,使用全局描!!述符表第一项,该项指出代码的基地址为0,因此这里的跳转指令就会去执行system代码empty_8042:               !.word 0x00eb,0x00eb !in al,#0x64         ! 读AT键盘控制器状态寄存器test al,#2          !测试第二位,输入缓冲器满jnz empty_8042      !ret                 !!全局描述表开始处,描述符表由多个8字节长的描述符表组成。!这里给出了3个描述符项,第一个无用,但必须存在,第二个是系统代码段描述符,第三项是系统数!据段描述符gdt:                      !.word 0,0,0,0       !!这里在gdt表中偏移为0x08,加载代码段寄存器时,使用的是这个偏移值.word 0x07ff        !8M -limit=2047 .word 0x0000        !base address=0.word 0x9a00        !code read/exec.word 0x00C0        !粒度(granularity)=4096,386!这里在gdt中偏移值为0x10,加载数据段寄存器时使用这个偏移值.word 0x07FF        !8M limit.word 0x0000        !base address.word 0x9200        !data read/write.word 0x00C0        !granularity = 4096 386idt_48:                   !.word 0             ! idt  limit =0 .word 0,0           !idt base =0 gdt_48:                   !.word 0x800         !gdt limit=2048,256 GDT entries!全局表长度为2k字节,因每8字节组成一个段描述符项!所以共有256项.word 512+gdt,0x9   !gdt base = 0x9XXXX!4个字节构成的内存线性地址0x0009<<16+0x0200+gdt!也即0x90200+gdt.textendtext:.dataenddata:.bssendbss:


setup运行完成后的内存示意图:



1 0