RAM size? BIOS or other? [Working]
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.
I use this code first.
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.
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
@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?
@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.
First it contains zero. I store value of this variable within a stack too.
In my kernel the RM startup code and the PM startup code have common stack.
Code: Select all
mov cl, [mbcount] ; ch=0
...
push 0
push cx
It's defined in the RM startup code.
Then I push it to stack and finally pop it in the PM startup code.
Code: Select all
mbcount db 0
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.
-
- Posts: 8
- Joined: Sun Aug 12, 2007 12:45 pm
- Location: Feliz, Rio Grande do Sul, Brazil
- Contact:
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?JAAman wrote: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
Obs.: I suppose it's a IBM compatible system.
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...The code read and write up to 2MB of RAM not on init of it
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
okay, that is almost exactly what I have done. my variables are defined in the data section at the begining of my Stage2 bootloader
Then right before the jmp to stage3 where I switch to protected mode I run the GetRamSize funciton.
And then right after I load my new stack pointer I push the values onto the stack.
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.
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?
Code: Select all
ExtMemorySize db 0
TotalMemoryMB db 0
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
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
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);
Getting back in the game.
Hi,
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).
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
Here's the information for this BIOS function.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
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).
Why is this code rounding up to the next even MB?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
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: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
Not quite - the first thing you do is stuff up the stack frame and ESP that the compiler thought it could relying on.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.
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.
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
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.
Hi,
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).
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
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.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.
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).
That is the easy enough:LordMage wrote:how do I pop or push the values in those variables and not the memory locations of the variables?
Code: Select all
push dword [ExtMemorySize]
push dword [TotalMemoryMB]
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).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.
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 (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.
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.
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.Brendan wrote:Why is this code rounding up to the next even MB?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
Cheers,
Brendan
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
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.