Page 1 of 1

[SOLVED] Using memory map to calculate size of system RAM

Posted: Thu Dec 03, 2020 1:02 pm
by austanss
I wrote a function to parse my memory map, namely to print to serial output the contents, and return the size of system RAM in bytes.

Code: Select all

// @brief Parses the memory map and returns the amount of RAM in the system.
uint64_t mem_map_parse(Memory_Map_Descriptor* memmap, uint64_t map_size, uint64_t desc_size)
{
	uint8_t *startOfMemoryMap = (uint8_t *)memmap;
	uint8_t *endOfMemoryMap = startOfMemoryMap + map_size;

	uint8_t *offset = startOfMemoryMap;

	uint32_t counter = 0;
 	serial_msg("\n\nMEMORY MAP:\n-=-=-=-=-=-\n");

	while (offset < endOfMemoryMap)
	{
		Memory_Map_Descriptor *desc = (Memory_Map_Descriptor *)offset;

		hex_str_serial(desc->physical_start);
		serial_msg(": ");
		serial_msg(memory_types[desc->type]);
		serial_msg(" (");
		dec_str_serial(desc->count);
		serial_msg(")");
		serial_msg("\n");

		offset += desc_size;

		counter++;
	}

	offset -= desc_size;

	Memory_Map_Descriptor *desc = (Memory_Map_Descriptor *)offset;

	hex_str_serial(desc->physical_start);
	serial_msg(": ");
	serial_msg(memory_types[desc->type]);
	serial_msg(" (");
	dec_str_serial(desc->count);
	serial_msg(")");
	serial_msg("\n");

	return (((uint64_t)desc->physical_start) + ((desc->count * 0x1000)));
}
Aight so I have a function calling that function:

Code: Select all

void malloc_init(Memory_Map_Descriptor* memmap, uint64_t map_size, uint64_t desc_size)
{
	serial_msg("\n");
	dec_str_serial(((mem_map_parse(memmap, map_size, desc_size)) / 1024) / 1024);
	serial_msg("MiB of RAM\n");
}
And it prints:

Code: Select all

5120MiB of RAM
However, it should state that i have 4096MiB, as I am allocating 4GiB to QEMU.
I try allocating 6GiB:

Code: Select all

7168MiB of RAM
I know it has to be a mathematical error, as my memory map is correct...

Forgive me if I am overlooking something, I am taking 8th grade pre-algebra at the moment...

...though this shouldn't be too complicated.

Re: Using memory map to calculate size of system RAM

Posted: Thu Dec 03, 2020 3:24 pm
by feryno
there is a "hole" below 4 GB for firmware, APIC, video frame buffer etc so the RAM is not contiguous, part of RAM somewhere like 0-3GB, then the hole for hardware like 3-4 GB, then the rest of RAM starts from 4 GB

Re: Using memory map to calculate size of system RAM

Posted: Thu Dec 03, 2020 3:42 pm
by Octocontrabass
Memory is not guaranteed to be one contiguous block. Memory is not guaranteed to start from physical address 0 (although it usually does on x86 systems). The memory map is not guaranteed to be sorted in any particular order.

If you want to know how much memory there is, you have to add up all of the memory map entries that indicate memory.

Re: Using memory map to calculate size of system RAM

Posted: Thu Dec 03, 2020 4:04 pm
by austanss
so do I count
"EfiUnusableMemory"
"EfiACPIReclaimMemory"
"EfiACPIMemoryNVS"
towards the total memory count or no?

Re: Using memory map to calculate size of system RAM

Posted: Thu Dec 03, 2020 4:09 pm
by zaval
here is an example of counting number of usable RAM size in UEFI pages (4KB)

Code: Select all

