Reading the memory map from multiboot

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.
Post Reply
yukito

Reading the memory map from multiboot

Post by yukito »

Hi!

For starters, I _DID_ read the FAQ on this, so don't start reacting with your guns blazing ;)

I don't see why the code in the faq is supposed to work: it uses int's where they say that there are 4 bytes per field, so a long should be used right? I'm probably just confused so set me straight if I'm wrong.

Other than that, they also add sizeof(unsigned int) to the size of the memory map entry, why is that? To get the base_addr_low at offset 0? won't that mess up the structure and put the base_addr_low in the size field?

The memory_map structure from multiboot.h looks correct though, so why can't I use that one?

However, using:

Code: Select all

      struct memory_map* mmap = (struct memory_map*)mbd->mmap_addr;
      while(mmap < (struct memory_map*) mbd->mmap_addr + mbd->mmap_length) {
         puts("Base address: ");
         puts_longhex(mmap->base_addr_low);
         puts(" - Size: ");
         puts_longdec(mmap->length_low);
         puts("\n");
         mmap = mmap +  mmap->size;
      }
Reads the first entry correctly, but the rest is messed up. What's wrong?

And why are we using 2 longs per address? 64bit address space, for non 32bit systems compatibility? Can I just use the lower 32bits on a 32bit x86?

This is just what pops into mind at 0:44, maybe it's just me being to tired to write an OS right now, but it just looks plain wrong :(
User avatar
Colonel Kernel
Member
Member
Posts: 1437
Joined: Tue Oct 17, 2006 6:06 pm
Location: Vancouver, BC, Canada
Contact:

Re:Reading the memory map from multiboot

Post by Colonel Kernel »

yukito wrote:I don't see why the code in the faq is supposed to work: it uses int's where they say that there are 4 bytes per field, so a long should be used right?
When compiling for a 32-bit target, int and long are the same size (i.e. -- 4 bytes). In my code, I use uint32_t (defined in stdint.h) to make things really clear. :)
And why are we using 2 longs per address? 64bit address space, for non 32bit systems compatibility? Can I just use the lower 32bits on a 32bit x86?
Newer x86 processors support Physical Address Space extensions (PAE), which allows for 36-bit physical addresses. x64 processors use PAE for even larger physical address spaces (48-bit IIRC... not sure). If you use only 32 bits and someone's machine has more than 4 GB RAM installed, your code will end up doing weird and unexpected things.

Don't have time to look into the rest of your questions at the moment...
Top three reasons why my OS project died:
  1. Too much overtime at work
  2. Got married
  3. My brain got stuck in an infinite loop while trying to design the memory manager
Don't let this happen to you!
AR

Re:Reading the memory map from multiboot

Post by AR »

The field telling the size of the struct is not accounted for in itself (ie. it says the size is 20 but you actually need to cycle 24bytes [+4 for the "size" field itself which is "sizeof(unsigned int)"]).

The code in the Wiki is broken actually, I fixed it now. The reason it didn't work is that when you do this:

Code: Select all

mmap = mmap +  mmap->size;
The compiler actually sees this:

Code: Select all

mmap = (memory_map_t*) ( (unsigned int)mmap + ( mmap->size * sizeof(memory_map_t) ) )
The correct increment code looks like:

Code: Select all

mmap = (memory_map_t*) ( (unsigned int)mmap + mmap->size + sizeof(unsigned int) );
yukito

Re:Reading the memory map from multiboot

Post by yukito »

Why does it need (unsigned int)mmap if long and int are both 32bit anyway? Or is there another difference? Thanks for your help!
AR

Re:Reading the memory map from multiboot

Post by AR »

The cast to unsigned int is to convert the pointer to a number so that it can be manipulated as such.

long, int, unsigned and signed all map to 4 byte numbers. A complete list for the x86 is:
char - 1 byte
short - 2 bytes
int - 4 bytes
long - 4 bytes
long long - 8 bytes
A pointer is equivalent to "unsigned long int" which is still 4 bytes anyway. The reason for the use of "sizeof(unsigned int)" instead of just "+ 4" is because when you come back to the code after not having used it for a while, you can see exactly why 4 bytes are being added rather than having to work out what the hell "+ 4" is about.
User avatar
Solar
Member
Member
Posts: 7615
Joined: Thu Nov 16, 2006 12:01 pm
Location: Germany
Contact:

Re:Reading the memory map from multiboot

Post by Solar »

Note that any assumptions about int and long being the same size are valid on the vast majority of platforms, but by no means guaranteed in any way.

Likewise, casting a pointer to some integer and assuming it will fit is compiler-dependent; more exactly, compiler configuration dependent.

If you want to play it safe, use C99 and <stdint.h> (uint32_t, intptr_t etc.)
Every good solution is obvious once you've found it.
yukito

Re:Reading the memory map from multiboot

Post by yukito »

Yes sorry about that, my C++ book states that an int is 4 bytes, by which they probably meant a short int.

Also, my code outputs the following:

Base address: 0x3064662820202020 - Size: 1701511209 - Type: 6B2F2020

What does this mean/do? The rest of the output is just plain avaible RAM.
AR

Re:Reading the memory map from multiboot

Post by AR »

That looks like you've misread it, AFAIK Hardware won't map itself in PAE memory. If that's from Bochs can you show the whole list and the updated code?
User avatar
Brendan
Member
Member
Posts: 8561
Joined: Sat Jan 15, 2005 12:00 am
Location: At his keyboard!
Contact:

Re:Reading the memory map from multiboot

Post by Brendan »

Hi,
yukito wrote: Also, my code outputs the following:

Base address: 0x3064662820202020 - Size: 1701511209 - Type: 6B2F2020
If you convert it all to ASCII, the base address is " (fd0", the size is ")" then a zero then "ke", and the type is " /k". Every byte is valid ASCII.

I think your either reading from the wrong place or the correct data has been overwritten.


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.
Post Reply