操作系统|哈工大操作系统的引导实验一


文章目录

  • 前言
  • 一、实验内容
  • 二、bootsect显示
  • 三、bootsect.s 读入 setup.s
  • 总结

前言 提示:以下是本篇文章正文内容
一、实验内容 此次实验的基本内容是:
1.阅读《Linux 内核完全注释》的第 6 章,对计算机和 Linux 0.11 的引导过程进行初步的了解;
2.按照下面的要求改写 0.11 的引导程序 bootsect.s
3.有兴趣同学可以做做进入保护模式前的设置程序 setup.s。
改写 bootsect.s 主要完成如下功能:
bootsect.s 能在屏幕上打印一段提示信息“XXX is booting…”,其中 XXX 是你给自己的操作系统起的名字,例如 LZJos、Sunix 等(可以上论坛上秀秀谁的 OS 名字最帅,也可以显示一个特色 logo,以表示自己操作系统的与众不同。)
改写 setup.s 主要完成如下功能:
1.bootsect.s 能完成 setup.s 的载入,并跳转到 setup.s 开始地址执行。而 setup.s 向屏幕输出一行"Now we are in SETUP"
2.setup.s 能获取至少一个基本的硬件参数(如内存参数、显卡参数、硬盘参数等),将其存放在内存的特定地址,并输出到屏幕上
3.setup.s 不再加载 Linux 内核,保持上述信息显示在屏幕上即可
二、bootsect显示 实验中主要使用 BIOS 0x10 和 0x13 中断
1.首先来看完成屏幕显示的关键代码:
! 首先读入光标位置 mov ah,#0x03 xor bh,bh int 0x10! 显示字符串 “Hello OS world, my name is LMF” ! 要显示的字符串长度 mov cx,#36 mov bx,#0x0007 mov bp,#msg1 ! es:bp 是显示字符串的地址 ! 相比与 linux-0.11 中的代码,需要增加对 es 的处理,因为原代码中在输出之前已经处理了 es mov ax,#0x07c0 mov es,ax mov ax,#0x1301 int 0x10! 设置一个无限循环 inf_loop: jmp inf_loop

这里需要修改的是字符串长度,即用需要输出的字符串长度替换 mov cx,#24 中的 24。要注意:除了我们设置的字符串 msg1 之外,还有三个换行 + 回车,一共是 6 个字符。比如这里 Hello OS world, my name is LMF 的长度是 30,加上 6 后是 36,所以代码应该修改为 mov cx,#36。
2.修改输出的字符串:
! msg1 处放置字符串 msg1: ! 换行 + 回车 .byte13,10 .ascii"Hello OS world, my name is LMF" ! 两对换行 + 回车 .byte13,10,13,10! boot_flag 必须在最后两个字节 .org 510 ! 设置引导扇区标记 0xAA55 ! 必须有它,才能引导 boot_flag: .word0xAA55

将 .org 508 修改为 .org 510,是因为这里不需要 root_dev: .word ROOT_DEV,为了保证 boot_flag 一定在最后两个字节,所以要修改 .org。
3.将完成屏幕显示的代码在开发环境中编译,并将编译后的目标文件做成 Image 文件
Ubuntu 上先从终端进入 ~/oslab/linux-0.11/boot/ 目录
无论那种系统,都执行下面两个命令编译和链接 bootsect.s:
$ as86 -0 -a -o bootsect.o bootsect.s $ ld86 -0 -s -o bootsect bootsect.o

其中 -0(注意:这是数字 0,不是字母 O)表示生成 8086 的 16 位目标程序,-a 表示生成与 GNU as 和 ld 部分兼容的代码,-s 告诉链接器 ld86 去除最后生成的可执行文件中的符号信息。
如果这两个命令没有任何输出,说明编译与链接都通过了。
其中 bootsect.o 是中间文件。bootsect 是编译、链接后的目标文件。
操作系统|哈工大操作系统的引导实验一
文章图片

