/* Support for Multiboot */ #include "config.h" #include "asm/io.h" #include "libopenbios/sys_info.h" #include "multiboot.h" #define printf printk #ifdef CONFIG_DEBUG_BOOT #define debug printk #else #define debug(x...) #endif struct mbheader { unsigned int magic, flags, checksum; }; const struct mbheader multiboot_header __attribute__((section (".hdr"))) = { MULTIBOOT_HEADER_MAGIC, MULTIBOOT_HEADER_FLAGS, -(MULTIBOOT_HEADER_MAGIC + MULTIBOOT_HEADER_FLAGS) }; /* Multiboot information structure, provided by loader to us */ struct multiboot_mmap { unsigned entry_size; unsigned base_lo, base_hi; unsigned size_lo, size_hi; unsigned type; }; #define MULTIBOOT_MEM_VALID 0x01 #define MULTIBOOT_BOOT_DEV_VALID 0x02 #define MULTIBOOT_CMDLINE_VALID 0x04 #define MULTIBOOT_MODS_VALID 0x08 #define MULTIBOOT_AOUT_SYMS_VALID 0x10 #define MULTIBOOT_ELF_SYMS_VALID 0x20 #define MULTIBOOT_MMAP_VALID 0x40 void collect_multiboot_info(struct sys_info *info); void collect_multiboot_info(struct sys_info *info) { struct multiboot_info *mbinfo; struct multiboot_mmap *mbmem; unsigned mbcount, mbaddr; unsigned int i; struct memrange *mmap; int mmap_count; module_t *mod; if (info->boot_type != 0x2BADB002) return; debug("Using Multiboot information at %#lx\n", info->boot_data); mbinfo = phys_to_virt(info->boot_data); if (mbinfo->mods_count != 1) { printf("Multiboot: no dictionary\n"); return; } mod = (module_t *) mbinfo->mods_addr; info->dict_start=(unsigned long *)mod->mod_start; info->dict_end=(unsigned long *)mod->mod_end; if (mbinfo->flags & MULTIBOOT_MMAP_VALID) { /* convert mmap records */ mbmem = phys_to_virt(mbinfo->mmap_addr); mbcount = mbinfo->mmap_length / (mbmem->entry_size + 4); mmap = malloc(mbcount * sizeof(struct memrange)); mmap_count = 0; mbaddr = mbinfo->mmap_addr; for (i = 0; i < mbcount; i++) { mbmem = phys_to_virt(mbaddr); debug("%08x%08x %08x%08x (%d)\n", mbmem->base_hi, mbmem->base_lo, mbmem->size_hi, mbmem->size_lo, mbmem->type); if (mbmem->type == 1) { /* Only normal RAM */ mmap[mmap_count].base = mbmem->base_lo + (((unsigned long long) mbmem->base_hi) << 32); mmap[mmap_count].size = mbmem->size_lo + (((unsigned long long) mbmem->size_hi) << 32); mmap_count++; } mbaddr += mbmem->entry_size + 4; if (mbaddr >= mbinfo->mmap_addr + mbinfo->mmap_length) break; } /* simple sanity check - there should be at least 2 RAM segments * (base 640k and extended) */ if (mmap_count >= 2) goto got_it; printf("Multiboot mmap is broken\n"); free(mmap); /* fall back to mem_lower/mem_upper */ } if (mbinfo->flags & MULTIBOOT_MEM_VALID) { /* use mem_lower and mem_upper */ mmap_count = 2; mmap = malloc(2 * sizeof(*mmap)); mmap[0].base = 0; mmap[0].size = mbinfo->mem_lower << 10; mmap[1].base = 1 << 20; /* 1MB */ mmap[1].size = mbinfo->mem_upper << 10; goto got_it; } printf("Can't get memory information from Multiboot\n"); return; got_it: info->memrange = mmap; info->n_memranges = mmap_count; return; }