176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman/* ----------------------------------------------------------------------- * 276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * 376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * Copyright 2007-2008 H. Peter Anvin - All Rights Reserved 476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * Copyright 2009-2010 Intel Corporation; author: H. Peter Anvin 576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * 676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * Permission is hereby granted, free of charge, to any person 776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * obtaining a copy of this software and associated documentation 876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * files (the "Software"), to deal in the Software without 976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * restriction, including without limitation the rights to use, 1076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * copy, modify, merge, publish, distribute, sublicense, and/or 1176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * sell copies of the Software, and to permit persons to whom 1276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * the Software is furnished to do so, subject to the following 1376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * conditions: 1476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * 1576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * The above copyright notice and this permission notice shall 1676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * be included in all copies or substantial portions of the Software. 1776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * 1876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 1976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES 2076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 2176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT 2276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, 2376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 2476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR 2576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * OTHER DEALINGS IN THE SOFTWARE. 2676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * 2776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * ----------------------------------------------------------------------- */ 2876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 2976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman/* 3076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * map.c 3176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * 3276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * Functions that deal with the memory map of various objects 3376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman */ 3476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 3576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman#include "mboot.h" 3676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 3776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartmanstatic struct syslinux_movelist *ml = NULL; 3876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartmanstatic struct syslinux_memmap *mmap = NULL, *amap = NULL; 3976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartmanstatic addr_t mboot_high_water_mark = 0x100000; 4076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 4176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman/* 4276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * Note: although there is no such thing in the spec, at least Xen makes 4376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * assumptions as to where in the memory space Grub would have loaded 4476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * certain things. To support that, if "high" is set, then allocate this 4576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * at an address strictly above any previous allocations. 4676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * 4776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * As a precaution, this also pads the data with zero up to the next 4876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * alignment datum. 4976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman */ 5076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartmanaddr_t map_data(const void *data, size_t len, size_t align, int flags) 5176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman{ 5276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman addr_t start = (flags & MAP_HIGH) ? mboot_high_water_mark : 0x2000; 5376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman addr_t pad = (flags & MAP_NOPAD) ? 0 : -len & (align - 1); 5476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman addr_t xlen = len + pad; 5576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 5676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman if (syslinux_memmap_find_type(amap, SMT_FREE, &start, &xlen, align) || 5776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman syslinux_add_memmap(&amap, start, len + pad, SMT_ALLOC) || 5876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman syslinux_add_movelist(&ml, start, (addr_t) data, len) || 5976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman (pad && syslinux_add_memmap(&mmap, start + len, pad, SMT_ZERO))) { 6076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman printf("Cannot map %zu bytes\n", len + pad); 6176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman return 0; 6276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman } 6376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 6476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman dprintf("Mapping 0x%08x bytes (%#x pad) at 0x%08x\n", len, pad, start); 6576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 6676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman if (start + len + pad > mboot_high_water_mark) 6776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman mboot_high_water_mark = start + len + pad; 6876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 6976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman return start; 7076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman} 7176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 7276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartmanaddr_t map_string(const char *string) 7376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman{ 7476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman if (!string) 7576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman return 0; 7676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman else 7776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman return map_data(string, strlen(string) + 1, 1, 0); 7876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman} 7976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 8076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartmanint init_map(void) 8176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman{ 8276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman /* 8376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * Note: mmap is the memory map (containing free and zeroed regions) 8476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * needed by syslinux_shuffle_boot_pm(); amap is a map where we keep 8576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * track ourselves which target memory ranges have already been 8676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * allocated. 8776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman */ 8876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman mmap = syslinux_memory_map(); 8976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman amap = syslinux_dup_memmap(mmap); 9076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman if (!mmap || !amap) { 9176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman error("Failed to allocate initial memory map!\n"); 9276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman return -1; 9376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman } 9476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 9576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman dprintf("Initial memory map:\n"); 9676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman syslinux_dump_memmap(mmap); 9776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 9876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman return 0; 9976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman} 10076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 10176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartmanstruct multiboot_header *map_image(void *ptr, size_t len) 10276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman{ 10376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman struct multiboot_header *mbh; 10476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman int mbh_len; 10576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman char *cptr = ptr; 10676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman Elf32_Ehdr *eh = ptr; 10776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman Elf32_Phdr *ph; 10876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman Elf32_Shdr *sh; 10976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman unsigned int i, mbh_offset; 11076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman uint32_t bad_flags; 11176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 11276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman /* 11376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * Search for the multiboot header... 11476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman */ 11576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman mbh_len = 0; 11676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman for (mbh_offset = 0; mbh_offset < MULTIBOOT_SEARCH; mbh_offset += 4) { 11776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman mbh = (struct multiboot_header *)((char *)ptr + mbh_offset); 11876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman if (mbh->magic != MULTIBOOT_MAGIC) 11976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman continue; 12076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman if (mbh->magic + mbh->flags + mbh->checksum) 12176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman continue; 12276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman if (mbh->flags & MULTIBOOT_VIDEO_MODE) 12376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman mbh_len = 48; 12476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman else if (mbh->flags & MULTIBOOT_AOUT_KLUDGE) 12576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman mbh_len = 32; 12676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman else 12776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman mbh_len = 12; 12876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 12976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman if (mbh_offset + mbh_len > len) 13076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman mbh_len = 0; /* Invalid... */ 13176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman else 13276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman break; /* Found something... */ 13376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman } 13476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 13576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman if (mbh_len) { 13676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman bad_flags = mbh->flags & MULTIBOOT_UNSUPPORTED; 13776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman if (bad_flags) { 13876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman printf("Unsupported Multiboot flags set: %#x\n", bad_flags); 13976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman return NULL; 14076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman } 14176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman } 14276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 14376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman if (len < sizeof(Elf32_Ehdr) || 14476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman memcmp(eh->e_ident, "\x7f" "ELF\1\1\1", 6) || 14576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman (eh->e_machine != EM_386 && eh->e_machine != EM_486 && 14676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman eh->e_machine != EM_X86_64) || 14776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman eh->e_version != EV_CURRENT || 14876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman eh->e_ehsize < sizeof(Elf32_Ehdr) || eh->e_ehsize >= len || 14976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman eh->e_phentsize < sizeof(Elf32_Phdr) || 15076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman !eh->e_phnum || eh->e_phoff + eh->e_phentsize * eh->e_phnum > len) 15176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman eh = NULL; /* No valid ELF header found */ 15276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 15376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman /* Is this a Solaris kernel? */ 15476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman if (!set.solaris && eh && kernel_is_solaris(eh)) 15576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman opt.solaris = true; 15676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 15776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman /* 15876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * Note: the Multiboot Specification implies that AOUT_KLUDGE should 15976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * have precedence over the ELF header. However, Grub disagrees, and 16076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * Grub is "the reference bootloader" for the Multiboot Specification. 16176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * This is insane, since it makes the AOUT_KLUDGE bit functionally 16276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * useless, but at least Solaris apparently depends on this behavior. 16376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman */ 16476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman if (eh && !(opt.aout && mbh_len && (mbh->flags & MULTIBOOT_AOUT_KLUDGE))) { 16576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman regs.eip = eh->e_entry; /* Can be overridden further down... */ 16676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 16776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman ph = (Elf32_Phdr *) (cptr + eh->e_phoff); 16876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 16976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman for (i = 0; i < eh->e_phnum; i++) { 17076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman if (ph->p_type == PT_LOAD || ph->p_type == PT_PHDR) { 17176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman /* 17276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * This loads at p_paddr, which matches Grub. However, if 17376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * e_entry falls within the p_vaddr range of this PHDR, then 17476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * adjust it to match the p_paddr range... this is how Grub 17576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * behaves, so it's by definition correct (it doesn't have to 17676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * make sense...) 17776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman */ 17876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman addr_t addr = ph->p_paddr; 17976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman addr_t msize = ph->p_memsz; 18076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman addr_t dsize = min(msize, ph->p_filesz); 18176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 18276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman if (eh->e_entry >= ph->p_vaddr 18376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman && eh->e_entry < ph->p_vaddr + msize) 18476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman regs.eip = eh->e_entry + (ph->p_paddr - ph->p_vaddr); 18576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 18676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman dprintf("Segment at 0x%08x data 0x%08x len 0x%08x\n", 18776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman addr, dsize, msize); 18876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 18976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman if (syslinux_memmap_type(amap, addr, msize) != SMT_FREE) { 19076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman printf 19176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman ("Memory segment at 0x%08x (len 0x%08x) is unavailable\n", 19276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman addr, msize); 19376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman return NULL; /* Memory region unavailable */ 19476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman } 19576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 19676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman /* Mark this region as allocated in the available map */ 19776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman if (syslinux_add_memmap(&amap, addr, msize, SMT_ALLOC)) { 19876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman error("Overlapping segments found in ELF header\n"); 19976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman return NULL; 20076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman } 20176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 20276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman if (ph->p_filesz) { 20376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman /* Data present region. Create a move entry for it. */ 20476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman if (syslinux_add_movelist 20576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman (&ml, addr, (addr_t) cptr + ph->p_offset, dsize)) { 20676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman error("Failed to map PHDR data\n"); 20776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman return NULL; 20876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman } 20976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman } 21076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman if (msize > dsize) { 21176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman /* Zero-filled region. Mark as a zero region in the memory map. */ 21276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman if (syslinux_add_memmap 21376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman (&mmap, addr + dsize, msize - dsize, SMT_ZERO)) { 21476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman error("Failed to map PHDR zero region\n"); 21576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman return NULL; 21676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman } 21776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman } 21876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman if (addr + msize > mboot_high_water_mark) 21976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman mboot_high_water_mark = addr + msize; 22076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman } else { 22176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman /* Ignore this program header */ 22276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman } 22376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 22476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman ph = (Elf32_Phdr *) ((char *)ph + eh->e_phentsize); 22576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman } 22676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 22776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman /* Load the ELF symbol table */ 22876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman if (eh->e_shoff) { 22976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman addr_t addr, len; 23076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 23176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman sh = (Elf32_Shdr *) ((char *)eh + eh->e_shoff); 23276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 23376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman len = eh->e_shentsize * eh->e_shnum; 23476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman /* 23576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * Align this, but don't pad -- in general this means a bunch of 23676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * smaller sections gets packed into a single page. 23776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman */ 23876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman addr = map_data(sh, len, 4096, MAP_HIGH | MAP_NOPAD); 23976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman if (!addr) { 24076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman error("Failed to map symbol table\n"); 24176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman return NULL; 24276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman } 24376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 24476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman mbinfo.flags |= MB_INFO_ELF_SHDR; 24576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman mbinfo.syms.e.addr = addr; 24676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman mbinfo.syms.e.num = eh->e_shnum; 24776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman mbinfo.syms.e.size = eh->e_shentsize; 24876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman mbinfo.syms.e.shndx = eh->e_shstrndx; 24976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 25076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman for (i = 0; i < eh->e_shnum; i++) { 25176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman addr_t align; 25276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 25376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman if (!sh[i].sh_size) 25476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman continue; /* Empty section */ 25576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman if (sh[i].sh_flags & SHF_ALLOC) 25676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman continue; /* SHF_ALLOC sections should have PHDRs */ 25776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 25876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman align = sh[i].sh_addralign ? sh[i].sh_addralign : 0; 25976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman addr = map_data((char *)ptr + sh[i].sh_offset, sh[i].sh_size, 26076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman align, MAP_HIGH); 26176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman if (!addr) { 26276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman error("Failed to map symbol section\n"); 26376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman return NULL; 26476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman } 26576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman sh[i].sh_addr = addr; 26676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman } 26776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman } 26876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman } else if (mbh_len && (mbh->flags & MULTIBOOT_AOUT_KLUDGE)) { 26976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman /* 27076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * a.out kludge thing... 27176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman */ 27276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman char *data_ptr; 27376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman addr_t data_len, bss_len; 27476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman addr_t bss_addr; 27576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 27676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman regs.eip = mbh->entry_addr; 27776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 27876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman data_ptr = (char *)mbh - (mbh->header_addr - mbh->load_addr); 27976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 28076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman if (mbh->load_end_addr) 28176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman data_len = mbh->load_end_addr - mbh->load_addr; 28276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman else 28376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman data_len = len - mbh_offset + (mbh->header_addr - mbh->load_addr); 28476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 28576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman bss_addr = mbh->load_addr + data_len; 28676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 28776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman if (mbh->bss_end_addr) 28876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman bss_len = mbh->bss_end_addr - mbh->load_end_addr; 28976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman else 29076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman bss_len = 0; 29176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 29276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman if (syslinux_memmap_type(amap, mbh->load_addr, data_len + bss_len) 29376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman != SMT_FREE) { 29476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman printf("Memory segment at 0x%08x (len 0x%08x) is unavailable\n", 29576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman mbh->load_addr, data_len + bss_len); 29676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman return NULL; /* Memory region unavailable */ 29776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman } 29876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman if (syslinux_add_memmap(&amap, mbh->load_addr, 29976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman data_len + bss_len, SMT_ALLOC)) { 30076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman error("Failed to claim a.out address space!\n"); 30176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman return NULL; 30276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman } 30376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman if (data_len) 30476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman if (syslinux_add_movelist(&ml, mbh->load_addr, (addr_t) data_ptr, 30576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman data_len)) { 30676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman error("Failed to map a.out data\n"); 30776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman return NULL; 30876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman } 30976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman if (bss_len) 31076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman if (syslinux_add_memmap 31176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman (&mmap, bss_addr, bss_len, SMT_ZERO)) { 31276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman error("Failed to map a.out bss\n"); 31376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman return NULL; 31476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman } 31576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman if (bss_addr + bss_len > mboot_high_water_mark) 31676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman mboot_high_water_mark = bss_addr + bss_len; 31776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman } else { 31876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman error 31976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman ("Invalid Multiboot image: neither ELF header nor a.out kludge found\n"); 32076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman return NULL; 32176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman } 32276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 32376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman return mbh; 32476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman} 32576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 32676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman/* 32776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * Set up a stack. This isn't actually required by the spec, but it seems 32876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * like a prudent thing to do. Also, put enough zeros at the top of the 32976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * stack that something that looks for an ELF invocation record will know 33076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * there isn't one. 33176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman */ 33276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartmanstatic void mboot_map_stack(void) 33376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman{ 33476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman addr_t start, len; 33576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 33676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman if (syslinux_memmap_largest(amap, SMT_FREE, &start, &len) || len < 64) 33776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman return; /* Not much we can do, here... */ 33876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 33976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman regs.esp = (start + len - 32) & ~15; 34076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman dprintf("Mapping stack at 0x%08x\n", regs.esp); 34176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman syslinux_add_memmap(&mmap, regs.esp, 32, SMT_ZERO); 34276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman} 34376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 34476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartmanvoid mboot_run(int bootflags) 34576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman{ 34676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman mboot_map_stack(); 34776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 34876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman dprintf("Running, eip = 0x%08x, ebx = 0x%08x\n", regs.eip, regs.ebx); 34976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 35076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman regs.eax = MULTIBOOT_VALID; 35176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman syslinux_shuffle_boot_pm(ml, mmap, bootflags, ®s); 35276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman} 353