概要
一个计算机系统分为三层,最底层是硬件部分,中间是OS操作系统,最上层是APP。APP层要使用使用硬件资源,访问一些端口,必须经过操作系统,它为用户使用硬件资源提供了方便,比方说printf函数输出。大部分人都停留在立足于 操作系统去使用资源这一层境界,就像大部分人会弹钢琴,而不会揭开钢琴的盖子去搞清楚里面的构造和工作原理,自然就不会对钢琴有更深入,更接近本质的了解。
启动过程:
设置CPU为实模式—>
跳转到0XFFFF0开始执行(ROM-BIOS所在,主要动作是监测硬件和外设,初始化中断向量表)–>
将启动设备(软盘或者硬盘)的第一扇区512字节(也就是bootsec)读入内存的绝对地址0x7c00处并跳转到此处执行–>
执行到偏移地址为‘go’的地方 其结果是把刚才读入的512字节(256字)搬移到0x90000处,并跳转到0x90000且偏移‘go’的地方执行继续执行(因为不用重复执行搬过来的代码)—>
剩下的代码的作用就是继续从启动磁盘读入setup的四个扇区的代码到0x9000处偏移512字节的地方(即0x90200)且在屏幕上显示一段"Loading system…"字符,再调用read_it来读入system模块,调用返回后转入0x90200:0x0000执行setup.s
故事就得从引导扇区读入的512个字节开始说起:
引导扇区就是启动设备的第一个扇区
启动设备信息被设置在CMOS中
因此,硬盘的第一个扇区上存放着开机后执行的第一段我们可以控制的程序
操作系统的故事就从这里开始
BOOTSEG = 0X07C0
INITSEG = 0X9000
SETUPSEG = 0X9020
引导扇区的代码:bootsect.s
.globl begtext,begdata,begbss,endtext,enddata,endbss
.text//文本段
begtest:
.data //数据段
begdata:
.bss //为初始化数据段
begbss:
entry start //关键字entry告诉链接器“程序入口”
start;
mov ax,#BOOTSEG ;此条语句就是0x7c00处存放的语句
mov ds,ax ;将ds 段寄存器置为0×7C0;
mov ax,#INITSEG
mov es,ax ;将es 段寄存器置为0×9000;
mov cx,#256 ;为下面rep的次数做准备 256次
sub si,si ;源地址 ds:si = 0×07C0:0×0000
sub di,di ;目的地址 es:di = 0×9000:0×0000
rep movw ;重复执行 直到cx=0
;移动一个字
;将DS:SI的内容复制至ES:DI ,是复制过去。
;将0x07c0:0x0000处的256个字(512字节)移动到0x9000:0x0000,
jmpi go , INITSEG ;间接跳转,INITSEG-->CS,go-->IP go就是上面这段代码的偏移量
==============================================================================
--------- 前面那段代码的作用就是将0x07c0:0x0000处的256个字(512字节)移动到这里
--------- jmpi go , INITSEG这条语句已经帮我们跳过这段代码了,不会再重复执行一遍
--------- CS:IP现在在下面这一条语句上
go: mov ax,cs ;cs=0x9000 IP=go
mov ds,ax ;ds=0x9000
mov es,ax ;es=0x9000
mov ss,ax ;ss=0x9000
mov sp,#0xff00 ;一直到这儿都是为call做准备
load_setup: ;载入setup模块
mov dx,#0x0000 ;dh=磁头号 dl=驱动器号
mov cx,#0x0003 ;ch=柱面号00 cl=开始扇区03
mov bx,#0x0200 ;ex:bx=内存地址 200H=512B
mov ax,#0x0200+SETUPLEN ;ah=0x05 读磁盘 al=扇区数量
;SETUPLEN=4
int 0x013 ;读磁盘扇区BIOS的中断
jnc ok_load_setup ;加法没有进位,减法没有错位则转移
mov dx.#0x0000
mov ax,#0x0000
int 0x13
j load_setup; ;重读
OK_load_setup: ;载入setup模块
mov dl,#0x00
mov ax,#0x0800 ;ah=8获得磁盘参数
int 0x13
mov ch,#0x00
mov sectors,cx
mov ah,#0x03
xor bh,bh
int 0x10 ;读光标
mov cx,#24
mov bx,#0x0007 ;7是显示属性
mov bp,#msg1 ;存储要显示的消息在内存中的位置 偏移量
mov ax,#1301
int 0x10 ;显示字符到光标的位置
mov ax,#SYSSEG ;SYSSEG=0X1000
mov es,ax
call read_it ;读入system模块
jmpi 0,SETUPSEG ;转入0x9020:0x0000执行setup.s 查询最开始的宏定义,发现SETUPSEG果然是0x90200
read_it: mov ax,es
cmp ax,#ENDSEG
jb ok1_read ;ENGSEG=SYSSEG+SYSSIZE(SYSSIZE=0x8000)
ret
ok1_read:mov ax,sectors
sub ax,sread ;sread是当前磁道已读扇区数,ax未读扇区数
call read_track ;读磁道
bootsect.s中文件末尾有这一段
sectors: .word 0 ;磁道扇区数
msg1: .byte 13,10
.ascill "Loading system..."
.byte 13,10,13,10