获取物理内存容量(下)

我们这节课BIOS提供的(int 0x15)号中断的高级功能(eax = 0xE820),遍历主机上所有的内存范围(内存地址段),获取各个内存范围的详细信息

int 0x15 进阶版功能

中断参数

  • eax = 0xE820 (固定值)
  • edx = 0x534D4150 (固定值)
  • ebx --> 初始参数必须为0,终止标志
  • ecx --> ARDS 结构体大小 (20字节)
  • es : di --> ARDS 结构体数组 (每个元素占用20字节)



地址范围描述结构 (Address Range Descriptor Structure)

int 0x15 进阶功能示例

%include "inc.asm"

org 0x9000

jmp ENTRY_SEGMENT

[section .gdt]
; GDT definition
;                                 段基址,       段界限,       段属性
GDT_ENTRY		: Descriptor		0, 			    0,		      0
CODE32_DESC		: Descriptor		0, 	   Code32SegLen - 1,  DA_32 + DA_C
VIDEO_DESC	    : Descriptor     0xb8000,       0x7fff,       DA_32 + DA_DRWA
DATA32_DESC		: Descriptor	    0,     Data32SegLen - 1,  DA_32 + DA_DRW
STACK32_DESC	: Descriptor        0,      TopOfStack32,     DA_32 + DA_DRW
; GDT end  

GdtLen	  equ	   $ - GDT_ENTRY
GdtPtr:    
		dw	GdtLen - 1
		dd	0

; GDT Selector
Code32Selector	equ    (0x0001 << 3) + SA_TIG + SA_RPL0
VideoSelector	equ    (0x0002 << 3) + SA_TIG + SA_RPL0
Data32Selector  equ    (0x0003 << 3) + SA_TIG + SA_RPL0
Stack32Selector equ    (0x0004 << 3) + SA_TIG + SA_RPL0
; end of [section .gdt]

TopOfStack16	equ    0x7c00

; get hardware memory infomation
MEM_SIZE	  times	   4     db  0x00	; int mem_size = 0
MEM_ARDS_NUM  times    4     db  0x00	; int men_addr_num = 0
MEM_ARDS	  times 20 * 64  db  0x00	; ARDS mem_adrs[64] = {0}

[section .dat]
[bits 32]
DATA32_SEGMENT:
	DTOS		        db    "D.T.OS!", 0
	DTOS_Offset	        equ	  DTOS - $$ 

	HELLOWORLD		    db    "Hello, World!", 0
	HELLOWORLD_Offset   equ   HELLOWORLD - $$

Data32SegLen	equ   $ - DATA32_SEGMENT

[section .s16]
[bits 16]
ENTRY_SEGMENT:
	mov ax, cs
	mov ds, ax
	mov es, ax
	mov ss, ax
	mov sp, TopOfStack16

	;
	call InitSysMemBuf

	; initialize GDT for 32 bits code segment
	mov esi, CODE32_SEGMENT
	mov edi, CODE32_DESC
	call InitDescItem

	mov esi, DATA32_SEGMENT
	mov edi, DATA32_DESC
	call InitDescItem

	mov esi, STACK32_SEGMENT
	mov edi, STACK32_DESC
	call InitDescItem

	; initalize GDT pointer struct
	mov eax, 0
	mov ax, ds
	shl eax, 4
	add eax, GDT_ENTRY
	mov dword [GdtPtr + 2], eax

	; 1. load GDT
    lgdt [GdtPtr]
    
    ; 2. close interrupt
    cli 
    
    ; 3. open A20
    in al, 0x92
    or al, 00000010b
    out 0x92, al
    
    ; 4. enter protect mode
    mov eax, cr0
    or eax, 0x01
    mov cr0, eax
    
    ; 5. jump to 32 bits code
    jmp dword Code32Selector : 0


; esi    --> code segment labelBACK_ENTRY_SEGMENT
; edi    --> descriptor label
InitDescItem:
	push eax

	mov eax, 0
	mov ax, cs
	shl eax, 4
	add eax, esi
	mov word [edi + 2], ax
	shr eax, 16
	mov byte [edi + 4], al
	mov byte [edi + 7], ah
	
	pop eax

	ret

