您的位置:首页 > 其它

写操作系统(五)执着 初始引导程序 加载汇编内核

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语言编写的内核。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息