diff options
author | H. Peter Anvin <hpa@zytor.com> | 2012-06-07 15:23:46 -0700 |
---|---|---|
committer | H. Peter Anvin <hpa@zytor.com> | 2012-06-07 15:23:46 -0700 |
commit | 83f4c75f69986637ae653cd94a37329f3841f65a (patch) | |
tree | 5f77475764db987e3a89074f4d75d5c77abd2c85 | |
parent | 4afa3c9082377c6bd96b1bde412f03ba9fa003ac (diff) | |
download | syslinux-83f4c75f69986637ae653cd94a37329f3841f65a.tar.gz syslinux-83f4c75f69986637ae653cd94a37329f3841f65a.tar.xz syslinux-83f4c75f69986637ae653cd94a37329f3841f65a.zip |
execute(): move chainbooting code to its own file
To improve readability, move chainbooting to its own source file.
Signed-off-by: H. Peter Anvin <hpa@zytor.com>
-rw-r--r-- | com32/elflink/ldlinux/Makefile | 2 | ||||
-rw-r--r-- | com32/elflink/ldlinux/chainboot.c | 175 | ||||
-rw-r--r-- | com32/elflink/ldlinux/execute.c | 137 | ||||
-rw-r--r-- | com32/include/menu.h | 3 |
4 files changed, 180 insertions, 137 deletions
diff --git a/com32/elflink/ldlinux/Makefile b/com32/elflink/ldlinux/Makefile index 75c618f6..dc48ca97 100644 --- a/com32/elflink/ldlinux/Makefile +++ b/com32/elflink/ldlinux/Makefile @@ -20,7 +20,7 @@ LIBS = --whole-archive $(com32)/lib/libcom32min.a all: ldlinux.c32 ldlinux_lnx.a ldlinux.c32 : ldlinux.o cli.o readconfig.o refstr.o colors.o getadv.o \ - adv.o execute.o kernel.o get_key.o \ + adv.o execute.o chainboot.o kernel.o get_key.o \ advwrite.o setadv.o eprintf.o loadhigh.o $(LD) $(LDFLAGS) -o $@ $^ $(LIBS) diff --git a/com32/elflink/ldlinux/chainboot.c b/com32/elflink/ldlinux/chainboot.c new file mode 100644 index 00000000..28f32808 --- /dev/null +++ b/com32/elflink/ldlinux/chainboot.c @@ -0,0 +1,175 @@ +/* ----------------------------------------------------------------------- * + * + * Copyright 2012 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. + * + * ----------------------------------------------------------------------- */ + +/* + * chainbooting - replace the current bootloader completely. This + * is BIOS-specific. + */ + +#include <stdlib.h> +#include <string.h> +#include <stdio.h> +#include <dprintf.h> + +#include <com32.h> +#include <sys/exec.h> +#include <sys/io.h> +#include "core.h" +#include "menu.h" +#include "fs.h" +#include "config.h" +#include "localboot.h" +#include "bios.h" + +#include <syslinux/bootrm.h> +#include <syslinux/movebits.h> +#include <syslinux/config.h> + +void chainboot_file(const char *file, enum kernel_type type) +{ + uint8_t keeppxe = 0; + const union syslinux_derivative_info *sdi; + struct syslinux_rm_regs regs; + struct syslinux_movelist *fraglist = NULL; + struct syslinux_memmap *mmap = NULL; + struct com32_filedata fd; + unsigned int free_mem, new_free_mem; + unsigned int edx, esi, bx; + com32sys_t reg; + char *stack; + void *buf; + int rv, max, size; + + max = 0xA0000; /* Maximum load */ + buf = malloc(max); + if (!buf) + goto bail; + + rv = open_file(file, &fd); + if (rv == -1) { + free(buf); + goto bail; + } + + reg.eax.l = max; + reg.ebx.l = 0; + reg.edx.w[0] = 0; + reg.edi.l = (uint32_t)buf; + reg.ebp.l = -1; /* XXX: limit? */ + reg.esi.w[0] = rv; + + pm_load_high(®); + + size = reg.edi.l - (unsigned long)buf; + if (size > 0xA0000 - 0x7C00) { + printf("Too large for a boostrap (need LINUX instead of KERNEL?)\n"); + goto boot_bail; + } + + esi = 0; + bx = 0; + + sdi = syslinux_derivative_info(); + edx = sdi->rr.r.edx.b[0]; + + memset(®s, 0, sizeof(regs)); + + if (sdi->c.filesystem == SYSLINUX_FS_SYSLINUX || + sdi->c.filesystem == SYSLINUX_FS_EXTLINUX) { + memcpy((void *)0x800 - 18, sdi->r.esbx, 16); + + /* DS:SI points to partition info */ + esi = 0x800 - 18; + } + + /* + * For a BSS boot sector we have to transfer the + * superblock. + */ + if (sdi->c.filesystem == SYSLINUX_FS_SYSLINUX && + type == KT_BSS && vfat_copy_superblock(buf)) + goto boot_bail; + + /* + * Set up initial stack frame (not used by PXE if + * keeppxe is set - we use the PXE stack then.) + */ + if (sdi->c.filesystem == SYSLINUX_FS_PXELINUX) { + keeppxe = 0x03; /* Chainloading + keep PXE */ + stack = (char *)sdi->r.fssi; + + /* + * Restore DS, EDX and ESI to the true initial + * values. + */ + bx = *(uint16_t *)&stack[6]; + edx = *(uint32_t *)&stack[28]; + esi = *(uint32_t *)&stack[12]; + + /* Reset stack to PXE original */ + regs.es = regs.ss = sdi->rr.r.fs; + regs.esp.w[0] = sdi->rr.r.esi.w[0] + 44; + } else { + char *esdi = (char *)sdi->disk.esdi_ptr; + + /* + * StackBuf is guaranteed to have 44 bytes + * free immediately above it, and will not + * interfere with our existing stack. + */ + stack = StackBuf; + memset(stack, 0, 44); + + regs.esp.w[0] = (uint16_t)(unsigned long)stack + 44; + + /* + * DON'T DO THIS FOR PXELINUX... + * For PXE, ES:BX -> PXENV+, and this would + * corrupt that use. + * + * Restore ES:DI -> $PnP (if we were ourselves + * called that way...) + */ + + /* New DI */ + *(uint16_t *)&stack[8] = *(uint16_t *)&esdi[0]; + + /* New ES */ + *(uint16_t *)&stack[4] = *(uint16_t *)&esdi[2]; + + } + + *(uint32_t *)&stack[28] = edx; /* New EDX */ + *(uint32_t *)&stack[12] = esi; /* New ESI */ + *(uint16_t *)&stack[6] = bx; /* New DS */ + + regs.ip = 0x7c00; + regs.esi.l = esi; + regs.edx.l = edx; + + free_mem = *(volatile unsigned int *)BIOS_fbm; + free_mem <<= 10; + new_free_mem = free_mem - (0x7c00 + size); + + mmap = syslinux_memory_map(); + if (!mmap) + goto boot_bail; + + if (!syslinux_add_movelist(&fraglist, 0x7c00, (addr_t)buf, size)) + syslinux_shuffle_boot_rm(fraglist, mmap, keeppxe, ®s); + + free(mmap); +boot_bail: + free(buf); +bail: + return; +} diff --git a/com32/elflink/ldlinux/execute.c b/com32/elflink/ldlinux/execute.c index 5e47a622..97e51168 100644 --- a/com32/elflink/ldlinux/execute.c +++ b/com32/elflink/ldlinux/execute.c @@ -53,7 +53,6 @@ void execute(const char *cmdline, enum kernel_type type) const char *kernel, *args; com32sys_t ireg; char *q; - uint8_t keeppxe = 0; memset(&ireg, 0, sizeof ireg); @@ -109,147 +108,13 @@ void execute(const char *cmdline, enum kernel_type type) } else if (type == KT_LOCALBOOT) { local_boot(strtoul(kernel, NULL, 0)); } else if (type == KT_PXE || type == KT_BSS || type == KT_BOOT) { - const union syslinux_derivative_info *sdi; - struct syslinux_rm_regs regs; - struct syslinux_movelist *fraglist = NULL; - struct syslinux_memmap *mmap = NULL; - struct com32_filedata fd; - unsigned int free_mem, new_free_mem; - unsigned int edx, esi, bx; - com32sys_t reg; - char *stack; - void *buf; - int rv, max, size; - - max = 0xA0000; /* Maximum load */ - buf = malloc(max); - if (!buf) - goto bail; - - rv = open_file(kernel, &fd); - if (rv == -1) { - free(buf); - goto bail; - } - - reg.eax.l = max; - reg.ebx.l = 0; - reg.edx.w[0] = 0; - reg.edi.l = (uint32_t)buf; - reg.ebp.l = -1; /* XXX: limit? */ - reg.esi.w[0] = rv; - - pm_load_high(®); - - size = reg.edi.l - (unsigned long)buf; - if (size > 0xA0000 - 0x7C00) { - printf("Too large for a boostrap (need LINUX instead of KERNEL?)\n"); - goto boot_bail; - } - - esi = 0; - bx = 0; - - sdi = syslinux_derivative_info(); - edx = sdi->rr.r.edx.b[0]; - - memset(®s, 0, sizeof(regs)); - - if (sdi->c.filesystem == SYSLINUX_FS_SYSLINUX || - sdi->c.filesystem == SYSLINUX_FS_EXTLINUX) { - memcpy((void *)0x800 - 18, sdi->r.esbx, 16); - - /* DS:SI points to partition info */ - esi = 0x800 - 18; - } - - /* - * For a BSS boot sector we have to transfer the - * superblock. - */ - if (sdi->c.filesystem == SYSLINUX_FS_SYSLINUX && - type == KT_BSS && vfat_copy_superblock(buf)) - goto boot_bail; - - /* - * Set up initial stack frame (not used by PXE if - * keeppxe is set - we use the PXE stack then.) - */ - if (sdi->c.filesystem == SYSLINUX_FS_PXELINUX) { - keeppxe = 0x03; /* Chainloading + keep PXE */ - stack = (char *)sdi->r.fssi; - - /* - * Restore DS, EDX and ESI to the true initial - * values. - */ - bx = *(uint16_t *)&stack[6]; - edx = *(uint32_t *)&stack[28]; - esi = *(uint32_t *)&stack[12]; - - /* Reset stack to PXE original */ - regs.es = regs.ss = sdi->rr.r.fs; - regs.esp.w[0] = sdi->rr.r.esi.w[0] + 44; - } else { - char *esdi = (char *)sdi->disk.esdi_ptr; - - /* - * StackBuf is guaranteed to have 44 bytes - * free immediately above it, and will not - * interfere with our existing stack. - */ - stack = StackBuf; - memset(stack, 0, 44); - - regs.esp.w[0] = (uint16_t)(unsigned long)stack + 44; - - /* - * DON'T DO THIS FOR PXELINUX... - * For PXE, ES:BX -> PXENV+, and this would - * corrupt that use. - * - * Restore ES:DI -> $PnP (if we were ourselves - * called that way...) - */ - - /* New DI */ - *(uint16_t *)&stack[8] = *(uint16_t *)&esdi[0]; - - /* New ES */ - *(uint16_t *)&stack[4] = *(uint16_t *)&esdi[2]; - - } - - *(uint32_t *)&stack[28] = edx; /* New EDX */ - *(uint32_t *)&stack[12] = esi; /* New ESI */ - *(uint16_t *)&stack[6] = bx; /* New DS */ - - regs.ip = 0x7c00; - regs.esi.l = esi; - regs.edx.l = edx; - - free_mem = *(volatile unsigned int *)BIOS_fbm; - free_mem <<= 10; - new_free_mem = free_mem - (0x7c00 + size); - - mmap = syslinux_memory_map(); - if (!mmap) - goto boot_bail; - - if (!syslinux_add_movelist(&fraglist, 0x7c00, - (addr_t)buf, size)) - syslinux_shuffle_boot_rm(fraglist, mmap, - keeppxe, ®s); - free(mmap); -boot_bail: - free(buf); + chainboot_file(kernel, type); } else { /* Need add one item for kernel load, as we don't use * the assembly runkernel.inc any more */ new_linux_kernel((char *)kernel, (char *)cmdline); } -bail: lfree((void *)kernel); /* If this returns, something went bad; return to menu */ diff --git a/com32/include/menu.h b/com32/include/menu.h index ba6b9ced..be2eaeb1 100644 --- a/com32/include/menu.h +++ b/com32/include/menu.h @@ -234,4 +234,7 @@ void execute(const char *cmdline, enum kernel_type type); /* drain.c */ void drain_keyboard(void); +/* chainboot.c */ +void chainboot_file(const char *file, enum kernel_type type); + #endif /* MENU_H */ |