;
;
GetMemSize:
	push eax
	push ebx
	push ecx
	push edx

	mov dword [MEM_SIZE], 0

	xor eax, eax
	mov eax, 0xE801
	int 0x15	

	jc geterr

	mov ecx, 1

	shl eax, 10    ; eax = eax * 1024
	shl ebx, 6     ; ebx = ebx * 64
	shl ebx, 10    ; ebx = ebx * 1024
	shl ecx, 20	   ; ecx = 1M

	add [MEM_SIZE], eax
	add [MEM_SIZE], ebx
	add [MEM_SIZE], ecx

	jmp getok

geterr:
	mov dword [MEM_SIZE], 0

getok:
	pop edx
	pop ecx
	pop ebx
	pop eax

	ret

; return
;    eax  --> 0 : successd    1 : failed
InitSysMemBuf:
	push edi
	push edx
	push ebx
	push ecx

	mov edi, MEM_ARDS
	mov ebx, 0

doloop:
	mov eax, 0xE820
	mov edx, 0x534D4150
    mov ecx, 20
	int 0x15
	
	jc memerr
	
	add edi, 20
	inc dword [MEM_ARDS_NUM]
	
	cmp ebx, 0
	jne doloop

	mov eax, 0
	jmp memok

memerr:
	mov eax, 1

memok:
	pop ecx
	pop ebx
	pop edx
	pop edi

	ret

[section .s32]
[bits 32]
CODE32_SEGMENT:
	mov ax, VideoSelector
	mov gs, ax

	mov ax, Stack32Selector
	mov ss, ax

	mov eax, TopOfStack32
	mov esp, eax

	mov ax, Data32Selector
	mov ds, ax

	mov ebp, DTOS_Offset
	mov bx, 0x0c
	mov dh, 13
	mov dl, 33
	call PrintString

	mov ebp, HELLOWORLD_Offset
	mov bx, 0x0c
	mov dh, 14
	mov dl, 30
	call PrintString
	

	jmp $

; ds:ebp    --> string address
; bx        --> attribute
; dx        --> dh : row, dl : col
PrintString:
	push ebp
	push cx
	push eax
	push dx
	push edi

print:
	mov cl, [ds:ebp]
	cmp cl, 0
	je end
	mov eax, 80
	mul dh
	add al, dl
	shl eax, 1
	mov edi, eax
	mov ah, bl
	mov al, cl
	mov [gs:edi], ax
	inc ebp
	inc dl
	jmp print
	
end:
	pop edi
	pop dx
	pop eax
	pop cx
	pop ebp

	ret

Code32SegLen	equ    $ - CODE32_SEGMENT


[section .gs]
[bits 32]
STACK32_SEGMENT:
	times 1024 * 4 db 0

Stack32SegLen	equ    $ - STACK32_SEGMENT
TopOfStack32    equ    Stack32SegLen - 1

 第33行我们定义了MEM_ARDS_NUM,MEM_ARDS_NUM表示主机上有多少个段。第34行我们定义了MEM_ARDS,MEM_ARDS为ARDS数组的起始地址,大小我们定义为64个ARDS,每个ARDS为20个字节。

157 - 193行,我们定义了InitSysMemBuf,这个函数利用BIOS提供的 int 0x15 的高级功能来获取主机上所有段的段信息。

第57行,我们通过调用InitSysMemBuf这个函数来获取主机上的所有段信息。

下面我们来进行断点调试

 InitSysMemBuf函数调用前,MEM_ARDS_NUM = 0;InitSysMemBuf函数调用后,eax = 0,说明这个函数没有调用出错,MEM_ARDS_NUM = 6,表明这个主机上一共有6个段。

下面我们来查看这6个段的具体信息

 在查看前6个段的段信息时,它的值不为0。在查看第7个段的段信息,它的值为0,则又说明了这个我们一个查到了6个段。

