Page 1 of 1

int 15h E820h problems

Posted: Mon Feb 16, 2009 1:54 pm
by Richy
So I've tried to create a memory map using a function similar to the one in the wiki. The map is fine. The problem is that, while it correctly lists seven regions, the value in the bp pointer is of several thousands. I don't get it. It's incremented in the code at the same place where we move the di pointer, and that one is ok... What's going on here?

Code: Select all

GetMemoryMap:
	pushad
	xor	ebx, ebx
	xor	bp, bp					; number of entries stored here
	mov	edx, 'PAMS'				; 'SMAP'
	mov	eax, 0xe820
	mov	ecx, 24					; memory map entry struct is 24 bytes
	int	0x15					; get first entry
	jc	.error	
	cmp	eax, 'PAMS'				; bios returns SMAP in eax
	jne	.error
	test	ebx, ebx				; if ebx=0 then list is one entry long; bail out
	je	.error
	jmp	.start
.next_entry:
	mov	edx, 'PAMS'				; some bios's trash this register
	mov	ecx, 24					; entry is 24 bytes
	mov	eax, 0xe820
	int	0x15					; get next entry
.start:
	jcxz	.skip_entry				; if actual returned bytes is 0, skip entry
.notext:
	mov	ecx, [es:di + MemoryMapEntry.length]	; get length (low dword)
	test	ecx, ecx				; if length is 0 skip it
	jne	short .good_entry
	mov	ecx, [es:di + MemoryMapEntry.length + 4]; get length (upper dword)
	jecxz	.skip_entry				; if length is 0 skip it
.good_entry:
	inc	bp					; increment entry count
	add	di, 24					; point di to next entry in buffer
.skip_entry:
	cmp	ebx, 0					; if ebx return is 0, list is done
	jne	.next_entry				; get next entry
	jmp	.done
.error:
	stc
.done:
	popad
	ret

Re: int 15h E820h problems

Posted: Mon Feb 16, 2009 11:06 pm
by bewing
The code looks good. Are you trying to run this in an emulator, or on real hardware? Do you have singlestep debugging capability?
How are you checking the "final" value of bp? You do not show that you are saving the value, or printing it from this function.
If you are trying to check it outside this function, the fact that you did the PUSHA/POPA will trash bp. The only other possibilities are that bp is getting trashed by the E820 function, or that you are getting thousands of "length = 0" entries before ebx returns as 0.

Re: int 15h E820h problems

Posted: Tue Feb 17, 2009 1:46 am
by egos
Try this:

Code: Select all

  mov ecx, 20
  int 15h
And use checking code every time when calling int 15h:

Code: Select all

  jc .error
  cmp eax, "PAMS"
  jne .error
  cmp ecx, 20
  jne .error

Re: int 15h E820h problems

Posted: Tue Feb 17, 2009 10:02 am
by Richy
bewing wrote:The code looks good. Are you trying to run this in an emulator, or on real hardware? Do you have singlestep debugging capability?
How are you checking the "final" value of bp? You do not show that you are saving the value, or printing it from this function.
If you are trying to check it outside this function, the fact that you did the PUSHA/POPA will trash bp. The only other possibilities are that bp is getting trashed by the E820 function, or that you are getting thousands of "length = 0" entries before ebx returns as 0.
I'm running it on a Microsoft Virtual PC. No debugging :(

In fact, I've tried checking the value of BP multiple ways. The short answer is, I'm copying it into the bootinfo structure and passing it to the kernel, which then displays it:

Code: Select all

mov	word [boot_info+multiboot_info.mmap_length], bp
I've tried copying it after exiting the function, and I've tried copying it inside the function, as the first line of the ".done:" section before "popad". I've also tried skipping BP entirely and incrementing [boot_info+multiboot_info.mmap_length] directly. In all cases, I got results in the thousands.

I then figured that maybe BP was ok, but getting trashed when being passed to the kernel. So I added a simple display routine: I copied the value of BP in CX, and looped a single-character display with INT 10h. It displayed thousands of characters. So the value is being passed correctly to the kernel, it's being computed incorrectly by the function.

Re: int 15h E820h problems

Posted: Tue Feb 17, 2009 10:04 am
by Richy
egos wrote:Try this:

Code: Select all

  mov ecx, 20
  int 15h
And use checking code every time when calling int 15h:

Code: Select all

  jc .error
  cmp eax, "PAMS"
  jne .error
  cmp ecx, 20
  jne .error
20 byte entries instead of 24? Why?

Re: int 15h E820h problems

Posted: Tue Feb 17, 2009 10:28 am
by quok
egos wrote:Try this:

Code: Select all

  mov ecx, 20
  int 15h
And use checking code every time when calling int 15h:

Code: Select all

  jc .error
  cmp eax, "PAMS"
  jne .error
  cmp ecx, 20
  jne .error
ACPI 3.0 extends the structure that the E820 function returns from 20 to 24 bytes. ACPI 3.0, and previous versions, all say that if the size of the buffer passed to E820 is greater than the amount supported by E820, then E820 will ignore the extra bytes. This way, on machines that support ACPI 3.0, the same code will work, and you'll get the extra information provided. On ACPI 2.0 machines, that extra information will be empty (provided you clear the buffer before you pass it in). So checking to make sure that E820 returned the same amount of bytes you asked for isn't a good idea, unless you have separate E820 functions for each version of the E820 function as defined in the ACPI specifications.

Regardless, if you are passing in a 24 byte structure, you must always increment the pointer to the buffer/structure by 24 bytes even if E820 only supports 20 bytes. Or you could do like I do, and use the same buffer for each call to E820. After the call, I translate the E820 map into something of my own format, so the kernel's memory map will have the same format on any architecture I port to.