1:功能
从bootset.s跳转到setup.s中执行,该代码作用如下:
1:获取初始化的基本参数
2:进入保护模式
1)将system模块从0x10000-0x8ffff整体移动到0X0地址处
2)启动保护模式
3)进入32位保护模式运行,并跳转到head.s
2:代码实现
2.1:获取初始化参数
! Get memory size (extended mem, kB)
//获取扩展内存并放人0X90002处
mov ah,#0x88
int 0x15
mov [2],ax
! Get video-card data:
//获取显示卡当前显示模式
mov ah,#0x0f
int 0x10
mov [4],bx ! bh = display page
mov [6],ax ! al = video mode, ah = window width
! check for EGA/VGA and some config parameters
//检查EGA/VGA并获取参数
mov ah,#0x12
mov bl,#0x10
int 0x10
mov [8],ax
mov [10],bx
mov [12],cx
! Get hd0 data
! Get hd1 data
//获取硬盘信息
2.2:进入保护模式
1)将system模块从0x10000-0x8ffff整体移动到0X0地址处
! first we move the system to it's rightful place
mov ax,#0x0000
cld ! 'direction'=0, movs moves forward
do_move:
mov es,ax ! destination segment
add ax,#0x1000
cmp ax,#0x9000
jz end_move
mov ds,ax ! source segment
sub di,di
sub si,si
mov cx,#0x8000
rep
movsw
jmp do_move
2)启动保护模式
开启保护模式后会进行32位寻址,计算机会启动另一套电路来解释执行指令。所以CS:IP不能再用CS<<4 + IP来工作了。因为此时CS如果是16位寄存器,那么CS<<4只能到20位,那边段基地址只能在1M以内,如果是32位寄存器,那么CS<<4就会移出36位,不符合32位寻址,所以需要新的寻址方式。为了支持新的寻址方式,就需要将A20地址先选通,并将CR0寄存器最后一位置1,完成后,内存寻址就会采用另一套电路----保护模式电路。
end_move:
mov ax,#SETUPSEG ! right, forgot this at first. didn't work :-)
mov ds,ax
//1)加载中断描述符表寄存器
lidt idt_48 ! load idt with 0,0
//2)加载全局描述符表寄存器
lgdt gdt_48 ! load gdt with whatever appropriate
! that was painless, now we enable A20
//3)开启A20地址线
call empty_8042
mov al,#0xD1 ! command write
out #0x64,al
call empty_8042
mov al,#0xDF ! A20 on
out #0x60,al
call empty_8042
//4)重新对中断编程
!Now we have to reprogram the interrupts
mov al,#0x11 ! initialization sequence
..............
3)进入32位保护模式运行,并跳转到head.s
保护模式启动后,第一条指令就是“jmpi 0,8”,那么此时就不应该是8<<4 + 0这样算出来的0X80了。
32位保护模式下的寻址是这样设计的:
用段寄存器作为索引在一个地址表里找到32位的基址,再和偏移寄存器中存放的32位数值相加,形成最终的地址放到地址总线上选定内存。
mov ax,#0x0001 ! protected mode (PE) bit //打开保护模式bit位
lmsw ax ! This is it! //加载机器状态字
jmpi 0,8 ! jmp offset 0 of segment 8 (cs) //跳转到基地址0处执行head.s
//2)加载全局描述符表寄存器
lgdt gdt_48 ! load gdt with whatev
//全局描述符由多个8字节长的描述符组成。这里给出3个描述符项
gdt:
//第一个描述符不用
.word 0,0,0,0 ! dummy
//第二个是操作系统内核代码段描述符
.word 0x07FF ! 8Mb - limit=2047 (2048*4096=8Mb)
.word 0x0000 ! base address=0
.word 0x9A00 ! code read/exec
.word 0x00C0 ! granularity=4096, 386
//第三个是操作系统内核数据段描述符
.word 0x07FF ! 8Mb - limit=2047 (2048*4096=8Mb)
.word 0x0000 ! base address=0
.word 0x9200 ! data read/write
.word 0x00C0 ! granularity=4096, 386
gdt_48:
.word 0x800 ! gdt limit=2048, 256 GDT entries
//0x0009<<16 + 0x0200 + gdt,0x90200恰好是setup开始的位置
.word 512+gdt,0x9 ! gdt base = 0X9xxxx
所以,根据上面的代码,最终形成如下的gdt表,根据该表,可以知道cs处的基地址为0x0处,IP也0,所以就跳到0地址处执行代码,即head.s代码中。