From bf8f85bfe6fd2f48aeafe21838ae7c36eb506ade Mon Sep 17 00:00:00 2001 From: "Ronald G. Minnich" Date: Wed, 11 Dec 2013 16:18:21 -0800 Subject: [PATCH] payload/ubootcli: add the u-boot cli This is a first cut at the u-boot cli. It builds and loads and runs and has no commands. That's next. Interestingly, this is code right from our u-boot tree, and it's full of style violations which I don't intend to fix. Remove dependency on anything else, but this won't work until the libpayload serial drivers for arm are set up. BUG=None TEST=build and boot on nyan and get a u-boot cli prompt. BRANCH=None Change-Id: I52cf7c02e2bdd00a82e6e48fd2471416c87e4627 Signed-off-by: Ronald G. Minnich Reviewed-on: https://chromium-review.googlesource.com/179721 Reviewed-by: Puneet Kumar Commit-Queue: Puneet Kumar Tested-by: Puneet Kumar --- payloads/ubootcli/Makefile | 89 ++ payloads/ubootcli/build/libpayload | 1 + payloads/ubootcli/cmd_help.c | 47 + payloads/ubootcli/cmd_license.c | 40 + payloads/ubootcli/command.c | 562 +++++++++++ payloads/ubootcli/command.h | 250 +++++ payloads/ubootcli/common.h | 242 +++++ payloads/ubootcli/linker_lists.h | 294 ++++++ payloads/ubootcli/main.c | 1101 ++++++++++++++++++++++ payloads/ubootcli/ubootcli.h | 28 + payloads/ubootcli/ubootcli.ldscript.arm | 92 ++ payloads/ubootcli/ubootcli.ldscript.i386 | 87 ++ 12 files changed, 2833 insertions(+) create mode 100644 payloads/ubootcli/Makefile create mode 120000 payloads/ubootcli/build/libpayload create mode 100644 payloads/ubootcli/cmd_help.c create mode 100644 payloads/ubootcli/cmd_license.c create mode 100644 payloads/ubootcli/command.c create mode 100644 payloads/ubootcli/command.h create mode 100644 payloads/ubootcli/common.h create mode 100644 payloads/ubootcli/linker_lists.h create mode 100644 payloads/ubootcli/main.c create mode 100644 payloads/ubootcli/ubootcli.h create mode 100644 payloads/ubootcli/ubootcli.ldscript.arm create mode 100644 payloads/ubootcli/ubootcli.ldscript.i386 diff --git a/payloads/ubootcli/Makefile b/payloads/ubootcli/Makefile new file mode 100644 index 0000000000..10535c0d37 --- /dev/null +++ b/payloads/ubootcli/Makefile @@ -0,0 +1,89 @@ +## +## This file is part of the bayou project. +## +## Copyright (C) 2008 Advanced Micro Devices, Inc. +## +## This program is free software; you can redistribute it and/or modify +## it under the terms of the GNU General Public License version 2 as +## published by the Free Software Foundation. +## +## This program is distributed in the hope that it will be useful, +## but WITHOUT ANY WARRANTY; without even the implied warranty of +## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +## GNU General Public License for more details. +## +## You should have received a copy of the GNU General Public License +## along with this program; if not, write to the Free Software +## Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA +## + +include build/libpayload/libpayload.config + +export src := $(shell pwd) +export obj := $(src)/build + +LIBPAYLOAD_DIR := $(obj)/libpayload + +$(if $(wildcard .xcompile),,$(eval $(shell bash ../libpayload/util/xcompile/xcompile > .xcompile))) +include .xcompile + +ARCHDIR-$(CONFIG_LP_ARCH_ARM) := arm +ARCHDIR-$(CONFIG_LP_ARCH_X86) := x86 + +ARCH-y := $(ARCHDIR-y) + +classes-$(CONFIG_LP_PCI) += build/libpayload/lib/libpci.a +classes-$(CONFIG_LP_CURSES) += build/libpayload/lib/libcurses.a +classes-$(CONFIG_LP_PDCURSES) += build/libpayload/lib/libmenu.a +classes-$(CONFIG_LP_PDCURSES) += build/libpayload/lib/libform.a +classes-$(CONFIG_LP_PDCURSES) += build/libpayload/lib/libpanel.a +classes-$(CONFIG_LP_CBFS) += build/libpayload/lib/libcbfs.a +classes-$(CONFIG_LP_LZMA) += build/libpayload/lib/liblzma.a +classes-$(CONFIG_LP_LIBC) += build/libpayload/lib/libc.a +headdoto= build/libpayload/lib/$(ARCHDIR-y)/head.o +libraries := $(classes-y) + +# If architecture folder name is different from GCC binutils architecture name, +# override here. +ARCH-$(CONFIG_LP_ARCH_ARM) := arm +ARCH-$(CONFIG_LP_ARCH_X86) := i386 + +LPCC := $(CC_$(ARCH-y)) +LPAS := $(AS_$(ARCH-y)) +LPLD := $(LD_$(ARCH-y)) +LPNM := $(NM_$(ARCH-y)) +OBJCOPY := $(OBJCOPY_$(ARCH-y)) +OBJDUMP := $(OBJDUMP_$(ARCH-y)) +READELF := $(READELF_$(ARCH-y)) +STRIP := $(STRIP_$(ARCH-y)) +AR := $(AR_$(ARCH-y)) + +CFLAGS_arm= -mfloat-abi=softfp -marm -mabi=aapcs +CFLAGS_arm += -march=armv7-a -Os -fno-builtin +CFLAGS_arm += -ffreestanding -fomit-frame-pointer + +LIBGCC_FILE_NAME := $(shell test -r `$(LPCC) -print-libgcc-file-name` && \ + $(LPCC) -print-libgcc-file-name) + +OBJECTS-y=main.o command.o cmd_help.o cmd_license.o + +OBJECTS-y += $(libraries) $(LIBGCC_FILE_NAME) + +CFLAGS= -Wall -Werror -Os $(FFLAGS-y) -Ibuild/libpayload/include -I. +CFLAGS+= -Ibuild/libpayload/include/$(ARCHDIR-y) +CFLAGS+= $(CFLAGS_$(ARCH-y)) + +LDFLAGS=-Wl,-T,ubootcli.ldscript.$(ARCH-y) -static -nostartfiles -nostdlib +LIBGCC=$(shell $(CC) -m32 -print-libgcc-file-name) + + +ubootcli.elf: $(OBJECTS-y) + $(LPCC) $(LDFLAGS) -o $@ $(headdoto) $(OBJECTS-y) $(libraries) + @$(STRIP) $@ + +%.o: %.c + $(LPCC) $(CFLAGS) -c -o $@ $< + +clean: + rm -f *.o ubootcli.elf + diff --git a/payloads/ubootcli/build/libpayload b/payloads/ubootcli/build/libpayload new file mode 120000 index 0000000000..eb13cf6bad --- /dev/null +++ b/payloads/ubootcli/build/libpayload @@ -0,0 +1 @@ +../../libpayload/install/libpayload \ No newline at end of file diff --git a/payloads/ubootcli/cmd_help.c b/payloads/ubootcli/cmd_help.c new file mode 100644 index 0000000000..994138de9c --- /dev/null +++ b/payloads/ubootcli/cmd_help.c @@ -0,0 +1,47 @@ +/* + * Copyright 2000-2009 + * Wolfgang Denk, DENX Software Engineering, wd@denx.de. + * + * See file CREDITS for list of people who contributed to this + * project. + * + * 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; either version 2 of + * the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, + * MA 02111-1307 USA + */ + +#include "ubootcli.h" + +static int do_help(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[]) +{ + cmd_tbl_t *start = ll_entry_start(cmd_tbl_t, cmd); + const int len = ll_entry_count(cmd_tbl_t, cmd); + return _do_help(start, len, cmdtp, flag, argc, argv); +} + +U_BOOT_CMD( + help, CONFIG_SYS_MAXARGS, 1, do_help, + "print command description/usage", + "\n" + " - print brief description of all commands\n" + "help command ...\n" + " - print detailed usage of 'command'" +); + +/* This does not use the U_BOOT_CMD macro as ? can't be used in symbol names */ +ll_entry_declare(cmd_tbl_t, question_mark, cmd) = { + "?", CONFIG_SYS_MAXARGS, 1, do_help, + "alias for 'help'", + "" +}; diff --git a/payloads/ubootcli/cmd_license.c b/payloads/ubootcli/cmd_license.c new file mode 100644 index 0000000000..5509d67f80 --- /dev/null +++ b/payloads/ubootcli/cmd_license.c @@ -0,0 +1,40 @@ +/* + * (C) Copyright 2007 by OpenMoko, Inc. + * Author: Harald Welte + * + * See file CREDITS for list of people who contributed to this + * project. + * + * 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; either version 2 of + * the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, + * MA 02111-1307 USA + */ + +#include "ubootcli.h" + +/* COPYING is currently 15951 bytes in size */ +#define LICENSE_MAX 20480 + +int do_license(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[]) +{ + puts("Go read the GPL you lazy sod. I won't print it for you\n"); + + return 0; +} + +U_BOOT_CMD( + license, 1, 1, do_license, + "print GPL license text", + "" +); diff --git a/payloads/ubootcli/command.c b/payloads/ubootcli/command.c new file mode 100644 index 0000000000..6dc57df7ee --- /dev/null +++ b/payloads/ubootcli/command.c @@ -0,0 +1,562 @@ +/* + * (C) Copyright 2000-2009 + * Wolfgang Denk, DENX Software Engineering, wd@denx.de. + * + * See file CREDITS for list of people who contributed to this + * project. + * + * 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; either version 2 of + * the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, + * MA 02111-1307 USA + */ + +/* + * Command Processor Table + */ + +#include "ubootcli.h" + +/* + * Use printf() instead of printf() to avoid printf buffer overflow + * for long help messages + */ + +int _do_help (cmd_tbl_t *cmd_start, int cmd_items, cmd_tbl_t * cmdtp, int + flag, int argc, char * const argv[]) +{ + int i; + int rcode = 0; + + if (argc == 1) { /*show list of commands */ + cmd_tbl_t *cmd_array[cmd_items]; + int i, j, swaps; + + /* Make array of commands from .uboot_cmd section */ + cmdtp = cmd_start; + for (i = 0; i < cmd_items; i++) { + cmd_array[i] = cmdtp++; + } + + /* Sort command list (trivial bubble sort) */ + for (i = cmd_items - 1; i > 0; --i) { + swaps = 0; + for (j = 0; j < i; ++j) { + if (strcmp (cmd_array[j]->name, + cmd_array[j + 1]->name) > 0) { + cmd_tbl_t *tmp; + tmp = cmd_array[j]; + cmd_array[j] = cmd_array[j + 1]; + cmd_array[j + 1] = tmp; + ++swaps; + } + } + if (!swaps) + break; + } + + /* print short help (usage) */ + for (i = 0; i < cmd_items; i++) { + const char *usage = cmd_array[i]->usage; + + /* allow user abort */ + /* later + if (ctrlc ()) + return 1; + */ + if (usage == NULL) + continue; + printf("%-*s- %s\n", CONFIG_SYS_HELP_CMD_WIDTH, + cmd_array[i]->name, usage); + } + return 0; + } + /* + * command help (long version) + */ + for (i = 1; i < argc; ++i) { + if ((cmdtp = find_cmd_tbl (argv[i], cmd_start, cmd_items )) != NULL) { + rcode |= cmd_usage(cmdtp); + } else { + printf ("Unknown command '%s' - try 'help'" + " without arguments for list of all" + " known commands\n\n", argv[i] + ); + rcode = 1; + } + } + return rcode; +} + +/*************************************************************************** + * find command table entry for a command + */ +cmd_tbl_t *find_cmd_tbl (const char *cmd, cmd_tbl_t *table, int table_len) +{ +#ifdef CONFIG_CMDLINE + cmd_tbl_t *cmdtp; + cmd_tbl_t *cmdtp_temp = table; /*Init value */ + const char *p; + int len; + int n_found = 0; + + if (!cmd) + return NULL; + /* + * Some commands allow length modifiers (like "cp.b"); + * compare command name only until first dot. + */ + len = ((p = strchr(cmd, '.')) == NULL) ? strlen (cmd) : (p - cmd); + + for (cmdtp = table; + cmdtp != table + table_len; + cmdtp++) { + if (strncmp (cmd, cmdtp->name, len) == 0) { + if (len == strlen (cmdtp->name)) + return cmdtp; /* full match */ + + cmdtp_temp = cmdtp; /* abbreviated command ? */ + n_found++; + } + } + if (n_found == 1) { /* exactly one match */ + return cmdtp_temp; + } +#endif /* CONFIG_CMDLINE */ + + return NULL; /* not found or ambiguous command */ +} + +cmd_tbl_t *find_cmd (const char *cmd) +{ + cmd_tbl_t *start = ll_entry_start(cmd_tbl_t, cmd); + const int len = ll_entry_count(cmd_tbl_t, cmd); + return find_cmd_tbl(cmd, start, len); +} + +int cmd_usage(const cmd_tbl_t *cmdtp) +{ + printf("%s - %s\n\n", cmdtp->name, cmdtp->usage); + +#ifdef CONFIG_SYS_LONGHELP + printf("Usage:\n%s ", cmdtp->name); + + if (!cmdtp->help) { + printf ("- No additional help available.\n"); + return 1; + } + + printf (cmdtp->help); + putc ('\n'); +#endif /* CONFIG_SYS_LONGHELP */ + return 1; +} + +int var_complete(int argc, char * const argv[], char last_char, int maxv, char *cmdv[]) +{ + //static char tmp_buf[512]; + int space; + + space = last_char == '\0' || isblank(last_char); + + //if (space && argc == 1) + // return env_complete("", maxv, cmdv, sizeof(tmp_buf), tmp_buf); + + //if (!space && argc == 2) + // return env_complete(argv[1], maxv, cmdv, sizeof(tmp_buf), tmp_buf); + + return 0; +} + +/*************************************************************************************/ + +static int complete_cmdv(int argc, char * const argv[], char last_char, int maxv, char *cmdv[]) +{ + cmd_tbl_t *cmdtp = ll_entry_start(cmd_tbl_t, cmd); + const int count = ll_entry_count(cmd_tbl_t, cmd); + const cmd_tbl_t *cmdend = cmdtp + count; + const char *p; + int len, clen; + int n_found = 0; + const char *cmd; + + /* sanity? */ + if (maxv < 2) + return -2; + + cmdv[0] = NULL; + + if (argc == 0) { + /* output full list of commands */ + for (; cmdtp != cmdend; cmdtp++) { + if (n_found >= maxv - 2) { + cmdv[n_found] = "..."; + break; + } + cmdv[n_found] = cmdtp->name; + } + cmdv[n_found] = NULL; + return n_found; + } + + /* more than one arg or one but the start of the next */ + if (argc > 1 || (last_char == '\0' || isblank(last_char))) { + cmdtp = find_cmd(argv[0]); + if (cmdtp == NULL || cmdtp->complete == NULL) { + cmdv[0] = NULL; + return 0; + } + return (*cmdtp->complete)(argc, argv, last_char, maxv, cmdv); + } + + cmd = argv[0]; + /* + * Some commands allow length modifiers (like "cp.b"); + * compare command name only until first dot. + */ + p = strchr(cmd, '.'); + if (p == NULL) + len = strlen(cmd); + else + len = p - cmd; + + /* return the partial matches */ + for (; cmdtp != cmdend; cmdtp++) { + + clen = strlen(cmdtp->name); + if (clen < len) + continue; + + if (memcmp(cmd, cmdtp->name, len) != 0) + continue; + + /* too many! */ + if (n_found >= maxv - 2) { + cmdv[n_found++] = "..."; + break; + } + + cmdv[n_found++] = cmdtp->name; + } + + cmdv[n_found] = NULL; + return n_found; +} + +static int make_argv(char *s, int argvsz, char *argv[]) +{ + int argc = 0; + + /* split into argv */ + while (argc < argvsz - 1) { + + /* skip any white space */ + while (isblank(*s)) + ++s; + + if (*s == '\0') /* end of s, no more args */ + break; + + argv[argc++] = s; /* begin of argument string */ + + /* find end of string */ + while (*s && !isblank(*s)) + ++s; + + if (*s == '\0') /* end of s, no more args */ + break; + + *s++ = '\0'; /* terminate current arg */ + } + argv[argc] = NULL; + + return argc; +} + +static void print_argv(const char *banner, const char *leader, const char *sep, int linemax, char * const argv[]) +{ + int ll = leader != NULL ? strlen(leader) : 0; + int sl = sep != NULL ? strlen(sep) : 0; + int len, i; + + if (banner) { + printf("\n"); + printf(banner); + } + + i = linemax; /* force leader and newline */ + while (*argv != NULL) { + len = strlen(*argv) + sl; + if (i + len >= linemax) { + printf("\n"); + if (leader) + printf(leader); + i = ll - sl; + } else if (sep) + printf(sep); + printf(*argv++); + i += len; + } + printf("\n"); +} + +static int find_common_prefix(char * const argv[]) +{ + int i, len; + char *anchor, *s, *t; + + if (*argv == NULL) + return 0; + + /* begin with max */ + anchor = *argv++; + len = strlen(anchor); + while ((t = *argv++) != NULL) { + s = anchor; + for (i = 0; i < len; i++, t++, s++) { + if (*t != *s) + break; + } + len = s - anchor; + } + return len; +} + +static char tmp_buf[CONFIG_SYS_CBSIZE]; /* copy of console I/O buffer */ + +int cmd_auto_complete(const char *const prompt, char *buf, int *np, int *colp) +{ + int n = *np, col = *colp; + char *argv[CONFIG_SYS_MAXARGS + 1]; /* NULL terminated */ + char *cmdv[20]; + char *s, *t; + const char *sep; + int i, j, k, len, seplen, argc; + int cnt; + char last_char; + + if (strcmp(prompt, CONFIG_SYS_PROMPT) != 0) + return 0; /* not in normal console */ + + cnt = strlen(buf); + if (cnt >= 1) + last_char = buf[cnt - 1]; + else + last_char = '\0'; + + /* copy to secondary buffer which will be affected */ + strcpy(tmp_buf, buf); + + /* separate into argv */ + argc = make_argv(tmp_buf, sizeof(argv)/sizeof(argv[0]), argv); + + /* do the completion and return the possible completions */ + i = complete_cmdv(argc, argv, last_char, sizeof(cmdv)/sizeof(cmdv[0]), cmdv); + + /* no match; bell and out */ + if (i == 0) { + if (argc > 1) /* allow tab for non command */ + return 0; + serial_putchar('\a'); + return 1; + } + + s = NULL; + len = 0; + sep = NULL; + seplen = 0; + if (i == 1) { /* one match; perfect */ + k = strlen(argv[argc - 1]); + s = cmdv[0] + k; + len = strlen(s); + sep = " "; + seplen = 1; + } else if (i > 1 && (j = find_common_prefix(cmdv)) != 0) { /* more */ + k = strlen(argv[argc - 1]); + j -= k; + if (j > 0) { + s = cmdv[0] + k; + len = j; + } + } + + if (s != NULL) { + k = len + seplen; + /* make sure it fits */ + if (n + k >= CONFIG_SYS_CBSIZE - 2) { + serial_putchar('\a'); + return 1; + } + + t = buf + cnt; + for (i = 0; i < len; i++) + *t++ = *s++; + if (sep != NULL) + for (i = 0; i < seplen; i++) + *t++ = sep[i]; + *t = '\0'; + n += k; + col += k; + printf(t - k); + if (sep == NULL) + serial_putchar('\a'); + *np = n; + *colp = col; + } else { + print_argv(NULL, " ", " ", 78, cmdv); + + printf(prompt); + printf(buf); + } + return 1; +} + +#ifdef CMD_DATA_SIZE +int cmd_get_data_size(char* arg, int default_size) +{ + /* Check for a size specification .b, .w or .l. + */ + int len = strlen(arg); + if (len > 2 && arg[len-2] == '.') { + switch(arg[len-1]) { + case 'b': + return 1; + case 'w': + return 2; + case 'l': + return 4; + case 's': + return -2; + default: + return -1; + } + } + return default_size; +} +#endif + +#if defined(CONFIG_NEEDS_MANUAL_RELOC) +DECLARE_GLOBAL_DATA_PTR; + +void fixup_cmdtable(cmd_tbl_t *cmdtp, int size) +{ + int i; + + if (gd->reloc_off == 0) + return; + + for (i = 0; i < size; i++) { + uint32_t addr; + + addr = (uint32_t) (cmdtp->cmd) + gd->reloc_off; +#if DEBUG_COMMANDS + printf("Command \"%s\": 0x%08lx => 0x%08lx\n", + cmdtp->name, (uint32_t) (cmdtp->cmd), addr); +#endif + cmdtp->cmd = + (int (*)(struct cmd_tbl_s *, int, int, char * const []))addr; + addr = (uint32_t)(cmdtp->name) + gd->reloc_off; + cmdtp->name = (char *)addr; + if (cmdtp->usage) { + addr = (uint32_t)(cmdtp->usage) + gd->reloc_off; + cmdtp->usage = (char *)addr; + } +#ifdef CONFIG_SYS_LONGHELP + if (cmdtp->help) { + addr = (uint32_t)(cmdtp->help) + gd->reloc_off; + cmdtp->help = (char *)addr; + } +#endif +#ifdef CONFIG_AUTO_COMPLETE + if (cmdtp->complete) { + addr = (uint32_t)(cmdtp->complete) + gd->reloc_off; + cmdtp->complete = + (int (*)(int, char * const [], char, int, char * []))addr; + } +#endif + cmdtp++; + } +} +#endif + +#ifdef CONFIG_CMDLINE +/** + * Call a command function. This should be the only route in U-Boot to call + * a command, so that we can track whether we are waiting for input or + * executing a command. + * + * @param cmdtp Pointer to the command to execute + * @param flag Some flags normally 0 (see CMD_FLAG_.. above) + * @param argc Number of arguments (arg 0 must be the command text) + * @param argv Arguments + * @return 0 if command succeeded, else non-zero (CMD_RET_...) + */ +static int cmd_call(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[]) +{ + int result; + + result = (cmdtp->cmd)(cmdtp, flag, argc, argv); + if (result) + debug("Command failed, result=%d", result); + return result; +} +#endif /* CONFIG_CMDLINE */ + +int cmd_process(int flag, int argc, char * const argv[], + int *repeatable, unsigned long *ticks) +{ + enum command_ret_t rc = CMD_RET_SUCCESS; + +#ifdef CONFIG_CMDLINE + cmd_tbl_t *cmdtp; + + /* Look up command in command table */ + cmdtp = find_cmd(argv[0]); + if (cmdtp == NULL) { + printf("Unknown command '%s' - try 'help'\n", argv[0]); + return 1; + } + + /* found - check max args */ + if (argc > cmdtp->maxargs) + rc = CMD_RET_USAGE; + +#if defined(CONFIG_CMD_BOOTD) + /* avoid "bootd" recursion */ + else if (cmdtp->cmd == do_bootd) { + if (flag & CMD_FLAG_BOOTD) { + printf("'bootd' recursion detected\n"); + rc = CMD_RET_FAILURE; + } else { + flag |= CMD_FLAG_BOOTD; + } + } +#endif + + /* If OK so far, then do the command */ + if (!rc) { + if (ticks) + ; //*ticks = get_timer(0); + rc = cmd_call(cmdtp, flag, argc, argv); + if (ticks) + ; //*ticks = get_timer(*ticks); + if (!(cmdtp->info & CMD_INFO_REPEATABLE)) + *repeatable = 0; + } + if (rc == CMD_RET_USAGE) + rc = cmd_usage(cmdtp); +#else + rc = board_run_command(argv[0]); +#endif + return rc; +} diff --git a/payloads/ubootcli/command.h b/payloads/ubootcli/command.h new file mode 100644 index 0000000000..5d3380571f --- /dev/null +++ b/payloads/ubootcli/command.h @@ -0,0 +1,250 @@ +/* + * (C) Copyright 2000-2009 + * Wolfgang Denk, DENX Software Engineering, wd@denx.de. + * + * See file CREDITS for list of people who contributed to this + * project. + * + * 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; either version 2 of + * the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, + * MA 02111-1307 USA + */ + +/* + * Definitions for Command Processor + */ +#ifndef __COMMAND_H +#define __COMMAND_H + +/* Default to a width of 8 characters for help message command width */ +#ifndef CONFIG_SYS_HELP_CMD_WIDTH +#define CONFIG_SYS_HELP_CMD_WIDTH 8 +#endif + +#ifndef __ASSEMBLY__ +enum { + CMD_INFO_MASK = 0xffffff, /* user data */ + CMD_INFO_REPEATABLE_SHIFT = 24, /* commaand is repeatable */ + CMD_INFO_REPEATABLE = 1U << CMD_INFO_REPEATABLE_SHIFT, +}; + +/* + * Monitor Command Table + */ + +struct cmd_tbl_s { + char *name; /* Command Name */ + int maxargs; /* maximum number of arguments */ + int info; /* CMD_INFO_... flags */ + /* Implementation function */ + int (*cmd)(struct cmd_tbl_s *, int, int, char * const []); + char *usage; /* Usage message (short) */ + char *help; /* Help message (long) */ + /* do auto completion on the arguments */ + int (*complete)(int argc, char * const argv[], char last_char, int maxv, char *cmdv[]); +}; + +typedef struct cmd_tbl_s cmd_tbl_t; + +/* Returns the info word for a command */ +static inline int cmd_get_info(struct cmd_tbl_s *cmd) +{ + return cmd->info & CMD_INFO_MASK; +} + + +#if defined(CONFIG_CMD_RUN) +extern int do_run(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[]); +#endif + +/* common/command.c */ +int _do_help (cmd_tbl_t *cmd_start, int cmd_items, cmd_tbl_t * cmdtp, int + flag, int argc, char * const argv[]); +cmd_tbl_t *find_cmd(const char *cmd); +cmd_tbl_t *find_cmd_tbl (const char *cmd, cmd_tbl_t *table, int table_len); + +extern int cmd_usage(const cmd_tbl_t *cmdtp); + +extern int var_complete(int argc, char * const argv[], char last_char, int maxv, char *cmdv[]); +extern int cmd_auto_complete(const char *const prompt, char *buf, int *np, int *colp); + +/* + * Monitor Command + * + * All commands use a common argument format: + * + * void function (cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[]); + */ + +#if defined(CONFIG_CMD_MEMORY) \ + || defined(CONFIG_CMD_I2C) \ + || defined(CONFIG_CMD_ITEST) \ + || defined(CONFIG_CMD_PCI) \ + || defined(CONFIG_CMD_PORTIO) +#define CMD_DATA_SIZE +extern int cmd_get_data_size(char* arg, int default_size); +#endif + +#ifdef CONFIG_CMD_BOOTD +extern int do_bootd(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[]); +#endif +#ifdef CONFIG_CMD_BOOTM +extern int do_bootm(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[]); +extern int bootm_maybe_autostart(cmd_tbl_t *cmdtp, const char *cmd); +#else +static inline int bootm_maybe_autostart(cmd_tbl_t *cmdtp, const char *cmd) +{ + return 0; +} +#endif + +extern int common_diskboot(cmd_tbl_t *cmdtp, const char *intf, int argc, + char *const argv[]); + +extern int do_reset(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[]); + +/* + * Error codes that commands return to cmd_process(). We use the standard 0 + * and 1 for success and failure, but add one more case - failure with a + * request to call cmd_usage(). But the cmd_process() function handles + * CMD_RET_USAGE itself and after calling cmd_usage() it will return 1. + * This is just a convenience for commands to avoid them having to call + * cmd_usage() all over the place. + */ +enum command_ret_t { + CMD_RET_SUCCESS, /* 0 = Success */ + CMD_RET_FAILURE, /* 1 = Failure */ + CMD_RET_USAGE = -1, /* Failure, please report 'usage' error */ +}; + +/** + * Process a command with arguments. We look up the command and execute it + * if valid. Otherwise we print a usage message. + * + * @param flag Some flags normally 0 (see CMD_FLAG_.. above) + * @param argc Number of arguments (arg 0 must be the command text) + * @param argv Arguments + * @param repeatable This function sets this to 0 if the command is not + * repeatable. If the command is repeatable, the value + * is left unchanged. + * @param ticks If ticks is not null, this function set it to the + * number of ticks the command took to complete. + * @return 0 if the command succeeded, 1 if it failed + */ +int cmd_process(int flag, int argc, char * const argv[], + int *repeatable, unsigned long *ticks); + +#endif /* __ASSEMBLY__ */ + +/* + * Command Flags: + */ +#define CMD_FLAG_REPEAT 0x0001 /* repeat last command */ +#define CMD_FLAG_BOOTD 0x0002 /* command is from bootd */ + +#ifdef CONFIG_AUTO_COMPLETE +# define _CMD_COMPLETE(x) x, +#else +# define _CMD_COMPLETE(x) +#endif +#ifdef CONFIG_SYS_LONGHELP +# define _CMD_HELP(x) x, +#else +# define _CMD_HELP(x) +#endif + +/* + * These macros help declare commands. They are set up in such as way that + * it is possible to completely remove all commands when CONFIG_CMDLINE is + * not defined. + * + * Usage is: + * U_BOOT_SUBCMD_START(name) + * U_BOOT_CMD_MKENT(...) (or U_BOOT_CMD_MKENT_COMPLETE) + * U_BOOT_CMD_MKENT(...) + * ... + * U_BOOT_SUBCMD_END + * + * We need to ensure that a command is placed between each entry + */ +#ifdef CONFIG_CMDLINE +#define U_BOOT_SUBCMD_START(name) static cmd_tbl_t name[] = { +#define U_BOOT_SUBCMD_END }; +#define U_BOOT_CMD_MKENT_LINE(_name, _maxargs, _rep, _cmd, _usage, \ + _help, _comp, _info) \ + { #_name, _maxargs, (_rep) << CMD_INFO_REPEATABLE_SHIFT | (_info), \ + _cmd, _usage, _CMD_HELP(_help) _CMD_COMPLETE(_comp) } + +/* Add a comma to separate lines */ +#define U_BOOT_CMD_MKENT_COMPLETE(_name, _maxargs, _rep, _cmd, _usage, \ + _help, _comp, _info) \ + U_BOOT_CMD_MKENT_LINE(_name, _maxargs, _rep, _cmd, _usage, \ + _help, _comp, _info), + +/* Here we want a semicolon after the (single) entry */ +#define U_BOOT_CMD_COMPLETE(_name, _maxargs, _rep, _cmd, _usage, _help, \ + _comp, _info) \ + ll_entry_declare(cmd_tbl_t, _name, cmd) = \ + U_BOOT_CMD_MKENT_LINE(_name, _maxargs, _rep, _cmd, \ + _usage, _help, _comp, _info); +#else +#define U_BOOT_SUBCMD_START(name) static cmd_tbl_t name[] = {}; +#define U_BOOT_SUBCMD_END + +#define _CMD_REMOVE(_name, _cmd) \ + int __remove_ ## _name(void) \ + { \ + if (0) \ + _cmd(NULL, 0, 0, NULL); \ + return 0; \ + } +#define U_BOOT_CMD_MKENT_COMPLETE(_name, _maxargs, _rep, _cmd, _usage, \ + _help, _comp, _info) \ + _CMD_REMOVE(_name ## _cmd, _cmd) + +#define U_BOOT_CMD_COMPLETE(_name, _maxargs, _rep, _cmd, _usage, _help, \ + _comp, _info) \ + _CMD_REMOVE(sub_ ## _name, _cmd) + +#endif /* CONFIG_CMDLINE */ + +#define U_BOOT_CMD_MKENT(_name, _maxargs, _rep, _cmd, _usage, _help) \ + U_BOOT_CMD_MKENT_COMPLETE(_name, _maxargs, _rep, _cmd, \ + _usage, _help, NULL, 0) + +#define U_BOOT_CMD(_name, _maxargs, _rep, _cmd, _usage, _help) \ + U_BOOT_CMD_COMPLETE(_name, _maxargs, _rep, _cmd, _usage, _help, \ + NULL, 0) + +#if defined(CONFIG_NEEDS_MANUAL_RELOC) +void fixup_cmdtable(cmd_tbl_t *cmdtp, int size); +#endif + +/* Dummy command for use in U_BOOT_CMD_MKENT() when none is needed */ +static inline int cmd_dummy(cmd_tbl_t *cmdtp, int flag, int argc, + char * const argv[]) +{ + return 0; +} + +/* + * When there is no U-Boot command line, the board must provide a way of + * executing commands. + * + * @cmd: Command string to execute + * @return Result of command, CMD_RET_... + */ +int board_run_command(const char *cmd); + +#endif /* __COMMAND_H */ diff --git a/payloads/ubootcli/common.h b/payloads/ubootcli/common.h new file mode 100644 index 0000000000..703b8b1602 --- /dev/null +++ b/payloads/ubootcli/common.h @@ -0,0 +1,242 @@ +/* + * (C) Copyright 2000-2009 + * Wolfgang Denk, DENX Software Engineering, wd@denx.de. + * + * See file CREDITS for list of people who contributed to this + * project. + * + * 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; either version 2 of + * the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, + * MA 02111-1307 USA + */ + +#ifndef __COMMON_H_ +#define __COMMON_H_ 1 + +//#include +//#include +//#include +//#include +//#include +#include +#include +#include +//#include +#include +#include +#include "linker_lists.h" + +/* + * Output a debug text when condition "cond" is met. The "cond" should be + * computed by a preprocessor in the best case, allowing for the best + * optimization. + */ +#define debug_cond(cond, fmt, args...) \ + do { \ + if (cond) \ + printf(fmt, ##args); \ + } while (0) + +#define debug(fmt, args...) \ + debug_cond(_DEBUG, fmt, ##args) + +/* + * General Purpose Utilities + */ +#define min(X, Y) \ + ({ typeof(X) __x = (X); \ + typeof(Y) __y = (Y); \ + (__x < __y) ? __x : __y; }) + +#define max(X, Y) \ + ({ typeof(X) __x = (X); \ + typeof(Y) __y = (Y); \ + (__x > __y) ? __x : __y; }) + +#define min3(X, Y, Z) \ + ({ typeof(X) __x = (X); \ + typeof(Y) __y = (Y); \ + typeof(Z) __z = (Z); \ + __x < __y ? (__x < __z ? __x : __z) : \ + (__y < __z ? __y : __z); }) + +#define max3(X, Y, Z) \ + ({ typeof(X) __x = (X); \ + typeof(Y) __y = (Y); \ + typeof(Z) __z = (Z); \ + __x > __y ? (__x > __z ? __x : __z) : \ + (__y > __z ? __y : __z); }) + +#define MIN3(x, y, z) min3(x, y, z) +#define MAX3(x, y, z) max3(x, y, z) + +/* + * Return the absolute value of a number. + * + * This handles unsigned and signed longs, ints, shorts and chars. For all + * input types abs() returns a signed long. + * + * For 64-bit types, use abs64() + */ +#define abs(x) ({ \ + long ret; \ + if (sizeof(x) == sizeof(long)) { \ + long __x = (x); \ + ret = (__x < 0) ? -__x : __x; \ + } else { \ + int __x = (x); \ + ret = (__x < 0) ? -__x : __x; \ + } \ + ret; \ + }) + +#define abs64(x) ({ \ + s64 __x = (x); \ + (__x < 0) ? -__x : __x; \ + }) + +/** + * container_of - cast a member of a structure out to the containing structure + * @ptr: the pointer to the member. + * @type: the type of the container struct this is embedded in. + * @member: the name of the member within the struct. + * + */ +#define container_of(ptr, type, member) ({ \ + const typeof( ((type *)0)->member ) *__mptr = (ptr); \ + (type *)( (char *)__mptr - offsetof(type,member) );}) + +/* + * Function Prototypes + */ + +/* common/main.c */ +void main_loop (void); +int run_command(const char *cmd, int flag); + +/** + * Run a list of commands separated by ; or even \0 + * + * Note that if 'len' is not -1, then the command does not need to be nul + * terminated, Memory will be allocated for the command in that case. + * + * @param cmd List of commands to run, each separated bu semicolon + * @param len Length of commands excluding terminator if known (-1 if not) + * @param flag Execution flags (CMD_FLAG_...) + * @return 0 on success, or != 0 on error. + */ +int run_command_list(const char *cmd, int len, int flag); +int ubreadline (const char *const prompt); +int ubreadline_into_buffer(const char *const prompt, char *buffer, + int timeout); +int parse_line (char *, char *[]); +void init_cmd_timeout(void); +void reset_cmd_timeout(void); +extern char console_buffer[]; + +/** + * Show the DRAM size in a board-specific way + * + * This is used by boards to display DRAM information in their own way. + * + * @param size Size of DRAM (which should be displayed along with other info) + */ +void board_show_dram(uint32_t size); +/* + * + * Defined in arch/$(ARCH)/lib/bootm.c + * + * @blob: FDT blob to write to + * @return 0 if ok, or -ve FDT_ERR_... on failure + */ +int arch_fixup_memory_node(void *blob); + +/* common/flash.c */ +void flash_perror (int); + +/* common/cmd_source.c */ +int source (uint32_t addr, const char *fit_uname); + +extern uint32_t load_addr; /* Default Load Address */ +extern uint32_t save_addr; /* Default Save Address */ +extern uint32_t save_size; /* Default Save Size */ + +/* common/cmd_doc.c */ +void doc_probe(unsigned long physadr); + +/* common/cmd_net.c */ +int do_tftpb(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[]); + +/* common/cmd_fat.c */ +int do_fat_fsload(cmd_tbl_t *, int, int, char * const []); + +/* common/cmd_ext2.c */ +int do_ext2load(cmd_tbl_t *, int, int, char * const []); + +/* common/cmd_nvedit.c */ +int env_init (void); +void env_relocate (void); +int envmatch (uint8_t *, int); + +/* Avoid unfortunate conflict with libc's getenv() */ +#ifdef CONFIG_SANDBOX +#define getenv uboot_getenv +#endif +char *getenv (const char *); +int getenv_f (const char *name, char *buf, unsigned len); +uint32_t getenv_ulong(const char *name, int base, uint32_t default_val); + +/** + * getenv_hex() - Return an environment variable as a hex value + * + * Decode an environment as a hex number (it may or may not have a 0x + * prefix). If the environment variable cannot be found, or does not start + * with hex digits, the default value is returned. + * + * @varname: Variable to decode + * @default_val: Value to return on error + */ +uint32_t getenv_hex(const char *varname, uint32_t default_val); + +/* + * Read an environment variable as a boolean + * Return -1 if variable does not exist (default to true) + */ +int getenv_yesno(const char *var); +int saveenv (void); +//int setenv (const char *, const char *); +int setenv_ulong(const char *varname, uint32_t value); +int setenv_hex(const char *varname, uint32_t value); +/** + * setenv_addr - Set an environment variable to an address in hex + * + * @varname: Environmet variable to set + * @addr: Value to set it to + * @return 0 if ok, 1 on error + +static inline int setenv_addr(const char *varname, const void *addr) +{ + uint32_t stupid_u_boot = (uint32_t) addr; + return setenv_hex(varname, stupid_u_boot); +} + */ +/* HACK */ +#define _DEBUG 1 +#define CONFIG_CMDLINE 1 +#define CONFIG_SYS_CBSIZE 512 +#define CONFIG_SYS_PROMPT "C: " +#define CONFIG_SYS_MAXARGS 32 +#define CONFIG_CMDLINE_EDITING 1 +#define WATCHDOG_RESET() +#endif /* __COMMON_H_ */ diff --git a/payloads/ubootcli/linker_lists.h b/payloads/ubootcli/linker_lists.h new file mode 100644 index 0000000000..245ab47b61 --- /dev/null +++ b/payloads/ubootcli/linker_lists.h @@ -0,0 +1,294 @@ +/* + * include/linker_lists.h + * + * Implementation of linker-generated arrays + * + * Copyright (C) 2012 Marek Vasut + * + * See file CREDITS for list of people who contributed to this + * project. + * + * 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; either version 2 of + * the License, or (at your option) any later version. + */ + +/* + * There is no use in including this from ASM files, but that happens + * anyway, e.g. PPC kgdb.S includes command.h which incluse us. + * So just don't define anything when included from ASM. + */ + +#if !defined(__ASSEMBLY__) + +/** + * A linker list is constructed by grouping together linker input + * sections, each containning one entry of the list. Each input section + * contains a constant initialized variable which holds the entry's + * content. Linker list input sections are constructed from the list + * and entry names, plus a prefix which allows grouping all lists + * together. Assuming _list and _entry are the list and entry names, + * then the corresponding input section name is + * + * _u_boot_list + _2_ + @_list + _2_ + @_entry + * + * and the C variable name is + * + * .u_boot_list_ + 2_ + @_list + _2_ + @_entry + * + * This ensures uniqueness for both input section and C variable name. + * + * Note that the names differ only in the first character, "." for the + * setion and "_" for the variable, so that the linker cannot confuse + * section and symbol names. From now on, both names will be referred + * to as + * + * %u_boot_list_ + 2_ + @_list + _2_ + @_entry + * + * Entry variables need never be referred to directly. + * + * The naming scheme for input sections allows grouping all linker lists + * into a single linker output section and grouping all entries for a + * single list. + * + * Note the two '_2_' constant components in the names: their presence + * allows putting a start and end symbols around a list, by mapping + * these symbols to sections names with components "1" (before) and + * "3" (after) instead of "2" (within). + * Start and end symbols for a list can generally be defined as + * + * %u_boot_list_2_ + @_list + _1_... + * %u_boot_list_2_ + @_list + _3_... + * + * Start and end symbols for the whole of the linker lists area can be + * defined as + * + * %u_boot_list_1_... + * %u_boot_list_3_... + * + * Here is an example of the sorted sections which result from a list + * "array" made up of three entries : "first", "second" and "third", + * iterated at least once. + * + * .u_boot_list_2_array_1 + * .u_boot_list_2_array_2_first + * .u_boot_list_2_array_2_second + * .u_boot_list_2_array_2_third + * .u_boot_list_2_array_3 + * + * If lists must be divided into sublists (e.g. for iterating only on + * part of a list), one can simply give the list a name of the form + * 'outer_2_inner', where 'outer' is the global list name and 'inner' + * is the sub-list name. Iterators for the whole list should use the + * global list name ("outer"); iterators for only a sub-list should use + * the full sub-list name ("outer_2_inner"). + * + * Here is an example of the sections generated from a global list + * named "drivers", two sub-lists named "i2c" and "pci", and iterators + * defined for the whole list and each sub-list: + * + * %u_boot_list_2_drivers_1 + * %u_boot_list_2_drivers_2_i2c_1 + * %u_boot_list_2_drivers_2_i2c_2_first + * %u_boot_list_2_drivers_2_i2c_2_first + * %u_boot_list_2_drivers_2_i2c_2_second + * %u_boot_list_2_drivers_2_i2c_2_third + * %u_boot_list_2_drivers_2_i2c_3 + * %u_boot_list_2_drivers_2_pci_1 + * %u_boot_list_2_drivers_2_pci_2_first + * %u_boot_list_2_drivers_2_pci_2_second + * %u_boot_list_2_drivers_2_pci_2_third + * %u_boot_list_2_drivers_2_pci_3 + * %u_boot_list_2_drivers_3 + */ + +#ifndef __LINKER_LISTS_H__ +#define __LINKER_LISTS_H__ + +/** + * ll_entry_declare() - Declare linker-generated array entry + * @_type: Data type of the entry + * @_name: Name of the entry + * @_list: name of the list. Should contain only characters allowed + * in a C variable name! + * + * This macro declares a variable that is placed into a linker-generated + * array. This is a basic building block for more advanced use of linker- + * generated arrays. The user is expected to build their own macro wrapper + * around this one. + * + * A variable declared using this macro must be compile-time initialized. + * + * Special precaution must be made when using this macro: + * + * 1) The _type must not contain the "static" keyword, otherwise the + * entry is generated and can be iterated but is listed in the map + * file and cannot be retrieved by name. + * + * 2) In case a section is declared that contains some array elements AND + * a subsection of this section is declared and contains some elements, + * it is imperative that the elements are of the same type. + * + * 4) In case an outer section is declared that contains some array elements + * AND an inner subsection of this section is declared and contains some + * elements, then when traversing the outer section, even the elements of + * the inner sections are present in the array. + * + * Example: + * ll_entry_declare(struct my_sub_cmd, my_sub_cmd, cmd_sub, cmd.sub) = { + * .x = 3, + * .y = 4, + * }; + */ +#define ll_entry_declare(_type, _name, _list) \ + _type _u_boot_list_2_##_list##_2_##_name /*__aligned(4)*/ \ + __attribute__((unused, \ + section(".u_boot_list_2_"#_list"_2_"#_name))) + +/** + * We need a 0-byte-size type for iterator symbols, and the compiler + * does not allow defining objects of C type 'void'. Using an empty + * struct is allowed by the compiler, but causes gcc versions 4.4 and + * below to complain about aliasing. Therefore we use the next best + * thing: zero-sized arrays, which are both 0-byte-size and exempt from + * aliasing warnings. + */ + +/** + * ll_entry_start() - Point to first entry of linker-generated array + * @_type: Data type of the entry + * @_list: Name of the list in which this entry is placed + * + * This function returns (_type *) pointer to the very first entry of a + * linker-generated array placed into subsection of .u_boot_list section + * specified by _list argument. + * + * Since this macro defines an array start symbol, its leftmost index + * must be 2 and its rightmost index must be 1. + * + * Example: + * struct my_sub_cmd *msc = ll_entry_start(struct my_sub_cmd, cmd_sub); + */ +#define ll_entry_start(_type, _list) \ +({ \ + static char start[0] __attribute__((/*__aligned(4) ,*/ unused, \ + section(".u_boot_list_2_"#_list"_1"))); \ + (_type *)&start; \ +}) + +/** + * ll_entry_end() - Point after last entry of linker-generated array + * @_type: Data type of the entry + * @_list: Name of the list in which this entry is placed + * (with underscores instead of dots) + * + * This function returns (_type *) pointer after the very last entry of + * a linker-generated array placed into subsection of .u_boot_list + * section specified by _list argument. + * + * Since this macro defines an array end symbol, its leftmost index + * must be 2 and its rightmost index must be 3. + * + * Example: + * struct my_sub_cmd *msc = ll_entry_end(struct my_sub_cmd, cmd_sub); + */ +#define ll_entry_end(_type, _list) \ +({ \ + static char end[0] __attribute__((/*__aligned(4) ,*/ unused, \ + section(".u_boot_list_2_"#_list"_3"))); \ + (_type *)&end; \ +}) +/** + * ll_entry_count() - Return the number of elements in linker-generated array + * @_type: Data type of the entry + * @_list: Name of the list of which the number of elements is computed + * + * This function returns the number of elements of a linker-generated array + * placed into subsection of .u_boot_list section specified by _list + * argument. The result is of an unsigned int type. + * + * Example: + * int i; + * const unsigned int count = ll_entry_count(struct my_sub_cmd, cmd_sub); + * struct my_sub_cmd *msc = ll_entry_start(struct my_sub_cmd, cmd_sub); + * for (i = 0; i < count; i++, msc++) + * printf("Entry %i, x=%i y=%i\n", i, msc->x, msc->y); + */ +#define ll_entry_count(_type, _list) \ + ({ \ + _type *start = ll_entry_start(_type, _list); \ + _type *end = ll_entry_end(_type, _list); \ + unsigned int _ll_result = end - start; \ + _ll_result; \ + }) + +/** + * ll_entry_get() - Retrieve entry from linker-generated array by name + * @_type: Data type of the entry + * @_name: Name of the entry + * @_list: Name of the list in which this entry is placed + * + * This function returns a pointer to a particular entry in LG-array + * identified by the subsection of u_boot_list where the entry resides + * and it's name. + * + * Example: + * ll_entry_declare(struct my_sub_cmd, my_sub_cmd, cmd_sub, cmd.sub) = { + * .x = 3, + * .y = 4, + * }; + * ... + * struct my_sub_cmd *c = ll_entry_get(struct my_sub_cmd, my_sub_cmd, cmd_sub); + */ +#define ll_entry_get(_type, _name, _list) \ + ({ \ + extern _type _u_boot_list_2_##_list##_2_##_name; \ + _type *_ll_result = \ + &_u_boot_list_2_##_list##_2_##_name; \ + _ll_result; \ + }) + +/** + * ll_start() - Point to first entry of first linker-generated array + * @_type: Data type of the entry + * + * This function returns (_type *) pointer to the very first entry of + * the very first linker-generated array. + * + * Since this macro defines the start of the linker-generated arrays, + * its leftmost index must be 1. + * + * Example: + * struct my_sub_cmd *msc = ll_start(struct my_sub_cmd); + */ +#define ll_start(_type) \ +({ \ + static char start[0] /*__aligned(4)*/ __attribute__((unused, \ + section(".u_boot_list_1"))); \ + (_type *)&start; \ +}) + +/** + * ll_entry_end() - Point after last entry of last linker-generated array + * @_type: Data type of the entry + * + * This function returns (_type *) pointer after the very last entry of + * the very last linker-generated array. + * + * Since this macro defines the end of the linker-generated arrays, + * its leftmost index must be 3. + * + * Example: + * struct my_sub_cmd *msc = ll_end(struct my_sub_cmd); + */ +#define ll_end(_type) \ +({ \ + static char end[0] /*__aligned(4)*/ __attribute__((unused, \ + section(".u_boot_list_3"))); \ + (_type *)&end; \ +}) + +#endif /* __ASSEMBLY__ */ + +#endif /* __LINKER_LISTS_H__ */ diff --git a/payloads/ubootcli/main.c b/payloads/ubootcli/main.c new file mode 100644 index 0000000000..0ca6dba8d2 --- /dev/null +++ b/payloads/ubootcli/main.c @@ -0,0 +1,1101 @@ +/* + * (C) Copyright 2000 + * Wolfgang Denk, DENX Software Engineering, wd@denx.de. + * + * Add to readline cmdline-editing by + * (C) Copyright 2005 + * JinHua Luo, GuangDong Linux Center, + * + * See file CREDITS for list of people who contributed to this + * project. + * + * 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; either version 2 of + * the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, + * MA 02111-1307 USA + */ + +/* #define DEBUG */ + +#include "ubootcli.h" + +/* + * Board-specific Platform code can reimplement show_boot_progress () if needed + */ +void inline __show_boot_progress (int val) {} +void show_boot_progress (int val) __attribute__((weak, alias("__show_boot_progress"))); + +#define MAX_DELAY_STOP_STR 32 + +#define DEBUG_PARSER 0 /* set to 1 to debug */ + +#define debug_parser(fmt, args...) \ + debug_cond(DEBUG_PARSER, fmt, ##args) + +#ifndef DEBUG_BOOTKEYS +#define DEBUG_BOOTKEYS 0 +#endif +#define debug_bootkeys(fmt, args...) \ + debug_cond(DEBUG_BOOTKEYS, fmt, ##args) + +char console_buffer[CONFIG_SYS_CBSIZE + 1]; /* console I/O buffer */ + +#ifdef CONFIG_CMDLINE +static char * delete_char (char *buffer, char *p, int *colp, int *np, int plen); +#endif +static const char erase_seq[] = "\b \b"; /* erase sequence */ +static const char tab_seq[] = " "; /* used to expand TABs */ + +#ifdef CONFIG_BOOT_RETRY_TIME +static uint64_t endtime = 0; /* must be set, default is instant timeout */ +static int retry_time = -1; /* -1 so can call readline before main_loop */ +#endif + +#define endtick(seconds) (get_ticks() + (uint64_t)(seconds) * get_tbclk()) + +#ifndef CONFIG_BOOT_RETRY_MIN +#define CONFIG_BOOT_RETRY_MIN CONFIG_BOOT_RETRY_TIME +#endif + +#ifdef CONFIG_MODEM_SUPPORT +int do_mdm_init = 0; +extern void mdm_init(void); /* defined in board.c */ +#endif + + +void main_loop(void) +{ + int len, flag, rc = 0; + char lastcommand[128]; + /* + * Main Loop for Monitor Command Processing + */ + for (;;) { + len = ubreadline (CONFIG_SYS_PROMPT); + + flag = 0; /* assume no special flags for now */ + if (len > 0) + strcpy (lastcommand, console_buffer); + else if (len == 0) + flag |= CMD_FLAG_REPEAT; + + if (len == -1) + printf ("\n"); + else + rc = run_command(lastcommand, flag); + + if (rc <= 0) { + /* invalid command or not repeatable, forget it */ + lastcommand[0] = 0; + } + } +} + +#ifdef CONFIG_CMDLINE_EDITING + +/* + * cmdline-editing related codes from vivi. + * Author: Janghoon Lyu + */ + +#define putnstr(str,n) do { \ + printf ("%.*s", (int)n, str); \ + } while (0) + +#define CTL_CH(c) ((c) - 'a' + 1) +#define CTL_BACKSPACE ('\b') +#define DEL ((char)255) +#define DEL7 ((char)127) +#define CREAD_HIST_CHAR ('!') + +#define getcmd_putch(ch) serial_putchar(ch) +#define getcmd_getch() serial_getchar() +#define getcmd_cbeep() getcmd_putch('\a') + +#define HIST_MAX 20 +#define HIST_SIZE CONFIG_SYS_CBSIZE + +static int hist_max; +static int hist_add_idx; +static int hist_cur = -1; +static unsigned hist_num; + +static char *hist_list[HIST_MAX]; +static char hist_lines[HIST_MAX][HIST_SIZE + 1]; /* Save room for NULL */ + +#define add_idx_minus_one() ((hist_add_idx == 0) ? hist_max : hist_add_idx-1) + +static void hist_init(void) +{ + int i; + + hist_max = 0; + hist_add_idx = 0; + hist_cur = -1; + hist_num = 0; + + for (i = 0; i < HIST_MAX; i++) { + hist_list[i] = hist_lines[i]; + hist_list[i][0] = '\0'; + } +} + +static void cread_add_to_hist(char *line) +{ + strcpy(hist_list[hist_add_idx], line); + + if (++hist_add_idx >= HIST_MAX) + hist_add_idx = 0; + + if (hist_add_idx > hist_max) + hist_max = hist_add_idx; + + hist_num++; +} + +static char* hist_prev(void) +{ + char *ret; + int old_cur; + + if (hist_cur < 0) + return NULL; + + old_cur = hist_cur; + if (--hist_cur < 0) + hist_cur = hist_max; + + if (hist_cur == hist_add_idx) { + hist_cur = old_cur; + ret = NULL; + } else + ret = hist_list[hist_cur]; + + return (ret); +} + +static char* hist_next(void) +{ + char *ret; + + if (hist_cur < 0) + return NULL; + + if (hist_cur == hist_add_idx) + return NULL; + + if (++hist_cur > hist_max) + hist_cur = 0; + + if (hist_cur == hist_add_idx) { + ret = ""; + } else + ret = hist_list[hist_cur]; + + return (ret); +} + +#ifndef CONFIG_CMDLINE_EDITING +static void cread_print_hist_list(void) +{ + int i; + unsigned long n; + + n = hist_num - hist_max; + + i = hist_add_idx + 1; + while (1) { + if (i > hist_max) + i = 0; + if (i == hist_add_idx) + break; + printf("%s\n", hist_list[i]); + n++; + i++; + } +} +#endif /* CONFIG_CMDLINE_EDITING */ + +#define BEGINNING_OF_LINE() { \ + while (num) { \ + getcmd_putch(CTL_BACKSPACE); \ + num--; \ + } \ +} + +#define ERASE_TO_EOL() { \ + if (num < eol_num) { \ + printf("%*s", (int)(eol_num - num), ""); \ + do { \ + getcmd_putch(CTL_BACKSPACE); \ + } while (--eol_num > num); \ + } \ +} + +#define REFRESH_TO_EOL() { \ + if (num < eol_num) { \ + wlen = eol_num - num; \ + putnstr(buf + num, wlen); \ + num = eol_num; \ + } \ +} + +static void cread_add_char(char ichar, int insert, unsigned long *num, + unsigned long *eol_num, char *buf, unsigned long len) +{ + unsigned long wlen; + + /* room ??? */ + if (insert || *num == *eol_num) { + if (*eol_num > len - 1) { + getcmd_cbeep(); + return; + } + (*eol_num)++; + } + + if (insert) { + wlen = *eol_num - *num; + if (wlen > 1) { + memmove(&buf[*num+1], &buf[*num], wlen-1); + } + + buf[*num] = ichar; + putnstr(buf + *num, wlen); + (*num)++; + while (--wlen) { + getcmd_putch(CTL_BACKSPACE); + } + } else { + /* echo the character */ + wlen = 1; + buf[*num] = ichar; + putnstr(buf + *num, wlen); + (*num)++; + } +} + +static void cread_add_str(char *str, int strsize, int insert, unsigned long *num, + unsigned long *eol_num, char *buf, unsigned long len) +{ + while (strsize--) { + cread_add_char(*str, insert, num, eol_num, buf, len); + str++; + } +} + +static int cread_line(const char *const prompt, char *buf, unsigned int *len, + int timeout) +{ + unsigned long num = 0; + unsigned long eol_num = 0; + unsigned long wlen; + char ichar; + int insert = 1; + int esc_len = 0; + char esc_save[8]; + int init_len = strlen(buf); + //int first = 1; + + if (init_len) + cread_add_str(buf, init_len, 1, &num, &eol_num, buf, *len); + + while (1) { +#if 0 +#ifdef CONFIG_BOOT_RETRY_TIME + while (!tstc()) { /* while no incoming data */ + if (retry_time >= 0 && get_ticks() > endtime) + return (-2); /* timed out */ +// WATCHDOG_RESET(); + } +#endif + if (first && timeout) { + uint64_t etime = endtick(timeout); + + while (!tstc()) { /* while no incoming data */ + if (get_ticks() >= etime) + return -2; /* timed out */ + WATCHDOG_RESET(); + } + first = 0; + } +#endif + ichar = getcmd_getch(); + + if ((ichar == '\n') || (ichar == '\r')) { + serial_putchar('\n'); + break; + } + + /* + * handle standard linux xterm esc sequences for arrow key, etc. + */ + if (esc_len != 0) { + if (esc_len == 1) { + if (ichar == '[') { + esc_save[esc_len] = ichar; + esc_len = 2; + } else { + cread_add_str(esc_save, esc_len, insert, + &num, &eol_num, buf, *len); + esc_len = 0; + } + continue; + } + + switch (ichar) { + + case 'D': /* <- key */ + ichar = CTL_CH('b'); + esc_len = 0; + break; + case 'C': /* -> key */ + ichar = CTL_CH('f'); + esc_len = 0; + break; /* pass off to ^F handler */ + case 'H': /* Home key */ + ichar = CTL_CH('a'); + esc_len = 0; + break; /* pass off to ^A handler */ + case 'A': /* up arrow */ + ichar = CTL_CH('p'); + esc_len = 0; + break; /* pass off to ^P handler */ + case 'B': /* down arrow */ + ichar = CTL_CH('n'); + esc_len = 0; + break; /* pass off to ^N handler */ + default: + esc_save[esc_len++] = ichar; + cread_add_str(esc_save, esc_len, insert, + &num, &eol_num, buf, *len); + esc_len = 0; + continue; + } + } + + switch (ichar) { + case 0x1b: + if (esc_len == 0) { + esc_save[esc_len] = ichar; + esc_len = 1; + } else { + printf("impossible condition #876\n"); + esc_len = 0; + } + break; + + case CTL_CH('a'): + BEGINNING_OF_LINE(); + break; + case CTL_CH('c'): /* ^C - break */ + *buf = '\0'; /* discard input */ + return (-1); + case CTL_CH('f'): + if (num < eol_num) { + getcmd_putch(buf[num]); + num++; + } + break; + case CTL_CH('b'): + if (num) { + getcmd_putch(CTL_BACKSPACE); + num--; + } + break; + case CTL_CH('d'): + if (num < eol_num) { + wlen = eol_num - num - 1; + if (wlen) { + memmove(&buf[num], &buf[num+1], wlen); + putnstr(buf + num, wlen); + } + + getcmd_putch(' '); + do { + getcmd_putch(CTL_BACKSPACE); + } while (wlen--); + eol_num--; + } + break; + case CTL_CH('k'): + ERASE_TO_EOL(); + break; + case CTL_CH('e'): + REFRESH_TO_EOL(); + break; + case CTL_CH('o'): + insert = !insert; + break; + case CTL_CH('x'): + case CTL_CH('u'): + BEGINNING_OF_LINE(); + ERASE_TO_EOL(); + break; + case DEL: + case DEL7: + case 8: + if (num) { + wlen = eol_num - num; + num--; + memmove(&buf[num], &buf[num+1], wlen); + getcmd_putch(CTL_BACKSPACE); + putnstr(buf + num, wlen); + getcmd_putch(' '); + do { + getcmd_putch(CTL_BACKSPACE); + } while (wlen--); + eol_num--; + } + break; + case CTL_CH('p'): + case CTL_CH('n'): + { + char * hline; + + esc_len = 0; + + if (ichar == CTL_CH('p')) + hline = hist_prev(); + else + hline = hist_next(); + + if (!hline) { + getcmd_cbeep(); + continue; + } + + /* nuke the current line */ + /* first, go home */ + BEGINNING_OF_LINE(); + + /* erase to end of line */ + ERASE_TO_EOL(); + + /* copy new line into place and display */ + strcpy(buf, hline); + eol_num = strlen(buf); + REFRESH_TO_EOL(); + continue; + } +#ifdef CONFIG_AUTO_COMPLETE + case '\t': { + int num2, col; + + /* do not autocomplete when in the middle */ + if (num < eol_num) { + getcmd_cbeep(); + break; + } + + buf[num] = '\0'; + col = strlen(prompt) + eol_num; + num2 = num; + if (cmd_auto_complete(prompt, buf, &num2, &col)) { + col = num2 - num; + num += col; + eol_num += col; + } + break; + } +#endif + default: + cread_add_char(ichar, insert, &num, &eol_num, buf, *len); + break; + } + } + *len = eol_num; + buf[eol_num] = '\0'; /* lose the newline */ + + if (buf[0] && buf[0] != CREAD_HIST_CHAR) + cread_add_to_hist(buf); + hist_cur = hist_add_idx; + + return 0; +} + +#endif /* CONFIG_CMDLINE_EDITING */ + +/****************************************************************************/ + +#ifdef CONFIG_CMDLINE +/* + * Prompt for input and read a line. + * If CONFIG_BOOT_RETRY_TIME is defined and retry_time >= 0, + * time out when time goes past endtime (timebase time in ticks). + * Return: number of read characters + * -1 if break + * -2 if timed out + */ +int ubreadline (const char *const prompt) +{ + /* + * If console_buffer isn't 0-length the user will be prompted to modify + * it instead of entering it from scratch as desired. + */ + console_buffer[0] = '\0'; + + return ubreadline_into_buffer(prompt, console_buffer, 0); +} + + +int ubreadline_into_buffer(const char *const prompt, char *buffer, int timeout) +{ + char *p = buffer; + unsigned int len = CONFIG_SYS_CBSIZE; + int rc; + static int initted = 0; + + /* + * History uses a global array which is not + * writable until after relocation to RAM. + * Revert to non-history version if still + * running from flash. + */ + if (0) { + if (!initted) { + hist_init(); + initted = 1; + } + + if (prompt) + printf (prompt); + + rc = cread_line(prompt, p, &len, timeout); + return rc < 0 ? rc : len; + + } else { + char * p_buf = p; + int n = 0; /* buffer index */ + int plen = 0; /* prompt length */ + int col; /* output column cnt */ + char c; + + /* print prompt */ + if (prompt) { + plen = strlen (prompt); + printf (prompt); + } + col = plen; + + for (;;) { + + c = serial_getchar(); + + /* + * Special character handling + */ + switch (c) { + case '\r': /* Enter */ + case '\n': + *p = '\0'; + printf ("\r\n"); + return p - p_buf; + + case '\0': /* nul */ + continue; + + case 0x03: /* ^C - break */ + p_buf[0] = '\0'; /* discard input */ + return -1; + + case 0x15: /* ^U - erase line */ + while (col > plen) { + printf (erase_seq); + --col; + } + p = p_buf; + n = 0; + continue; + + case 0x17: /* ^W - erase word */ + p=delete_char(p_buf, p, &col, &n, plen); + while ((n > 0) && (*p != ' ')) { + p=delete_char(p_buf, p, &col, &n, plen); + } + continue; + + case 0x08: /* ^H - backspace */ + case 0x7F: /* DEL - backspace */ + p=delete_char(p_buf, p, &col, &n, plen); + continue; + + default: + /* + * Must be a normal character then + */ + if (n < CONFIG_SYS_CBSIZE-2) { + if (c == '\t') { /* expand TABs */ + /* if auto completion triggered just continue */ + *p = '\0'; + if (cmd_auto_complete(prompt, console_buffer, &n, &col)) { + p = p_buf + n; /* reset */ + continue; + } + printf (tab_seq+(col&07)); + col += 8 - (col&07); + } else { + char buf[2]; + + /* + * Echo input using printf() to force an + * LCD flush if we are using an LCD + */ + ++col; + buf[0] = c; + buf[1] = '\0'; + printf(buf); + } + *p++ = c; + ++n; + } else { /* Buffer full */ + serial_putchar('\a'); + } + } + } + } +} + +/****************************************************************************/ + +static char * delete_char (char *buffer, char *p, int *colp, int *np, int plen) +{ + char *s; + + if (*np == 0) { + return (p); + } + + if (*(--p) == '\t') { /* will retype the whole line */ + while (*colp > plen) { + printf (erase_seq); + (*colp)--; + } + for (s=buffer; s= CONFIG_SYS_CBSIZE) { + printf ("## Command too long!\n"); + return -1; + } + + strcpy (cmdbuf, cmd); + + /* Process separators and check for invalid + * repeatable commands + */ + + debug_parser("[PROCESS_SEPARATORS] %s\n", cmd); + while (*str) { + + /* + * Find separator, or string end + * Allow simple escape of ';' by writing "\;" + */ + for (inquotes = 0, sep = str; *sep; sep++) { + if ((*sep=='\'') && + (*(sep-1) != '\\')) + inquotes=!inquotes; + + if (!inquotes && + (*sep == ';') && /* separator */ + ( sep != str) && /* past string start */ + (*(sep-1) != '\\')) /* and NOT escaped */ + break; + } + + /* + * Limit the token to data between separators + */ + token = str; + if (*sep) { + str = sep + 1; /* start of command for next pass */ + *sep = '\0'; + } + else + str = sep; /* no more commands for next pass */ + debug_parser("token: \"%s\"\n", token); + + /* find macros in this token and replace them */ + process_macros (token, finaltoken); + + /* Extract arguments */ + if ((argc = parse_line (finaltoken, argv)) == 0) { + rc = -1; /* no command at all */ + continue; + } + + if (cmd_process(flag, argc, argv, &repeatable, NULL)) + rc = -1; + + /* Did the user stop this? */ + //if (had_ctrlc ()) + // return -1; /* if stopped then not repeatable */ + } + + return rc ? rc : repeatable; +} +#endif + +#ifdef CONFIG_CMDLINE +/* + * Run a command using the selected parser. + * + * @param cmd Command to run + * @param flag Execution flags (CMD_FLAG_...) + * @return 0 on success, or != 0 on error. + */ +int run_command(const char *cmd, int flag) +{ +#ifndef CONFIG_SYS_HUSH_PARSER + /* + * builtin_run_command can return 0 or 1 for success, so clean up + * its result. + */ + if (builtin_run_command(cmd, flag) == -1) + return 1; + + return 0; +#else + return parse_string_outer(cmd, + FLAG_PARSE_SEMICOLON | FLAG_EXIT_FROM_LOOP); +#endif +} +#endif + +#if !defined(CONFIG_SYS_HUSH_PARSER) && defined(CONFIG_CMDLINE) +/** + * Execute a list of command separated by ; or \n using the built-in parser. + * + * This function cannot take a const char * for the command, since if it + * finds newlines in the string, it replaces them with \0. + * + * @param cmd String containing list of commands + * @param flag Execution flags (CMD_FLAG_...) + * @return 0 on success, or != 0 on error. + */ +static int builtin_run_command_list(char *cmd, int flag) +{ + char *line, *next; + int rcode = 0; + + /* + * Break into individual lines, and execute each line; terminate on + * error. + */ + line = next = cmd; + while (*next) { + if (*next == '\n') { + *next = '\0'; + /* run only non-empty commands */ + if (*line) { + debug("** exec: \"%s\"\n", line); + if (builtin_run_command(line, 0) < 0) { + rcode = 1; + break; + } + } + line = next + 1; + } + ++next; + } + if (rcode == 0 && *line) + rcode = (builtin_run_command(line, 0) >= 0); + + return rcode; +} +#endif + +#ifdef CONFIG_CMDLINE +int run_command_list(const char *cmd, int len, int flag) +{ + int need_buff = 1; + char *buff = (char *)cmd; /* cast away const */ + int rcode = 0; + + if (len == -1) { + len = strlen(cmd); +#ifdef CONFIG_SYS_HUSH_PARSER + /* hush will never change our string */ + need_buff = 0; +#else + /* the built-in parser will change our string if it sees \n */ + need_buff = strchr(cmd, '\n') != NULL; +#endif + } + if (need_buff) { + buff = malloc(len + 1); + if (!buff) + return 1; + memcpy(buff, cmd, len); + buff[len] = '\0'; + } +#ifdef CONFIG_SYS_HUSH_PARSER + rcode = parse_string_outer(buff, FLAG_PARSE_SEMICOLON); +#else + /* + * This function will overwrite any \n it sees with a \0, which + * is why it can't work with a const char *. Here we are making + * using of internal knowledge of this function, to avoid always + * doing a malloc() which is actually required only in a case that + * is pretty rare. + */ + rcode = builtin_run_command_list(buff, flag); + if (need_buff) + free(buff); +#endif + + return rcode; +} +#endif + +/****************************************************************************/ + +#if defined(CONFIG_CMD_RUN) +int do_run (cmd_tbl_t * cmdtp, int flag, int argc, char * const argv[]) +{ + int i; + + if (argc < 2) + return CMD_RET_USAGE; + + for (i=1; i +#include +#include +#include + +#endif diff --git a/payloads/ubootcli/ubootcli.ldscript.arm b/payloads/ubootcli/ubootcli.ldscript.arm new file mode 100644 index 0000000000..108a94252c --- /dev/null +++ b/payloads/ubootcli/ubootcli.ldscript.arm @@ -0,0 +1,92 @@ +/* + * This file is part of the bayou project. + * + * Copyright (C) 2008 Advanced Micro Devices, Inc. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +BASE_ADDRESS = 0x81000000; + +/*OUTPUT_FORMAT(armv7a-eabi) +OUTPUT_ARCH(arm)*/ + +ENTRY(_entry) + +HEAP_SIZE = 16384; +STACK_SIZE = 16384; + +SECTIONS +{ + . = BASE_ADDRESS; + + . = ALIGN(16); + _start = .; + + .text : { + *(.text._entry) + *(.text) + *(.text.*) + } + + .rodata : { + *(.rodata) + *(.rodata.*) + } + + /* whatever. */ + PROVIDE_HIDDEN (__exidx_start = .); + .ARM.exidx : { *(.ARM.exidx* .gnu.linkonce.armexidx.*) } + PROVIDE_HIDDEN (__exidx_end = .); + + .data : { + *(.data) + *(.data.*) + } + + _edata = .; + + .bss : { + *(.bss) + *(.bss.*) + *(COMMON) + + /* Stack and heap */ + + . = ALIGN(16); + _heap = .; + . += HEAP_SIZE; + . = ALIGN(16); + _eheap = .; + + _estack = .; + . += STACK_SIZE; + . = ALIGN(16); + _stack = .; + } + + _end = .; + + /DISCARD/ : { *(.comment) *(.note) *(.note.*) } +} diff --git a/payloads/ubootcli/ubootcli.ldscript.i386 b/payloads/ubootcli/ubootcli.ldscript.i386 new file mode 100644 index 0000000000..86baaecb2e --- /dev/null +++ b/payloads/ubootcli/ubootcli.ldscript.i386 @@ -0,0 +1,87 @@ +/* + * This file is part of the bayou project. + * + * Copyright (C) 2008 Advanced Micro Devices, Inc. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +BASE_ADDRESS = 0x19000; + +OUTPUT_FORMAT(elf32-i386) +OUTPUT_ARCH(i386) + +ENTRY(_entry) + +HEAP_SIZE = 16384; +STACK_SIZE = 16384; + +SECTIONS +{ + . = BASE_ADDRESS; + + . = ALIGN(16); + _start = .; + + .text : { + *(.text._entry) + *(.text) + *(.text.*) + } + + .rodata : { + *(.rodata) + *(.rodata.*) + } + + .data : { + *(.data) + *(.data.*) + } + + _edata = .; + + .bss : { + *(.bss) + *(.bss.*) + *(COMMON) + + /* Stack and heap */ + + . = ALIGN(16); + _heap = .; + . += HEAP_SIZE; + . = ALIGN(16); + _eheap = .; + + _estack = .; + . += STACK_SIZE; + . = ALIGN(16); + _stack = .; + } + + _end = .; + + /DISCARD/ : { *(.comment) *(.note) *(.note.*) } +}