From: H. Peter Anvin Date: Sat, 5 Jan 2008 00:24:47 +0000 (-0800) Subject: Handle mem= and vga= in the Linux kernel command line. X-Git-Tag: wraplinux-1.0~42 X-Git-Url: http://git.etherboot.org/wraplinux.git/commitdiff_plain/31d7fd2186ee15dbc227296affbf1b87112134e0 Handle mem= and vga= in the Linux kernel command line. --- diff --git a/linux.c b/linux.c index 93fd62e..97f0b6d 100644 --- a/linux.c +++ b/linux.c @@ -16,6 +16,7 @@ * Actually wrap the kernel image... */ +#include #include #include #include @@ -36,6 +37,66 @@ extern char reloc[]; extern uint32_t reloc_size; +/* Find the last instance of a particular command line argument + (which should include the final =; do not use for boolean arguments) */ +static const char *find_argument(const char *cmdline, const char *argument) +{ + int la = strlen(argument); + const char *p = cmdline; + int wasspace = 1; + + while (*p) { + if (wasspace && !memcmp(p, argument, la)) + return p+la; + + wasspace = isspace(*p++); + } + + return NULL; +} + +/* Truncate to 32 bits, with saturate */ +static inline uint32_t saturate32(unsigned long long v) +{ + return (v > 0xffffffff) ? 0xffffffff : (uint32_t)v; +} + +/* Get a value with a potential suffix (k/m/g/t/p/e) */ +static unsigned long long suffix_number(const char *str) +{ + char *ep; + unsigned long long v; + int shift; + + v = strtoull(str, &ep, 0); + switch (*ep|0x20) { + case 'k': + shift = 10; + break; + case 'm': + shift = 20; + break; + case 'g': + shift = 30; + break; + case 't': + shift = 40; + break; + case 'p': + shift = 50; + break; + case 'e': + shift = 60; + break; + default: + shift = 0; + break; + } + v <<= shift; + + return v; +} + int wrap_kernel(const char *kernel_file, const char *cmdline, const struct string_list *initrd_list, FILE *out) { @@ -59,6 +120,8 @@ int wrap_kernel(const char *kernel_file, const char *cmdline, const struct string_list *ip; int setup_ver; /* Setup protocol version */ int setup_space; /* How much space for the setup */ + const char *cmd; + uint32_t initrd_max; /* Process the kernel file */ @@ -88,7 +151,7 @@ int wrap_kernel(const char *kernel_file, const char *cmdline, if (setup_len == 512) setup_len += 2048; /* Really old kernel */ - if (rdle32(&hdr->header) != 0x53726448) + if (rdle32(&hdr->header) != LINUX_MAGIC) setup_ver = 0; /* Ancient kernel */ else setup_ver = rdle16(&hdr->version); @@ -106,6 +169,37 @@ int wrap_kernel(const char *kernel_file, const char *cmdline, if (setup_ver <= 0x200) initrd_list = NULL; /* No initrd for ancient kernel */ + if (setup_ver >= 0x203) + initrd_max = rdle32(&hdr->initrd_addr_max); + else + initrd_max = 0x37ffffff; + + if ((cmd = find_argument(cmdline, "mem="))) { + uint32_t mem = saturate32(suffix_number(cmd)); + if (initrd_max >= mem) + initrd_max = mem-1; + } + + if ((cmd = find_argument(cmdline, "vga="))) { + uint16_t vga; + + switch (cmd[0] | 0x20) { + case 'a': /* "ask" */ + vga = 0xfffd; + break; + case 'e': /* "ext" */ + vga = 0xfffe; + break; + case 'n': /* "normal" */ + vga = 0xffff; + break; + default: + vga = strtoul(cmd, NULL, 0); + break; + } + wrle16(vga, &hdr->vid_mode); + } + /* Process the initrd file(s) */ ninitrd = 0; @@ -182,7 +276,7 @@ int wrap_kernel(const char *kernel_file, const char *cmdline, wrle32(scmd.address, &hdr->cmd_line_ptr); } else { /* Old-style command line protocol */ - wrle16(0xA33F, (uint16_t *)(kernel+0x20)); + wrle16(OLD_CMDLINE_MAGIC, (uint16_t *)(kernel+0x20)); wrle16(scmd.address - ssup.address, (uint16_t *)(kernel+0x22)); } if (setup_ver >= 0x201) { @@ -222,10 +316,7 @@ int wrap_kernel(const char *kernel_file, const char *cmdline, /* Set up the startup info */ wrle32(ninitrd ? ird[0].seg.address : 0, &info->rd_addr); wrle32(initrd_len, &info->rd_len); - if (setup_ver >= 0x203) - wrle32(rdle32(&hdr->initrd_addr_max), &info->rd_maxaddr); - else - wrle32(0x37ffffff, &info->rd_maxaddr); + wrle32(initrd_max, &info->rd_maxaddr); wrle32(ssup.address, &info->setup_addr); wrle32(scmd.address, &info->cmdline_addr); diff --git a/setup.h b/setup.h index baf008d..a28a94c 100644 --- a/setup.h +++ b/setup.h @@ -12,6 +12,9 @@ struct startup_info { uint32_t reloc_size; }; +#define LINUX_MAGIC ('H' + ('d' << 8) + ('r' << 16) + ('S' << 24)) +#define OLD_CMDLINE_MAGIC 0xA33F + struct setup_header { uint8_t setup_sects; uint16_t root_flags;