Linux0.11
"pull oneself up by one's bootstraps"?
开机上电……
1. BIOS
开机程序被刷入ROM中
- 开机自检:哔哔哔——
- BIOS中设定启动顺序
2. 引导
把控制权转交给排在第一位的存储设备,读取第一个512字节
1-446: 调用操作系统
447-510: 分区表
511-512: 主引导记录签名(0x55, 0xaa)
3. 硬盘启动
4. 操作系统
/boot/bootsect.s
筹备内存访问
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
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
mov ds,ax
mov es,ax
! put stack at 0x9ff00.
mov ss,ax
mov sp,#0xFF00 ! arbitrary value >>512
首先将ds寄存器设定为0x07c0,es寄存器设定为0x9000;cx设定为256,si和di清零,此时
DS = 0X7C00
ES = 0X9000
CX = 256
SI = 0, DI = 0
以上操作均为了下一步的rep movw
服务,它表示重复复制一个字(word 16bits=2Bytes)
- 重复复制cx次,即256次,总共复制512字节
- 从DS:SI复制到ES:DI,即从0x7c00复制到0x90000
接下来,执行jmpi go, INITSEG
,表示跳转到0x9000:go处执行指令,等价于
cs = 0x9000
ip = [go]
go标签表示bootsect.s编译成二进制文件bootsect后,go的内存地址偏移量,就是上面代码第24行的位置
下面执行go处的代码,将cs的内容赋值给ds,es和ss,然后sp设定为0xFF00
DS寄存器是数据段寄存器,512个字节从0x7c00移动到0x90000,所以DS改为指向0新000
SS寄存器是栈段寄存器,SP是栈顶指针,此时SS:SP指向0x9FF00
至此,操作系统初步规划了内存,为访问代码和数据设置了基址,把栈顶指针指向了远离代码的位置。
操作系统代码放入内存
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:
...
第一部分的代码解决了访问数据段、代码段和栈段的问题,接下来要将操作系统代码加载到内存:
首先将dx,cx,bx,ax依次赋值,作为中断程序的参数(通过寄存器传参),然后发起中断,实现从硬盘第2个扇区开始,把数据加载到0x90200处,一共加载了4个扇区(第2,3,4,5扇区)
之后的jnc表示如果复制成功,跳转到ok_load_setup,如果失败,就会重复执行复制代码……
下面是ok_load_setup主要代码
! 省略非主逻辑代码(包括输出字符串等)
ok_load_setup
...
mov ax,#SYSSEG
mov es,ax ! segment of 0x010000
call read_it
...
jmpi 0,SETUPSEG
其作用是把硬盘第6个扇区开始的240个扇区加载到内存0x10000处,然后指针跳转到0x90200处,即第2个扇区的开始位置
最终内存如下图:
下面将进入setup.s文件,未完待续……