aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorFeng Tang <feng.tang@intel.com>2010-06-01 16:18:42 +0800
committerFeng Tang <feng.tang@intel.com>2010-07-20 11:10:03 +0800
commit8f33a3dff6cd44fa2d12e626354479e020e25bdc (patch)
tree3d98ec8ffbc637f8728ee5c9fed5895628f82a0e
parent4d66117c87409691ddf1501c17d1642040414a7c (diff)
downloadsyslinux-8f33a3dff6cd44fa2d12e626354479e020e25bdc.tar.gz
syslinux-8f33a3dff6cd44fa2d12e626354479e020e25bdc.tar.xz
syslinux-8f33a3dff6cd44fa2d12e626354479e020e25bdc.zip
move core/elflink over
-rw-r--r--MCONFIG.devel2
-rw-r--r--core/elflink/abort_new.c29
-rw-r--r--core/elflink/adv.c49
-rw-r--r--core/elflink/advwrite.c45
-rw-r--r--core/elflink/cli.c406
-rw-r--r--core/elflink/cli.h23
-rw-r--r--core/elflink/colors.c184
-rw-r--r--core/elflink/common.h62
-rw-r--r--core/elflink/config.c41
-rw-r--r--core/elflink/core-elf.h16
-rw-r--r--core/elflink/elfutils.h67
-rw-r--r--core/elflink/execute.c85
-rw-r--r--core/elflink/get_key.c172
-rw-r--r--core/elflink/getadv.c68
-rw-r--r--core/elflink/getkey.h80
-rw-r--r--core/elflink/ipappend.c58
-rw-r--r--core/elflink/kernel.c130
-rw-r--r--core/elflink/load_env32.c128
-rw-r--r--core/elflink/menu.h229
-rw-r--r--core/elflink/readconfig.c1183
-rw-r--r--core/elflink/refstr.c106
-rw-r--r--core/elflink/refstr.h40
-rw-r--r--core/elflink/setadv.c116
23 files changed, 3317 insertions, 2 deletions
diff --git a/MCONFIG.devel b/MCONFIG.devel
deleted file mode 100644
index 104207f5..00000000
--- a/MCONFIG.devel
+++ /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
index 00000000..39ba2267
--- /dev/null
+++ b/core/elflink/abort_new.c
@@ -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
index 00000000..be38e89d
--- /dev/null
+++ b/core/elflink/adv.c
@@ -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
index 00000000..4152eea5
--- /dev/null
+++ b/core/elflink/advwrite.c
@@ -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
index 00000000..2e223ae0
--- /dev/null
+++ b/core/elflink/cli.c
@@ -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
index 00000000..9cd8c16b
--- /dev/null
+++ b/core/elflink/cli.h
@@ -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
index 00000000..68732bdb
--- /dev/null
+++ b/core/elflink/colors.c
@@ -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
index 00000000..e288d1e4
--- /dev/null
+++ b/core/elflink/common.h
@@ -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
index 00000000..b27aa827
--- /dev/null
+++ b/core/elflink/config.c
@@ -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
index 00000000..1edd1744
--- /dev/null
+++ b/core/elflink/core-elf.h
@@ -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
index 00000000..3c8e70fc
--- /dev/null
+++ b/core/elflink/elfutils.h
@@ -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
index 00000000..1a7ce797
--- /dev/null
+++ b/core/elflink/execute.c
@@ -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
index 00000000..ce82fd1f
--- /dev/null
+++ b/core/elflink/get_key.c
@@ -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
index 00000000..456084b0
--- /dev/null
+++ b/core/elflink/getadv.c
@@ -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
index 00000000..52312a25
--- /dev/null
+++ b/core/elflink/getkey.h
@@ -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
index 00000000..bd000920
--- /dev/null
+++ b/core/elflink/ipappend.c
@@ -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
index 00000000..f8efa168
--- /dev/null
+++ b/core/elflink/kernel.c
@@ -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
index 00000000..40041624
--- /dev/null
+++ b/core/elflink/load_env32.c
@@ -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
index 00000000..3bdf2d45
--- /dev/null
+++ b/core/elflink/menu.h
@@ -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
index 00000000..faeda022
--- /dev/null
+++ b/core/elflink/readconfig.c
@@ -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
index 00000000..f9d98e11
--- /dev/null
+++ b/core/elflink/refstr.c
@@ -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
index 00000000..7001d407
--- /dev/null
+++ b/core/elflink/refstr.h
@@ -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
index 00000000..40f00a4e
--- /dev/null
+++ b/core/elflink/setadv.c
@@ -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;
+}