move core/elflink over
authorFeng Tang <feng.tang@intel.com>
Tue, 1 Jun 2010 08:18:42 +0000 (16:18 +0800)
committerFeng Tang <feng.tang@intel.com>
Tue, 20 Jul 2010 03:10:03 +0000 (11:10 +0800)
23 files changed:
MCONFIG.devel [deleted file]
core/elflink/abort_new.c [new file with mode: 0644]
core/elflink/adv.c [new file with mode: 0644]
core/elflink/advwrite.c [new file with mode: 0644]
core/elflink/cli.c [new file with mode: 0644]
core/elflink/cli.h [new file with mode: 0644]
core/elflink/colors.c [new file with mode: 0644]
core/elflink/common.h [new file with mode: 0644]
core/elflink/config.c [new file with mode: 0644]
core/elflink/core-elf.h [new file with mode: 0644]
core/elflink/elfutils.h [new file with mode: 0644]
core/elflink/execute.c [new file with mode: 0644]
core/elflink/get_key.c [new file with mode: 0644]
core/elflink/getadv.c [new file with mode: 0644]
core/elflink/getkey.h [new file with mode: 0644]
core/elflink/ipappend.c [new file with mode: 0644]
core/elflink/kernel.c [new file with mode: 0644]
core/elflink/load_env32.c [new file with mode: 0644]
core/elflink/menu.h [new file with mode: 0644]
core/elflink/readconfig.c [new file with mode: 0644]
core/elflink/refstr.c [new file with mode: 0644]
core/elflink/refstr.h [new file with mode: 0644]
core/elflink/setadv.c [new file with mode: 0644]

diff --git a/MCONFIG.devel b/MCONFIG.devel
deleted file mode 100644 (file)
index 104207f..0000000
+++ /dev/null
@@ -1,2 +0,0 @@
-# Useful while doing development, but not for production.
-GCCWARN += -Wno-clobbered -Werror
diff --git a/core/elflink/abort_new.c b/core/elflink/abort_new.c
new file mode 100644 (file)
index 0000000..39ba226
--- /dev/null
@@ -0,0 +1,29 @@
+#include <stdbool.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <console.h>
+
+//#include <syslinux/loadfile.h>
+//#include <syslinux/linux.h>
+//#include <syslinux/pxe.h>
+
+#include "core.h"
+#include "core-elf.h"
+#include "menu.h"
+
+void abort_load_new(com32sys_t *reg)
+{
+       char *str;
+
+       str = (void *)reg->esi.l;
+
+       printf("Error!\n");
+       if (str)
+               printf("%s\n", str);
+
+       if (onerrorlen)
+               execute(start_menu->onerror, KT_NONE);
+       enter_cmdline();
+       return;
+}
diff --git a/core/elflink/adv.c b/core/elflink/adv.c
new file mode 100644 (file)
index 0000000..be38e89
--- /dev/null
@@ -0,0 +1,49 @@
+/* ----------------------------------------------------------------------- *
+ *
+ *   Copyright 2007-2008 H. Peter Anvin - All Rights Reserved
+ *
+ *   Permission is hereby granted, free of charge, to any person
+ *   obtaining a copy of this software and associated documentation
+ *   files (the "Software"), to deal in the Software without
+ *   restriction, including without limitation the rights to use,
+ *   copy, modify, merge, publish, distribute, sublicense, and/or
+ *   sell copies of the Software, and to permit persons to whom
+ *   the Software is furnished to do so, subject to the following
+ *   conditions:
+ *
+ *   The above copyright notice and this permission notice shall
+ *   be included in all copies or substantial portions of the Software.
+ *
+ *   THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ *   EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+ *   OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ *   NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+ *   HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+ *   WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ *   FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ *   OTHER DEALINGS IN THE SOFTWARE.
+ *
+ * ----------------------------------------------------------------------- */
+
+/*
+ * syslinux/adv.c
+ *
+ * Access the syslinux auxilliary data vector
+ */
+
+#include <syslinux/adv.h>
+#include <klibc/compiler.h>
+#include <com32.h>
+
+void *__syslinux_adv_ptr;
+size_t __syslinux_adv_size;
+
+void __constructor __syslinux_get_adv(void)
+{
+    static com32sys_t reg;
+
+    reg.eax.w[0] = 0x001c;
+    __intcall(0x22, &reg, &reg);
+    __syslinux_adv_ptr = MK_PTR(reg.es, reg.ebx.w[0]);
+    __syslinux_adv_size = reg.ecx.w[0];
+}
diff --git a/core/elflink/advwrite.c b/core/elflink/advwrite.c
new file mode 100644 (file)
index 0000000..4152eea
--- /dev/null
@@ -0,0 +1,45 @@
+/* ----------------------------------------------------------------------- *
+ *
+ *   Copyright 2007-2008 H. Peter Anvin - All Rights Reserved
+ *
+ *   Permission is hereby granted, free of charge, to any person
+ *   obtaining a copy of this software and associated documentation
+ *   files (the "Software"), to deal in the Software without
+ *   restriction, including without limitation the rights to use,
+ *   copy, modify, merge, publish, distribute, sublicense, and/or
+ *   sell copies of the Software, and to permit persons to whom
+ *   the Software is furnished to do so, subject to the following
+ *   conditions:
+ *
+ *   The above copyright notice and this permission notice shall
+ *   be included in all copies or substantial portions of the Software.
+ *
+ *   THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ *   EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+ *   OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ *   NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+ *   HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+ *   WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ *   FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ *   OTHER DEALINGS IN THE SOFTWARE.
+ *
+ * ----------------------------------------------------------------------- */
+
+/*
+ * syslinux/advwrite.c
+ *
+ * Write back the ADV
+ */
+
+#include <syslinux/adv.h>
+#include <klibc/compiler.h>
+#include <com32.h>
+
+int syslinux_adv_write(void)
+{
+    static com32sys_t reg;
+
+    reg.eax.w[0] = 0x001d;
+    __intcall(0x22, &reg, &reg);
+    return (reg.eflags.l & EFLAGS_CF) ? -1 : 0;
+}
diff --git a/core/elflink/cli.c b/core/elflink/cli.c
new file mode 100644 (file)
index 0000000..2e223ae
--- /dev/null
@@ -0,0 +1,406 @@
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <console.h>
+#include <com32.h>
+#include <syslinux/adv.h>
+#include <syslinux/config.h>
+#include <setjmp.h>
+#include <netinet/in.h>
+#include <limits.h>
+#include <minmax.h>
+#include <linux/list.h>
+#include <sys/exec.h>
+#include <sys/module.h>
+#include "getkey.h"
+
+#include "common.h"
+#include "menu.h"
+#include "cli.h"
+
+void clear_screen(void)
+{
+    fputs("\033e\033%@\033)0\033(B\1#0\033[?25l\033[2J", stdout);
+}
+
+int mygetkey(clock_t timeout)
+{
+    clock_t t0, t;
+    clock_t tto, to;
+    int key;
+
+    if (!totaltimeout)
+       return get_key(stdin, timeout);
+
+    for (;;) {
+       tto = min(totaltimeout, INT_MAX);
+       to = timeout ? min(tto, timeout) : tto;
+
+       t0 = times(NULL);
+       key = get_key(stdin, to);
+       t = times(NULL) - t0;
+
+       if (totaltimeout <= t)
+           longjmp(timeout_jump, 1);
+
+       totaltimeout -= t;
+
+       if (key != KEY_NONE)
+           return key;
+
+       if (timeout) {
+           if (timeout <= t)
+               return KEY_NONE;
+
+           timeout -= t;
+       }
+    }
+}
+
+const char *edit_cmdline(const char *input, int top /*, int width */ ,
+                        int (*pDraw_Menu) (int, int, int),
+                        void (*show_fkey) (int))
+{
+    static char cmdline[MAX_CMDLINE_LEN];
+    char temp_cmdline[MAX_CMDLINE_LEN] = { };
+    int key, len, prev_len, cursor;
+    int redraw = 1;            /* We enter with the menu already drawn */
+    int x, y;
+    bool done = false;
+    const char *ret;
+    int width = 0;
+    struct cli_command *comm_counter;
+    comm_counter =
+       list_entry(cli_history_head.next->prev, typeof(*comm_counter), list);
+
+    if (!width) {
+       int height;
+       if (getscreensize(1, &height, &width))
+           width = 80;
+    }
+    //printf("width = %d\n", width);
+
+    strncpy(cmdline, input, MAX_CMDLINE_LEN);
+    cmdline[MAX_CMDLINE_LEN - 1] = '\0';
+
+    len = cursor = strlen(cmdline);
+    prev_len = 0;
+    x = y = 0;
+
+    while (!done) {
+       if (redraw > 1 && pDraw_Menu != NULL) {
+           /* Clear and redraw whole screen */
+           /* Enable ASCII on G0 and DEC VT on G1; do it in this order
+              to avoid confusing the Linux console */
+           /* clear_screen();
+              draw_menu(-1, top, 1); */
+           clear_screen();
+           (*pDraw_Menu) (-1, top, 1);
+           prev_len = 0;
+           // printf("\033[0m\033[2J\033[H");
+       }
+
+       if (redraw > 0) {
+           int dy, at;
+
+           prev_len = max(len, prev_len);
+
+           /* Redraw the command line */
+           printf("\033[?7l\033[?25l");
+           if (y)
+               printf("\033[%dA", y);
+           printf("\033[1G\033[1;36m> \033[0m");
+
+           x = 2;
+           y = 0;
+           at = 0;
+           while (at < prev_len) {
+               putchar(at >= len ? ' ' : cmdline[at]);
+               at++;
+               x++;
+               if (x >= width) {
+                   printf("\r\n");
+                   x = 0;
+                   y++;
+               }
+           }
+           printf("\033[K\r");
+
+           dy = y - (cursor + 2) / width;
+           x = (cursor + 2) % width;
+
+           if (dy) {
+               printf("\033[%dA", dy);
+               y -= dy;
+           }
+           if (x)
+               printf("\033[%dC", x);
+           printf("\033[?25h");
+           prev_len = len;
+           redraw = 0;
+       }
+
+       key = mygetkey(0);
+
+       switch (key) {
+       case KEY_CTRL('L'):
+           redraw = 2;
+           break;
+
+       case KEY_ENTER:
+       case KEY_CTRL('J'):
+           ret = cmdline;
+           done = true;
+           break;
+
+       case KEY_ESC:
+       case KEY_CTRL('C'):
+           ret = NULL;
+           done = true;
+           break;
+
+       case KEY_BACKSPACE:
+       case KEY_DEL:
+           if (cursor) {
+               memmove(cmdline + cursor - 1, cmdline + cursor,
+                       len - cursor + 1);
+               len--;
+               cursor--;
+               redraw = 1;
+           }
+           break;
+
+       case KEY_CTRL('D'):
+       case KEY_DELETE:
+           if (cursor < len) {
+               memmove(cmdline + cursor, cmdline + cursor + 1, len - cursor);
+               len--;
+               redraw = 1;
+           }
+           break;
+
+       case KEY_CTRL('U'):
+           if (len) {
+               len = cursor = 0;
+               cmdline[len] = '\0';
+               redraw = 1;
+           }
+           break;
+
+       case KEY_CTRL('W'):
+           if (cursor) {
+               int prevcursor = cursor;
+
+               while (cursor && my_isspace(cmdline[cursor - 1]))
+                   cursor--;
+
+               while (cursor && !my_isspace(cmdline[cursor - 1]))
+                   cursor--;
+
+#if 0
+               memmove(cmdline + cursor, cmdline + prevcursor,
+                       len - prevcursor + 1);
+#else
+               {
+                   int i;
+                   char *q = cmdline + cursor;
+                   char *p = cmdline + prevcursor;
+                   for (i = 0; i < len - prevcursor + 1; i++)
+                       *q++ = *p++;
+               }
+#endif
+               len -= (prevcursor - cursor);
+               redraw = 1;
+           }
+           break;
+
+       case KEY_LEFT:
+       case KEY_CTRL('B'):
+           if (cursor) {
+               cursor--;
+               redraw = 1;
+           }
+           break;
+
+       case KEY_RIGHT:
+       case KEY_CTRL('F'):
+           if (cursor < len) {
+               putchar(cmdline[cursor]);
+               cursor++;
+               x++;
+               if (x >= width) {
+                   printf("\r\n");
+                   y++;
+                   x = 0;
+               }
+           }
+           break;
+
+       case KEY_CTRL('K'):
+           if (cursor < len) {
+               cmdline[len = cursor] = '\0';
+               redraw = 1;
+           }
+           break;
+
+       case KEY_HOME:
+       case KEY_CTRL('A'):
+           if (cursor) {
+               cursor = 0;
+               redraw = 1;
+           }
+           break;
+
+       case KEY_END:
+       case KEY_CTRL('E'):
+           if (cursor != len) {
+               cursor = len;
+               redraw = 1;
+           }
+           break;
+
+       case KEY_F1:
+       case KEY_F2:
+       case KEY_F3:
+       case KEY_F4:
+       case KEY_F5:
+       case KEY_F6:
+       case KEY_F7:
+       case KEY_F8:
+       case KEY_F9:
+       case KEY_F10:
+       case KEY_F11:
+       case KEY_F12:
+           if (show_fkey != NULL) {
+               (*show_fkey) (key);
+               redraw = 1;
+           }
+           break;
+       case KEY_UP:
+           {
+               if (!list_empty(&cli_history_head)) {
+                   comm_counter =
+                       list_entry(comm_counter->list.next,
+                                  typeof(*comm_counter), list);
+                   if (&comm_counter->list == &cli_history_head) {
+                       strcpy(cmdline, temp_cmdline);
+                   } else {
+                       strcpy(cmdline, comm_counter->command);
+                   }
+                   cursor = len = strlen(cmdline);
+                   redraw = 1;
+               }
+           }
+           break;
+       case KEY_DOWN:
+           {
+               if (!list_empty(&cli_history_head)) {
+                   comm_counter =
+                       list_entry(comm_counter->list.prev,
+                                  typeof(*comm_counter), list);
+                   if (&comm_counter->list == &cli_history_head) {
+                       strcpy(cmdline, temp_cmdline);
+                   } else {
+                       strcpy(cmdline, comm_counter->command);
+                   }
+                   cursor = len = strlen(cmdline);
+                   redraw = 1;
+               }
+           }
+           break;
+       default:
+           if (key >= ' ' && key <= 0xFF && len < MAX_CMDLINE_LEN - 1) {
+               if (cursor == len) {
+                   temp_cmdline[len] = key;
+                   cmdline[len++] = key;
+                   temp_cmdline[len] = cmdline[len] = '\0';
+                   putchar(key);
+                   cursor++;
+                   x++;
+                   if (x >= width) {
+                       printf("\r\n\033[K");
+                       y++;
+                       x = 0;
+                   }
+                   prev_len++;
+               } else {
+                   memmove(cmdline + cursor + 1, cmdline + cursor,
+                           len - cursor + 1);
+                   memmove(temp_cmdline + cursor + 1, temp_cmdline + cursor,
+                           len - cursor + 1);
+                   temp_cmdline[cursor] = key;
+                   cmdline[cursor++] = key;
+                   len++;
+                   redraw = 1;
+               }
+           }
+           break;
+       }
+    }
+
+    printf("\033[?7h");
+    return ret;
+}
+
+void process_command(const char *cmd)
+{
+       char **argv = malloc((MAX_COMMAND_ARGS + 1) * sizeof(char *));
+       char *temp_cmd = (char *)malloc(sizeof(char) * (strlen(cmd) + 1));
+       int argc = 1, len_mn;
+       char *crt_arg, *module_name;
+
+       /* return if user only press enter */
+       if (cmd[0] == '\0') {
+               printf("\n");
+               return;
+       }
+
+       strcpy(temp_cmd, cmd);
+       module_name = strtok(cmd, COMMAND_DELIM);
+       len_mn = strlen(module_name);
+
+       printf("\n");
+       mp("enter, cmd = %s, module_name = %s",cmd, module_name);
+
+       if (!strcmp(module_name + len_mn - 4, ".c32")) {
+               if (module_find(module_name) != NULL) {
+                       /* make module re-enterable */
+                       mp("Module %s is already running");
+                       //goto cleanup;
+               }
+               do {
+                       argv[0] = module_name;
+                       crt_arg = strtok(NULL, COMMAND_DELIM);
+                       if (crt_arg != NULL && strlen(crt_arg) > 0) {
+                               argv[argc] = crt_arg;
+                               argc++;
+                       } else
+                               break;
+               } while (argc < MAX_COMMAND_ARGS);
+               argv[argc] = NULL;
+               module_load_dependencies(module_name, MODULES_DEP);
+               spawn_load(module_name, argv);
+       } else if (!strcmp(module_name + len_mn - 2, ".0")) {
+               execute(cmd, KT_PXE);
+       } else if (!strcmp(module_name + len_mn - 3, ".bs")) {
+       } else if (!strcmp(module_name + len_mn - 4, ".img")) {
+               execute(cmd, KT_FDIMAGE);
+       } else if (!strcmp(module_name + len_mn - 4, ".bin")) {
+       } else if (!strcmp(module_name + len_mn - 4, ".bss")) {
+               execute(cmd, KT_BSS);
+       } else if (!strcmp(module_name + len_mn - 4, ".com")
+              || !strcmp(module_name + len_mn - 4, ".cbt")) {
+               execute(cmd, KT_COMBOOT);
+       } else if (!strcmp(module_name + len_mn - 4, ".cfg")
+              || !strcmp(module_name + len_mn - 5, ".conf")
+              || !strcmp(module_name + len_mn - 7, ".config")) {
+               execute(module_name, KT_CONFIG);
+       }
+       /* use KT_KERNEL as default */
+       else
+               execute(temp_cmd, KT_KERNEL);
+
+cleanup:
+       free(argv);
+       free(temp_cmd);
+}
diff --git a/core/elflink/cli.h b/core/elflink/cli.h
new file mode 100644 (file)
index 0000000..9cd8c16
--- /dev/null
@@ -0,0 +1,23 @@
+#ifndef CLI_H
+#define CLI_H
+
+#define MAX_CMD_HISTORY 64
+#define COMMAND_DELIM          " \t\n" // Whitespace delimiters
+#define MAX_COMMAND_ARGS       40
+
+struct cli_command {
+    struct list_head list;
+    char *command;
+};
+
+struct list_head cli_history_head;
+
+extern void clear_screen(void);
+extern int mygetkey(clock_t timeout);
+extern const char *edit_cmdline(const char *input, int top /*, int width */ ,
+                               int (*pDraw_Menu) (int, int, int),
+                               void (*show_fkey) (int));
+extern void process_command(const char *cmd);
+
+extern struct menu *root_menu, *start_menu, *hide_menu, *menu_list, *default_menu;
+#endif
diff --git a/core/elflink/colors.c b/core/elflink/colors.c
new file mode 100644 (file)
index 0000000..68732bd
--- /dev/null
@@ -0,0 +1,184 @@
+/* ----------------------------------------------------------------------- *
+ *
+ *   Copyright 2004-2008 H. Peter Anvin - All Rights Reserved
+ *
+ *   This program is free software; you can redistribute it and/or modify
+ *   it under the terms of the GNU General Public License as published by
+ *   the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
+ *   Boston MA 02110-1301, USA; either version 2 of the License, or
+ *   (at your option) any later version; incorporated herein by reference.
+ *
+ * ----------------------------------------------------------------------- */
+
+#include <stdlib.h>
+#include <string.h>
+#include <stdio.h>
+#include <colortbl.h>
+#include "menu.h"
+
+/*
+ * The color/attribute indexes (\1#X, \2#XX, \3#XXX) are as follows
+ *
+ * 00 - screen         Rest of the screen
+ * 01 - border         Border area
+ * 02 - title          Title bar
+ * 03 - unsel          Unselected menu item
+ * 04 - hotkey         Unselected hotkey
+ * 05 - sel            Selection bar
+ * 06 - hotsel         Selected hotkey
+ * 07 - scrollbar      Scroll bar
+ * 08 - tabmsg         Press [Tab] message
+ * 09 - cmdmark                Command line marker
+ * 10 - cmdline                Command line
+ * 11 - pwdborder      Password box border
+ * 12 - pwdheader      Password box header
+ * 13 - pwdentry       Password box contents
+ * 14 - timeout_msg    Timeout message
+ * 15 - timeout                Timeout counter
+ * 16 - help           Current entry help text
+ * 17 - disabled        Disabled menu item
+ */
+
+static const struct color_table default_colors[] = {
+    {"screen", "37;40", 0x80ffffff, 0x00000000, SHADOW_NORMAL},
+    {"border", "30;44", 0x40000000, 0x00000000, SHADOW_NORMAL},
+    {"title", "1;36;44", 0xc00090f0, 0x00000000, SHADOW_NORMAL},
+    {"unsel", "37;44", 0x90ffffff, 0x00000000, SHADOW_NORMAL},
+    {"hotkey", "1;37;44", 0xffffffff, 0x00000000, SHADOW_NORMAL},
+    {"sel", "7;37;40", 0xe0000000, 0x20ff8000, SHADOW_ALL},
+    {"hotsel", "1;7;37;40", 0xe0400000, 0x20ff8000, SHADOW_ALL},
+    {"scrollbar", "30;44", 0x40000000, 0x00000000, SHADOW_NORMAL},
+    {"tabmsg", "31;40", 0x90ffff00, 0x00000000, SHADOW_NORMAL},
+    {"cmdmark", "1;36;40", 0xc000ffff, 0x00000000, SHADOW_NORMAL},
+    {"cmdline", "37;40", 0xc0ffffff, 0x00000000, SHADOW_NORMAL},
+    {"pwdborder", "30;47", 0x80ffffff, 0x20ffffff, SHADOW_NORMAL},
+    {"pwdheader", "31;47", 0x80ff8080, 0x20ffffff, SHADOW_NORMAL},
+    {"pwdentry", "30;47", 0x80ffffff, 0x20ffffff, SHADOW_NORMAL},
+    {"timeout_msg", "37;40", 0x80ffffff, 0x00000000, SHADOW_NORMAL},
+    {"timeout", "1;37;40", 0xc0ffffff, 0x00000000, SHADOW_NORMAL},
+    {"help", "37;40", 0xc0ffffff, 0x00000000, SHADOW_NORMAL},
+    {"disabled", "1;30;44", 0x60cccccc, 0x00000000, SHADOW_NORMAL},
+};
+
+#define NCOLORS (sizeof default_colors/sizeof default_colors[0])
+const int message_base_color = NCOLORS;
+const int menu_color_table_size = NCOLORS + 256;
+
+/* Algorithmically generate the msgXX colors */
+void set_msg_colors_global(struct color_table *tbl,
+                          unsigned int fg, unsigned int bg,
+                          enum color_table_shadow shadow)
+{
+    struct color_table *cp = tbl + message_base_color;
+    unsigned int i;
+    unsigned int fga, bga;
+    unsigned int fgh, bgh;
+    unsigned int fg_idx, bg_idx;
+    unsigned int fg_rgb, bg_rgb;
+
+    static const unsigned int pc2rgb[8] =
+       { 0x000000, 0x0000ff, 0x00ff00, 0x00ffff, 0xff0000, 0xff00ff, 0xffff00,
+       0xffffff
+    };
+
+    /* Converting PC RGBI to sensible RGBA values is an "interesting"
+       proposition.  This algorithm may need plenty of tweaking. */
+
+    fga = fg & 0xff000000;
+    fgh = ((fg >> 1) & 0xff000000) | 0x80000000;
+
+    bga = bg & 0xff000000;
+    bgh = ((bg >> 1) & 0xff000000) | 0x80000000;
+
+    for (i = 0; i < 256; i++) {
+       fg_idx = i & 15;
+       bg_idx = i >> 4;
+
+       fg_rgb = pc2rgb[fg_idx & 7] & fg;
+       bg_rgb = pc2rgb[bg_idx & 7] & bg;
+
+       if (fg_idx & 8) {
+           /* High intensity foreground */
+           fg_rgb |= fgh;
+       } else {
+           fg_rgb |= fga;
+       }
+
+       if (bg_idx == 0) {
+           /* Default black background, assume transparent */
+           bg_rgb = 0;
+       } else if (bg_idx & 8) {
+           bg_rgb |= bgh;
+       } else {
+           bg_rgb |= bga;
+       }
+
+       cp->argb_fg = fg_rgb;
+       cp->argb_bg = bg_rgb;
+       cp->shadow = shadow;
+       cp++;
+    }
+}
+
+struct color_table *default_color_table(void)
+{
+    unsigned int i;
+    const struct color_table *dp;
+    struct color_table *cp;
+    struct color_table *color_table;
+    static const int pc2ansi[8] = { 0, 4, 2, 6, 1, 5, 3, 7 };
+    static char msg_names[6 * 256];
+    char *mp;
+
+    color_table = calloc(NCOLORS + 256, sizeof(struct color_table));
+
+    dp = default_colors;
+    cp = color_table;
+
+    for (i = 0; i < NCOLORS; i++) {
+       *cp = *dp;
+       cp->ansi = refstrdup(dp->ansi);
+       cp++;
+       dp++;
+    }
+
+    mp = msg_names;
+    for (i = 0; i < 256; i++) {
+       cp->name = mp;
+       mp += sprintf(mp, "msg%02x", i) + 1;
+
+       rsprintf(&cp->ansi, "%s3%d;4%d", (i & 8) ? "1;" : "",
+                pc2ansi[i & 7], pc2ansi[(i >> 4) & 7]);
+       cp++;
+    }
+
+  /*** XXX: This needs to move to run_menu() ***/
+    console_color_table = color_table;
+    console_color_table_size = NCOLORS + 256;
+
+    set_msg_colors_global(color_table, MSG_COLORS_DEF_FG,
+                         MSG_COLORS_DEF_BG, MSG_COLORS_DEF_SHADOW);
+
+    return color_table;
+}
+
+struct color_table *copy_color_table(const struct color_table *master)
+{
+    const struct color_table *dp;
+    struct color_table *color_table, *cp;
+    unsigned int i;
+
+    color_table = calloc(NCOLORS + 256, sizeof(struct color_table));
+
+    dp = master;
+    cp = color_table;
+
+    for (i = 0; i < NCOLORS + 256; i++) {
+       *cp = *dp;
+       cp->ansi = refstr_get(dp->ansi);
+       cp++;
+       dp++;
+    }
+
+    return color_table;
+}
diff --git a/core/elflink/common.h b/core/elflink/common.h
new file mode 100644 (file)
index 0000000..e288d1e
--- /dev/null
@@ -0,0 +1,62 @@
+/*
+ * common.h - Common internal operations performed by the module subsystem
+ *
+ *  Created on: Aug 11, 2008
+ *      Author: Stefan Bucur <stefanb@zytor.com>
+ */
+
+#ifndef COMMON_H_
+#define COMMON_H_
+
+#include <stdio.h>
+
+#include <sys/module.h>
+#include <linux/list.h>
+
+#include "elfutils.h"
+
+// Performs an operation and jumps to a given label if an error occurs
+#define CHECKED(res, expr, error)              \
+       do {                                                            \
+               (res) = (expr);                                 \
+               if ((res) < 0)                                  \
+                       goto error;                                     \
+       } while (0)
+
+#define MIN(x,y)       (((x) < (y)) ? (x) : (y))
+#define MAX(x,y)       (((x) > (y)) ? (x) : (y))
+
+//#define ELF_DEBUG
+
+#ifdef ELF_DEBUG
+#define DBG_PRINT(fmt, args...)        fprintf(stderr, "[ELF] " fmt, ##args)
+#else
+#define DBG_PRINT(fmt, args...)        // Expand to nothing
+#endif
+
+// User-space debugging routines
+#ifdef ELF_DEBUG
+extern void print_elf_ehdr(Elf32_Ehdr * ehdr);
+extern void print_elf_symbols(struct elf_module *module);
+#endif //ELF_DEBUG
+
+/*
+ * Image files manipulation routines
+ */
+
+extern int image_load(struct elf_module *module);
+extern int image_unload(struct elf_module *module);
+extern int image_read(void *buff, size_t size, struct elf_module *module);
+extern int image_skip(size_t size, struct elf_module *module);
+extern int image_seek(Elf32_Off offset, struct elf_module *module);
+
+extern struct module_dep *module_dep_alloc(struct elf_module *module);
+
+extern int check_header_common(Elf32_Ehdr * elf_hdr);
+
+extern int enforce_dependency(struct elf_module *req, struct elf_module *dep);
+extern int clear_dependency(struct elf_module *req, struct elf_module *dep);
+
+extern int check_symbols(struct elf_module *module);
+
+#endif /* COMMON_H_ */
diff --git a/core/elflink/config.c b/core/elflink/config.c
new file mode 100644 (file)
index 0000000..b27aa82
--- /dev/null
@@ -0,0 +1,41 @@
+/* ----------------------------------------------------------------------- *
+ *
+ *   Copyright 2007-2008 H. Peter Anvin - All Rights Reserved
+ *
+ *   Permission is hereby granted, free of charge, to any person
+ *   obtaining a copy of this software and associated documentation
+ *   files (the "Software"), to deal in the Software without
+ *   restriction, including without limitation the rights to use,
+ *   copy, modify, merge, publish, distribute, sublicense, and/or
+ *   sell copies of the Software, and to permit persons to whom
+ *   the Software is furnished to do so, subject to the following
+ *   conditions:
+ *
+ *   The above copyright notice and this permission notice shall
+ *   be included in all copies or substantial portions of the Software.
+ *
+ *   THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ *   EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+ *   OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ *   NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+ *   HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+ *   WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ *   FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ *   OTHER DEALINGS IN THE SOFTWARE.
+ *
+ * ----------------------------------------------------------------------- */
+
+#include <syslinux/config.h>
+#include <klibc/compiler.h>
+#include <com32.h>
+
+const char *__syslinux_config_file;
+
+void __constructor __syslinux_get_config_file_name(void)
+{
+    static com32sys_t reg;
+
+    reg.eax.w[0] = 0x000e;
+    __intcall(0x22, &reg, &reg);
+    __syslinux_config_file = MK_PTR(reg.es, reg.ebx.w[0]);
+}
diff --git a/core/elflink/core-elf.h b/core/elflink/core-elf.h
new file mode 100644 (file)
index 0000000..1edd174
--- /dev/null
@@ -0,0 +1,16 @@
+#ifndef _CORE_ELF_H
+#define _coRE_ELF_H
+
+extern char *append;
+extern char *ippappend;
+extern char *globaldefault;
+extern short onerrorlen;
+
+extern void parse_configs(char **argv);
+extern int new_linux_kernel(char *okernel, char *ocmdline);
+
+/* load_env32.c, should be moved out */
+extern void enter_cmdline(void);
+
+extern void start_ui(char *config_file);
+#endif
diff --git a/core/elflink/elfutils.h b/core/elflink/elfutils.h
new file mode 100644 (file)
index 0000000..3c8e70f
--- /dev/null
@@ -0,0 +1,67 @@
+#ifndef ELF_UTILS_H_
+#define ELF_UTILS_H_
+
+#include <elf.h>
+#include <stdlib.h>
+
+/**
+ * elf_get_header - Returns a pointer to the ELF header structure.
+ * @elf_image: pointer to the ELF file image in memory
+ */
+static inline Elf32_Ehdr *elf_get_header(void *elf_image)
+{
+    return (Elf32_Ehdr *) elf_image;
+}
+
+/**
+ * elf_get_pht - Returns a pointer to the first entry in the PHT.
+ * @elf_image: pointer to the ELF file image in memory
+ */
+static inline Elf32_Phdr *elf_get_pht(void *elf_image)
+{
+    Elf32_Ehdr *elf_hdr = elf_get_header(elf_image);
+
+    return (Elf32_Phdr *) ((Elf32_Off) elf_hdr + elf_hdr->e_phoff);
+}
+
+//
+/**
+ * elf_get_ph - Returns the element with the given index in the PTH
+ * @elf_image: pointer to the ELF file image in memory
+ * @index: the index of the PHT entry to look for
+ */
+static inline Elf32_Phdr *elf_get_ph(void *elf_image, int index)
+{
+    Elf32_Phdr *elf_pht = elf_get_pht(elf_image);
+    Elf32_Ehdr *elf_hdr = elf_get_header(elf_image);
+
+    return (Elf32_Phdr *) ((Elf32_Off) elf_pht + index * elf_hdr->e_phentsize);
+}
+
+/**
+ * elf_hash - Returns the index in a SysV hash table for the symbol name.
+ * @name: the name of the symbol to look for
+ */
+extern unsigned long elf_hash(const unsigned char *name);
+
+/**
+ * elf_gnu_hash - Returns the index in a GNU hash table for the symbol name.
+ * @name: the name of the symbol to look for
+ */
+extern unsigned long elf_gnu_hash(const unsigned char *name);
+
+/**
+ * elf_malloc - Allocates memory to be used by ELF module contents.
+ * @memptr: pointer to a variable to hold the address of the allocated block.
+ * @alignment: alignment constraints of the block
+ * @size: the required size of the block
+ */
+extern int elf_malloc(void **memptr, size_t alignment, size_t size);
+
+/**
+ * elf_free - Releases memory previously allocated by elf_malloc.
+ * @memptr: the address of the allocated block
+ */
+extern void elf_free(void *memptr);
+
+#endif /*ELF_UTILS_H_ */
diff --git a/core/elflink/execute.c b/core/elflink/execute.c
new file mode 100644 (file)
index 0000000..1a7ce79
--- /dev/null
@@ -0,0 +1,85 @@
+/* ----------------------------------------------------------------------- *
+ *
+ *   Copyright 2004-2008 H. Peter Anvin - All Rights Reserved
+ *
+ *   This program is free software; you can redistribute it and/or modify
+ *   it under the terms of the GNU General Public License as published by
+ *   the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
+ *   Boston MA 02110-1301, USA; either version 2 of the License, or
+ *   (at your option) any later version; incorporated herein by reference.
+ *
+ * ----------------------------------------------------------------------- */
+
+#include <stdlib.h>
+#include <string.h>
+#include <stdio.h>
+
+#include <com32.h>
+#include "menu.h"
+
+void execute(const char *cmdline, enum kernel_type type)
+{
+       com32sys_t ireg;
+       const char *p, *const *pp;
+       char *q = __com32.cs_bounce;
+       const char *kernel, *args;
+
+       /* work around for spawn_load parameter */
+       char *spawn_load_param[2] = { NULL, NULL};
+
+       memset(&ireg, 0, sizeof ireg);
+
+       kernel = q;
+       p = cmdline;
+       while (*p && !my_isspace(*p))
+               *q++ = *p++;
+       *q++ = '\0';
+
+       args = q;
+       while (*p && my_isspace(*p))
+               p++;
+
+       strcpy(q, p);
+
+       mp("kernel is %s, args = %s  type = %d \n", kernel, args, type);
+
+       if (kernel[0] == '.' && type == KT_NONE) {
+               /* It might be a type specifier */
+               enum kernel_type type = KT_NONE;
+               for (pp = kernel_types; *pp; pp++, type++) {
+                       if (!strcmp(kernel + 1, *pp))
+                               execute(p, type);       /* Strip the type specifier and retry */
+               }
+       }
+
+       if (type == KT_COM32) {
+               /* new entry for elf format c32 */
+               spawn_load_param[0] = args;
+               module_load_dependencies(kernel, "modules.dep");
+               spawn_load(kernel, spawn_load_param);
+       } else if (type <= KT_KERNEL) {
+               /* Need add one item for kernel load, as we don't use
+               * the assembly runkernel.inc any more */
+               new_linux_kernel(kernel, cmdline);
+       } else if (type == KT_CONFIG) {
+               /* kernel contains the config file name */
+               start_ui(kernel);
+       } else {
+               /* process the image need int 22 support */
+               if (type == KT_LOCALBOOT) {
+                       ireg.eax.w[0] = 0x0014; /* Local boot */
+                       ireg.edx.w[0] = strtoul(kernel, NULL, 0);
+               }
+               ireg.eax.w[0] = 0x0016; /* Run kernel image */
+               ireg.esi.w[0] = OFFS(kernel);
+               ireg.ds = SEG(kernel);
+               ireg.ebx.w[0] = OFFS(args);
+               ireg.es = SEG(args);
+               ireg.edx.l = type - KT_KERNEL;
+               /* ireg.ecx.l    = 0; *//* We do ipappend "manually" */
+
+               __intcall(0x22, &ireg, NULL);
+       }
+
+       /* If this returns, something went bad; return to menu */
+}
diff --git a/core/elflink/get_key.c b/core/elflink/get_key.c
new file mode 100644 (file)
index 0000000..ce82fd1
--- /dev/null
@@ -0,0 +1,172 @@
+/* ----------------------------------------------------------------------- *
+ *
+ *   Copyright 2004-2008 H. Peter Anvin - All Rights Reserved
+ *
+ *   Permission is hereby granted, free of charge, to any person
+ *   obtaining a copy of this software and associated documentation
+ *   files (the "Software"), to deal in the Software without
+ *   restriction, including without limitation the rights to use,
+ *   copy, modify, merge, publish, distribute, sublicense, and/or
+ *   sell copies of the Software, and to permit persons to whom
+ *   the Software is furnished to do so, subject to the following
+ *   conditions:
+ *
+ *   The above copyright notice and this permission notice shall
+ *   be included in all copies or substantial portions of the Software.
+ *
+ *   THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ *   EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+ *   OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ *   NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+ *   HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+ *   WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ *   FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ *   OTHER DEALINGS IN THE SOFTWARE.
+ *
+ * ----------------------------------------------------------------------- */
+
+/*
+ * get_key.c
+ *
+ * Get a single key, and try to pick apart function key codes.
+ * This doesn't decode anywhere close to all possiblities, but
+ * hopefully is enough to be useful.
+ */
+
+#include <stdio.h>
+#include <string.h>
+#include <errno.h>
+#include <unistd.h>
+#include <time.h>
+#include <sys/times.h>
+#include <sys/module.h>
+#include "getkey.h"
+
+struct keycode {
+    int code;
+    int seqlen;
+    const unsigned char *seq;
+};
+
+#define MAXLEN 8
+#define CODE(x,y) { x, (sizeof y)-1, y }
+
+static const struct keycode keycodes[] = {
+    /* First, the BIOS combined codes */
+    CODE(KEY_F1, "\0\x3B"),
+    CODE(KEY_F2, "\0\x3C"),
+    CODE(KEY_F3, "\0\x3D"),
+    CODE(KEY_F4, "\0\x3E"),
+    CODE(KEY_F5, "\0\x3F"),
+    CODE(KEY_F6, "\0\x40"),
+    CODE(KEY_F7, "\0\x41"),
+    CODE(KEY_F8, "\0\x42"),
+    CODE(KEY_F9, "\0\x43"),
+    CODE(KEY_F10, "\0\x44"),
+    CODE(KEY_F11, "\0\x85"),
+    CODE(KEY_F12, "\0\x86"),
+
+    CODE(KEY_UP, "\0\x48"),
+    CODE(KEY_DOWN, "\0\x50"),
+    CODE(KEY_LEFT, "\0\x4B"),
+    CODE(KEY_RIGHT, "\0\x4D"),
+    CODE(KEY_PGUP, "\0\x49"),
+    CODE(KEY_PGDN, "\0\x51"),
+    CODE(KEY_HOME, "\0\x47"),
+    CODE(KEY_END, "\0\x4F"),
+    CODE(KEY_INSERT, "\0\x52"),
+    CODE(KEY_DELETE, "\0\x53"),
+
+    /* Now, VT/xterm/Linux codes */
+    CODE(KEY_F1, "\033[[A"),
+    CODE(KEY_F1, "\033OP"),
+    CODE(KEY_F2, "\033[[B"),
+    CODE(KEY_F2, "\033OQ"),
+    CODE(KEY_F3, "\033[[C"),
+    CODE(KEY_F3, "\033OR"),
+    CODE(KEY_F4, "\033[[D"),
+    CODE(KEY_F4, "\033OS"),
+    CODE(KEY_F5, "\033[[E"),
+    CODE(KEY_F5, "\033[15~"),
+    CODE(KEY_F6, "\033[17~"),
+    CODE(KEY_F7, "\033[18~"),
+    CODE(KEY_F8, "\033[19~"),
+    CODE(KEY_F9, "\033[20~"),
+    CODE(KEY_F10, "\033[21~"),
+    CODE(KEY_F11, "\033[23~"),
+    CODE(KEY_F12, "\033[24~"),
+
+    CODE(KEY_UP, "\033[A"),
+    CODE(KEY_DOWN, "\033[B"),
+    CODE(KEY_LEFT, "\033[D"),
+    CODE(KEY_RIGHT, "\033[C"),
+    CODE(KEY_PGUP, "\033[5~"),
+    CODE(KEY_PGUP, "\033[V"),
+    CODE(KEY_PGDN, "\033[6~"),
+    CODE(KEY_PGDN, "\033[U"),
+    CODE(KEY_HOME, "\033[1~"),
+    CODE(KEY_HOME, "\033[H"),
+    CODE(KEY_END, "\033[4~"),
+    CODE(KEY_END, "\033[F"),
+    CODE(KEY_END, "\033OF"),
+    CODE(KEY_INSERT, "\033[2~"),
+    CODE(KEY_INSERT, "\033[@"),
+    CODE(KEY_DELETE, "\033[3~"),
+};
+
+#define NCODES ((int)(sizeof keycodes/sizeof(struct keycode)))
+
+#define KEY_TIMEOUT ((CLK_TCK+9)/10)
+
+int get_key(FILE * f, clock_t timeout)
+{
+    unsigned char buffer[MAXLEN];
+    int nc, i, rv;
+    const struct keycode *kc;
+    int another;
+    unsigned char ch;
+    clock_t start;
+
+    /* We typically start in the middle of a clock tick */
+    if (timeout)
+       timeout++;
+
+    nc = 0;
+    start = times(NULL);
+    do {
+       rv = read(fileno(f), &ch, 1);
+       if (rv == 0 || (rv == -1 && errno == EAGAIN)) {
+           clock_t lateness = times(NULL) - start;
+           if (nc && lateness > 1 + KEY_TIMEOUT) {
+               if (nc == 1)
+                   return buffer[0];   /* timeout in sequence */
+               else if (timeout && lateness > timeout)
+                   return KEY_NONE;
+           } else if (!nc && timeout && lateness > timeout)
+               return KEY_NONE;        /* timeout before sequence */
+
+           syslinux_idle();
+
+           another = 1;
+           continue;
+       }
+
+       start = times(NULL);
+
+       buffer[nc++] = ch;
+
+       another = 0;
+       for (i = 0, kc = keycodes; i < NCODES; i++, kc++) {
+           if (nc == kc->seqlen && !memcmp(buffer, kc->seq, nc))
+               return kc->code;
+           else if (nc < kc->seqlen && !memcmp(buffer, kc->seq, nc)) {
+               another = 1;
+               break;
+           }
+       }
+    } while (another);
+
+    /* We got an unrecognized sequence; return the first character */
+    /* We really should remember this and return subsequent characters later */
+    return buffer[0];
+}
diff --git a/core/elflink/getadv.c b/core/elflink/getadv.c
new file mode 100644 (file)
index 0000000..456084b
--- /dev/null
@@ -0,0 +1,68 @@
+/* ----------------------------------------------------------------------- *
+ *
+ *   Copyright 2007-2008 H. Peter Anvin - All Rights Reserved
+ *
+ *   Permission is hereby granted, free of charge, to any person
+ *   obtaining a copy of this software and associated documentation
+ *   files (the "Software"), to deal in the Software without
+ *   restriction, including without limitation the rights to use,
+ *   copy, modify, merge, publish, distribute, sublicense, and/or
+ *   sell copies of the Software, and to permit persons to whom
+ *   the Software is furnished to do so, subject to the following
+ *   conditions:
+ *
+ *   The above copyright notice and this permission notice shall
+ *   be included in all copies or substantial portions of the Software.
+ *
+ *   THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ *   EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+ *   OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ *   NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+ *   HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+ *   WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ *   FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ *   OTHER DEALINGS IN THE SOFTWARE.
+ *
+ * ----------------------------------------------------------------------- */
+
+/*
+ * syslinux/getadv.c
+ *
+ * Get a data item from the auxilliary data vector.  Returns a pointer
+ * and sets *size on success; NULL on failure.
+ */
+
+#include <syslinux/adv.h>
+#include <klibc/compiler.h>
+#include <inttypes.h>
+
+const void *syslinux_getadv(int tag, size_t * size)
+{
+    const uint8_t *p;
+    size_t left, len;
+
+    p = syslinux_adv_ptr();
+    left = syslinux_adv_size();
+
+    while (left >= 2) {
+       uint8_t ptag = *p++;
+       size_t plen = *p++;
+       left -= 2;
+
+       if (ptag == ADV_END)
+           return NULL;        /* Not found */
+
+       if (left < plen)
+           return NULL;        /* Item overrun */
+
+       if (ptag == tag) {
+           *size = plen;
+           return p;
+       }
+
+       p += plen;
+       left -= plen;
+    }
+
+    return NULL;
+}
diff --git a/core/elflink/getkey.h b/core/elflink/getkey.h
new file mode 100644 (file)
index 0000000..52312a2
--- /dev/null
@@ -0,0 +1,80 @@
+/* ----------------------------------------------------------------------- *
+ *
+ *   Copyright 2004-2008 H. Peter Anvin - All Rights Reserved
+ *
+ *   Permission is hereby granted, free of charge, to any person
+ *   obtaining a copy of this software and associated documentation
+ *   files (the "Software"), to deal in the Software without
+ *   restriction, including without limitation the rights to use,
+ *   copy, modify, merge, publish, distribute, sublicense, and/or
+ *   sell copies of the Software, and to permit persons to whom
+ *   the Software is furnished to do so, subject to the following
+ *   conditions:
+ *
+ *   The above copyright notice and this permission notice shall
+ *   be included in all copies or substantial portions of the Software.
+ *
+ *   THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ *   EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+ *   OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ *   NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+ *   HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+ *   WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ *   FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ *   OTHER DEALINGS IN THE SOFTWARE.
+ *
+ * ----------------------------------------------------------------------- */
+
+/*
+ * getkey.h
+ *
+ * Function to get a key symbol and parse it
+ */
+
+#ifndef LIBUTIL_GETKEY_H
+#define LIBUTIL_GETKEY_H
+
+#include <stdio.h>
+#include <unistd.h>
+#include <sys/times.h>
+
+#ifndef CLK_TCK
+# define CLK_TCK sysconf(_SC_CLK_TCK)
+#endif
+
+#define KEY_NONE       (-1)
+
+#define KEY_CTRL(x)    ((x) & 0x001f)
+#define KEY_BACKSPACE  0x0008
+#define KEY_TAB                0x0009
+#define KEY_ENTER      0x000d
+#define KEY_ESC                0x001b
+#define KEY_DEL                0x007f
+
+#define KEY_F1         0x0100
+#define KEY_F2         0x0101
+#define KEY_F3         0x0102
+#define KEY_F4         0x0103
+#define KEY_F5         0x0104
+#define KEY_F6         0x0105
+#define KEY_F7         0x0106
+#define KEY_F8         0x0107
+#define KEY_F9         0x0108
+#define KEY_F10                0x0109
+#define KEY_F11                0x010A
+#define KEY_F12                0x010B
+
+#define KEY_UP         0x0120
+#define KEY_DOWN       0x0121
+#define KEY_LEFT       0x0122
+#define KEY_RIGHT      0x0123
+#define KEY_PGUP       0x0124
+#define KEY_PGDN       0x0125
+#define KEY_HOME       0x0126
+#define KEY_END                0x0127
+#define KEY_INSERT     0x0128
+#define KEY_DELETE     0x0129
+
+int get_key(FILE *, clock_t);
+
+#endif /* LIBUTIL_GETKEY_H */
diff --git a/core/elflink/ipappend.c b/core/elflink/ipappend.c
new file mode 100644 (file)
index 0000000..bd00092
--- /dev/null
@@ -0,0 +1,58 @@
+/* ----------------------------------------------------------------------- *
+ *
+ *   Copyright 2008 H. Peter Anvin - All Rights Reserved
+ *
+ *   Permission is hereby granted, free of charge, to any person
+ *   obtaining a copy of this software and associated documentation
+ *   files (the "Software"), to deal in the Software without
+ *   restriction, including without limitation the rights to use,
+ *   copy, modify, merge, publish, distribute, sublicense, and/or
+ *   sell copies of the Software, and to permit persons to whom
+ *   the Software is furnished to do so, subject to the following
+ *   conditions:
+ *
+ *   The above copyright notice and this permission notice shall
+ *   be included in all copies or substantial portions of the Software.
+ *
+ *   THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ *   EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+ *   OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ *   NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+ *   HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+ *   WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ *   FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ *   OTHER DEALINGS IN THE SOFTWARE.
+ *
+ * ----------------------------------------------------------------------- */
+
+/*
+ * syslinux/ipappend.c
+ *
+ * Get ipappend strings
+ */
+
+#include <syslinux/config.h>
+#include <klibc/compiler.h>
+#include <com32.h>
+
+struct syslinux_ipappend_strings __syslinux_ipappend_strings;
+static const char *syslinux_ipappend_string_list[32];
+
+void __constructor __syslinux_get_ipappend_strings(void)
+{
+    static com32sys_t reg;
+    int i;
+
+    reg.eax.w[0] = 0x000f;
+    __intcall(0x22, &reg, &reg);
+
+    if (!(reg.eflags.l & EFLAGS_CF)) {
+       __syslinux_ipappend_strings.count = reg.ecx.w[0];
+       __syslinux_ipappend_strings.ptr = syslinux_ipappend_string_list;
+       for (i = 0; i < reg.ecx.w[0]; i++) {
+           syslinux_ipappend_string_list[i] =
+               MK_PTR(reg.es,
+                      *(uint16_t *) MK_PTR(reg.es, reg.ebx.w[0] + i * 2));
+       }
+    }
+}
diff --git a/core/elflink/kernel.c b/core/elflink/kernel.c
new file mode 100644 (file)
index 0000000..f8efa16
--- /dev/null
@@ -0,0 +1,130 @@
+#include <stdbool.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <console.h>
+#include <syslinux/loadfile.h>
+#include <syslinux/linux.h>
+#include <syslinux/pxe.h>
+#include "core.h"
+#include "core-elf.h"
+
+/* Will be called from readconfig.c */
+int new_linux_kernel(char *okernel, char *ocmdline)
+{
+       const char *kernel_name;
+       struct initramfs *initramfs;
+       char *temp;
+       void *kernel_data;
+       size_t kernel_len;
+       bool opt_quiet = false;
+       char initrd_name[256];
+       char cmdline_buf[256], *cmdline;
+       int i;
+
+       /* to make malloc works for code in com32/lib */
+       /*
+       openconsole(&dev_null_r, &dev_stdcon_w);
+       init_memory_arena();
+       */
+
+       mp("okernel = %s, ocmdline = %s", okernel, ocmdline);
+
+       cmdline = cmdline_buf;
+
+       temp = cmdline;
+       /*
+       strcpy(temp, "BOOT_IMAGE=");
+       temp += 11;
+       */
+
+       if (okernel)
+               kernel_name = okernel;
+       else if (globaldefault)
+               kernel_name = globaldefault;
+
+       strcpy(temp, kernel_name);
+       temp += strlen(kernel_name);
+
+       /* in elflink branch, KernelCName no more exist */      
+       /*
+       else {
+               strcpy(temp, KernelCName);
+               temp += strlen(KernelCName);
+               kernel_name = KernelCName;
+       }
+       */
+
+       *temp = ' ';
+       temp++;
+       if (ocmdline)
+               strcpy(temp, ocmdline);
+       else if (append)
+               strcpy(temp, append);
+       /*      
+       else if (*(char *)CmdOptPtr)
+               strcpy(temp, (char *)CmdOptPtr);
+       else if (AppendLen) {
+               for (i = 0; i < AppendLen; i++)
+                       *temp++ = AppendBuf[i];
+               *temp = '\0';
+       }
+       */
+
+       printf("cmdline = %s\n", cmdline);
+       /*
+       printf("VkernelEnd = %x\n", VKernelEnd);
+       printf("HighMemSize = %x\n", __com32.cs_memsize);
+       */
+
+       /* "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!\n");
+               goto bail;
+       }
+
+       if (!opt_quiet)
+               printf("ok\n");
+
+       /* Initialize the initramfs chain */
+       initramfs = initramfs_init();
+       if (!initramfs)
+               goto bail;
+
+       /* Find and load initramfs */
+       temp = strstr(cmdline, "initrd=");
+       if (temp) {
+               i = 0;
+
+               temp += strlen("initrd=");
+               while (*temp != ' ' && *temp)
+                       initrd_name[i++] = *temp++;
+               initrd_name[i] = '\0';
+
+               initramfs_load_archive(initramfs, initrd_name);
+       }
+
+       //mp("loading initrd done");
+
+       /* This should not return... */
+       syslinux_boot_linux(kernel_data, kernel_len, initramfs, cmdline);
+
+bail:
+       printf("Kernel load failure (insufficient memory?)\n");
+       return 1;
+}
diff --git a/core/elflink/load_env32.c b/core/elflink/load_env32.c
new file mode 100644 (file)
index 0000000..4004162
--- /dev/null
@@ -0,0 +1,128 @@
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <string.h>
+#include <console.h>
+#include <com32.h>
+#include <syslinux/adv.h>
+#include <syslinux/config.h>
+#include <setjmp.h>
+#include <linux/list.h>
+#include <netinet/in.h>
+#include <sys/cpu.h>
+
+#include <sys/exec.h>
+#include <sys/module.h>
+#include "common.h"
+#include "menu.h"
+#include "cli.h"
+#include "core-elf.h"
+
+typedef void (*constructor_t) (void);
+constructor_t __ctors_start[], __ctors_end[];
+
+extern char __dynstr_start[];
+extern char __dynstr_len[], __dynsym_len[];
+extern char __dynsym_start[];
+extern char __got_start[];
+extern Elf32_Dyn __dynamic_start[];
+extern Elf32_Word __gnu_hash_start[];
+
+struct elf_module core_module = {
+    .name              = "(core)",
+    .shallow           = true,
+    .required          = LIST_HEAD_INIT((core_module.required)),
+    .dependants                = LIST_HEAD_INIT((core_module.dependants)),
+    .list              = LIST_HEAD_INIT((core_module.list)),
+    .module_addr       = (void *)0x0,
+    .base_addr         = (Elf32_Addr) 0x0,
+    .ghash_table       = __gnu_hash_start,
+    .str_table         = __dynstr_start,
+    .sym_table         = __dynsym_start,
+    .got               = __got_start,
+    .dyn_table         = __dynamic_start,
+    .strtable_size     = (size_t) __dynstr_len,
+    .syment_size       = sizeof(Elf32_Sym),
+    .symtable_size     = (size_t) __dynsym_len
+};
+
+/*
+       Initializes the module subsystem by taking the core module ( shallow module ) and placing
+       it on top of the modules_head_list. Since the core module is initialized when declared
+       we technically don't need the exec_init() and module_load_shallow() procedures
+*/
+void init_module_subsystem(struct elf_module *module)
+{
+    list_add(&module->list, &modules_head);
+}
+
+/* call_constr: initializes sme things related */
+static void call_constr(void)
+{
+       constructor_t *p;
+
+       for (p = __ctors_start; p < __ctors_end; p++)
+               (*p) ();
+}
+
+void enter_cmdline(void)
+{
+       struct cli_command  *comm, *aux;
+       char *cmdline;
+
+       /* Enter endless command line prompt, should support "exit" */
+       while (1) {
+               cmdline = edit_cmdline("", 1, NULL, NULL);
+               /* feng: give up the aux check here */
+               //aux = list_entry(cli_history_head.next, typeof(*aux), list);
+               //if (strcmp(aux->command, cmdline)) {
+                       comm = (struct cli_command *)malloc(sizeof(struct cli_command *));
+                       comm->command =
+                               (char *)malloc(sizeof(char) * (strlen(cmdline) + 1));
+                       strcpy(comm->command, cmdline);
+                       list_add(&(comm->list), &cli_history_head);
+                       process_command(cmdline);
+               //}
+       }
+}
+
+/* parameter is the config file name if any */
+void start_ui(char *config_file)
+{
+       char *cmdline;
+       char *argv[2] = {config_file, NULL};
+
+       parse_configs(argv);
+       /* run the default menu if found */
+       /*
+       if (default_menu) {
+               cmdline = default_menu->menu_entries[default_menu->defentry]->cmdline;
+               if (*cmdline == '.') {
+                       while (*cmdline++ != ' ');
+               }
+               process_command(cmdline);
+       }
+       */
+
+       /* try to run a default linux kernel */
+       /*
+       if (append || globaldefault)
+               new_linux_kernel(NULL, NULL);
+       */
+
+       /* Should never return */
+       enter_cmdline();
+}
+
+/* note to self: do _*NOT*_ use static key word on this function */
+void load_env32(com32sys_t * regs)
+{
+       call_constr();
+       openconsole(&dev_rawcon_r, &dev_ansiserial_w);
+       INIT_LIST_HEAD(&cli_history_head);
+
+       printf("Starting 32 bit elf module subsystem...\n");
+       init_module_subsystem(&core_module);
+
+       start_ui(NULL);
+}
diff --git a/core/elflink/menu.h b/core/elflink/menu.h
new file mode 100644 (file)
index 0000000..3bdf2d4
--- /dev/null
@@ -0,0 +1,229 @@
+/* ----------------------------------------------------------------------- *
+ *
+ *   Copyright 2004-2008 H. Peter Anvin - All Rights Reserved
+ *
+ *   This program is free software; you can redistribute it and/or modify
+ *   it under the terms of the GNU General Public License as published by
+ *   the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
+ *   Boston MA 02110-1301, USA; either version 2 of the License, or
+ *   (at your option) any later version; incorporated herein by reference.
+ *
+ * ----------------------------------------------------------------------- */
+
+/*
+ * menu.h
+ *
+ * Header file for the simple menu system
+ */
+
+#ifndef MENU_H
+#define MENU_H
+
+#include <time.h>
+#include <sys/time.h>
+#include <sys/times.h>
+#include <inttypes.h>
+#include <unistd.h>
+#include <colortbl.h>
+#include <stdbool.h>
+#include <setjmp.h>
+#include "refstr.h"
+
+#ifndef CLK_TCK
+# define CLK_TCK sysconf(_SC_CLK_TCK)
+#endif
+
+struct menu;
+
+/* Note: the _UNRES variants must always be immediately after their
+   "normal" versions. */
+enum menu_action {
+    MA_NONE,                   /* Undefined value */
+    MA_CMD,                    /* Execute a command */
+    MA_DISABLED,               /* Disabled menu entry */
+    MA_SUBMENU,                        /* This is a submenu entry */
+    MA_GOTO,                   /* Go to another menu */
+    MA_GOTO_UNRES,             /* Unresolved go to */
+    MA_QUIT,                   /* Quit to CLI */
+    MA_EXIT,                   /* Exit to higher-level menu */
+    MA_EXIT_UNRES,             /* Unresolved exit */
+};
+
+struct menu_entry {
+    struct menu *menu;         /* Parent menu */
+    const char *displayname;
+    const char *label;
+    const char *passwd;
+    char *helptext;
+    const char *cmdline;
+    struct menu *submenu;
+    struct menu_entry *next;   /* Linked list of all labels across menus */
+    int entry;                 /* Entry number inside menu */
+    enum menu_action action;
+    unsigned char hotkey;
+    bool save;                 /* Save this entry if selected */
+};
+
+static inline bool is_disabled(struct menu_entry *me)
+{
+    return me->action == MA_DISABLED;
+}
+
+enum kernel_type {
+    /* Meta-types for internal use */
+    KT_NONE,
+    KT_LOCALBOOT,
+
+    /* The ones we can pass off to SYSLINUX, in order */
+    KT_KERNEL,                 /* Undefined type */
+    KT_LINUX,                  /* Linux kernel */
+    KT_BOOT,                   /* Bootstrap program */
+    KT_BSS,                    /* Boot sector with patch */
+    KT_PXE,                    /* PXE NBP */
+    KT_FDIMAGE,                        /* Floppy disk image */
+    KT_COMBOOT,                        /* COMBOOT image */
+    KT_COM32,                  /* COM32 image */
+    KT_CONFIG,                 /* Configuration file */
+};
+
+extern const char *const kernel_types[];
+
+/* Configurable integer parameters */
+enum parameter_number {
+    P_WIDTH,
+    P_MARGIN,
+    P_PASSWD_MARGIN,
+    P_MENU_ROWS,
+    P_TABMSG_ROW,
+    P_CMDLINE_ROW,
+    P_END_ROW,
+    P_PASSWD_ROW,
+    P_TIMEOUT_ROW,
+    P_HELPMSG_ROW,
+    P_HELPMSGEND_ROW,
+    P_HSHIFT,
+    P_VSHIFT,
+    P_HIDDEN_ROW,
+
+    NPARAMS
+};
+
+/* Configurable messages */
+enum message_number {
+    MSG_TITLE,
+    MSG_AUTOBOOT,
+    MSG_TAB,
+    MSG_NOTAB,
+    MSG_PASSPROMPT,
+
+    MSG_COUNT
+};
+
+struct messages {
+    const char *name;          /* Message configuration name */
+    const char *defmsg;                /* Default message text */
+};
+
+struct menu_parameter {
+    const char *name;
+    int value;
+};
+
+extern const struct menu_parameter mparm[NPARAMS];
+
+struct fkey_help {
+    const char *textname;
+    const char *background;
+};
+
+struct menu {
+    struct menu *next;         /* Linked list of all menus */
+    const char *label;         /* Goto label for this menu */
+    struct menu *parent;
+    struct menu_entry *parent_entry;   /* Entry for self in parent */
+
+    struct menu_entry **menu_entries;
+    struct menu_entry *menu_hotkeys[256];
+
+    const char *messages[MSG_COUNT];
+    int mparm[NPARAMS];
+
+    int nentries;
+    int nentries_space;
+    int defentry;
+    int timeout;
+
+    bool allowedit;
+    bool save;                 /* MENU SAVE default for this menu */
+
+    int curentry;
+    int curtop;
+
+    const char *title;
+    const char *ontimeout;
+    const char *onerror;
+    const char *menu_master_passwd;
+    const char *menu_background;
+
+    struct color_table *color_table;
+
+    struct fkey_help fkeyhelp[12];
+};
+
+extern struct menu *root_menu, *start_menu, *hide_menu, *menu_list;
+
+/* 2048 is the current definition inside syslinux */
+#define MAX_CMDLINE_LEN         2048
+
+/* These are global parameters regardless of which menu we're displaying */
+extern int shiftkey;
+extern int hiddenmenu;
+extern long long totaltimeout;
+jmp_buf timeout_jump;
+
+void parse_configs(char **argv);
+extern int draw_background(const char *filename);
+
+static inline int my_isspace(char c)
+{
+    return (unsigned char)c <= ' ';
+}
+
+int my_isxdigit(char c);
+unsigned int hexval(char c);
+unsigned int hexval2(const char *p);
+uint32_t parse_argb(char **p);
+
+int menu_main(int argc, char *argv[]);
+void console_prepare(void);
+void console_cleanup(void);
+
+extern const int message_base_color, menu_color_table_size;
+int mygetkey(clock_t timeout);
+int show_message_file(const char *filename, const char *background);
+
+/* passwd.c */
+int passwd_compare(const char *passwd, const char *entry);
+
+/* colors.c */
+#define MSG_COLORS_DEF_FG      0x90ffffff
+#define MSG_COLORS_DEF_BG      0x80ffffff
+#define MSG_COLORS_DEF_SHADOW  SHADOW_NORMAL
+void set_msg_colors_global(struct color_table *tbl,
+                          unsigned int fg, unsigned int bg,
+                          enum color_table_shadow shadow);
+struct color_table *default_color_table(void);
+struct color_table *copy_color_table(const struct color_table *master);
+extern const int message_base_color;
+
+/* background.c */
+extern const char *current_background;
+void set_background(const char *new_background);
+
+/* execute.c */
+void execute(const char *cmdline, enum kernel_type type);
+
+/* drain.c */
+void drain_keyboard(void);
+
+#endif /* MENU_H */
diff --git a/core/elflink/readconfig.c b/core/elflink/readconfig.c
new file mode 100644 (file)
index 0000000..faeda02
--- /dev/null
@@ -0,0 +1,1183 @@
+/* ----------------------------------------------------------------------- *
+ *
+ *   Copyright 2004-2009 H. Peter Anvin - All Rights Reserved
+ *   Copyright 2009 Intel Corporation; author: H. Peter Anvin
+ *
+ *   This program is free software; you can redistribute it and/or modify
+ *   it under the terms of the GNU General Public License as published by
+ *   the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
+ *   Boston MA 02110-1301, USA; either version 2 of the License, or
+ *   (at your option) any later version; incorporated herein by reference.
+ *
+ * ----------------------------------------------------------------------- */
+
+#include <stdio.h>
+#include <stdbool.h>
+#include <stdlib.h>
+#include <string.h>
+#include <minmax.h>
+#include <alloca.h>
+#include <inttypes.h>
+#include <colortbl.h>
+#include <com32.h>
+#include <syslinux/adv.h>
+#include <syslinux/config.h>
+
+#include "menu.h"
+
+const struct menu_parameter mparm[NPARAMS] = {
+    [P_WIDTH] = {"width", 0},
+    [P_MARGIN] = {"margin", 10},
+    [P_PASSWD_MARGIN] = {"passwordmargin", 3},
+    [P_MENU_ROWS] = {"rows", 12},
+    [P_TABMSG_ROW] = {"tabmsgrow", 18},
+    [P_CMDLINE_ROW] = {"cmdlinerow", 18},
+    [P_END_ROW] = {"endrow", -1},
+    [P_PASSWD_ROW] = {"passwordrow", 11},
+    [P_TIMEOUT_ROW] = {"timeoutrow", 20},
+    [P_HELPMSG_ROW] = {"helpmsgrow", 22},
+    [P_HELPMSGEND_ROW] = {"helpmsgendrow", -1},
+    [P_HSHIFT] = {"hshift", 0},
+    [P_VSHIFT] = {"vshift", 0},
+    [P_HIDDEN_ROW] = {"hiddenrow", -2},
+};
+
+short uappendlen;              //bytes in append= command
+short ontimeoutlen;            //bytes in ontimeout command
+short onerrorlen;              //bytes in onerror command
+short forceprompt;             //force prompt
+short noescape;                        //no escape
+short nocomplete;              //no label completion on TAB key
+short allowimplicit = 1;       //allow implicit kernels
+short allowoptions = 1;                //user-specified options allowed
+short includelevel = 1;                //nesting level
+short defaultlevel;            //the current level of default
+short vkernel;                 //have we seen any "label" statements?
+short displaycon = 1;          //conio.inc
+short nohalt = 1;              //idle.inc
+
+
+/* Empty refstring */
+const char *empty_string;
+
+/* Root menu, starting menu, hidden menu, and list of all menus */
+struct menu *root_menu, *start_menu, *hide_menu, *menu_list, *default_menu;
+
+/* These are global parameters regardless of which menu we're displaying */
+int shiftkey = 0;              /* Only display menu if shift key pressed */
+int hiddenmenu = 0;
+long long totaltimeout = 0;
+
+/* Keep track of global default */
+static int has_ui = 0;         /* DEFAULT only counts if UI is found */
+char *globaldefault = NULL;
+static bool menusave = false;  /* True if there is any "menu save" */
+
+/* Linked list of all entires, hidden or not; used by unlabel() */
+static struct menu_entry *all_entries;
+static struct menu_entry **all_entries_end = &all_entries;
+
+static const struct messages messages[MSG_COUNT] = {
+    [MSG_AUTOBOOT] = {"autoboot", "Automatic boot in # second{,s}..."},
+    [MSG_TAB] = {"tabmsg", "Press [Tab] to edit options"},
+    [MSG_NOTAB] = {"notabmsg", ""},
+    [MSG_PASSPROMPT] = {"passprompt", "Password required"},
+};
+
+#define astrdup(x) ({ char *__x = (x); \
+                      size_t __n = strlen(__x) + 1; \
+                      char *__p = alloca(__n); \
+                      if ( __p ) memcpy(__p, __x, __n); \
+                      __p; })
+
+/* Must match enum kernel_type */
+const char *const kernel_types[] = {
+    "none",
+    "localboot",
+    "kernel",
+    "linux",
+    "boot",
+    "bss",
+    "pxe",
+    "fdimage",
+    "comboot",
+    "com32",
+    "config",
+    NULL
+};
+
+/*
+ * Search the list of all menus for a specific label
+ */
+static struct menu *find_menu(const char *label)
+{
+    struct menu *m;
+
+    for (m = menu_list; m; m = m->next) {
+       if (!strcmp(label, m->label))
+           return m;
+    }
+
+    return NULL;
+}
+
+#define MAX_LINE 4096
+
+static char *skipspace(char *p)
+{
+    while (*p && my_isspace(*p))
+       p++;
+
+    return p;
+}
+
+/* Strip ^ from a string, returning a new reference to the same refstring
+   if none present */
+static const char *strip_caret(const char *str)
+{
+    const char *p, *r;
+    char *q;
+    int carets = 0;
+
+    p = str;
+    for (;;) {
+       p = strchr(p, '^');
+       if (!p)
+           break;
+       carets++;
+       p++;
+    }
+
+    if (!carets)
+       return refstr_get(str);
+
+    r = q = refstr_alloc(strlen(str) - carets);
+    for (p = str; *p; p++)
+       if (*p != '^')
+           *q++ = *p;
+
+    *q = '\0';                 /* refstr_alloc() already did this... */
+
+    return r;
+}
+
+/* Check to see if we are at a certain keyword (case insensitive) */
+/* Returns a pointer to the first character past the keyword */
+static char *looking_at(char *line, const char *kwd)
+{
+    char *p = line;
+    const char *q = kwd;
+
+    while (*p && *q && ((*p ^ *q) & ~0x20) == 0) {
+       p++;
+       q++;
+    }
+
+    if (*q)
+       return NULL;            /* Didn't see the keyword */
+
+    return my_isspace(*p) ? p : NULL;  /* Must be EOL or whitespace */
+}
+
+static struct menu *new_menu(struct menu *parent,
+                            struct menu_entry *parent_entry, const char *label)
+{
+    struct menu *m = calloc(1, sizeof(struct menu));
+    int i;
+       
+       //mp("enter: menu_label = %s", label);
+
+    m->label = label;
+    m->title = refstr_get(empty_string);
+
+    if (parent) {
+       /* Submenu */
+       m->parent = parent;
+       m->parent_entry = parent_entry;
+       parent_entry->action = MA_SUBMENU;
+       parent_entry->submenu = m;
+
+       for (i = 0; i < MSG_COUNT; i++)
+           m->messages[i] = refstr_get(parent->messages[i]);
+
+       memcpy(m->mparm, parent->mparm, sizeof m->mparm);
+
+       m->allowedit = parent->allowedit;
+       m->timeout = parent->timeout;
+       m->save = parent->save;
+
+       m->ontimeout = refstr_get(parent->ontimeout);
+       m->onerror = refstr_get(parent->onerror);
+       m->menu_master_passwd = refstr_get(parent->menu_master_passwd);
+       m->menu_background = refstr_get(parent->menu_background);
+
+       m->color_table = copy_color_table(parent->color_table);
+
+       for (i = 0; i < 12; i++) {
+           m->fkeyhelp[i].textname = refstr_get(parent->fkeyhelp[i].textname);
+           m->fkeyhelp[i].background =
+               refstr_get(parent->fkeyhelp[i].background);
+       }
+    } else {
+       /* Root menu */
+       for (i = 0; i < MSG_COUNT; i++)
+           m->messages[i] = refstrdup(messages[i].defmsg);
+       for (i = 0; i < NPARAMS; i++)
+           m->mparm[i] = mparm[i].value;
+
+       m->allowedit = true;    /* Allow edits of the command line */
+       m->color_table = default_color_table();
+    }
+
+    m->next = menu_list;
+    menu_list = m;
+
+    return m;
+}
+
+struct labeldata {
+    const char *label;
+    const char *kernel;
+    enum kernel_type type;
+    const char *append;
+    const char *initrd;
+    const char *menulabel;
+    const char *passwd;
+    char *helptext;
+    unsigned int ipappend;
+    unsigned int menuhide;
+    unsigned int menudefault;
+    unsigned int menuseparator;
+    unsigned int menudisabled;
+    unsigned int menuindent;
+    enum menu_action action;
+    int save;
+    struct menu *submenu;
+};
+
+/* Menu currently being parsed */
+static struct menu *current_menu;
+
+static void clear_label_data(struct labeldata *ld)
+{
+    refstr_put(ld->label);
+    refstr_put(ld->kernel);
+    refstr_put(ld->append);
+    refstr_put(ld->initrd);
+    refstr_put(ld->menulabel);
+    refstr_put(ld->passwd);
+
+    memset(ld, 0, sizeof *ld);
+}
+
+static struct menu_entry *new_entry(struct menu *m)
+{
+    struct menu_entry *me;
+
+    //mp("enter, call from menu %s", m->label);
+
+    if (m->nentries >= m->nentries_space) {
+       if (!m->nentries_space)
+           m->nentries_space = 1;
+       else
+           m->nentries_space <<= 1;
+
+       m->menu_entries = realloc(m->menu_entries, m->nentries_space *
+                                 sizeof(struct menu_entry *));
+    }
+
+    me = calloc(1, sizeof(struct menu_entry));
+    me->menu = m;
+    me->entry = m->nentries;
+    m->menu_entries[m->nentries++] = me;
+    *all_entries_end = me;
+    all_entries_end = &me->next;
+
+    return me;
+}
+
+static void consider_for_hotkey(struct menu *m, struct menu_entry *me)
+{
+    const char *p = strchr(me->displayname, '^');
+
+    if (me->action != MA_DISABLED) {
+       if (p && p[1]) {
+           unsigned char hotkey = p[1] & ~0x20;
+           if (!m->menu_hotkeys[hotkey]) {
+               me->hotkey = hotkey;
+               m->menu_hotkeys[hotkey] = me;
+           }
+       }
+    }
+}
+
+static void record(struct menu *m, struct labeldata *ld, const char *append)
+{
+       int i;
+       struct menu_entry *me;
+       const struct syslinux_ipappend_strings *ipappend;
+
+       if (!ld->label)
+               return;                 /* Nothing defined */
+
+       /* Hidden entries are recorded on a special "hidden menu" */
+       if (ld->menuhide)
+               m = hide_menu;
+
+       char ipoptions[4096], *ipp;
+       const char *a;
+       char *s;
+
+       me = new_entry(m);
+
+       me->displayname = ld->menulabel
+           ? refstr_get(ld->menulabel) : refstr_get(ld->label);
+       me->label = refstr_get(ld->label);
+       me->passwd = refstr_get(ld->passwd);
+       me->helptext = ld->helptext;
+       me->hotkey = 0;
+       me->action = ld->action ? ld->action : MA_CMD;
+       me->save = ld->save ? (ld->save > 0) : m->save;
+
+       if (ld->menuindent) {
+           const char *dn;
+
+           rsprintf(&dn, "%*s%s", ld->menuindent, "", me->displayname);
+           refstr_put(me->displayname);
+           me->displayname = dn;
+       }
+
+       if (ld->menuseparator) {
+           refstr_put(me->displayname);
+           me->displayname = refstr_get(empty_string);
+       }
+
+       if (ld->menuseparator || ld->menudisabled) {
+           me->action = MA_DISABLED;
+           refstr_put(me->label);
+           me->label = NULL;
+           refstr_put(me->passwd);
+           me->passwd = NULL;
+       }
+
+       if (ld->menulabel)
+           consider_for_hotkey(m, me);
+
+       switch (me->action) {
+       case MA_CMD:
+           ipp = ipoptions;
+           *ipp = '\0';
+
+           if (ld->initrd)
+               ipp += sprintf(ipp, " initrd=%s", ld->initrd);
+
+           if (ld->ipappend) {
+               ipappend = syslinux_ipappend_strings();
+               for (i = 0; i < ipappend->count; i++) {
+                   if ((ld->ipappend & (1U << i)) && ipappend->ptr[i])
+                       ipp += sprintf(ipp, " %s", ipappend->ptr[i]);
+               }
+           }
+
+           a = ld->append;
+           if (!a)
+               a = append;
+           if (!a || (a[0] == '-' && !a[1]))
+               a = "";
+           s = a[0] ? " " : "";
+
+           if (ld->type == KT_KERNEL)
+               rsprintf(&me->cmdline, "%s%s%s%s", ld->kernel, s, a, ipoptions);
+           else
+               rsprintf(&me->cmdline, ".%s %s%s%s%s",
+                        kernel_types[ld->type], ld->kernel, s, a, ipoptions);
+               mp("type = %s, cmd = %s", kernel_types[ld->type], me->cmdline);
+           break;
+
+       case MA_GOTO_UNRES:
+       case MA_EXIT_UNRES:
+           me->cmdline = refstr_get(ld->kernel);
+           break;
+
+       case MA_GOTO:
+       case MA_EXIT:
+           me->submenu = ld->submenu;
+           break;
+
+       default:
+           break;
+       }
+
+       if (ld->menudefault && me->action == MA_CMD)
+           m->defentry = m->nentries - 1;
+
+    clear_label_data(ld);
+}
+
+static struct menu *begin_submenu(const char *tag)
+{
+    struct menu_entry *me;
+
+    if (!tag[0])
+       tag = NULL;
+
+    me = new_entry(current_menu);
+    me->displayname = refstrdup(tag);
+    return new_menu(current_menu, me, refstr_get(me->displayname));
+}
+
+static struct menu *end_submenu(void)
+{
+    return current_menu->parent ? current_menu->parent : current_menu;
+}
+
+static struct menu_entry *find_label(const char *str)
+{
+    const char *p;
+    struct menu_entry *me;
+    int pos;
+
+    p = str;
+    while (*p && !my_isspace(*p))
+       p++;
+
+    /* p now points to the first byte beyond the kernel name */
+    pos = p - str;
+
+    for (me = all_entries; me; me = me->next) {
+       if (!strncmp(str, me->label, pos) && !me->label[pos])
+           return me;
+    }
+
+    return NULL;
+}
+
+static const char *unlabel(const char *str)
+{
+    /* Convert a CLI-style command line to an executable command line */
+    const char *p;
+    const char *q;
+    struct menu_entry *me;
+    int pos;
+
+    p = str;
+    while (*p && !my_isspace(*p))
+       p++;
+
+    /* p now points to the first byte beyond the kernel name */
+    pos = p - str;
+
+    for (me = all_entries; me; me = me->next) {
+       if (!strncmp(str, me->label, pos) && !me->label[pos]) {
+           /* Found matching label */
+           rsprintf(&q, "%s%s", me->cmdline, p);
+           refstr_put(str);
+           return q;
+       }
+    }
+
+    return str;
+}
+
+static const char *refdup_word(char **p)
+{
+    char *sp = *p;
+    char *ep = sp;
+
+    while (*ep && !my_isspace(*ep))
+       ep++;
+
+    *p = ep;
+    return refstrndup(sp, ep - sp);
+}
+
+int my_isxdigit(char c)
+{
+    unsigned int uc = c;
+
+    return (uc - '0') < 10 || ((uc | 0x20) - 'a') < 6;
+}
+
+unsigned int hexval(char c)
+{
+    unsigned char uc = c | 0x20;
+    unsigned int v;
+
+    v = uc - '0';
+    if (v < 10)
+       return v;
+
+    return uc - 'a' + 10;
+}
+
+unsigned int hexval2(const char *p)
+{
+    return (hexval(p[0]) << 4) + hexval(p[1]);
+}
+
+uint32_t parse_argb(char **p)
+{
+    char *sp = *p;
+    char *ep;
+    uint32_t argb;
+    size_t len, dl;
+
+    if (*sp == '#')
+       sp++;
+
+    ep = sp;
+
+    while (my_isxdigit(*ep))
+       ep++;
+
+    *p = ep;
+    len = ep - sp;
+
+    switch (len) {
+    case 3:                    /* #rgb */
+       argb =
+           0xff000000 +
+           (hexval(sp[0]) * 0x11 << 16) +
+           (hexval(sp[1]) * 0x11 << 8) + (hexval(sp[2]) * 0x11);
+       break;
+    case 4:                    /* #argb */
+       argb =
+           (hexval(sp[0]) * 0x11 << 24) +
+           (hexval(sp[1]) * 0x11 << 16) +
+           (hexval(sp[2]) * 0x11 << 8) + (hexval(sp[3]) * 0x11);
+       break;
+    case 6:                    /* #rrggbb */
+    case 9:                    /* #rrrgggbbb */
+    case 12:                   /* #rrrrggggbbbb */
+       dl = len / 3;
+       argb =
+           0xff000000 +
+           (hexval2(sp + 0) << 16) +
+           (hexval2(sp + dl) << 8) + hexval2(sp + dl * 2);
+       break;
+    case 8:                    /* #aarrggbb */
+       /* #aaarrrgggbbb is indistinguishable from #rrrrggggbbbb,
+          assume the latter is a more common format */
+    case 16:                   /* #aaaarrrrggggbbbb */
+       dl = len / 4;
+       argb =
+           (hexval2(sp + 0) << 24) +
+           (hexval2(sp + dl) << 16) +
+           (hexval2(sp + dl * 2) << 8) + hexval2(sp + dl * 3);
+       break;
+    default:
+       argb = 0xffff0000;      /* Bright red (error indication) */
+       break;
+    }
+
+    return argb;
+}
+
+/*
+ * Parser state.  This is global so that including multiple
+ * files work as expected, which is that everything works the
+ * same way as if the files had been concatenated together.
+ */
+//static const char *append = NULL;
+char *append = NULL;
+//static unsigned int ipappend = 0;
+unsigned int ipappend = 0;
+static struct labeldata ld;
+
+static int parse_one_config(const char *filename);
+
+static char *is_kernel_type(char *cmdstr, enum kernel_type *type)
+{
+    const char *const *p;
+    char *q;
+    enum kernel_type t = KT_NONE;
+
+    for (p = kernel_types; *p; p++, t++) {
+       if ((q = looking_at(cmdstr, *p))) {
+           *type = t;
+           return q;
+       }
+    }
+
+    return NULL;
+}
+
+static char *is_message_name(char *cmdstr, enum message_number *msgnr)
+{
+    char *q;
+    enum message_number i;
+
+    for (i = 0; i < MSG_COUNT; i++) {
+       if ((q = looking_at(cmdstr, messages[i].name))) {
+           *msgnr = i;
+           return q;
+       }
+    }
+
+    return NULL;
+}
+
+static char *is_fkey(char *cmdstr, int *fkeyno)
+{
+    char *q;
+    int no;
+
+    if ((cmdstr[0] | 0x20) != 'f')
+       return NULL;
+
+    no = strtoul(cmdstr + 1, &q, 10);
+    if (!my_isspace(*q))
+       return NULL;
+
+    if (no < 0 || no > 12)
+       return NULL;
+
+    *fkeyno = (no == 0) ? 10 : no - 1;
+    return q;
+}
+
+static void parse_config_file(FILE * f)
+{
+    char line[MAX_LINE], *p, *ep, ch;
+    enum kernel_type type;
+    enum message_number msgnr;
+    int fkeyno;
+    struct menu *m = current_menu;
+
+    while (fgets(line, sizeof line, f)) {
+       p = strchr(line, '\r');
+       if (p)
+           *p = '\0';
+       p = strchr(line, '\n');
+       if (p)
+           *p = '\0';
+
+       p = skipspace(line);
+
+       if (looking_at(p, "menu")) {
+
+           p = skipspace(p + 4);
+
+           if (looking_at(p, "label")) {
+                       if (ld.label) {
+                               refstr_put(ld.menulabel);
+                               ld.menulabel = refstrdup(skipspace(p + 5));
+                       } else if (m->parent_entry) {
+                               refstr_put(m->parent_entry->displayname);
+                               m->parent_entry->displayname = refstrdup(skipspace(p + 5));
+                               consider_for_hotkey(m->parent, m->parent_entry);
+                               if (!m->title[0]) {
+                               /* MENU LABEL -> MENU TITLE on submenu */
+                               refstr_put(m->title);
+                               m->title = strip_caret(m->parent_entry->displayname);
+                               }
+                       }
+                       } else if (looking_at(p, "title")) {
+                       refstr_put(m->title);
+                       m->title = refstrdup(skipspace(p + 5));
+                       if (m->parent_entry) {
+                               /* MENU TITLE -> MENU LABEL on submenu */
+                               if (m->parent_entry->displayname == m->label) {
+                               refstr_put(m->parent_entry->displayname);
+                               m->parent_entry->displayname = refstr_get(m->title);
+                               }
+                       }
+           } else if (looking_at(p, "default")) {
+               if (ld.label) {
+                   ld.menudefault = 1;
+               } else if (m->parent_entry) {
+                   m->parent->defentry = m->parent_entry->entry;
+               }
+           } else if (looking_at(p, "hide")) {
+               ld.menuhide = 1;
+           } else if (looking_at(p, "passwd")) {
+               if (ld.label) {
+                   refstr_put(ld.passwd);
+                   ld.passwd = refstrdup(skipspace(p + 6));
+               } else if (m->parent_entry) {
+                   refstr_put(m->parent_entry->passwd);
+                   m->parent_entry->passwd = refstrdup(skipspace(p + 6));
+               }
+           } else if (looking_at(p, "shiftkey")) {
+               shiftkey = 1;
+           } else if (looking_at(p, "save")) {
+               menusave = true;
+               if (ld.label)
+                   ld.save = 1;
+               else
+                   m->save = true;
+           } else if (looking_at(p, "nosave")) {
+               if (ld.label)
+                   ld.save = -1;
+               else
+                   m->save = false;
+           } else if (looking_at(p, "onerror")) {
+               refstr_put(m->onerror);
+               m->onerror = refstrdup(skipspace(p + 7));
+               onerrorlen = strlen(m->onerror);
+           } else if (looking_at(p, "master")) {
+               p = skipspace(p + 6);
+               if (looking_at(p, "passwd")) {
+                   refstr_put(m->menu_master_passwd);
+                   m->menu_master_passwd = refstrdup(skipspace(p + 6));
+               }
+           } else if ((ep = looking_at(p, "include"))) {
+               goto do_include;
+           } else if ((ep = looking_at(p, "background"))) {
+               p = skipspace(ep);
+               refstr_put(m->menu_background);
+               m->menu_background = refdup_word(&p);
+           } else if ((ep = looking_at(p, "hidden"))) {
+               hiddenmenu = 1;
+           } else if ((ep = is_message_name(p, &msgnr))) {
+               refstr_put(m->messages[msgnr]);
+               m->messages[msgnr] = refstrdup(skipspace(ep));
+           } else if ((ep = looking_at(p, "color")) ||
+                      (ep = looking_at(p, "colour"))) {
+               int i;
+               struct color_table *cptr;
+               p = skipspace(ep);
+               cptr = m->color_table;
+               for (i = 0; i < menu_color_table_size; i++) {
+                   if ((ep = looking_at(p, cptr->name))) {
+                       p = skipspace(ep);
+                       if (*p) {
+                           if (looking_at(p, "*")) {
+                               p++;
+                           } else {
+                               refstr_put(cptr->ansi);
+                               cptr->ansi = refdup_word(&p);
+                           }
+
+                           p = skipspace(p);
+                           if (*p) {
+                               if (looking_at(p, "*"))
+                                   p++;
+                               else
+                                   cptr->argb_fg = parse_argb(&p);
+
+                               p = skipspace(p);
+                               if (*p) {
+                                   if (looking_at(p, "*"))
+                                       p++;
+                                   else
+                                       cptr->argb_bg = parse_argb(&p);
+
+                                   /* Parse a shadow mode */
+                                   p = skipspace(p);
+                                   ch = *p | 0x20;
+                                   if (ch == 'n')      /* none */
+                                       cptr->shadow = SHADOW_NONE;
+                                   else if (ch == 's') /* std, standard */
+                                       cptr->shadow = SHADOW_NORMAL;
+                                   else if (ch == 'a') /* all */
+                                       cptr->shadow = SHADOW_ALL;
+                                   else if (ch == 'r') /* rev, reverse */
+                                       cptr->shadow = SHADOW_REVERSE;
+                               }
+                           }
+                       }
+                       break;
+                   }
+                   cptr++;
+               }
+           } else if ((ep = looking_at(p, "msgcolor")) ||
+                      (ep = looking_at(p, "msgcolour"))) {
+               unsigned int fg_mask = MSG_COLORS_DEF_FG;
+               unsigned int bg_mask = MSG_COLORS_DEF_BG;
+               enum color_table_shadow shadow = MSG_COLORS_DEF_SHADOW;
+
+               p = skipspace(ep);
+               if (*p) {
+                   if (!looking_at(p, "*"))
+                       fg_mask = parse_argb(&p);
+
+                   p = skipspace(p);
+                   if (*p) {
+                       if (!looking_at(p, "*"))
+                           bg_mask = parse_argb(&p);
+
+                       p = skipspace(p);
+                       switch (*p | 0x20) {
+                       case 'n':
+                           shadow = SHADOW_NONE;
+                           break;
+                       case 's':
+                           shadow = SHADOW_NORMAL;
+                           break;
+                       case 'a':
+                           shadow = SHADOW_ALL;
+                           break;
+                       case 'r':
+                           shadow = SHADOW_REVERSE;
+                           break;
+                       default:
+                           /* go with default */
+                           break;
+                       }
+                   }
+               }
+               set_msg_colors_global(m->color_table, fg_mask, bg_mask, shadow);
+           } else if (looking_at(p, "separator")) {
+               record(m, &ld, append);
+               ld.label = refstr_get(empty_string);
+               ld.menuseparator = 1;
+               record(m, &ld, append);
+           } else if (looking_at(p, "disable") || looking_at(p, "disabled")) {
+               ld.menudisabled = 1;
+           } else if (looking_at(p, "indent")) {
+               ld.menuindent = atoi(skipspace(p + 6));
+           } else if (looking_at(p, "begin")) {
+               record(m, &ld, append);
+               m = current_menu = begin_submenu(skipspace(p + 5));
+           } else if (looking_at(p, "end")) {
+               record(m, &ld, append);
+               m = current_menu = end_submenu();
+           } else if (looking_at(p, "quit")) {
+               if (ld.label)
+                   ld.action = MA_QUIT;
+           } else if (looking_at(p, "goto")) {
+               if (ld.label) {
+                   ld.action = MA_GOTO_UNRES;
+                   refstr_put(ld.kernel);
+                   ld.kernel = refstrdup(skipspace(p + 4));
+               }
+           } else if (looking_at(p, "exit")) {
+               p = skipspace(p + 4);
+               if (ld.label && m->parent) {
+                   if (*p) {
+                       /* This is really just a goto, except for the marker */
+                       ld.action = MA_EXIT_UNRES;
+                       refstr_put(ld.kernel);
+                       ld.kernel = refstrdup(p);
+                   } else {
+                       ld.action = MA_EXIT;
+                       ld.submenu = m->parent;
+                   }
+               }
+           } else if (looking_at(p, "start")) {
+               start_menu = m;
+           } else {
+               /* Unknown, check for layout parameters */
+               enum parameter_number mp;
+               for (mp = 0; mp < NPARAMS; mp++) {
+                   if ((ep = looking_at(p, mparm[mp].name))) {
+                       m->mparm[mp] = atoi(skipspace(ep));
+                       break;
+                   }
+               }
+           }
+       }
+       /* feng: menu handling end */   
+       else if (looking_at(p, "text")) {
+
+               /* loop till we fined the "endtext" */
+           enum text_cmd {
+               TEXT_UNKNOWN,
+               TEXT_HELP
+           } cmd = TEXT_UNKNOWN;
+           int len = ld.helptext ? strlen(ld.helptext) : 0;
+           int xlen;
+
+           p = skipspace(p + 4);
+
+           if (looking_at(p, "help"))
+               cmd = TEXT_HELP;
+
+           while (fgets(line, sizeof line, f)) {
+               p = skipspace(line);
+               if (looking_at(p, "endtext"))
+                   break;
+
+               xlen = strlen(line);
+
+               switch (cmd) {
+               case TEXT_UNKNOWN:
+                   break;
+               case TEXT_HELP:
+                   ld.helptext = realloc(ld.helptext, len + xlen + 1);
+                   memcpy(ld.helptext + len, line, xlen + 1);
+                   len += xlen;
+                   break;
+               }
+           }
+       } else if ((ep = is_fkey(p, &fkeyno))) {
+           p = skipspace(ep);
+           if (m->fkeyhelp[fkeyno].textname) {
+               refstr_put(m->fkeyhelp[fkeyno].textname);
+               m->fkeyhelp[fkeyno].textname = NULL;
+           }
+           if (m->fkeyhelp[fkeyno].background) {
+               refstr_put(m->fkeyhelp[fkeyno].background);
+               m->fkeyhelp[fkeyno].background = NULL;
+           }
+
+           refstr_put(m->fkeyhelp[fkeyno].textname);
+           m->fkeyhelp[fkeyno].textname = refdup_word(&p);
+           if (*p) {
+               p = skipspace(p);
+               m->fkeyhelp[fkeyno].background = refdup_word(&p);
+           }
+       } else if ((ep = looking_at(p, "include"))) {
+do_include:
+           {
+               const char *file;
+               p = skipspace(ep);
+               file = refdup_word(&p);
+               p = skipspace(p);
+               if (*p) {
+                   record(m, &ld, append);
+                   m = current_menu = begin_submenu(p);
+                   parse_one_config(file);
+                   record(m, &ld, append);
+                   m = current_menu = end_submenu();
+               } else {
+                   parse_one_config(file);
+               }
+               refstr_put(file);
+           }
+       } else if (looking_at(p, "append")) {
+           const char *a = refstrdup(skipspace(p + 6));
+           if (ld.label) {
+               refstr_put(ld.append);
+               ld.append = a;
+           } else {
+               refstr_put(append);
+               append = a;
+           }
+           //mp("we got a append: %s", a);
+       } else if (looking_at(p, "initrd")) {
+           const char *a = refstrdup(skipspace(p + 6));
+           if (ld.label) {
+               refstr_put(ld.initrd);
+               ld.initrd = a;
+           } else {
+               /* Ignore */
+           }
+       } else if (looking_at(p, "label")) {
+           p = skipspace(p + 5);
+           /* when first time see "label", it will not really record anything */
+           record(m, &ld, append);
+           ld.label = refstrdup(p);
+           ld.kernel = refstrdup(p);
+           /* feng: this is the default type for all */
+           ld.type = KT_KERNEL;
+           ld.passwd = NULL;
+           ld.append = NULL;
+           ld.initrd = NULL;
+           ld.menulabel = NULL;
+           ld.helptext = NULL;
+           ld.ipappend = ipappend;
+           ld.menudefault = ld.menuhide = ld.menuseparator =
+               ld.menudisabled = ld.menuindent = 0;
+       } else if ((ep = is_kernel_type(p, &type))) {
+           if (ld.label) {
+               refstr_put(ld.kernel);
+               ld.kernel = refstrdup(skipspace(ep));
+               ld.type = type;
+               //mp("got a kernel: %s, type = %d", ld.kernel, ld.type);
+           }
+       } else if (looking_at(p, "timeout")) {
+           m->timeout = (atoi(skipspace(p + 7)) * CLK_TCK + 9) / 10;
+       } else if (looking_at(p, "totaltimeout")) {
+           totaltimeout = (atoll(skipspace(p + 13)) * CLK_TCK + 9) / 10;
+       } else if (looking_at(p, "ontimeout")) {
+           m->ontimeout = refstrdup(skipspace(p + 9));
+       } else if (looking_at(p, "allowoptions")) {
+           m->allowedit = !!atoi(skipspace(p + 12));
+       } else if (looking_at(p, "ipappend")) {
+           if (ld.label)
+               ld.ipappend = atoi(skipspace(p + 8));
+           else
+               ipappend = atoi(skipspace(p + 8));
+       } else if (looking_at(p, "default")) {
+               /* default could be a kernel image or another label */
+               refstr_put(globaldefault);
+               globaldefault = refstrdup(skipspace(p + 7));
+       } else if (looking_at(p, "ui")) {
+           has_ui = 1;
+       }
+       
+       /*
+        * subset 1:  pc_opencmd 
+        * display/font/kbdmap are rather similar, open a file then do sth
+        */
+       else if (looking_at(p, "display")) {
+
+       } else if (looking_at(p, "font")) {
+
+       } else if (looking_at(p, "kbdmap")) {
+
+       }
+       /*
+        * subset 2:  pc_setint16
+        * set a global flag
+        */
+       else if (looking_at(p, "implicit")) {
+               allowimplicit = atoi(skipspace(p + 8));
+       } else if (looking_at(p, "prompt")) {
+               forceprompt = atoi(skipspace(p + 8));
+       } else if (looking_at(p, "console")) {
+               displaycon = atoi(skipspace(p + 7));
+       } else if (looking_at(p, "allowoptions")) {
+               allowoptions = atoi(skipspace(p + 12));
+       } else if (looking_at(p, "noescape")) {
+               noescape = atoi(skipspace(p + 8));
+       } else if (looking_at(p, "nocomplete")) {
+               nocomplete = atoi(skipspace(p + 10));
+       } else if (looking_at(p, "nohalt")) {
+               nohalt = atoi(skipspace(p + 8));
+       }
+
+       /* serial setting, bps, flow control */
+       else if (looking_at(p, "serial")) {
+               /* core/conio.inc
+                * should be able to find some code in com32
+                */
+
+       } else if (looking_at(p, "say")) {
+               printf("%s\n", p + 4);
+       }
+    }
+}
+
+static int parse_one_config(const char *filename)
+{
+       FILE *f;
+       int i;
+
+       /*
+       if (!strcmp(filename, "~"))
+               filename = syslinux_config_file();
+       */
+
+       f = fopen(filename, "r");
+       if (f)
+               goto config_found;
+
+       /* force to use hard coded config file name */
+       f = fopen("extlinux.conf", "r");
+       if (f)
+               goto config_found;
+
+       f = fopen("isolinux.cfg", "r");
+       if (f)
+               goto config_found;
+
+       return -1;
+config_found:
+       parse_config_file(f);
+       fclose(f);
+       return 0;
+}
+
+static void resolve_gotos(void)
+{
+    struct menu_entry *me;
+    struct menu *m;
+
+    for (me = all_entries; me; me = me->next) {
+       if (me->action == MA_GOTO_UNRES || me->action == MA_EXIT_UNRES) {
+           m = find_menu(me->cmdline);
+           refstr_put(me->cmdline);
+           me->cmdline = NULL;
+           if (m) {
+               me->submenu = m;
+               me->action--;   /* Drop the _UNRES */
+           } else {
+               me->action = MA_DISABLED;
+           }
+       }
+    }
+}
+
+static void dump_menu(struct menu *menu)
+{
+       mp("will dump menu for %s:", menu->label);
+       printf("entries num: %d\n", menu->nentries);
+       printf("defentry: %d, nam = %s\n",
+               menu->defentry, menu->menu_entries[menu->defentry]->label);
+       printf("save: %d\n", menu->save);
+       //printf("", menu->);
+       //printf("", menu->);
+       //printf("", menu->);
+}
+
+void parse_configs(char **argv)
+{
+    const char *filename;
+    struct menu *m;
+    struct menu_entry *me;
+    char *cmdline;
+
+    empty_string = refstrdup("");
+
+    /* feng: reset current menu_list and entry list */
+    menu_list = NULL;
+    all_entries = NULL;
+
+    /* Initialize defaults for the root and hidden menus */
+    hide_menu = new_menu(NULL, NULL, refstrdup(".hidden"));
+    root_menu = new_menu(NULL, NULL, refstrdup(".top"));
+    start_menu = root_menu;
+
+    /* Other initialization */
+    memset(&ld, 0, sizeof(struct labeldata));
+
+    /* Actually process the files */
+    current_menu = root_menu;
+
+    if (!argv || !*argv) {
+       parse_one_config("~");
+    } else {
+       while ((filename = *argv++)) {
+               mp("Parsing config: %s", filename);
+           parse_one_config(filename);
+       }
+    }
+
+    /* On final EOF process the last label statement */
+    record(current_menu, &ld, append);
+
+    /* Common postprocessing */
+    resolve_gotos();
+
+    /* Handle global default */
+    //if (has_ui && globaldefault) {
+    if (globaldefault) {
+       mp("gloabldefault = %s", globaldefault);
+       me = find_label(globaldefault);
+       if (me && me->menu != hide_menu) {
+           me->menu->defentry = me->entry;
+           start_menu = me->menu;
+           default_menu = me->menu;
+       }
+    }
+
+    /* If "menu save" is active, let the ADV override the global default */
+    if (menusave) {
+       size_t len;
+       const char *lbl = syslinux_getadv(ADV_MENUSAVE, &len);
+       char *lstr;
+       if (lbl && len) {
+           lstr = refstr_alloc(len);
+           memcpy(lstr, lbl, len);     /* refstr_alloc() adds the final null */
+           me = find_label(lstr);
+           if (me && me->menu != hide_menu) {
+               me->menu->defentry = me->entry;
+               start_menu = me->menu;
+           }
+           refstr_put(lstr);
+       }
+    }
+
+    /* Final per-menu initialization, with all labels known */
+    for (m = menu_list; m; m = m->next) {
+       m->curentry = m->defentry;      /* All menus start at their defaults */
+
+       if (m->ontimeout)
+           m->ontimeout = unlabel(m->ontimeout);
+       if (m->onerror)
+           m->onerror = unlabel(m->onerror);
+    }
+}
diff --git a/core/elflink/refstr.c b/core/elflink/refstr.c
new file mode 100644 (file)
index 0000000..f9d98e1
--- /dev/null
@@ -0,0 +1,106 @@
+/* ----------------------------------------------------------------------- *
+ *
+ *   Copyright 2008 H. Peter Anvin - All Rights Reserved
+ *
+ *   This program is free software; you can redistribute it and/or modify
+ *   it under the terms of the GNU General Public License as published by
+ *   the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
+ *   Boston MA 02110-1301, USA; either version 2 of the License, or
+ *   (at your option) any later version; incorporated herein by reference.
+ *
+ * ----------------------------------------------------------------------- */
+
+/*
+ * refstr.c
+ *
+ * Simple reference-counted strings
+ */
+
+#include <stdlib.h>
+#include <string.h>
+#include <stdio.h>
+#include <sys/module.h>
+#include "refstr.h"
+
+/* Allocate space for a refstring of len bytes, plus final null */
+/* The final null is inserted in the string; the rest is uninitialized. */
+char *refstr_alloc(size_t len)
+{
+    char *r = malloc(sizeof(unsigned int) + len + 1);
+    if (!r)
+       return NULL;
+    *(unsigned int *)r = 1;
+    r += sizeof(unsigned int);
+    r[len] = '\0';
+    return r;
+}
+
+const char *refstrndup(const char *str, size_t len)
+{
+    char *r;
+
+    if (!str)
+       return NULL;
+
+    len = strnlen(str, len);
+    r = refstr_alloc(len);
+    if (r)
+       memcpy(r, str, len);
+    return r;
+}
+
+const char *refstrdup(const char *str)
+{
+    char *r;
+    size_t len;
+
+    if (!str)
+       return NULL;
+
+    len = strlen(str);
+    r = refstr_alloc(len);
+    if (r)
+       memcpy(r, str, len);
+    return r;
+}
+
+int vrsprintf(const char **bufp, const char *fmt, va_list ap)
+{
+    va_list ap1;
+    int len;
+    char *p;
+
+    va_copy(ap1, ap);
+    len = vsnprintf(NULL, 0, fmt, ap1);
+    va_end(ap1);
+
+    *bufp = p = refstr_alloc(len);
+    if (!p)
+       return -1;
+
+    return vsnprintf(p, len + 1, fmt, ap);
+}
+
+int rsprintf(const char **bufp, const char *fmt, ...)
+{
+    int rv;
+    va_list ap;
+
+    va_start(ap, fmt);
+    rv = vrsprintf(bufp, fmt, ap);
+    va_end(ap);
+
+    return rv;
+}
+
+void refstr_put(const char *r)
+{
+    unsigned int *ref;
+
+    if (r) {
+       ref = (unsigned int *)r - 1;
+
+       if (!--*ref)
+           free(ref);
+    }
+}
diff --git a/core/elflink/refstr.h b/core/elflink/refstr.h
new file mode 100644 (file)
index 0000000..7001d40
--- /dev/null
@@ -0,0 +1,40 @@
+/* ----------------------------------------------------------------------- *
+ *
+ *   Copyright 2008 H. Peter Anvin - All Rights Reserved
+ *
+ *   This program is free software; you can redistribute it and/or modify
+ *   it under the terms of the GNU General Public License as published by
+ *   the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
+ *   Boston MA 02110-1301, USA; either version 2 of the License, or
+ *   (at your option) any later version; incorporated herein by reference.
+ *
+ * ----------------------------------------------------------------------- */
+
+/*
+ * refstr.h
+ *
+ * Simple reference-counted strings
+ */
+
+#ifndef REFSTR_H
+#define REFSTR_H
+
+#include <stddef.h>
+#include <stdarg.h>
+
+static inline __attribute__ ((always_inline))
+const char *refstr_get(const char *r)
+{
+    if (r)
+       ((unsigned int *)r)[-1]++;
+    return r;
+}
+
+void refstr_put(const char *);
+char *refstr_alloc(size_t);
+const char *refstrdup(const char *);
+const char *refstrndup(const char *, size_t);
+int rsprintf(const char **, const char *, ...);
+int vrsprintf(const char **, const char *, va_list);
+
+#endif
diff --git a/core/elflink/setadv.c b/core/elflink/setadv.c
new file mode 100644 (file)
index 0000000..40f00a4
--- /dev/null
@@ -0,0 +1,116 @@
+/* ----------------------------------------------------------------------- *
+ *
+ *   Copyright 2007-2008 H. Peter Anvin - All Rights Reserved
+ *   Copyright 2009 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
+ *   files (the "Software"), to deal in the Software without
+ *   restriction, including without limitation the rights to use,
+ *   copy, modify, merge, publish, distribute, sublicense, and/or
+ *   sell copies of the Software, and to permit persons to whom
+ *   the Software is furnished to do so, subject to the following
+ *   conditions:
+ *
+ *   The above copyright notice and this permission notice shall
+ *   be included in all copies or substantial portions of the Software.
+ *
+ *   THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ *   EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+ *   OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ *   NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+ *   HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+ *   WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ *   FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ *   OTHER DEALINGS IN THE SOFTWARE.
+ *
+ * ----------------------------------------------------------------------- */
+
+/*
+ * syslinux/setadv.c
+ *
+ * (Over)write a data item in the auxilliary data vector.  To
+ * delete an item, set its length to zero.
+ *
+ * Return 0 on success, -1 on error, and set errno.
+ *
+ * NOTE: Data is not written to disk unless
+ * syslinux_adv_write() is called.
+ */
+
+#include <syslinux/adv.h>
+#include <klibc/compiler.h>
+#include <inttypes.h>
+#include <string.h>
+#include <errno.h>
+#include <alloca.h>
+
+int syslinux_setadv(int tag, size_t size, const void *data)
+{
+    uint8_t *p, *advtmp;
+    size_t rleft, left;
+
+    if ((unsigned)tag - 1 > 254) {
+       errno = EINVAL;
+       return -1;              /* Impossible tag value */
+    }
+
+    if (size > 255) {
+       errno = ENOSPC;         /* Max 255 bytes for a data item */
+       return -1;
+    }
+
+    rleft = left = syslinux_adv_size();
+    p = advtmp = alloca(left);
+    memcpy(p, syslinux_adv_ptr(), left);       /* Make working copy */
+
+    while (rleft >= 2) {
+       uint8_t ptag = p[0];
+       size_t plen = p[1] + 2;
+
+       if (ptag == ADV_END)
+           break;
+
+       if (ptag == tag) {
+           /* Found our tag.  Delete it. */
+
+           if (plen >= rleft) {
+               /* Entire remainder is our tag */
+               break;
+           }
+           memmove(p, p + plen, rleft - plen);
+           rleft -= plen;      /* Fewer bytes to read, but not to write */
+       } else {
+           /* Not our tag */
+           if (plen > rleft)
+               break;          /* Corrupt tag (overrun) - overwrite it */
+
+           left -= plen;
+           rleft -= plen;
+           p += plen;
+       }
+    }
+
+    /* Now (p, left) reflects the position to write in and how much space
+       we have for our data. */
+
+    if (size) {
+       if (left < size + 2) {
+           errno = ENOSPC;     /* Not enough space for data */
+           return -1;
+       }
+
+       *p++ = tag;
+       *p++ = size;
+       memcpy(p, data, size);
+       p += size;
+       left -= size + 2;
+    }
+
+    memset(p, 0, left);
+
+    /* If we got here, everything went OK, commit the write to low memory */
+    memcpy(syslinux_adv_ptr(), advtmp, syslinux_adv_size());
+
+    return 0;
+}