* Actually wrap the kernel image...
*/
+#include <ctype.h>
#include <stdio.h>
#include <unistd.h>
#include <getopt.h>
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)
{
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 */
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);
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;
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) {
/* 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);