RAM size? BIOS or other? [Working]
RAM size? BIOS or other? [Working]
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.
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.
Re: RAM size? BIOS or other?
Hi,
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):
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.
Cheers,
Brendan
The first question is "how good is good enough"?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.
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
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.
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.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.
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.
Re: RAM size? BIOS or other?
There are two good ways to solve this problem at all. Both use the BIOS.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.
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.
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.
-
- Posts: 8
- Joined: Sun Aug 12, 2007 12:45 pm
- Location: Feliz, Rio Grande do Sul, Brazil
- Contact:
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;
};
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...
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...
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
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.
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.
consider this: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.
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
Are you use the code as i posted ?, also how are you converting it ?.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.
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 (16.97 KiB) Viewed 2280 times