For reference (and because that offset of -4 threw me off), this is my code for that. Hope it helps:
Code: Select all
struct mbinfo {
uint32_t flags,
mem_lower,
mem_upper,
boot_device,
cmdline,
mods_count,
mods_addr,
syms[4],
mmap_length,
mmap_addr,
drives_length,
drives_addr,
config_table,
bootloader_name,
apm_table,
vbe_control_info,
vbe_mode_info;
uint16_t vbe_mode,
vbe_interface_seg,
vbe_interface_off,
vbe_interface_len;
uint64_t framebuffer_addr;
uint32_t framebuffer_pitch,
framebuffer_width,
framebuffer_height;
uint8_t framebuffer_bpp,
framebuffer_type,
color_info[6];
};
struct mbmmap {
uint32_t size;
uint32_t addr[2], len[2];
uint8_t type;
};
static void print_mem_info(unsigned len_mmap, const struct mbmmap *mmap, uint64_t *maxram)
{
const unsigned char *const start = (void*)mmap;
uint64_t mr = 0;
while ((const unsigned char*)mmap - start < len_mmap)
{
uint64_t addr, len;
addr = (uint64_t)mmap->addr[1] << 32 | mmap->addr[0];
len = (uint64_t)mmap->len[1] << 32 | mmap->len[0];
if (mmap->type == 1 && addr + len > mr)
mr = addr + len;
dbg_printf("%8X-%8X type %d\n", addr, addr + len, mmap->type);
if (addr < 0x100000000)
{
if (addr + len > 0x100000000)
len = 0x100000000 - addr;
if (mmap->type == 1)
add_avail_range(addr, len);
else
add_reserved_range(addr, len);
}
mmap = (const void*)((const unsigned char*)mmap + mmap->size + 4);
}
*maxram = mr;
}
void mbmain(uint32_t mbmagic, const struct mbinfo *bootinfo)
{
[...]
if (bootinfo->flags & 64)
print_mem_info(bootinfo->mmap_length, (const void*)bootinfo->mmap_addr, &maxram);
}
So the "mmap_addr" in the multiboot info points immediately to a length. And afterwards all memory maps are offset by a further four bytes. And since now everything is misaligned, I have to break the 64-bit members down into two 32-bit members, else the compiler would insert padding. Yes, I am aware of __attribute__((packed)) and I choose not to use such a crutch. And so far it is working out.