Linux0.11源码学习--操作系统启动

2022-04-04  本文已影响0人  郭江伟

Linux0.11启动过程

启动过程

需要重点记住:cpu按照pc寄存器的值取值执行,取值后pc的值会加一

  1. 系统加电 从bios启动系统
    系统加电时,cs 寄存器的值是0xFFFF pc 寄存器的值是0x0000
    cs的值左移4位加上pc值等于0xFFFF0 ,cpu从0xFFFF0开始寻址,这个地址映射的bios rom,这段代码会检查内存、硬盘 等设备,并将硬盘的第一个扇区读入到内存的0x7C00处
  2. 硬盘的第一个扇区存放的程序源码为bootsect.s,是操作系统的引导程序,从这一步开始进入操作代码
  3. bootsect会依次读入setup和sytem,
    启动引导试内核在内存中会移动,移动情况如下图:


    启动引导时内核在内存中的移动

Linux0.11内存划分

boot 文件夹源码解析

bootsect.s 源码介绍

!
! SYS_SIZE is the number of clicks (16 bytes) to be loaded.
! 0x3000 is 0x30000 bytes = 196kB, more than enough for current
! versions of linux
!
SYSSIZE = 0x3000  ## 左移4位置等于 3*16^4= 192 kB  ,
!
!   bootsect.s      (C) 1991 Linus Torvalds
!
! bootsect.s is loaded at 0x7c00 by the bios-startup routines, and moves
! iself out of the way to address 0x90000, and jumps there.
!
! It then loads 'setup' directly after itself (0x90200), and the system
! at 0x10000, using BIOS interrupts. 
!
! NOTE! currently system is at most 8*65536 bytes long. This should be no
! problem, even in the future. I want to keep it simple. This 512 kB
! kernel size should be enough, especially as this doesn't contain the
! buffer cache as in minix
!
! The loader has been made as simple as possible, and continuos
! read errors will result in a unbreakable loop. Reboot by hand. It
! loads pretty fast by getting whole sectors at a time whenever possible.

SETUPLEN = 4                ! 加载的扇区数
BOOTSEG  = 0x07c0           ! original address of boot-sector 7*16^3+12*16^2 =31k
INITSEG  = 0x9000           ! 会将 boot-sector移动到此处 9*16*4 = 576k
SETUPSEG = 0x9020           ! setup 会加载到这里 INITSEG  + 512
SYSSEG   = 0x1000           ! system loaded at 0x10000 (65536).
ENDSEG   = SYSSEG + SYSSIZE     ! where to stop loading

entry _start  !程序入口
_start:
    mov ax,#BOOTSEG   !ax寄存器的值设置为0x07c0
    mov ds,ax             !ds(数据段)寄存器的值设置为0x07c0
    mov ax,#INITSEG  !ax寄存器的值设置为 0x9000
    mov es,ax              !es寄存器的值设置为 0x9000
    mov cx,#256         ! cx寄存器的值设为256 ,表示循环次数,
    sub si,si               ! si寄存器 置0  源地址 ds:si = 0x07C0:0x0000
    sub di,di      ! di寄存器 置0  目的地址 es:di = 0x9000:0x0000
    rep                 ! 循环,每循环一次cx减1  
    movw  !移动一个字, 8086 字长16bit,两个字节,总共移动512字节
    jmpi    go,INITSEG !跳转到go 并将cs 设为0x9000
go: mov ax,cs       !后面三句 把ds es都设为0x9000
    mov ds,ax
    mov es,ax
! put stack at 0x9ff00.
    mov ss,ax
    mov sp,#0xFF00      ! arbitrary value >>512

! load the setup-sectors directly after the bootblock.
! Note that 'es' is already set up.

!load_setup用途是利用 BIOS 中断 INT 0x13 将 setup 模块从磁盘第 2 个扇区
! 开始读到 0x90200 开始处,共读 4 个扇区。如果读出错,则复位驱动器,并
! 重试,没有退路。INT 0x13 的使用方法如下:
! 读扇区:
! ah = 0x02 - 读磁盘扇区到内存;al = 需要读出的扇区数量;
! ch = 磁道(柱面)号的低 8 位; cl = 开始扇区(0-5 位),磁道号高 2 位(6-7);
! dh = 磁头号; dl = 驱动器号(如果是硬盘则要置位 7);
! es:bx ?指向数据缓冲区; 如果出错则 CF 标志置位。
load_setup: !加载setup模块
    mov dx,#0x0000      ! drive 0, head 0
    mov cx,#0x0002      ! sector 2, track 0
    mov bx,#0x0200      ! address = 512, in INITSEG 在前面已经将es设置为0x9000
    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:

! Get disk drive parameters, specifically nr of sectors/track

    mov dl,#0x00
    mov ax,#0x0800      ! AH=8 is get drive parameters
    int 0x13
    mov ch,#0x00
    seg cs
    mov sectors,cx
    mov ax,#INITSEG
    mov es,ax

! Print some inane message    这里是往屏幕打印一些字符

    mov ah,#0x03        ! read cursor pos
    xor bh,bh
    int 0x10
    
    mov cx,#24   ! 打印字符的数量
    mov bx,#0x0007      ! page 0, attribute 7 (normal)
    mov bp,#msg1               ! bp指想msg1 ,这个是下一步要实验的该的地方
    mov ax,#0x1301      ! write string, move cursor
    int 0x10                  !显示器中断

! ok, we've written the message, now
! we want to load the system (at 0x10000)

    mov ax,#SYSSEG     !将ax寄存器设为0x1000
    mov es,ax       ! segment of 0x010000 
    call    read_it            ! 加载system模块
    call    kill_motor

! After that we check which root-device to use. If the device is
! defined (!= 0), nothing is done and the given device is used.
! Otherwise, either /dev/PS0 (2,28) or /dev/at0 (2,8), depending
! on the number of sectors that the BIOS reports currently.

    seg cs
    mov ax,root_dev
    cmp ax,#0
    jne root_defined
    seg cs
    mov bx,sectors
    mov ax,#0x0208      ! /dev/ps0 - 1.2Mb
    cmp bx,#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

! after that (everyting loaded), we jump to
! the setup-routine loaded directly after
! the bootblock:

    jmpi    0,SETUPSEG

! This routine loads the system at address 0x10000, making sure
! no 64kB boundaries are crossed. We try to load it as fast as
! possible, loading whole tracks whenever we can.
!
! in:   es - starting address segment (normally 0x1000)
!
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



sectors:
    .word 0

msg1:
    .byte 13,10     !13是ascii码的回车键 10是ascii的换行符
    .ascii "Loading system ..."
    .byte 13,10,13,10   !两次回车加换行

源码实验

  1. 实验目的
    原始系统启动界面显示Loading system ...


    原始启动界面

    本实验将Loading system ... 改为guojiangwei is testing ...

  2. 实验过程
    Loading system ... 长度为18
    guojiangwei is testing ... 长度为26
    mov cx,#24 改为mov cx,#32 比之前多打印8个字符
    修改如下代码:
    msg1:
    .byte 13,10 !13是ascii码的回车键 10是ascii的换行符
    .ascii "guojiangwei is testing ..."
    .byte 13,10,13,10 !两次回车加换行
root@c38ac0380e56:~/oslab/linux-0.11# pwd
/root/oslab/linux-0.11
root@c38ac0380e56:~/oslab/linux-0.11# make all
  1. 实验结果


    实验结果
上一篇下一篇

猜你喜欢

热点阅读