Hi,
David2010 wrote:Also you said that I shouldn't test all the way to 0x0009FC00 but where should I stop testing at because "http://wiki.osdev.org/Memory_Map_%28x86%29#.22Low.22_memory_.28.3C_1_MiB.29" says I should stop testing for RAM at 0x0009FBFF.
That table could be a little misleading, in that the size of the EBDA is not fixed. For example the EBDA could be 1 KiB (and the RAM from 0x00080000 to 0x0009FBFF may be usable); but the EBDA could also be 16 KiB (and only the RAM from 0x00080000 to 0x0009BFFF might be usable), or the EBDA could be any other size that is a multiple of 1 KiB (e.g. 1 KiB, 2 KiB, 3 KiB, ... ). Ancient software may have assumed that RAM up to 0x00080000 is usable and therefore (because backward compatibility is excessive on "PC compatible" computers) it's extremely unlikely that the EBDA will ever be more than 64 KiB, which means the RAM up to 0x0007FFFF is (almost) guaranteed to be free for your use.
You have to ask the BIOS to determine where this area of RAM ends (and stop your testing at the address that the BIOS says the area of RAM ends).
David2010 wrote:Being as the OS itself is only a little over 1 KB large I find these results to be WAY off. :-/
In general, the method you're using to calculate "used memory" is complete bullshit. For an example, imagine you turn the computer on and the BIOS uses 100 KiB of "usable RAM" in this area during initialisation, then the BIOS stops using this area, then starts your boot loader. Your boot loader counts "non-zero bytes" and decides that most of that 100 KiB that the BIOS used is still in use, even though it's not. For some computers RAM is not filled with zeros during reset (and remembers what was there before the reset), so in this case you could determine that 600 KiB of RAM is being used when it isn't.
Then there's things like your stack. You should reserve a few KiB for your stack, but this RAM is "in use" even if it contains zeros. The same applies to everything else. For example, imagine some executable code is in memory that does "add ax,0x0000". There's 2 bytes that are zeros in that instruction - are they "free RAM"? No.
To do it properly (and get sane results) you have to find a completely different way to determine which areas are being used.
For an example; you could split RAM up into small chunks (e.g. 1 KiB per chunk, so that if there's 630 KiB of RAM you've got 630 chunks); and then have an array where each entry in the array says if the corresponding chunk is "free RAM" or "used RAM" or "not usable RAM". Initially you'd fill this array with "not usable RAM" values, then ask the BIOS which areas of RAM are usable and change the corresponding entries in the array to "free RAM"; then change entries in the array that correspond to things you are already using (e.g. the BIOS data area starting at 0x00000000, and the boot loader area starting at 0x00007C00) to "used RAM". After the array is initialised; you'd be able to use the array to allocate RAM (e.g. find entries in the array that are marked as "free RAM" and change them to "used RAM") and use the array to free RAM (e.g. find entries in the array that are marked as "free RAM" and change them to "used RAM"). You would also be able to check the array and count how many chunks are "free RAM" and how many are "used RAM", and use that to determine how much RAM is in use and how much RAM exists (sum of "free RAM" and "used RAM").
Of course this isn't the only way to do things - for example, MS-DOS uses a linked list to track free and unused RAM.
For a real mode OS, the BIOS "int 0x12" function is enough to determine which areas are usable RAM (and which areas aren't), because you don't need to care about any memory you can't access (e.g. memory above 0x00100000) . For a protected mode OS (or a long mode/64-bit OS) you can access a lot more RAM, and therefore need to use something more complex (like the BIOS "int 0x15, eax = 0xE820" function). However, for a protected mode OS or a long mode OS, you'd need to gather information from the BIOS then switch to protected mode or long mode, and you'd need to implement your memory manager in protected mode or long mode because you won't be able to (easily) use anything designed for real mode after the OS has left real mode.
Cheers,
Brendan