写操作系统(五)执着 初始引导程序 加载汇编内核
2009-02-17 00:45
274 查看
在第一篇的文章中有学习到,引导程序的作用实质是一个桥梁的作用。虽然它本身空间有限,能实现的功能也有限,然而它却是被BIOS看重的继承者,将大权传给引导程序手上。现在为了实现“大业”,识时务引导程序现在必须找一个文武双全的人将大权传与它,而这个人就是操作系统,当然准确地说应该是操作系统内核。
具体实现的原理是:
1.BIOS将引导调入0X7C00处;
2.BIOS隐退,引导程序执行;
3.引导程序做完自己的工作后,像BIOS寻找引导程序一样,将指定位置的程序读入内存。所以,引导程序需要知道内核在磁盘的什么位置,这样才能载入内存;
4.引导程序隐退,内核程序执行;
而上篇的代码都是实现了能让BIOS引导,即BIOS隐退时将大权给了引导程序,并未实现引导程序能够移交大权于内核。下面我就试着写并解读一下:
下面的文件是boot.asm引导文件
;; 文件:boot.asm
;; 工具:UltraEdit14.12编辑,Nasm2.02汇编
;; 创建日期:2009/02/2 HouRj
;; 作用:接管BIOS,引导kernel执行
;; 备注:没有文件系统,1.44M 512bits/80sec 软盘启动,
;; hourj_er@yahoo.cn
;;================================================
org 0x7c00
init:
mov ax,cs ;设置数据段
mov ds,ax
mov es,ax
jmp start
;定义意义串
welcome db 'Welcome numOS,the boot is running',13,10,0
print:
lodsb ;从SI地址处加载一个字节到al
or al,al ;检查要显示的串是否结束,因为如果结束,si给加载0x0进入al
jz pe ;判断是否相等即zf=0,则结束,跳至pe结束输出
mov ah,0x0e ;10号中断初始化,功能0EH 在Teletype模式下显示字符
mov bx,0x0002 ;显示方式
int 0x10 ;打开中断
jmp print ;中断响应,跳至print输出
pe:
ret
showboot: ;欢迎模块
mov si,welcome
call print
ret
start:
call showboot ;调用欢迎模块
jmp dkernel ;执行对内核的加载模块
dkernel:
reset:
mov ax,0 ;13号中断,00h为磁盘系统复位
mov dl,0 ;dl为驱动器,00h-7Fh是软盘,80-0FF是硬盘
int 13h ;中断调用
jc reset ;若复位成功,则CF=0,若CF !=0,则复位不成功,重新复位
loop:
mov ax,0x1000 ;0x1000为代码载入的段地址,自己可按照一定规则自己定义,
mov es,ax ;移送ES
mov bx,0x0 ;0为在ES(1000h)的段地址下的偏移地址
mov ah, 0x02 ;13号中断,02h为读磁盘数据,BIOS 读取扇区
mov al, 0x01 ;读取的空间为一个扇区,事先估计或规定好的
mov ch, 0h ;起始磁道 0
mov cl, 2h ;起始扇区 第二扇区
mov dh, 0h ;磁头号 1
mov dl, 0h ;dl为驱动器,00h-7Fh是软盘,80-0FF是硬盘
int 13h ;调用中断
jc loop ;同理,若CF位!=0,则失败,重新读写
jmp 1000h:0000h ;跳转到1000H:0000地址处执行,此时,cs:1000h ip:0000h
times 510-($-$$) db 0
dw 0xaa55
;;================================================
下面是汇编语言的内核文件(当然,简单内核,试验目的是看怎么加载)
;; 文件:kernel.asm
;; 工具:UltraEdit14.12编辑,Nasm2.02汇编
;; 创建日期:2009/02/2 HouRj
;; 作用:作为简单的操作系统核心,被boot引导
;; 备注:没有文件系统,1.44M 512bits/80sec 软盘启动,
;; hourj_er@yahoo.cn
;;================================================
org 0x0 ;从本段的偏移地址为0,即段首开始载入
init:
mov ax,cs ;设置数据段
mov ds,ax
mov es,ax
jmp start ;跳到start处执行
;定义意义串
welcome db 'OK,the kernel is running......',13,10,0
type db 'please input the char',13,10,0
print: ;打印字符的功能块
lodsb ;boot.asm 有详细解释
or al,al
jz pe
mov ah,0x0e
mov bx,0x0002
int 10h
jmp print
pe: ;显示结束,返回
ret
showkernel: ;欢迎功能块
mov si,welcome ;显示欢迎信息和提示信息
call print
mov si,type
call print
ret
echo: ;回显功能块
mov ah,0 ;调用键盘中断,等待按键,上篇文章有解释
int 0x16
mov ah,0x0e ;回显到屏幕
mov bx,0x0002
int 0x10
jmp echo
start: ;开始,主模块
call showkernel ;调用欢迎模块
call echo ;调用回显模块
times 510-($-$$) db 0
dw 0xaa55
;;================================================
详细的解答我都尽力下到代码里了,注释在详细不过了。下面是汇编和执行步骤:
1.进入cmd,cd到文件保存的目录
2.nasm boot.asm -o boot.img ;汇编boot.img二进制文件
3.nasm kernel.asm -o kernel.img ;汇编kernel.img二进制文件
4.parycopy kernel.img 0 200 boot.img 200 ;将kernel.img 无缝接到boot.img文件后面
5.将生成的boot.img载入到虚拟机,启动就可以看到效果
注:第4个步骤,我查看了一下网上的说法,说最后的200是200个字节,并且,好多文章都这样说。我无意看一片E文时发现,原来前面0 200是范围,后面200是拷入到boot.img的起始位置,并不是大小。我特地用UltraEdit打开了boot.img二进制文件,看到,原来512K大小的地址空间为0000h-01FFh,而下一个地址,也就是kernel.img无缝连在boot.img后面的起始地址为0200h。
好了,再看看C语言编写的内核。
相关文章推荐
- 写操作系统(三)执着 初始引导程序
- 写操作系统(四)执着 初始引导程序 中断
- NASM 纯汇编打造简单中文操作系统(1.boot.asm 操作系统的开始--引导程序)
- 操作系统学习之程序编译,链接,加载过程中的内存管理
- NASM 纯汇编打造简单中文操作系统(3 kernel.asm 内核(实现汉字的显示,鼠标的支持等))
- 32位汇编第二讲,编写窗口程序,加载资源,响应消息,以及调用C库函数
- linux内核分析作业:操作系统是如何工作的进行:完成一个简单的时间片轮转多道程序内核代码
- 加载内核并执行init程序
- 引导加载程序之争: LILO 和 GRUB
- 如何配置Ubuntu 16.04 GRUB 2引导加载程序
- 操作系统学习 (二)用户程序的加载和运行
- u-boot-2011.06在基于s3c2440开发板的移植之引导内核与加载根文件系统
- 操作系统实践之加载程序
- Linux操作系统分析-lab2-进程的创建与可执行程序的加载
- 进程信号Linux操作系统分析(2)- 进程的创建与可执行程序的加载
- 引导加载程序之争:了解 LILO 和 GRUB
- 64位操作系统下IIS报“试图加载格式不正确的程序”错误
- 通过简单的Linux内核启动程序代码窥探操作系统的启动原理
- 什么是引导加载程序?
- 引导加载程序之争:了解 LILO 和 GRUB