Page 1 of 1

Can't get memory map with E820 (SOLVED)

Posted: Sat Jul 24, 2021 1:01 am
by geomal
Hello everyone!

I've been trying to fetch a memory map with E820, but I am doing something wrong I guess.
I have a C structure based on how E820 entries are supposed to be, and E820 runs successfully, but I end up getting no entries for some reason.

Here are the relevant codes:

Code: Select all

global do_e820

 do_e820:
    pushad
	xor ax,ax
	;mov ax, 0x0000
	mov es,ax
    xor ebp, ebp			;/* entry number */
    xor ebx, ebx		;	/* ebx must be 0 to start */
	mov edi, 0xA000 ; /*  The E820 entries are supposed to be saved in es:edi, in our case 0x0A000. I made several attempts with different addresses. */
.loopy_e820:
	mov edx, 0x0534D4150		;/* magical number: "SMAP" */
	mov eax, 0xe820
	mov ecx, 24
	int 0x15
	jc short .end_e820
	cmp eax, edx
	jne short .fail_e820			;/* eax != SMAP for error */
	jcxz .next_e820			;/* ignore 0-length entry */
	inc ebp			;/* increase entry number */
	add edi, 24	;/* edi points next entry space */
.next_e820:
	test ebx, ebx			;/* if ebx equals 0, list ends */
	je short .end_e820
	mov eax, ebp
	cmp eax, 128
	je short .fail_e820			;/* entry number >= E820_MAX for error */
	jmp short .loopy_e820
.end_e820:
	cmp eax, 0x01		;/* entry number <= 1 for error */
	je short .fail_e820
	xor eax, eax
	mov  [ 0x00000dfd0], ebp ; /* The total number of entries. Always 6 */
	xor ebp,ebp
    popad
    ret
.fail_e820:
    stc
	jmp .fail_e820			
and the relevant C part:

Code: Select all

void boot_memory_init()
{
	int address = 0x00000dfd0;
	int* a = (int*)address;
	int content = *a;
  	printlnVGA(itoa(content, ' ', 10)); //Prints the content of 0x00000dfd0 as decimal. Always 6.

  	struct boot_param *myboot_param = (struct boot_param *)(E820_ADDRESS); //The address of es:edi. I tried with edi too, just in case.

	struct e820_entry *entry = myboot_param->memMapp;
	unsigned long i, npage, num = myboot_param->e820_num;

      printlnVGA(itoa(num, ' d', 10)); //Number of entries. Always 0.

	unsigned long memory_end = 0;
	printlnVGA("Memory map: ");
	for (i = 0; i < num; i++) {
		if (entry[i].type != E820_TYPE_FREE)
			continue;
		if (entry[i].addr + entry[i].length > memory_end){
			memory_end = entry[i].addr + entry[i].length;}
	}
	
	npage = memory_end / PGSIZE;  /*  memory pages */

        printlnVGA(itoa(npage * (4 / 1024), ' ', 10)); /*  A function turning converting numbers to chars, once one gives the base (decimal in our case). Supposed to show available memory in MBs. Always 0. */

  return;
}
The structures look like this:


typedef struct e820_entry {
unsigned int addr;
unsigned int addr_high;
unsigned int length;
unsigned int length_high;
unsigned int type;
unsigned int pad;
};

struct boot_param {
struct e820_entry memMapp[128];
unsigned long e820_num;
};

I know I am doing something wrong, but after many hours of googling as well as retarded trial and error , I think I've hit a dead end.
This may seem n00bish to most of you, but I am just a fullstack dev who tries to do some low-level programming at the weekends.

Thank you in advance!



PS: The only thing that was wrong was me going on to make this without much knowledge of C.
It just needed a '&' in this line: '

unsigned long i, npage, num = myboot_param->e820_num; ------> unsigned long i, npage, num = &myboot_param->e820_num

Re: Can't get memory map with E820

Posted: Sat Jul 24, 2021 1:56 am
by davmac314
What have you tried, debugging-wise? The first thing I would do is run it in a VM with a debugger and single-step through the code to see what happens.

A few potential problems I can spot by eyeballing: the code assumes edx is unchanged after the call to int 0x15, here:

Code: Select all

