linux引导程序剖析(二)

为什么不一开始就把内核代码移动到0x0000处,是因为,在
setup.s程序中,我们需要利用BIOS提供的中断功能来加载
一些系统参数。而BIOS的中断向量表一开始存放在内存开始的
地方。
INITSEG  = 0x9000 ! we move boot here - out of the way
SYSSEG   = 0x1000 ! system loaded at 0x10000 (65536).
SETUPSEG = 0x9020 ! this is the current segment
.globl begtext, begdata, begbss, endtext, enddata, endbss
.text
begtext:
.data
begdata:
.bss
begbss:
.text
entry start
start:
将光标的信息利用BIOS中断读入从0x9000开始的2个字节
mov ax,#INITSEG ! this is done in bootsect already, but...
mov ds,ax
mov ah,#0x03 ! read cursor pos
xor bh,bh
int 0x10  ! save it in known place, con_init fetches
mov [0],dx  ! it from 0x90000.
! Get memory size (extended mem, kB)
将内存大小利用BIOS中断读入0x9002开始的2个字节
mov ah,#0x88
int 0x15
mov [2],ax
! Get video-card data:
利用BIOS中断取得video card的信息,并存入0x9004和0x9006
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
利用BIOS中断取得VGA的配置参数,存入0x9008,0x900A和0x900C
mov ah,#0x12
mov bl,#0x10
int 0x10
mov [8],ax
mov [10],bx
mov [12],cx
! Get hd0 data
利用BIOS中断,取得第一个硬盘的参数
第一个硬盘的参数表信息,正好是中断向量
0x41的向量值,即[4 * 0x41]
mov ax,#0x0000
mov ds,ax
lds si,[4*0x41]
mov ax,#INITSEG
mov es,ax
mov di,#0x0080
mov cx,#0x10
rep
movsb
! Get hd1 data
尝试取得第二个硬盘参数
第二个硬盘的参数表信息,正好是中断向量
0x46的向量值,即[4 * 0x46]
mov ax,#0x0000
mov ds,ax
lds si,[4*0x46]
mov ax,#INITSEG
mov es,ax
mov di,#0x0090
mov cx,#0x10
rep
movsb
检查第二个硬盘是否存在
! Check that there IS a hd1 :-)
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:
! now we want to move to protected mode ...
cli   ! no interrupts allowed !
! first we move the system to it's rightful place
将内核代码移动到内存的开始地址,0x0000
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
! then we load the segment descriptors
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
! that was painless, now we enable A20
开启A20地址线,为了能访问1M的地址空间。
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
重新设置8259A中断向量
mov al,#0x11  ! initialization sequence
out #0x20,al  ! send it to 8259A-1
.word 0x00eb,0x00eb  ! jmp $+2, jmp $+2
out #0xA0,al  ! and to 8259A-2
.word 0x00eb,0x00eb
mov al,#0x20  ! start of hardware int's (0x20)
out #0x21,al
.word 0x00eb,0x00eb
mov al,#0x28  ! start of hardware int's 2 (0x28)
out #0xA1,al
.word 0x00eb,0x00eb
mov al,#0x04  ! 8259-1 is master
out #0x21,al
.word 0x00eb,0x00eb
mov al,#0x02  ! 8259-2 is slave
out #0xA1,al
.word 0x00eb,0x00eb
mov al,#0x01  ! 8086 mode for both
out #0x21,al
.word 0x00eb,0x00eb
out #0xA1,al
.word 0x00eb,0x00eb
mov al,#0xFF  ! mask off all interrupts for now
out #0x21,al
.word 0x00eb,0x00eb
out #0xA1,al
进入保护模式
mov ax,#0x0001 ! protected mode (PE) bit
lmsw ax  ! This is it!
跳转到代码段中执行,选择子8即全局描述附表第二个表项对应的段
jmpi 0,8  ! jmp offset 0 of segment 8 (cs)
empty_8042:
.word 0x00eb,0x00eb
in al,#0x64 ! 8042 status port
test al,#2  ! is input buffer full?
jnz empty_8042 ! yes - loop
ret
定义全局描述符表
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
定义加载中断描述符表的指令的操作数
idt_48:
.word 0   ! idt limit=0
.word 0,0   ! idt base=0L
定义加载全局描述符表的指令的操作数
gdt_48:
.word 0x800  ! gdt limit=2048, 256 GDT entries
.word 512+gdt,0x9 ! gdt base = 0X9xxxx

.text
endtext:
.data
enddata:
.bss
endbss:
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值