文章目录
- 功能号
- 返回信息
- 功能号详解
- 子功能号:0xE820
- 子功能号:0xE801
- 子功能号:0x88
 
- 内存检测示例
- 当前内存分布
- 说明
- 程序
- boot.inc
- mbr.s
- loader.s
 
- 编译并写入硬盘
- 启动bochs运行
 
 
功能号
EAX=0xE820:遍历主机上全部内存
 AX=0xE801:分别检测低15MB和16~4GB的内存
 AH=0x88:最多检测64MB,超过64MB也按照64MB返回
返回信息
返回信息是用地址范围描述符来描述的,用于存储这种描述符的结构称之为地址范围描述符(Address Range Descriptor Structure, ARDS)
 此数据结构共有5个字段,每个字段大小都是4byte,如下
 BaseAddrLow,0~3字节:基地址的低32位
 BaseAddrHigh,4~7字节:基地址的高32位
 LengthLow,8~11字节:内存长度的低32位,以byte为单位
 LengthHigh,12~15字节:内存长度的高32位,以byte为单位
 Type,16~19字节:本段内存的类型
Type字段解释:
 type值=1,AddressRangeMemory,表示可被操作系统使用
 type值=2,AddressRangeReserved,表示被系统保留,操作系统不可用
 type值=其他值,未定义,将来会用到,被操作系统视为AddresssRangeReserved
功能号详解
子功能号:0xE820

 
子功能号:0xE801

 示例:
 
子功能号:0x88

内存检测示例
当前内存分布

说明
boot.inc包含loader加载所需的参数,以及打开保护模式所需的全局描述符
 mbr.s程序:在窗口中输出"enter mbr",然后加载loader.s程序到0x7E00
 loader.s程序:在窗口中输出"enter loader",然后使用BIOS中断0x15的子功能0xE820获取可用内存信息并输出在窗口中,最后进入保护模式在窗口中输出"enter protect mode"
程序
boot.inc
;--------- mbr & loader ---------
LBA_START_SECTOR equ 0x1
SECTOR_COUNT equ 0x4
LOADER_BASE_ADDR equ 0x7E0
LOADER_OFF_ADDR equ 0x0
LOADER_ADDR equ 0x7E00
ARDS_ADDR equ 0x1000
;--------- gdt ---------
DESC_G_4K   equ	  1_00000000000000000000000b   
DESC_D_32   equ	   1_0000000000000000000000b
DESC_L	    equ	    0_000000000000000000000b
DESC_AVL    equ	     0_00000000000000000000b
DESC_LIMIT_CODE2  equ 1111_0000000000000000b
DESC_LIMIT_DATA2  equ DESC_LIMIT_CODE2
DESC_LIMIT_VIDEO2  equ 0000_000000000000000b
DESC_P	    equ		  1_000000000000000b
DESC_DPL_0  equ		   00_0000000000000b
DESC_DPL_1  equ		   01_0000000000000b
DESC_DPL_2  equ		   10_0000000000000b
DESC_DPL_3  equ		   11_0000000000000b
DESC_S_CODE equ		     1_000000000000b
DESC_S_DATA equ	  DESC_S_CODE
DESC_S_sys  equ		     0_000000000000b
DESC_TYPE_CODE  equ	      1000_00000000b	;x=1,c=0,r=0,a=0 代码段是可执行的,非依从的,不可读的,已访问位a清0.  
DESC_TYPE_DATA  equ	      0010_00000000b	;x=0,e=0,w=1,a=0 数据段是不可执行的,向上扩展的,可写的,已访问位a清0.
;code section
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
;data section
DESC_DATA_HIGH4 equ (0x00 << 24) + DESC_G_4K + DESC_D_32 + DESC_L + DESC_AVL + DESC_LIMIT_DATA2 + DESC_P + DESC_DPL_0 + DESC_S_DATA + DESC_TYPE_DATA + 0x00
;video section
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 + 0x0b
;--------------   选择子属性  ---------------
RPL0  equ   00b
RPL1  equ   01b
RPL2  equ   10b
RPL3  equ   11b
TI_GDT	 equ   000b
TI_LDT	 equ   100b
mbr.s
;主引导程序
;------------------------------------------------------------
%include "boot.inc"
SECTION MBR vstart=0x7c00         
   mov ax,cs      
   mov ds,ax
   mov es,ax
   mov ss,ax
   mov fs,ax
   mov ax, 0xB800
   mov gs, ax
   mov sp,0x7c00
