哈工大计算机系统实验一,哈工大操作系统实验(一)系统引导

实验一内容:

阅读《Linux内核完全注释》的第6章,对计算机和Linux0.11的引导过程进行初步的了解;

按照下面的要求改写0.11的引导程序bootsect.s

修改build.c,以便可以使用 make BootImage命令

实验步骤:

修改bootsect.s中的提示信息及相关代码;

在目录linux-0.11\boot下,分别用命令as86 -0 -a -o bootsect.obootsect.s和ld86 -0 -s -o bootsect bootsect.o编译和链接bootsect.s,生成bootsect文件;

用命令dd bs=1 if=bootsect of=Image skip=32去掉bootsect的文件头生成Image文件,并复制Image到linux-0.11目录下;

运行run命令验证运行结果是否正确;

重新用make命令生成BootImage,结合提示信息和makefile文件修改build.c;

验证:用make是否能成功生成BootImage。

(一)改写bootsect.s主要完成的如下功能:

bootsect.s能在屏幕上打印一段提示信息“XXX booting...”,其中XXX是你给自己的操作系统起的名字,例如LZJos、Sunix等

关键代码:

! 首先读入光标位置

mov ah,#0x03

xor bh,bh

int 0x10

! 显示字符串“LZJos is running...”

mov cx,#25 ! 要显示的字符串长度

mov bx,#0x0007 ! page 0, attribute 7 (normal)

mov bp,#msg1

mov ax,#0x1301 ! write string, move cursor

int 0x10

inf_loop:

jmp inf_loop ! 后面都不是正经代码了,得往回跳呀

! msg1处放置字符串

msg1: //msg1 为要输出的字符串 ,13为换行,10为回车

.byte 13,10 ! 换行+回车

.ascii "LZJos is running..."

.byte 13,10,13,10 ! 两对换行+回车

!设置引导扇区标记0xAA55

.org 510

boot_flag:

.word 0xAA55 ! 必须有它,才能引导

我们需要改的就是msg1中的内容,以及mov cx,#25 这里的字符串长度

注意计算字符串的长度;

比如这样

Print some inane message

mov ah,#0x03 ! read cursor pos

xor bh,bh

int 0x10

mov cx,#27 !修改这里

mov bx,#0x0007 ! page 0, attribute 7 (normal)

mov bp,#msg1

mov ax,#0x1301 ! write string, move cursor

int 0x10

msg1:

.byte 13,10

.ascii "Jinux OS is booting ..."

.byte 13,10,13,10

然后修改build.c 该文件位于 linux-0.11/tools/build.c

build.c从命令行参数得到bootsect、setup和system内核的文件名,将三者做简单的整理后一起写入Image。其中system是第三个参数(argv[3])。当“make all”或者“makeall”的时候,这个参数传过来的是正确的文件名,build.c会打开它,将内容写入Image。而“make BootImage”时,传过来的是字符串"none"。所以,改造build.c的思路就是当argv[3]是"none"的时候,只写bootsect和setup,忽略所有与system有关的工作,或者在该写system的位置都写上“0”。

要修改的部分在build.c文件尾端:

bulid.c 之前为:

if ((id=open(argv[3],O_RDONLY,0))<0)

die("Unable to open 'system'");

// if (read(id,buf,GCC_HEADER) != GCC_HEADER)

// die("Unable to read header of 'system'");

// if (((long *) buf)[5] != 0)

// die("Non-GCC header of 'system'");

for (i=0 ; (c=read(id,buf,sizeof buf))>0 ; i+=c )

if (write(1,buf,c)!=c)

die("Write call failed");

close(id);

fprintf(stderr,"System is %d bytes.\n",i);

if (i > SYS_SIZE*16)

die("System is too big");

return(0);

修改为:

if(strcmp("none",argv[3]) == 0) //添加判断

return 0;

if ((id=open(argv[3],O_RDONLY,0))<0)

die("Unable to open 'system'");

// if (read(id,buf,GCC_HEADER) != GCC_HEADER)

// die("Unable to read header of 'system'");

// if (((long *) buf)[5] != 0)

// die("Non-GCC header of 'system'");

