Exemplo n.º 1
0
/*
 * 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);
}
Exemplo n.º 2
0
int syslinux_do_shuffle(struct syslinux_movelist *fraglist,
			struct syslinux_memmap *memmap,
			addr_t entry_point, addr_t entry_type,
			uint16_t bootflags)
{
    int rv = -1;
    struct syslinux_movelist *moves = NULL, *mp;
    struct syslinux_memmap *rxmap = NULL, *ml;
    struct shuffle_descriptor *dp, *dbuf;
    int np;
    int desc_blocks, need_blocks;
    int need_ptrs;
    addr_t desczone, descfree, descaddr;
    int nmoves, nzero;
    com32sys_t ireg;

    descaddr = 0;
    dp = dbuf = NULL;

    /* Count the number of zero operations */
    nzero = 0;
    for (ml = memmap; ml->type != SMT_END; ml = ml->next) {
	if (ml->type == SMT_ZERO)
	    nzero++;
    }

    /* Find the largest contiguous region unused by input *and* output;
       this is where we put the move descriptor list and safe area */

    rxmap = syslinux_dup_memmap(memmap);
    if (!rxmap)
	goto bail;
    /* Avoid using the low 1 MB for the shuffle area -- this avoids
       possible interference with the real mode code or stack */
    if (syslinux_add_memmap(&rxmap, 0, 1024 * 1024, SMT_RESERVED))
	goto bail;
    for (mp = fraglist; mp; mp = mp->next) {
	if (syslinux_add_memmap(&rxmap, mp->src, mp->len, SMT_ALLOC) ||
	    syslinux_add_memmap(&rxmap, mp->dst, mp->len, SMT_ALLOC))
	    goto bail;
    }
    if (syslinux_memmap_largest(rxmap, SMT_FREE, &desczone, &descfree))
	goto bail;

    syslinux_free_memmap(rxmap);

    dprintf("desczone = 0x%08x, descfree = 0x%08x\n", desczone, descfree);

    rxmap = syslinux_dup_memmap(memmap);
    if (!rxmap)
	goto bail;

    __syslinux_get_shuffer_size();
    desc_blocks = (nzero + DESC_BLOCK_SIZE - 1) / DESC_BLOCK_SIZE;
    for (;;) {
	/* We want (desc_blocks) allocation blocks, plus the terminating
	   descriptor, plus the shuffler safe area. */
	addr_t descmem = desc_blocks *
	    sizeof(struct shuffle_descriptor) * DESC_BLOCK_SIZE
	    + sizeof(struct shuffle_descriptor) + shuffler_size;

	descaddr = (desczone + descfree - descmem) & ~3;

	if (descaddr < desczone)
	    goto bail;		/* No memory block large enough */

	/* Mark memory used by shuffle descriptors as reserved */
	if (syslinux_add_memmap(&rxmap, descaddr, descmem, SMT_RESERVED))
	    goto bail;

#if DEBUG > 1
	syslinux_dump_movelist(fraglist);
#endif

	if (syslinux_compute_movelist(&moves, fraglist, rxmap))
	    goto bail;

	nmoves = 0;
	for (mp = moves; mp; mp = mp->next)
	    nmoves++;

	need_blocks = (nmoves + nzero + DESC_BLOCK_SIZE - 1) / DESC_BLOCK_SIZE;

	if (desc_blocks >= need_blocks)
	    break;		/* Sufficient memory, yay */

	desc_blocks = need_blocks;	/* Try again... */
    }

#if DEBUG > 1
    dprintf("Final movelist:\n");
    syslinux_dump_movelist(moves);
#endif

    syslinux_free_memmap(rxmap);
    rxmap = NULL;

    need_ptrs = nmoves + nzero + 1;
    dbuf = malloc(need_ptrs * sizeof(struct shuffle_descriptor));
    if (!dbuf)
	goto bail;

#if DEBUG
    {
	addr_t descoffs = descaddr - (addr_t) dbuf;

	dprintf("nmoves = %d, nzero = %d, dbuf = %p, offs = 0x%08x\n",
		nmoves, nzero, dbuf, descoffs);
    }
