runningwater 1 rok pred
rodič
commit
86bab40199
3 zmenil súbory, kde vykonal 127 pridanie a 20 odobranie
  1. 48 1
      boot/include/boot.inc
  2. 78 18
      boot/loader.S
  3. 1 1
      boot/mbr.s

+ 48 - 1
boot/include/boot.inc

@@ -1,4 +1,51 @@
-;---------------------------loader和kernel-------------------------------------
+;--------------------------- loader和kernel --------------------------------------------------------------------------------------------------------------------
 MBR_BASE_ADDR equ 0x7c00   ; mbr 在内存中的位置
 LOADER_BASE_ADDR equ 0x900 ; loader 在内存中的位置 
 LOADER_START_SECTOR equ 0x2 ; loader 在硬盘上的逻辑扇区地址,即 LBA 地址 
+
+;---------------------------- GDT 描述符属性 -----------------------------------------------------------------------------------------------------------------------
+; 段描述符格式
+;  31~24  23  22  21  20  19~16   15  14~13 12  11~8   7~0
+;  ----------------------------------------------------------
+; |Base | G | D | L |AVL| Limit | P | DPL | S | TYPE | Base |
+;  ----------------------------------------------------------
+; 
+;        31~16                           15~0
+;  ----------------------------------------------------------
+; |         Base                |        Limit              |
+;  ----------------------------------------------------------
+
+DESC_G_4K equ 1OOO_OOOO_OOOO_OOOO_OOOO_OOOOb
+DESC_D_32 equ  1_OO_OOOO_OOOO_OOOO_OOOO_OOOOb
+DESC_L    equ   0_OOOOOOOOOOOOOOOOOOOOOb   ; 64 位代码标记,不设置, clear(0)
+DESC_AVL  equ    0_OOOOOOOOOOOOOOOOOOOOb   ; Reserved for future use
+
+DESC_LIMIT_CODE2  equ 1111_0000_0000_0000_0000b
+DESC_LIMIT_DATA2  equ DESC_LIMIT_CODE2
+DESC_LIMIT_VIDEO2 equ 0000_0000_0000_0000_0000b
+
+DESC_P     equ 1000_0000_0000_0000b  ; 段是否存在。由 CPU 来检查,如果为 0,CPU 将抛出异常
+
+; DPL 表示 4 种特权级,分别是 0、1、2、3 级特权,数据越小,特权越大
+DESC_DPL_0  equ 000_0000_0000_0000b
+DESC_DPL_1  equ 010_0000_0000_0000b
+DESC_DPL_2  equ 100_0000_0000_0000b
+DESC_DPL_3  equ 110_0000_0000_0000b
+
+DESC_S_CODE    equ 1_0000_0000_0000b ; s 为 0 表示系统段,S 为 1 表示非系统段
+DESC_S_DATA    equ DESC_S_CODE
+DESC_S_SYS     equ 0_0000_0000_0000b
+DESC_TYPE_CODE equ 1000_0000_0000b    ; x=1,c=0,r=0,a=0 代码是可执行的,非一致性,不可读,已访问位 a 清 0
+DESC_TYPE_DATA equ 0010_0000_0000b    ; x=0,e=0,w=1,a=0 数据段是不可执行的,向上扩展,可写,已访问位 a 清 0
+
+DESC_CODE_HIGH4 equ (0x00 << 24) + DESC_G_4K + DESC_D_32 + DESC_L + DESC_AVL + DESC_LIMIT_CODE2 + DESC_P + DESC_DPL_0 + DESC_S_CODE + DESC_TYPE_CODE + 0x00
+DESC_DATA_HIGH4 equ (0x00 << 24) + DESC_G_4K + DESC_D_32 + DESC_L + DESC_AVL + DESC_LIMIT_CODE2 + DESC_P + DESC_DPL_0 + DESC_S_DATA + DESC_TYPE_DATA + 0x00
+DESC_VIDEO_HIGH4 equ (0x00 << 24) + DESC_G_4K + DESC_D_32 + DESC_L + DESC_AVL + DESC_LIMIT_VIDEO2 + DESC_P + DESC_DPL_0 + DESC_S_DATA + DESC_TYPE_DATA + 0x00
+
+; ------------------------------------- 选择子属性 ---------------------------------------------------------------------------------------------------------------
+RPL0 equ 00b
+RPL1 equ 01b
+RPL2 equ 10b
+RPL3 equ 11b
+TI_GDT equ 000b 
+TI_LDT equ 100b

+ 78 - 18
boot/loader.S

@@ -3,30 +3,90 @@
 ; ----------------------------------------------------------------
 %include "boot.inc"
 SECTION LOADER vstart=LOADER_BASE_ADDR
+LOADER_STACK_TOP equ LOADER_BASE_ADDR
+jmp loader_start
 
-; 输出背景绿色,前景红色,并且跳动的字符串 "2 LOADER"
-    mov byte [gs:0x00], '2'
-    mov byte [gs:0x01], 0xA4
+; 构建 GDT 及其内部描述符(GDT 的第 0 个描述符不可用)
+GDT_BASE: dd 0x00000000
+        dd 0x00000000
 
