从linux0.11学习linux内核设计之程序加载
阅读原文时间:2021年04月20日阅读:1

作者:朱克锋

转载请注明出处: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。