版权说明:本文档由用户提供并上传,收益归属内容提供方,若内容存在侵权,请进行举报或认领
文档简介
若何编写自己的操作系统
有人可能担忧自己既没有学过计算机原理,也没有学过操作系统原理,更不懂汇编语言,
对C语言也一知半解,能写操作系统吗答案是没问题。我将带大家一步一步完成自己的操
作系统。
当然如果学一学上述内容再好不过。
首先要明确处理器(也就是CPU)控制着计算机。对PC而言,启动的时候,CPU都处在实模
式状态,
相当于只是一个Intel8086处理涔。也就是说,即使你现在拥有一个奔腾处理器,它的功能
也只能
是8086级别。从这一点上来讲,可以使用一些软件把处理器转换到著名的保护模式。只有
这样,
我们才可以充分利用处理器的强大功能。
编写操作系统开场是对BIOS控制,取出存储在ROM里的程序。BIOS是用来执行
POST(PowerOnSelfTest,
自检)的。自检是检查计算机的完整性(比方外设是否工作正常、键盘是否连接等)。这一切完
成以后,
你就会听到PC喇叭发出一声清脆的响声。如果一切正常,BIOS就会选择一个启动设备,
并且读取该设备的第一扇区(即启动扇区),然后控制过程就会转移到指定位置。
启动设备可能是一个软盘、光盘、硬盘,或者其它所选择的设备。在此我们把软盘作为启动
设备。
如果我们已经在软盘的启动扇区里写了一些代码,这时它就被执行。因此,我们的目的很明
确,
就是往软盘的启动扇区写一些程序。
首先使用8086汇编来写一个小程序,然后将其拷贝至软盘的启动扇区。为了实现拷贝,要
写一个C程序。
最后,使用软盘启动计算机。
需要的工具
•as86:这是一个汇编程序,它负责把写的代码转换成目标文件。
•ld86:这是一个连接器,as86产生的FI标代码由它来转换成真正的机器语言。
机器语言是8086能够解读的形式。
•GCC:著名的C编程器。因为我们需要写一个C程序将自己的OS转移到软盘中。
•一张空软盘:它用于存储编写的操作系统,也是启动设备。
・一台装有Linux的计算机:这台机器可以很旧,386、486都可以。
在大局部标准Linux发行版中都会带有as86和ld86。在我使用的RedHat7.3中就包含有这
两个工具,
并且在默认的情况下,它已经安装在机器里。如果使用的Linux没有这两个工具,可以从网
上下载
(://cix.co.uk/~mayday/),这两个工具都包含在一个名为bin86的软件包中。
此外,有关的文档也可以在网上获得
(/docs/ldp/howlo/Assembly-HOWTO/as86.html)o
开场工作
使用一个你喜欢的编辑器输入以下内容:
entrystart
start:
movax,#Oxb8OO
moves,ax
seges
mov[0],#0x41
seges
mov[l],#Oxlf
loopl:jmploopl
这是as86可以读懂的一段汇编程序。第一个句子指明了程序的入n点,声明整个过程从start
处开场。
第二行指明了start的位置,说明整个程序要从start处开场执行。0xb800是显存的开场地址。
#说明其后是一个立即数。执行语句:
movax,#oxb8(X)
ax存放器的值就变为Oxb8OO,这就是显存的地址。下面再将这个值移至es存放器,?s是
附加段存放器。
请记住8086有一个分段的体系构造。它的各段存放器为代码段、数据段、堆栈段和附加段,
对应的存放器名称分别为cs、ds、ss和es。事实上,我们把显存地址送入了附加段,因此,
仃•何送入附加段的东西都会被送到显存中。
要在屏幕上显示字符,就需要向显存中写两个字节。前一个是所要显示字符的ASCII值,
第二个字节表示该字符的属性。属性包括字符的前风光、背风光及是否闪烁等等。
seges指明下一个将要执行的指令是指向es段的。所以,我们把值0x41(在ASCII中表示的
字符是A)送到
显存的第一个字节中。接下来要把字符的属性送到下一个字节当中。在此输入的是Oxlf,
该属性指的是在蓝色背景下显示白色的字符。因此,如果执行这个程序,
就可以在屏幕上得到显示在蓝底上的一个白色的Ao接着是一个循环。
因为在执行完显示字符的任务后,要么让程序完毕,要么使用•个循环使其永远运行下去。
把该文件命名为boot.s,然后存盘。
2若何编写自己的操作系统
此处显存的概念说得不是很清楚,有必要进一步解释一下。假设屏幕由80列X25行组成,
那么第一行就需要16()字节,其中一个字节用于表示字符,另外一个字节用于表示字符的属
性。
如果要在第三行显示某•字符的话,就要跳过显存的第。和1字节(它们是用于显示第1列
的),
第2和3字节(它们是用于显示第2列的),然后把需要显示字符的ASCH码值入第4字节,
把字符的属性写入第5字节。
把程序写至启动扇区
下面写一个C程序,把我的操作系统写入软盘第一扇区。程序内容如下:
#include/*unistd.h需要这个文件*/
#include/*包含有read和write函数*/
#include
intmain()
charboot_buf[512];
intfloppy_dcsc,filc_desc;
file.desc=open("./boot",O_RDONLY);
rcad(filc_dcsc,boot_buf,510);
close(file_desc);
boot_buf[510]=0x55;
boot_buf]511J=Oxaa;
floppy_desc=open('7dev/fd0",O_RDWR);
lseek(floppy_desc,0,SEEK_CUR);
write(floppy_desc.boot_buf,512);
close(floppy_dcsc);
}
首先,以只读模式翻开bod文件,然后在翻开文件时把文件描述符复制到file_desc变量中。
从文件中读取510个字符,或者读取直到文件完毕。在本例中由于文件很小,所以是读取至
文件完毕
O然后关闭文件。
最后4行代码翻开软盘驱动设备(一般来说是/dev/fdO)。使用Iseek找到文件开场处,
然后从缓冲中向软盘写512个字节。
在read、write>open和hcck的帮助页中,可以看到与函数所有有美的参数及其使用方法。
程序中有两行比较难懂:
boot_buf[510]=0x55;
boot_buf[511]=Oxaa;
该信息是用于BIOS的,如果它识别出该设备是一个可启动的设备,那么在第510和511的
位置,
该值就应该是0x55和Oxaao程序会把文件boot读至名为bootjmf的缓冲中。
它要求改变第510和第511字节,然后把boojbuf写至软盘之上。如果执行代码,
软盘上的前512字节就包含了启动代码。最后,把文件存为write.c。
编译运行
使用下面的命令把文件变为可执行文件:
as86boot.s-oboot.o
Id86-dboot.o-oboot
ccwrite.c-owrite
首先将boot.s文件编译成目标文件boot.。,然后将该文件连接成最终的bool文件。
最后C程序编译成可执行的write文件。
插入一个空白软盘,运行以下程序:
./write
重新启动电脑,进展BIOS的界面设置.,并且把软盘设为第一个启动的设备。然后插入软盘,
电脑从软盘上启动。
启动完成后,在屏幕上可以看到一个字母A(蓝底白字),启动速度很快,几乎是在瞬间完成。
这就意味着系统已经从我们制作的软盘上启动了,并且执行了刚刚写入启动扇区的程序。
现在,它正处在一个无限循环的状态。所以,如果想进入Linux,必需拿掉软盘,并且重启
机器。
至此,这个操作系统就算完成了,虽然它没有实现什么功能,但是它己经可以启动机器了。
下一期我将在这个启动扇区程序里参加一些代码,使它可以做一些比较复杂的事情
(比方使用BIOS中断、保护模式切换等等)。
0x5000,
即偏移地址为0)。这时我们需要使用BIOS的中断13ho这时启动扇区的代码就会把控制权
转移至0x500处。
在第二个汇编文件中,代玛会使用BIOS中断IOh在屏幕上显示一个信息。C程序实现的功
能那么是把可
执行的文件I拷贝至启动扇区,把可执行的文件2拷贝至软盘的第二扇区.
启动扇区代码
使用中断I3h,启动扇区把软盘第二扇区里的内容加载至内存的0x500()处(段地址为0x500)。
下面的代码是用于实现这一目的的代码,将其保存至文件sbect.s中。
LOCI=0x500
entrystart
start:
movax,#LOCI
moves,ax
movbx,#()
movdl,#0
movdh,#O
movch,#0
movcl,#2
moval,#I
movah,#2
int()xl3
jmpi0,#LOC1
上面代码第一行类似于一个宏。接下去的两行那么是把值0x500加载至es存放器中,
这是软盘上第二扇区代码将拷贝到的地方(第一扇区是启动扇区)。这时,把段内的偏移设为
0o
接下来把驱动器号送入<11存放器中,其中磁头号送入(11存放器中,磁道号送入ch存放器中,
扇区号送入cl存放器中,扇区数送入al存放器之中。我们想要实现的功能是把扇区2、磁
道号为0、驱动器号为。的内容送至段地址0x500处。所有这些参数都和L44MB的软盘相
对应。
把2送入ah存放器中,是选择了由中断13h提供的相应功能,即实现从软驱转移数据的功
能。
最后调用中断13h,并且转至偏移为0的段地址0x500处。
第二个扇区的代码
第二个扇区中的代码如下所示(把这些代码保存至文件sbect2.s之中):
entrystart
start:
movah,#0x03
xorbh,bh
int0x10
movcx,#26
movbx,#0x0007
movbp,#mymsg
movax,#0x1301
intOx10
loopl:jmploopl
mymsg:
.byte13,10
.ascii"OperatingSystemisLoading....."
上面代码将被加载至段地址为0x500处,并且被执行。在这段代码中,使用了中断IOh来获
取目前的光标
位置,然后显示信息。
从第3行到第5行用于得到目前光标的位置,在此中断IOh选用的是功能3。然后,去除了
bh存放器的内容,
并把字符串送至ch存放器中。在bx中,我们送入了页码及显示的属性。此处,我们想要在
黑背景上显示
白色的字符。然后,把要显示字符的地址送到bp之中,信息由两个字节组成,其值分别为
13的10,
它们分别对应回车和LF(换行)的ASCII值。接下来是一个由29个字符组成的串;在下面实
现的功能是
输出字符串然后移动光标;最后是调用中断,然后进入循环。
4若何编写自己的操作系统
C程序代码
C程序的源代码如下所示,将其存储为write.c文件。
#include/*unistd.hneedsthis*/
#include/*containsread/write*/
#includc
intmain()
(
charboot_buH512];
intfloppy_desc,file_desc;
file_desc=open("./bsect",O_RDONLY);
read(file_desc,boot_buf,510);
close(file_desc);
boot_buf[510]=0x55;
boot_buf[511]=Oxaa;
floppy_desc=open('7dev/f(10",O_RDWR);
lseek(floppy_desc,0,SEEK_SET);
write(floppy_desc,boot_buf,512);
file_desc=open("./sect2",O_RDONLY);
read(file_desc,boot_buf,512);
close(file_desc);
lseek(floppy_desc,512,SEEK_SET);
write(floppy_desc,boot_buf,512);
close(floppy_desc);
在上一期中,我曾经介绍过若何操作能启动的软盘。现在这一个过程稍微有点不同,
首先把由bsect.s编译出来的可执行文件bsect拷贝至软盘的启动扇区。然后再把由sect2.s
产生的可执行
文件scct2拷贝至软盘的第二个扇区。
把上述文件置于同一目录之下,然后分别对其进展编译,方法如下所示:
as86bsect.s-obsect.o
ld86-dbsect.o-obsect
对sect2.s文件重复以上的操作,得出可执行文件sect2o编译write.c,插入软盘后执行write
文件,
命令如下所示:
ccwritc.c-owrite
./write
下一步我们要做的事情
从软盘启动以后,可以看到显示出来的字符串。这是使用了BIOS中断来完成的。
下一期要做的事情是在这个操作系统中实现实模式向保护模式的转换。
自己动手写操作系统(三)
在上两期中(自己动手写操作系统1,2),我向大家讲述了若何使用Linux提供的开发工具
在软盘的启动
扇区写一些代码,以及若何调用DIOS的问题。现在,这个操作系统已经越来越接近当年
LinusTorvalds的
那个具有“历史意义”的Linux内核了。因此,要马上把这个系统切换到保护模式之下。
什么是保护模式
自从1969年推出第一个微处理器以来,Intel处理器就在不断地更新换代,从8086、8。88、
80286,
到80386、80486、奔腾、奔腾II、奔腾4等,其体系构造也在不断变化。80386以后,
提供了一些新的功能,弥补了8086的一些缺陷。这其中包括内存保护、多任务及使用640KB
以上的内存等,
井仍然保持和8086家族的兼容性。也就是说80386仍然具备了8086和80286的所有功能,
但是在功能上有了很大的增强。早期的处理器是工作在实模式之下的,80286以后引入了保
护模式,
而在80386以后保护模式又进展了很大的改进。在80386中,保护模式为程序员提供了更好
的保护,
提供了更多的内存。事实上,保护模式的目的不是为了保护程序,而是要保护程序以外的所
有程序
(包括操作系统)。
简言之,保护模式是处理器的一种最自然的模式。在这种模式下,处理器的所有指令及体系
构造的所有
特色都是可用的,并且能够到达最高的性能。
保护模式和实模式
从外表上看,保护模式和实模式并没有太大的区别,二者都使用了内存段、中断和设备驱动
来处理硬件
,但二者有很多不同之处.我们知道,在实模式中内存被划分成段,每个段的大小为64KB,
而这样的段地址可以用16位来表示。内存段的处理是通过和段存放器相关联的内部机制来
处理的,
这些段存放器(CS.DS、SS和ES)的内容形成了物理地址的一局部。具体来说,最终的
物理地址是由
16位的段地址和16位的段内偏移地址组成的。用公式表示为:
物理地址二左移4位的段地址+偏移地址。
在保护模式下,段是通过一系列被称之为“描述符表”的表所定义的。段存放器存储的是指向
这
些表的指针。用于定义内存段的表有两种:全局描述符表(GDT)和局部描述符表(LDT)°GDT
是一个段描述
符数组,其中包含所有应用程序都可以使用的基本描述符。在实模式中,段长是固定的(为
64KB),
而在保护模式中,段长是可变的,其最大可达4GB。LDT也是段描述符的一个数组。与GDT
不同,
LDT是一个段,其中存放的是局部的、不需要全局共享的段描述符。每一个操作系统都必
须定义一个GDT,
而每一个正在运行的任务都会有一个相应的LDTo每一个描述符的长度是8个字节,格式
如图3所示。
当段存放器被加载的时候,段基地址就会从相应的表入口获得。描述符的内容会被存储在一
个程序员不可
见的影像存放那(shadowregister)之中,以便下一次同一个段可以使用该信息而不用每次都到
表中提取
。物理地址由16位或者32位的偏移加上影像存放器中的基址组成。实模式和保护模式的不
同可以从图1
和图2中很清楚地看出来,
5若何编写自己的操作系统
图1实模式的寻址
图2保护模式下的寻址
图3段描述俯的格式
此外,还有一个中断描述符表(IDT)。这些中断描述符会告诉处理器到那里可以找到中断处
理程序。
和实模式一样,每一个中断都有一个入口,但是这些入口的格式却完全不同。
因为在切换到保护模式的过程中没有使用到IDT,所以在此就不多做介绍了。
进入保护模式
80386有4个32位控制存放器,名字分别为CRO、CR1、CR2和CR3。CR1是保存在未来
处理器中使用的,
在80386中没有定义。CR0包含系统的控制标志,用于控制处理器的操作模式和状态。CR2
和CR3是用于
控制分页机制的。在此,我们关注的是CR0存放器的PE位控制,它负责实模式和保护模式
之间的切换。
当PE=1时,说明处理器运行于保护模式之下,其采用的段机制和前面所述的相应内容对应。
如果PE=0,
那么处理器就工作在实模式之下。
切换到保护模式,实际就是把PE位置为1。为了把系统切换到保护模式,还要做•些其它
的事情。
程序必须要对系统的段存放器和控制存放器进展初始化。把PE位置1后,还要执行跳转指
令。
过程简述如下:
1.创立GDT表;
2.通过置PE位为1进入保护模式;
3.执行跳转以去除在实模式下读取的任何指令。
下面使用代码来实现这个切换过程。
需要的东西
♦一张空白软盘
♦NASM编译器
下面是整个程序的源代码:
org0x07c00;起始地址是0000:7c00
jmpshortbegin_boot;跳过其它的数据,跳转到引导程序的开场处
boolmesgdb"OurOSbootsectorloading....."
pm_mesgdb"Switchingtoprotectedmode
dw512;每一扇区的字节数
dbl;每一簇的扇区数
dw1;保存的扇区号
db2
dwOxOOcO
dw0x0b40
dbOxOfO
dw9
dw18
dw2;读写扇区号
dwO;隐藏扇区号
print_mcsg:
movah,0xl3;使用中断IOh的功能13,在屏幕上写一个字符串
movai,0x00;决定调用函数后光标所处的位置
movbx,0x0(X)7;设置显示属性
movcx,0x20;在此字符串长度为32
movdx,0x0000;光标的起始行和列
int0x10;调用BIOS的中断10h
ret;返回调用程序
get_key:
movah,0x00
ini0xl6;Get_key使用中断I6h的功能0,读取下一个字符
ret
clrscr:
movax,0x0600;使用中断10h的功能6,实现卷屏,如果al=0那么清屏
movex,0x0000;清屏
movdx,0x174f;卷屏至23,79
movbh,0;使用颜色0来填充
ini0x10;调用JOh中断
ret
bcgin_boot:
callcirscr;先清屏
movbp,bootmesg;提供串地址
callprinl_mesg;输出信息
callget_key;等待用户按下任一键
bits16
callcirscr;清屏
movax,()xh8()();使gs指向显示内存
movgs,ax;在实模式下显示一个棕色的A
movwordlgs:O],0x641;显示
callget_key;调用Get_key等待用户按下任一键
movbp,pm_mesg;设置市指针
callprinl_mesg;调用print_mesg子程序
callget_key;等待按键
callcirscr;清屏
cli;关中断
lgdt[gdtr];加载GDT
movcax,crO
oral,0x01;设置保护模式位
movcrO,eax;将更改后的字送至控制存放器中
jmpcodesei:go_pm
bits32
go_pm:
movax,datascl
movds,ax;初始化ds和es,使其指向数据段
moves,ax
movax,videosei;初始化gs,使其指向显示内存
movgs,ax
movword[gs:0],0x74l;在保护模式下显示一个白色的字符A
spin:jmpspin;循环
bits16
gdtr:
dwgdt_end-gdt-1;gdt的长度
ddgdt;gdt的物理地址
gdt
nullseiequ$-gdt;$指向当前位置,所以nullsel=Oh
gdtO;空描述符
ddO
dd0;所有的段描述符都是64位的
codeseiequ$-gdt;这是8h也就是gdt的第二个描述符
6若何编写自己的操作系统
code_gdt
dwOxOffff;段描述符的界限是4Gb
dwOxOOOO
db0x00
db0x09a
dbOxOcf
db0x00
daiaselequ$-gdt
data_gdt
dwOxOffff
dwOxOOOO
db0x00
db0x092
dbOxOcf
db0x00
videoseiequ$-gdt
dw3999
dw0x8000;基址是0xb8000
db0x0b
db0x92
db0x00
db0x00
gdt_end
times510-($-$$)db0
dwOxOaa55
把上面的代码存在一个名为abc.asm的文件之中,使用令令nasmabc.asm,将得出一个名为
abc的文件。
然后插入软盘,输入命令:ddif=abcof=/dev/fdOo该命令将把文件abc写入到软盘的第一扇
区之中。
然后重新启动系统,就会看到如下的信息:
*Ourosbooting................
*A(棕色)
*Switchingtoprotectedmode....
*A(白色)
对代码的解释
上面给出了所有的代码,下面我对上述代码做一些解释。
♦使用的函数
下面是代码中一些函数的说明:
print_mesg该子程序使用了BIOS中断10h的功能13h,即向屏幕写一字符串。属性控制是
通过向一些寄
存器中送入不同的值来实现的。中断10h是用于各种字符串操作,我们把子功能号13h送到
ah中,
用于指明要打印一个字符串。al存放器中的0说明了光标返回的起始位置,0表示调用函数
后光标返回到
下一行的行首。如果al为1那么表示光标位于最后一个字符处。
显存被分成了几页,在同一时刻只能显示其中的一页。bh指明的是页号;bl那么指明要显
示字符的颜色
:CX指明要显示字符串的长度;dx指明光标的位置(即起始的行和列)。所有相关存放器初始
化完成以后,
就可以调用BIOS中断IOh了。
get_key使用中断16h的子功能00h,从屏幕得到下一个字符。
clrscr该函数使用了中断l()h的另外一个子功能06h,用于输出开场前清屏。初始化时给al
中送入0。
存放器ex和dx指
温馨提示
- 1. 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。图纸软件为CAD,CAXA,PROE,UG,SolidWorks等.压缩文件请下载最新的WinRAR软件解压。
- 2. 本站的文档不包含任何第三方提供的附件图纸等,如果需要附件,请联系上传者。文件的所有权益归上传用户所有。
- 3. 本站RAR压缩包中若带图纸,网页内容里面会有图纸预览,若没有图纸预览就没有图纸。
- 4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
- 5. 人人文库网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
- 6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
- 7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。
最新文档
- 2026年克拉玛依市克拉玛依区工会人员招聘考试参考题库及答案详解
- 2026年通化市东昌区政务服务中心(窗口人员)招聘笔试备考题库及答案详解
- 2026年太原市万柏林区政务服务中心(窗口人员)招聘考试备考题库及答案详解
- 遂宁市2026年“筑梦巴蜀·万才兴农”农业农村领域经营主体招聘 (第二期)考试参考题库及答案详解
- 2026年江西省上饶市医疗系统事业编人员招聘笔试备考试题及答案详解
- 2025年南京市浦口区政务服务中心(窗口人员)招聘笔试试题及答案详解
- 2026大湾区大学行政岗位招聘3人笔试备考题库及答案详解
- 2026年8月自贡汇东建设工程有限责任公司市场化选聘职业经理人笔试模拟试题及答案详解
- 2025年大同市南郊区医疗系统事业编人员招聘笔试试题及答案详解
- 2025年鄂州市梁子湖区医疗系统事业编人员招聘笔试试题及答案详解
- 牛结节病的症状和治疗方法
- 企业违反纪律检讨书范文(8篇)
- 《非遗手工技艺(拓印)》课件-第一章 拓片的由来和历史
- 工程量清单及招标控制价编制服务采购实施方案
- (高清版)JTGT 5440-2018 公路隧道加固技术规范
- (正式版)QBT 2821-2024 金属晾衣架
- 施工方案设计的经济性与可行性分析
- 汽车钢管激光打标自动化产线课件
- 国际红十字运动的基本知识
- 中药注射剂合理应用手册
- 新版ISO45001培训课件
评论
0/150
提交评论