; 清屏 利用0x06号功能,上卷全部行,则可清屏。
; -----------------------------------------------------------
;INT 0x10   功能号:0x06	   功能描述:上卷窗口
;------------------------------------------------------
;输入:
;AH 功能号= 0x06
;AL = 上卷的行数(如果为0,表示全部)
;BH = 上卷行属性
;(CL,CH) = 窗口左上角的(X,Y)位置
;(DL,DH) = 窗口右下角的(X,Y)位置
;无返回值:
   mov     ax, 0x600
   mov     bx, 0x700
   mov     cx, 0           ; 左上角: (0, 0)
   mov     dx, 0x184f	   ; 右下角: (80,25),
			   ; VGA文本模式中,一行只能容纳80个字符,共25行。
			   ; 下标从0开始,所以0x18=24,0x4f=79
   int     0x10            ; int 0x10
;;;;;;;;;     打印字符串    ;;;;;;;;;;;
   mov cx, sx - msg
   mov si, msg
   mov di, 0
show_str:
   mov byte al, [si]
   mov byte ah, [sx]
   mov word [gs:di], ax
   inc si
   add di, 2
   loop show_str
   jmp L0
   msg db "enter mbr"
   sx db 0x24
;;;;;;;;;      打字字符串结束	 ;;;;;;;;;;;;;;;
L0:
   push ds
   push di
   mov eax, LBA_START_SECTOR
   push eax
   mov ax, SECTOR_COUNT
   push ax
   mov ax, LOADER_BASE_ADDR
   push ax
   mov ax, LOADER_OFF_ADDR
   push ax
   call read_disk
   add sp, 10
   pop di
   pop ds
   jmp LOADER_ADDR
;;;;;;;;;      read disk      ;;;;;;;;;
; LBA: [bp+10]
; sector count: [bp+8]
; destination: sec=[bp+6], off=[bp+4]
read_disk:
   push bp
   mov bp, sp
;sector_count
   mov dx,0x1f2
   mov ax, [bp+8]
   out dx, al
;sector_addr
   mov dx, 0x1f3
   mov ax, [bp+10]
   out dx, al
   mov dx, 0x1f4
   mov al, ah
   out dx, al
   mov dx, 0x1f5
   mov ax, [bp+12]
   out dx, al
   mov dx, 0x1f6
   mov al, ah
   and al, 0x0f
   or al, 0xe0
   out dx, al
;command_write
   mov dx, 0x1f7
   mov al, 0x20
   out dx, al
disk_test:
   nop          ;give disk a moment
   in al, dx
   and al, 0x88 ;7: BUSY, 3: READY
   cmp al, 0x08 ; (BUSY=0 & READY=1) or not?
   jnz disk_test
;data_read:   
   mov ax, [bp+8]
   mov dx, 256
   mul dx
   mov cx, ax
   mov bx, [bp+4]
   mov ax, [bp+6]
   mov ds, ax
   mov dx, 0x1f0
go_on_read:
   in ax, dx
   mov [bx], ax
   add bx,2
   loop go_on_read
   mov sp, bp
   pop bp
   ret
;;;;;;;;;      read disk      ;;;;;;;;;
   times 510-($-$$) db 0
   db 0x55,0xaa
loader.s
%include "boot.inc"
section loader vstart=LOADER_ADDR
;;;;;;;;;     打印字符串    ;;;;;;;;;;;
   mov cx, sx-msg1
   mov si, msg1
   mov di, 160
show_str:
   mov byte al, [si]
   mov byte ah, [sx]
   mov word [gs:di], ax
   inc si
   add di, 2
   loop show_str
   jmp get_memoinfo
   msg1 db "enter loader"
   sx db 0x24
;;;;;;;;;      打字字符串结束    ;;;;;;;;;;;;;;;
;----- get memory information -----
get_memoinfo:
;----- get all: 0xE820
jmp_e820:
   xor ebx, ebx
   mov edx, 0x534d4150
   mov di, ARDS_ADDR+2
ards_e820:
   mov eax, 0x0000e820
   mov ecx, 20
   int 0x15
   jc Error
   add di, cx
   inc word [ARDS_ADDR]
   cmp ebx, 0
   jnz ards_e820
show_memoinfo:
   mov ax, 0xb800
   mov gs, ax
   mov cx, [ARDS_ADDR]
   mov si, ARDS_ADDR+0x2
   mov di, 320
loop_print:
   push di