UINTN GetUsableRamSizeInPages(EFI_MEMORY_DESCRIPTOR *MemoryMap, UINTN NumberOfElements, UINTN ReportedDescriptorSize){
	UINTN	Nop;
	INTN	i, Type;
	EFI_MEMORY_DESCRIPTOR *Desc;

	Nop = 0;
	for(i = 0, Desc = MemoryMap; i < NumberOfElements; i++){
		Type = Desc->Type;
		if(Type == EfiConventionalMemory
			|| Type == EfiLoaderCode || Type == EfiLoaderData
			|| Type == EfiBootServicesCode || Type == BootServicesData
		){
			Nop += Desc->NumberOfPages;
		}
		Desc = (EFI_MEMORY_DESCRIPTOR *)((UINT8 *)Desc + ReportedDescriptorSize);
	}

	return Nop;
}
Depending on when you want to call this calculation, you also might want to add memory of the type EfiACPIReclaimMemory, in case, you've dealt with ACPI as per the spec. Also, if you use your own private OSL types, you need to add them too.

Edit: I totally forgot about the moronic tendency for the reported by FW descriptor size often be larger, than than the descriptor structure (with paddings incl), for example, it's often reported to be 48 bytes instead of 40 - yet some 8 bytes got added behind the descriptor in every entry. fixed the example.

Re: Using memory map to calculate size of system RAM

Posted: Thu Dec 03, 2020 4:25 pm
by austanss
I haven't dealt with ACPI.

This is my code:

Code: Select all

uint64_t mem_map_parse(Memory_Map_Descriptor* memmap, uint64_t map_size, uint64_t desc_size)
{
	uint8_t *startOfMemoryMap = (uint8_t *)memmap;
	uint8_t *endOfMemoryMap = startOfMemoryMap + map_size;

	uint8_t *offset = startOfMemoryMap;

	uint64_t pages;

	uint32_t counter = 0;
 	serial_msg("\n\nMEMORY MAP:\n-=-=-=-=-=-\n");

	while (offset < endOfMemoryMap)
	{
		Memory_Map_Descriptor *desc = (Memory_Map_Descriptor *)offset;

		if   (desc->type == 0x07
		   || desc->type == 0x01 || desc->type == 0x02
		   || desc->type == 0x04 || desc->type == 0x05)
			pages += desc->count;

		hex_str_serial(desc->physical_start);
		serial_msg(": ");
		serial_msg(memory_types[desc->type]);
		serial_msg(" (");
		dec_str_serial(desc->count);
		serial_msg(")");
		serial_msg("\n");

		offset += desc_size;

		counter++;
	}

	offset -= desc_size;

	Memory_Map_Descriptor *desc = (Memory_Map_Descriptor *)offset;

	hex_str_serial(desc->physical_start);
	serial_msg(": ");
	serial_msg(memory_types[desc->type]);
	serial_msg(" (");
	dec_str_serial(desc->count);
	serial_msg(")");
	serial_msg("\n");

	return pages * 0x1000;
}
And it states that I have 12504056MiB of RAM... I allocated 6GB...

Re: Using memory map to calculate size of system RAM

Posted: Thu Dec 03, 2020 4:36 pm
by zaval
your pages variable isn't initialized before the loop. also, you forgot to add pages in that block after the loop. why you have that at all?

Re: Using memory map to calculate size of system RAM

Posted: Thu Dec 03, 2020 4:37 pm
by Octocontrabass
rizxt wrote:so do I count
"EfiUnusableMemory"
"EfiACPIReclaimMemory"
"EfiACPIMemoryNVS"
towards the total memory count or no?
Memory that is not usable to your OS may not be memory at all, so I'd only count usable memory. The UEFI specification should tell you which of those are usable.

Re: Using memory map to calculate size of system RAM

Posted: Thu Dec 03, 2020 5:14 pm
by austanss
zaval wrote:your pages variable isn't initialized before the loop. also, you forgot to add pages in that block after the loop. why you have that at all?
that was debug.

Re: Using memory map to calculate size of system RAM

Posted: Thu Dec 03, 2020 5:16 pm
by austanss
thanks for that it's printing out values with operable accuracy. solved.