操作系统|哈工大操作系统的引导实验一
文章目录
- 前言
- 一、实验内容
- 二、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提供了大量能使我们快速便捷地处理数据的函数和方法。
推荐阅读
- 热闹中的孤独
- JAVA(抽象类与接口的区别&重载与重写&内存泄漏)
- 放屁有这三个特征的,请注意啦!这说明你的身体毒素太多
- 一个人的旅行,三亚
- 布丽吉特,人生绝对的赢家
- 慢慢的美丽
- 尽力
- 一个小故事,我的思考。
- 家乡的那条小河
- 《真与假的困惑》???|《真与假的困惑》??? ——致良知是一种伟大的力量