BIOS function e820 always returns the same result
<p>I've been working on my operating system. To detect the memory map, I use the BIOS function <code>e820</code> but it always returns the same value. </p>

<p>I first wrote the code in Assembly, which I actually copied from OSDev wiki so I am sure that there is no error in the code then wire the code to the C code by a pointer to the <code>ES:DI</code>. Here is my assembly code:</p>

<pre><code>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 -&gt; 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:  
</code></pre>

<p>My code goes on and sets IDT and GDT then switches to protected mode. Here is the C code:</p>

<pre><code>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&lt;memMapLength;i++){
            if(memMapArr[i].type==1){           
                availableMemBytes += memMapArr[i].length;               
            }               
    }
}
</code></pre>

<p>In Assembly, I set the return buffer address <code>ES:DI</code> to <code>0x7c4:0</code> and catch this in C by pointing to <code>0x00007c40</code>. Is this possibly wrong? When I combine the assembly and C with <code>objconv</code> and compile them in NASM as binary, the resulting kernel tells me there is 1 byte of available memory when I run on VirtualBox. How do I resolve my problem? Any suggestions?</p>