blob: b1e8a33a22d6e09f3615017f51046d268e35c39a [file] [log] [blame]
/* Copyright (c) 2009,13 The Regents of the University of California
* Barret Rhoden <brho@cs.berkeley.edu>
* Kevin Klues <klueska@cs.berkeley.edu>
* See LICENSE for details.
*
* Multiboot parsing and helper functions. */
#include <multiboot.h>
#include <ros/common.h>
#include <arch/mmu.h>
#include <arch/arch.h>
#include <ros/memlayout.h>
#include <stdio.h>
#include <pmap.h>
#ifdef CONFIG_X86
#include <arch/apic.h>
#endif
/* Misc dead code to read from mboot. We'll need to do this to run a legit
* initrd from grub (module /initramfs.cpio, or whatever). */
static void mboot_parsing(struct multiboot_info *mbi)
{
if (mbi->flags & MULTIBOOT_INFO_BOOTDEV)
printk("MBI: boot_device = 0x%08x\n", mbi->boot_device);
if (mbi->flags & MULTIBOOT_INFO_CMDLINE)
printk("MBI: command line: %s\n",
(char*)((physaddr_t)mbi->cmdline + KERNBASE));
if (mbi->flags & MULTIBOOT_INFO_MODS) {
printk("MBI: nr mods, %d: mods addr %p\n", mbi->mods_count,
mbi->mods_addr);
}
}
bool mboot_has_mmaps(struct multiboot_info *mbi)
{
return mbi->flags & MULTIBOOT_INFO_MEM_MAP;
}
/* This only notices bios detectable memory - there's a lot more in the higher
* paddrs. */
void mboot_detect_memory(struct multiboot_info *mbi)
{
physaddr_t max_bios_mem;
physaddr_t max_bios_addr;
size_t basemem;
size_t extmem;
if (!(mbi->flags & MULTIBOOT_INFO_MEMORY)) {
printk("No BIOS memory info from multiboot, crash impending\n");
return;
}
/* mem_lower and upper are measured in KB. They are 32 bit values, so
* we're limited to 4TB total. */
basemem = ROUNDDOWN((size_t)mbi->mem_lower * 1024, PGSIZE);
/* On 32 bit, This shift << 10 could cause us to lose some memory, but
* we weren't going to access it anyways (won't go beyond ~1GB) */
extmem = ROUNDDOWN((size_t)mbi->mem_upper * 1024, PGSIZE);
/* Calculate the maximum physical address based on whether or not there
* is any extended memory. */
if (extmem) {
max_bios_mem = EXTPHYSMEM + extmem;
/* On 32 bit, if we had enough RAM that adding a little wrapped
* us around, we'll back off a little and run with just extmem
* amount (in essence, subtracing 1MB). */
if (max_bios_mem < extmem)
max_bios_mem = extmem;
} else {
max_bios_mem = basemem;
}
max_bios_addr = MIN(max_bios_mem, KERN_VMAP_TOP - KERNBASE);
printk("Base memory: %luK, Extended memory: %luK\n", basemem / 1024,
extmem / 1024);
printk("Maximum directly addressable base and extended memory: %luK\n",
max_bios_addr / 1024);
/* Take a first stab at the max pmem, in case there are no memory
* mappings (like in riscv) */
max_pmem = max_bios_mem;
}
void mboot_foreach_mmap(struct multiboot_info *mbi, mboot_foreach_t func,
void *data)
{
struct multiboot_mmap_entry *mmap_b, *mmap_e, *mmap_i;
if (!mboot_has_mmaps(mbi)) {
printd("No memory mapping info from multiboot\n");
return;
}
mmap_b = (struct multiboot_mmap_entry*)((size_t)mbi->mmap_addr +
KERNBASE);
mmap_e = (struct multiboot_mmap_entry*)((size_t)mbi->mmap_addr +
KERNBASE + mbi->mmap_length);
printd("mmap_addr = %p, mmap_length = %p\n", mbi->mmap_addr,
mbi->mmap_length);
/* Note when we incremement mmap_i, we add in the value of size... */
for (mmap_i = mmap_b;
mmap_i < mmap_e;
mmap_i = (struct multiboot_mmap_entry*)((void*)mmap_i +
mmap_i->size +
sizeof(mmap_i->size))) {
func(mmap_i, data);
}
}
void mboot_print_mmap(struct multiboot_info *mbi)
{
void print_entry(struct multiboot_mmap_entry *entry, void *data)
{
printk("Base = 0x%016llx, Length = 0x%016llx : %s\n",
entry->addr, entry->len,
entry->type == MULTIBOOT_MEMORY_AVAILABLE ? "FREE" :
"RESERVED");
}
mboot_foreach_mmap(mbi, print_entry, 0);
}
/* Given a range of memory, will tell us if multiboot is using anything we care
* about in that range. It usually uses memory below 1MB, so boot_alloc is
* fine. This is pre, so MBI is still a paddr. */
bool mboot_region_collides(struct multiboot_info *mbi, uintptr_t base,
uintptr_t end)
{
if (regions_collide_unsafe((uintptr_t)mbi, (uintptr_t)mbi +
sizeof(struct multiboot_info), base, end))
return TRUE;
if (mboot_has_mmaps(mbi)) {
if (regions_collide_unsafe((uintptr_t)mbi->mmap_addr + KERNBASE,
(uintptr_t)mbi->mmap_addr + KERNBASE
+ mbi->mmap_length, base, end))
return TRUE;
}
return FALSE;
}