本文共 3179 字,大约阅读时间需要 10 分钟。
一、功能描述
setup.s是一个操作系统加载程序,主要作用是 1)利用ROS BIOS中断读取机器系统数据,并将这些数据保存到0x90000开始的位置(覆盖了bootsect程序所在地方),所取得的参数和保留的内存位置如下表: 2)将setup程序将system模块从0x10000-0x8ffff整块向下移动到内存绝对地址0x00000处; 3)加载中断描述符表寄存器(idtr)和全局描述符表寄存器(gdtr),开启A20地址线,重新设置两个中断控制芯片8259A,将硬件中断号重新设置为0x20-0x2f; 4)最后设置CPU的控制寄存器CR0,进入32位保护模式运行,并跳转到system模块最前面的head.s程序。 二、代码注释 定义宏:INITSEG = 0x9000 ! we move boot here - out of the waySYSSEG = 0x1000 ! system loaded at 0x10000 (65536).SETUPSEG = 0x9020 ! this is the current segment
1) 利用ROS BIOS中断读取机器系统数据,并将这些数据保存到0x90000开始的位置
①使用BIOS中断0x10功能号ah=0x03,读光标位置,并保存在内存0x90000处(2字节)。 中断0x10功能号ah=0x03介绍: 输入:bh=页号 返回:ch=扫描开始线; cl=扫描结束线; dh=行号(0x00顶端); dl=列号(0x00最左边)mov ax,#INITSEG ! this is done in bootsect already, but...mov ds,ax !ds=0x9000,即即将保存光标的寄存器地址mov ah,#0x03 ! read cursor posxor bh,bh !第0页int 0x10 ! save it in known place, con_init fetchesmov [0],dx !将光标行和列号保存在ds x 10H + 0
②利用BIOS中断0x15功能号 ah=0x88 取系统所含扩展内存大小并保存在内存0x90002处
中断返回值: ax= 从0x100000 (1M)处开始的扩展内存大小(KB)。若出错则CF置位,ax = 出错码mov ah,#0x88int 0x15 !开启BIOS中断0x15 ah=0x88,ax=返回值mov [2],ax…
代码51-104同①②,均是使用BIOS中断功能获取相关数据,由于使用方式相似,很好理解,没什么内容,不再赘述。
2) 将setup程序将system模块从0x10000-0x8ffff整块向下移动到内存绝对地址0x00000处
! now we want to move to protected mode ... cli ! 禁用硬件中断! first we move the system to it's rightful place mov ax,#0x0000 cld ! cld是清方向标志位,使DF=0(使一次计数+1,如果DF=1,则一次计数-1)do_move: mov es,ax !目的地址es:di 初始0x0:0x0 add ax,#0x1000 cmp ax,#0x9000 ! 比较是否把最后一段代码移动完 jz end_move mov ds,ax !源地址ds:si,初始0x1000:0x0 sub di,di sub si,si ! di、si清零 mov cx,#0x8000 !计数器,移动0x8000(0x10000-0x8fff)字 rep movsw jmp do_move
我们需要将system模块从0x10000-0x8ffff移动到0x00000,那么初始(源)地址就是0x1000:0x0,目的初始地址是0x0:0x0,共移动0x8000(0x10000-0x8fff)字。那么我们使用rep循环操作去移动,每次移动完毕使用cmp语句去判断,是否移动到结尾(0x9000),其中源寄存器ds:si,目的寄存器es:di,这就是上面整段语句的含义。
3)加载中断描述符表寄存器(idtr)和全局描述符表寄存器(gdtr),开启A20地址线,重新设置两个中断控制芯片8259A,将硬件中断号重新设置为0x20-0x2f
①加载中断描述符表和全局描述符表end_move: mov ax,#SETUPSEG ! right, forgot this at first. didn't work :-) mov ds,ax lidt idt_48 ! load idt with 0,0 lgdt gdt_48 ! load gdt with whatever appropriate … 设置IDT表,这里先设置一个长度为0的空表 idt_48: .word 0 ! idt limit=0 .word 0,0 ! idt base=0L 设置GDT表gdt_48: .word 0x800 ! gdt limit=2048, 256 GDT entries .word 512+gdt,0x9 ! gdt base = 0X9xxxx
②开启A20地址线
call empty_8042 !测试8042状态寄存器,等待输入缓冲器空,只有当输入缓冲器空才可以对其执行写命令 mov al,#0xD1 ! command write 0xD1命令码——表示要写数据到8042的P2端口。P2端口的位1用于A20线的选通,数据要写到0x60口 out #0x64,al call empty_8042 !等待输入缓冲器空,看命令是否被接受 mov al,#0xDF ! A20 on out #0x60,al call empty_8042 !测试:若输入缓冲器为空,则表示A20线已选通
3) 最后设置CPU的控制寄存器CR0,进入32位保护模式运行,并跳转到system模块最前面的head.s程序.。