> 文章列表 > 《操作系统》by李治军 | 实验2 - 操作系统的引导

《操作系统》by李治军 | 实验2 - 操作系统的引导

《操作系统》by李治军 | 实验2 - 操作系统的引导

目录

一、实验内容

二、实验准备

三、正式实验

(一)修改 bootsect.s 代码,实现向屏幕输出信息 “Hello OS world, my name is XXX”。

(二)修改 setup.s 代码,向屏幕输出一行信息 "Now we are in SETUP",并实现 bootsect.s 对 setup.s 的载入。

(三)修改 setup.s 代码获取基本硬件参数。


一、实验内容

1、阅读《Linux内核完全注释:基于0.11内核》第 6 章,对计算机和 Linux 0.11 的引导过程进行初步了解。

2、改写 bootsect.s 代码,实现:

      在屏幕上打印一段自己设定的信息,如 “XXX is booting...” 。

3、改写 setup.s 代码,实现:

      ① bootsect.s 完成 setup.s 的载入,并跳转到 setup.s 开始地址执行。而 setup.s 向屏幕输出信息 "Now we are in SETUP" 。

      ② setup.s 能够获取至少一个基本的硬件参数(如 内存参数、显卡参数、硬盘参数 等),将其存放在内存的特定地址,并输出到屏幕上。

      ③ setup.s 不再加载 Linux 内核,保持上述信息显示在屏幕上即可。

二、实验准备

1、实验环境

        蓝桥云课实验楼:操作系统原理与实践_Linux - 蓝桥云课

2、相关代码文件
       
Linux-0.11/boot 目录下的 bootsect.s、setup.s 和 Linux-0.11/tools 目录下 build.c 是本实验会涉及到的源文件,它们的功能详见《注释》的 6.2、6.3 节和 16 章。

   

3、引导程序的运行环境
        引导程序由
BIOS 加载并运行。它活动时,操作系统还不存在,整台计算机的所有资源都由它掌控,此时能利用的功能只有 BIOS 中断调用。实验中主要使用 BIOS 0x10 和 0x13 中断。

三、正式实验

(一)修改 bootsect.s 代码,实现向屏幕输出信息 “Hello OS world, my name is XXX”。

1. 打开 oslab/linux-0.11/boot 目录下的 bootsect.s 源码文件。

    

2. 直接删除原来所有的代码,替换以下新代码并保存。

entry _start
_start:!使用 0x10 号中断读取光标位置mov ah,#0x03xor bh,bhint 0x10!显示字符串 “Hello OS world, my name is LQN”!cx 为要显示字符串的长度(除字符串外还有3个换行+1个回车)mov cx,#36mov bx,#0x0007! es:bp 为显示字符串的地址mov bp,#msg1mov ax,#0x07c0mov es,axmov ax,#0x1301int 0x10!设置一个无限循环
inf_loop:jmp inf_loop!设置显示字符串
msg1:!回车+换行.byte   13,10.ascii  "Hello OS world, my name is LQN"!两对 “回车+换行”.byte   13,10,13,10!boot_flag 必须在最后两个字节
.org 510
!设置引导扇区标记 0xAA55(必须设置,否则无法成功引导)
boot_flag:.word   0xAA55

3. 打开终端(Ctrl + Alt + T),输入以下命令 编译 新编写的 bootsect.s。

as86 -0 -a -o bootsect.o bootsect.s
  • bootsect.o 为 bootsect.s 编译生成的中间文件

4. 输入以下命令 链接 生成的 bootsect.o 文件。

ld86 -0 -s -o bootsect bootsect.o
  • bootsect 是编译、链接后的生成的目标文件

5. 输入 ls -l 列出文件信息,可以看出 boot 目录下多了一个中间文件 bootsect.o 和一个目标文件 bootsect。

6. 可以看出这里 bootsect 文件大小是 544 字节,而引导程序必须要正好占用一个磁盘扇区,即 512 个字节,这里多出了 32 个字节,所以输入以下指令去掉文件头的 32 个字节。

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

生成的 Image 就是去掉文件头的 bootsect,刚好512字节:

7. 确保上一步生成的 Image 文件位于 linux-0.11 目录下,如果没有就拷贝一下。

cp ./Image ../Image

8. 输入以下指令执行 oslab 目录下的 run 脚本。

../../run

9. 运行结果:

(二)修改 setup.s 代码,向屏幕输出一行信息 "Now we are in SETUP",并实现 bootsect.s 对 setup.s 的载入。

1. 这里 setup.s 的功能和前面 bootsect.s 的功能基本一致,所以可以直接拷贝前面的 bootsect.s 代码,将显示的信息改为 “Now we are in SETUP” 即可 ,完整 setup.s 代码如下。

