实验二:操作系统的启动
前言:
bootsect.s与setup.s均位于linux-0.11内核源码boot目录下,setup.s
和bootsect.s
一样都是操作系统进入system的准备工作,其主要功能就是获取各种硬件参数,并将这些数据保存到内存0x90000
处,也就是覆盖bootsect程序所在的空间,然后我们就可以进入保护模式啦,那么如何进入保护模式呢?
我们将寻址方式从16位扩展到32位,就可以进入保护模式,在16位实模式下寻址方式是cs寄存器中左移4位+ip地址,扩展到32即通过ax寄存器存储0x0001值后存储到cr0寄存器内,等价于将CR0寄存器的PE置为1开启保护模式,在保护模式下,我们的寻址方式就是根据cs查表+ip。
实践
修改linux-0.11内核源码boot目录下的bootsect.s
bootsect.s
entry _start
_start:
mov ah,#0x03
xor bh,bh
int 0x10
mov cx,#36
mov bx,#0x0007
mov bp,#msg1
mov ax,#0x07c0
mov es,ax
mov ax,#0x1301
int 0x10
inf_loop:
jmp inf_loop
msg1:
.byte 13,10
.ascii "Hello OS world, my name is WYN"
.byte 13,10,13,10
.org 510
boot_flag:
.word 0xAA55
编译运行:
cd ~/oslab/linux-0.11/boot/
as86 -0 -a -o bootsect.o bootsect.s
ld86 -0 -s -o bootsect bootsect.o
struct exec {
unsigned char a_magic[2]; //执行文件魔数
unsigned char a_flags;
unsigned char a_cpu; //CPU标识号
unsigned char a_hdrlen; //头部长度,32字节或48字节
unsigned char a_unused;
unsigned short a_version;
long a_text; long a_data; long a_bss; //代码段长度、数据段长度、堆长度
long a_entry; //执行入口地址
long a_total; //分配的内存总量
long a_syms; //符号表大小
};
我们可以分析该结构体的总字节数,char6字节、short2字节、long24字节,那么我们可以计算出该结构的总字节数为32字节,然而bootsect文件字节数是544个字节,一个磁盘扇区字节数为512字节,刚好多了32个字节即Id86产生的Minix可执行文件格式,所以我们需要将多余的32个字节进行删除,先查看一下它的信息,我们可以发现我们要删除的32个字节正好对应文件头部32个字节。
$ dd bs=1 if=bootsect of=Image skip=32//删除并保存到Image文件
cp Image ../Image//复制到 linux-0.11/目录中
../run //运行oslab目录下的run命令
bootsect.s读入setup.s
bootsect.s
SETUPLEN=2
SETUPSEG=0x07e0
entry _start
_start:
mov ah,#0x03
xor bh,bh
int 0x10
mov cx,#36
mov bx,#0x0007
mov bp,#msg1
mov ax,#0x07c0
mov es,ax
mov ax,#0x1301
int 0x10
load_setup:
mov dx,#0x0000
mov cx,#0x0002
mov bx,#0x0200
mov ax,#0x0200+SETUPLEN
int 0x13
jnc ok_load_setup
mov dx,#0x0000
mov ax,#0x0000
int 0x13
jmp load_setup
ok_load_setup:
jmpi 0,SETUPSEG
msg1:
.byte 13,10
.ascii "Hello OS world, my name is WYN"
.byte 13,10,13,10
.org 510
boot_flag:
.word 0xAA55
setup.s
entry _start
_start:
mov ah,#0x03
xor bh,bh
int 0x10//获取光标位置
mov cx,#25
mov bx,#0x0007
mov bp,#msg2
mov ax,cs
mov es,ax
mov ax,#0x1301
int 0x10
inf_loop:
jmp inf_loop
msg2:
.byte 13,10
.ascii "NOW we are in Setup"
.byte 13,10,13,10
.org 510
boot_flag:
.word 0xAA55
在linux-0.11目录下运行报错 make,根据 Makefile 的指引执行了 tools/build.c
,它是为生成整个内核的镜像文件而设计的,没考虑我们只需要 bootsect.s
和 setup.s
的情况。所以我们需要做出修改。
make BootImage
我们发现提示不能打开system模块哦
修改build.c
成功图如下
bochs上运行结果最终显示图
setup.s获取硬件参数
INITSEG = 0x9000
entry _start
_start:
! Print "NOW we are in SETUP"
mov ah,#0x03
xor bh,bh
int 0x10
mov cx,#25
mov bx,#0x0007
mov bp,#msg2
mov ax,cs
mov es,ax
mov ax,#0x1301
int 0x10
mov ax,cs
mov es,ax
! init ss:sp
mov ax,#INITSEG
mov ss,ax
mov sp,#0xFF00
! Get Params
mov ax,#INITSEG
mov ds,ax
mov ah,#0x03
xor bh,bh
int 0x10
mov [0],dx
mov ah,#0x88
int 0x15
mov [2],ax
mov ax,#0x0000
mov ds,ax
lds si,[4*0x41]
mov ax,#INITSEG
mov es,ax
mov di,#0x0004
mov cx,#0x10
rep
movsb
! Be Ready to Print
mov ax,cs
mov es,ax
mov ax,#INITSEG
mov ds,ax
! Cursor Position
mov ah,#0x03
xor bh,bh
int 0x10
mov cx,#18
mov bx,#0x0007
mov bp,#msg_cursor
mov ax,#0x1301
int 0x10
mov dx,[0]
call print_hex
! Memory Size
mov ah,#0x03
xor bh,bh
int 0x10
mov cx,#14
mov bx,#0x0007
mov bp,#msg_memory
mov ax,#0x1301
int 0x10
mov dx,[2]
call print_hex
! Add KB
mov ah,#0x03
xor bh,bh
int 0x10
mov cx,#2
mov bx,#0x0007
mov bp,#msg_kb
mov ax,#0x1301
int 0x10
! Cyles
mov ah,#0x03
xor bh,bh
int 0x10
mov cx,#7
mov bx,#0x0007
mov bp,#msg_cyles
mov ax,#0x1301
int 0x10
mov dx,[4]
call print_hex
! Heads
mov ah,#0x03
xor bh,bh
int 0x10
mov cx,#8
mov bx,#0x0007
mov bp,#msg_heads
mov ax,#0x1301
int 0x10
mov dx,[6]
call print_hex
! Secotrs
mov ah,#0x03
xor bh,bh
int 0x10
mov cx,#10
mov bx,#0x0007
mov bp,#msg_sectors
mov ax,#0x1301
int 0x10
mov dx,[12]
call print_hex
inf_loop:
jmp inf_loop
print_hex:
mov cx,#4
print_digit:
rol dx,#4
mov ax,#0xe0f
and al,dl
add al,#0x30
cmp al,#0x3a
jl outp
add al,#0x07
outp:
int 0x10
loop print_digit
ret
print_nl:
mov ax,#0xe0d ! CR
int 0x10
mov al,#0xa ! LF
int 0x10
ret
msg2:
.byte 13,10
.ascii "NOW we are in SETUP"
.byte 13,10,13,10
msg_cursor:
.byte 13,10
.ascii "Cursor position:"
msg_memory:
.byte 13,10
.ascii "Memory Size:"
msg_cyles:
.byte 13,10
.ascii "Cyls:"
msg_heads:
.byte 13,10
.ascii "Heads:"
msg_sectors:
.byte 13,10
.ascii "Sectors:"
msg_kb:
.ascii "KB"
.org 510
boot_flag:
.word 0xAA55
我们需要对内核重新编译并cp Image到linux0.1目录下,bochs最终结果图:
分析:
运行结果图Memory Size:0x3C00KB转换成十进制即15360KB,我们知道1KB=0.0009766MB,所以我们最终可以得到当前所加载系统的内存总容量为15360✖15.000576=15MB,我们要求当前系统最低内存容量是16MB,所以需要加上1MB,我们在bochs/bochsrc.bxrc配置文件中可以查看参数情况与预期结果吻合。
我们现在可以对操作系统的启动涉及到的.s文件做一个简单的总结。
bootsect.s | 将操作系统从磁盘上读入到内存中 |
---|---|
setup.s | 获取硬件参数,启动保护模式 |
head.s | 初始化gdt表以及idt表以及一些页表,在system模块起始位置 |