#endif

    /* Copy the move sequence into the descriptor buffer */
    np = 0;
    dp = dbuf;
    for (mp = moves; mp; mp = mp->next) {
	dp->dst = mp->dst;
	dp->src = mp->src;
	dp->len = mp->len;
	dprintf2("[ %08x %08x %08x ]\n", dp->dst, dp->src, dp->len);
	dp++;
	np++;
    }

    /* Copy bzero operations into the descriptor buffer */
    for (ml = memmap; ml->type != SMT_END; ml = ml->next) {
	if (ml->type == SMT_ZERO) {
	    dp->dst = ml->start;
	    dp->src = (addr_t) - 1;	/* bzero region */
	    dp->len = ml->next->start - ml->start;
	    dprintf2("[ %08x %08x %08x ]\n", dp->dst, dp->src, dp->len);
	    dp++;
	    np++;
	}
    }

    /* Finally, record the termination entry */
    dp->dst = entry_point;
    dp->src = entry_type;
    dp->len = 0;
    dp++;
    np++;

    if (np != need_ptrs) {
	dprintf("!!! np = %d : nmoves = %d, nzero = %d, desc_blocks = %d\n",
		np, nmoves, nzero, desc_blocks);
    }

    rv = 0;

bail:
    /* This is safe only because free() doesn't use the bounce buffer!!!! */
    if (moves)
	syslinux_free_movelist(moves);
    if (rxmap)
	syslinux_free_memmap(rxmap);

    if (rv)
	return rv;

    /* Actually do it... */
    memset(&ireg, 0, sizeof ireg);
    ireg.edi.l = descaddr;
    ireg.esi.l = (addr_t) dbuf;
    ireg.ecx.l = (addr_t) dp - (addr_t) dbuf;
    ireg.edx.w[0] = bootflags;
    ireg.eax.w[0] = 0x0024;
    __intcall(0x22, &ireg, NULL);

    return -1;			/* Shouldn't have returned! */
}
Exemplo n.º 3
0
int boot_raw(void *ptr, size_t len, addr_t where, char **argv)
{
    struct syslinux_movelist *ml = NULL;
    struct syslinux_memmap *mmap = NULL, *amap = NULL;
    struct syslinux_pm_regs regs;
    int argc;
    addr_t argsize;
    char **argp;
    addr_t lstart, llen;
    char *stack_frame = NULL;
    addr_t stack_frame_size;
    addr_t stack_pointer;
    uint32_t *spp;
    char *sfp;
    addr_t sfa;

    memset(&regs, 0, sizeof regs);

    mmap = syslinux_memory_map();
    amap = syslinux_dup_memmap(mmap);
    if (!mmap || !amap)
	goto bail;

    dprintf("Initial memory map:\n");
    syslinux_dump_memmap(mmap);

    dprintf("Segment at 0x%08x len 0x%08x\n", where, len);

    if (syslinux_memmap_type(amap, where, len) != SMT_FREE) {
	printf("Memory segment at 0x%08x (len 0x%08x) is unavailable\n",
	       where, len);
	goto bail;		/* Memory region unavailable */
    }

    /* Mark this region as allocated in the available map */
    if (syslinux_add_memmap(&amap, where, len, SMT_ALLOC))
	goto bail;

    /* Data present region.  Create a move entry for it. */
    if (syslinux_add_movelist(&ml, where, (addr_t) ptr, len))
	goto bail;

    /* Create the invocation record (initial stack frame) */

    argsize = argc = 0;
    for (argp = argv; *argp; argp++) {
	dprintf("argv[%2d] = \"%s\"\n", argc, *argp);
	argc++;
	argsize += strlen(*argp) + 1;
    }

    /* We need the argument strings, argument pointers,
       argc, plus four zero-word terminators. */
    stack_frame_size = argsize + argc * sizeof(char *) + 5 * sizeof(long);
    stack_frame_size = (stack_frame_size + 15) & ~15;
    stack_frame = calloc(stack_frame_size, 1);
    if (!stack_frame)
	goto bail;

    dprintf("Right before syslinux_memmap_largest()...\n");
    syslinux_dump_memmap(amap);

    if (syslinux_memmap_largest(amap, SMT_FREE, &lstart, &llen))
	goto bail;		/* NO free memory?! */

    if (llen < stack_frame_size + MIN_STACK + 16)
	goto bail;		/* Insufficient memory  */

    /* Initial stack pointer address */
    stack_pointer = (lstart + llen - stack_frame_size) & ~15;

    dprintf("Stack frame at 0x%08x len 0x%08x\n",
	    stack_pointer, stack_frame_size);

    /* Create the stack frame.  sfp is the pointer in current memory for
       the next argument string, sfa is the address in its final resting place.
       spp is the pointer into the argument array in current memory. */
    spp = (uint32_t *) stack_frame;
    sfp = stack_frame + argc * sizeof(char *) + 5 * sizeof(long);
    sfa = stack_pointer + argc * sizeof(char *) + 5 * sizeof(long);

    *spp++ = argc;
    for (argp = argv; *argp; argp++) {
	int bytes = strlen(*argp) + 1;	/* Including final null */
	*spp++ = sfa;
	memcpy(sfp, *argp, bytes);
	sfp += bytes;
	sfa += bytes;
    }
    /* Zero fields are aready taken care of by calloc() */

    /* ... and we'll want to move it into the right place... */
#if DEBUG
    if (syslinux_memmap_type(amap, stack_pointer, stack_frame_size)
	!= SMT_FREE) {
	dprintf("Stack frame area not free (how did that happen?)!\n");
	goto bail;		/* Memory region unavailable */
    }
#endif

    if (syslinux_add_memmap(&amap, stack_pointer, stack_frame_size, SMT_ALLOC))
	goto bail;

    if (syslinux_add_movelist(&ml, stack_pointer, (addr_t) stack_frame,
			      stack_frame_size))
	goto bail;

    memset(&regs, 0, sizeof regs);
    regs.eip = where;
    regs.esp = stack_pointer;

    dprintf("Final memory map:\n");
    syslinux_dump_memmap(mmap);

    dprintf("Final available map:\n");
    syslinux_dump_memmap(amap);

    dprintf("Movelist:\n");
    syslinux_dump_movelist(ml);

    /* This should not return... */
    fputs("Booting...\n", stdout);
    syslinux_shuffle_boot_pm(ml, mmap, 0, &regs);

bail:
    if (stack_frame)
	free(stack_frame);
    syslinux_free_memmap(amap);
    syslinux_free_memmap(mmap);
    syslinux_free_movelist(ml);

    return -1;
}
Exemplo n.º 4
0
int boot_elf(void *ptr, size_t len, char **argv)
{
    char *cptr = ptr;
    Elf32_Ehdr *eh = ptr;
    Elf32_Phdr *ph;
    unsigned int i;
    struct syslinux_movelist *ml = NULL;
    struct syslinux_memmap *mmap = NULL, *amap = NULL;
    struct syslinux_pm_regs regs;
    int argc;
    addr_t argsize;
    char **argp;
    addr_t lstart, llen;
    char *stack_frame = NULL;
    addr_t stack_frame_size;
    addr_t stack_pointer;
    uint32_t *spp;
    char *sfp;
    addr_t sfa;

    memset(&regs, 0, sizeof regs);

    /*
     * 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.
     */

    if (len < sizeof(Elf32_Ehdr))
	goto bail;

    /* Must be ELF, 32-bit, littleendian, version 1 */
    if (memcmp(eh->e_ident, "\x7f" "ELF\1\1\1", 6))
	goto bail;

    /* Is this a worthwhile test?  In particular x86-64 normally
       would imply ELF64 support, which we could do as long as
       the addresses are 32-bit addresses, and entry is 32 bits.
       64-bit addresses would take a lot more work. */
    if (eh->e_machine != EM_386 && eh->e_machine != EM_486 &&
	eh->e_machine != EM_X86_64)
	goto bail;

    if (eh->e_version != EV_CURRENT)
	goto bail;

    if (eh->e_ehsize < sizeof(Elf32_Ehdr) || eh->e_ehsize >= len)
	goto bail;

    if (eh->e_phentsize < sizeof(Elf32_Phdr))
	goto bail;

    if (!eh->e_phnum)
	goto bail;

    if (eh->e_phoff + eh->e_phentsize * eh->e_phnum > len)
	goto bail;

    mmap = syslinux_memory_map();
    amap = syslinux_dup_memmap(mmap);
    if (!mmap || !amap)
	goto bail;

#if DEBUG
    dprintf("Initial memory map:\n");
    syslinux_dump_memmap(stdout, mmap);
#endif

    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 is arguably the correct semantics.
	       The SysV spec says that SysV loads at p_vaddr (and thus Linux does,
	       too); that is, however, a major brainfuckage in the spec. */
	    addr_t addr = ph->p_paddr;
	    addr_t msize = ph->p_memsz;
	    addr_t dsize = min(msize, ph->p_filesz);

	    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);
		goto bail;	/* Memory region unavailable */
	    }

	    /* Mark this region as allocated in the available map */
	    if (syslinux_add_memmap(&amap, addr, dsize, SMT_ALLOC))
		goto bail;

	    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))
		    goto bail;
	    }
	    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))
		    goto bail;
	    }
	} else {
	    /* Ignore this program header */
	}

	ph = (Elf32_Phdr *) ((char *)ph + eh->e_phentsize);
    }

    /* Create the invocation record (initial stack frame) */

    argsize = argc = 0;
    for (argp = argv; *argp; argp++) {
	dprintf("argv[%2d] = \"%s\"\n", argc, *argp);
	argc++;
	argsize += strlen(*argp) + 1;
    }

    /* We need the argument strings, argument pointers,
       argc, plus four zero-word terminators. */
    stack_frame_size = argsize + argc * sizeof(char *) + 5 * sizeof(long);
    stack_frame_size = (stack_frame_size + 15) & ~15;
    stack_frame = calloc(stack_frame_size, 1);
    if (!stack_frame)
	goto bail;

#if DEBUG
    dprintf("Right before syslinux_memmap_largest()...\n");
    syslinux_dump_memmap(stdout, amap);
#endif

    if (syslinux_memmap_largest(amap, SMT_FREE, &lstart, &llen))
	goto bail;		/* NO free memory?! */

    if (llen < stack_frame_size + MIN_STACK + 16)
	goto bail;		/* Insufficient memory  */

    /* Initial stack pointer address */
    stack_pointer = (lstart + llen - stack_frame_size) & ~15;

    dprintf("Stack frame at 0x%08x len 0x%08x\n",
	    stack_pointer, stack_frame_size);

    /* Create the stack frame.  sfp is the pointer in current memory for
       the next argument string, sfa is the address in its final resting place.
       spp is the pointer into the argument array in current memory. */
    spp = (uint32_t *) stack_frame;
    sfp = stack_frame + argc * sizeof(char *) + 5 * sizeof(long);
    sfa = stack_pointer + argc * sizeof(char *) + 5 * sizeof(long);

    *spp++ = argc;
    for (argp = argv; *argp; argp++) {
	int bytes = strlen(*argp) + 1;	/* Including final null */
	*spp++ = sfa;
	memcpy(sfp, *argp, bytes);
	sfp += bytes;
	sfa += bytes;
    }
    /* Zero fields are aready taken care of by calloc() */

    /* ... and we'll want to move it into the right place... */
