Page 1 of 1

GRUB memory map

Posted: Sat Aug 13, 2016 4:09 pm
by BringerOfShadows
I'm having a problem figuring out how to get the GRUB memory map. I understand the basics, but there has always been something confusing with it. Namely the offset for the memory map entries.

http://wiki.osdev.org/Detecting_Memory_ ... Memory_Map
Declare the appropriate structure, get the pointer to the first instance, grab whatever address and length information you want, and finally skip to the next memory map instance by adding size+4 to the pointer, tacking on the 4 to account for GRUB treating base_addr_low as offset 0 in the structure
Can anyone explain how the whole -4 offset is handled, because it keeps me from moving forward.

Re: GRUB memory map

Posted: Tue Aug 16, 2016 8:32 am
by michaellangford
Not sure exactly what you mean, but I hope this helps:

This is how I import the memory map slots:

Code: Select all

  memory_slots = mboot_header->mmap_length / sizeof(mboot_memmap_t);
  
  mem_map_start = (uint32_t)mboot_header->mmap_addr;
  mem_map_size  = (uint32_t)mboot_header->mmap_length;
  mem_map_end = (uint32_t)mboot_header->mmap_addr + (uint32_t)mboot_header->mmap_length;
  
  mboot_memmap_t mmap_entries[memory_slots];
  memcpy((char*)&mmap_entries, (char*)mboot_header->mmap_addr, mboot_header->mmap_length);
  
This is my header file for multiboot definitions, and structs:

Code: Select all

#ifndef MULTIBOOT_H
#define MULTIBOOT_H

#define MULTIBOOT_KERNEL_MAGIC      0x2BADB002
#define MULTIBOOT_HEADER_MAGIC      0x1BADB002

#define MULTIBOOT_MMAP_FREE_MEMORY  1
#define MULTIBOOT_MMAP_RESERVED     2
#define MULTIBOOT_MMAP_ACPI         3
#define MULTIBOOT_MMAP_HIBERNATION  4
#define MULTIBOOT_MMAP_BAD_CELL     5

struct multiboot_header {
  uint32_t flags;
	uint32_t mem_lower;
	uint32_t mem_upper;
	uint32_t boot_device;
	uint32_t cmdline;
	uint32_t mods_count;
	uint32_t mods_addr;
	uint32_t num;
	uint32_t size;
	uint32_t addr;
	uint32_t shndx;
	uint32_t mmap_length;
	uint32_t mmap_addr;
	uint32_t drives_length;
	uint32_t drives_addr;
	uint32_t config_table;
	uint32_t boot_loader_name;
	uint32_t apm_table;
	uint32_t vbe_control_info;
	uint32_t vbe_mode_info;
	uint32_t vbe_mode;
	uint32_t vbe_interface_seg;
	uint32_t vbe_interface_off;
	uint32_t vbe_interface_len;
} __attribute__ ((packed));

typedef struct {
	uint16_t attributes;
	uint8_t  winA, winB;
	uint16_t granularity;
	uint16_t winsize;
	uint16_t segmentA, segmentB;
	uint32_t realFctPtr;
	uint16_t pitch;

	uint16_t Xres, Yres;
	uint8_t  Wchar, Ychar, planes, bpp, banks;
	uint8_t  memory_model, bank_size, image_pages;
	uint8_t  reserved0;

	uint8_t  red_mask, red_position;
	uint8_t  green_mask, green_position;
	uint8_t  blue_mask, blue_position;
	uint8_t  rsv_mask, rsv_position;
	uint8_t  directcolor_attributes;

	uint32_t physbase;
	uint32_t reserved1;
	uint16_t reserved2;
} __attribute__ ((packed)) vbe_info_t;

typedef struct {
	uint32_t size;
	uint64_t base_addr;
	uint64_t length;
	uint32_t type;
} __attribute__ ((packed)) mboot_memmap_t;

Re: GRUB memory map

Posted: Tue Aug 16, 2016 8:36 am
by michaellangford
---I think I see what you mean. I just memcpy the entire map directly into my array. I know the GRUB2 specs say that it is possible for a map entry to be a different size, but in my experience, it's impossible. The offset of 4 only matters to you if you are going through each entry one by one. I don't know how I would go about doing that - Like I said, I just copy the whole thing directly into an array.

