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:

Post by LordMage »

Yes, I used the code that you posted with limited changes. I changed the '@f' and '@@:' to names because I really am not that comfortable with asm and didn't know exactly what those symbols were for. I created variables in my data section to hold the values of TotalRamMB and ExtendedMemory. Then after I did the switch to protected mode and setup the new stack pointer I push the values onto the stack. inside the first function of my kernel I pop the same variables in reverse order off the stack and then pass them to my kernel main as funciton parameters. How do you pass them to your kernel??
Getting back in the game.
egos
Member
Member
Posts: 612
Joined: Fri Nov 16, 2007 1:59 pm

Post by egos »

I use this code first.

Code: Select all

                xor     ebx, ebx
                mov     ecx, 20

smap_next:      mov     edx, "PAMS" ; it's fasm :-)
                mov     eax, 0E820h
                int     15h
                jc      error_5
                sub     eax, "PAMS"
                jnz     error_5
                cmp     ecx, 20
                jne     error_5
                cmp     [di+ARDESC.Type], 1
                jne     smap_continue
                mov     ebp, [di+ARDESC.BaseAddrLow]
                mov     edx, ebp
                add     ebp, 0FFFh
                cmp     ebp, 100FFFh
                jb      smap_continue
                cmp     eax, [di+ARDESC.BaseAddrHigh]
                jne     smap_continue
                add     edx, [di+ARDESC.LengthLow]
                jc      @f
                cmp     eax, [di+ARDESC.LengthHigh]
                jne     @f
                mov     eax, edx
                and     ax, 0F000h
@@:             and     bp, 0F000h
                sub     eax, 1000h
                cmp     ebp, eax
                ja      smap_continue
                push    eax
                push    ebp
                inc     [mbcount]
                js      @f
smap_continue:  and     ebx, ebx
                jnz     smap_next
I store the data about memory blocks above 1M boundary (base page address and last page address) within a stack. In addition to this code I use int 15h/0E801h and int 15h/88h.
LordMage
Member
Member
Posts: 115
Joined: Sat Sep 22, 2007 7:26 am
Contact:

Post by LordMage »

@egos: your using the variable mbcount, how is that defined and how do you pass it to your kernel? I am fine with the functions I just don't know how to get the info inside the kernel?

@dex: basically the same thing I ask egos, how do I get the information inside my kernel? am I correct in putting it in the stack or is there a better way?
Getting back in the game.
egos
Member
Member
Posts: 612
Joined: Fri Nov 16, 2007 1:59 pm

Post by egos »

First it contains zero. I store value of this variable within a stack too.

Code: Select all

                mov     cl, [mbcount] ; ch=0
...
                push    0
                push    cx
In my kernel the RM startup code and the PM startup code have common stack.
LordMage
Member
Member
Posts: 115
Joined: Sat Sep 22, 2007 7:26 am
Contact:

Post by LordMage »

Again, I am not familiar with fasm and not real comfortable with asm to start with. Where does mbcount come from. were is it initially defined and how exactly do you get it to the kernel?
Getting back in the game.
egos
Member
Member
Posts: 612
Joined: Fri Nov 16, 2007 1:59 pm

Post by egos »

It's defined in the RM startup code.

Code: Select all

mbcount         db      0
Then I push it to stack and finally pop it in the PM startup code.

Code: Select all

                push    0 ; RM startup code
                push    cx
...
                pop     ecx ; PM startup code
Last edited by egos on Mon Nov 19, 2007 5:51 pm, edited 2 times in total.
Mounter
Posts: 8
Joined: Sun Aug 12, 2007 12:45 pm
Location: Feliz, Rio Grande do Sul, Brazil
Contact:

Post by Mounter »

JAAman wrote:
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
The code read and write up to 2MB of RAM not on init of it, then I consider this code not dangerous... or I am incorrect on this?

Obs.: I suppose it's a IBM compatible system.
User avatar
JAAman
Member
Member
Posts: 879
Joined: Wed Oct 27, 2004 11:00 pm
Location: WA

Post by JAAman »

The code read and write up to 2MB of RAM not on init of it
not quite sure what you mean by this, but anytime you are writing random values to random pieces of hardware, you run a risk -- if you dont know if there is ram there, you dont know that there isnt some other hardware there...

this is one of the reasons probing to see how much memory there is is never a good idea, because you are putting bits of data into devices, when you dont know what device you are talking to
LordMage
Member
Member
Posts: 115
Joined: Sat Sep 22, 2007 7:26 am
Contact:

Post by LordMage »

okay, that is almost exactly what I have done. my variables are defined in the data section at the begining of my Stage2 bootloader

Code: Select all


ExtMemorySize db 0
TotalMemoryMB db 0

Then right before the jmp to stage3 where I switch to protected mode I run the GetRamSize funciton.

Code: Select all


RAMerror:
	mov	si, msgFailure		; Nope--print error
	call	Puts16
	mov	ah, 0
	int     0x16                    ; await keypress
	int     0x19                    ; warm boot computer
	cli				; If we get here, something really went wong
	hlt
	
	;----------------------------------------------------; 
	; Get Ram Size.                                      ; 
	;----------------------------------------------------; 
GetRamSize: 
   mov   ax,0xe801 
   int   15h 
   jc    RAMerror   ;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   EndTotalRam 
   mov   [TotalMemoryMB],ebx 
   ret 
EndTotalRam:
   inc   ebx 
   mov   [TotalMemoryMB],ebx 
   ret 


And then right after I load my new stack pointer I push the values onto the stack.

Code: Select all


bits 32

Stage3:

	;-------------------------------;
	;   Set registers		;
	;-------------------------------;
	  
	mov	ax, 0x10		; set data segments to data selector (0x10)
	mov	ds, ax
	mov	ss, ax
	mov	es, ax
	mov fs, ax
	mov gs, ax
	mov	esp, 90000h		; stack begins from 90000h
	
	push ExtMemorySize
	push TotalMemoryMB
	
then in my C++ code the first thing I do is pop the values off the stack. and pass them to the kernels main function.

Code: Select all


unsigned int ExtMemorySize, TotalMemoryMB;

	ExtMemorySize = 0;
	TotalMemoryMB = 0;

	_asm { 
		pop TotalMemoryMB
		pop ExtMemorySize
	};

	//	Setup stack frame pointer so functions have a place to return to
	_asm {
		mov ebp, esp
		push ebp
	}

#endif //ARCH_X86

	// Execute global constructors
	InitializeConstructors();

	//	Call kernel entry point
	kmain(TotalMemoryMB, ExtMemorySize);

then I simply print them out using my cout function which I have tested with manual integers and it works fine. Any ideas what I am doing wrong?
Getting back in the game.
User avatar
Brendan
Member
Member
Posts: 8561
Joined: Sat Jan 15, 2005 12:00 am
Location: At his keyboard!
Contact:

Post by Brendan »

Hi,
LordMage wrote:

Code: Select all

	;----------------------------------------------------; 
	; Get Ram Size.                                      ; 
	;----------------------------------------------------; 
GetRamSize: 
   mov   ax,0xe801 
   int   15h 
   jc    RAMerror   ;may jump to some error code 
   movzx ebx, bx 
   shl   ebx,6 
   movzx eax, ax 
   add   ebx,eax 
   mov   [ExtMemorySize],ebx 
   call  TotalRam 
   ret 
Here's the information for this BIOS function.

You're doing "64KB_blocks_above_16MB * 64 + 1KB_blocks_between_1MB_and_16MB" which should give you the number of KB above 1MB, unless it's one of the computers that doesn't support this function, or it's one of the computers that returns this information in CX & DX instead.

Also, what Ralph Brown's list doesn't say is that this function only returns information for the contiguous block of RAM starting at 16 MB. If there's several seperate blocks or RAM above 16 MB (which is likely if the computer has 3GB of RAM or more, and possible in any case) it only reports one of them.

The other problem is that it only reports RAM, and doesn't give you any other information (reserved areas that can't be used for memory mapped devices, ACPI areas, etc).
LordMage wrote:

Code: Select all

 ;----------------------------------------------------; 
 ; TotalRam.                                          ; 
 ;----------------------------------------------------; 
TotalRam: 
   shr   ebx,10 
   inc   ebx 
   test  ebx,1 
   jnz   EndTotalRam 
   mov   [TotalMemoryMB],ebx 
   ret 
EndTotalRam:
   inc   ebx 
   mov   [TotalMemoryMB],ebx 
   ret
Why is this code rounding up to the next even MB?
LordMage wrote:And then right after I load my new stack pointer I push the values onto the stack.

Code: Select all

bits 32

Stage3:

	;-------------------------------;
	;   Set registers		;
	;-------------------------------;
	  
	mov	ax, 0x10		; set data segments to data selector (0x10)
	mov	ds, ax
	mov	ss, ax
	mov	es, ax
	mov fs, ax
	mov gs, ax
	mov	esp, 90000h		; stack begins from 90000h
	
	push ExtMemorySize
	push TotalMemoryMB
This pushes the address of the variables on the stack, not the contents of the variables (e.g. a pointer to "ExtMemorySize" rather than the value at ExtMemorySize)...
LordMage wrote:then in my C++ code the first thing I do is pop the values off the stack. and pass them to the kernels main function.
Not quite - the first thing you do is stuff up the stack frame and ESP that the compiler thought it could relying on.