entry _start
_start:mov ah,#0x03xor bh,bhint 0x10!注意字符串长度的变化mov cx,#25mov bx,#0x0007mov bp,#msg2mov ax,csmov es,axmov ax,#0x1301int 0x10inf_loop:jmp inf_loopmsg2:.byte   13,10.ascii  "Now we are in SETUP".byte   13,10,13,10.org 510
boot_flag:.word   0xAA55

2. 编写 bootsect.s 中 载入 setup.s 的代码,完整 bootsect.s 代码如下。

SETUPLEN=2
SETUPSEG=0x07e0
entry _start
_start:mov ah,#0x03xor bh,bhint 0x10mov cx,#36mov bx,#0x0007mov bp,#msg1mov ax,#0x07c0mov es,axmov ax,#0x1301int 0x10load_setup:mov dx,#0x0000mov cx,#0x0002mov bx,#0x0200mov ax,#0x0200+SETUPLENint 0x13jnc ok_load_setupmov dx,#0x0000mov ax,#0x0000int 0x13jmp load_setupok_load_setup:jmpi    0,SETUPSEGmsg1:.byte   13,10.ascii  "Hello OS world, my name is LQN".byte   13,10,13,10.org 510
boot_flag:.word   0xAA55

3. 再次编译。

        现在有两个文件 bootsect.s 和 setup.s 需要编译、链接。如果还是使用之前的手动编译,效率较低(先 as86 再 ld86 )。所以可以借助 Makefile 提高效率。

进入 linux-0.11 目录,输入以下命令:

make BootImage

编译失败,显示以下结果:

Unable to open 'system'

make: * [BootImage] Error 1

  • 因为 make 指令根据 Makefile 的指引执行了 tools/build.c ,它是为生成整个内核的镜像文件而设计的,没考虑我们只需要 bootsect.s 和 setup.s 的情况。它在向我们要求 “系统” 的核心代码,所以为完成实验需要对 build.c 进行一点修改。

4. 修改 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 写入 Image,忽略所有与 system 有关的工作,或者在该写 system 的位置都写上 “0”。

5. 回到 linux-0.11 目录,再次执行编译命令。

make BootImage

6. 编译成功后,再次执行 run  脚本,运行结果:

(三)修改 setup.s 代码获取基本硬件参数。

1. setup.s 参考代码。

INITSEG  = 0x9000
entry _start
_start:
! Print "NOW we are in SETUP"mov ah,#0x03xor bh,bhint 0x10mov cx,#25mov bx,#0x0007mov bp,#msg2mov ax,csmov es,axmov ax,#0x1301int 0x10mov ax,csmov es,ax! init ss:spmov ax,#INITSEGmov ss,axmov sp,#0xFF00! Get Paramsmov ax,#INITSEGmov ds,axmov ah,#0x03xor bh,bhint 0x10mov [0],dxmov ah,#0x88int 0x15mov [2],axmov ax,#0x0000mov ds,axlds si,[4*0x41]mov ax,#INITSEGmov es,axmov di,#0x0004mov cx,#0x10repmovsb! Be Ready to Printmov ax,csmov es,axmov ax,#INITSEGmov ds,ax! Cursor Positionmov ah,#0x03xor bh,bhint 0x10mov cx,#18mov bx,#0x0007mov bp,#msg_cursormov ax,#0x1301int 0x10mov dx,[0]call    print_hex! Memory Sizemov ah,#0x03xor bh,bhint 0x10mov cx,#14mov bx,#0x0007mov bp,#msg_memorymov ax,#0x1301int 0x10mov dx,[2]call    print_hex! Add KBmov ah,#0x03xor bh,bhint 0x10mov cx,#2mov bx,#0x0007mov bp,#msg_kbmov ax,#0x1301int 0x10! Cylesmov ah,#0x03xor bh,bhint 0x10mov cx,#7mov bx,#0x0007mov bp,#msg_cylesmov ax,#0x1301int 0x10mov dx,[4]call    print_hex! Headsmov ah,#0x03xor bh,bhint 0x10mov cx,#8mov bx,#0x0007mov bp,#msg_headsmov ax,#0x1301int 0x10mov dx,[6]call    print_hex! Secotrsmov ah,#0x03xor bh,bhint 0x10mov cx,#10mov bx,#0x0007mov bp,#msg_sectorsmov ax,#0x1301int 0x10mov dx,[12]call    print_hexinf_loop:jmp inf_loopprint_hex:mov    cx,#4print_digit:rol    dx,#4mov    ax,#0xe0fand    al,dladd    al,#0x30cmp    al,#0x3ajl     outpadd    al,#0x07outp:int    0x10loop   print_digitretprint_nl:mov    ax,#0xe0d     ! CRint    0x10mov    al,#0xa     ! LFint    0x10retmsg2:.byte 13,10.ascii "NOW we are in SETUP".byte 13,10,13,10msg_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

2. 运行结果: