Reputation: 61
I am writing a simple program in Assembly (NASM). When the boot sector loads it has to display all the memory (RAM) installed in the computer in Megabytes. There would be no Operating System (DOS, Windows, Linux) when the boot sector is loaded, so how would I find out total RAM size. I have 2 GB RAM in my computer. I have searched alot on the internet but could not find a solution.
Is there an interrupt of BIOS that shows memory size of 2 GB? There is an interrupt that was used in old computers to shows memory, but it does not shows all 2 GBs. I checked and there is no solution for this in Ralph Brown List. May be someone knows alot more about BIOS. If BIOS does not provide this facility then can I use C/C++ to find out Total RAM size? And call C/C++ code from assembly? What function of C/C++ would be used to find Total RAM size?
Remember that my assembly code will do a cold boot and there would be no operating system to provide any facility to my code.
EDITED:
I read the website http://wiki.osdev.org/Detecting_Memory_%28x86%29. And decided to check if int 15 works. So I got the code from this website and edited it to test if int 15 EAX = E820 works. But it fails to work and the output is 'F' in .failed1. 'F' is test case which I made to check for "unsupported function". Test Cases are 'F', 'G' and 'H'. Here is the code.
; use the INT 0x15, eax= 0xE820 BIOS function to get a memory map
; inputs: es:di -> destination buffer for 24 byte entries
; outputs: bp = entry count, trashes all registers except esi
do_e820:
xor ebx, ebx ; ebx must be 0 to start
xor bp, bp ; keep an entry count in bp
mov edx, 0x0534D4150 ; Place "SMAP" into edx
mov eax, 0xe820
mov [es:di + 20], dword 1 ; force a valid ACPI 3.X entry
mov ecx, 24 ; ask for 24 bytes
int 0x15
jc short .failed1 ; carry set on first call means "unsupported function"
mov edx, 0x0534D4150 ; Some BIOSes apparently trash this register?
cmp eax, edx ; on success, eax must have been reset to "SMAP"
jne short .failed2
test ebx, ebx ; ebx = 0 implies list is only 1 entry long (worthless)
je short .failed3
jmp short .jmpin
.e820lp:
mov eax, 0xe820 ; eax, ecx get trashed on every int 0x15 call
mov [es:di + 20], dword 1 ; force a valid ACPI 3.X entry
mov ecx, 24 ; ask for 24 bytes again
int 0x15
jc short .e820f ; carry set means "end of list already reached"
mov edx, 0x0534D4150 ; repair potentially trashed register
.jmpin:
jcxz .skipent ; skip any 0 length entries
cmp cl, 20 ; got a 24 byte ACPI 3.X response?
jbe short .notext
test byte [es:di + 20], 1 ; if so: is the "ignore this data" bit clear?
je short .skipent
.notext:
mov ecx, [es:di + 8] ; get lower dword of memory region length
or ecx, [es:di + 12] ; "or" it with upper dword to test for zero
jz .skipent ; if length qword is 0, skip entry
inc bp ; got a good entry: ++count, move to next storage spot
add di, 24
.skipent:
test ebx, ebx ; if ebx resets to 0, list is complete
jne short .e820lp
.e820f:
mov [mmap_ent], bp ; store the entry count
clc ; there is "jc" on end of list to this point, so the carry must be cleared
mov ah, 0x0E ; Teletype command
mov bh, 0x00 ; Page number
mov bl, 0x07 ; Attributes (7 == white foreground, black background)
mov al, mmap_ent ; Character to print
int 0x10
ret
.failed1:
push eax
push ebx
mov ah, 0x0E ; Teletype command
mov bh, 0x00 ; Page number
mov bl, 0x07 ; Attributes (7 == white foreground, black background)
mov al, 70 ; Character 'F' to print
int 0x10
pop ebx
pop eax
stc ; "function unsupported" error exit
ret
.failed2:
push eax
push ebx
mov ah, 0x0E ; Teletype command
mov bh, 0x00 ; Page number
mov bl, 0x07 ; Attributes (7 == white foreground, black background)
mov al, 71 ; Character 'G' to print
int 0x10
pop ebx
pop eax
stc ; "function unsupported" error exit
ret
.failed3:
push eax
push ebx
mov ah, 0x0E ; Teletype command
mov bh, 0x00 ; Page number
mov bl, 0x07 ; Attributes (7 == white foreground, black background)
mov al, 72 ; Character 'H' to print
int 0x10
pop ebx
pop eax
stc ; "function unsupported" error exit
ret
mmap_ent db 0
failmsg db 0
failmem db 'Failed', 0
;times 512-($-$$) db 0
;dw 0xAA55
EDITED:
I used nasm memext.asm -o memext.com -l memext.lst . Used MagicISO to make a bootable image file memext.iso and used Windows disk burner to burn it to a DVD/RW. Loaded Oracle VM and made a new Virtual Machine with 256 Mb RAM, CD/DVD, Hard disk of 2GB. Booted with DVD for a cold boot test, does not print anything.
Also, I open Command Console and just typed memext and it gave 'F' as output.
Upvotes: 2
Views: 1286
Reputation: 11706
EDIT: my mistake, the wiki is correct, just leaving this here because...
Looks like there's a typo in the wiki - the line:
mov edx,0x0534D4150
should look like:
mov edx,0x050414D53
Notice the bytes are in reverse order (since x86 is little endian).
Upvotes: 1
Reputation: 129474
You will need to read the ACPI tables on a PC (or other machines that support ACPI).
Note that this will not give you the total size as one number, but give you the memory size of each region of memory - on a simple machine, that may just be two or three regions (there are holes of "not real memory" at the 0xA0000-0xFFFFF and wherever the BIOS decides to put the "PCI-hole").
I suspect it won't be entirely trivial to fit the ACPI reader into a single sector, considering some of the boot sector only has around 400 bytes of space available (although if you completely skip the partition table, I suppose you can use almost all of the 512 bytes).
As to "how to call C/C++", you will not be able to fit any meaningful C or C++ program in less than several sectors. You will need to take a look at an OS bootloader, and see how they achieve the setup for the compiler (and in many cases, you will also need special tools to produce code that is at a particular location suitable to be loaded into the memory and directly executed). This page may be of help for that (I haven't read through it all, it may even tell how much memory you have): http://www.codeproject.com/Articles/36907/How-to-develop-your-own-Boot-Loader
Upvotes: 4