实验目的

熟悉hit-oslab实验环境; 建立对操作系统引导过程的深入认识; 掌握操作系统的基本开发过程; 能对操作系统代码进行简单的控制,揭开操作系统的神秘面纱

实验内容

此次实验的基本内容是: 阅读《Linux内核完全注释》的第6章,对计算机和Linux 0.11的引导过程进行初步的了解; 按照下面的要求改写0.11的引导程序bootsect.s 有兴趣同学可以做做进入保护模式前的设置程序setup.s。 改写bootsect.s主要完成如下功能: bootsect.s能在屏幕上打印一段提示信息“XXX is booting…”,其中XXX是你给自己的操作系统起的名字,例如LZJos、Sunix等(可以上论坛上秀秀谁的OS名字最帅,也可以显示一个特色logo,以表示自己操作系统的与众不同。) 改写setup.s主要完成如下功能: bootsect.s能完成setup.s的载入,并跳转到setup.s开始地址执行。而setup.s向屏幕输出一行”Now we are in SETUP”。 setup.s能获取至少一个基本的硬件参数(如内存参数、显卡参数、硬盘参数等),将其存放在内存的特定地址,并输出到屏幕上。 setup.s不再加载Linux内核,保持上述信息显示在屏幕上即可。

Linux 0.11相关代码详解

boot/bootsect.s、boot/setup.s和tools/build.c是本实验会涉及到的源文件。它们的功能详见《注释》的6.2、6.3节和16章。 如果使用Windows下的环境,那么要注意Windows环境里提供的build.c是一个经过修改过的版本。Linus Torvalds的原版是将0.11内核的最终目标代码输出到标准输出,由make程序将数据重定向到Image文件,这在Linux、Unix和Minix等系统下都是非常有效的。但Windows本身的缺陷(也许是特色)决定了在Windows下不能这么做,所以flyfish修改了build.c,将输出直接写入到Image(flyfish是写入到Boot.img文件,我们为了两个环境的一致,也为了最大化地与原始版本保持统一,将其改为Image)文件中。同时为了适应Windows的一些特殊情况,他还做了其它一些小修改。

引导程序的运行环境

引导程序由BIOS加载并运行。它活动时,操作系统还不存在,整台计算机的所有资源都由它掌控,而能利用的功能只有BIOS中断调用。

完成bootsect.s的屏幕输出功能

首先来看完成屏幕显示的关键代码如下:

! 首先读入光标位置
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:
.byte 13,10 ! 换行+回车
.ascii “WJG OS is running …”
.byte 13,10,13,10 ! 两对换行+回车
!设置引导扇区标记0xAA55
.org 510
boot_flag:
.word 0xAA55 ! 必须有它,才能引导

接下来,将完成屏幕显示的代码在开发环境中编译,并使用linux-0.11/tools/build.c将编译后的目标文件做成Image文件。

编译和运行

Ubuntu上先从终端进入~/oslab/linux-0.11/boot/目录。Windows上则先双击快捷方式“MinGW32.bat”,将打开一个命令行窗口,当前目录是oslab,用cd命令进入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去除最后生成的可执行文件中的符号信息。 如果这两个命令没有任何输出,说明编译与链接都通过了。Ubuntu下用ls -l可列出下面的信息:

wjg@v-m:/oslab$ cd ~/oslab/linux-0.11/boot/
wjg@v-m:
/oslab/linux-0.11/boot$ as86 -0 -a -o bootsect.o bootsect.s
wjg@v-m:/oslab/linux-0.11/boot$ ld86 -0 -s -o bootsect bootsect.o
wjg@v-m:
/oslab/linux-0.11/boot$ ls -l
总用量 68
-rwxr-xr-x 1 wjg wjg 544 5月 31 14:56 bootsect
-rw-r–r– 1 wjg wjg 927 5月 31 14:56 bootsect.o
-rw-r–r– 1 wjg wjg 5095 5月 31 14:50 bootsect.s
-rw-r–r– 1 wjg wjg 27868 4月 30 15:46 head.o
-rw-r–r– 1 wjg wjg 5938 8月 28 2008 head.s
-rwxr-xr-x 1 wjg wjg 344 4月 30 15:46 setup
-rw-r–r– 1 wjg wjg 596 4月 30 15:46 setup.o
-rw-r–r– 1 wjg wjg 5362 8月 28 2008 setup.s

其中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”可以看到:

wjg@v-m:~/oslab/linux-0.11/boot$ hexdump -C bootsect
00000000 01 03 10 04 20 00 00 00 00 02 00 00 00 00 00 00 |…. ………..|
00000010 00 00 00 00 00 00 00 00 00 82 00 00 00 00 00 00 |…………….|
00000020 b8 c0 07 8e d8 b8 00 90 8e c0 b9 00 01 29 f6 29 |………….).)|
00000030 ff f3 a5 ea 18 00 00 90 8c c8 8e d8 8e c0 8e d0 |…………….|
00000040 bc 00 ff ba 00 00 b9 02 00 bb 00 02 b8 04 02 cd |…………….|
00000050 13 73 0a ba 00 00 b8 00 00 cd 13 eb e6 b2 00 b8 |.s…………..|
00000060 00 08 cd 13 b5 00 2e 89 0e 3d 01 b8 00 90 8e c0 |………=……|
00000070 b4 03 30 ff cd 10 b9 1a 00 bb 07 00 bd 3f 01 b8 |..0……….?..|
00000080 01 13 cd 10 b8 00 10 8e c0 e8 32 00 e8 c5 00 2e |……….2…..|
00000090 a1 fc 01 3d 00 00 75 17 2e 8b 1e 3d 01 b8 08 02 |…=..u….=….|
000000a0 83 fb 0f 74 0a b8 1c 02 83 fb 12 74 02 eb fe 2e |…t…….t….|
000000b0 a3 fc 01 ea 00 00 20 90 05 00 00 00 00 00 8c c0 |…… ………|
000000c0 a9 ff 0f 75 fe 31 db 8c c0 3d 00 40 72 01 c3 2e |…u.1…=.@r…|
000000d0 a1 3d 01 2b 06 98 00 89 c1 c1 e1 09 01 d9 73 09 |.=.+……….s.|
000000e0 74 07 31 c0 29 d8 c1 e8 09 e8 34 00 89 c1 03 06 |t.1.)…..4…..|
000000f0 98 00 2e 3b 06 3d 01 75 12 b8 01 00 2b 06 9a 00 |…;.=.u….+…|
00000100 75 04 ff 06 9c 00 a3 9a 00 31 c0 a3 98 00 c1 e1 |u……..1……|
00000110 09 01 cb 73 b2 8c c0 05 00 10 8e c0 31 db eb a7 |…s……..1…|
00000120 50 53 51 52 8b 16 9c 00 8b 0e 98 00 41 88 d5 8b |PSQR……..A…|
00000130 16 9a 00 88 d6 b2 00 81 e2 00 01 b4 02 cd 13 72 |……………r|
00000140 05 5a 59 5b 58 c3 b8 00 00 ba 00 00 cd 13 5a 59 |.ZY[X………ZY|
00000150 5b 58 eb cc 52 ba f2 03 b0 00 ee 5a c3 00 00 0d |[X..R……Z….|
00000160 0a 57 4a 47 20 4f 53 20 69 73 20 72 75 6e 6e 69 |.WJG OS is runni|
00000170 6e 67 20 2e 2e 2e 0d 0a 0d 0a 00 00 00 00 00 00 |ng ………….|
00000180 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |…………….|
*
00000210 00 00 00 00 00 00 00 00 00 00 00 00 06 03 55 aa |…………..U.|
00000220

接下来干什么呢?是的,要去掉这32个字节的文件头部(tools/build.c的功能之一就是这个)!随手编个小的文件读写程序都可以去掉它。不过,懒且聪明的人会在Ubuntu下用命令:

wjg@v-m:~/oslab/linux-0.11/boot$ dd bs=1 if=bootsect of=Image skip=32
记录了512+0 的读入
记录了512+0 的写出
512 bytes copied, 0.00156749 s, 327 kB/s

生成的Image就是去掉文件头的bootsect,正好512字节。 [

](http://www.wjgbaby.com/wp-content/uploads/2018/05/18053103.jpg)](http://www.wjgbaby.com/wp-content/uploads/2018/05/18053103.jpg) 去掉这32个字节后,将生成的文件拷贝到linux-0.11目录下,并一定要命名为“Image”(注意大小写)。然后就“run”吧! [![](http://www.wjgbaby.com/wp-content/uploads/2018/05/18053104.jpg)
](http://www.wjgbaby.com/wp-content/uploads/2018/05/18053103.jpg)](http://www.wjgbaby.com/wp-content/uploads/2018/05/18053103.jpg) 去掉这32个字节后,将生成的文件拷贝到linux-0.11目录下,并一定要命名为“Image”(注意大小写)。然后就“run”吧! [![](http://www.wjgbaby.com/wp-content/uploads/2018/05/18053104.jpg)

参考链接:

操作系统原理与实践

课程链接:

操作系统之基础

操作系统之进程与线程

操作系统之内存管理

操作系统之外设与文件系统

所需资源下载:

GitHub