瀏覽代碼

完善 MBR 部分

runningwater 1 年之前
父節點
當前提交
cba2768934
共有 7 個文件被更改,包括 204 次插入50 次删除
  1. 25 27
      .gitignore
  2. 7 3
      bochsrc
  3. 4 0
      boot/include/boot.inc
  4. 32 0
      boot/loader.S
  5. 110 20
      boot/mbr.s
  6. 26 0
      boot/readme.md
  7. 二進制
      hd30M.img

+ 25 - 27
.gitignore

@@ -43,33 +43,31 @@ install_manifest.txt
 # ---> VisualStudioCode
 .settings
 
-
 # ---> macOS
-.DS_Store
-.AppleDouble
-.LSOverride
-
-# Icon must end with two \r
-Icon
-
-
-# Thumbnails
-._*
-
-# Files that might appear in the root of a volume
-.DocumentRevisions-V100
-.fseventsd
-.Spotlight-V100
-.TemporaryItems
-.Trashes
-.VolumeIcon.icns
-
-# Directories potentially created on remote AFP share
-.AppleDB
-.AppleDesktop
-Network Trash Folder
-Temporary Items
-.apdisk
+.DS_Store
+.AppleDouble
+.LSOverride
+
+# Icon must end with two \r
+Icon
+
+# Thumbnails
+._*
+
+# Files that might appear in the root of a volume
+.DocumentRevisions-V100
+.fseventsd
+.Spotlight-V100
+.TemporaryItems
+.Trashes
+.VolumeIcon.icns
+
+# Directories potentially created on remote AFP share
+.AppleDB
+.AppleDesktop
+Network Trash Folder
+Temporary Items
+.apdisk
 bochsout.txt
 a.img
-boot.bin
+*.bin

+ 7 - 3
bochsrc

@@ -6,12 +6,16 @@ vgaromimage: file=$BXSHARE/VGABIOS-lgpl-latest
 
 mouse: enabled=0
 
-floppya: 1_44=a.img, status=inserted
+# floppya: 1_44=a.img, status=inserted
 
-boot: floppy
+# disk
+ata0: enabled=1, ioaddr1=0x1f0, ioaddr2=0x3f0, irq=14
+ata0-master: type=disk, mode=flat, path="hd30M.img", cylinders=60, heads=16, spt=63
+
+boot: disk
 
 log: bochsout.txt
 
-logprefix: %t%e%d
+# logprefix: %t%e%d
 
 # memory: guest=512, host=256, block_size=512

+ 4 - 0
boot/include/boot.inc

@@ -0,0 +1,4 @@
+;---------------------------loader和kernel-------------------------------------
+MBR_BASE_ADDR equ 0x7c00   ; mbr 在内存中的位置
+LOADER_BASE_ADDR equ 0x900 ; loader 在内存中的位置 
+LOADER_START_SECTOR equ 0x2 ; loader 在硬盘上的逻辑扇区地址,即 LBA 地址 

+ 32 - 0
boot/loader.S

@@ -0,0 +1,32 @@
+; loader
+; 位于硬盘第 2 扇区(LBA 地址)
+; ----------------------------------------------------------------
+%include "boot.inc"
+SECTION LOADER vstart=LOADER_BASE_ADDR
+
+; 输出背景绿色,前景红色,并且跳动的字符串 "2 LOADER"
+    mov byte [gs:0x00], '2'
+    mov byte [gs:0x01], 0xA4
+
+    mov byte [gs:0x02], ' '
+    mov byte [gs:0x03], 0xA4
+
+    mov byte [gs:0x04], 'L'
+    mov byte [gs:0x05], 0xA4
+
+    mov byte [gs:0x06], 'O'
+    mov byte [gs:0x07], 0xA4
+
+    mov byte [gs:0x08], 'A'
+    mov byte [gs:0x09], 0xA4
+
+    mov byte [gs:0x0A], 'D'
+    mov byte [gs:0x0B], 0xA4
+
+    mov byte [gs:0x0C], 'E'
+    mov byte [gs:0x0D], 0xA4
+
+    mov byte [gs:0x0E], 'R'
+    mov byte [gs:0x0F], 0xA4
+
+    jmp $  ; 通过死循环使程序悬停在此

+ 110 - 20
boot/mbr.s

@@ -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

+ 26 - 0
boot/readme.md

@@ -0,0 +1,26 @@
+1. `boot.inc` 文件放置在 `include` 目录下,所以编译的时候需要添加 `-I` 参数
+
+    ```language=sh
+       boot git:(master) ✗ nasm -I include/ -o mbr.bin mbr.s
+       boot git:(master) ✗ nasm -I include/ -o loader.bin loader.S
+    ```
+
+2. 用 `dd` 命令将 mbr.bin 写入虚拟硬盘 `dd if=./mbr.bin of=/此处替换成你的安装目录
+/bochs/hd30M.img bs=512 count=1 conv=notrunc 回车`
+
+    ```sh
+       (base) ➜  boot git:(master) ✗ dd if=mbr.bin of=../hd30M.img bs=512 count=1 conv=notrunc
+        1+0 records in
+        1+0 records out
+        512 bytes transferred in 0.000350 secs (1462864 bytes/sec) 
+    ```
+
+3. 将生成的 `loader.bin` 写入硬盘第 2 个扇区。第 0 个扇区是 MBR,第 1 个扇区是空的未使用。`dd if=./loader.bin of=/此处替换成你的安装目录
+/bochs/hd30M.img bs=512 count=1 seek=2 conv=notrunc 回车`
+
+    ```sh
+        (base) ➜  boot git:(master) ✗ dd if=loader.bin of=../hd30M.img bs=512 count=1 seek=2 conv=notrunc
+        0+1 records in
+        0+1 records out
+        103 bytes transferred in 0.000102 secs (1011741 bytes/sec)
+    ```

二進制
hd30M.img