diff options
author | Matt Fleming <matt.fleming@intel.com> | 2012-05-01 08:55:45 +0100 |
---|---|---|
committer | Matt Fleming <matt.fleming@intel.com> | 2012-06-07 14:19:20 +0100 |
commit | c0d18deeee22f3466fd863d64b432660965ec66e (patch) | |
tree | 8fce613ef56efd6d112ede4e394051a99490a66f | |
parent | 4fc3fd1e14f4c1b9208ef262e5b6aef853e9fce4 (diff) | |
download | syslinux-c0d18deeee22f3466fd863d64b432660965ec66e.tar.gz syslinux-c0d18deeee22f3466fd863d64b432660965ec66e.tar.xz syslinux-c0d18deeee22f3466fd863d64b432660965ec66e.zip |
elflink: Fix boot sector booting
This adds missing support for booting from a boot sector file such as
.bs, .bss or .0, by re-implementing the old asm bootsec code from
core/bootsect.inc in C.
This has resulted in some external changes. We've had to make StackBuf
a global symbol because we access it directly from execute.c. Also, we
need to move dsinfo.c into MINLIBOBJS because ldlinux now needs to
reference __syslinux_derivative_info.
Signed-off-by: Matt Fleming <matt.fleming@intel.com>
-rw-r--r-- | com32/elflink/ldlinux/Makefile | 2 | ||||
-rw-r--r-- | com32/elflink/ldlinux/config.h | 2 | ||||
-rw-r--r-- | com32/elflink/ldlinux/execute.c | 143 | ||||
-rw-r--r-- | com32/elflink/ldlinux/loadhigh.c (renamed from core/fs/loadhigh.c) | 2 | ||||
-rw-r--r-- | com32/lib/Makefile | 3 | ||||
-rw-r--r-- | core/diskboot.inc | 1 | ||||
-rw-r--r-- | core/fs/fat/fat.c | 28 | ||||
-rw-r--r-- | core/include/core.h | 1 | ||||
-rw-r--r-- | core/include/fs.h | 3 | ||||
-rw-r--r-- | core/isolinux.asm | 1 | ||||
-rw-r--r-- | core/pxelinux.asm | 1 |
11 files changed, 184 insertions, 3 deletions
diff --git a/com32/elflink/ldlinux/Makefile b/com32/elflink/ldlinux/Makefile index ca4c7e25..75c618f6 100644 --- a/com32/elflink/ldlinux/Makefile +++ b/com32/elflink/ldlinux/Makefile @@ -21,7 +21,7 @@ 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 \ - advwrite.o setadv.o eprintf.o + advwrite.o setadv.o eprintf.o loadhigh.o $(LD) $(LDFLAGS) -o $@ $^ $(LIBS) LNXLIBOBJS = get_key.lo diff --git a/com32/elflink/ldlinux/config.h b/com32/elflink/ldlinux/config.h index b15a0828..45832022 100644 --- a/com32/elflink/ldlinux/config.h +++ b/com32/elflink/ldlinux/config.h @@ -45,4 +45,6 @@ extern void eprintf(const char *filename, ...); extern int new_linux_kernel(char *okernel, char *ocmdline); +extern void pm_load_high(com32sys_t *regs); + #endif /* __CONFIG_H__ */ diff --git a/com32/elflink/ldlinux/execute.c b/com32/elflink/ldlinux/execute.c index afe999e2..dd9854e1 100644 --- a/com32/elflink/ldlinux/execute.c +++ b/com32/elflink/ldlinux/execute.c @@ -17,10 +17,16 @@ #include <com32.h> #include <sys/exec.h> +#include <sys/io.h> #include "core.h" #include "menu.h" #include "fs.h" #include "config.h" +#include "bios.h" + +#include <syslinux/bootrm.h> +#include <syslinux/movebits.h> +#include <syslinux/config.h> /* Must match enum kernel_type */ const char *const kernel_types[] = { @@ -46,6 +52,7 @@ 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); @@ -103,12 +110,148 @@ void execute(const char *cmdline, enum kernel_type type) ireg.eax.w[0] = 0x0014; /* Local boot */ ireg.edx.w[0] = strtoul(kernel, NULL, 0); __intcall(0x22, &ireg, NULL); + } 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); } 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/core/fs/loadhigh.c b/com32/elflink/ldlinux/loadhigh.c index bd9d3535..0f2f8428 100644 --- a/core/fs/loadhigh.c +++ b/com32/elflink/ldlinux/loadhigh.c @@ -37,7 +37,7 @@ #include "core.h" #include "fs.h" -#define MAX_CHUNK (1 << 20) /* 1 MB */ +#define MAX_CHUNK (1UL << 20) /* 1 MB */ void pm_load_high(com32sys_t *regs) { diff --git a/com32/lib/Makefile b/com32/lib/Makefile index a0ddb9d6..4edf0a41 100644 --- a/com32/lib/Makefile +++ b/com32/lib/Makefile @@ -47,7 +47,7 @@ LIBPCI_OBJS = \ LIBSYSLINUX_OBJS = \ syslinux/reboot.o syslinux/keyboard.o \ syslinux/features.o syslinux/config.o \ - syslinux/dsinfo.o syslinux/version.o \ + syslinux/version.o \ syslinux/pxe_get_cached.o syslinux/pxe_get_nic.o \ syslinux/video/fontquery.o syslinux/video/reportmode.o @@ -178,6 +178,7 @@ CORELIBOBJS = \ MINLIBOBJS = \ syslinux/ipappend.o \ + syslinux/dsinfo.o \ $(LIBOTHER_OBJS) \ $(LIBGCC_OBJS) \ $(LIBCONSOLE_OBJS) \ diff --git a/core/diskboot.inc b/core/diskboot.inc index 141986e8..3e42044a 100644 --- a/core/diskboot.inc +++ b/core/diskboot.inc @@ -28,6 +28,7 @@ ; reduce the code size... ; + global StackBuf StackBuf equ STACK_TOP-44-92 ; Start the stack here (grow down - 4K) PartInfo equ StackBuf .mbr equ PartInfo diff --git a/core/fs/fat/fat.c b/core/fs/fat/fat.c index fbc4386b..2c8dc315 100644 --- a/core/fs/fat/fat.c +++ b/core/fs/fat/fat.c @@ -779,6 +779,34 @@ static int vfat_fs_init(struct fs_info *fs) return fs->block_shift; } +int vfat_copy_superblock(void *buf) +{ + struct fat_bpb fat; + struct disk *disk; + size_t sb_off; + void *dst; + int sb_len; + + disk = this_fs->fs_dev->disk; + disk->rdwr_sectors(disk, &fat, 0, 1, 0); + + /* XXX: Find better sanity checks... */ + if (!fat.bxResSectors || !fat.bxFATs) + return -1; + + sb_off = offsetof(struct fat_bpb, sector_size); + sb_len = offsetof(struct fat_bpb, fat12_16) - sb_off \ + + sizeof(fat.fat12_16); + + /* + * Only copy fields of the superblock we actually care about. + */ + dst = buf + sb_off; + memcpy(dst, (void *)&fat + sb_off, sb_len); + + return 0; +} + const struct fs_ops vfat_fs_ops = { .fs_name = "vfat", .fs_flags = FS_USEMEM | FS_THISIND, diff --git a/core/include/core.h b/core/include/core.h index 7d36e982..e19f2f1e 100644 --- a/core/include/core.h +++ b/core/include/core.h @@ -24,6 +24,7 @@ extern char cmd_line[]; extern char ConfigFile[]; extern char syslinux_banner[]; extern char copyright_str[]; +extern char StackBuf[]; extern uint8_t KbdMap[256]; diff --git a/core/include/fs.h b/core/include/fs.h index 40ca09a4..481e085c 100644 --- a/core/include/fs.h +++ b/core/include/fs.h @@ -234,4 +234,7 @@ uint32_t generic_getfssec(struct file *file, char *buf, /* nonextextent.c */ int no_next_extent(struct inode *, uint32_t); +/* fat.c */ +int vfat_copy_superblock(void *buf); + #endif /* FS_H */ diff --git a/core/isolinux.asm b/core/isolinux.asm index 6e52736b..4790887c 100644 --- a/core/isolinux.asm +++ b/core/isolinux.asm @@ -167,6 +167,7 @@ _spec_len equ _spec_end - _spec_start ;; CD-ROM sector (2K) of the file, so the number one priority is actually ;; loading the rest. ;; + global StackBuf StackBuf equ STACK_TOP-44 ; 44 bytes needed for ; the bootsector chainloading ; code! diff --git a/core/pxelinux.asm b/core/pxelinux.asm index e59a0e2e..5f72809e 100644 --- a/core/pxelinux.asm +++ b/core/pxelinux.asm @@ -89,6 +89,7 @@ LocalBootType resw 1 ; Local boot return code DHCPMagic resb 1 ; PXELINUX magic flags section .text16 + global StackBuf StackBuf equ STACK_TOP-44 ; Base of stack if we use our own StackHome equ StackBuf |