|
|
@@ -1,17 +1,26 @@
|
|
|
; 主引导程序
|
|
|
; ----------------------------------------------------------------
|
|
|
-SECTION MBR vstart=0x7c00
|
|
|
+%include "boot.inc"
|
|
|
+SECTION MBR vstart=MBR_BASE_ADDR
|
|
|
mov ax, cs ; 0x00000000
|
|
|
mov ds, ax
|
|
|
mov es, ax
|
|
|
mov ss, ax
|
|
|
mov fs, ax
|
|
|
mov sp, 0x7c00
|
|
|
+ mov ax, 0xb800 ;文本模式显示
|
|
|
+ mov gs, ax
|
|
|
|
|
|
- call CleanDisply
|
|
|
- call GetCursorPosition
|
|
|
- call DispStr
|
|
|
- jmp $
|
|
|
+ ; call clean_display
|
|
|
+ ; call get_cursor_position
|
|
|
+ call disp_string
|
|
|
+
|
|
|
+ mov eax, LOADER_START_SECTOR ; 起始扇区地址: LBA 地址
|
|
|
+ mov bx, LOADER_BASE_ADDR ; 写入的地址
|
|
|
+ mov cx, 1 ; 待写入的扇区数(1 个扇区)
|
|
|
+ call rd_disk_m_16 ; 读取硬盘数据
|
|
|
+
|
|
|
+ jmp LOADER_BASE_ADDR
|
|
|
|
|
|
|
|
|
;清屏,利用 0x06 号功能,上巻全部行,则可清屏
|
|
|
@@ -25,7 +34,7 @@ SECTION MBR vstart=0x7c00
|
|
|
; DH=右下角行号 (DH、DL)=窗口的右下角位置(Y坐标,X坐标)
|
|
|
; DL=右下角列号
|
|
|
; ----------------------------------------------------------------
|
|
|
-CleanDisply:
|
|
|
+clean_display:
|
|
|
mov ah, 0x06 ; 功能号
|
|
|
mov al, 0x00 ; 上巻的行数(如果为 0,表示全部)
|
|
|
mov bx, 0x700
|
|
|
@@ -33,13 +42,13 @@ CleanDisply:
|
|
|
mov dx, 0x184f ; 右下角: (80, 25)
|
|
|
; VGA 文本模式中,一行只能容纳 80 个字符,共 25 行.
|
|
|
;下标、从 0 开始,所以 Ox18=24, 0x4f=79
|
|
|
- int 0x10 ; 调用 INT 0x10 功能
|
|
|
+ int 10h ; 调用 INT 0x10 功能
|
|
|
ret
|
|
|
|
|
|
|
|
|
;;;;;;;;;;;; 获取光标位置 ;;;;;;;;;;;;;
|
|
|
; .get_cursor_position, 在光标位置打印字符
|
|
|
-GetCursorPosition:
|
|
|
+get_cursor_position:
|
|
|
mov ah, 0x3 ; 3 号功能是获取光标位置,需要
|
|
|
mov bh, 0 ; 待获取光标的页号
|
|
|
|
|
|
@@ -47,20 +56,101 @@ GetCursorPosition:
|
|
|
ret
|
|
|
;;;;;;;;;;;; 获取光标位置结束 ;;;;;;;;;
|
|
|
|
|
|
-; 13 号子功能打印字符串
|
|
|
+; 直接操作显卡显示
|
|
|
;--------------------------------------------------------
|
|
|
+; 输出背景色绿色,前景色红色, 并且跳动的字符串 "1 MBR"
|
|
|
;--------------------------------------------------------
|
|
|
-DispStr:
|
|
|
- mov ax, BootMessage
|
|
|
- mov bp, ax ; ss:bp 为串首地址
|
|
|
-
|
|
|
- mov cx, 16 ; 串长度,不包括结束符个数
|
|
|
- mov ax, 0x01301 ; 子功能号 13 显示字符及属性
|
|
|
- ; al 设置写字符方式 al=01: 显示字符串,光标跟随移动
|
|
|
- mov bx, 0x2 ; bh 显示的页号 bl 是字符属性,黑底绿字(bl=02h)
|
|
|
- mov dl, 0
|
|
|
- int 0x10
|
|
|
+disp_string:
|
|
|
+ mov byte [gs:0x00], '1'
|
|
|
+ mov byte [gs:0x01], 0xA4 ; A(K:1 R:0 G:1 B:0) 绿色背景闪烁, 4(K:0 R:1 G:0 B:0)前景红色
|
|
|
+
|
|
|
+ mov byte [gs:0x02], ' '
|
|
|
+ mov byte [gs:0x03], 0xA4
|
|
|
+
|
|
|
+ mov byte [gs:0x04], 'M'
|
|
|
+ mov byte [gs:0x05], 0xA4
|
|
|
+
|
|
|
+ mov byte [gs:0x06], 'B'
|
|
|
+ mov byte [gs:0x07], 0xA4
|
|
|
+
|
|
|
+ mov byte [gs:0x08], 'R'
|
|
|
+ mov byte [gs:0x09], 0xA4
|
|
|
+
|
|
|
+ mov byte [gs:0x0A], '.'
|
|
|
+ mov byte [gs:0x0B], 0xA4
|
|
|
+
|
|
|
+ mov byte [gs:0x0C], '.'
|
|
|
+ mov byte [gs:0x0D], 0xA4
|
|
|
+
|
|
|
+ mov byte [gs:0x0E], '.'
|
|
|
+ mov byte [gs:0x0F], 0xA4
|
|
|
ret
|
|
|
-BootMessage: db "Hello OS World"
|
|
|
+;----------------------------------------------------------------
|
|
|
+; 读取硬盘数据
|
|
|
+; EAX=LBA 地址(扇区号)
|
|
|
+; BX=将数据写入的内存地址
|
|
|
+; CX=读取的扇区数
|
|
|
+rd_disk_m_16:
|
|
|
+;----------------------------------------------------------------
|
|
|
+ mov esi, eax ; 备份 eax
|
|
|
+ mov di, cx ; 备份 cx
|
|
|
+
|
|
|
+; 第 1 步:设置要读取的扇区数
|
|
|
+ mov dx, 0x1f2 ; Primary 通道 Sector count
|
|
|
+ mov al, cl
|
|
|
+ out dx, al ; 读取的扇区数
|
|
|
+
|
|
|
+ mov eax, esi ; 恢复 eax
|
|
|
+
|
|
|
+; 第 2 步:设置 LBA 地址,存入 0x1f3 - 0x1f6 端口中
|
|
|
+ ; LBA 地址 7 ~ 0 位写入端口 0x1f3
|
|
|
+ mov dx, 0x1f3 ; Primary 通道 LBA low
|
|
|
+ out dx, al
|
|
|
+
|
|
|
+ ; LBA 地址 15 ~ 8 位写入端口 0x1f4
|
|
|
+ mov cl, 8
|
|
|
+ shr eax, cl
|
|
|
+ mov dx, 0x1f4 ; Primary 通道 LBA mid
|
|
|
+ out dx, al
|
|
|
+
|
|
|
+ ; LBA 地址 23 ~ 16 位写入端口 0x1f5
|
|
|
+ shr eax, cl
|
|
|
+ mov dx, 0x1f5 ; Primary 通道 LBA high
|
|
|
+ out dx, al
|
|
|
+
|
|
|
+ shr eax, cl
|
|
|
+ and al, 0x0f ; LBA 第 24~27 位
|
|
|
+ or al, 0xe0 ; 设置 7-4 位为 1110, 表示 LBA 模式
|
|
|
+ mov dx, 0x1f6 ; Device
|
|
|
+ out dx, al
|
|
|
+
|
|
|
+; 第 3 步:向 0x1f7 端口写入命令 0x20
|
|
|
+ mov dx, 0x1f7 ; Command
|
|
|
+ mov al, 0x20
|
|
|
+ out dx, al
|
|
|
+
|
|
|
+; 第 4 步:检测硬盘状态
|
|
|
+.not_ready:
|
|
|
+ ; 同一端口,写时表示写入命令,读时表示读入硬盘状态
|
|
|
+ nop
|
|
|
+ in al, dx ; 0x1f7 Status
|
|
|
+ and al, 0x88 ; 第 4 位为 1 表示硬盘控制器已准备好数据传输,第 7 位为 1 表示硬盘忙
|
|
|
+ cmp al, 0x08
|
|
|
+ jnz .not_ready
|
|
|
+
|
|
|
+; 第 5 步:从 0x1f0 端口读取数据
|
|
|
+ ; di 为要读取的扇区数,一个扇区 512 字节,每次读入一个字,共需要 di*512/2 次,所以 di*256
|
|
|
+ mov ax, di
|
|
|
+ mov dx, 256
|
|
|
+ mul dx ; dx:ax = dx * 256
|
|
|
+ mov cx, ax
|
|
|
+ mov dx, 0x1f0
|
|
|
+.go_on_read:
|
|
|
+ in ax, dx
|
|
|
+ mov [bx], ax ; LOADER_BASE_ADDR (0~FFFFh)
|
|
|
+ add bx, 2
|
|
|
+ loop .go_on_read
|
|
|
+ ret
|
|
|
+
|
|
|
times 510 - ($-$$) db 0
|
|
|
db 0x55, 0xaa
|