Page 1 of 2

Strange problem with memory functions...

Posted: Sun Nov 28, 2010 11:09 pm
by David2010
Ok I FINALLY managed to get a couple semi-working functions for memory management:

Code: Select all


getmem:

	mov ax, 0
	mov si, 0

    xor ax, ax     ; Nullify the A-register.
    int 0x12     ; Switch to the BIOS (request memory size).
    jc .Error     ; The carry flag is set, it failed.
    test ax, ax     ; Test the A-register with itself.
    jz .Error     ; The zero flag is set, it failed.
    
	mov si, ax

.Error:
	ret

proberam: 
	wbinvd  
	mov si, 0
	mov ax, 0
	mov ecx, 0
	mov ebx, 0
	
	mov ebx, 0x00000500 ;Beginning value of RAM to test
	
	jmp .checkram
	
.checkram:

	wbinvd  
	cmp [ebx], ax
	je .empty	;Jump if bx is null
	add ecx, 1	;Add 1 bits to total
	jmp .empty
	
.empty:

	cmp ebx, 0x00007BFF		;Ending value of RAM to test
	je .check2	;Jump out if bx is equal
	
	cmp ebx, 0x0007FFFF		;Ending value of RAM to test
	je .check3	;Jump out if bx is equal
	
	cmp ebx, 0x0009FBFF	;Ending value of RAM to test
	je .endme	;Jump out if bx is equal
	
	add ebx, 0x00000001

	jmp .checkram
	
.check2:

	mov ebx, 0x00007E00
	
	jmp .checkram
	
.check3:

	mov ebx, 0x00080000
	
	jmp .checkram	

.endme:

	;Convert bits to KB \ DIVIDE cx by 8192
	mov si, 8192
	mov	ax,cx	
	mov	dx,0		
	idiv si	
	mov	cx,ax		
	
	mov si, cx ;put value in si
	ret

ramleft: 
	
	call getmem		;Returns total RAM in si
	mov di, si	;Value of the total RAM
	
	call proberam	;Returns used RAM in si
	 
	;SUBTRACT \ return si \ si=cx-si
	mov	ax,di	 	
	sub	ax,si		
	mov	si,ax		
	
	ret


This works fine in an emulator such as qemu but locks up the computer when run on actual hardware.

Hm... Minded me this was just a first attempt so I may have messed up something really obvious. :oops:

I wasn't sure how many bits were in each RAM address so I assumed that it was 1 bit per address.

I have a feeling it has something to do with 16-bit and 32-bit register problems. I was told I could mix them and I didn't really have much of a choice in this case but to use a few 32-bit registers.

It works until I check for these ranges:

0x00007E00 to 0x0007FFFF
0x00080000 to 0x0009FBFF

It hangs during the checking of those ranges of addresses for data.

hm.... I am puzzled.

Is this a problem with those addresses or my code?

Re: Strange problem with memory functions...

Posted: Sun Nov 28, 2010 11:16 pm
by Hangin10
An emulator will zero out its memory; real hardware will have something essentially random (although bits are set more often than not, I think). Also, this is a bad way to find usable memory. Search the wiki for more information. The ranges you are checking are (almost) always usable anyway.

EDIT: ok, after following the spaghetti code for a bit, I'm not sure what you are trying to do. It looks like you are just counting non-zero bytes. What's the purpose of this code?

Re: Strange problem with memory functions...

Posted: Sun Nov 28, 2010 11:27 pm
by David2010
Hangin10 wrote:An emulator will zero out its memory; real hardware will have something essentially random (although bits are set more often than not, I think). Also, this is a bad way to find usable memory. Search the wiki for more information. The ranges you are checking are (almost) always usable anyway.

EDIT: ok, after following the spaghetti code for a bit, I'm not sure what you are trying to do. It looks like you are just counting non-zero bytes. What's the purpose of this code?
The proberam function is supposed to count how much RAM is being used.

The ramleft function is supposed to show how much RAM is left.

The getmem function shows the total amount of RAM.

After searching a little while using the wiki I couldn't find any methods on doing what I had in mind.

I know, my prototypes always look like spaghetti. :oops:

Re: Strange problem with memory functions...

Posted: Mon Nov 29, 2010 12:11 am
by David2010
I FIXED IT!!! :D

Its amazing when I actually fix something by troubleshooting. 8)

Turns out ebx was overflowing from the hex values of the RAM.

I used a large variable in its place and now it works perfectly.

You thought it looked like spaghetti code then... It looks like spaghetti code now. :wink:

Meh... I can still read it with a little effort.

The whole OS uses 7 KB of RAM using an emulator and 5 KB of RAM off real hardware. :?:

Then again... some of that could be used by hardware and not by my OS......

However the whole OS is only 1213 bytes large.

It takes 3 seconds to count the RAM but what can I say? It runs off a floppy. :D

