execute(): move chainbooting code to its own file
authorH. Peter Anvin <hpa@zytor.com>
Thu, 7 Jun 2012 22:23:46 +0000 (15:23 -0700)
committerH. Peter Anvin <hpa@zytor.com>
Thu, 7 Jun 2012 22:23:46 +0000 (15:23 -0700)
To improve readability, move chainbooting to its own source file.

Signed-off-by: H. Peter Anvin <hpa@zytor.com>
com32/elflink/ldlinux/Makefile
com32/elflink/ldlinux/chainboot.c [new file with mode: 0644]
com32/elflink/ldlinux/execute.c
com32/include/menu.h

index 75c618f..dc48ca9 100644 (file)
@@ -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 (file)
index 0000000..28f3280
--- /dev/null
@@ -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(&reg);
+
+    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(&regs, 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, &regs);
+
+    free(mmap);
+boot_bail:
+    free(buf);
+bail:
+    return;
+}
index 5e47a62..97e5116 100644 (file)
@@ -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(&reg);
-
-               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(&regs, 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, &regs);
-               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 */
index ba6b9ce..be2eaeb 100644 (file)
@@ -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 */