作者:朱克锋
转载请注明出处:http://blog.csdn.net/linux_zkf
从这篇文章开始我将正式开始分析学习linux,大家一起努力。
Linux0.11的启动部分在boot目录中,是汇编语言描述的,包括bootsect.s、setup.s、head.s三个文件
大家都知道,所谓的操作系统就是一个软件而已,计算机的运行离不开这个软件,在计算机启动之前,计算机内存中什么东西都没有,CPU是无法运行硬盘上的程序的(逻辑电路就这样设计的,没有办法啊),怎么办呢?对,把软件搞到内存中就行了。这就要用到一个被称为BIOS的东西,什么是BIOS这里不做讨论,简要做一个说明吧
BIOS程序是被固化在计算机主板上的一块ROM芯片里的,BIOS会把需要的软件加载到内存,BIOS的入口程序在0xFFFF0这个位置,计算机硬件设计在加电的时候让CPU从这个位置执行,OK,这样就能启动BIOS,加载linux的启动程序了,具体的BIOS相关的东西如果读者感兴趣请自己查找资料研究学习。
下面开始介绍如何加载操作系统,从启动到加载完成要经过这样的过程:
BIOS |
Bootsec |
Setup |
Head |
system->main |
对于linux0.11来说,加载分三个阶段:1,BIOS加载bootsec;2,bootsec加载setup;3,bootsec加载system
先看看bootsec是如何加载的,在设计中计算机会让CPU收到一个 int 19h的中断,进而找到中断服务程序,这个中断服务程序是BIOS的部分,作用就是把硬盘的第一个扇区的512个字节加载到内存,OK,到此BIOS已经把bootsec加载到计算机内存了,下面就是靠这个bootsec把剩余代码加到内存,要把后两部分程序加载到内存适当的位置,bootsec首先要对计算机内存做一些规划,如何规划内存呢?
计算机在实模式下寻址范围是1M,为了规划内存,bootsec中设计的一些代码:
SETUPLEN = 4 ! setup程序的扇区数
BOOTSEG = 0x07c0 ! bootsec的原始地址
INITSEG = 0x9000 ! 将要移动的新位置
SETUPSEG = 0x9020 ! setup 被加载到的位置
SYSSEG = 0x1000 ! system 加载到的位置
ENDSEG = SYSSEG + SYSSIZE ! system 加载到的结束位置
具体含义我已经注释了,就不再重复了。
BIOS把bootsec程序加载到内存之后,接下来bootsec开始执行,首先要做的就是把自己移到0x90000这个位置INITSEG
entry start
start:
mov ax,#BOOTSEG
mov ds,ax
mov ax,#INITSEG
mov es,ax
mov cx,#256
sub si,si
sub di,di
rep
movw
然后接着原来的位置继续执行,这就是下面这几行代码的功劳
jmpi go,INITSEG
go: mov ax,cs
下面就开始加载setup部分,和前面一样,加载setup也需要BIOS的中断服务程序
代码如下所示
load_setup:
mov dx,#0x0000 ! drive 0, head 0
mov cx,#0x0002 ! sector 2, track 0
mov bx,#0x0200 ! address = 512, in INITSEG
mov ax,#0x0200+SETUPLEN ! service 2, nr of sectors
int 0x13 ! read it
jnc ok_load_setup ! ok - continue
mov dx,#0x0000
mov ax,#0x0000 ! reset the diskette
int 0x13
j load_setup
ok_load_setup:
加载setup之后就要加载system了,这次加载和加载setup一样,不过内容的数据量大了许多这部分加载又下面这段代码完成:
sread: .word 1+SETUPLEN ! sectors read of current track
head: .word 0 ! current head
track: .word 0 ! current track
read_it:
mov ax,es
test ax,#0x0fff
die: jne die ! es must be at 64kB boundary
xor bx,bx ! bx is starting address within segment
rp_read:
mov ax,es
cmp ax,#ENDSEG ! have we loaded all yet?
jb ok1_read
ret
ok1_read:
seg cs
mov ax,sectors
sub ax,sread
mov cx,ax
shl cx,#9
add cx,bx
jnc ok2_read
je ok2_read
xor ax,ax
sub ax,bx
shr ax,#9
ok2_read:
call read_track
mov cx,ax
add ax,sread
seg cs
cmp ax,sectors
jne ok3_read
mov ax,#1
sub ax,head
jne ok4_read
inc track
ok4_read:
mov head,ax
xor ax,ax
ok3_read:
mov sread,ax
shl cx,#9
add bx,cx
jnc rp_read
mov ax,es
add ax,#0x1000
mov es,ax
xor bx,bx
jmp rp_read
read_track:
push ax
push bx
push cx
push dx
mov dx,track
mov cx,sread
inc cx
mov ch,dl
mov dx,head
mov dh,dl
mov dl,#0
and dx,#0x0100
mov ah,#2
int 0x13
jc bad_rt
pop dx
pop cx
pop bx
pop ax
ret
bad_rt: mov ax,#0
mov dx,#0
int 0x13
pop dx
pop cx
pop bx
pop ax
jmp read_track
OK,到此为止,所有程序都已经加载到内存,bootsec任务就已经完成了,接下来就要把控制权交给setup了,就是这行代码!!!
jmpi 0,SETUPSEG
注:
加载bootsec和setup过程本质一样,但是还是有很大区别的:
1)Int 19h中断向量所指的加载服务程序是BIOS执行的而Int 13h加载服务程序是linux操作系统自身的代码bootsec执行的
2)Int 19h只是把硬盘的第一个扇区的代码加载到固定的位置(ox7C00),而Int 13h可以根据不同的参数把指定扇区的代码加在到内存的指定位置
OK,下篇文章将接着jmpi 0,SETUPSEG继续研究学习linux。