cmp eax, edx
I'm not sure that's a safe assumption - it's probably better to compare with the immediate value, to be on the safe side.

Is your DS set the same as ES? Otherwise:

Code: Select all

mov  [ 0x00000dfd0], ebp ; /* The total number of entries. Always 6 */
... probably isn't storing to the right location.

Finally, and sorry if this is being too simplistic, but you haven't shown any code that actually calls/runs the do_e820 routine - are you sure that it executes?

Re: Can't get memory map with E820

Posted: Sat Jul 24, 2021 3:03 am
by geomal
davmac314 wrote:What have you tried, debugging-wise? The first thing I would do is run it in a VM with a debugger and single-step through the code to see what happens.

A few potential problems I can spot by eyeballing: the code assumes edx is unchanged after the call to int 0x15, here:

Code: Select all

cmp eax, edx
I'm not sure that's a safe assumption - it's probably better to compare with the immediate value, to be on the safe side.

Is your DS set the same as ES? Otherwise:

Code: Select all

mov  [ 0x00000dfd0], ebp ; /* The total number of entries. Always 6 */
... probably isn't storing to the right location.

Finally, and sorry if this is being too simplistic, but you haven't shown any code that actually calls/runs the do_e820 routine - are you sure that it executes?
Not that this is the best way to debug a program, but so far I've used the so-called printf debugging .
The ds is the same as es, and the ebp is indeed stored to 0x00000dfd0. If I comment the line out it becomes zero, and if I double-increase ebp it becomes twelve.

The code surrounding the call looks like this:

Code: Select all

 
    xor ax, ax
    mov ds, ax
    mov es, ax
    mov ss, ax
    mov sp, MEM_POS ;address to store the kernel -0x1000 in our case
    mov ax, ERROR_MSG2
    mov [BOOT_DRIVE], dl; Boot drive passed to us by the BIOS
    mov dh, 12        ; Number of sectors (kernel.bin) to read from disk
                       
    mov bx, MEM_POS      ; Load Kernel to ES:BX 
    call load_kernel
    call a20_gate_fast   
    call do_e820; ;the call
    xor eax,eax
    lgdt [gdt_descriptor]
    mov eax, cr0
    or eax, 1
    mov cr0, eax    
    jmp dword CODE_SEG:init_pm

Re: Can't get memory map with E820

Posted: Sat Jul 24, 2021 3:29 am
by iansjack
How are you assembling/compiling you code? 32-bit toolset throughout?

Re: Can't get memory map with E820

Posted: Sat Jul 24, 2021 3:31 am
by davmac314
I may have misunderstood the problem. Are you saying these two lines *should* be printing the same number, but aren't?:

Code: Select all

     printlnVGA(itoa(content, ' ', 10)); //Prints the content of 0x00000dfd0 as decimal. Always 6.

      printlnVGA(itoa(num, ' d', 10)); //Number of entries. Always 0.
In that case I would add print statements for:

Code: Select all

E820_ADDRESS
,

Code: Select all

entry
, and

Code: Select all

&myboot_param->e820_num
. The fact that you're reading a different number implies that the address is different, or that the value has been overwritten (which doesn't seem likely).

I'd look at a mismatch between your C structure and assembly as a likely culprit.

Re: Can't get memory map with E820

Posted: Sat Jul 24, 2021 12:14 pm
by geomal
davmac314 wrote:I may have misunderstood the problem. Are you saying these two lines *should* be printing the same number, but aren't?:

Code: Select all

     printlnVGA(itoa(content, ' ', 10)); //Prints the content of 0x00000dfd0 as decimal. Always 6.

      printlnVGA(itoa(num, ' d', 10)); //Number of entries. Always 0.
In that case I would add print statements for:

Code: Select all

E820_ADDRESS
,

Code: Select all

entry
, and

Code: Select all

&myboot_param->e820_num
. The fact that you're reading a different number implies that the address is different, or that the value has been overwritten (which doesn't seem likely).

I'd look at a mismatch between your C structure and assembly as a likely culprit.
What a total idiot I am. The problem was that the '&' was missing. I would expect some kind of warning by the compiler, but I didn't see a thing...

That was several hours wasted for nothing.

Thanks for your help -and of course I won't even attempt to go any further with this before I really get familiar with C.