================================================
How to Detect the Amount of RAM?:
I want to give a short description on how to detect the amount of RAM: (This description I collected from the forums (mainly from Brendan and Smiddy) and from my experience).
1).
Use those BIOS calls:
INT 0x15, eax = 0xE820
INT 0x15, ax = 0xE881
INT 0x15, ax = 0xE801
INT 0x15, ah = 0xC7
INT 0x15, ah = 0x88
Use the CMOS:
Locations 0x17 and 0x18
All this can only give you information how much RAM is there below 64MB, but you would not get any information about ROM or any reserved areas, except for 0xE820, 0xE881, 0xE801 functions that are only present on new PCs.
================================================
2). Get RAM & ROM Information from the PnP BIOS.
(Some times the PnP Bios causes the OS to crash, so make sure you have a good exception handling and not to only display some blue screen of death, make sure that your OS can continue after a PnP Bios crash, and after crash only skip the PnP Information).
(Maybe is better getting the PnP Information by using the special I/O address, I have not yet tried it out but maybe it would work).
Fix me if I'm wrong.
================================================
3). Get the memory information from the PCI headers.
(This means go over all the valid PCI headers, and get the RAM and ROM locations and sizes).
================================================
4). Get ROM & RAM information from the SM BIOS.
(I didn't yet get good information about the RAM from the SM (Maybe because I'm not interpreting it right, but you can get from it the BIOS version, location, size, CPU, PCI slots etc).
It seems that you can't get any voluble information about the installed RAM from the SM BIOS, Fix me if I'm wrong.
================================================
From all what you have collected from the BIOS, CMOS, PnP, PCI, and SM BIOS, make a list and get ready for the last part >> Probing <<.
================================================
5). Probe every 1MB block of memory if it is valid.
(This is done by writing to the beginning block 0xAA55AA55 and reading it, if the value redden = 0xAA55AA55 do the test again but this time by writing 0x55AA55AA, if the test past you know that this RAM block is valid, before you start you must be in PM, and disable paging, and cashing).
Note:
Probing memory-mapped PCI devices may have unpredictable results and possibly damage your system, so once again we discourage its use. (From: http://www.osdev.org\osfaq2).
It seems that Brendan claims that you don't really have to be worried about this.
He wrote:
For older machines (80486 and older IIRC) there can be a problem with bus capacitance, where you write a value out to the system bus and read the same value back in when nothing is at that address. To solve this problem it's best to write to a dummy address in RAM between the write and the read.
(Brendan, tell me if I understood right what you write).
Another reason why not to be worried from probing, is because you first got all the information form the PCI headers, so you know were not to probe.
(Brendan, tell me if I'm right).
================================================
Another note (from Brendan):
If the computer has 15/16 MB of RAM and something (e.g. an old ISA SVGA card) mapped in the area from 15 MB to 16 MB, then your code will think that's an extra 1 MB of RAM. I guess you could provide warnings but be careful with your wording - there's a difference between not supporting the cards (e.g. OS works but card doesn't) and not supporting any computer that contains these cards (e.g. OS crashes).
================================================
Conclusion:
In conclusion it seems that to get the RAM amount and reserved areas use the PnP BIOS, PCI Headers, and probing, all the rest would not really help you a lot (this includes the BIOS functions, CMOS, and SM BIOS).
Fix me if I'm wrong.
Another thing to make sure that when you load your OS kernel and drivers, check their checksums to make sure that the files were loaded successfully, and not to invalid RAM, etc.
Have a successful RAM detection!
How to Detect the Amount of RAM on Your PC
I think that for new PC's, specially the 64-bit ones, we can assume that the first 16 megabytes shouldn't be tested.
Also, since almost all PC motherboards have support for up to 2GB of RAM, we can start testing past megabyte 15, at 0x1000000, and start counting up to the end of the 2GB. Anyway we already know that the PC's in general have its PCI devices mapped towards the third or fourth gigabyte.
After that, I think we could keep testing for further RAM past the 4GB barrier (for 64-bit code) and almost certainly any device will be mapped there to keep compatibility with 16 and 32-bit environments.
Also, since almost all PC motherboards have support for up to 2GB of RAM, we can start testing past megabyte 15, at 0x1000000, and start counting up to the end of the 2GB. Anyway we already know that the PC's in general have its PCI devices mapped towards the third or fourth gigabyte.
After that, I think we could keep testing for further RAM past the 4GB barrier (for 64-bit code) and almost certainly any device will be mapped there to keep compatibility with 16 and 32-bit environments.
- Combuster
- Member
- Posts: 9301
- Joined: Wed Oct 18, 2006 3:45 am
- Libera.chat IRC: [com]buster
- Location: On the balcony, where I can actually keep 1½m distance
- Contact:
Grub is just an implementation of "ask the bios and store the results". Your 1337 bootloader will probably do pretty much the same.
That aside, i wonder what the use is of dumping info here that exists in the wiki![Rolling Eyes :roll:](./images/smilies/icon_rolleyes.gif)
That aside, i wonder what the use is of dumping info here that exists in the wiki
![Rolling Eyes :roll:](./images/smilies/icon_rolleyes.gif)
I have a relatively modern celeron box that wont take ram chips > 256M, so that's a bad assumption. Not to mention the old 486sAlso, since almost all PC motherboards have support for up to 2GB of RAM
Hi,
Some more notes...
Never assume that there's N KB of RAM at 0x00000000 - use BIOS int 0x12 instead. There are things (e.g. BIOS/ROM network boot code and the EBDA) that can be using RAM between 0x00080000 and 0x000A000000.
The BIOS functions have been added over time, as systems support more RAM. Because of this you can fully expect any "new" system (e.g. after the year 2000) to support BIOS int 0x15 EAX = 0xE820.
In my experience, older computers (from Pentium to "new") will support at least one of the other BIOS functions mentioned and return usable results, and will usually support more than one of them.
For the other BIOS functions, sometimes you can't tell if the results returned by the BIOS actually are correct. An example of this would be BIOS int 0x15 AH = 0x88 that returns 15 MB of RAM above 1 MB (where you don't know if the BIOS limited the value for backwards compatibility) or 64 MB of RAM (which is the most RAM this function can report, even if there's more). There's also a number of bugs in some BIOSs that would need to be avoided (see Ralph Brown's Interrupt List for a description of these bugs).
All systems "support" CMOS locations 0x17 and 0x18, but this may also be limited/unusable just like BIOS int 0x15 AH = 0x88.
For "ancient" computers (80486 and older) you might find none of the BIOS functions are supported, or find that none of them return results you can trust. In this case the only viable option may be direct probing (which must be done with care - see notes below).
For "pre-historic" computers (80386 and older), I wouldn't bother supporting them at all. Part of the reason for this is that most of them used "Expanded Memory", where there was special bank switching circuitry to allow N MB of RAM to be selectively mapped below 1 MB (unlike "Extended Memory" that can accessed in a sane manner).
To reliably write code for manual probing there's several things you'd want to consider. First, if your OS doesn't support 80486 (or older) then don't bother - if none of the other methods work then refuse to boot.
A system with 32 MB of RAM may have an ISA video card mapped from 15 MB to 16 MB, so there's no point testing this area - for safety it's best to refuse to use this memory (or perhaps provide some sort of configuration option so the user can tell the OS that this area is safe).
![Wink ;)](./images/smilies/icon_wink.gif)
Some older computers remap the RAM underneath the ROMs to the end of RAM. For e.g. if there's 8 MB of RAM installed you might find RAM from 0x00000000 to 0x000A0000 and then more RAM from 0x00100000 to 0x00840000. Because of this you can't test at 1 MB intervals and expect correct results in all cases. A better idea is to test at the start and end of each MB, and then if there's RAM at the start but not at the end test at smaller intervals (e.g. 1 KB).
You must avoid problems caused by CPU caches, where you do a write (to cache and RAM) and then read that data back from cache (and not from RAM). This means disabling caching in CR0, or (for 80486 and later only) using WBINVD.
For some systems there's a problem with bus capacitance, where a value written will be read back even though nothing is attached at that address. To avoid this problem you need to read or write to/from a known valid address to change any value that might be "floating" on the bus. You'd also need to make sure that this value is different from what you wrote to the address being tested.
Because of all of this, manual probing can be slow (mostly due to lack of caching). On a Pentium II with 256 MB of RAM my manual probing code takes about 10 seconds.
There are a few other ways of detecting the "top of RAM". One is to use data from the chipset (which is chipset specific) or data from modern AMD CPUs that have hypertransport links (which is CPU specific). The other way is to use values left in the MTRRs by the BIOS - if the BIOS tells the MTTRs that certain areas are cacheable, then it's *probably* safe to assume those areas are RAM. Both of these methods are theoretical - any computer that is new enough to support either of these methods will also have reliable BIOS functions that should be used instead.
Basically it doesn't check for any known BIOS bugs, doesn't try all known BIOS functions, has very little sanity checks and won't do manual probing where the computer is so messed up that it's required. Instead they assume it'll work and provide a way for the user to override it when it doesn't.
This means if you rely on GRUB alone, then your OS will work most of the time, but force the user to jump through hoops if they're unlucky. If you're trying to write a very high quality OS (reliable and user-friendly) then IMHO this just isn't good enough. Most people who use GRUB boot Linux, which does it's own (much more thorough) memory detection using methods described above (and isn't a "multiboot compliant" OS).
IMHO the SM BIOS is intended to allow system adminstrators to get a report of what hardware is present (for e.g. so someone responsible for maintaining 100 computers can run a "SM BIOS" client on each computer instead of manually inspecting each computer). It's not intended to be relied on by software, and it's not at the top of BIOS manufacturers quality control checklists. This web page (an FAQ for a utility to view the SM BIOS data) describes this fairly well.
Cheers,
Brendan
Some more notes...
Never assume that there's N KB of RAM at 0x00000000 - use BIOS int 0x12 instead. There are things (e.g. BIOS/ROM network boot code and the EBDA) that can be using RAM between 0x00080000 and 0x000A000000.
The BIOS functions have been added over time, as systems support more RAM. Because of this you can fully expect any "new" system (e.g. after the year 2000) to support BIOS int 0x15 EAX = 0xE820.
In my experience, older computers (from Pentium to "new") will support at least one of the other BIOS functions mentioned and return usable results, and will usually support more than one of them.
For the other BIOS functions, sometimes you can't tell if the results returned by the BIOS actually are correct. An example of this would be BIOS int 0x15 AH = 0x88 that returns 15 MB of RAM above 1 MB (where you don't know if the BIOS limited the value for backwards compatibility) or 64 MB of RAM (which is the most RAM this function can report, even if there's more). There's also a number of bugs in some BIOSs that would need to be avoided (see Ralph Brown's Interrupt List for a description of these bugs).
All systems "support" CMOS locations 0x17 and 0x18, but this may also be limited/unusable just like BIOS int 0x15 AH = 0x88.
For "ancient" computers (80486 and older) you might find none of the BIOS functions are supported, or find that none of them return results you can trust. In this case the only viable option may be direct probing (which must be done with care - see notes below).
For "pre-historic" computers (80386 and older), I wouldn't bother supporting them at all. Part of the reason for this is that most of them used "Expanded Memory", where there was special bank switching circuitry to allow N MB of RAM to be selectively mapped below 1 MB (unlike "Extended Memory" that can accessed in a sane manner).
To reliably write code for manual probing there's several things you'd want to consider. First, if your OS doesn't support 80486 (or older) then don't bother - if none of the other methods work then refuse to boot.
A system with 32 MB of RAM may have an ISA video card mapped from 15 MB to 16 MB, so there's no point testing this area - for safety it's best to refuse to use this memory (or perhaps provide some sort of configuration option so the user can tell the OS that this area is safe).
No - ISA devices that use the memory range from 15 MB to 16 MB don't have PCI headers...keller wrote:Another reason why not to be worried from probing, is because you first got all the information form the PCI headers, so you know were not to probe.
![Wink ;)](./images/smilies/icon_wink.gif)
Some older computers remap the RAM underneath the ROMs to the end of RAM. For e.g. if there's 8 MB of RAM installed you might find RAM from 0x00000000 to 0x000A0000 and then more RAM from 0x00100000 to 0x00840000. Because of this you can't test at 1 MB intervals and expect correct results in all cases. A better idea is to test at the start and end of each MB, and then if there's RAM at the start but not at the end test at smaller intervals (e.g. 1 KB).
You must avoid problems caused by CPU caches, where you do a write (to cache and RAM) and then read that data back from cache (and not from RAM). This means disabling caching in CR0, or (for 80486 and later only) using WBINVD.
For some systems there's a problem with bus capacitance, where a value written will be read back even though nothing is attached at that address. To avoid this problem you need to read or write to/from a known valid address to change any value that might be "floating" on the bus. You'd also need to make sure that this value is different from what you wrote to the address being tested.
Because of all of this, manual probing can be slow (mostly due to lack of caching). On a Pentium II with 256 MB of RAM my manual probing code takes about 10 seconds.
There are a few other ways of detecting the "top of RAM". One is to use data from the chipset (which is chipset specific) or data from modern AMD CPUs that have hypertransport links (which is CPU specific). The other way is to use values left in the MTRRs by the BIOS - if the BIOS tells the MTTRs that certain areas are cacheable, then it's *probably* safe to assume those areas are RAM. Both of these methods are theoretical - any computer that is new enough to support either of these methods will also have reliable BIOS functions that should be used instead.
If your OS uses GRUB to boot then you could just use GRUB. Unfortunately I've read the source code for GRUB's memory detection and it's only "adequate".pcmattman wrote:Can't you just use the memory map passed from GRUB?
Basically it doesn't check for any known BIOS bugs, doesn't try all known BIOS functions, has very little sanity checks and won't do manual probing where the computer is so messed up that it's required. Instead they assume it'll work and provide a way for the user to override it when it doesn't.
This means if you rely on GRUB alone, then your OS will work most of the time, but force the user to jump through hoops if they're unlucky. If you're trying to write a very high quality OS (reliable and user-friendly) then IMHO this just isn't good enough. Most people who use GRUB boot Linux, which does it's own (much more thorough) memory detection using methods described above (and isn't a "multiboot compliant" OS).
AFAIK you can get the size of each RAM bank from SM BIOS.keller wrote:4). Get ROM & RAM information from the SM BIOS.
(I didn't yet get good information about the RAM from the SM (Maybe because I'm not interpreting it right, but you can get from it the BIOS version, location, size, CPU, PCI slots etc).
It seems that you can't get any voluble information about the installed RAM from the SM BIOS, Fix me if I'm wrong.
IMHO the SM BIOS is intended to allow system adminstrators to get a report of what hardware is present (for e.g. so someone responsible for maintaining 100 computers can run a "SM BIOS" client on each computer instead of manually inspecting each computer). It's not intended to be relied on by software, and it's not at the top of BIOS manufacturers quality control checklists. This web page (an FAQ for a utility to view the SM BIOS data) describes this fairly well.
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.
It looks like sooner or later one would end up writing areas of BIOS services that are above 1MB and above 64MB if one doesn't find out which areas are those.
Now I see that I haven't made far too bad assumptions. For example, I don't plan to support the older 32-bit motherboards mainly with ISA devices and some PCI buses (in those machines it will readily restart because it requires 64-bit). That's why I always start probing at Megabyte 64, and require to be at least 128MB of RAM installed so it be a really useable system run; otherwise I refuse to boot. I don't think that for modern requirements a machine with less than 128MB could run all of the required programs by the user efficiently. I mean things like a nice GUI with games, large files, network processes and other heavy tasks.
Also, I make a manual RAM probe for each 4Kb in an Athlon machine, and it probes from Mb #64 up to the end of the 512Mb it has installed, and I know that there aren't PCI devices mapped there (although I'm not sure for network boot code), and I even restore the memory I tested, and it executes immediately and has never failed me (the oldest machine I have is a Pentium III).
The only problem I have faced is when trying to write for example, at any moment, in the memory of the video card mapped at something like 0xF0000000 when it's in text mode, it locks (in graphics mode it does nothing ill). And it seems to let the machine in a normal state because if the system is restarted it can load another OS without apparent trouble running anything as usual.
Anyway, would destroying 16 or 32-bit BIOS code above 1Mb have some importance if one is going to program a fully 64-bit kernel?
Now I see that I haven't made far too bad assumptions. For example, I don't plan to support the older 32-bit motherboards mainly with ISA devices and some PCI buses (in those machines it will readily restart because it requires 64-bit). That's why I always start probing at Megabyte 64, and require to be at least 128MB of RAM installed so it be a really useable system run; otherwise I refuse to boot. I don't think that for modern requirements a machine with less than 128MB could run all of the required programs by the user efficiently. I mean things like a nice GUI with games, large files, network processes and other heavy tasks.
Also, I make a manual RAM probe for each 4Kb in an Athlon machine, and it probes from Mb #64 up to the end of the 512Mb it has installed, and I know that there aren't PCI devices mapped there (although I'm not sure for network boot code), and I even restore the memory I tested, and it executes immediately and has never failed me (the oldest machine I have is a Pentium III).
The only problem I have faced is when trying to write for example, at any moment, in the memory of the video card mapped at something like 0xF0000000 when it's in text mode, it locks (in graphics mode it does nothing ill). And it seems to let the machine in a normal state because if the system is restarted it can load another OS without apparent trouble running anything as usual.
Anyway, would destroying 16 or 32-bit BIOS code above 1Mb have some importance if one is going to program a fully 64-bit kernel?
- AndrewAPrice
- Member
- Posts: 2309
- Joined: Mon Jun 05, 2006 11:00 pm
- Location: USA (and Australia)
- Brynet-Inc
- Member
- Posts: 2426
- Joined: Tue Oct 17, 2006 9:29 pm
- Libera.chat IRC: brynet
- Location: Canada
- Contact: