说在前面
做了一个" 艰难的" 决定。本书是在2009 年11 月22 日买的,到现在已经一年多了,大多数时间它都是在睡大觉。毕竟是"x86 汇编" 和" 操作系统" 的,听上去感觉相当的古老和神秘!以前上80x86 汇编语言课时,我就体验过它的云里雾里了,要学好它,一定要有打持久战和攻坚战的心理准备。
现在我来到华清远见嵌入式长期班培训,难得有这份闲情逸致来研究一下操作系统。(课程很多,忙里偷闲)
本章的操作系统麻雀虽小五脏甚至连胚胎都还不是,但我相信,在作者的“ 步步为营是我们的战术,成就感是我们的宗旨” 的引领下,麻雀终有长成大雕的一天。
就让我们摘掉酒瓶底,换上哈勃望远镜,一起窥视OS 的那些事吧!( 最近把眼镜给戒了^^)
马上动手写一个最小的“ 操作系统”
虽说万事开头难,但有时也未必。比如说,写一个有实用价值的操作系统是一项艰巨的工作,但一个最小的操作系统或许很容易就实现了。现在我们就来实现一个小得无法再小的“ 操作系统” ......
1.1 准备工作
对于写程序,准备工作无非就是硬件和软件两方面:
1. 硬件
一台计算机(linux 操作系统或windows 操作系统) ( 我的环境是window xp + vmware6 + ubuntu8.10 )
一张空白软盘 ( 现在这东东可不好找! )
2. 软件
汇编编译器NASM ( 为什么要选它? )
软盘绝对扇区读写工具, linux 下可用dd 命令
1.2 十分钟完成的操作系统
org 07c00h ; 告诉编译器程序加载到7c00 处
mov ax, cs
mov ds, ax
mov es, ax
call DispStr ; 调用显示字符串例程
jmp $ ; 无限循环
DispStr:
mov ax, BootMessage
mov bp, ax ;ES:BP = 串地址
mov cx, 16 ;CX = 串长度
mov ax, 01301h ;AH = 13, AL = 01h
mov bx, 000ch ; 页号为 0(BH = 0) 黑底红字 (BL = 0ch , 高亮 )
mov dl, 0
int 10h ;10h 号中断
ret
BootMessage: db "Hello, OS world!"
times 510-($-$$) db 0 ; 填充剩下的空间,使生成的二进制代码恰好为512 字节
dw 0xaa55 ; 结束标志
保存为boot.asm 。
编译一下:nasm boot.asm -o boot.bin
别急,NASM 都还没装呢!
1.3 引导扇区
如果选择从软盘启动,计算机会检查软盘的0 面0 磁道1 扇区 ,若发现它以0xAA55 结束 ,则BIOS 认为它是一个引导扇区 。一旦BIOS 发现了引导扇区,就会将512 字节的内容装载到内存0000:7c00 处, 然后跳转到0000:7c00 处将控制权交给这段引导代码。
1.4 代码解释
1. 方括号[]
在NASM 中任何 不被方括号[] 括起来的标签或变量名都被认为是地址 。
2.$ 和 $$
$ 表示当前行被汇编后的地址;$$ 表示一个节(section )的开始处被汇编后的地址, 在本程序中$$ 实际就是0x7c00 。times 510-($-$$) db 0 表示将这个字节重复510- ($-$$ )遍,把剩下的空间不停地填0 ,直到510 字节为止,加结束标志0xaa55 占用的2 字节,恰好是512 字节。
3.网友Hector解释得非常详细,直接引用过来:
table.MsoNormalTable { font-size: 10pt; font-family: "Times New Roman"; }
这个代码段是存于磁盘引导扇区的系统引导(自举)程序。若存于硬盘第一个扇区,则这段代码称为:硬盘主引导记录;若存于硬盘某个分区的第一个扇区,则称为:分区引导记录;若存于软盘的第一个扇区,则称为:软盘引导记录。称为磁盘引导记录的重要标志是:
dw 0xaa55
磁盘的一个扇区是512 字节,标志0xaa55 存于这个扇区的最后一个字(两字节,偏移地址为:1FEH ),其余空间用于存储指令代码和一些参数、 提示信息等。磁盘引导记录由ROM BIOS 的INT 19H( 引导加载程序,相当于热启动系统,对应的快捷键为:Ctrl+Alt+Del) ,固定装入内存的0000:7C00H ,然后将控制权交给磁盘引导 程序,相当于开始执行下面的程序段。下面详细解答一下这个程序段的功能:
org 07c00h ;
调整偏移量伪指令ORG
,指定下面的指令从7c00h
处开始,因为BIOS
一旦发现引导扇区,就会将这512
字节装载到内存0000
:7c00
处
mov ax, cs ;
数据传送指令,将代码段寄存器cs
的内容赋给通用寄存器ax
mov ds, ax ;ax→ds
,使数据段与代码段在同一个段
mov es, ax ;ax→es
,使附加段与代码段在同一个段
call DispStr ;
调用子程序DispStr
,显示字符串信息:Hello, OS world!
jmp $ ;$
表示当前地址,实现死循环
DispStr: ;
子程序:显示字符串
mov ax, BootMessage ;BootMessage
的首地址给ax
mov bp, ax ;BootMessage
首地址给堆栈指针BP
mov cx, 16 ;
要显示的字符数
mov ax, 01301h ;AH=13h
,int 10h
,即视频中断13h
号功能:写字符串;AL=01H
,表示写完字符串后,更新光标位置
mov bx, 000ch ;BH=0
,页号(视频缓冲区是分页的),初学者暂时不必理会;BL=0CH
,字符显示属性,以黑底亮红显示字符
mov dl, 0 ;DH
、DL=
写串的光标位置,DH=
行号,DL=
列号
int 10h ;
调用视频中断
ret ;
子程序返回指令,返回调用者
BootMessage: db “Hello, OS world!” ;
要显示的字符串信息
times 510-($-$$) db 0 ;$
是当前地址,$$
是首地址,总体意思就是从此处一直到510
都用0
填充
dw 0xaa55 ;
磁盘引导记录重要标志 ,最后2
个字节代表这是引导扇区。
1.5 水面下的冰山
每一个问题都是一把锁,你要相信,世界上一定存在在把钥匙 可以打开这把锁。你也一定能找到这把钥匙。