ARDS记录中并没有包含物理内存容量的信息,那么获取这些记录有什么意义?


ARDS结构体中的TYPE成员

1 - AddressRangeMemory

  • 这段内存可以被操作系统使用

2 - AddressRangeReserved

  • 内存使用中或被保留,操作系统不可用

其他值 - 未定义

  • 保留,可用作 AddressRangeMemory 处理

在32位系统中

ARDS结构体中的 BaseAddrHigh 和 LengthHigh 均为0

物理内存容量需要通过属性为1的内存段计算

计算方式为:max{BaseAddrLow + LengthLow}

  • BaseAddrLow + LengthLow 是一段内存的地址上限

 根据ARDS记录计算物理内存

我们修改了InitSysMemBuf这个函数,如下

; return
;    eax  --> 0 : successd    1 : failed
InitSysMemBuf:
	push edi
	push edx
	push ebx
	push ecx

	mov edi, MEM_ARDS
	mov ebx, 0

doloop:
	mov eax, 0xE820
	mov edx, 0x534D4150
    mov ecx, 20
	int 0x15
	
	jc memerr
	
	mov eax, [edi + 16]
	cmp eax, 1
	jne next
	
	mov eax, [edi]
	add eax, [edi + 8]
	cmp dword [MEM_SIZE], eax
	jnb next

	mov dword [MEM_SIZE], eax

next:
	add edi, 20
	inc dword [MEM_ARDS_NUM]
	
	cmp ebx, 0
	jne doloop

	mov eax, 0
	jmp memok

memerr:
	mov eax, 1

memok:
	pop ecx
	pop ebx
	pop edx
	pop edi

	ret

 TYPE为1表示这段物理内存可被操作系统使用,我们取这段物理内存的最大值,放入MEM_SIZE中。

下面,我们来进行断点调试,查看MEM_SIZE的值

在调用 InitSysMemBuf 之后,MEM_SIZE = 0x01FF0000字节,并不等于我们设置的32M,我们来查看ARDS中的值,来判断我们实现的算法是否存在错误

我们发现TYPE为1的最大物理内存为 0x01FF0000字节,和我们得到的大小是一样的,这样就证明了我们实现的算法并没有出错。

 这里有一个TYPE为3的一个段,大小为0x10000,我们获取到的物理内存加上这个大小就为32M。我们猜想:我们要获得的物理内存大小可能和这个段有关系。

Linux中获取物理内存的策略

 在Linux中,获取物理内存是比对了BIOS中断提供的三种获取物理内存的办法。

 实验中使用的策略

  1. 通过 0xE801 计算物理内存大小
  2. 通过 0xE820 获取各个ARDS 并填入结构体数组
  3. 根据 ARDS 结构体数组计算物理内存大小
  4.  选择计算得到的较大内存容量作为最终结果
%include "inc.asm"

org 0x9000

jmp ENTRY_SEGMENT

[section .gdt]
; GDT definition
;                                 段基址,       段界限,       段属性
GDT_ENTRY		: Descriptor		0, 			    0,		      0
CODE32_DESC		: Descriptor		0, 	   Code32SegLen - 1,  DA_32 + DA_C
VIDEO_DESC	    : Descriptor     0xb8000,       0x7fff,       DA_32 + DA_DRWA
DATA32_DESC		: Descriptor	    0,     Data32SegLen - 1,  DA_32 + DA_DRW
STACK32_DESC	: Descriptor        0,      TopOfStack32,     DA_32 + DA_DRW
SYSDAT32_DESC   : Descriptor        0,    SysDat32SegLen - 1, DA_32 + DA_DR
; GDT end  

GdtLen	  equ	   $ - GDT_ENTRY
GdtPtr:    
		dw	GdtLen - 1
		dd	0

; GDT Selector
Code32Selector	 equ    (0x0001 << 3) + SA_TIG + SA_RPL0
VideoSelector	 equ    (0x0002 << 3) + SA_TIG + SA_RPL0
Data32Selector   equ    (0x0003 << 3) + SA_TIG + SA_RPL0
Stack32Selector  equ    (0x0004 << 3) + SA_TIG + SA_RPL0
SysDat32Selector equ    (0x0004 << 3) + SA_TIG + SA_RPL0
; end of [section .gdt]

TopOfStack16	equ    0x7c00

[section .sysdat]
SYSDAT32_SEGMENT:
	MEM_SIZE	         times 4 db  0x00	; int mem_size = 0
	MEM_SIZE_OFFSET      equ   MEM_SIZE - $$  
	MEM_ARDS_NUM         times 4 db  0x00	; int men_addr_num = 0
	MEM_ADDR_NUM_OFFSET  equ   MEM_ARDS_NUM - $$
	MEM_ARDS	         times 20 * 64  db  0x00	; ARDS mem_adrs[64] = {0}
	MEM_ARDS_OFFSET      equ   MEM_ARDS - $$

SysDat32SegLen	equ    $ - SYSDAT32_SEGMENT

[section .d16]
DATA16_SEGMENT:
	MEM_ERR_MSG      db  "[FAILED] memory check error..."
	MEM_ERR_MSG_LEN  equ $ - MEM_ERR_MSG

Data16SegLen    equ    $ - DATA16_SEGMENT

[section .dat]
[bits 32]
DATA32_SEGMENT:
	DTOS		        db    "D.T.OS!", 0
	DTOS_Offset	        equ	  DTOS - $$ 

	HELLOWORLD		    db    "Hello, World!", 0
	HELLOWORLD_Offset   equ   HELLOWORLD - $$

Data32SegLen	equ   $ - DATA32_SEGMENT

[section .s16]
[bits 16]
ENTRY_SEGMENT:
	mov ax, cs
	mov ds, ax
	mov es, ax
	mov ss, ax
	mov sp, TopOfStack16

	; get system memory information
	call InitSysMemBuf

	cmp eax, 0
	jnz CODE16_MEM_ERROR

	; initialize GDT for 32 bits code segment
	mov esi, CODE32_SEGMENT
	mov edi, CODE32_DESC
	call InitDescItem

	mov esi, DATA32_SEGMENT
	mov edi, DATA32_DESC
	call InitDescItem

	mov esi, STACK32_SEGMENT
	mov edi, STACK32_DESC
	call InitDescItem

	mov esi, SYSDAT32_SEGMENT
	mov edi, SYSDAT32_DESC
	call InitDescItem

	; initalize GDT pointer struct
	mov eax, 0
	mov ax, ds
	shl eax, 4
	add eax, GDT_ENTRY
	mov dword [GdtPtr + 2], eax

	; 1. load GDT
    lgdt [GdtPtr]
    
    ; 2. close interrupt
    cli 
    
    ; 3. open A20
    in al, 0x92
    or al, 00000010b
    out 0x92, al
    
    ; 4. enter protect mode
    mov eax, cr0
    or eax, 0x01
    mov cr0, eax
    
    ; 5. jump to 32 bits code
    jmp dword Code32Selector : 0

CODE16_MEM_ERROR:
	mov bp, MEM_ERR_MSG
	mov cx, MEM_ERR_MSG_LEN
	call Print

	jmp $

; es:bp  --> string address
; cx     --> string length
Print:
	push ax
	push bx

	mov dx, 0
	mov ax, 0x1301
	mov bx, 0x0007

	int 0x10

	pop bx
	pop ax

	ret 

; esi    --> code segment labelBACK_ENTRY_SEGMENT
; edi    --> descriptor label
InitDescItem:
	push eax

	mov eax, 0
	mov ax, cs
	shl eax, 4
	add eax, esi
	mov word [edi + 2], ax
	shr eax, 16
	mov byte [edi + 4], al
	mov byte [edi + 7], ah
	
	pop eax

	ret

;
;
GetMemSize:
	push eax
	push ebx
	push ecx
	push edx

	mov dword [MEM_SIZE], 0

	xor eax, eax
	mov eax, 0xE801
	int 0x15	

	jc geterr

	mov ecx, 1

	shl eax, 10    ; eax = eax * 1024
	shl ebx, 6     ; ebx = ebx * 64
	shl ebx, 10    ; ebx = ebx * 1024
	shl ecx, 20	   ; ecx = 1M

	add [MEM_SIZE], eax
	add [MEM_SIZE], ebx
	add [MEM_SIZE], ecx

	jmp getok

geterr:
	mov dword [MEM_SIZE], 0

getok:
	pop edx
	pop ecx
	pop ebx
	pop eax

	ret

; return
;    eax  --> 0 : successd    1 : failed
InitSysMemBuf:
	push edi
	push edx
	push ebx
	push ecx

	call GetMemSize

	mov edi, MEM_ARDS
	mov ebx, 0

doloop:
	mov eax, 0xE820
	mov edx, 0x534D4150
    mov ecx, 20
	int 0x15
	
	jc memerr
	
	mov eax, [edi + 16]
	cmp eax, 1
	jne next
	
	mov eax, [edi]
	add eax, [edi + 8]
	cmp dword [MEM_SIZE], eax
	jnb next

	mov dword [MEM_SIZE], eax

next:
	add edi, 20
	inc dword [MEM_ARDS_NUM]
	
	cmp ebx, 0
	jne doloop

	mov eax, 0
	jmp memok

memerr:
	mov eax, 1
	mov dword [MEM_SIZE], 0
	mov dword [MEM_ARDS_NUM], 0

memok:
	pop ecx
	pop ebx
	pop edx
	pop edi

	ret

[section .s32]
[bits 32]
CODE32_SEGMENT:
	mov ax, VideoSelector
	mov gs, ax

	mov ax, Stack32Selector
	mov ss, ax

	mov eax, TopOfStack32
	mov esp, eax

	mov ax, Data32Selector
	mov ds, ax

	mov ebp, DTOS_Offset
	mov bx, 0x0c
	mov dh, 13
	mov dl, 33
	call PrintString

	mov ebp, HELLOWORLD_Offset
	mov bx, 0x0c
	mov dh, 14
	mov dl, 30
	call PrintString
	

	jmp $

; ds:ebp    --> string address
; bx        --> attribute
; dx        --> dh : row, dl : col
PrintString:
	push ebp
	push cx
	push eax
	push dx
	push edi

print:
	mov cl, [ds:ebp]
	cmp cl, 0
	je end
	mov eax, 80
	mul dh
	add al, dl
	shl eax, 1
	mov edi, eax
	mov ah, bl
	mov al, cl
	mov [gs:edi], ax
	inc ebp
	inc dl
	jmp print
	
end:
	pop edi
	pop dx
	pop eax
	pop cx
	pop ebp

	ret

Code32SegLen	equ    $ - CODE32_SEGMENT


[section .gs]
[bits 32]
STACK32_SEGMENT:
	times 1024 * 4 db 0

Stack32SegLen	equ    $ - STACK32_SEGMENT
TopOfStack32    equ    Stack32SegLen - 1

我们通过InitSysMemBuf这个函数返回 0xE820 和 0xE801 中较大的物理内存,MEM_SIZE记录了较大的物理内存。

 MEM_SIZE 的值为32M。

我们在16位实模式下新增了 InitSysMemBuf 这个函数的出错处理,我们打印一个出错字符串,我们在241行故意令eax = 1, 查看运行结果。

正确的打印出了出错字符串。

下面我们将有关物理内存大小的数据定义为32位保护模式下的只读数据段,因为系统上电后,一开始是工作在实模式下,进行初始化工作,包括获取物理内存,随后就进入了保护模式,系统大部分时间是运行在保护模式下的。这些数据是系统相关的数据,需要保护起来,并将特权级设为0,只有内核才能访问这段数据。 

%include "inc.asm"

org 0x9000

jmp ENTRY_SEGMENT

[section .gdt]
; GDT definition
;                                 段基址,       段界限,       段属性
GDT_ENTRY		: Descriptor		0, 			    0,		      0
CODE32_DESC		: Descriptor		0, 	   Code32SegLen - 1,  DA_32 + DA_C
VIDEO_DESC	    : Descriptor     0xb8000,       0x7fff,       DA_32 + DA_DRWA
DATA32_DESC		: Descriptor	    0,     Data32SegLen - 1,  DA_32 + DA_DRW
STACK32_DESC	: Descriptor        0,      TopOfStack32,     DA_32 + DA_DRW
SYSDAT32_DESC   : Descriptor        0,    SysDat32SegLen - 1, DA_32 + DA_DR
; GDT end  

GdtLen	  equ	   $ - GDT_ENTRY
GdtPtr:    
		dw	GdtLen - 1
		dd	0

; GDT Selector
Code32Selector	 equ    (0x0001 << 3) + SA_TIG + SA_RPL0
VideoSelector	 equ    (0x0002 << 3) + SA_TIG + SA_RPL0
Data32Selector   equ    (0x0003 << 3) + SA_TIG + SA_RPL0
Stack32Selector  equ    (0x0004 << 3) + SA_TIG + SA_RPL0
SysDat32Selector equ    (0x0004 << 3) + SA_TIG + SA_RPL0
; end of [section .gdt]

TopOfStack16	equ    0x7c00

[section .sysdat]
SYSDAT32_SEGMENT:
	MEM_SIZE	         times 4 db  0x00	; int mem_size = 0
	MEM_SIZE_OFFSET      equ   MEM_SIZE - $$  
	MEM_ARDS_NUM         times 4 db  0x00	; int men_addr_num = 0
	MEM_ADDR_NUM_OFFSET  equ   MEM_ARDS_NUM - $$
	MEM_ARDS	         times 20 * 64  db  0x00	; ARDS mem_adrs[64] = {0}
	MEM_ARDS_OFFSET      equ   MEM_ARDS - $$

SysDat32SegLen	equ    $ - SYSDAT32_SEGMENT

[section .d16]
DATA16_SEGMENT:
	MEM_ERR_MSG      db  "[FAILED] memory check error..."
	MEM_ERR_MSG_LEN  equ $ - MEM_ERR_MSG

Data16SegLen    equ    $ - DATA16_SEGMENT

[section .dat]
[bits 32]
DATA32_SEGMENT:
	DTOS		        db    "D.T.OS!", 0
	DTOS_Offset	        equ	  DTOS - $$ 

	HELLOWORLD		    db    "Hello, World!", 0
	HELLOWORLD_Offset   equ   HELLOWORLD - $$

Data32SegLen	equ   $ - DATA32_SEGMENT

[section .s16]
[bits 16]
ENTRY_SEGMENT:
	mov ax, cs
	mov ds, ax
	mov es, ax
	mov ss, ax
	mov sp, TopOfStack16

	; get system memory information
	call InitSysMemBuf

	cmp eax, 0
	jnz CODE16_MEM_ERROR

	; initialize GDT for 32 bits code segment
	mov esi, CODE32_SEGMENT
	mov edi, CODE32_DESC
	call InitDescItem

	mov esi, DATA32_SEGMENT
	mov edi, DATA32_DESC
	call InitDescItem

	mov esi, STACK32_SEGMENT
	mov edi, STACK32_DESC
	call InitDescItem

	mov esi, SYSDAT32_SEGMENT
	mov edi, SYSDAT32_DESC
	call InitDescItem

	; initalize GDT pointer struct
	mov eax, 0
	mov ax, ds
	shl eax, 4
	add eax, GDT_ENTRY
	mov dword [GdtPtr + 2], eax

	; 1. load GDT
    lgdt [GdtPtr]
    
    ; 2. close interrupt
    cli 
    
    ; 3. open A20
    in al, 0x92
    or al, 00000010b
    out 0x92, al
    
    ; 4. enter protect mode
    mov eax, cr0
    or eax, 0x01
    mov cr0, eax
    
    ; 5. jump to 32 bits code
    jmp dword Code32Selector : 0

CODE16_MEM_ERROR:
	mov bp, MEM_ERR_MSG
	mov cx, MEM_ERR_MSG_LEN
	call Print

	jmp $

; es:bp  --> string address
; cx     --> string length
Print:
	push ax
	push bx

	mov dx, 0
	mov ax, 0x1301
	mov bx, 0x0007
mov eax, 0
	jmp memok

	int 0x10

	pop bx
	pop ax

	ret 

; esi    --> code segment labelBACK_ENTRY_SEGMENT
; edi    --> descriptor label
InitDescItem:
	push eax

	mov eax, 0
	mov ax, cs
	shl eax, 4
	add eax, esi
	mov word [edi + 2], ax
	shr eax, 16
	mov byte [edi + 4], al
	mov byte [edi + 7], ah
	
	pop eax

	ret

;
;
GetMemSize:
	push eax
	push ebx
	push ecx
	push edx

	mov dword [MEM_SIZE], 0

	xor eax, eax
	mov eax, 0xE801
	int 0x15	

	jc geterr

	mov ecx, 1

	shl eax, 10    ; eax = eax * 1024
	shl ebx, 6     ; ebx = ebx * 64
	shl ebx, 10    ; ebx = ebx * 1024
	shl ecx, 20	   ; ecx = 1M

	add [MEM_SIZE], eax
	add [MEM_SIZE], ebx
	add [MEM_SIZE], ecx

	jmp getok

geterr:
	mov dword [MEM_SIZE], 0

getok:
	pop edx
	pop ecx
	pop ebx
	pop eax

	ret

; return
;    eax  --> 0 : successd    1 : failed
InitSysMemBuf:
	push edi
	push edx
	push ebx
	push ecx

	call GetMemSize

	mov edi, MEM_ARDS
	mov ebx, 0

doloop:
	mov eax, 0xE820
	mov edx, 0x534D4150
	mov ecx, 20
	int 0x15
	
	jc memerr
	
	mov eax, [edi + 16]
	cmp eax, 1
	jne next
	
	mov eax, [edi]
	add eax, [edi + 8]
	cmp dword [MEM_SIZE], eax
	jnb next

	mov dword [MEM_SIZE], eax

next:
	add edi, 20
	inc dword [MEM_ARDS_NUM]
	
	cmp ebx, 0
	jne doloop

	mov eax, 0
	jmp memok

memerr:
	mov eax, 1
	mov dword [MEM_SIZE], 0
	mov dword [MEM_ARDS_NUM], 0

memok:
	pop ecx
	pop ebx
	pop edx
	pop edi

	ret

[section .s32]
[bits 32]
CODE32_SEGMENT:
	mov ax, VideoSelector
	mov gs, ax

	mov ax, Stack32Selector
	mov ss, ax

	mov eax, TopOfStack32
	mov esp, eax

	mov ax, Data32Selector
	mov ds, ax

	mov ebp, DTOS_Offset
	mov bx, 0x0c
	mov dh, 13
	mov dl, 33
	call PrintString

	mov ebp, HELLOWORLD_Offset
	mov bx, 0x0c
	mov dh, 14
	mov dl, 30
	call PrintString
	

	jmp $

; ds:ebp    --> string address
; bx        --> attribute
; dx        --> dh : row, dl : col
PrintString:
	push ebp
	push cx
	push eax
	push dx
	push edi

print:
	mov cl, [ds:ebp]
	cmp cl, 0
	je end
	mov eax, 80
	mul dh
	add al, dl
	shl eax, 1
	mov edi, eax
	mov ah, bl
	mov al, cl
	mov [gs:edi], ax
	inc ebp
	inc dl
	jmp print
	
end:
	pop edi
	pop dx
	pop eax
	pop cx
	pop ebp

	ret

Code32SegLen	equ    $ - CODE32_SEGMENT


[section .gs]
[bits 32]
STACK32_SEGMENT:
	times 1024 * 4 db 0

Stack32SegLen	equ    $ - STACK32_SEGMENT
TopOfStack32    equ    Stack32SegLen - 1
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值