一、功能描述
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 way
SYSSEG = 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 pos
xor bh,bh !第0页int 0x10 ! save it in known place, con_init fetches
mov [0],dx !将光标行和列号保存在ds x 10H + 0
②利用BIOS中断0x15功能号 ah=0x88 取系统所含扩展内存大小并保存在内存0x90002处
中断返回值: ax= 从0x100000 (1M)处开始的扩展内存大小(KB)。若出错则CF置位,ax = 出错码
mov ah,#0x88
int 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程序.。
手机扫一扫
移动阅读更方便
你可能感兴趣的文章