diff options
Diffstat (limited to 'com32/elflink/ldlinux/kernel.c')
-rw-r--r-- | com32/elflink/ldlinux/kernel.c | 131 |
1 files changed, 131 insertions, 0 deletions
diff --git a/com32/elflink/ldlinux/kernel.c b/com32/elflink/ldlinux/kernel.c new file mode 100644 index 0000000..f3ba37f --- /dev/null +++ b/com32/elflink/ldlinux/kernel.c @@ -0,0 +1,131 @@ +#include <stdbool.h> +#include <stdlib.h> +#include <stdio.h> +#include <string.h> +#include <console.h> +#include <dprintf.h> +#include <syslinux/loadfile.h> +#include <syslinux/linux.h> +#include <syslinux/pxe.h> +#include "core.h" + +const char *globaldefault = NULL; +const char *append = NULL; + +/* Will be called from readconfig.c */ +int new_linux_kernel(char *okernel, char *ocmdline) +{ + const char *kernel_name = NULL, *args = NULL; + struct initramfs *initramfs = NULL; + char *temp; + void *kernel_data; + size_t kernel_len, cmdline_len; + bool opt_quiet = false; + char *initrd_name, *cmdline; + + dprintf("okernel = %s, ocmdline = %s", okernel, ocmdline); + + if (okernel) + kernel_name = okernel; + else if (globaldefault) + kernel_name = globaldefault; + + if (ocmdline) + args = ocmdline; + else if (append) + args = append; + + cmdline_len = strlen("BOOT_IMAGE=") + strlen(kernel_name); + cmdline_len += 1; /* space between BOOT_IMAGE and args */ + cmdline_len += strlen(args); + cmdline_len += 1; /* NUL-termination */ + + cmdline = malloc(cmdline_len); + if (!cmdline) { + printf("Failed to alloc memory for cmdline\n"); + return 1; + } + + sprintf(cmdline, "BOOT_IMAGE=%s %s", kernel_name, args); + + /* "keeppxe" handling */ +#if IS_PXELINUX + extern char KeepPXE; + + if (strstr(cmdline, "keeppxe")) + KeepPXE |= 1; +#endif + + if (strstr(cmdline, "quiet")) + opt_quiet = true; + + if (!opt_quiet) + printf("Loading %s... ", kernel_name); + + if (loadfile(kernel_name, &kernel_data, &kernel_len)) { + if (opt_quiet) + printf("Loading %s ", kernel_name); + printf("failed: "); + goto bail; + } + + if (!opt_quiet) + printf("ok\n"); + + /* Find and load initramfs */ + temp = strstr(cmdline, "initrd="); + if (temp) { + /* Initialize the initramfs chain */ + initramfs = initramfs_init(); + if (!initramfs) + goto bail; + + temp += 6; /* strlen("initrd") */ + do { + size_t n = 0; + char *p; + + temp++; /* Skip = or , */ + + p = temp; + while (*p != ' ' && *p != ',' && *p) { + p++; + n++; + } + + initrd_name = malloc(n + 1); + if (!initrd_name) { + printf("Failed to allocate space for initrd\n"); + goto bail; + } + + snprintf(initrd_name, n + 1, "%s", temp); + temp += n; + + if (!opt_quiet) + printf("Loading %s...", initrd_name); + + if (initramfs_load_archive(initramfs, initrd_name)) { + if (opt_quiet) + printf("Loading %s ", initrd_name); + free(initrd_name); + printf("failed: "); + goto bail; + } + + free(initrd_name); + + if (!opt_quiet) + printf("ok\n"); + } while (*temp == ','); + } + + /* This should not return... */ + syslinux_boot_linux(kernel_data, kernel_len, initramfs, NULL, cmdline); + printf("Booting kernel failed: "); + +bail: + free(cmdline); + printf("%s\n", strerror(errno)); + return 1; +} |