title | date | comments | categories | tags | permalink | |||
---|---|---|---|---|---|---|---|---|
操作系统启动画面的背后bootsect.s
|
2020/2/15
|
true
|
|
|
3.1
|
1、图灵机
图灵机是A.C图灵在1936提出的。最开始的图灵机,只能做最简单的加法运算。
后来演变出来通用图灵机,是指计算机的控制器逻辑可以修改——即支持更多的运算指令。
后来冯诺依曼提出了存储程序思想:将程序和数据存放到计算机的存储器中,计算机在
程序的控制下一步一步的进行处理。
计算机有五大部件组成:输入设备,输出设备,存储器,运算器,控制器
2、打开电源,计算机执行的第一句执行是什么
根据上面图灵机的知识,可以知道,执行哪条语句,是有IP指针的指向决定的——硬件设计者决定。
1、x86刚开机时,CPU处于实模式(和保护模式相对应),实模式的寻址方式是 CS:IP(CS左移4位+IP),
与保护模式不同。
2、开机时(刚通电),CS=0xFFFF,IP=0x0000
3、寻址0xFFFF0(就是BIOS的映射区)
4、检查RAM,键盘显示器,软硬磁盘
5、将磁盘0磁道0扇区读入0x7c00处 6、设置CS=0x7C00,ip=0x0000
3、0x7c00处存放的代码
就是从磁盘读取的第一个扇形区存放的代码,因此,磁盘的第一个扇形区,存放着我们可以控制的第一段代码
操作系统的故事从这里开始
3、引导扇区的代码: bootsect.s
linux source code的linux/arch/i386/boot子目录下(以2.2.5版本为例)找到几个以.S作为后缀的文档.
其中就有bootsect.s,也就是磁盘第一个扇形区存放的汇编代码,也就是开机时候要写入0x7c00处的代码。
.globl begtext, begdata, begbss, endtext, enddata, endbss
.text
begtext:
.data
begdata:
.bss
begbss:
.text
//规划内存,由BIOS执行
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
!bootsect.s的执行过程
!复制自身到指定地址
entry _start
_start:
mov ax,#BOOTSEG ;0x07c0,启动代码所在位置放入ax
mov ds,ax ;将启动代码与ds寄存器关联
mov ax,#INITSEG ;启动代码要被复制到的目的地址
mov es,ax ;将目的地址与es寄存器关联
mov cx,#256 ;循环控制字节,512字节,因为bootsect.s中的每条代码占2个字节
sub si,si ;si清零,ds:si即0x07c00(0x7c00左移四位+0x0000)
sub di,di ;di清零,es:di即0x90000
rep ;循环指令,到cx==0时停止
movw ;将ds:si复制到es:di,movw把16位(bit)立即数放到ax低16位,高16位清0
jmpi go,INITSEG ;段间跳转,跳转到go标志处,cs:INITSEG(0x9000),ip:指向go那个地址
!由于启动代码复制到了新位置,需要更改相应寄存器的值
go: mov ax,cs ;将当前的cs值赋值给ax,
mov ds,ax
mov es,ax
mov ss,ax ;开始引入栈
mov sp,#0xFF00 ;栈空间的起始地址为0x9ff00(ss:0x9000,sp:0xFF00)
!开始加载setup块
load_setup:
!为后面进入0x13中断准备参数
mov dx,#0x0000 ;dh=磁头号,dl=驱动器号
mov cx,#0x0002 ;ch=柱面号,cl=开始扇区
mov bx,#0x0200 ;es:bx=内存地址
mov ax,#0x0200+SETUPLEN ;ah=0x02指明是读磁盘操作,al=4说明读取4个扇形区
int 0x13 ;(interupt 19)BIOS中断
jnc ok_load_setup ;cf标志寄存器为0(读取成功)就跳转至ok_load_setup块
mov dx,#0x0000 ;cf!=0中断出错 dx:需要复位的驱动器信息
mov ax,#0x0000 ;cf!=0中断出错 ax中保存的是错误信息 ax复位
int 0x13 ;0x13中断,ah=0x00指明是 驱动器复位命令
j load_setup ;重读
!取磁盘驱动器参数
ok_load_setup:
mov dl,#0x00
mov ax,#0x0800 ;ah=0x08指明命令是读取磁盘参数
int 0x13
mov ch,#0x00
seg cs ;下一条语句的操作数在cs所指段中
mov sectors,cx ;保存每磁道扇区数
mov ax,#INITSEG
mov es,ax
!在屏幕上输出 "Loding system..."即msg1的内容
mov ah,#0x03 ;ah=0x03指示读光标位置
xor bh,bh
int 0x10 ;0x10号中断,读取光标位置
mov cx,#24 ;共24个字符
mov bx,#0x0007 ;page 0, attribute 7 (normal)
mov bp,#msg1 ;指向要显示字符串的地址,即显示在屏幕上的第一个string
mov ax,#0x1301 ;ah=0x13指示 输出一个字符,移动一下光标
int 0x10 ;实现上条指令屏幕连续打印字符
!加载第三批代码,即剩余内核代码,时间较长
mov ax,#SYSSEG ;内核代码被加载到的地址
mov es,ax ;segment of 0x010000
call read_it ;读取磁盘上的system模块
call kill_motor ;关闭驱动器
!确定使用哪个根文件系统设备,若指定了设备(开始的ax!=0),就直接用给定的设备
seg cs
mov ax,root_dev
cmp ax,#0 ;比较ax是否为0
jne root_defined ;ax!=0跳转
seg cs
mov bx,sectors ;取磁道扇区数,如果sectors==15,则说明是1.2Mb驱动器
;如果sectors==18,则说明是1.44Mb驱动器
mov ax,#0x0208 ;/dev/ps0 - 1.2Mb
cmp bx,#15 ;判断磁道扇区数是否为15
je root_defined
mov ax,#0x021c ;! /dev/PS0 - 1.44Mb
cmp bx,#18
je root_defined
undef_root: ;如果都不是,死循环
jmp undef_root
root_defined:
seg cs
mov root_dev,ax ;保存设备号到数据区
//本程序执行完毕,跳转到已经加载在内存的setup处继续执行
jmpi 0,SETUPSEG
***
//以下是被调用的块的详细代码,以及显示在屏幕的文字信息的数据安排
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
!/*
! * This procedure turns off the floppy drive motor, so
! * that we enter the kernel in a known state, and
! * don't have to worry about it later.
! */
kill_motor:
push dx
mov dx,#0x3f2
mov al,#0
outb
pop dx
ret
sectors:
.word 0
msg1:
.byte 13,10
.ascii "Loading system ..."
.byte 13,10,13,10
.org 508
root_dev:
.word ROOT_DEV
boot_flag:
.word 0xAA55
.text
endtext:
.data
enddata:
.bss
endbss: