您的位置:首页 > 编程语言

跟大师学习系统编程---操作系统加载(1)

2017-11-01 09:03 204 查看

简介

本文选取linux 0.11版本,描述操作系统是如何加载起来的。读者可以参考《linux内核完全注释》这本书,作者赵炯。本文主要选取这一主题最重要的方面进行说明。

当开发linux 0.11版本时,linus torwards自己的pc是80386的cpu。

当PC的电源打开后,80x86结构的CPU将自动进入实模式,并从地址0xFFFF0开始自动执行程序代码,这个地址通常是ROM-BIOS中的地址。

PC机的BIOS将执行某些系统的检测,并在物理地址0处开始初始化中断向量。此后,它将可启动设备的第一个扇区(磁盘引导扇区,512

字节)读入内存绝对地址0x7C00处,并跳转到这个地方。启动设备通常是软驱或是硬盘。

注意:这里有一个可启动设备的概念。相信大多数同学安装过windows操作系统,在BIOS设置菜单中可以设置可启动设备的优先顺序,假定系统中只有2种可启动设备,一块硬盘和一块光盘。并且设置成了硬盘优先,那么会出现一种状况:无法安装新的操作系统,因为始终启动硬盘中已经存在的操作系统。 此时,就需要进入BIOS设置菜单中,调整可启动设备优先顺序,优先启动光盘,保存配置重启后。BIOS检测到光盘中有可启动系统,则执行光盘中的程序,然后我们就可以安装操作系统了。

启动

.globl begtext, begdata, begbss, endtext, enddata, endbss
.text
begtext:
.data
begdata:
.bss
begbss:
.text

SETUPLEN = 4                ! nr of setup-sectors
BOOTSEG  = 0x07c0           ! original address of boot-sector
INITSEG  = 0x9000           ! we move boot here - out of the way
SETUPSEG = 0x9020           ! setup starts here
SYSSEG   = 0x1000           ! system loaded at 0x10000 (65536).
ENDSEG   = SYSSEG + SYSSIZE     ! where to stop loading

! ROOT_DEV: 0x000 - same type of floppy as boot.
!       0x301 - first partition on first drive etc
ROOT_DEV = 0x306


上述代码使用了8086的汇编语言,当前CPU工作在实模式。本段代码声明了数据段,代码段,BSS段(未初始化数据段)当前是共享的。上述那些常量并不占用内存,只在实际使用的时候替换对应的汇编指令?

需要说明的是:BOOTSEG = 0x07c0这个地址即OS与BIOS之间的约定,BIOS将操作系统的第一行代码加载到这个位置。不同的CPU架构,这个代码位置是不同的。

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


start开始即为操作系统的第1条可执行语句(mov ax,#BOOTSEG),其存放位置就是0x07c00。

这段代码的含义是将自身(512字节)拷贝到另外一个内存区(INITSEG)区域。即从内存(0x07c00–0x07e00)拷贝到(0x90000–0x90200)。然后跳转到0x90000对应的内存区去执行go标签对应的语句——即已经在另外一个内存区执行了指令mov ax, cs了。原来的内存区中只会执行前十行代码。

为什么需要将这512字节的代码和数据移动到另外一个地方,不移动行不行? 在后面的代码会看到,启动代码分成了3部分

bootsect.s

setup.s

system(剩余的的内核代码打包而成)

bootsect.s主要负责将setup.s和system加载进内存。考虑到中断向量表在0地址附近,在setup.s中还需要使用,所以system先加载到0x10000以后。并且linus 为system预留了0x80000字节空间(在当时看,这个空间足够了)。

当setup.s使用完中断向量(利用中断获取一些硬件配置参数)以后,则把system从0x10000~0x8ffff移动到0x00000~0x7fffff。因此,setup.s必须处于0x90000以后,否则setup.s执行system移动过程中会修改代码自身(假定setup.s放在0x00000~0x10000内存区)。

而且setup.s获取到的参数也必须保存在0x90000以后。否则其会修订system代码或者被system代码修改。

结论:bootsect.s移动到0x90000不是必须的,但setup.s移动到0x90000之后是必须的,linus torwards先移动了bootsect.s,然后让setup.s(0x90200)位于bootsect.s之后,最后setup.s获取的参数覆盖bootsect.s(0x90000~0x90200)的内存区。到达了上述要求。

加载setup.s到0x90000之外是必须的,且setup.s的数据存储在0x90000之外也是必须的。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息