从linux0.11学习linux内核设计之程序加载

作者:朱克锋

转载请注明出处:http://blog.csdn.net/linux_zkf

 

从这篇文章开始我将正式开始分析学习linux,大家一起努力。

    Linux0.11的启动部分在boot目录中,是汇编语言描述的,包括bootsect.ssetup.shead.s三个文件

    大家都知道,所谓的操作系统就是一个软件而已,计算机的运行离不开这个软件,在计算机启动之前,计算机内存中什么东西都没有,CPU是无法运行硬盘上的程序的(逻辑电路就这样设计的,没有办法啊),怎么办呢?对,把软件搞到内存中就行了。这就要用到一个被称为BIOS的东西,什么是BIOS这里不做讨论,简要做一个说明吧

    BIOS程序是被固化在计算机主板上的一块ROM芯片里的,BIOS会把需要的软件加载到内存,BIOS的入口程序在0xFFFF0这个位置,计算机硬件设计在加电的时候让CPU从这个位置执行,OK,这样就能启动BIOS,加载linux的启动程序了,具体的BIOS相关的东西如果读者感兴趣请自己查找资料研究学习。

    下面开始介绍如何加载操作系统,从启动到加载完成要经过这样的过程:

 

BIOS

 

Bootsec

 

Setup

 

Head

 

system->main

 

 

 

    对于linux0.11来说,加载分三个阶段:1BIOS加载bootsec2bootsec加载setup3bootsec加载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 加载到的结束位置

 

    具体含义我已经注释了,就不再重复了。

    

         BIOSbootsec程序加载到内存之后,接下来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

 

注:

加载bootsecsetup过程本质一样,但是还是有很大区别的:

1Int 19h中断向量所指的加载服务程序是BIOS执行的而Int 13h加载服务程序是linux操作系统自身的代码bootsec执行的

 

2Int 19h只是把硬盘的第一个扇区的代码加载到固定的位置(ox7C00),而Int 13h可以根据不同的参数把指定扇区的代码加在到内存的指定位置

OK,下篇文章将接着jmpi 0,SETUPSEG继续研究学习linux。

你可能感兴趣的:(从linux0.11学习linux内核设计之程序加载)