《自己动手写操作系统》学习笔记目录(持续更新) http://www.techbulo.com/832.html
一直以来自己就想写个操作系统,虽然也看过不少操作系统的书籍,但大多都是讲理论,完全没有教给你这么实现一个操作系统,哪怕他再简单!忽然有一天我发现了一本书《自己动手写操作系统》于渊著,对书中的内容深深吸引,随即买了一本仔细阅读并一边实践,从今天开始我将学习的过程以及遇到的问题一一记录下来,便于日后查阅。
一.今天首先说一下需要用到的工具,包括硬件和软件:
1.硬件
— 一台计算机(Windows操作系统)
— 一张空白软盘(现在电脑几乎没有使用软盘的,可以使用虚拟软盘,见后续章节)
2.软件
— 汇编编译器NASM。最新版本可以在此链接处获得:http://sourceforge.net/projects/nasm
— 软盘绝对扇区读写工具(FloppyWriter.exe)
二.最简单的启动扇区分析
%define _BOOT_DEBUG_ ; 做 Boot Sector 时一定将此行注释掉! ;将此行打开后用 nasm Boot.asm -o Boot.com ;做成一个.COM文件易于调试 %ifdef _BOOT_DEBUG_ org 0100h ; 调试状态, 做成 .COM 文件, 可调试 %else org 07c00h ; Boot 状态, Bios 将把 Boot Sector 加载到 0:7C00 处并开始执行 %endif 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 ; 结束标志
先解释几个伪指令:
1.org伪指令
org 07C00h
格式:ORG 数值表达式
其中,ORG(origin)是操作码,不可省略。表达式给出偏移地址值,即ORG语句后的指令或数据以表达式给出的值作为起始的偏移地址。表达式必须是一个可计算得到的正整数,数值范围在0~65 535之间。
ORG伪指令用来指出其后的程序段或数据块存放的起始地址的偏移量。汇编程序汇编时把语句中表达式的值作为起始地址,连续存放ORG语句之后的程序和数据,直到出现一个新的ORG指令。若省略ORG语句,则从本段起始地址开始连续存放。
在大多数情况下,不需要用ORG语句设置位置指针。由于段定义语句是段的起点,它的偏移地址为0000H,以后每分配一个字节,位置指针自动加1,所以每条指令都有确定的偏移地址。只有程序要求改变这个位置指针时,才需要安排ORG语句。通常ORG语句可以出现在程序中任何位置上。
我们知道编译器本身在汇编时对指令的地址计算是相对地址,而对于引导扇区,是按绝对地址执行,那么对于用相对地址编译的执行码就要换算成绝对地址。一般而言,“真实开始执行的引导扇区”都会被BIOS固定装载到07C00h处。
由于编译器在编译时的地址是从第一行开始用0000h开始相对计算的,而且我们要写的是“引导扇区”程序,所以我们要将下面的代码加载到地址07C00h处,所以我们需要org 07C00h,通过该伪指令,将代码和数据加载到07C00h地址。
如果你对上边的解释还不是很理解,可以看这篇文章《引导程序为什么要org 07c00h》
下面ORG伪指令举个例子:
下列变量定义,并且变量word1的偏移量为0
word1 DW 1234h
byte1 DB 56h
word2 DW abcdh
org 0001h
byte2 DB ?
word3 DW ?
byte3 DB ?
故如下图所示:
2、
jmp $
$被称为当前位置计数器
在汇编程序对源程序进行汇编的过程中,使用地址计数器来保证当前正在汇编的指令地址。地址计数器值可用“$”来表示,汇编语言也允许用户直接用“$”来引用地址计数器的当前值,因此,ORG $+5可表示从当前地址开始跳过5个字节存储单元,在指令和伪指令中,也可直接用“$”表示地址计数器的当前值。
故jmp $进入了一个无限循环
3、
int 10h
int 10号中断
int 10H 是由BIOS 对屏幕及显示器所提供的服务程序。使用 INT 10H 中断服务程序时,先设定 AH 寄存器得值,该值表示欲调用的功用,而其他寄存器的详细说明,请参考下侧文章,当一切设定好之后再调用 int 10H。
在这里我们只详细讲解本程序中的10号中断。由于ah=13,故调用编号为13的功能:即显示字符串。其中ES:BP=串地址,CX=串长度 ,AH=13,当AL=01h时,光标会跟随显示移动。BH为页号,BH=0表示页号为0,BL=0CH,表示属性,即黑底红字高亮。
因此在调用10号中断之前,无非就是对各个寄存器进行初始化。
关于10号中断的其他信息,请参考
《BIOS INT 10中断功能详解》
4、
times 510-($-$$) db 0
times:重复指令或数据
times前缀引起指令被汇编多次。其中$$表示是该程序的初始代码段的地址,故该指令将会被执行510-($-$$)次。也就是用0来填充剩下的空间,达到510字节。
5、
dw 0xaa55 ;
引导扇区结束标志