Why not shift this inline assembly into your assembly source code, and use "extern unsigned int ExtMemorySize" so the linker can figure out where it is (and so you don't need to pass it from the assembly code to C++ code)?


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.
LordMage
Member
Member
Posts: 115
Joined: Sat Sep 22, 2007 7:26 am
Contact:

Post by LordMage »

if your refering to the inline asm that pops my variables I suppose I could put that in my included asm code but that still wouldn't solve my problem. how do I pop or push the values in those variables and not the memory locations of the variables?

I have been trying every permutation I can think of. I used the functions I used because Dex provided them and before I can make changes and customize things I need to know that they work correctly. So, I always go with the tried and true before I modify.

EDIT: I guess I should say that I am using bochs and it is setup with 32mb of ram but the function is returning somthing like 500Gb ram
Getting back in the game.
User avatar
Brendan
Member
Member
Posts: 8561
Joined: Sat Jan 15, 2005 12:00 am
Location: At his keyboard!
Contact:

Post by Brendan »

Hi,
LordMage wrote:if your refering to the inline asm that pops my variables I suppose I could put that in my included asm code but that still wouldn't solve my problem.
In your C++ code (e.g. in a header file) you could use "extern unsigned int ExtMemorySize" so that your C++ code can get it from the same memory location that your assembly code used. You might have to put "global ExtMemorySize" in your assembly source code to keep the linker happy (not sure - I usually don't use C or C++). In this case, you don't need to mess about with the stack.

Another way would be to push these values on the stack (in your assembly source code) and use them as function arguments in your C++ code (e.g. call "kmain()" directly from assembly).
LordMage wrote:how do I pop or push the values in those variables and not the memory locations of the variables?
That is the easy enough:

Code: Select all

   push dword [ExtMemorySize]
   push dword [TotalMemoryMB]
LordMage wrote:I have been trying every permutation I can think of. I used the functions I used because Dex provided them and before I can make changes and customize things I need to know that they work correctly. So, I always go with the tried and true before I modify.
That's probably the biggest problem - you're accidentally designing your OS so that it relies on a single "there's X MB of memory" variable, when you should be deliberately designing your OS (ie. with foresight) so that it takes a full list of all areas in the physical address space (not just RAM).

Your code (after it's fixed) is probably "good enough" for display purposes, but it's mostly inadequate for memory management. Once you redesign things so that you've got the information you need for memory management you'll probably realise that this information could be used for display purposes too, and the method you're using now will (hopefully?) become obsolete not long after you get it working.


Cheers,

Brendan
Attachments
memlist.jpg
memlist.jpg (30.67 KiB) Viewed 1326 times
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.
LordMage
Member
Member
Posts: 115
Joined: Sat Sep 22, 2007 7:26 am
Contact:

Post by LordMage »

I am going to convert the function to do what I want after I get it working the way Dex originally implemented it. Trust me I am not designing my OS around my functions, I just have to make sure that I can get stuff I've never used before to work and see how it is supposed to work before I go and make it mine. The way I figure it is that the amount of output and planning for holes won't do anygood if the information being given is wrong.
Getting back in the game.
User avatar
Dex
Member
Member
Posts: 1444
Joined: Fri Jan 27, 2006 12:00 am
Contact:

Post by Dex »

Brendan wrote:
LordMage wrote:

Code: Select all

 ;----------------------------------------------------; 
 ; TotalRam.                                          ; 
 ;----------------------------------------------------; 
TotalRam: 
   shr   ebx,10 
   inc   ebx 
   test  ebx,1 
   jnz   EndTotalRam 
   mov   [TotalMemoryMB],ebx 
   ret 
EndTotalRam:
   inc   ebx 
   mov   [TotalMemoryMB],ebx 
   ret
Why is this code rounding up to the next even MB?

Cheers,
Brendan
I have found when using this int, that it will give the right amount of ram, but it some times gives you a odd number, but windows would give you a even number (i think it round the .??? up.
Example: windows would post 64 MB and that function would post 63 MB of ram, so when people see windows saying one thing and my OS post a differant number, people always think windows is right.

So i use this to post the amount of ram, But i use the unevened number, for internal use.

@LordMage, Brendan is right you are pushing the address. not the contents.
The @@: in fasm works like this
This @f = the next @@: label forward
This @b = the next @@: label backward
LordMage
Member
Member
Posts: 115
Joined: Sat Sep 22, 2007 7:26 am
Contact:

Post by LordMage »

okay, I tried to push the contents like he suggested but I got the same answer, I must be doing something wrong but I really don't know what. is there anything else wrong with my code? Can I actually make something in my stage2 bootloader globally available so that my kernel can see it also?
Getting back in the game.
Post Reply