#if DEBUG
    if (syslinux_memmap_type(amap, stack_pointer, stack_frame_size)
	!= SMT_FREE) {
	dprintf("Stack frame area not free (how did that happen?)!\n");
	goto bail;		/* Memory region unavailable */
    }
#endif

    if (syslinux_add_memmap(&amap, stack_pointer, stack_frame_size, SMT_ALLOC))
	goto bail;

    if (syslinux_add_movelist(&ml, stack_pointer, (addr_t) stack_frame,
			      stack_frame_size))
	goto bail;

    memset(&regs, 0, sizeof regs);
    regs.eip = eh->e_entry;
    regs.esp = stack_pointer;

#if DEBUG
    dprintf("Final memory map:\n");
    syslinux_dump_memmap(stdout, mmap);

    dprintf("Final available map:\n");
    syslinux_dump_memmap(stdout, amap);

    dprintf("Movelist:\n");
    syslinux_dump_movelist(stdout, ml);
#endif

    /* This should not return... */
    fputs("Booting...\n", stdout);
    syslinux_shuffle_boot_pm(ml, mmap, 0, &regs);

bail:
    if (stack_frame)
	free(stack_frame);
    syslinux_free_memmap(amap);
    syslinux_free_memmap(mmap);
    syslinux_free_movelist(ml);

    return -1;
}