diff options
Diffstat (limited to 'com32/lib/syslinux/load_linux.c')
-rw-r--r-- | com32/lib/syslinux/load_linux.c | 147 |
1 files changed, 106 insertions, 41 deletions
diff --git a/com32/lib/syslinux/load_linux.c b/com32/lib/syslinux/load_linux.c index 856141f8..7638e6f6 100644 --- a/com32/lib/syslinux/load_linux.c +++ b/com32/lib/syslinux/load_linux.c @@ -1,7 +1,7 @@ /* ----------------------------------------------------------------------- * * * Copyright 2007-2009 H. Peter Anvin - All Rights Reserved - * Copyright 2009-2011 Intel Corporation; author: H. Peter Anvin + * Copyright 2009-2013 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 @@ -40,11 +40,13 @@ #include <minmax.h> #include <errno.h> #include <suffix_number.h> +#include <graphics.h> +#include <dprintf.h> + #include <syslinux/align.h> #include <syslinux/linux.h> #include <syslinux/bootrm.h> #include <syslinux/movebits.h> -#include <dprintf.h> struct linux_header { uint8_t boot_sector_1[0x0020]; @@ -202,8 +204,11 @@ int syslinux_boot_linux(void *kernel_buf, size_t kernel_size, cmdline_size = strlen(cmdline) + 1; - if (kernel_size < 2 * 512) + errno = EINVAL; + if (kernel_size < 2 * 512) { + dprintf("Kernel size too small\n"); goto bail; + } /* Look for specific command-line arguments we care about */ if ((arg = find_argument(cmdline, "mem="))) @@ -234,8 +239,10 @@ int syslinux_boot_linux(void *kernel_buf, size_t kernel_size, memcpy(&hdr, kernel_buf, sizeof hdr); whdr = (struct linux_header *)kernel_buf; - if (hdr.boot_flag != BOOT_MAGIC) + if (hdr.boot_flag != BOOT_MAGIC) { + dprintf("Invalid boot magic\n"); goto bail; + } if (hdr.header != LINUX_MAGIC) { hdr.version = 0x0100; /* Very old kernel */ @@ -247,7 +254,7 @@ int syslinux_boot_linux(void *kernel_buf, size_t kernel_size, if (!hdr.setup_sects) hdr.setup_sects = 4; - if (hdr.version < 0x0203) + if (hdr.version < 0x0203 || !hdr.initrd_addr_max) hdr.initrd_addr_max = 0x37ffffff; if (!memlimit && memlimit - 1 > hdr.initrd_addr_max) @@ -285,11 +292,18 @@ int syslinux_boot_linux(void *kernel_buf, size_t kernel_size, hdr.init_size = 3 * prot_mode_size; } - if (!(hdr.loadflags & LOAD_HIGH) && prot_mode_size > 512 * 1024) - goto bail; /* Kernel cannot be loaded low */ + if (!(hdr.loadflags & LOAD_HIGH) && prot_mode_size > 512 * 1024) { + dprintf("Kernel cannot be loaded low\n"); + goto bail; + } + + /* Get the size of the initramfs, if there is one */ + irf_size = initramfs_size(initramfs); - if (initramfs && hdr.version < 0x0200) - goto bail; /* initrd/initramfs not supported */ + if (irf_size && hdr.version < 0x0200) { + dprintf("Initrd specified but not supported by kernel\n"); + goto bail; + } if (hdr.version >= 0x0200) { whdr->type_of_loader = 0x30; /* SYSLINUX unknown module */ @@ -297,21 +311,15 @@ int syslinux_boot_linux(void *kernel_buf, size_t kernel_size, whdr->heap_end_ptr = cmdline_offset - 0x0200; whdr->loadflags |= CAN_USE_HEAP; } - if (hdr.version >= 0x0202) { - whdr->cmd_line_ptr = real_mode_base + cmdline_offset; - } else { - whdr->old_cmd_line_magic = OLD_CMDLINE_MAGIC; - whdr->old_cmd_line_offset = cmdline_offset; - /* Be paranoid and round up to a multiple of 16 */ - whdr->setup_move_size = (cmdline_offset + cmdline_size + 15) & ~15; - } } /* Get the memory map */ mmap = syslinux_memory_map(); /* Memory map for shuffle_boot */ amap = syslinux_dup_memmap(mmap); /* Keep track of available memory */ - if (!mmap || !amap) + if (!mmap || !amap) { + errno = ENOMEM; goto bail; + } dprintf("Initial memory map:\n"); syslinux_dump_memmap(mmap); @@ -321,17 +329,22 @@ int syslinux_boot_linux(void *kernel_buf, size_t kernel_size, it's unavailable to the boot loader, which probably has already touched some of it), or just in the amap? */ if (memlimit) - if (syslinux_add_memmap(&amap, memlimit, -memlimit, SMT_RESERVED)) + if (syslinux_add_memmap(&amap, memlimit, -memlimit, SMT_RESERVED)) { + errno = ENOMEM; goto bail; + } /* Place the kernel in memory */ /* First, find a suitable place for the protected-mode code */ - if (syslinux_memmap_type(amap, prot_mode_base, prot_mode_size) + if (prot_mode_size && + syslinux_memmap_type(amap, prot_mode_base, prot_mode_size) != SMT_FREE) { const struct syslinux_memmap *mp; - if (!hdr.relocatable_kernel) - goto bail; /* Can't relocate - no hope */ + if (!hdr.relocatable_kernel) { + dprintf("Cannot relocate kernel\n"); + goto bail; + } ok = false; for (mp = amap; mp; mp = mp->next) { @@ -360,8 +373,10 @@ int syslinux_boot_linux(void *kernel_buf, size_t kernel_size, } } - if (!ok) + if (!ok) { + dprintf("Could not find location for protected-mode code\n"); goto bail; + } } /* Real mode code */ @@ -393,39 +408,65 @@ int syslinux_boot_linux(void *kernel_buf, size_t kernel_size, break; } } + + if (!ok) { + dprintf("Could not find location for real-mode code\n"); + goto bail; + } } if (syslinux_add_movelist(&fraglist, real_mode_base, (addr_t) kernel_buf, real_mode_size)) goto bail; if (syslinux_add_memmap - (&amap, real_mode_base, cmdline_offset + cmdline_size, SMT_ALLOC)) + (&amap, real_mode_base, cmdline_offset + cmdline_size, SMT_ALLOC)) { + errno = ENOMEM; goto bail; + } /* Zero region between real mode code and cmdline */ if (syslinux_add_memmap(&mmap, real_mode_base + real_mode_size, - cmdline_offset - real_mode_size, SMT_ZERO)) + cmdline_offset - real_mode_size, SMT_ZERO)) { + errno = ENOMEM; goto bail; + } /* Command line */ if (syslinux_add_movelist(&fraglist, real_mode_base + cmdline_offset, - (addr_t) cmdline, cmdline_size)) + (addr_t) cmdline, cmdline_size)) { + errno = ENOMEM; goto bail; + } + if (hdr.version >= 0x0202) { + whdr->cmd_line_ptr = real_mode_base + cmdline_offset; + } else { + whdr->old_cmd_line_magic = OLD_CMDLINE_MAGIC; + whdr->old_cmd_line_offset = cmdline_offset; + if (hdr.version >= 0x0200) { + /* Be paranoid and round up to a multiple of 16 */ + whdr->setup_move_size = (cmdline_offset + cmdline_size + 15) & ~15; + } + } /* Protected-mode code */ - if (syslinux_add_movelist(&fraglist, prot_mode_base, - (addr_t) kernel_buf + real_mode_size, - prot_mode_size)) - goto bail; - if (syslinux_add_memmap(&amap, prot_mode_base, prot_mode_size, SMT_ALLOC)) - goto bail; + if (prot_mode_size) { + if (syslinux_add_movelist(&fraglist, prot_mode_base, + (addr_t) kernel_buf + real_mode_size, + prot_mode_size)) { + errno = ENOMEM; + goto bail; + } + if (syslinux_add_memmap(&amap, prot_mode_base, prot_mode_size, + SMT_ALLOC)) { + errno = ENOMEM; + goto bail; + } + } /* Figure out the size of the initramfs, and where to put it. We should put it at the highest possible address which is <= hdr.initrd_addr_max, which fits the entire initramfs. */ - irf_size = initramfs_size(initramfs); /* Handles initramfs == NULL */ - if (irf_size) { addr_t best_addr = 0; struct syslinux_memmap *ml; @@ -439,17 +480,23 @@ int syslinux_boot_linux(void *kernel_buf, size_t kernel_size, best_addr = (adj_end - irf_size) & ~align_mask; } - if (!best_addr) - goto bail; /* Insufficient memory for initramfs */ + if (!best_addr) { + dprintf("Insufficient memory for initramfs\n"); + goto bail; + } whdr->ramdisk_image = best_addr; whdr->ramdisk_size = irf_size; - if (syslinux_add_memmap(&amap, best_addr, irf_size, SMT_ALLOC)) + if (syslinux_add_memmap(&amap, best_addr, irf_size, SMT_ALLOC)) { + errno = ENOMEM; goto bail; + } - if (map_initramfs(&fraglist, &mmap, initramfs, best_addr)) + if (map_initramfs(&fraglist, &mmap, initramfs, best_addr)) { + errno = ENOMEM; goto bail; + } } } @@ -485,14 +532,20 @@ int syslinux_boot_linux(void *kernel_buf, size_t kernel_size, *prev_ptr = best_addr; prev_ptr = &sdp->hdr.next; - if (syslinux_add_memmap(&amap, best_addr, size, SMT_ALLOC)) + if (syslinux_add_memmap(&amap, best_addr, size, SMT_ALLOC)) { + errno = ENOMEM; goto bail; + } if (syslinux_add_movelist(&fraglist, best_addr, - (addr_t)&sdp->hdr, sizeof sdp->hdr)) + (addr_t)&sdp->hdr, sizeof sdp->hdr)) { + errno = ENOMEM; goto bail; + } if (syslinux_add_movelist(&fraglist, best_addr + sizeof sdp->hdr, - (addr_t)sdp->data, sdp->hdr.len)) + (addr_t)sdp->data, sdp->hdr.len)) { + errno = ENOMEM; goto bail; + } } } @@ -513,7 +566,19 @@ int syslinux_boot_linux(void *kernel_buf, size_t kernel_size, dprintf("Initial movelist:\n"); syslinux_dump_movelist(fraglist); + if (video_mode != 0x0f04) { + /* + * video_mode is not "current", so if we are in graphics mode we + * need to revert to text mode... + */ + dprintf("*** Calling syslinux_force_text_mode()...\n"); + syslinux_force_text_mode(); + } else { + dprintf("*** vga=current, not calling syslinux_force_text_mode()...\n"); + } + syslinux_shuffle_boot_rm(fraglist, mmap, 0, ®s); + dprintf("shuffle_boot_rm failed\n"); bail: syslinux_free_movelist(fraglist); |