美文网首页
哈工大操作系统实验(一)系统引导

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

作者: 寒夏凉秋 | 来源:发表于2017-05-17 17:24 被阅读0次

    实验一内容:

    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

    相关文章

      网友评论

          本文标题:哈工大操作系统实验(一)系统引导

          本文链接:https://www.haomeiwen.com/subject/jjndxxtx.html