写操作系统的热情不是一蹴而就的,需要语言功底的积累,当然每个人去选择以写一个属于自己的玩具内核OS来挑战自己并在挑战的过程中享受自我的时候,所考虑的初衷都是不一的,更深层次的去探究底层,去了解计算机的本质。
当你原生的接触到以前被隐匿在操作系统的外壳下那些最底层的硬件机构——寄存器的时候,你会得到一种莫名的成就感。
当你自己的操作系统引导起来的时候,可能尽管只是一个bootloader,连操作系统都称不上,但是它没有任何的其他依赖,是直接运行在裸机上的,这时候你就会感受到难以抑制的喜悦。
当你小有成就的时候,你可以自豪的像别人炫耀,这是我自己的操作系统,我可以设计它运行的规则秩序,这是我的地盘!
无论你的初衷是什么,希望能一直坚持下去,遇到问题请百度或者谷歌。
关于操作系统
What’s a kernel
It handles events generated by hardware (called interrupts) and software (called system calls), and manages access to resources.
什么是操作系统!?
简而言之,就是能够处理来自硬件的中断和软件的调用,并能够管理计算机所拥有的一切资源。
关于开发环境
在开发任何项目之前,必然是环境的搭建,有时候选择一个合适的开发环境,可以事半功倍。
windows还是linux?
毫无疑问的当然是linux,在linux下面你有众多的开源软件,使用apt-get你可以很快搭建起来一个开发平台。
你有Makefile、shell等脚本,可以很容易的处理你的任务。
我的开发环境
:
操作系统:kali linux
编译器:nasm、gcc
链接器:ld
虚拟机:qemu
环境搭建
:
apt-get install build-essential nasm qemu
关于Makefile
在linux下面工程的开发可以说必须配置一个Makefile,有了Makefile就不必每次都去敲gcc -o output input.c
,在工程下面文件少了还比较好管理,一旦文件多起来,如果每次都是去敲gcc...
这样去编译你的项目基本是不可能的。
Makefile可以简单的理解为基于依赖的编译规则,其中依赖是靠递归的方式去构建的。
这里有两个教程,个人觉得都挺好的
1.Makefile经典教程(掌握这些足够)
2.这是老外的一个教程A Simple Makefile Tutorial
这两个教程讲的都挺明白,读完之后会发现关于Makefile明朗了许多。
裸机的Hello world
全世界程序员的潜规则——Hello world!
到这里你需要准备好前面的开发环境配置,接下来会用到汇编编译器和虚拟机qemu。
用软盘写一个引导扇区的Hello world汇编程序其实挺简单的
;%define _BOOT_DEBUG_ ; 做 Boot Sector 时一定将此行注释掉!将此行打开后用 nasm Boot.asm -o Boot.com 做成一个.COM文件易于调试
%ifdef _BOOT_DEBUG_
org 0400h ; 调试状态, 做成 .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, 21 ; CX = 串长度
mov ax, 01301h ; AH = 13, AL = 01h
mov bx, 000ch ; 页号为0(BH = 0) 黑底红字(BL = 0Ch,高亮)
mov dl, 0
int 10h ; int 10h
ret
BootMessage: db "Hello, AtkOS world ! "
; 填充剩下的空间,使生成的二进制代码恰好为512字节
times 510-($-$$) db 0
dw 0xaa55 ; 结束标志
将上述汇编保存为boot.asm
。
Makefile如下:
S_SRC=boot.asm
S_OBJ=boot.bin
OBJ=boot.img
ASM=nasm
#Note that make with no arguments executes the first rule in the file
all:$(S_OBJ) update_image
$(S_OBJ):$(S_SRC)
@echo 编译汇编文件
$(ASM) $< -o $@
.PHONY:update_image
update_image:
dd if=$(S_OBJ) of=$(OBJ) bs=512 count=1
.PHONY:qemu
qemu:
qemu-system-i386 -fda boot.img -boot a -m 64 -localtime
.PHONY:clean
clean:
-rm -f $(OBJ) $(S_OBJ)
然后编译:make
。
在qemu里面运行查看效果:make qemu
。
在我的电脑上效果如下:
到这里为止,我们已经在裸机上运行我们的引导程序了,是不是小有成就感了。
关于引导的思考
不知道你阅读的时候有没有发现上面是使用的软盘镜像.img
+虚拟机qemu
得到的实验结果,现在软盘已经基本不存在了,为什么还要使用软盘镜像呢,答案其实很简单。
就是因为简单!
一开始做的时候想把引导扇区放在U盘里面,然后从真机里面起来,于是就把上面做好的用于引导的软盘镜像img用dd命令刻录到u盘里面。
结果发现用dd if=boot.img of=/dev/sdb bs=512 count=1
命令将刚生成的软盘镜像刻到U盘里面时,系统根本就引导不起来。
然后想是不是因为dd命令并没有将我生成的软盘镜像刻录到U盘的引导扇区,就是通常所说的MBR,主引导记录,决定切换到windows下面用powerIso重新将软盘镜像刻录到U盘里面,结果重新开机还是无果。
后来才知道所有的U盘都有512字节的引导,其中前446字节存的是引导记录,中间64字节存的是DPT分区表,最后两个字节是0x55aa。
一开始觉得有点奇怪,就随便找了一个U盘,把里面的前512个字节读了出来:dd if=/dev/sdb of=bootsec.img bs=512 count=1
然后将bootsec.img拖到sublime text里面发现果真最后两个字节就是0x55aa!!瞬间就惊呆了!!
对!没错,就是操作系统判定是否是引导盘的最后两个字节0x55aa。
后面就先将U盘引导放下了,转向了用虚拟软盘镜像+虚拟机qemu,就看到了系统引导起来的效果。