哈工大操作系统实验(一)系统引导


实验一内容:

  1. 阅读《Linux内核完全注释》的第6章,对计算机和Linux0.11的引导过程进行初步的了解;
  2. 按照下面的要求改写0.11的引导程序bootsect.s
  3. 修改build.c,以便可以使用 make BootImage命令

实验步骤:

  1. 修改bootsect.s中的提示信息及相关代码;
  2. 在目录linux-0.11\boot下,分别用命令as86 -0 -a -o bootsect.obootsect.s和ld86 -0 -s -o bootsect bootsect.o编译和链接bootsect.s,生成bootsect文件;
  3. 用命令dd bs=1 if=bootsect of=Image skip=32去掉bootsect的文件头生成Image文件,并复制Image到linux-0.11目录下;
  4. 运行run命令验证运行结果是否正确;
  5. 重新用make命令生成BootImage,结合提示信息和makefile文件修改build.c;
  6. 验证:用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命令

神奇画面出现了:

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

好啦,惊喜出现:

image.png
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 213,558评论 6 492
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 91,002评论 3 387
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 159,036评论 0 349
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 57,024评论 1 285
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 66,144评论 6 385
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 50,255评论 1 292
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,295评论 3 412
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 38,068评论 0 268
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,478评论 1 305
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 36,789评论 2 327
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 38,965评论 1 341
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,649评论 4 336
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,267评论 3 318
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,982评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,223评论 1 267
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 46,800评论 2 365
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 43,847评论 2 351

推荐阅读更多精彩内容