title

date

comments

categories

tags

permalink

操作系统启动画面的背后bootsect.s

2020/2/15

true

3.1

操作系统

1、图灵机

图灵机是A.C图灵在1936提出的。最开始的图灵机,只能做最简单的加法运算。
后来演变出来通用图灵机,是指计算机的控制器逻辑可以修改——即支持更多的运算指令。
后来冯诺依曼提出了存储程序思想:将程序和数据存放到计算机的存储器中,计算机在
程序的控制下一步一步的进行处理。
计算机有五大部件组成:输入设备,输出设备,存储器,运算器,控制器

最经典的计算机运行程序示意图(取指执行):

扬天bios修改启动画面 更改bios启动画面_加载

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: