我一直在使用我的操作系统。要检测内存映射,我使用BIOS函数e820
但它总是返回相同的值。
我首先在Assembly中编写代码,我实际上是从OSDev wiki复制的,所以我确信代码中没有错误,然后通过指向ES:DI
的指针将代码连接到C代码。这是我的汇编代码:
mov bx,7c4h; Starting address of memory map array
mov es,bx;
mov di,0h;
; use the INT 0x15, eax= 0xE820 BIOS function to get a memory map
; inputs: es:di -> destination buffer for 24 byte entries
; outputs: bp = entry count, trashes all registers except esi
do_e820:
xor ebx, ebx ; ebx must be 0 to start
xor bp, bp ; keep an entry count in bp
mov edx, 0x0534D4150 ; Place "SMAP" into edx
mov eax, 0xe820
mov [es:di + 20], dword 1 ; force a valid ACPI 3.X entry
mov ecx, 24 ; ask for 24 bytes
int 0x15
jc short .failed ; carry set on first call means "unsupported function"
mov edx, 0x0534D4150 ; Some BIOSes apparently trash this register?
cmp eax, edx ; on success, eax must have been reset to "SMAP"
jne short .failed
test ebx, ebx ; ebx = 0 implies list is only 1 entry long (worthless)
je short .failed
jmp short .jmpin
.e820lp:
mov eax, 0xe820 ; eax, ecx get trashed on every int 0x15 call
mov [es:di + 20], dword 1 ; force a valid ACPI 3.X entry
mov ecx, 24 ; ask for 24 bytes again
int 0x15
jc short .e820f ; carry set means "end of list already reached"
mov edx, 0x0534D4150 ; repair potentially trashed register
.jmpin:
jcxz .skipent ; skip any 0 length entries
cmp cl, 20 ; got a 24 byte ACPI 3.X response?
jbe short .notext
test byte [es:di + 20], 1 ; if so: is the "ignore this data" bit clear?
je short .skipent
.notext:
mov ecx, [es:di + 8] ; get lower uint32_t of memory region length
or ecx, [es:di + 12] ; "or" it with upper uint32_t to test for zero
jz .skipent ; if length uint64_t is 0, skip entry
inc bp ; got a good entry: ++count, move to next storage spot
add di, 24
.skipent:
test ebx, ebx ; if ebx resets to 0, list is complete
jne short .e820lp
.e820f:
mov [memMapLength], bp ; store the entry count
clc ; there is "jc" on end of list to this point, so the carry must be cleared
jmp .done
.failed:
;stc ; "function unsupported" error exit
hlt
ret
.done:
我的代码继续并设置IDT和GDT然后切换到保护模式。这是C代码:
short memMapLength=0;
unsigned long availableMemBytes=0;
typedef struct memoryMapEntry{
unsigned int baseLow;
unsigned int baseHigh;
unsigned long length;
unsigned int type;
unsigned int acpi_null;
} memoryMapEntry;
memoryMapEntry* memMapArr=0;
void DetectMem(){
memMapArr= (memoryMapEntry*)(0x00007c40);
int i;
for(i=0;i<memMapLength;i++){
if(memMapArr[i].type==1){
availableMemBytes += memMapArr[i].length;
}
}
}
在Assembly中,我将返回缓冲区地址ES:DI
设置为0x7c4:0
,并通过指向0x00007c40
在C中捕获它。这可能是错的吗?当我将程序集和C与objconv
组合在一起并在NASM中将它们编译为二进制时,生成的内核告诉我在VirtualBox上运行时有1个字节的可用内存。我该如何解决我的问题?有什么建议吗?