我依稀记得当初看到这一节标题的时候很是很是的兴奋,由于能够用C语言了。windows
首先是咱们要来制做真正的IPL了,回顾一下,IPL就是那512个启动字节,让他来引导真正的操做系统,由于512个字节太少了,不能作太多逻辑。安全
MOV AX,0x0820 MOV ES,AX MOV CH,0 ; 柱面0 MOV DH,0 ; 磁头0 MOV CL,2 ; 扇区2 MOV AH,0x02 ; AH=0x02 : 读盘 MOV AL,1 ; 1个扇区 MOV BX,0 MOV DL,0x00 ; A驱动器 INT 0x13 ; 调用磁盘BIOS JC error
这里又调用了一个中断,上一个中断是向显示器上输出一个字符,这个中断的做用就是对磁盘进行操做的,若是把他看成C语言或者其余高级语言来说会很方便,就是这是个对磁盘操做的函数,而后调用前,你给这些寄存器传一些参数,而后会经过标志位的方式返回读取结果,即CF标志位。函数
介绍一下软盘,这玩意儿淘宝上还能买到,我最开始学的时候买过,实体店早已看不到了,一点几MB的内存,我小仓老师的照片都放不了。。。要它何用。软盘分正反,叫磁头。柱面,能够理解在这个软盘上画了更多的圆圈,而后再分红扇形,也就有了,柱面和扇区。磁盘号是指那么多个软盘,你读哪一个。
咱们的IPL就会放在C0-H0-S1(也就是柱面0,磁头0,扇区1),本人不太理解,为啥柱面从0开始而扇区不是。
这里要介绍个新玩意儿了段寄存器,我记得我在学汇编时很经典的一句话,物理地址=段地址 x 10 + 偏移地址 (基于10进制,若是是16进制x16就行了)。若是指定用法就得把段寄存器与偏移地址写在一起,若是不写默认以DS做为默认段寄存器,昨天就用到了[],暂时还没讲这个东西次。记得和C语言保持一个习惯,变量初始化,这里的DS也记得初始化,否则会读到其余的内存地址去。
by the way Makefile里面的变量特别像PHP里的变量。oop
;多式几回操作系统
MOV AX,0x0820 MOV ES,AX MOV CH,0 ; 柱面0 MOV DH,0 ; 磁头0 MOV CL,2 ; 扇区2 MOV SI,0 ; 记录失败次数
retry:命令行
MOV AH,0x02 ; AH=0x02 : 读盘 MOV AL,1 ; 1个扇区 MOV BX,0 MOV DL,0x00 ; A驱动器 INT 0x13 ; 调用磁盘BIOS JNC fin ; 若OK则跳转至fin ADD SI,1 ; 往SI加1 CMP SI,5 ; 比较SI是否大于5 JAE error ; 若SI >= 5,则跳转到error MOV AH,0x00 MOV DL,0x00 ; A驱动器 INT 0x13 ; 重置驱动器 JMP retry
JNC会去判断CF标志位的状态如果0则会跳转。
JAE大于等于则跳转code
MOV AX,0x0820 MOV ES,AX MOV CH,0 ; 柱面0 MOV DH,0 ; 磁头0 MOV CL,2 ; 扇区2
readloop:内存
MOV SI,0 ;
retry:开发
MOV AH,0x02 ; AH=0x02 : 读盘 MOV AL,1 ; 1个扇区 MOV BX,0 MOV DL,0x00 ; A驱动器 INT 0x13 ; 调用磁盘BIOS JNC next ; 若OK则跳转至next ADD SI,1 ; 往SI加1 CMP SI,5 ; 比较SI是否大于5 JAE error ; 若SI >= 5,则跳转到error MOV AH,0x00 MOV DL,0x00 ; A驱动器 INT 0x13 ; 重置驱动器 JMP retry
next:编译器
MOV AX,ES ; 把内存地址后移0x200(512字节) ADD AX,0x0020 MOV ES,AX ; ADD ES,0x020 由于没有这个指令因此只能找中介 ADD CL,1 ; 往CL里加1 CMP CL,18 ; 比较CL与18 JBE readloop ; 若是CL <= 18 跳转至readloop
JBE只要是拿来控制读取到18扇区的,小于等于则跳转。
咱们知道磁盘读出来后的内容都放到了ES:BX了,然而咱们分别设置了ES与BX,因此程序也就装载到相应位置啦。
接下来是读取是个柱面,这里就不贴代码了。直接说说新指令把。
JB就是小于等于跳转。还有EQU 这个很是建议写一些常常要改的东西这样写,由于稍微作过项目就知道这种玩意儿不写成这样那是找骂呀。
如今磁盘上的180KB字节就存储在ES:BX这个地方啦。没什么太多难度,就是须要每句去理解。
着手开发操做系统啦。。。
这里做者给了一个很是简单的操做系统。。
but...这是历史的转折点,这毕竟是在启动区以外了,咱们要读取IPL以外的代码了,从harib00e(光盘目录)看得出来多了一个文件haribote.nas,这个就是咱们的操做系统啦,由刚才的main函数(IPL),调用到了这边来,而后做者经过二进制软件一顿分析,得出了以下结论 1.文件名会写在0x002600之后的地方 2.文件的内容会写在0x004200之后的地方 其实我在纠结一个问题,要是0x002600-0x004200之间都写了文件名咋办。不过他说的是0x002600之后,并不是之间,嗯,那我就放心了。知道这个文件的内存地址后,如今咱们就要来读取这个文件啦。
从启动区执行操做系统
若是咱们是把程序装载在0的位置那么直接使用0x004200就好了,但问题是操做系统有它应该放的位置,因此前面咱们放在了0x0820的位置,一开始做者说0x8000我小楞了一下,不是放在0x0820位置的吗?(我仍是解释一下,怕有些出血朋友不能理解到)首先,这是个段地址会进行偏移,偏移为0x8200,而后200,一想是512个字节,因此这就是咱们的启动区嘛,因此正确,就是0x8000。因此咱们的程序须要从0x8000+0x4200 = 0xc200地址读取咱们的hairbote.nas文件。
这里又新调用了一个“函数” int 0x10,配合上参数这个的做用是把屏幕弄成VGA图形模式,因此咱们要开始作图形界面啦,而非一部份书是作命令行模式的(固然这并不表明我对那种书的差评,我直是以为一上来作图形界面,会让初学者更又兴趣)
立刻要进入32位模式啦
优势固然是更多的内存空间可使用,与安全性。
; 有关BOOT_INFO
CYLS EQU 0x0ff0 ; 设定启动项
LEDS EQU 0x0ff1
VMODE EQU 0x0ff2 ; 关于颜色数目的信息。颜色的位数
SCRNX EQU 0x0ff4 ; 分辨率的X
SCRNY EQU 0x0ff6 ; 分辨率的Y
VRAM EQU 0x0ff8 ; 图像缓冲区的开始地址
ORG 0xc200 ; 将程序装载到0xc200处 MOV AL,0x13 ; VGA显卡,320*200*8位彩色 MOV AH,0x00 INT 0x10 MOV BYTE [VMODE],8 ; 记录画面模式 MOV WORD [SCRNX],320 MOV WORD [SCRNY],200 MOV DWORD [VRAM],0x000a0000
; 用BIOS去得键盘上各类LED指示灯的状态
MOV AH,0x02 INT 0x16 ; keyboard BIOS MOV [LEDS],AL
这里呢,也没作啥实际的操做,就是把各类数据记录下来了,而后经过int 0x16取得了键盘上各类指示灯的状态
开始导入C语言
从一开始我就说要开始C语言了,结果到了今天快结束才开始说导入C语言
虽然说导入吧,其实有不少原理性的东西,在这里不会讲,其实里面就是后面的GDT等内容,我也是看到后面的GDT开始有些卡主了,因此这里做者没有讲,而是直接来看bootpack.c吧。
void HariMain(void)
{
fin:
goto fin;
}
看到这种代码,我又从新找回了自信,毕竟我不是那个时代过来的人,没有每天写过汇编,因此汇编和C,固然是C更亲近些。我想这玩意儿C代码也不用解释太多。至因而如何调用到这里来的,后面再细谈。
关于对编译器的解释,也很简单。解释的那么清楚,而后与windows,mac上如此成熟的集成开发环境作了对比,意思是相对于那种,咱们搞这么复杂,可是步奏是可控的。
最后做者必定要让计算机处于HALT那就来吧。
; naskfunc
; TAB=4
[FORMAT "WCOFF"] ; 制做目标文件的模式
[BITS 32] ; 制做32位模式用的机械语言
; 制做目标文件的信息
[FILE "naskfunc.nas"] ; 源文件名信息
GLOBAL _io_hlt ; 程序中包含的函数名
; 如下是实际的函数
[SECTION .text] ; 目标文件中写了这些以后再些程序
_io_hlt: ; void io_hlt(void);
HLT RET
而后回来在C语言声明一下,就能够调用啦,不过至于今天许多的细节问题,后面会又深刻讲解的。总的来讲咱们能够用C语言写代码啦。