操作系统课程实验-linux-0-11操作系统引导

实验一 操作系统引导

引导

一、bootsect.s

磁盘第一扇区的代码,大小为512BBIOS会将其放到0x7c000,用来加载setup.ssystem

磁盘基本知识

1. 移动bootsect.s0x90000

! 35 行处
BOOTSEG = 0x07c0
INITSEG = 0x9000

! entry 表示程序入口
entry _start
_start:
mov ax,#BOOTSEG
mov ds,ax
mov ax,#INITSEG
mov es,ax
mov cx,#256
! ds:si 0x7c000 BIOS运行时加载代码的地址
sub si,si
! es:di 0x90000 目的地址
sub di,di
rep
! 移动256个字,也就是512字节,将 bootsect.s 从0x7c000移动到0x90000
movw
! 跳转到 cs=INITSEG go=偏移地址 cs:go
jmpi go,INITSEG
go: mov ax,cs

为什么是0x07c0

2. 从磁盘载入setup.s0x90200

! 67 行处
load_setup:
! dh=磁头号 dl=驱动器号
mov dx,#0x0000
! ch=柱面号 cl=开始扇区
mov cx,#0x0002
! 移动到 es:bx=090200 0x200=512
mov bx,#0x0200
mov ax,#0x0200+SETUPLEN
! BIOS int 0x13 读磁盘中断
int 0x13
jnc ok_load_setup
mov dx,#0x0000
mov ax,#0x0000
int 0x13
j load_setup

ok_load_setup:

3. 使用中断显示信息到屏幕

! 94 行处
! 中断10的3号功能,读取光标位置
mov ah,#0x03
xor bh,bh
int 0x10

! cx 字符个数
mov cx,#24
mov bx,#0x0007
! msg1 显示的信息 => Loading system ...
mov bp,#msg1
! 13号功能,显示字符
mov ax,#0x1301
int 0x10

4. 加载system0x10000

! 107 行
mov ax,#SYSSEG
! es=0x10000
mov es,ax
call read_it
call kill_motor

5. 跳转到setup.s执行

! 139 行
jmpi 0,SETUPSEG

6. 尝试编译

使用as86ld86编译bootsect.s

$ as86 -0 -a -o bootsect.o bootsect.s
$ ld86 -0 -s -o bootsect bootsect.o
$ dd bs=1 if=bootsect of=Image skip=32
记录了512+0 的读入
记录了512+0 的写出
512字节已复制,0.00553681 s,92.5 kB/s

二、setup.s

移动system0地址处,硬件检查,完成OS启动前的设置

1. 使用中断获取参数

! 44 行,获取扩展内存
mov ah,#0x88
int 0x15
! es:[2] 0x90002
mov [2],ax
! ...

2. 移动system模块到0地址处

bootsect引导程序会把system模块读入到内存0x10000开始的位置。
由于当时假设system模块最大长度不会超过0x80000,即其末端不会超过内存地址0x90000,所以bootsect会把自己移动到0x90000开始的地方,并把setup加载到它的后面。
下面这段程序的用途是再把整个system模块移动到0x00000位置,即把从0x100000x8ffff的内存数据块512KB整块地向内存低端移动了0x10000字节。

使用GDTIDT处理地址和以及中断函数

    ! 禁止中断,要进入保护模式,设置GDT表
cli

mov ax,#0x0000
cld
do_move:
mov es,ax
add ax,#0x1000
cmp ax,#0x9000
jz end_move
! ds=1000 2000 ... 8000
mov ds,ax
! es:di 0x00000
sub di,di
! ds:si 0x10000
sub si,si
! 每次移动 0x8000 64KB
mov cx,#0x8000
rep
movsw
jmp do_move

3. 进入保护模式并执行system

! 189 行
mov ax,#0x0001
! cr0 PE设置为1
lmsw ax
! cs=8 段描述符查询GDT
jmpi 0,8

GDT设置

! 203 处
! gdt 表
gdt:
.word 0,0,0,0 ! dummy

! 第8个字节
.word 0x07FF ! 8Mb - limit=2047 (2048*4096=8Mb)
.word 0x0000 ! base address=0
.word 0x9A00 ! code read/exec
.word 0x00C0 ! granularity=4096, 386

.word 0x07FF ! 8Mb - limit=2047 (2048*4096=8Mb)
.word 0x0000 ! base address=0
.word 0x9200 ! data read/write
.word 0x00C0 ! granularity=4096, 386

三、head.s

head.ssystem头部,重新设置中断描述符表和全局段描述符表

1. 调用main函数

after_page_tables:
! main 函数的参数
pushl $0 # These are the parameters to main :-)
pushl $0
pushl $0
pushl $L6 # return address for main, if it decides to.
pushl $main
jmp setup_paging
! main 函数永远不会返回,返回就死机
L6:
jmp L6 # main should never return here, but
# just in case, we know what happens.

四、实验报告