mbr.S 4.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157
  1. ; 主引导程序
  2. ; ----------------------------------------------------------------
  3. %include "boot.inc"
  4. SECTION MBR vstart=0x7c00
  5. mov ax, cs ; 0x00000000
  6. mov ds, ax
  7. mov es, ax
  8. mov ss, ax
  9. mov fs, ax
  10. mov sp, 0x7c00
  11. mov ax, 0xb800 ;文本模式显示
  12. mov gs, ax
  13. call clean_display
  14. ; call get_cursor_position
  15. call disp_string
  16. mov eax, LOADER_START_SECTOR ; 起始扇区地址: LBA 地址
  17. mov bx, LOADER_BASE_ADDR ; 写入的地址
  18. mov cx, 4 ; 待写入的扇区数(4 个扇区)
  19. call rd_disk_m_16 ; 读取硬盘数据
  20. jmp LOADER_BASE_ADDR+0x300 ; 直接跳转到 loader 的 loader_start 位置
  21. ;清屏,利用 0x06 号功能,上巻全部行,则可清屏
  22. ; ----------------------------------------------------------------
  23. ; INT 0X10 功能号:0x06 功能描述:上巻窗口
  24. ; AL=上卷行数
  25. ; AL=0 整个窗口空白
  26. ; BH=卷入行属性
  27. ; CH=左上角行号 (CH、CL)=窗口的左上角位置(Y坐标,X坐标)
  28. ; CL=左上角列号
  29. ; DH=右下角行号 (DH、DL)=窗口的右下角位置(Y坐标,X坐标)
  30. ; DL=右下角列号
  31. ; ----------------------------------------------------------------
  32. clean_display:
  33. mov ah, 0x06 ; 功能号
  34. mov al, 0x00 ; 上巻的行数(如果为 0,表示全部)
  35. mov bx, 0x700
  36. mov cx, 0 ; 左上角:(0,0)
  37. mov dx, 0x184f ; 右下角: (80, 25)
  38. ; VGA 文本模式中,一行只能容纳 80 个字符,共 25 行.
  39. ;下标、从 0 开始,所以 Ox18=24, 0x4f=79
  40. int 10h ; 调用 INT 0x10 功能
  41. ret
  42. ;;;;;;;;;;;; 获取光标位置 ;;;;;;;;;;;;;
  43. ; .get_cursor_position, 在光标位置打印字符
  44. get_cursor_position:
  45. mov ah, 0x3 ; 3 号功能是获取光标位置,需要
  46. mov bh, 0 ; 待获取光标的页号
  47. int 0x10
  48. ret
  49. ;;;;;;;;;;;; 获取光标位置结束 ;;;;;;;;;
  50. ; 直接操作显卡显示
  51. ;--------------------------------------------------------
  52. ; 输出背景色绿色,前景色红色, 并且跳动的字符串 "1 MBR"
  53. ;--------------------------------------------------------
  54. disp_string:
  55. mov byte [gs:0x00], '1'
  56. mov byte [gs:0x01], 0xA4 ; A(K:1 R:0 G:1 B:0) 绿色背景闪烁, 4(K:0 R:1 G:0 B:0)前景红色
  57. mov byte [gs:0x02], ' '
  58. mov byte [gs:0x03], 0xA4
  59. mov byte [gs:0x04], 'M'
  60. mov byte [gs:0x05], 0xA4
  61. mov byte [gs:0x06], 'B'
  62. mov byte [gs:0x07], 0xA4
  63. mov byte [gs:0x08], 'R'
  64. mov byte [gs:0x09], 0xA4
  65. mov byte [gs:0x0A], '.'
  66. mov byte [gs:0x0B], 0xA4
  67. mov byte [gs:0x0C], '.'
  68. mov byte [gs:0x0D], 0xA4
  69. mov byte [gs:0x0E], '.'
  70. mov byte [gs:0x0F], 0xA4
  71. ret
  72. ;----------------------------------------------------------------
  73. ; 读取硬盘数据
  74. ; EAX=LBA 地址(扇区号)
  75. ; BX=将数据写入的内存地址
  76. ; CX=读取的扇区数
  77. rd_disk_m_16:
  78. ;----------------------------------------------------------------
  79. mov esi, eax ; 备份 eax
  80. mov di, cx ; 备份 cx
  81. ; 第 1 步:设置要读取的扇区数
  82. mov dx, 0x1f2 ; Primary 通道 Sector count
  83. mov al, cl
  84. out dx, al ; 读取的扇区数
  85. mov eax, esi ; 恢复 eax
  86. ; 第 2 步:设置 LBA 地址,存入 0x1f3 - 0x1f6 端口中
  87. ; LBA 地址 7 ~ 0 位写入端口 0x1f3
  88. mov dx, 0x1f3 ; Primary 通道 LBA low
  89. out dx, al
  90. ; LBA 地址 15 ~ 8 位写入端口 0x1f4
  91. mov cl, 8
  92. shr eax, cl
  93. mov dx, 0x1f4 ; Primary 通道 LBA mid
  94. out dx, al
  95. ; LBA 地址 23 ~ 16 位写入端口 0x1f5
  96. shr eax, cl
  97. mov dx, 0x1f5 ; Primary 通道 LBA high
  98. out dx, al
  99. shr eax, cl
  100. and al, 0x0f ; LBA 第 24~27 位
  101. or al, 0xe0 ; 设置 7-4 位为 1110, 表示 LBA 模式
  102. mov dx, 0x1f6 ; Device
  103. out dx, al
  104. ; 第 3 步:向 0x1f7 端口写入命令 0x20
  105. mov dx, 0x1f7 ; Command
  106. mov al, 0x20
  107. out dx, al
  108. ; 第 4 步:检测硬盘状态
  109. .not_ready:
  110. ; 同一端口,写时表示写入命令,读时表示读入硬盘状态
  111. nop
  112. in al, dx ; 0x1f7 Status
  113. and al, 0x88 ; 第 4 位为 1 表示硬盘控制器已准备好数据传输,第 7 位为 1 表示硬盘忙
  114. cmp al, 0x08
  115. jnz .not_ready
  116. ; 第 5 步:从 0x1f0 端口读取数据
  117. ; di 为要读取的扇区数,一个扇区 512 字节,每次读入一个字,共需要 di*512/2 次,所以 di*256
  118. mov ax, di
  119. mov dx, 256
  120. mul dx ; dx:ax = dx * 256
  121. mov cx, ax
  122. mov dx, 0x1f0
  123. .go_on_read:
  124. in ax, dx
  125. mov [bx], ax ; LOADER_BASE_ADDR (0~FFFFh)
  126. add bx, 2
  127. loop .go_on_read
  128. ret
  129. times 510 - ($-$$) db 0
  130. db 0x55, 0xaa