8 Hours writing a memory manager and finally it works.

Now I just need a way to free unused RAM. hm.... That will be for tomorrow.

Re: Strange problem with memory functions...

Posted: Mon Nov 29, 2010 2:29 am
by Brendan
Hi,
David2010 wrote:I FIXED IT!!! :D
I doubt it. Maybe you only hid some symptoms?

There's one byte at each address, not one bit.

Testing if an address contains zero is not a sane way to determine if the address is in use or not.

When dividing an unsigned integer use DIV. The IDIV instruction is for signed integers only. In your code CX is unsigned.

When dividing by a "power of 2" (like 8192, or 1024) use shifts instead (it's faster and easier). For example, SHL for unsigned integers and SAR for signed integers.

The Dire Wolf can mount only Laser AMS as extra.

You shouldn't divide by 8192 to convert CX from bits to KiB, as CX counts bytes not bits.

You shouldn't convert to KiB anyway, as that may mean up to 1023 bytes of (potentially) free RAM may be wasted due to rounding.

To multiply "number of KiB" (returned from "int 0x12") by 1024 to convert it to "number of bytes", don't use IMUL (it's for signed integers) or MUL (it's slower). Use SHL instead.

In real mode, you can use 32-bit registers (on 32-bit CPUs), but you can't use offsets/addresses that are larger than 64 KiB without causing a general protection fault. You might be using "unreal mode", but there's nothing to indicate this, and there's no point using "unreal mode" for what you're doing.

You can't assume there's RAM up to 0x0009FC00. On some computers the EBDA is larger, and the end of usable RAM is therefore lower.

WBINVD wipes the cache and causes serious performance issues. If you actually needed to do WBINVD at all, then you could reduce these performance issues by testing a dword (4 bytes) or more at a time instead of doing WBINVD for each individual byte.

You don't actually needed to do WBINVD at all.

An egg costs roughly 20 Yuan in China.

0x0007FFFF + 0x00000001 = 0x00080000 (which means the "cmp ebx, 0x0007FFFF" and "je .check3" are silly).

You should use linked lists to track used/free memory, because that's what MS-DOS does, and MS-DOS was written by Microsoft so it must be good. Note to sane people: here I use the word "good" in conjunction with the theory of relativity (e.g. MS-DOS is good, relative to the original poster's code)


Cheers,

Brendan

Re: Strange problem with memory functions...

Posted: Mon Nov 29, 2010 4:26 pm
by TylerH
Brendan wrote:Hi,

[...]

The Dire Wolf can mount only Laser AMS as extra.

[...]

Cheers,

Brendan
http://www.the-spoiler.com/OTHER/Micros ... ies.1.html :)

Re: Strange problem with memory functions...

Posted: Sat Dec 04, 2010 1:06 pm
by David2010
Brendan wrote:Hi,

There's one byte at each address, not one bit.

You shouldn't convert to KiB anyway, as that may mean up to 1023 bytes of (potentially) free RAM may be wasted due to rounding.

