diff options
Diffstat (limited to 'contrib/syslinux-4.02/com32/mboot')
| -rw-r--r-- | contrib/syslinux-4.02/com32/mboot/Makefile | 46 | ||||
| -rw-r--r-- | contrib/syslinux-4.02/com32/mboot/apm.c | 86 | ||||
| -rw-r--r-- | contrib/syslinux-4.02/com32/mboot/initvesa.c | 226 | ||||
| -rw-r--r-- | contrib/syslinux-4.02/com32/mboot/map.c | 353 | ||||
| -rw-r--r-- | contrib/syslinux-4.02/com32/mboot/mb_header.h | 88 | ||||
| -rw-r--r-- | contrib/syslinux-4.02/com32/mboot/mb_info.h | 207 | ||||
| -rw-r--r-- | contrib/syslinux-4.02/com32/mboot/mboot.c | 247 | ||||
| -rw-r--r-- | contrib/syslinux-4.02/com32/mboot/mboot.h | 98 | ||||
| -rw-r--r-- | contrib/syslinux-4.02/com32/mboot/mem.c | 205 | ||||
| -rw-r--r-- | contrib/syslinux-4.02/com32/mboot/solaris.c | 62 | ||||
| -rw-r--r-- | contrib/syslinux-4.02/com32/mboot/syslinux.c | 45 | ||||
| -rw-r--r-- | contrib/syslinux-4.02/com32/mboot/vesa.h | 100 |
12 files changed, 1763 insertions, 0 deletions
diff --git a/contrib/syslinux-4.02/com32/mboot/Makefile b/contrib/syslinux-4.02/com32/mboot/Makefile new file mode 100644 index 0000000..7e6c2e9 --- /dev/null +++ b/contrib/syslinux-4.02/com32/mboot/Makefile @@ -0,0 +1,46 @@ +## ----------------------------------------------------------------------- +## +## Copyright 2001-2009 H. Peter Anvin - All Rights Reserved +## Copyright 2009 Intel Corporation; author: H. Peter Anvin +## +## This program is free software; you can redistribute it and/or modify +## it under the terms of the GNU General Public License as published by +## the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, +## Boston MA 02110-1301, USA; either version 2 of the License, or +## (at your option) any later version; incorporated herein by reference. +## +## ----------------------------------------------------------------------- + +## +## Multiboot module +## + +topdir = ../.. +include ../MCONFIG + +LIBS = ../libutil/libutil_com.a ../lib/libcom32.a $(LIBGCC) +LNXLIBS = ../libutil/libutil_lnx.a + +MODULES = mboot.c32 +TESTFILES = + +OBJS = mboot.o map.o mem.o initvesa.o apm.o solaris.o syslinux.o + +all: $(MODULES) $(TESTFILES) + +mboot.elf : $(OBJS) $(LIBS) $(C_LIBS) + $(LD) $(LDFLAGS) -o $@ $^ + +tidy dist: + rm -f *.o *.lo *.a *.lst *.elf .*.d *.tmp + +clean: tidy + rm -f *.lnx + +spotless: clean + rm -f *.lss *.c32 *.com + rm -f *~ \#* + +install: + +-include .*.d diff --git a/contrib/syslinux-4.02/com32/mboot/apm.c b/contrib/syslinux-4.02/com32/mboot/apm.c new file mode 100644 index 0000000..3f48af7 --- /dev/null +++ b/contrib/syslinux-4.02/com32/mboot/apm.c @@ -0,0 +1,86 @@ +/* ----------------------------------------------------------------------- * + * + * Copyright 2009 Intel Corporation; author: H. Peter Anvin + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, + * Boston MA 02110-1301, USA; either version 2 of the License, or + * (at your option) any later version; incorporated herein by reference. + * + * Based on code from the Linux kernel: + * + * Copyright (C) 1991, 1992 Linus Torvalds + * Copyright 2007 rPath, Inc. - All Rights Reserved + * + * Original APM BIOS checking by Stephen Rothwell, May 1994 + * (sfr@canb.auug.org.au) + * + * This file is part of the Linux kernel, and is made available under + * the terms of the GNU General Public License version 2. + * + * ----------------------------------------------------------------------- */ + +/* + * apm.c + * + * APM information for Multiboot + */ + +#include "mboot.h" +#include <com32.h> + +void mboot_apm(void) +{ + static struct apm_info apm; + com32sys_t ireg, oreg; + + memset(&ireg, 0, sizeof ireg); + + ireg.eax.w[0] = 0x5300; + __intcall(0x15, &ireg, &oreg); + + if (oreg.eflags.l & EFLAGS_CF) + return; /* No APM BIOS */ + + if (oreg.ebx.w[0] != 0x504d) + return; /* No "PM" signature */ + + if (!(oreg.ecx.w[0] & 0x02)) + return; /* 32 bits not supported */ + + /* Disconnect first, just in case */ + ireg.eax.b[0] = 0x04; + __intcall(0x15, &ireg, &oreg); + + /* 32-bit connect */ + ireg.eax.b[0] = 0x03; + __intcall(0x15, &ireg, &oreg); + + apm.cseg = oreg.eax.w[0]; + apm.offset = oreg.ebx.l; + apm.cseg_16 = oreg.ecx.w[0]; + apm.dseg_16 = oreg.edx.w[0]; + apm.cseg_len = oreg.esi.w[0]; + apm.cseg_16_len = oreg.esi.w[1]; + apm.dseg_16_len = oreg.edi.w[0]; + + /* Redo the installation check as the 32-bit connect; + some BIOSes return different flags this way... */ + + ireg.eax.b[0] = 0x00; + __intcall(0x15, &ireg, &oreg); + + if ((oreg.eflags.l & EFLAGS_CF) || (oreg.ebx.w[0] != 0x504d)) { + /* Failure with 32-bit connect, try to disconect and ignore */ + ireg.eax.b[0] = 0x04; + __intcall(0x15, &ireg, NULL); + return; + } + + apm.version = oreg.eax.w[0]; + + mbinfo.apm_table = map_data(&apm, sizeof apm, 4, false); + if (mbinfo.apm_table) + mbinfo.flags |= MB_INFO_APM_TABLE; +} diff --git a/contrib/syslinux-4.02/com32/mboot/initvesa.c b/contrib/syslinux-4.02/com32/mboot/initvesa.c new file mode 100644 index 0000000..cf2707d --- /dev/null +++ b/contrib/syslinux-4.02/com32/mboot/initvesa.c @@ -0,0 +1,226 @@ +/* ----------------------------------------------------------------------- * + * + * Copyright 1999-2008 H. Peter Anvin - All Rights Reserved + * Copyright 2009 Intel Corporation; author: H. Peter Anvin + * + * Permission is hereby granted, free of charge, to any person + * obtaining a copy of this software and associated documentation + * files (the "Software"), to deal in the Software without + * restriction, including without limitation the rights to use, + * copy, modify, merge, publish, distribute, sublicense, and/or + * sell copies of the Software, and to permit persons to whom + * the Software is furnished to do so, subject to the following + * conditions: + * + * The above copyright notice and this permission notice shall + * be included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES + * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT + * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, + * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + * OTHER DEALINGS IN THE SOFTWARE. + * + * ----------------------------------------------------------------------- */ + +/* + * initvesa.c + * + * Query the VESA BIOS and select a 640x480x32 mode with local mapping + * support, if one exists. + */ + +#include <inttypes.h> +#include <com32.h> +#include <stdlib.h> +#include <string.h> +#include <limits.h> + +#include "vesa.h" +#include "mboot.h" + +struct vesa_info vesa_info; + +void set_graphics_mode(const struct multiboot_header *mbh, + struct multiboot_info *mbi) +{ + com32sys_t rm; + uint16_t mode, bestmode, *mode_ptr; + struct vesa_general_info *gi; + struct vesa_mode_info *mi; + int pxf, bestpxf; + int wantx, wanty; + int err, besterr; + bool better; + addr_t viaddr; + + /* Only do this if requested by the OS image */ + if (!(mbh->flags & MULTIBOOT_VIDEO_MODE) || mbh->mode_type != 0) + return; + + /* Allocate space in the bounce buffer for these structures */ + gi = &((struct vesa_info *)__com32.cs_bounce)->gi; + mi = &((struct vesa_info *)__com32.cs_bounce)->mi; + + memset(&rm, 0, sizeof rm); + memset(gi, 0, sizeof *gi); + + gi->signature = VBE2_MAGIC; /* Get VBE2 extended data */ + rm.eax.w[0] = 0x4F00; /* Get SVGA general information */ + rm.edi.w[0] = OFFS(gi); + rm.es = SEG(gi); + __intcall(0x10, &rm, &rm); + + if (rm.eax.w[0] != 0x004F) + return; /* Function call failed */ + if (gi->signature != VESA_MAGIC) + return; /* No magic */ + if (gi->version < 0x0102) + return; /* VESA 1.2+ required */ + + memcpy(&vesa_info.gi, gi, sizeof *gi); + + /* Search for a suitable mode with a suitable color and memory model... */ + + mode_ptr = GET_PTR(gi->video_mode_ptr); + bestmode = 0; + bestpxf = 0; + wantx = mbh->width ? mbh->width : 0xffff; + wanty = mbh->height ? mbh->height : 0xffff; + besterr = wantx + wanty; + + while ((mode = *mode_ptr++) != 0xFFFF) { + mode &= 0x1FF; /* The rest are attributes of sorts */ + + memset(mi, 0, sizeof *mi); + rm.eax.w[0] = 0x4F01; /* Get SVGA mode information */ + rm.ecx.w[0] = mode; + rm.edi.w[0] = OFFS(mi); + rm.es = SEG(mi); + __intcall(0x10, &rm, &rm); + + /* Must be a supported mode */ + if (rm.eax.w[0] != 0x004f) + continue; + + /* Must be an LFB color graphics mode supported by the hardware. + + The bits tested are: + 7 - linear frame buffer + 4 - graphics mode + 3 - color mode + 1 - mode information available (mandatory in VBE 1.2+) + 0 - mode supported by hardware + */ + if ((mi->mode_attr & 0x009b) != 0x009b) + continue; + + /* We don't support multibank (interlaced memory) modes */ + /* + * Note: The Bochs VESA BIOS (vbe.c 1.58 2006/08/19) violates the + * specification which states that banks == 1 for unbanked modes; + * fortunately it does report bank_size == 0 for those. + */ + if (mi->banks > 1 && mi->bank_size) + continue; + + /* Must either be a packed-pixel mode or a direct color mode + (depending on VESA version ); must be a supported pixel format */ + + if (mi->bpp == 32 && + (mi->memory_layout == 4 || + (mi->memory_layout == 6 && mi->rpos == 16 && mi->gpos == 8 && + mi->bpos == 0))) + pxf = 32; + else if (mi->bpp == 24 && + (mi->memory_layout == 4 || + (mi->memory_layout == 6 && mi->rpos == 16 && mi->gpos == 8 && + mi->bpos == 0))) + pxf = 24; + else if (mi->bpp == 16 && + (mi->memory_layout == 4 || + (mi->memory_layout == 6 && mi->rpos == 11 && mi->gpos == 5 && + mi->bpos == 0))) + pxf = 16; + else if (mi->bpp == 15 && + (mi->memory_layout == 4 || + (mi->memory_layout == 6 && mi->rpos == 10 && mi->gpos == 5 && + mi->bpos == 0))) + pxf = 15; + else + continue; + + better = false; + err = abs(mi->h_res - wantx) + abs(mi->v_res - wanty); + +#define IS_GOOD(mi, bestx, besty) \ + ((mi)->h_res >= (bestx) && (mi)->v_res >= (besty)) + + if (!bestpxf) + better = true; + else if (!IS_GOOD(&vesa_info.mi, wantx, wanty) && + IS_GOOD(mi, wantx, wanty)) + /* This matches criteria, which the previous one didn't */ + better = true; + else if (IS_GOOD(&vesa_info.mi, wantx, wanty) && + !IS_GOOD(mi, wantx, wanty)) + /* This doesn't match criteria, and the previous one did */ + better = false; + else if (err < besterr) + better = true; + else if (err == besterr && (pxf == (int)mbh->depth || pxf > bestpxf)) + better = true; + + if (better) { + bestmode = mode; + bestpxf = pxf; + memcpy(&vesa_info.mi, mi, sizeof *mi); + } + } + + if (!bestpxf) + return; /* No mode found */ + + mi = &vesa_info.mi; + mode = bestmode; + + /* Now set video mode */ + rm.eax.w[0] = 0x4F02; /* Set SVGA video mode */ + mode |= 0x4000; /* Request linear framebuffer */ + rm.ebx.w[0] = mode; + __intcall(0x10, &rm, &rm); + if (rm.eax.w[0] != 0x004F) + return; /* Failed to set mode */ + + mbi->flags |= MB_INFO_VIDEO_INFO; + mbi->vbe_mode = mode; + viaddr = map_data(&vesa_info, sizeof vesa_info, 4, 0); + mbi->vbe_control_info = viaddr + offsetof(struct vesa_info, gi); + mbi->vbe_mode_info = viaddr + offsetof(struct vesa_info, mi); + + /* Get the VBE 2.x PM entry point if supported */ + rm.eax.w[0] = 0x4F0A; + rm.ebx.w[0] = 0; + __intcall(0x10, &rm, &rm); + if (rm.eax.w[0] == 0x004F) { + mbi->vbe_interface_seg = rm.es; + mbi->vbe_interface_off = rm.edi.w[0]; + mbi->vbe_interface_len = rm.ecx.w[0]; + } + + /* Tell syslinux we changed video mode */ + rm.eax.w[0] = 0x0017; /* Report video mode change */ + /* In theory this should be: + + rm.ebx.w[0] = (mi->mode_attr & 4) ? 0x0007 : 0x000f; + + However, that would assume all systems that claim to handle text + output in VESA modes actually do that... */ + rm.ebx.w[0] = 0x000f; + rm.ecx.w[0] = vesa_info.mi.h_res; + rm.edx.w[0] = vesa_info.mi.v_res; + __intcall(0x22, &rm, NULL); +} diff --git a/contrib/syslinux-4.02/com32/mboot/map.c b/contrib/syslinux-4.02/com32/mboot/map.c new file mode 100644 index 0000000..0a71d4c --- /dev/null +++ b/contrib/syslinux-4.02/com32/mboot/map.c @@ -0,0 +1,353 @@ +/* ----------------------------------------------------------------------- * + * + * Copyright 2007-2008 H. Peter Anvin - All Rights Reserved + * Copyright 2009-2010 Intel Corporation; author: H. Peter Anvin + * + * Permission is hereby granted, free of charge, to any person + * obtaining a copy of this software and associated documentation + * files (the "Software"), to deal in the Software without + * restriction, including without limitation the rights to use, + * copy, modify, merge, publish, distribute, sublicense, and/or + * sell copies of the Software, and to permit persons to whom + * the Software is furnished to do so, subject to the following + * conditions: + * + * The above copyright notice and this permission notice shall + * be included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES + * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT + * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, + * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + * OTHER DEALINGS IN THE SOFTWARE. + * + * ----------------------------------------------------------------------- */ + +/* + * map.c + * + * Functions that deal with the memory map of various objects + */ + +#include "mboot.h" + +static struct syslinux_movelist *ml = NULL; +static struct syslinux_memmap *mmap = NULL, *amap = NULL; +static addr_t mboot_high_water_mark = 0x100000; + +/* + * Note: although there is no such thing in the spec, at least Xen makes + * assumptions as to where in the memory space Grub would have loaded + * certain things. To support that, if "high" is set, then allocate this + * at an address strictly above any previous allocations. + * + * As a precaution, this also pads the data with zero up to the next + * alignment datum. + */ +addr_t map_data(const void *data, size_t len, size_t align, int flags) +{ + addr_t start = (flags & MAP_HIGH) ? mboot_high_water_mark : 0x2000; + addr_t pad = (flags & MAP_NOPAD) ? 0 : -len & (align - 1); + addr_t xlen = len + pad; + + if (syslinux_memmap_find(amap, SMT_FREE, &start, &xlen, align) || + syslinux_add_memmap(&amap, start, len + pad, SMT_ALLOC) || + syslinux_add_movelist(&ml, start, (addr_t) data, len) || + (pad && syslinux_add_memmap(&mmap, start + len, pad, SMT_ZERO))) { + printf("Cannot map %zu bytes\n", len + pad); + return 0; + } + + dprintf("Mapping 0x%08x bytes (%#x pad) at 0x%08x\n", len, pad, start); + + if (start + len + pad > mboot_high_water_mark) + mboot_high_water_mark = start + len + pad; + + return start; +} + +addr_t map_string(const char *string) +{ + if (!string) + return 0; + else + return map_data(string, strlen(string) + 1, 1, 0); +} + +int init_map(void) +{ + /* + * Note: mmap is the memory map (containing free and zeroed regions) + * needed by syslinux_shuffle_boot_pm(); amap is a map where we keep + * track ourselves which target memory ranges have already been + * allocated. + */ + mmap = syslinux_memory_map(); + amap = syslinux_dup_memmap(mmap); + if (!mmap || !amap) { + error("Failed to allocate initial memory map!\n"); + return -1; + } +#if DEBUG + dprintf("Initial memory map:\n"); + syslinux_dump_memmap(stdout, mmap); +#endif + + return 0; +} + +struct multiboot_header *map_image(void *ptr, size_t len) +{ + struct multiboot_header *mbh; + int mbh_len; + char *cptr = ptr; + Elf32_Ehdr *eh = ptr; + Elf32_Phdr *ph; + Elf32_Shdr *sh; + unsigned int i, mbh_offset; + uint32_t bad_flags; + + /* + * Search for the multiboot header... + */ + mbh_len = 0; + for (mbh_offset = 0; mbh_offset < MULTIBOOT_SEARCH; mbh_offset += 4) { + mbh = (struct multiboot_header *)((char *)ptr + mbh_offset); + if (mbh->magic != MULTIBOOT_MAGIC) + continue; + if (mbh->magic + mbh->flags + mbh->checksum) + continue; + if (mbh->flags & MULTIBOOT_VIDEO_MODE) + mbh_len = 48; + else if (mbh->flags & MULTIBOOT_AOUT_KLUDGE) + mbh_len = 32; + else + mbh_len = 12; + + if (mbh_offset + mbh_len > len) + mbh_len = 0; /* Invalid... */ + else + break; /* Found something... */ + } + + if (mbh_len) { + bad_flags = mbh->flags & MULTIBOOT_UNSUPPORTED; + if (bad_flags) { + printf("Unsupported Multiboot flags set: %#x\n", bad_flags); + return NULL; + } + } + + if (len < sizeof(Elf32_Ehdr) || + memcmp(eh->e_ident, "\x7f" "ELF\1\1\1", 6) || + (eh->e_machine != EM_386 && eh->e_machine != EM_486 && + eh->e_machine != EM_X86_64) || + eh->e_version != EV_CURRENT || + eh->e_ehsize < sizeof(Elf32_Ehdr) || eh->e_ehsize >= len || + eh->e_phentsize < sizeof(Elf32_Phdr) || + !eh->e_phnum || eh->e_phoff + eh->e_phentsize * eh->e_phnum > len) + eh = NULL; /* No valid ELF header found */ + + /* Is this a Solaris kernel? */ + if (!set.solaris && eh && kernel_is_solaris(eh)) + opt.solaris = true; + + /* + * Note: the Multiboot Specification implies that AOUT_KLUDGE should + * have precedence over the ELF header. However, Grub disagrees, and + * Grub is "the reference bootloader" for the Multiboot Specification. + * This is insane, since it makes the AOUT_KLUDGE bit functionally + * useless, but at least Solaris apparently depends on this behavior. + */ + if (eh && !(opt.aout && mbh_len && (mbh->flags & MULTIBOOT_AOUT_KLUDGE))) { + regs.eip = eh->e_entry; /* Can be overridden further down... */ + + ph = (Elf32_Phdr *) (cptr + eh->e_phoff); + + for (i = 0; i < eh->e_phnum; i++) { + if (ph->p_type == PT_LOAD || ph->p_type == PT_PHDR) { + /* + * This loads at p_paddr, which matches Grub. However, if + * e_entry falls within the p_vaddr range of this PHDR, then + * adjust it to match the p_paddr range... this is how Grub + * behaves, so it's by definition correct (it doesn't have to + * make sense...) + */ + addr_t addr = ph->p_paddr; + addr_t msize = ph->p_memsz; + addr_t dsize = min(msize, ph->p_filesz); + + if (eh->e_entry >= ph->p_vaddr + && eh->e_entry < ph->p_vaddr + msize) + regs.eip = eh->e_entry + (ph->p_paddr - ph->p_vaddr); + + dprintf("Segment at 0x%08x data 0x%08x len 0x%08x\n", + addr, dsize, msize); + + if (syslinux_memmap_type(amap, addr, msize) != SMT_FREE) { + printf + ("Memory segment at 0x%08x (len 0x%08x) is unavailable\n", + addr, msize); + return NULL; /* Memory region unavailable */ + } + + /* Mark this region as allocated in the available map */ + if (syslinux_add_memmap(&amap, addr, msize, SMT_ALLOC)) { + error("Overlapping segments found in ELF header\n"); + return NULL; + } + + if (ph->p_filesz) { + /* Data present region. Create a move entry for it. */ + if (syslinux_add_movelist + (&ml, addr, (addr_t) cptr + ph->p_offset, dsize)) { + error("Failed to map PHDR data\n"); + return NULL; + } + } + if (msize > dsize) { + /* Zero-filled region. Mark as a zero region in the memory map. */ + if (syslinux_add_memmap + (&mmap, addr + dsize, msize - dsize, SMT_ZERO)) { + error("Failed to map PHDR zero region\n"); + return NULL; + } + } + if (addr + msize > mboot_high_water_mark) + mboot_high_water_mark = addr + msize; + } else { + /* Ignore this program header */ + } + + ph = (Elf32_Phdr *) ((char *)ph + eh->e_phentsize); + } + + /* Load the ELF symbol table */ + if (eh->e_shoff) { + addr_t addr, len; + + sh = (Elf32_Shdr *) ((char *)eh + eh->e_shoff); + + len = eh->e_shentsize * eh->e_shnum; + /* + * Align this, but don't pad -- in general this means a bunch of + * smaller sections gets packed into a single page. + */ + addr = map_data(sh, len, 4096, MAP_HIGH | MAP_NOPAD); + if (!addr) { + error("Failed to map symbol table\n"); + return NULL; + } + + mbinfo.flags |= MB_INFO_ELF_SHDR; + mbinfo.syms.e.addr = addr; + mbinfo.syms.e.num = eh->e_shnum; + mbinfo.syms.e.size = eh->e_shentsize; + mbinfo.syms.e.shndx = eh->e_shstrndx; + + for (i = 0; i < eh->e_shnum; i++) { + addr_t align; + + if (!sh[i].sh_size) + continue; /* Empty section */ + if (sh[i].sh_flags & SHF_ALLOC) + continue; /* SHF_ALLOC sections should have PHDRs */ + + align = sh[i].sh_addralign ? sh[i].sh_addralign : 0; + addr = map_data((char *)ptr + sh[i].sh_offset, sh[i].sh_size, + align, MAP_HIGH); + if (!addr) { + error("Failed to map symbol section\n"); + return NULL; + } + sh[i].sh_addr = addr; + } + } + } else if (mbh_len && (mbh->flags & MULTIBOOT_AOUT_KLUDGE)) { + /* + * a.out kludge thing... + */ + char *data_ptr; + addr_t data_len, bss_len; + addr_t bss_addr; + + regs.eip = mbh->entry_addr; + + data_ptr = (char *)mbh - (mbh->header_addr - mbh->load_addr); + + if (mbh->load_end_addr) + data_len = mbh->load_end_addr - mbh->load_addr; + else + data_len = len - mbh_offset + (mbh->header_addr - mbh->load_addr); + + bss_addr = mbh->load_addr + data_len; + + if (mbh->bss_end_addr) + bss_len = mbh->bss_end_addr - mbh->load_end_addr; + else + bss_len = 0; + + if (syslinux_memmap_type(amap, mbh->load_addr, data_len + bss_len) + != SMT_FREE) { + printf("Memory segment at 0x%08x (len 0x%08x) is unavailable\n", + mbh->load_addr, data_len + bss_len); + return NULL; /* Memory region unavailable */ + } + if (syslinux_add_memmap(&amap, mbh->load_addr, + data_len + bss_len, SMT_ALLOC)) { + error("Failed to claim a.out address space!\n"); + return NULL; + } + if (data_len) + if (syslinux_add_movelist(&ml, mbh->load_addr, (addr_t) data_ptr, + data_len)) { + error("Failed to map a.out data\n"); + return NULL; + } + if (bss_len) + if (syslinux_add_memmap + (&mmap, bss_addr, bss_len, SMT_ZERO)) { + error("Failed to map a.out bss\n"); + return NULL; + } + if (bss_addr + bss_len > mboot_high_water_mark) + mboot_high_water_mark = bss_addr + bss_len; + } else { + error + ("Invalid Multiboot image: neither ELF header nor a.out kludge found\n"); + return NULL; + } + + return mbh; +} + +/* + * Set up a stack. This isn't actually required by the spec, but it seems + * like a prudent thing to do. Also, put enough zeros at the top of the + * stack that something that looks for an ELF invocation record will know + * there isn't one. + */ +static void mboot_map_stack(void) +{ + addr_t start, len; + + if (syslinux_memmap_largest(amap, SMT_FREE, &start, &len) || len < 64) + return; /* Not much we can do, here... */ + + regs.esp = (start + len - 32) & ~15; + dprintf("Mapping stack at 0x%08x\n", regs.esp); + syslinux_add_memmap(&mmap, regs.esp, 32, SMT_ZERO); +} + +void mboot_run(int bootflags) +{ + mboot_map_stack(); + + dprintf("Running, eip = 0x%08x, ebx = 0x%08x\n", regs.eip, regs.ebx); + + regs.eax = MULTIBOOT_VALID; + syslinux_shuffle_boot_pm(ml, mmap, bootflags, ®s); +} diff --git a/contrib/syslinux-4.02/com32/mboot/mb_header.h b/contrib/syslinux-4.02/com32/mboot/mb_header.h new file mode 100644 index 0000000..c026d30 --- /dev/null +++ b/contrib/syslinux-4.02/com32/mboot/mb_header.h @@ -0,0 +1,88 @@ +/* + * GRUB -- GRand Unified Bootloader + * Copyright (C) 2000 Free Software Foundation, Inc. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +#ifndef MBOOT_MB_HEADER_H +#define MBOOT_MB_HEADER_H + +#include <inttypes.h> + +/* + * MultiBoot Header description + */ + +struct multiboot_header { + /* Must be MULTIBOOT_MAGIC - see below. */ + uint32_t magic; + + /* Feature flags - see below. */ + uint32_t flags; + + /* + * Checksum + * + * The above fields plus this one must equal 0 mod 2^32. + */ + uint32_t checksum; + + /* These are only valid if MULTIBOOT_AOUT_KLUDGE is set. */ + uint32_t header_addr; + uint32_t load_addr; + uint32_t load_end_addr; + uint32_t bss_end_addr; + uint32_t entry_addr; + + /* These are only valid if MULTIBOOT_VIDEO_MODE is set. */ + uint32_t mode_type; + uint32_t width; + uint32_t height; + uint32_t depth; +}; + +/* + * The entire multiboot_header must be contained + * within the first MULTIBOOT_SEARCH bytes of the kernel image. + */ +#define MULTIBOOT_SEARCH 8192 + +/* Magic value identifying the multiboot_header. */ +#define MULTIBOOT_MAGIC 0x1BADB002 + +/* + * Features flags for 'flags'. + * If a boot loader sees a flag in MULTIBOOT_MUSTKNOW set + * and it doesn't understand it, it must fail. + */ +#define MULTIBOOT_MUSTKNOW 0x0000FFFF + +/* currently unsupported flags... this is a kind of version number. */ +#define MULTIBOOT_UNSUPPORTED 0x0000FFF8 + +/* Align all boot modules on i386 page (4KB) boundaries. */ +#define MULTIBOOT_PAGE_ALIGN 0x00000001 + +/* Must pass memory information to OS. */ +#define MULTIBOOT_MEMORY_INFO 0x00000002 + +/* Must pass video information to OS. */ +#define MULTIBOOT_VIDEO_MODE 0x00000004 + +/* This flag indicates the use of the address fields in the header. */ +#define MULTIBOOT_AOUT_KLUDGE 0x00010000 + +#endif /* MBOOT_MB_HEADER_H */ diff --git a/contrib/syslinux-4.02/com32/mboot/mb_info.h b/contrib/syslinux-4.02/com32/mboot/mb_info.h new file mode 100644 index 0000000..597a738 --- /dev/null +++ b/contrib/syslinux-4.02/com32/mboot/mb_info.h @@ -0,0 +1,207 @@ +/* + * GRUB -- GRand Unified Bootloader + * Copyright (C) 2000 Free Software Foundation, Inc. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +/* + * The structure type "mod_list" is used by the "multiboot_info" structure. + */ + +#ifndef MBOOT_MB_INFO_H +#define MBOOT_MB_INFO_H + +#include <inttypes.h> + +struct mod_list { + /* the memory used goes from bytes 'mod_start' to 'mod_end-1' inclusive */ + uint32_t mod_start; + uint32_t mod_end; + + /* Module command line */ + uint32_t cmdline; + + /* padding to take it to 16 bytes (must be zero) */ + uint32_t pad; +}; + +/* + * INT-15, AX=E820 style "AddressRangeDescriptor" + * ...with a "size" parameter on the front which is the structure size - 4, + * pointing to the next one, up until the full buffer length of the memory + * map has been reached. + */ + +struct AddrRangeDesc { + uint32_t size; + uint64_t BaseAddr; + uint64_t Length; + uint32_t Type; + /* unspecified optional padding... */ +} __attribute__ ((packed)); + +/* usable memory "Type", all others are reserved. */ +#define MB_ARD_MEMORY 1 + +/* Drive Info structure. */ +struct drive_info { + /* The size of this structure. */ + uint32_t size; + + /* The BIOS drive number. */ + uint8_t drive_number; + + /* The access mode (see below). */ + uint8_t drive_mode; + + /* The BIOS geometry. */ + uint16_t drive_cylinders; + uint8_t drive_heads; + uint8_t drive_sectors; + + /* The array of I/O ports used for the drive. */ + uint16_t drive_ports[0]; +}; + +/* Drive Mode. */ +#define MB_DI_CHS_MODE 0 +#define MB_DI_LBA_MODE 1 + +/* APM BIOS info. */ +struct apm_info { + uint16_t version; + uint16_t cseg; + uint32_t offset; + uint16_t cseg_16; + uint16_t dseg_16; + uint16_t cseg_len; + uint16_t cseg_16_len; + uint16_t dseg_16_len; +}; + +/* + * MultiBoot Info description + * + * This is the struct passed to the boot image. This is done by placing + * its address in the EAX register. + */ + +struct multiboot_info { + /* MultiBoot info version number */ + uint32_t flags; + + /* Available memory from BIOS */ + uint32_t mem_lower; + uint32_t mem_upper; + + /* "root" partition */ + uint32_t boot_device; + + /* Kernel command line */ + uint32_t cmdline; + + /* Boot-Module list */ + uint32_t mods_count; + uint32_t mods_addr; + + union { + struct { + /* (a.out) Kernel symbol table info */ + uint32_t tabsize; + uint32_t strsize; + uint32_t addr; + uint32_t pad; + } a; + struct { + /* (ELF) Kernel section header table */ + uint32_t num; + uint32_t size; + uint32_t addr; + uint32_t shndx; + } e; + } syms; + + /* Memory Mapping buffer */ + uint32_t mmap_length; + uint32_t mmap_addr; + + /* Drive Info buffer */ + uint32_t drives_length; + uint32_t drives_addr; + + /* ROM configuration table */ + uint32_t config_table; + + /* Boot Loader Name */ + uint32_t boot_loader_name; + + /* APM table */ + uint32_t apm_table; + + /* Video */ + uint32_t vbe_control_info; + uint32_t vbe_mode_info; + uint16_t vbe_mode; + uint16_t vbe_interface_seg; + uint16_t vbe_interface_off; + uint16_t vbe_interface_len; +}; + +/* + * Flags to be set in the 'flags' parameter above + */ + +/* is there basic lower/upper memory information? */ +#define MB_INFO_MEMORY 0x00000001 +/* is there a boot device set? */ +#define MB_INFO_BOOTDEV 0x00000002 +/* is the command-line defined? */ +#define MB_INFO_CMDLINE 0x00000004 +/* are there modules to do something with? */ +#define MB_INFO_MODS 0x00000008 + +/* These next two are mutually exclusive */ + +/* is there a symbol table loaded? */ +#define MB_INFO_AOUT_SYMS 0x00000010 +/* is there an ELF section header table? */ +#define MB_INFO_ELF_SHDR 0x00000020 + +/* is there a full memory map? */ +#define MB_INFO_MEM_MAP 0x00000040 + +/* Is there drive info? */ +#define MB_INFO_DRIVE_INFO 0x00000080 + +/* Is there a config table? */ +#define MB_INFO_CONFIG_TABLE 0x00000100 + +/* Is there a boot loader name? */ +#define MB_INFO_BOOT_LOADER_NAME 0x00000200 + +/* Is there a APM table? */ +#define MB_INFO_APM_TABLE 0x00000400 + +/* Is there video information? */ +#define MB_INFO_VIDEO_INFO 0x00000800 + +/* + * The following value must be present in the EAX register. + */ + +#define MULTIBOOT_VALID 0x2BADB002 + +#endif /* MBOOT_MB_INFO_H */ diff --git a/contrib/syslinux-4.02/com32/mboot/mboot.c b/contrib/syslinux-4.02/com32/mboot/mboot.c new file mode 100644 index 0000000..35450e0 --- /dev/null +++ b/contrib/syslinux-4.02/com32/mboot/mboot.c @@ -0,0 +1,247 @@ +/* ----------------------------------------------------------------------- * + * + * Copyright 2007-2008 H. Peter Anvin - All Rights Reserved + * Copyright 2009-2010 Intel Corporation; author: H. Peter Anvin + * + * Permission is hereby granted, free of charge, to any person + * obtaining a copy of this software and associated documentation + * files (the "Software"), to deal in the Software without + * restriction, including without limitation the rights to use, + * copy, modify, merge, publish, distribute, sublicense, and/or + * sell copies of the Software, and to permit persons to whom + * the Software is furnished to do so, subject to the following + * conditions: + * + * The above copyright notice and this permission notice shall + * be included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES + * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT + * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, + * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + * OTHER DEALINGS IN THE SOFTWARE. + * + * ----------------------------------------------------------------------- */ + +/* + * mboot.c + * + * Module to load a multiboot kernel + */ + +#include "mboot.h" + +struct multiboot_info mbinfo; +struct syslinux_pm_regs regs; +struct my_options opt, set; + +struct module_data { + void *data; + size_t len; + const char *cmdline; +}; + +static int map_modules(struct module_data *modules, int nmodules) +{ + struct mod_list *mod_list; + addr_t map_list = 0; + size_t list_size = nmodules * sizeof *mod_list; + int i; + + mod_list = malloc(list_size); + if (!mod_list) { + printf("Failed to allocate module list\n"); + return -1; + } + + map_list = map_data(mod_list, list_size, 16, 0); + if (!map_list) { + printf("Cannot map module list\n"); + return -1; + } + + for (i = 0; i < nmodules; i++) { + addr_t mod_map = 0; + addr_t cmd_map = 0; + + dprintf("Module %d cmdline: \"%s\"\n", i, modules[i].cmdline); + + cmd_map = map_string(modules[i].cmdline); + + mod_map = map_data(modules[i].data, modules[i].len, 4096, MAP_HIGH); + if (!mod_map) { + printf("Failed to map module (memory fragmentation issue?)\n"); + return -1; + } + mod_list[i].mod_start = mod_map; + mod_list[i].mod_end = mod_map + modules[i].len; + mod_list[i].cmdline = cmd_map; + mod_list[i].pad = 0; + } + + mbinfo.flags |= MB_INFO_MODS; + mbinfo.mods_count = nmodules; + mbinfo.mods_addr = map_list; + return 0; +} + +static int get_modules(char **argv, struct module_data **mdp) +{ + char **argp, **argx; + struct module_data *mp; + int rv; + int module_count = 1; + int arglen; + const char module_separator[] = "---"; + + for (argp = argv; *argp; argp++) { + if (!strcmp(*argp, module_separator)) + module_count++; + } + + *mdp = mp = malloc(module_count * sizeof(struct module_data)); + if (!mp) { + error("Out of memory!\n"); + return -1; + } + + argp = argv; + while (*argp) { + /* Note: it seems Grub transparently decompresses all compressed files, + not just the primary kernel. */ + printf("Loading %s... ", *argp); + rv = zloadfile(*argp, &mp->data, &mp->len); + + if (rv) { + printf("failed!\n"); + return -1; + } + printf("ok\n"); + + /* + * Note: Grub includes the kernel filename in the command line, so we + * want to match that behavior. + */ + arglen = 0; + for (argx = argp; *argx && strcmp(*argx, module_separator); argx++) + arglen += strlen(*argx) + 1; + + if (arglen == 0) { + mp->cmdline = strdup(""); + } else { + char *p; + mp->cmdline = p = malloc(arglen); + for (; *argp && strcmp(*argp, module_separator); argp++) { + p = stpcpy(p, *argp); + *p++ = ' '; + } + *--p = '\0'; + } + mp++; + if (*argp) + argp++; /* Advance past module_separator */ + } + + return module_count; +} + +int main(int argc, char *argv[]) +{ + int nmodules; + struct module_data *modules; + struct multiboot_header *mbh; + bool keeppxe = false; + + openconsole(&dev_null_r, &dev_stdcon_w); + + (void)argc; /* Unused */ + argv++; + + while (*argv) { + bool v = true; + const char *p = *argv; + + if (!memcmp(p, "-no", 3)) { + v = false; + p += 3; + } + + if (!strcmp(p, "-solaris")) { + opt.solaris = v; + set.solaris = true; + } else if (!strcmp(p, "-aout")) { + opt.aout = v; + set.aout = true; + } else + break; + argv++; + } + + if (!*argv) { + error + ("Usage: mboot.c32 [opts] mboot_file args... [--- module args...]...\n" + "Options:\n" + " -solaris Enable Solaris DHCP information passing\n" + " -aout Use the \"a.out kludge\" if enabled, even for ELF\n" + " This matches the Multiboot spec, but differs from Grub\n"); + return 1; + } + + /* Load the files */ + nmodules = get_modules(argv, &modules); + if (nmodules < 1) { + error("No files found!\n"); + return 1; /* Failure */ + } + + if (init_map()) + return 1; /* Failed to allocate intitial map */ + + /* + * Map the primary image. This should be done before mapping anything + * else, since it will have fixed address requirements. + */ + mbh = map_image(modules[0].data, modules[0].len); + if (!mbh) + return 1; + + /* Map the mbinfo structure */ + regs.ebx = map_data(&mbinfo, sizeof mbinfo, 4, 0); + if (!regs.ebx) { + error("Failed to map Multiboot info structure!\n"); + return 1; + } + + /* Map the primary command line */ + if (modules[0].cmdline) { + mbinfo.cmdline = map_string(modules[0].cmdline); + dprintf("Main cmdline: \"%s\"\n", modules[0].cmdline); + if (mbinfo.cmdline) + mbinfo.flags |= MB_INFO_CMDLINE; + } + + /* Map auxilliary images */ + if (nmodules > 1) { + if (map_modules(modules + 1, nmodules - 1)) + return 1; + } + + /* Add auxilliary information */ + mboot_make_memmap(); + mboot_apm(); + mboot_syslinux_info(); + + if (opt.solaris) + mboot_solaris_dhcp_hack(); + + /* Set the graphics mode if requested */ + set_graphics_mode(mbh, &mbinfo); + + /* Run it */ + mboot_run(keeppxe ? 3 : 0); + error("mboot.c32: boot failed\n"); + return 1; +} diff --git a/contrib/syslinux-4.02/com32/mboot/mboot.h b/contrib/syslinux-4.02/com32/mboot/mboot.h new file mode 100644 index 0000000..da6ca2f --- /dev/null +++ b/contrib/syslinux-4.02/com32/mboot/mboot.h @@ -0,0 +1,98 @@ +/* ----------------------------------------------------------------------- * + * + * Copyright 2007-2008 H. Peter Anvin - All Rights Reserved + * Copyright 2009-2010 Intel Corporation; author: H. Peter Anvin + * + * Permission is hereby granted, free of charge, to any person + * obtaining a copy of this software and associated documentation + * files (the "Software"), to deal in the Software without + * restriction, including without limitation the rights to use, + * copy, modify, merge, publish, distribute, sublicense, and/or + * sell copies of the Software, and to permit persons to whom + * the Software is furnished to do so, subject to the following + * conditions: + * + * The above copyright notice and this permission notice shall + * be included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES + * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT + * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, + * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + * OTHER DEALINGS IN THE SOFTWARE. + * + * ----------------------------------------------------------------------- */ + +/* + * mboot.h + * + * Module to load a multiboot kernel + */ + +#ifndef MBOOT_H + +#include <dprintf.h> +#include <stdio.h> +#include <stdlib.h> +#include <inttypes.h> +#include <stdbool.h> +#include <string.h> +#include <fcntl.h> +#include <unistd.h> +#include <errno.h> +#include <minmax.h> +#include <sys/stat.h> +#include <elf.h> +#include <console.h> + +#include <syslinux/loadfile.h> +#include <syslinux/movebits.h> +#include <syslinux/bootpm.h> +#include <syslinux/config.h> + +#include "mb_header.h" +#include "mb_info.h" + +static inline void error(const char *msg) +{ + fputs(msg, stderr); +} + +/* mboot.c */ +extern struct multiboot_info mbinfo; +extern struct syslinux_pm_regs regs; +extern struct my_options { + bool solaris; + bool aout; +} opt, set; + +/* map.c */ +#define MAP_HIGH 1 +#define MAP_NOPAD 2 +addr_t map_data(const void *data, size_t len, size_t align, int flags); +addr_t map_string(const char *string); +struct multiboot_header *map_image(void *ptr, size_t len); +void mboot_run(int bootflags); +int init_map(void); + +/* mem.c */ +void mboot_make_memmap(void); + +/* apm.c */ +void mboot_apm(void); + +/* solaris.c */ +bool kernel_is_solaris(const Elf32_Ehdr *); +void mboot_solaris_dhcp_hack(void); + +/* syslinux.c */ +void mboot_syslinux_info(void); + +/* initvesa.c */ +void set_graphics_mode(const struct multiboot_header *mbh, + struct multiboot_info *mbi); + +#endif /* MBOOT_H */ diff --git a/contrib/syslinux-4.02/com32/mboot/mem.c b/contrib/syslinux-4.02/com32/mboot/mem.c new file mode 100644 index 0000000..6a31fac --- /dev/null +++ b/contrib/syslinux-4.02/com32/mboot/mem.c @@ -0,0 +1,205 @@ +/* ----------------------------------------------------------------------- * + * + * Copyright 2007-2009 H. Peter Anvin - All Rights Reserved + * Copyright 2009 H. Peter Anvin - All Rights Reserved + * + * Permission is hereby granted, free of charge, to any person + * obtaining a copy of this software and associated documentation + * files (the "Software"), to deal in the Software without + * restriction, including without limitation the rights to use, + * copy, modify, merge, publish, distribute, sublicense, and/or + * sell copies of the Software, and to permit persons to whom + * the Software is furnished to do so, subject to the following + * conditions: + * + * The above copyright notice and this permission notice shall + * be included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES + * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT + * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, + * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + * OTHER DEALINGS IN THE SOFTWARE. + * + * ----------------------------------------------------------------------- */ + +/* + * mem.c + * + * Obtain a memory map for a Multiboot OS + * + * This differs from the libcom32 memory map functions in that it doesn't + * attempt to filter out memory regions... + */ + +#include "mboot.h" +#include <com32.h> + +struct e820_entry { + uint64_t start; + uint64_t len; + uint32_t type; +}; + +#define RANGE_ALLOC_BLOCK 128 + +static int mboot_scan_memory(struct AddrRangeDesc **ardp, uint32_t * dosmem) +{ + com32sys_t ireg, oreg; + struct e820_entry *e820buf = __com32.cs_bounce; + struct AddrRangeDesc *ard; + size_t ard_count, ard_space; + + /* Use INT 12h to get DOS memory */ + __intcall(0x12, &__com32_zero_regs, &oreg); + *dosmem = oreg.eax.w[0] << 10; + if (*dosmem < 32 * 1024 || *dosmem > 640 * 1024) { + /* INT 12h reports nonsense... now what? */ + uint16_t ebda_seg = *(uint16_t *) 0x40e; + if (ebda_seg >= 0x8000 && ebda_seg < 0xa000) + *dosmem = ebda_seg << 4; + else + *dosmem = 640 * 1024; /* Hope for the best... */ + } + + /* Allocate initial space */ + *ardp = ard = malloc(RANGE_ALLOC_BLOCK * sizeof *ard); + if (!ard) + return 0; + + ard_count = 0; + ard_space = RANGE_ALLOC_BLOCK; + + /* First try INT 15h AX=E820h */ + memset(&ireg, 0, sizeof ireg); + ireg.eax.l = 0xe820; + ireg.edx.l = 0x534d4150; + /* ireg.ebx.l = 0; */ + ireg.ecx.l = sizeof(*e820buf); + ireg.es = SEG(e820buf); + ireg.edi.w[0] = OFFS(e820buf); + memset(e820buf, 0, sizeof *e820buf); + + do { + __intcall(0x15, &ireg, &oreg); + + if ((oreg.eflags.l & EFLAGS_CF) || + (oreg.eax.l != 0x534d4150) || (oreg.ecx.l < 20)) + break; + + if (ard_count >= ard_space) { + ard_space += RANGE_ALLOC_BLOCK; + *ardp = ard = realloc(ard, ard_space * sizeof *ard); + if (!ard) + return ard_count; + } + + ard[ard_count].size = 20; + ard[ard_count].BaseAddr = e820buf->start; + ard[ard_count].Length = e820buf->len; + ard[ard_count].Type = e820buf->type; + ard_count++; + + ireg.ebx.l = oreg.ebx.l; + } while (oreg.ebx.l); + + if (ard_count) + return ard_count; + + ard[0].size = 20; + ard[0].BaseAddr = 0; + ard[0].Length = *dosmem << 10; + ard[0].Type = 1; + + /* Next try INT 15h AX=E801h */ + ireg.eax.w[0] = 0xe801; + __intcall(0x15, &ireg, &oreg); + + if (!(oreg.eflags.l & EFLAGS_CF) && oreg.ecx.w[0]) { + ard[1].size = 20; + ard[1].BaseAddr = 1 << 20; + ard[1].Length = oreg.ecx.w[0] << 10; + ard[1].Type = 1; + + if (oreg.edx.w[0]) { + ard[2].size = 20; + ard[2].BaseAddr = 16 << 20; + ard[2].Length = oreg.edx.w[0] << 16; + ard[2].Type = 1; + return 3; + } else { + return 2; + } + } + + /* Finally try INT 15h AH=88h */ + ireg.eax.w[0] = 0x8800; + if (!(oreg.eflags.l & EFLAGS_CF) && oreg.eax.w[0]) { + ard[1].size = 20; + ard[1].BaseAddr = 1 << 20; + ard[1].Length = oreg.ecx.w[0] << 10; + ard[1].Type = 1; + return 2; + } + + return 1; /* ... problematic ... */ +} + +void mboot_make_memmap(void) +{ + int i, nmap; + struct AddrRangeDesc *ard; + uint32_t lowmem, highmem; + uint32_t highrsvd; + + /* Always report DOS memory as "lowmem", this may be overly conservative + (e.g. if we're dropping PXE), but it should be *safe*... */ + + nmap = mboot_scan_memory(&ard, &lowmem); + + highmem = 0x100000; + highrsvd = 0xfff00000; + +again: + for (i = 0; i < nmap; i++) { + uint64_t start, end; + + start = ard[i].BaseAddr; + end = start + ard[i].Length; + + if (end < start) + end = ~0ULL; + + if (start & 0xffffffff00000000ULL) + continue; /* Not interested in 64-bit memory */ + + if (start < highmem) + start = highmem; + + if (end <= start) + continue; + + if (ard[i].Type == 1 && start == highmem) { + highmem = end; + goto again; + } else if (ard[i].Type != 1 && start < highrsvd) + highrsvd = start; + } + + if (highmem > highrsvd) + highmem = highrsvd; + + mbinfo.mem_lower = lowmem >> 10; + mbinfo.mem_upper = (highmem - 0x100000) >> 10; + mbinfo.flags |= MB_INFO_MEMORY; + + /* The spec says this address should be +4, but Grub disagrees */ + mbinfo.mmap_addr = map_data(ard, nmap * sizeof *ard, 4, false); + if (mbinfo.mmap_addr) { + mbinfo.mmap_length = nmap * sizeof *ard; + mbinfo.flags |= MB_INFO_MEM_MAP; + } +} diff --git a/contrib/syslinux-4.02/com32/mboot/solaris.c b/contrib/syslinux-4.02/com32/mboot/solaris.c new file mode 100644 index 0000000..1b153dd --- /dev/null +++ b/contrib/syslinux-4.02/com32/mboot/solaris.c @@ -0,0 +1,62 @@ +/* ----------------------------------------------------------------------- * + * + * Copyright 2009-2010 Intel Corporation; author: H. Peter Anvin + * + * Permission is hereby granted, free of charge, to any person + * obtaining a copy of this software and associated documentation + * files (the "Software"), to deal in the Software without + * restriction, including without limitation the rights to use, + * copy, modify, merge, publish, distribute, sublicense, and/or + * sell copies of the Software, and to permit persons to whom + * the Software is furnished to do so, subject to the following + * conditions: + * + * The above copyright notice and this permission notice shall + * be included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES + * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT + * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, + * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + * OTHER DEALINGS IN THE SOFTWARE. + * + * ----------------------------------------------------------------------- */ + +/* + * solaris.c + * + * Solaris DHCP hack + * + * Solaris uses a nonstandard hack to pass DHCP information from a netboot. + */ + +#include "mboot.h" +#include <syslinux/pxe.h> +#include <syslinux/config.h> + +bool kernel_is_solaris(const Elf32_Ehdr *eh) +{ + return eh->e_ident[EI_OSABI] == 6; /* ABI == Solaris */ +} + +void mboot_solaris_dhcp_hack(void) +{ + void *dhcpdata; + size_t dhcplen; + + if (syslinux_derivative_info()->c.filesystem != SYSLINUX_FS_PXELINUX) + return; + + if (!pxe_get_cached_info(PXENV_PACKET_TYPE_DHCP_ACK, &dhcpdata, &dhcplen)) { + mbinfo.drives_addr = map_data(dhcpdata, dhcplen, 4, 0); + if (mbinfo.drives_addr) { + mbinfo.drives_length = dhcplen; + mbinfo.boot_device = 0x20ffffff; + mbinfo.flags = + (mbinfo.flags & ~MB_INFO_DRIVE_INFO) | MB_INFO_BOOTDEV; + } + } +} diff --git a/contrib/syslinux-4.02/com32/mboot/syslinux.c b/contrib/syslinux-4.02/com32/mboot/syslinux.c new file mode 100644 index 0000000..7de3853 --- /dev/null +++ b/contrib/syslinux-4.02/com32/mboot/syslinux.c @@ -0,0 +1,45 @@ +/* ----------------------------------------------------------------------- * + * + * Copyright 2010 Intel Corporation; author: H. Peter Anvin + * + * Permission is hereby granted, free of charge, to any person + * obtaining a copy of this software and associated documentation + * files (the "Software"), to deal in the Software without + * restriction, including without limitation the rights to use, + * copy, modify, merge, publish, distribute, sublicense, and/or + * sell copies of the Software, and to permit persons to whom + * the Software is furnished to do so, subject to the following + * conditions: + * + * The above copyright notice and this permission notice shall + * be included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES + * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT + * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, + * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + * OTHER DEALINGS IN THE SOFTWARE. + * + * ----------------------------------------------------------------------- */ + +/* + * syslinux.c + * + * Syslinux-specific information for the kernel + */ + +#include <syslinux/config.h> +#include "mboot.h" + +void mboot_syslinux_info(void) +{ + const struct syslinux_version *sv; + + sv = syslinux_version(); + mbinfo.boot_loader_name = map_string(sv->version_string); + if (mbinfo.boot_loader_name) + mbinfo.flags |= MB_INFO_BOOT_LOADER_NAME; +} diff --git a/contrib/syslinux-4.02/com32/mboot/vesa.h b/contrib/syslinux-4.02/com32/mboot/vesa.h new file mode 100644 index 0000000..ecc084a --- /dev/null +++ b/contrib/syslinux-4.02/com32/mboot/vesa.h @@ -0,0 +1,100 @@ +/* ----------------------------------------------------------------------- * + * + * Copyright 1999-2008 H. Peter Anvin - All Rights Reserved + * + * Permission is hereby granted, free of charge, to any person + * obtaining a copy of this software and associated documentation + * files (the "Software"), to deal in the Software without + * restriction, including without limitation the rights to use, + * copy, modify, merge, publish, distribute, sublicense, and/or + * sell copies of the Software, and to permit persons to whom + * the Software is furnished to do so, subject to the following + * conditions: + * + * The above copyright notice and this permission notice shall + * be included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES + * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT + * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, + * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + * OTHER DEALINGS IN THE SOFTWARE. + * + * ----------------------------------------------------------------------- */ + +#ifndef LIB_SYS_VESA_H +#define LIB_SYS_VESA_H + +#include <inttypes.h> +#include <com32.h> + +/* VESA General Information table */ +struct vesa_general_info { + uint32_t signature; /* Magic number = "VESA" */ + uint16_t version; + far_ptr_t vendor_string; + uint8_t capabilities[4]; + far_ptr_t video_mode_ptr; + uint16_t total_memory; + + uint16_t oem_software_rev; + far_ptr_t oem_vendor_name_ptr; + far_ptr_t oem_product_name_ptr; + far_ptr_t oem_product_rev_ptr; + + uint8_t reserved[222]; + uint8_t oem_data[256]; +} __attribute__ ((packed)); + +#define VESA_MAGIC ('V' + ('E' << 8) + ('S' << 16) + ('A' << 24)) +#define VBE2_MAGIC ('V' + ('B' << 8) + ('E' << 16) + ('2' << 24)) + +struct vesa_mode_info { + uint16_t mode_attr; + uint8_t win_attr[2]; + uint16_t win_grain; + uint16_t win_size; + uint16_t win_seg[2]; + far_ptr_t win_scheme; + uint16_t logical_scan; + + uint16_t h_res; + uint16_t v_res; + uint8_t char_width; + uint8_t char_height; + uint8_t memory_planes; + uint8_t bpp; + uint8_t banks; + uint8_t memory_layout; + uint8_t bank_size; + uint8_t image_pages; + uint8_t page_function; + + uint8_t rmask; + uint8_t rpos; + uint8_t gmask; + uint8_t gpos; + uint8_t bmask; + uint8_t bpos; + uint8_t resv_mask; + uint8_t resv_pos; + uint8_t dcm_info; + + uint8_t *lfb_ptr; /* Linear frame buffer address */ + uint8_t *offscreen_ptr; /* Offscreen memory address */ + uint16_t offscreen_size; + + uint8_t reserved[206]; +} __attribute__ ((packed)); + +struct vesa_info { + struct vesa_general_info gi; + struct vesa_mode_info mi; +}; + +extern struct vesa_info vesa_info; + +#endif /* LIB_SYS_VESA_H */ |