需要留意的文件是 bootsect 的文件大小是 544 字节,而引导程序必须要正好占用一个磁盘扇区,即 512 个字节。造成多了 32 个字节的原因是 ld86 产生的是 Minix 可执行文件格式,这样的可执行文件除了文本段、数据段等部分以外,还包括一个 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 的用途之一)。
对于上面的 Minix 可执行文件,其 a_magic[0]=0x01,a_magic[1]=0x03,a_flags=0x10(可执行文件),a_cpu=0x04(表示 Intel i8086/8088,如果是 0x17 则表示 Sun 公司的 SPARC),所以 bootsect 文件的头几个字节应该是 01 03 10 04。为了验证一下,Ubuntu 下用命令“hexdump -C bootsect”可以看到:
操作系统|哈工大操作系统的引导实验一
文章图片

删除多余的字节
dd bs=1 if=bootsect of=Image skip=32

生成的 Image 就是去掉文件头的 bootsect
操作系统|哈工大操作系统的引导实验一
文章图片

4.运行
# 将刚刚生成的 Image 复制到 linux-0.11 目录下 cp ./Image ../Image# 执行 oslab 目录中的 run 脚本 ../../run

操作系统|哈工大操作系统的引导实验一
文章图片

三、bootsect.s 读入 setup.s 首先编写一个 setup.s,该 setup.s 可以就直接拷贝前面的 bootsect.s(还需要简单的调整),然后将其中的显示的信息改为:“Now we are in SETUP”
操作系统|哈工大操作系统的引导实验一
文章图片

接下来需要编写 bootsect.s 中载入 setup.s 的关键代码。原版 bootsect.s 中下面的代码就是做这个的
load_setup: ! 设置驱动器和磁头(drive 0, head 0): 软盘 0 磁头 mov dx,#0x0000 ! 设置扇区号和磁道(sector 2, track 0): 0 磁头、0 磁道、2 扇区 mov cx,#0x0002 ! 设置读入的内存地址:BOOTSEG+address = 512,偏移512字节 mov bx,#0x0200 ! 设置读入的扇区个数(service 2, nr of sectors), ! SETUPLEN是读入的扇区个数,Linux 0.11 设置的是 4, ! 我们不需要那么多,我们设置为 2(因此还需要添加变量 SETUPLEN=2) mov ax,#0x0200+SETUPLEN ! 应用 0x13 号 BIOS 中断读入 2 个 setup.s扇区 int 0x13 ! 读入成功,跳转到 ok_load_setup: ok - continue jnc ok_load_setup ! 软驱、软盘有问题才会执行到这里。我们的镜像文件比它们可靠多了 mov dx,#0x0000 ! 否则复位软驱 reset the diskette mov ax,#0x0000 int 0x13 ! 重新循环,再次尝试读取 jmp load_setup ok_load_setup: ! 接下来要干什么?当然是跳到 setup 执行。 ! 要注意:我们没有将 bootsect 移到 0x9000,因此跳转后的段地址应该是 0x7ce0 ! 即我们要设置 SETUPSEG=0x07e0

【操作系统|哈工大操作系统的引导实验一】所有需要的功能在原版 bootsect.s 中都是存在的,我们要做的仅仅是将这些代码添加到新的 bootsect.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: jmpi0,SETUPSEG msg1: .byte13,10 .ascii"Hello OS world, my name is LZJ" .byte13,10,13,10 .org 510 boot_flag: .word0xAA55

现在有两个文件都要编译、链接。一个个手工编译,效率低下,所以借助 Makefile 是最佳方式。
在 Ubuntu 下,进入 linux-0.11 目录后,使用下面命令(注意大小写):
make BootImage

操作系统|哈工大操作系统的引导实验一
文章图片

有 Error!这是因为 make 根据 Makefile 的指引执行了 tools/build.c,它是为生成整个内核的镜像文件而设计的,没考虑我们只需要 bootsect.s 和 setup.s 的情况。它在向我们要 “系统” 的核心代码。为完成实验,接下来给它打个小补丁。
修改 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 的尾部,可以参考下面的方式,将下面的部分注释掉
操作系统|哈工大操作系统的引导实验一
文章图片

在编译运行
$ cd ~/oslab/linux-0.11 make BootImage ../run

总结 提示:这里对文章进行总结:
例如:以上就是今天要讲的内容,本文仅仅简单介绍了pandas的使用,而pandas提供了大量能使我们快速便捷地处理数据的函数和方法。

    推荐阅读