To multiply "number of KiB" (returned from "int 0x12") by 1024 to convert it to "number of bytes", don't use IMUL (it's for signed integers) or MUL (it's slower). Use SHL instead.

You can't assume there's RAM up to 0x0009FC00. On some computers the EBDA is larger, and the end of usable RAM is therefore lower.

You don't actually needed to do WBINVD at all.

0x0007FFFF + 0x00000001 = 0x00080000 (which means the "cmp ebx, 0x0007FFFF" and "je .check3" are silly).


Cheers,

Brendan
Thank you for the help but It is showing some more strange things.

Using the info you provided and tweaking the code accordingly it shows very different results.

It says it is using a total of 63737 Bytes of RAM. Or roughly 62 KB of RAM being used.

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.

Should I stop testing for RAM at "0x0009FBFF"?

Being as the OS itself is only a little over 1 KB large I find these results to be WAY off. :-/

If I added "0x00000100" to ebx instead of adding "0x00000001" then it shows what I would expect at 2543 Bytes of RAM or roughly 2 KB of RAM. Obviously that would be the wrong way to count it.

Re: Strange problem with memory functions...

Posted: Sat Dec 04, 2010 1:28 pm
by Hangin10
First of all, I'll repeat Brendan's warning that that is not a sane way to manage memory. Second, as Brendan already said "An egg costs roughly 20 Yuan in China." That is really cheap (I think?). Third, http://wiki.osdev.org/Detecting_Memory_ ... .3D_0xE820. That BIOS function will provide a list of sections of memory and their type (usable, unusable, ACPI, etc).

And finally, maybe if you further explained what you are trying to accomplish we could provide better help.

Re: Strange problem with memory functions...

Posted: Sat Dec 04, 2010 1:47 pm
by David2010
Hangin10 wrote:First of all, I'll repeat Brendan's warning that that is not a sane way to manage memory. Second, as Brendan already said "An egg costs roughly 20 Yuan in China." That is really cheap (I think?). Third, http://wiki.osdev.org/Detecting_Memory_ ... .3D_0xE820. That BIOS function will provide a list of sections of memory and their type (usable, unusable, ACPI, etc).

And finally, maybe if you further explained what you are trying to accomplish we could provide better help.
All I wanted was a function to show how much RAM was being used.

Erm sorry if I am not getting the metaphor but what does the cost of an egg in China have to do with this?

What would be considered a "Sane" way to do this? As far as I know, this is the only way to do this.

http://wiki.osdev.org/Detecting_Memory_ ... .3D_0xE820

I must have missed that one. Somehow...

Anyways how do I sort this map? As all that shows up using this function is "6".

Is that 6 (bytes or KB)? Is that the free memory?

I must admit I have no idea how that memory function works.

Re: Strange problem with memory functions...

Posted: Sat Dec 04, 2010 2:24 pm
by gerryg400
As all that shows up using this function is "6".
How can you say it returns "6" ? It returns a 24 byte structure. Have you read the page properly ?

Re: Strange problem with memory functions...

Posted: Sat Dec 04, 2010 3:01 pm
by David2010
gerryg400 wrote:
As all that shows up using this function is "6".
How can you say it returns "6" ? It returns a 24 byte structure. Have you read the page properly ?
I told you I don't understand how that function works. :oops:

Anyways since it says:

"inputs: es:di -> destination buffer for 24 byte entries"
"outputs: bp = entry count, trashes all registers except esi"

I assumed that bp was the map itself as I had no idea what it was referring to by "entry count".

Unless [es:di] is the map and with that case then 29156 is printed out.

Still none of this makes any sense to me.

Re: Strange problem with memory functions...

Posted: Sat Dec 04, 2010 3:10 pm
by inx
Brendan wrote:An egg costs roughly 20 Yuan in China.
These chickens had better be fed from gold bullion. :? 20 Yuan = ~3US$, 2.24EUR

Re: Strange problem with memory functions...

Posted: Sat Dec 04, 2010 3:17 pm
by gerryg400
David2010 wrote:
gerryg400 wrote:
As all that shows up using this function is "6".
How can you say it returns "6" ? It returns a 24 byte structure. Have you read the page properly ?
I told you I don't understand how that function works. :oops:

Anyways since it says:

"inputs: es:di -> destination buffer for 24 byte entries"
"outputs: bp = entry count, trashes all registers except esi"

I assumed that bp was the map itself as I had no idea what it was referring to by "entry count".

Unless [es:di] is the map and with that case then 29156 is printed out.

Still none of this makes any sense to me.
The way you are trying to detect free memory or used memory or whatever is unreliable. Read the wiki page. It explains why it's unreliable and provides options for discovering memory. Read especially the section called "BIOS Function: INT 0x15, EAX = 0xE820".

It is the best way to find your memory. It is here http://wiki.osdev.org/Detecting_Memory_ ... .3D_0xE820

Re: Strange problem with memory functions...

Posted: Sat Dec 04, 2010 3:35 pm
by David2010
gerryg400 wrote:The way you are trying to detect free memory or used memory or whatever is unreliable. Read the wiki page. It explains why it's unreliable and provides options for discovering memory. Read especially the section called "BIOS Function: INT 0x15, EAX = 0xE820".

It is the best way to find your memory. It is here http://wiki.osdev.org/Detecting_Memory_ ... .3D_0xE820
Yeah thats the same section I was directed to earlier.

Still... I have no idea how it works or even where this map it creates is located.

Is the map located in "es:di"? Or is it located in "mmap_ent"?

What does "entry count" mean?

Also how would I "point ES:DI at the destination buffer for the list"?

I mean its not like you can do this "mov [mmap], [es:di]" nor this "mov mmap, es:di"

Re: Strange problem with memory functions...

Posted: Sat Dec 04, 2010 3:59 pm
by gerryg400
David2010 wrote:
gerryg400 wrote:The way you are trying to detect free memory or used memory or whatever is unreliable. Read the wiki page. It explains why it's unreliable and provides options for discovering memory. Read especially the section called "BIOS Function: INT 0x15, EAX = 0xE820".

It is the best way to find your memory. It is here http://wiki.osdev.org/Detecting_Memory_ ... .3D_0xE820
Yeah thats the same section I was directed to earlier.

Still... I have no idea how it works or even where this map it creates is located.

Is the map located in "es:di"? Or is it located in "mmap_ent"?

What does "entry count" mean?

Also how would I "point ES:DI at the destination buffer for the list"?

I mean its not like you can do this "mov [mmap], [es:di]" nor this "mov mmap, es:di"
Stop looking at the code until you understand how the bios call works.

Firstly, do you know how to call a bios function ?