Re: GRUB memory map

Posted: Tue Aug 16, 2016 2:29 pm
by BringerOfShadows
but how do you get the number of entries. when I try, I keep getting an error saying that the size of the array is not constant. for the record, I am using c++.
here's my code:

Code: Select all

mmap_t *getmmap(multiboot_info_t* mbt)
{
	uint32_t i = 0;						// initialize an iterator for the memory map array
	mmap_t *mmap = (mmap_t *)mbt->mmap_addr;				// initialize a memory map structure pointer and point it at the memory map
	static mmap_t memMap[mbt->length/sizeof(mmap_t)];				// initialize a memory map container array with enough entries for the memory map.	
	uint32_t MapLim = mbt->mmap_addr + mbt->mmap_length;	// defines the limit of the memory map
	while((uint32_t)mmap < MapLim)					// loop until we reach the end of the memory map
	{
		memMap[i].size = mmap->size;
		memMap[i].addr = mmap->addr;
		memMap[i].len = mmap->len;
		memMap[i].type = mmap->type;			// fill the entry in memMap with the contents of mmap
		i++;						// increment the iterator
		mmap = (mmap_t *)
			((uint32_t)mmap + mmap->size +
			sizeof(uint32_t));			// increment the memory map to the next entry.
	}
	return (mmap_t*)&memMap;					// returns the memory map.
}
I had to initialize the array to only 20 entries just to compile it.
the memcpy idea works well though. I'll have to adopt that.

Re: GRUB memory map

Posted: Tue Aug 16, 2016 3:59 pm
by Boris
Please do not return references to things declared in a function.
Your error is simple: you cannot statically allocate something which size is dynamically known. You have no choice : declare a global map storage somewhere and make it big enough for all the entries.

Re: GRUB memory map

Posted: Tue Aug 16, 2016 8:49 pm
by BringerOfShadows
got it to work. declared the memory map array in main and passed a pointer to it.\

edit: I took a picture of my memory map output that was printed to screen and attached it below.
This was done on an x86 dell laptop that's about 7-8 years old.
can anyone tell me if my memory map is sane, and/or what to do about the overlapping areas?

Image

Re: GRUB memory map

Posted: Wed Aug 17, 2016 1:31 am
by Octocontrabass
That memory map doesn't look sane. Are you sure you're displaying the right number of entries? Can you verify it against something else (e.g. Linux dmesg)?

Once you have a sane memory map, you may still have overlaps. Overlapping areas of the memory map should be counted as whichever memory type is the most restrictive. For example, when type 1 (usable) and type 2 (reserved by hardware) overlap, the overlapping area should be counted as type 2.

Re: GRUB memory map

Posted: Thu Aug 18, 2016 10:25 am
by michaellangford
BringerOfShadows wrote:but how do you get the number of entries. when I try, I keep getting an error saying that the size of the array is not constant.
I get the number of entries from the multiboot header, and then declare the array locally, later, when you have a memory manager, you can allocate space for a permanent container. Hope that helps!

Re: GRUB memory map

Posted: Thu Aug 18, 2016 10:23 pm
by BringerOfShadows
How did you get the number of entries from the multiboot header? Where is that?

Re: GRUB memory map

Posted: Fri Aug 19, 2016 12:54 am
by Octacone
BringerOfShadows wrote:How did you get the number of entries from the multiboot header? Where is that?
If you want to get the number of entries just count the by hand. You cannot code that because you don't know if the compiler is going the add some padding or not. Why would you want to do that anyways? Just let GRUB parse the information to your structure instance and then get information from that instance. Like for example: "mboot->mem_upper", etc...

Re: GRUB memory map

Posted: Fri Aug 19, 2016 2:12 am
by Octocontrabass
BringerOfShadows wrote:How did you get the number of entries from the multiboot header? Where is that?
It's not in the multiboot header. GRUB only tells you how big the memory map is, not how many entries there are.
octacone wrote:Like for example: "mboot->mem_upper", etc...
You need the memory map to find all available RAM. This only reports contiguous RAM above 1MB, which can be a lot less than the total.