RAM size? BIOS or other? [Working]

Question about which tools to use, bugs, the best way to implement a function, etc should go here. Don't forget to see if your question is answered in the wiki first! When in doubt post here.
LordMage
Member
Member
Posts: 115
Joined: Sat Sep 22, 2007 7:26 am
Contact:

RAM size? BIOS or other? [Working]

Post by LordMage »

I got paging working and now I am working on my own system. I was reading the memory management 1 tutorial on osdever and It suggested using the BIOS to read an accurate RAM size, I then proceeded to look up INT15 and found a page of OsFaqWiki. That page has the appropriate BIOS info, but it also suggests a possible C/C++ solution for finding the RAM size but warns about dangers of shared memory devices.

I was wondering if I should just use the BIOS way of doing it or if anyone knows of a clever way to find the RAM size after my kernel is loaded. I would rather not have to put any important bits into my bootloader and transfer the info to my kernel. Just seems like back pedaling to me.
Last edited by LordMage on Tue Nov 20, 2007 8:13 pm, edited 1 time in total.
Getting back in the game.
User avatar
bewing
Member
Member
Posts: 1401
Joined: Wed Feb 07, 2007 1:45 pm
Location: Eugene, OR, US

Post by bewing »

AFAIK the BIOS method is the only effective way to do it. I haven't coded it up yet, though. I'm still messing with my directory caches. I'll be curious to hear the other responses. :)
Kieran
Member
Member
Posts: 54
Joined: Mon Apr 11, 2005 11:00 pm

Post by Kieran »

If you boot using the GRUB bootloader you can read the memory size from the multiboot information block.
User avatar
Brendan
Member
Member
Posts: 8561
Joined: Sat Jan 15, 2005 12:00 am
Location: At his keyboard!
Contact:

Re: RAM size? BIOS or other?

Post by Brendan »

Hi,
LordMage wrote:I was wondering if I should just use the BIOS way of doing it or if anyone knows of a clever way to find the RAM size after my kernel is loaded.
The first question is "how good is good enough"?

For most modern computers "Int 0x15, eax = 0xE820" is all you need.

For older computers there's older BIOS functions, and for some computers none of the BIOS functions are reliable (they're not supported by the BIOS, or return values my OS doesn't trust). My boot code for the PC BIOS tries these things (in order, until one works):
  • - Int 0x15, EAX = 0xE820
    - Int 0x15, AX = 0xE801
    - Int 0x15, AH = 0x8A
    - Int 0x15, AX = 0xDA88
    - Int 0x15, AH = 0x88
    - CMOS locations 0x17 and 0x18
    - Manual probing
All of these build a list of areas to pass to the OS, similar to that returned by "Int 0x15, eax = 0xE820", including areas that may not be usable for memory mapped PCI devices (e.g. the area from 0xFE000000 to 0xFFFFFFFF is assumed to be "reserved" if I only know about RAM areas).

For all of these my code is cautious. It handles any bugs mentioned in Ralph Brown's Interrupt List and handles limited return results (e.g. some BIOS functions return the maximum they can represent when more RAM is present).

I also sanitize the resulting list before the OS sees it - make sure that no areas overlap, combine adjacent areas of the same type together, sort it so that it's in order, etc.

My advice would probably be to get the information from "Int 0x15, eax = 0xE820" and copy it to a list in memory, and perhaps sanitize it; and then write the rest of your OS (if "Int 0x15, eax = 0xE820" doesn't work, just display an error message and lock up for now). You can always add other methods of "physical address range detection" later on, if you need to.
LordMage wrote:I would rather not have to put any important bits into my bootloader and transfer the info to my kernel. Just seems like back pedaling to me.
I'm mostly the reverse - I don't want to put anything in the kernel that the kernel won't need after boot (I don't want stuff like "physical address range detection" taking up RAM for no reason after boot). In addition my early boot code is responsible for gathering information from the firwmare and putting the computer into a well-defined state, so that the rest of the OS doesn't need to care what the firmware was (PC BIOS, EFI, LinuxBIOS, OpenFirwmare, aeBIOS, custom ROM code, etc) or where the boot loader's list of physical address ranges actually came from.


Cheers,

Brendan
For all things; perfection is, and will always remain, impossible to achieve in practice. However; by striving for perfection we create things that are as perfect as practically possible. Let the pursuit of perfection be our guide.
egos
Member
Member
Posts: 612
Joined: Fri Nov 16, 2007 1:59 pm

