`
film
  • 浏览: 226144 次
  • 性别: Icon_minigender_1
  • 来自: 北京
社区版块
存档分类
最新评论

实现OS中BOOTLOADER过程,并进入保护模式的代码

OS 
阅读更多
  1. ;;;;;;;实现进入进入保护模式,简单实现gdt,还没实现idt,用fat格式,这样利于内核文件的扩展。编写好内核之后,
  2. ;;;;;;;;可以直接放到软盘的根目录下。不需要在用镜像文件写入磁盘。
  3. ;;;;;;;;内存分配,堆栈在8FFFF,内核在500H,目录文件名被读取到7E00,等待扩展保护模式中断,完善磁盘读文件过程
  4. [bits 16]
  5. [org 0x7c00] ; 告诉编译器程序加载到7c00处
  6. CATALOG equ 0x7E00          ;catalog loaded at 0x7e00
  7. KERNEL  equ 0x500           ;kernel.bin loaded at 0x500.
  8. jmp Start
  9. ; 引导区文件系统数据
  10. ;----------------------------------------------------------------------------
  11.     brOEM       DB " T's OS "        ; 0003h - 引导程序的名字
  12.     brBPS       DW 0x200        ; 000Bh - 每扇区的字节数 512
  13.     brSPC       DB 0x01            ; 000Dh - 每簇扇区数
  14.     brResCount  DW    0x0001     ; 000Eh - 保留扇区数
  15.     brFATs      DB 0x02            ; 0010h - FAT 备份数
  16.     brRootEntries    DW    0x00e0     ; 0011h - 根目录文件数
  17.     brSectorCount    
  18.                 DW 2880        ; 0013h - 磁盘容量扇区数< 32MB
  19.     brMedia     DB 240         ; 0015h - 媒体描述符
  20.     brSPF       DW 9           ; 0016h - 每FAT扇区数
  21.     brSPH       DW 18         ; 0018h - 每磁道扇区数
  22.     brHPC       DW 2           ; 001Ah - 盘面数
  23.     brHidden    DD 0            ; 001Ch - 隐藏扇区数
  24.     brSectors   DD 0           ; 0020h - 如果大于32m的扇区总数
  25.                 DB 0           ; 0024h - 物理驱动器号
  26.                 DB 0           ; 0025h - 系统保留
  27.                 DB 29H         ; 0026h - 扩展扇区标记(包含29h)
  28.     brSerialNum DD    00000006H    ; 0027h - 卷ID
  29.     brLabel     DB    'NO NAME    '    ; 002Bh - 卷标
  30.     brFSID      DB    'FAT12   '        ; 0036h - 系统保留
  31. ;------------------------------------------------------------------------
  32. Start:
  33. mov ax, cs
  34. mov ds, ax
  35. mov es, ax
  36. mov ax,0x8000               ;栈放在0x1F00段里,这里栈有问题(栈放在0x1F00段里,会覆盖掉中断程序。)!!!!!!!!!!!!!!!
  37. mov ss,ax
  38. mov sp,0xffff               ; 堆栈入口 8FFFF
  39. call DispStr                ; 调用显示字符串例程
  40. call LoadFile               ; 把目录区读入到200的地方,bios
  41. call FindFile               ; 在7E00的地方找kernel.bin,读出来放到500的地方,并显示读取成功
  42. call Clrscr             ;先清屏
  43. ;=============================================
  44. ;SwitchPro建立GDT,进入保护模式
  45. ;=============================================
  46. SwitchPro;
  47.     ; 打开A20
  48.     in al, 92h
  49.     or al, 00000010b
  50.     out 92h, al
  51.     ; end 打开A20
  52.     ; 设置GDT
  53.     cli
  54.     ;mov ax,KERNEL          ; lgdt 指令加载 gdtr 是以ds为数据段加载
  55.     ;mov ds,ax
  56.     ;lea si, [dword gdtr]
  57.     lgdt [gdtr]
  58.     ;lea si, [dword idtr]
  59.     ;lidt [dword gdtr]
  60.     mov eax, cr0
  61.     or eax,1
  62.     mov cr0, eax
  63.     jmp dword selcode:0         ;进入保护模式,并且跳到下面的段中
  64.     ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;jmp KERNEL   保护模式下,跳到kenel.bin开始执行内核.等待内核编码完成在实现
  65. [bits 32]
  66. CODE32:
  67.     sti
  68.     mov eax,codesel_gdt
  69.     mov ebx,datasel_gdt
  70.     mov ax,ProMessage
  71.     mov bp,ax
  72.     mov cx,ProMsglength
  73.     ;call   PrintMsg        ;保护模式中断有问题,需要修改这里,最好能利用实模式下的bios中断程序。
  74. ;===================
  75. mov ax,videosel ; 初始化gs,使其指向显示内存
  76. mov gs,ax 
  77. mov word [gs:0],0x741 ; 在保护模式下显示一个白色的字符A
  78. ;===================
  79.     jmp $           ; 到此停止!!!!!!!!!!!!!!!!!!!!!!!
  80. [bits 16]
  81. ;===================================================================
  82. ;初始化gdtr和gdt
  83. ;===================================================================
  84. gdtr:
  85.     dw gdt_end - gdt-1              ; gdt的长度--16位(800H)GDT界限gdt limit=2048, 256 GDT entries
  86.                         ;这里应该是伪长度7,15,23,31,因为从0开始计算的
  87.     dd gdt                                      ; gdt的物理地址--32位GDT基地址
  88.                         ;0x00007c930017!!!!!!!!
  89. gdt:
  90.     gdt0:
  91.         dw 0,0,0,0                             ; 一定要为0
  92. codesel_gdt:
  93.     dw    0xffff                           ; 界限Limit值 = 0x100000 * 0x1000 = 4GB
  94.     dw    CODE32;0x0000                        ; 基地址 = CODE32.!!!!!!!是不是最好设置从0开始?
  95.     db    0x00
  96.     db    0x9A                             ; 表示 存在 可执行可读代码段
  97.     db    0xCF                             ; 粒度以及32位代码1100=0XC
  98.     db    0x00                             
  99. datasel_gdt:
  100.     dw    0xffff                           ; 界限4GB
  101.     dw    0x0000                           ; 基地址
  102.     db    0x00
  103.     db    0x92                             ; 表示 存在 可读写数据段
  104.     db    0xCF                             ; 粒度以及数据锻大小4G,1100=0XC
  105.     db    0x00                             
  106. ;========================
  107. videosel equ $-gdt 
  108. dw 3999 
  109. dw 0x8000 ; 基址是0xb8000
  110. db 0x0b
  111. db 0x92 
  112. db 0x00 
  113. db 0x00
  114. ;========================
  115. gdt_end:
  116. selcode equ codesel_gdt - gdt           ;索引值1,2,3....
  117. seldata equ datasel_gdt - gdt
  118. ;=============================================
  119. ;DispStr 显示boot已经启动!
  120. ;=============================================
  121. DispStr:
  122.    mov ax, BootMessage
  123.    mov bp, ax ; es:bp = 串地址
  124.    mov cx, Msglength ; cx = 串长度
  125.    call PrintMsg
  126. ret
  127. ;=============================================
  128. ;LoadFile 把目录从软盘中读出来!
  129. ;=============================================
  130. LoadFile:
  131. mov ax,19       ;开始的扇区
  132. mov bx,CATALOG          ;目录放在7E00H的地方!!!!!!!!!!!!!!!!!!!!!!!!!!!
  133. mov cx,14       ;目录扇区个数
  134. loopreadsec:
  135. push ax
  136. push bx
  137. push cx
  138. call    LBACHS          ; 调用转换
  139. mov     dl, 0           ; 因为是a:所以为0!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
  140. mov     ah, 0x02        ; BIOS 读取扇区命令
  141. mov     al, 0x01        ; 一个扇区
  142. int     0x13            ; 调用中断
  143. nop
  144. pop cx
  145. pop bx
  146. pop ax
  147. add bx,200
  148. inc ax
  149. loop loopreadsec
  150. ret
  151. ;=============================================
  152. ; 转换逻辑块访问为读取磁盘所使用的磁道,盘面,扇区
  153. ; 相对扇区 = (逻辑扇区 / 每磁道扇区数) + 1
  154. ; 相对盘面   = (逻辑扇区 / 每磁道扇区数) MOD 盘面数
  155. ; 相对磁道 = 逻辑扇区 / (每磁道扇区数 * 盘面数)
  156. ;=============================================
  157. LBACHS:
  158.     xor     dx, dx              ; dx = 0
  159.     mov     cx,18
  160.     div     cx        ; div: ax/18 -> 商:ax 余数:dx
  161.     inc     dl        ;sec           ; 
  162.     mov     cl, dl    ;sector
  163.     xor     dx, dx    ; dx = 0
  164.     push    bx
  165.     mov     bx,2
  166.     div     bx        ; ax/2 -> 商:ax 余数:dx
  167.     pop     bx
  168.     mov     ch, al    ; track
  169.     mov     dh, dl    ; head
  170. ret
  171. ;=============================================
  172. ;FindFile 查找文件名,并且装到0x500,显示Load Kernel.bin Success!
  173. ;=============================================
  174. FindFile:
  175. cld                             ;地址自动增加
  176. mov cx,224                          ;根目录共有224个文件
  177. mov di,CATALOG                          ;目录放在7E00H的地方!!!!!!!!!!!!!!!!!!!!!
  178. .l_findfile:
  179. push cx
  180. lea si,[Kernel]                             ;?
  181. push di
  182. mov cx,11                           ;8+3=0xb文件名和后缀长度
  183. repe cmpsb            
  184. pop di
  185. je findfile_ok
  186. add di,32                           ;开始找下1个文件
  187. pop cx
  188. loop .l_findfile
  189. mov ax, LoadKerFail                     ;失败
  190. mov bp, ax                          ; es:bp = 串地址
  191. mov cx, LoadKerFaillength                   ; cx = 串长度
  192. call PrintMsg
  193. ret
  194. findfile_ok:
  195. pop cx
  196. add di,26       ;取文件占用的第一个簇号,即起始簇
  197. mov ax,[di]
  198. add ax,31       ;簇转成扇区
  199. mov bx,KERNEL                           ;文件放在0x500!!!!!!!!!!!!!!!!!!!!!!!!!!!
  200. call    LBACHS          ; 调用转换
  201. mov     dl, 0           ; 因为是a:所以为0!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
  202. mov     ah, 0x02        ; BIOS 读取扇区命令
  203. mov     al, 0x03                            ; 一个扇区,这里不应该只读一个扇区,应该根据文件大小来决定,等待修改!!!!!
  204. int     0x13            ; 调用中断,内核放在0x1e00!      ;在磁盘的位置?
  205. mov ax, LoadKerSuess                        ;成功
  206. mov bp, ax                          ; es:bp = 串地址   
  207. mov cx, LoadKerlength                       ; cx = 串长度
  208. call PrintMsg   
  209. ret
  210. ;=============================================
  211. ;清屏
  212. ;=============================================
  213. Clrscr :
  214.    mov ax,0x0600 ; 使用中断10h的功能6,实现卷屏,如果al=0则清屏
  215.    mov cx,0x0000 ; 清屏
  216.    mov dx,0x174f ; 卷屏至23,79
  217.    mov bh,0 ; 使用颜色0来填充
  218.    int 0x10 ; 调用10h中断
  219. ret
  220. ;=============================================
  221. ;显示信息
  222. ;=============================================
  223. PrintMsg:
  224.    mov ax, 01301h ; ah = 13, al = 01h
  225.    mov bx, 000ch ; 页号为0(bh = 0) 黑底红字(bl = 0Ch,高亮)
  226.    mov dl, 0
  227.    mov dh, BYTE [NoLine]
  228.    int 10h ; 10h 号中断
  229.    add dh,1
  230.    mov BYTE [NoLine],dh
  231. ret
  232. BootMessage: db "Welcome to T's OS!",0x0D,0x0A
  233. Msglength equ $-BootMessage
  234. DB 0x00
  235. Kernel: db 'KERNEL  BIN'                    ;8+3=11位;将来这里改成内核的文件名!!!!!!!!!!!!!
  236. LoadKerSuess: db 'Load Kernel.bin Success!',0x0D,0x0A
  237. LoadKerlength equ $-LoadKerSuess
  238. DB 0x00
  239. LoadKerFail: db 'Load Kernel.bin Fail!',0x0D,0x0A
  240. LoadKerFaillength equ $-LoadKerFail
  241. DB 0x00
  242. ProMessage: db "I'm in the Pro Mode!",0x0D,0x0A
  243. ProMsglength equ $-ProMessage
  244. DB 0x00
  245. NoLine DB 0x00
  246. times 510-($-$$) db 0 ; 填充剩下的空间,使生成的二进制代码恰好为512字节
  247. dw 0xaa55 ; 结束标志
  248. ;把这段代码用NASM编译一下:
  249. ;nasm boot.asm –o boot.bin
  250. ;应该把内核在pro模式下加载就对了!
分享到:
评论

相关推荐

Global site tag (gtag.js) - Google Analytics