for (i=0 ; (c=read(id,buf,sizeof buf))>0 ; i+=c )

if (write(1,buf,c)!=c)

die("Write call failed");

close(id);

fprintf(stderr,"System is %d bytes.\n",i);

if (i > SYS_SIZE*16)

die("System is too big");

return(0);

现在,显示部分就做好了;

编译与运行:

cd ~/oslab/linux-0.11/boot/

as86 -0 -a -o bootsect.o bootsect.s

ld86 -0 -s -o bootsect bootsect.o

其中bootsect.o是中间文件。bootsect是编译、链接后的目标文件。

需要留意的文件是bootsect的文件大小是544字节,而引导程序必须要正好占用一个磁盘扇区,即512个字节。造成多了32个字节的原因是ld86产生的是Minix可执行文件格式,

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; //符号表大小

};

算一算:6 char(6字节)+1 short(2字节)+6 long(24字节)=32,正好是32个字节,去掉这32个字节后就可以放入引导扇区了(这是tools/build.c的用途之一)。

dd bs=1 if=bootsect of=Image skip=32

//该命令是删除bootsect那32个字节并保存为Image文件

cp Image ../Image

//复制到 linux-0.11/目录中

../run //运行oslab目录下的run命令

神奇画面出现了:

216653ad3d08?appinstall=0

image.png

(二)改写bootsect.s 读入setup.s

我们需要改写bootsect.s 使输出 “XXX is booting..." 后跳转到setup.s 中,并在setup.s 中输出"Now we are in SETUP"

开撸:

既然输出"XXX is booting..."后跳转到setup.s 那 除了数据段 后面的代码就是多余的(当然 ,你留着也行)

.globl begtext, begdata, begbss, endtext, enddata, endbss

.text

begtext:

.data

begdata:

.bss

begbss:

.text

SETUPLEN = 4 ! setup程序代码占用扇区数

BOOTSEG = 0x07c0 ! bootsect程序代码所在内存原始地址

INITSEG = 0x9000 ! 将bootsect移动到0x9000处

SETUPSEG = 0x9020 ! setup程序开始的地址

entry _start

_start:

! 下面这段代码将自身复制到0x9000处

mov ax,#BOOTSEG

mov ds,ax

mov ax,#INITSEG

mov es,ax

mov cx,#256

sub si,si

sub di,di

rep

movw

! 复制完成从0x9000的go标号处开始执行

jmpi go,INITSEG

go: mov ax,cs

mov ds,ax !设置ds=es=cs

mov es,ax

! 加载setup.s程序

load_setup:

mov dx,#0x0000 ! drive 0, head 0

mov cx,#0x0002 ! sector 2, track 0

mov bx,#0x0200 ! address = 512, in INITSEG

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:

!输出一些信息

mov ah,#0x03 ! read cursor pos

xor bh,bh

int 0x10

mov cx,#15

mov bx,#0x000c ! page 0, attribute c

mov bp,#msg1 ! es:bp 指向待显示 字符串

mov ax,#0x1301 ! write string, move cursor

int 0x10

!输出后开始执行setup代码

jmpi 0,SETUPSEG

msg1:

.byte 13,10

.ascii "hello os!"

.byte 13,10,13,10

.org 510

boot_flag:

.word 0xAA55

.text

endtext:

.data

enddata:

.bss

endbss:

setup.s 代码:

.globl begtext, begdata, begbss, endtext, enddata, endbss

.text

begtext:

.data

begdata:

.bss

begbss:

.text

BOOTSEG = 0x07c0 ! original address of boot-sector

INITSEG = 0x9000 ! we move boot here - out of the way

SETUPSEG = 0x9020 ! setup starts here

entry _start

_start:

!设置cs=ds=es

mov ax,cs

mov ds,ax

mov es,ax

mov ah,#0x03 ! read cursor pos

xor bh,bh

int 0x10

mov cx,#28

mov bx,#0x000c ! page 0, attribute c

mov bp,#msg1

mov ax,#0x1301 ! write string, move cursor

int 0x10

! ok, the read went well so we get current cursor position and save it for

! posterity.

! 获取光标位置 => 0x9000:0

mov ax,#INITSEG ! this is done in bootsect already, but...