-    mov byte [gs:0x02], ' '
-    mov byte [gs:0x03], 0xA4
+CODE_DESC: dd 0x0000FFFF
+        dd DESC_CODE_HIGH4
 
-    mov byte [gs:0x04], 'L'
-    mov byte [gs:0x05], 0xA4
+DATA_STACK_DESC: dd 0x0000FFFF
+        dd DESC_DATA_HIGH4
 
-    mov byte [gs:0x06], 'O'
-    mov byte [gs:0x07], 0xA4
+VIDEO_DESC: dd 0x80000007 ; limit=(0xbffff-0xb8000)/4k=0x7
+        dd DESC_VIDEO_HIGH4 ; 此时 dpl 为 0
 
-    mov byte [gs:0x08], 'A'
-    mov byte [gs:0x09], 0xA4
+GDT_SIZE equ $ - GDT_BASE
+GDT_LIMIT equ GDT_SIZE - 1
+times 60 dq 0   ; 此处预留 60 个描述符的空位
 
-    mov byte [gs:0x0A], 'D'
-    mov byte [gs:0x0B], 0xA4
+SELECTOR_CODE equ (0x0001<<3) + TI_GDT + RPL0 ; 相当于 (CODE_DESC - GDT_BASE)/8 + TI_GDT + RPL0 
+SELECTOR_DATA equ (0x0002<<3) + TI_GDT + RPL0
+SELECTOR_VIDEO equ (0x0003<<3) + TI_GDT + RPL0
 
-    mov byte [gs:0x0C], 'E'
-    mov byte [gs:0x0D], 0xA4
+; 以下是 gdt 的指针,前 2 个字节是 gdt 界限,后 4 字节是 gdt 起始地址
+gdt_ptr dw GDT_LIMIT 
+        dd GDT_BASE
+loadermsg db '2 loader in real.'
 
-    mov byte [gs:0x0E], 'R'
-    mov byte [gs:0x0F], 0xA4
+loader_start:
+;----------------------------------------------------------------
+; INT 0x10  功能号:0x13   功能描述: 打印字符串
+;----------------------------------------------------------------
+; 输入:
+; AH 子功能号 13H
+; BH = 页码
+; BL = 属性(若 AL=00H 或 01H)
+; CX = 字符串长度
+; (DH、DL) = 坐标(行,列)
+; ES:BP = 字符串地址
+; AL=显示输出方式
+;   0 ---- 字符串中只含显示字符,其显示属性在 BL 中,显示后,光标位置不变
+;   1 ---- 字符串中只含显示字符,其显示属性在 BL 中,显示后,光标位置不变
+;   2 ---- 字符串中含显示字符和显示属性。显示后,光标位置不变
+;   3 ---- 字符串中含显示字符和显示属性。显示后,光标位置改变
+; 无返回值
+    mov sp, LOADER_BASE_ADDR
+    mov bp, loadermsg        ; ES:BP = 字符串地址
+    mov cx, 17               ; CX = 字符串长度
+    mov ax, 0x1301           ; AH = 13h, AL = 01h
+    mov bx ,0x001f           ; 页号 0(BH=0)蓝底粉红色(BL=1fh)
+    mov dx, 0x1800           ; 坐标(行,列)
+    int 0x10                 ; 10h 号中断
 
-    jmp $  ; 通过死循环使程序悬停在此
+;---------------------- 准备进入保护模式 ------------------------------------------
+; 1 打开 A20
+; 2 加载 GDT
+; 3 将 cr0 的 pe 位置 1
+
+    ;-------------------------- 打开 A20 --------------------------------
+    in al, 0x92
+    or al, 0000_0010b
+    out 0x92, al
+
+    ;-------------------------- 加载 GDT --------------------------------
+    LGDT [gdt_ptr]
+
+    ;-------------------------- cr0 第 0 位置 1 --------------------------
+    mov eax, cr0
+    or eax, 0x00000001
+    mov cr0, eax 
+
+    jmp dword SELECTOR_CODE:p_mode_start ; 刷新流水线
+
+[bits 32]
+p_mode_start:
+    mov ax, SELECTOR_DATA
+    mov ds, ax 
+    mov es, ax 
+    mov ss, ax 
+    mov esp, LOADER_STACK_TOP
+    mov ax, SELECTOR_VIDEO
+    mov gs, ax 
+
+    mov byte [gs:160], 'P'
+
+    jmp $

+ 1 - 1
boot/mbr.s

@@ -17,7 +17,7 @@ SECTION MBR vstart=MBR_BASE_ADDR
 	
     mov eax, LOADER_START_SECTOR ; 起始扇区地址: LBA 地址
     mov bx, LOADER_BASE_ADDR ; 写入的地址
-    mov cx, 1 ; 待写入的扇区数(1 个扇区)
+    mov cx, 4 ; 待写入的扇区数(4 个扇区)
     call rd_disk_m_16  ; 读取硬盘数据
 
     jmp LOADER_BASE_ADDR