addr_info:
   mov edx, [si]
   mov di, memo_addr+22
   call BtH
   shr edx, 16
   mov di, memo_addr+18
   call BtH
   mov edx, [si+4]
   mov di, memo_addr+14
   call BtH
   shr edx, 16
   mov di, memo_addr+10
   call BtH
   
size_info:
   mov edx, [si+8]
   mov di, memo_size+22
   call BtH
   shr edx, 16
   mov di, memo_size+18
   call BtH
   mov edx, [si+12]
   mov di, memo_size+14
   call BtH
   shr edx, 16
   mov di, memo_size+10
   call BtH
type_info:
   mov edx, [si+16]
   mov di, memo_type+14
   call BtH
   shr edx, 16
   mov di, memo_type+10
   call BtH
   pop di
   push cx
   push si
   push di
   mov cx, BtH_Table-memo_addr
   mov ah, 0x24
   mov si, memo_addr
info_print:
   mov al, [si]
   mov [gs:di], ax
   inc si
   add di, 0x2
   loop info_print
   pop di
   add di, 160
   pop si
   add si, 20
   pop cx
   dec cx
   cmp cx, 0
   jne loop_print
   jmp Jmp_there
memo_addr db "ADDR:0xxxxxxxxxxxxxxxxx. "
memo_size db "SIZE:0xxxxxxxxxxxxxxxxx. "
memo_type db "TYPE:0xxxxxxxxx."
BtH_Table db "0123456789ABCDEF"
;params: dx, di
BtH:
   push ax
   push bx
   push edx
   push di
   
   mov bh, 0
   mov bl, dl
   and bl, 00001111b
   mov al, [BtH_Table+bx]
   mov [di], al
   dec di
   mov bl, dl
   shr bl, 4
   mov al, [BtH_Table+bx]
   mov [di], al
   dec di
   mov bl, dh
   and bl, 00001111b
   mov al, [BtH_Table+bx]
   mov [di], al
   dec di
   mov bl, dh
   shr bl, 4
   mov al, [BtH_Table+bx]
   mov [di], al
   pop di
   pop edx
   pop bx
   pop ax
   ret
   
Error:
   
;----- open A20 -----
Jmp_there:
   in al, 0x92
   or al, 00000010b
   out 0x92, al
;----- load gdtr-----
   lgdt [gdt_ptr]
;----- cr0 set -----
   mov eax, cr0
   or eax, 0x00000001
   mov cr0, eax
;----- clear instruction pipeline -----
   jmp dword SELECTOR_CODE:p_m_start
[bits 32]
p_m_start:
   mov ax, SELECTOR_DATA
   mov ds, ax
   mov es, ax
   mov ss, ax
   mov esp, LOADER_ADDR
   mov ax, SELECTOR_VIDEO
   mov gs, ax
   mov ecx, GDT_BASE-msg2
   mov si, msg2
   mov di, 1280
show_str2:
   mov byte al, [si]
   mov byte [gs:di], al
   inc si
   add di, 2
   loop show_str2
   jmp $
;string
msg2 db "enter protect mode"
;GDT_CREATE
GDT_BASE:
   dd 0x00000000, 0x00000000
CODE_DESC:
   dd 0x0000FFFF, DESC_CODE_HIGH4
DATA_DESC:
   dd 0x0000FFFF, DESC_DATA_HIGH4
VIDEO_DESC:
   dd 0x80000007, DESC_VIDEO_HIGH4
GDT_SIZE equ $ - GDT_BASE
GDT_LIMIT equ GDT_SIZE - 1
times 30 dq 0
;SELECTOR_SET
SELECTOR_CODE equ 0000000000001_000b + TI_GDT + RPL0
SELECTOR_DATA equ 0000000000010_000b + TI_GDT + RPL0
SELECTOR_VIDEO equ 0000000000011_000b + TI_GDT + RPL0
;GDT_pointer
gdt_ptr dw GDT_LIMIT
        dd GDT_BASE
编译并写入硬盘
nasm -I OS/include/ -o OS/boot/mbr.bin OS/boot/mbr.s
nasm -I OS/include/ -o OS/boot/loader.bin OS/boot/loader.s
dd if=OS/boot/mbr.bin of=bochs/hd60M.img bs=512 count=1 seek=0 conv=notrunc
dd if=OS/boot/loader.bin of=bochs/hd60M.img bs=512 count=4 seek=1 conv=notrunc
启动bochs运行
./bochs/bin/bochs -f bochs/boot.disk




