mov ds,ax

mov ah,#0x03 ! read cursor pos

xor bh,bh

int 0x10 ! save it in known place, con_init fetches

mov [0],dx ! it from 0x90000.

! Get memory size (extended mem, kB)

! 获取拓展内存大小 => 0x9000:2

mov ah,#0x88

int 0x15

mov [2],ax

! Get hd0 data

! 获取硬盘参数 => 0x9000:80 大小:16B

mov ax,#0x0000

mov ds,ax

lds si,[4*0x41]

mov ax,#INITSEG

mov es,ax

mov di,#0x0080

mov cx,#0x10

rep

movsb

! 前面修改了ds寄存器,这里将其设置为0x9000

mov ax,#INITSEG

mov ds,ax

mov ax,#SETUPSEG

mov es,ax

!显示 Cursor POS: 字符串

mov ah,#0x03 ! read cursor pos

xor bh,bh

int 0x10

mov cx,#11

mov bx,#0x0007 ! page 0, attribute c

mov bp,#cur

mov ax,#0x1301 ! write string, move cursor

int 0x10

!调用 print_hex 显示具体信息

mov ax,[0]

call print_hex

call print_nl

!显示 Memory SIZE: 字符串

mov ah,#0x03 ! read cursor pos

xor bh,bh

int 0x10

mov cx,#12

mov bx,#0x0007 ! page 0, attribute c

mov bp,#mem

mov ax,#0x1301 ! write string, move cursor

int 0x10

!显示 具体信息

mov ax,[2]

call print_hex

!显示相应 提示信息

mov ah,#0x03 ! read cursor pos

xor bh,bh

int 0x10

mov cx,#25

mov bx,#0x0007 ! page 0, attribute c

mov bp,#cyl

mov ax,#0x1301 ! write string, move cursor

int 0x10

!显示具体信息

mov ax,[0x80]

call print_hex

call print_nl

!显示 提示信息

mov ah,#0x03 ! read cursor pos

xor bh,bh

int 0x10

mov cx,#8

mov bx,#0x0007 ! page 0, attribute c

mov bp,#head

mov ax,#0x1301 ! write string, move cursor

int 0x10

!显示 具体信息

mov ax,[0x80+0x02]

call print_hex

call print_nl

!显示 提示信息

mov ah,#0x03 ! read cursor pos

xor bh,bh

int 0x10

mov cx,#8

mov bx,#0x0007 ! page 0, attribute c

mov bp,#sect

mov ax,#0x1301 ! write string, move cursor

int 0x10

!显示 具体信息

mov ax,[0x80+0x0e]

call print_hex

call print_nl

!死循环

l: jmp l

!以16进制方式打印ax寄存器里的16位数

print_hex:

mov cx,#4 ! 4个十六进制数字

mov dx,ax ! 将ax所指的值放入dx中,ax作为参数传递寄存器

print_digit:

rol dx,#4 ! 循环以使低4比特用上 !! 取dx的高4比特移到低4比特处。

mov ax,#0xe0f ! ah = 请求的功能值,al = 半字节(4个比特)掩码。

and al,dl ! 取dl的低4比特值。

add al,#0x30 ! 给al数字加上十六进制0x30

cmp al,#0x3a

jl outp !是一个不大于十的数字

add al,#0x07 !是a~f,要多加7

outp:

int 0x10

loop print_digit

ret

!打印回车换行

print_nl:

mov ax,#0xe0d

int 0x10

mov al,#0xa

int 0x10

ret

msg1:

.byte 13,10

.ascii "Now we are in setup..."

.byte 13,10,13,10

cur:

.ascii "Cursor POS:"

mem:

.ascii "Memory SIZE:"

cyl:

.ascii "KB"

.byte 13,10,13,10

.ascii "HD Info"

.byte 13,10

.ascii "Cylinders:"

head:

.ascii "Headers:"

sect:

.ascii "Secotrs:"

.text

endtext:

.data

enddata:

.bss

endbss:

修改后,进入linux-0.11目录重新一键编译

#编译

make BootImage

#运行

../run

好啦,惊喜出现:

216653ad3d08?appinstall=0

image.png

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值