| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157 |
- ; 主引导程序
- ; ----------------------------------------------------------------
- %include "boot.inc"
- SECTION MBR vstart=0x7c00
- 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 clean_display
- ; call get_cursor_position
- call disp_string
-
- mov eax, LOADER_START_SECTOR ; 起始扇区地址: LBA 地址
- mov bx, LOADER_BASE_ADDR ; 写入的地址
- mov cx, 4 ; 待写入的扇区数(4 个扇区)
- call rd_disk_m_16 ; 读取硬盘数据
- jmp LOADER_BASE_ADDR+0x300 ; 直接跳转到 loader 的 loader_start 位置
- ;清屏,利用 0x06 号功能,上巻全部行,则可清屏
- ; ----------------------------------------------------------------
- ; INT 0X10 功能号:0x06 功能描述:上巻窗口
- ; AL=上卷行数
- ; AL=0 整个窗口空白
- ; BH=卷入行属性
- ; CH=左上角行号 (CH、CL)=窗口的左上角位置(Y坐标,X坐标)
- ; CL=左上角列号
- ; DH=右下角行号 (DH、DL)=窗口的右下角位置(Y坐标,X坐标)
- ; DL=右下角列号
- ; ----------------------------------------------------------------
- clean_display:
- mov ah, 0x06 ; 功能号
- mov al, 0x00 ; 上巻的行数(如果为 0,表示全部)
- mov bx, 0x700
- mov cx, 0 ; 左上角:(0,0)
- mov dx, 0x184f ; 右下角: (80, 25)
- ; VGA 文本模式中,一行只能容纳 80 个字符,共 25 行.
- ;下标、从 0 开始,所以 Ox18=24, 0x4f=79
- int 10h ; 调用 INT 0x10 功能
- ret
- ;;;;;;;;;;;; 获取光标位置 ;;;;;;;;;;;;;
- ; .get_cursor_position, 在光标位置打印字符
- get_cursor_position:
- mov ah, 0x3 ; 3 号功能是获取光标位置,需要
- mov bh, 0 ; 待获取光标的页号
- int 0x10
- ret
- ;;;;;;;;;;;; 获取光标位置结束 ;;;;;;;;;
- ; 直接操作显卡显示
- ;--------------------------------------------------------
- ; 输出背景色绿色,前景色红色, 并且跳动的字符串 "1 MBR"
- ;--------------------------------------------------------
- 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
- ;----------------------------------------------------------------
- ; 读取硬盘数据
- ; 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
|