Linux0.11源码学习--操作系统启动
2022-04-04 本文已影响0人
郭江伟
Linux0.11启动过程
启动过程需要重点记住:cpu按照pc寄存器的值取值执行,取值后pc的值会加一
- 系统加电 从bios启动系统
系统加电时,cs 寄存器的值是0xFFFF pc 寄存器的值是0x0000
cs的值左移4位加上pc值等于0xFFFF0 ,cpu从0xFFFF0开始寻址,这个地址映射的bios rom,这段代码会检查内存、硬盘 等设备,并将硬盘的第一个扇区读入到内存的0x7C00处 - 硬盘的第一个扇区存放的程序源码为bootsect.s,是操作系统的引导程序,从这一步开始进入操作代码
-
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 !两次回车加换行
源码实验
-
实验目的
原始系统启动界面显示Loading system ...
原始启动界面
本实验将Loading system ... 改为guojiangwei is testing ...
- 实验过程
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
-
实验结果
实验结果