Page 1 of 1

Memory Area Detection

Posted: Wed May 10, 2006 11:21 pm
by Ryu
Hi, what are my options for detecting unreserved memory areas. Is interrupt 15h AX=0E820h my only option? And is it reliable on older systems? Is there a efficent way to do this without BIOS services? The interrupt is a pain at times as some system returns reserved areas rather then whats available.

Re:Memory Area Detection

Posted: Thu May 11, 2006 12:06 am
by Brendan
Hi,
Ryu wrote:Hi, what are my options for detecting unreserved memory areas. Is interrupt 15h AX=0E820h my only option? And is it reliable on older systems?
BIOS functions are your only reliable/practical option. If the computer is too old to support interrupt 15h eax=0E820h you can fall back on older functions (int 15 ax = 0xE881, int 15 ax = 0xE801, int 15 ah = 0xC7, int 15 ah = 0x88, etc) and then try CMOS locations (0x17/0x18, 0x30/0x31, 0x34/0x35).
Ryu wrote:Is there a efficent way to do this without BIOS services? The interrupt is a pain at times as some system returns reserved areas rather then whats available.
Int 15h eax=0E820h should be reliable (but some systems have bugs that can be worked around - see Ralph Brown's Interrupt List), and should always return reserved areas and usable RAM areas. All you'd do is check the "type" field that is returned to see if it's RAM or not.


Cheers,

Brendan

Re:Memory Area Detection

Posted: Thu May 11, 2006 12:24 am
by Ryu
Hmm I don't know if this is correct but Bochs gives me only whats unused. The service also does not return BIOS data area or the extended data area so I suppose that I would have to assume that those areas are reserved. But yes from a real system the interrupt returns both reserved and unused areas, and so its left me with an unease feeling. (Or this could be another of my stupid bugs)

Heres a picture, where the mapped areas were returned by the service and the last Unmapped part is done manually for kernel space. (This link is temperary)
http://69.194.132.189/boot.gif

Anyways thanks for the reply I'll check on the ralph's list about it.

Re:Memory Area Detection

Posted: Thu May 11, 2006 1:26 am
by Brendan
Hi,
Ryu wrote:Hmm I don't know if this is correct but Bochs gives me only whats unused. The service also does not return BIOS data area or the extended data area so I suppose that I would have to assume that those areas are reserved. But yes from a real system the interrupt returns both reserved and unused areas, and so its left me with an unease feeling. (Or this could be another of my stupid bugs)
This is a problem with the standard Bochs BIOS - it's "eax = 0xE820" function is wrong.

Qemu developers patched their version of the Bochs BIOS on the 3rd of May, but I don't think Bochs developers noticed.

If you boot from floppy and don't use much of the BIOS, you might be interested in using this BIOS with Bochs instead. It's "under development", but everything that has been implemented is far better than the normal Bochs BIOS, especially if you're trying to do hyper-threading/multi-core/multi-CPU or NUMA support (even if I do say so myself)... ::)


Cheers,

Brendan

Re:Memory Area Detection

Posted: Thu May 11, 2006 2:18 am
by Solar
Perhaps the FAQ page of How do I determine the amount of RAM is of help.

Re:Memory Area Detection

Posted: Thu May 11, 2006 6:36 am
by Ryu
Greetings,

Brendan:

Ahh so its Bochs that screwed up. I've tried your BIOS out however have ran into problems with INT 15h EAX=E820h, and I've noticed a minor bug..

In the source .\common\int15.asm (line 421):

Code: Select all

.sE820_generic:
   push edx
   lea eax,[.sE820_table+ebx*2]
   inc ebx                     ;ebx = next continuation value
   and eax,0xFFFF
   call [cs:eax]                  ;Get the details for this entry

   mov [es:di],edx                  ;Set base address of region (low dword)
   mov dword [es:di+4],0               ;Set base address of region (high dword)
   mov [es:di+8],ecx               ;Set size of region (low dword)
   mov dword [es:di+12],0               ;Set size of region (high dword)
   mov [es:di+16],eax               ;Set type of region
   mov ecx,20                  ;ecx = returned size
   pop edx

   pop ds
   mov eax,edx
   and word [bp+6],~FLAG_carry            ;Clear the carry flag (on the stack)
   pop bp
   iret
And what was disassembled by IDA:

Code: Select all

seg000:81AB loc_81AB:
seg000:81AB                 push    edx
seg000:81AD                 lea     eax, [ebx+ebx-7E0Ch]
seg000:81B6                 inc     ebx
seg000:81B8                 and     eax, 0FFFFh
seg000:81BE                 call    word ptr cs:[eax]
seg000:81C2                 mov     es:[di], edx
seg000:81C6                 mov     dword ptr es:[di+4], 0
seg000:81CF                 mov     es:[di+8], ecx
seg000:81D4                 mov     dword ptr es:[di+0Ch], 0
seg000:81DD                 mov     es:[di+10h], eax
seg000:81E2                 mov     ecx, 14h
seg000:81E8                 pop     edx
seg000:81EA                 pop     ds
seg000:81EB                 mov     eax, edx
seg000:81EE                 and     word ptr [bp+6], 0FFFEh
seg000:81F2                 pop     bp
seg000:81F3                 iret
As you probably already guessed, lea eax, [ebx+ebx-7E0Ch] is not intention. When you get this fixed up and reassembled I'll be using this over the default Bochs BIOS, thanks for sharing :)

Solar:

Aye yes the info helps, thanks for the reply.

Re:Memory Area Detection

Posted: Thu May 11, 2006 7:39 am
by Brendan
Hi,
Ryu wrote:As you probably already guessed, lea eax, [ebx+ebx-7E0Ch] is not intention.
I know it looks unusual, but it actually is intentional... :)

The reason is that the source code mixes 32 bit assembly, unreal mode and real mode, and half of it (the POST code) operates at 0xFFFF0000 while the other half operates at 0x000F0000 (or 0xF000:0000).

The instruction itself is "lea eax, [ebx * 2 + 0xFFFF8140]", where "0xFFFF8140" is the 32 bit address of ".sE820_table" for the copy of the BIOS at 0xFFFF0000. This is because I need to use 32 bit addresses for the 32 bit code - for the 16 bit code doing something like "mov ax,.sE820_table" works perfectly because the upper bits are truncated (even though I'm using "org 0xFFFF0000").

What I really wanted to do here is "lea ax, [bx * 2 + .sE820_table]", but the CPU doesn't support this addressing mode for 16 bit instructions.

The next best option is "lea eax, [ebx*2 + (.sE820_table & 0xFFFF) ]", but NASM won't allow that - it can't do mathmatical operations on labels because it doesn't know the address that the label would end up at. Instead you get "error: `&' operator may only be applied to scalar values".

Therefore, to avoid the limitations of the CPU and the limitations of the assembler, I did it in 2 seperate instructions:

Code: Select all

   lea eax,[.sE820_table+ebx*2]
   and eax,0xFFFF
Another alternative would be to do it like this:

Code: Select all

   lea eax,[ebx*2]
   add ax,.sE820_table
As long as those extra upper 16 bits are truncated somehow you end up with the correct value in EAX at the end. I have changed it to this second version though - it'd be easier to follow a disassembly that way....

The other alternative would be to assemble the 32 bit code and the 16 bit code seperately, with "org 0x0000" for the 16 bit code and "org 0xFFFF0000" for the 32 bit code. Unfortunately that creates a lot of problems elsewhere because it's impossible to use the addresses of labels defined in one binary from another binary.

I hope this makes sense... :)


Cheers,

Brendan

Re:Memory Area Detection

Posted: Thu May 11, 2006 1:35 pm
by Ryu
Oh so it works out.. (7E0Ch ^ 0FFFFh) + 1 = 81F4h. ??? Hmm if that is not the problem, I'm still left with a Bochs error:

00973049880i[BIOS ] Starting boot sector
00977297054i[CPU0 ] LOCK prefix unallowed (op1=0xf8, attr=0x0, mod=0x0, nnn=0)
00977297389i[BIOS ] Unimplemented BIOS function called (Int 0xFF, EAX=0x00000000)
00977297404i[CPU0 ] LOCK prefix unallowed (op1=0xf8, attr=0x0, mod=0x0, nnn=0)

Where the last contigiously was written in bochsout.txt and my bootloader never made pass the interrupt 15h. What was particular when I ran my investigation on the matter was, if I have set ecx=20 or higher the interrupt never returns and I end up with that output in Bochs, however a zero value in ECX returns and continues my execution. So.. I was really suspicious with that instruction. The simplified code I used was:

Code: Select all

???push    ss
???pop??????es
???mov??????edi, 800h - 14h
???mov??????eax, 0E820h
???mov??????edx, "SMAP"
???xor??????ebx, ebx
???mov??????ecx, 14h??????; 20 bytes 

???int??????15h????????????;BIOS INT 15h AX=0E820h
Any ideas why? Just a guess maybe using a 32bit offset in a 16bit enviroment have anything to do with it? -> call cs:[eax]. Unfortunitly I don't use Nasm so I don't get to play around with the source hehe.

Re:Memory Area Detection

Posted: Thu May 11, 2006 2:38 pm
by FlashBurn
@brendan

Maybe you have a look at fasm. It has some features nasm doesn?t have (like mathematical operations on labels).

Re:Memory Area Detection

Posted: Thu May 11, 2006 4:13 pm
by Ryu
Okay I found my silly problem, it was the stack.