Chinaunix首页 | 论坛 | 博客
  • 博客访问: 1745344
  • 博文数量: 1493
  • 博客积分: 38
  • 博客等级: 民兵
  • 技术积分: 5834
  • 用 户 组: 普通用户
  • 注册时间: 2009-08-19 17:28
文章分类

全部博文(1493)

文章存档

2016年(11)

2015年(38)

2014年(137)

2013年(253)

2012年(1054)

2011年(1)

分类: C/C++

2013-05-13 09:20:18

概述:

    bootsector的代码是磁盘引导块程序,驻留在磁盘的第一个扇区中(引导扇区,0磁道,0磁头,1扇区),在PC机器加电自检后,引导扇区将由bios加载到内存的0x7c00处,然后将自己移动到内存0x90000处,该程序的主要作用是首先将setup(后边写,负责开启保护模式)加载到内存,紧接着bootloader的后边位置0x90200,然后利用bios终端取一下每个磁道的扇区数量,并在屏幕上打印“loading system...."因为反应太快特此,在这里做了一个无用的循环,然后的部分是把32位的保护模式的代码加载到0x10000开始的地方。最后跳转到setup程序的开始位置执行setup。

代码:


点击(此处)折叠或打开

  1. ;这个程序是boot程序,也就是IPL(init program loader),放到磁盘的第一个扇区,当但脑加电的时候
  2. ;bios会吧第一个扇区的512字节加载到0x7c00, 然后本程序负责吧内核从
  3. ;磁盘加载到内存。
  4. [bits 16]
  5. SYSSIZE EQU 0x3000;我们只读取192k的内核,也足够了
  6. SETUPLEN EQU 4
  7. BOOTSEG EQU 0x7c0
  8. INITSEG EQU 0x9000
  9. SETUPSEG EQU 0x9020
  10. SYSSEG EQU 0x1000
  11. ENDSEG EQU SYSSEG + SYSSIZE
  12.         
  13. entry:
  14.         jmp start;3字节的跳转指令
  15.         ;标准的磁盘属性
  16.         DB        0x90
  17.         DB        "hahahaha"        ;
  18.         DW        512                ;
  19.         DB        1                ;
  20.         DW        1                ;
  21.         DB        2                ;
  22.         DW        224                ;
  23.         DW        2880            ;
  24.         DB        0xf0            ;
  25.         DW        9                ;
  26.         DW        18                ;
  27.         DW        2                ;
  28.         DD        0                ;
  29.         DD        2880            ;
  30.         DB        0,0,0x29        ;
  31.         DD        0xffffffff        ;
  32.         DB        "HAHAHAHAOS "    ;
  33.         DB        "FAT12 "        ;
  34.         
  35.         ;设置各个段寄存器的值使他指向0x7c0
  36.         ;因为地址可以是段寄存器左移4位 + 偏移量
  37. start:
  38.         mov ax, BOOTSEG
  39.         mov ss, ax
  40.         mov ds, ax
  41.         mov es, ax
  42.         ;我们把自己放到0x9000处,我这里是参照了linux内0.1版本,
  43.         ;(这个位置可以防止加载内核的覆盖问题)可以改到其他的合适的位置。
  44.         mov ax, INITSEG
  45.         mov es,ax
  46.         mov cx, 256
  47.         sub si, si;ds:si 0x7c00
  48.         sub di, di;es:di 0x9000:0x0000
  49.         cld
  50.         rep movsw;一次移植2byte
  51.         
  52.         jmp INITSEG:go
  53.         ;从下面开始我们到0x9000处执行
  54. go:     
  55.         mov ax, cs
  56.         mov ds, ax
  57.         mov es, ax
  58.         mov ss, ax
  59.         mov sp, 0xff00;任意设定只要不覆盖代码即可
  60.         ;下面我们加载setup模块。从第二个扇区到第六个扇区。
  61. load_setup:    
  62.         mov ax, 0x200 + SETUPLEN;ah = 0x20读磁盘, al=4 读扇区数量
  63.         mov cx, 0x0002     ;CH柱面号,CL扇区号
  64.         mov dx, 0x0000         ;DH磁头号,DL驱动器号
  65.         mov bx, 0x200
  66.         int 0x13                ;ES:BX缓冲区地址
  67.         jnc ok_load_setup        ;如果错误CF位置位,jump if not carry
  68.         mov dx, 0x0000
  69.         mov ax, 0x0000
  70.         jmp load_setup
  71. ok_load_setup:
  72.         ;去磁盘驱动器参数,例如每道的扇区数量,用int 0x13中断,ah为0x08,dl驱动器号。
  73.         ;返回ah=0,al=0;bl=驱动器类型;ch最大磁道号的低8位,cl每磁道的扇区号(0-5位)
  74.         ;最大磁道号的高2位(6-7位),dh=最大磁头数,dl=驱动器的数量,es:di软驱参数表
  75.         ;若出错CF置位ah状态码
  76.         mov dl, 0x00
  77.         mov ax, 0x800
  78.         int 0x13
  79.         mov ch, 0x00
  80.         mov word [cs:sectors], cx
  81.         mov ax, INITSEG
  82.         mov es, ax
  83.         ;打印消息
  84.         mov ah, 0x03
  85.         xor bh,bh
  86.         int 0x10;读取光标位置
  87.         
  88.         mov cx,24
  89.         mov bx,0x7
  90.         mov bp,msg1
  91.         mov ax,0x1301
  92.         int 0x10;打印消息
  93.         ;我们已经写了message了,是时候加载system模块了。我们将它加载到0x10000处
  94.         mov ax, SYSSEG
  95.         mov es, ax
  96.         call read_it
  97.         mov ax,0xfff
  98. delay:
  99.         mov cx,0xffff
  100. setup:
  101.         
  102.         sub cx,1
  103.         cmp cx,0
  104.         jne setup
  105.         sub ax,1
  106.         cmp ax,0
  107.         jne delay;故意延迟一下
  108.         
  109.         jmp SETUPSEG:0
  110. ;该子程序将系统模块加载到内存地址0x10000处,并确定没有跨越64k边界。我们试图尽快的进行加载,只要可能,
  111. ;就每次加载整条磁道的数据。
  112. sread:   dw 1+ SETUPLEN
  113. head:    dw 0                    ;当前磁头号
  114. track:   dw 0                     ;当前柱面号
  115. read_it:
  116.         mov ax, es
  117.         test ax, 0xfff
  118. die:    jnz die;64k边界
  119.         xor bx,bx
  120. rp_read:
  121.         mov ax, es
  122.         cmp ax, ENDSEG;是否到达结束为止
  123.         jb ok1_read
  124.         ret
  125. ok1_read:
  126.         mov ax,[cs:sectors];每个磁道的扇区数
  127.         sub ax,[cs:sread];减去已经读取的扇区,为需要读取的扇区数
  128.         mov cx,ax
  129.         shl cx,9;扇区数*512,为需要的内存
  130.         add cx,bx;判断是否超过了段内偏移量
  131.         jnc ok2_read
  132.         je ok2_read
  133.         xor ax,ax
  134.         sub ax,bx;如果超过了,我们读取不超过的数量
  135.         shr ax,9
  136. ok2_read:
  137.         call read_track;读取数据
  138.         mov cx, ax ;读取的数量
  139.         add ax,[cs:sread]
  140.         cmp ax,[cs:sectors]
  141.         jne ok3_read
  142.         mov ax,1;读取了一个柱面了
  143.         sub ax,[cs:head];取当前的柱面
  144.         jne ok4_read
  145.         push dx
  146.         mov dx ,[cs:track];当前的柱面为1,我们得取下个柱面
  147.         inc dx
  148.         mov [cs:track],dx
  149.         pop dx
  150. ok4_read:
  151.         mov [cs:head],ax
  152.         xor ax,ax
  153. ok3_read:
  154.         mov [cs:sread],ax;保存读取的扇区数
  155.         shl cx,9
  156.         add bx,cx;移动bx的地址到读完扇区后的地址
  157.         jnc rp_read
  158.         mov ax,es
  159.         add ax,0x1000;读取了16位的数据了也就是2^16即64k的数据
  160.         mov es,ax
  161.         xor bx,bx
  162.         jmp rp_read
  163. read_track:
  164.         push ax
  165.         push bx
  166.         push cx
  167.         push dx
  168.         mov dx,[cs:track]
  169.         mov cx,[cs:sread]
  170.         inc cx
  171.         mov ch,dl
  172.         mov dx,[cs:head]
  173.         mov dh,dl
  174.         mov dl,0;驱动器号
  175.         and dx,0x0100
  176.         mov ah,2;读盘
  177.         int 0x13
  178.         jc bad_rt
  179.         pop dx
  180.         pop cx
  181.         pop bx
  182.         pop ax
  183.         ret
  184. bad_rt: mov ax,0
  185.         mov dx,0
  186.         int 0x13
  187.         pop dx
  188.         pop cx
  189.         pop bx
  190.         pop ax
  191.         jmp read_track                        
  192. sectors:
  193.         db 18
  194. msg1:
  195.         db 13,10;回车键
  196.         db "Loading system ..."
  197.         db 13,10,13,10

  198.         
  199. size equ $ - entry
  200. %if size +2 > 512
  201.         %error "code is too large for boot sector"
  202. %endif
  203.         times (512 - size -2) db 0
  204.         db 0x55,0xAA;2字节的磁盘标识

代码里面有详细的注释,现在有两个版本的了,现在我不喜欢用winimage这个windows工具了。现在使用的是linux的dd命令
假设编译成loader.bin
我们用  dd if=./loader.bin of=disk.img bs=512 count=1

点击(此处)折叠或打开

  1. dd if=./loader.bin of=./disk.img bs=512 count=1
  2. dd if=/dev/zero of=./disk.img bs=512 count=2879 seek=1
就可以把disk.img放到虚拟机中玩了。
github上的以前版本os:   
现在版本os:
 

欢迎下载讨论。


 
阅读(593) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~