| /* 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; | 
 | } |