Re: RAM size? BIOS or other?

Post by egos »

LordMage wrote:I was wondering if I should just use the BIOS way of doing it or if anyone knows of a clever way to find the RAM size after my kernel is loaded. I would rather not have to put any important bits into my bootloader and transfer the info to my kernel. Just seems like back pedaling to me.
There are two good ways to solve this problem at all. Both use the BIOS.
1. Second stage bootloader detects available memory using the BIOS and passes the data to the PM kernel.
2. Bootloader loads the kernel, which consists of two parts (RM part and PM part), then the kernel detects available memory using the BIOS.
LordMage
Member
Member
Posts: 115
Joined: Sat Sep 22, 2007 7:26 am
Contact:

Post by LordMage »

Alright, I am going to try to get the info from the BIOS until I can find a different way, I still don't like it. I have made a funciton based on the stuff on the wiki and I just want to know if this is close to what you guys are using. I am implementing the function the best way I know how, ASM is not my strong point. I did have to leave out the ES:DI part, not sure if I was supposed to inlclude it in the first place though. From what I read I thought I should have put 01h into ES:DI but I am not sure how so I left it out. on the bright side when I check the carry flag using JB everything seems to have worked. here is the code please let me know if this is close to right. I still have to tweak my stack after I move the stack pointer later in the bootloader but this is the important bit because if this is wrong then I will be passing junk onto my kernel.

Code: Select all


;-------------------------------;
;   Read size of RAM from BIOS  ;
;-------------------------------;

mov ax, 0xE820
mov eax, 0xE820
mov edx, 0x534D4150
mov ebx, 0
mov ecx, 20

int 0x15

jb RAMerror
push eax
push es
push di
push ebx
push ecx

Getting back in the game.
cyr1x
Member
Member
Posts: 207
Joined: Tue Aug 21, 2007 1:41 am
Location: Germany

Post by cyr1x »

How to determine the RAM size on a NUMA system? Does the BIOS provide a
special Memory-Map? Or can you get the size from the ACPI-tables?
Mounter
Posts: 8
Joined: Sun Aug 12, 2007 12:45 pm
Location: Feliz, Rio Grande do Sul, Brazil
Contact:

Post by Mounter »

I use this code for get the memory size:

Code: Select all

unsigned long getRamSize(const uint08_t unit)
{
	unsigned long rez;
	unsigned long memsize;
	unsigned long last;
	unsigned char tmp;

	memsize = 1;            // 1MB
	rez = 0x12;             // Number for teste
	last = 0x200000-0x1;    // From 2MB of RAM

	while (rez == 0x12) {
		tmp = *(char *)last; 
		*(char *)last = rez;   
		rez = *(char *)last; 
		last += 0x100000;

		if (rez == 0x12) {
			memsize++;
			*(char *)last = tmp;
		}
	}

	switch (unit)
	{
        /*case 'M':
            break;*/
        case 'K':
            memsize <<= 0x0A;
            break;
        case 'B':
            memsize <<= 0x14;
	}

    return memsize;
};
User avatar
JAAman
Member
Member
Posts: 879
Joined: Wed Oct 27, 2004 11:00 pm
Location: WA

Post by JAAman »

if i understood that correctly, your probing -- that is very dangerous, and in some cases (admittedly rare) can permanently destroy your computer so that it will never work again...

even if that doesnt happen, there is a good chance that it will return the wrong answer, and possibly prevent the computer from working properly -- there are portions of RAM you shouldnt ever touch, and there are often holes in ram, where the ram stops, then starts again later, and sometimes there are hardware devices located in between portions of ram (and if you try to write to these devices, you can permanently damage your computer -- depending on what you write, and to what part of which device) even if you dont damage the computer with it, sometimes writing to a device will look exactly the same as writing to ram, in which case your test will say its real memory, where it really isnt (for example, video ram, or shared ram acting as video ram -- neither of these can be detected with your program)

the only way to know for certain what is real memory, and what is safe to write to, is to ask the one that knows all -- the BIOS (technically, you could also do it with a MB driver, but since you would need a separate driver for each MB, it becomes very impractical -- even MS doesnt do that...
User avatar
Dex
Member
Member
Posts: 1444
Joined: Fri Jan 27, 2006 12:00 am
Contact:

Post by Dex »

Try something like this;

Code: Select all

 ;----------------------------------------------------;
 ; Get Ram Size.                                      ;
 ;----------------------------------------------------;
GetRamSize:
	mov   ax,0xe801
	int   15h
	jc    @f   ;may jump to some error code
	movzx ebx, bx
	shl   ebx,6
	movzx eax, ax
	add   ebx,eax
	mov   [ExtMemorySize],ebx
	call  TotalRam
@@:
	ret

 ;----------------------------------------------------;
 ; TotalRam.                                          ;
 ;----------------------------------------------------;
TotalRam:
	shr   ebx,10
	inc   ebx
	test  ebx,1
	jnz   @f
	mov   [TotalMemoryMB],ebx
	ret
@@:	inc   ebx
	mov   [TotalMemoryMB],ebx
	ret
LordMage
Member
Member
Posts: 115
Joined: Sat Sep 22, 2007 7:26 am
Contact:

Post by LordMage »

thanks Dex, that is what I wanted but it looks like you are passing variables which would mean that my kernel would already be loaded??? does your code expect me to be in V86 mode? Isn't that the older version of the call, is it reliable enough? I will implement it, thanks
Getting back in the game.
Mounter
Posts: 8
Joined: Sun Aug 12, 2007 12:45 pm
Location: Feliz, Rio Grande do Sul, Brazil
Contact:

Post by Mounter »

I use this function only in the initiation of the kernel, and write it on a variable.

The function save the memory position, write and test if it's 0x12 and return the original value to the memory position, I don't consider it so dangerous.

Sorry for my inglish, but I am a brazillian programmer...
LordMage
Member
Member
Posts: 115
Joined: Sat Sep 22, 2007 7:26 am
Contact:

Post by LordMage »

well, I instituted the function the Dex gave me, I also tried my own implimentation and both of them returned a funny value. Well, at least one I wasn't expecting. does this look right

0xE820

RAM: 589845

0xE801

RAM: 589832
Extended Memory: 1049647

I mean bochs says the system has 0x02000000 RAM and then I get those returns from the RAM functions it doesn't make sense to me.
Getting back in the game.
User avatar
JAAman
Member
Member
Posts: 879
Joined: Wed Oct 27, 2004 11:00 pm
Location: WA

Post by JAAman »

The function save the memory position, write and test if it's 0x12 and return the original value to the memory position, I don't consider it so dangerous.
consider this:
a device has a register at location x, this register regulates a timing clock for a chip -- you write '0x12' into that location -- you just told it to overclock that chip to 250GHz -- and now that chip will never function again -- all thats left is a pile of ashes

when i said it was dangerous, i didnt mean you could change the values at that location (besides, you cannot prevent the computer from relying on the information at that memory address while you are 'testing' it), i meant placing the wrong value in a hardware register, will itself cause damage to the computer -- sometimes rebooting will fix it, but sometimes the damage may be permanent -- and if it is a hardware register, you (most likely) cannot restore the previous value, because you dont know what the previous value was -- sometimes the register is read only (in which case the value you read from it was completely nonsense) and sometimes the same address will work as a read port for another register, and the value you read, was the device status - not the previous value for that port

and sometimes the read will work perfectly well, and will decide that there is memory at that address, but in fact its not memory, but either a r/w port, or onboard memory from some device (such as video memory -- which on many systems is actually part of system memory, and the only way to tell that it is separate, is to ask the BIOS), your function will declare all device memory to be system memory
User avatar
Dex
Member
Member
Posts: 1444
Joined: Fri Jan 27, 2006 12:00 am
Contact:

Post by Dex »

LordMage wrote:well, I instituted the function the Dex gave me, I also tried my own implimentation and both of them returned a funny value. Well, at least one I wasn't expecting. does this look right

0xE820

RAM: 589845

0xE801

RAM: 589832
Extended Memory: 1049647

I mean bochs says the system has 0x02000000 RAM and then I get those returns from the RAM functions it doesn't make sense to me.
Are you use the code as i posted ?, also how are you converting it ?.
As that same code works fine in BOCHS for my OS, and it work on all real PC's, i and other have tested it on (other 100)
Running in bochs
Attachments
ram.png
ram.png (16.97 KiB) Viewed 2285 times
Post Reply