Signed-off-by: Mike Frysinger <vap...@gentoo.org>
---
 arch/sandbox/cpu/os.c                     |   64 ++++++++++++++++++++++
 arch/sandbox/cpu/start.c                  |   83 +++++++++++++++++++++++++++++
 arch/sandbox/cpu/u-boot.lds               |    4 ++
 arch/sandbox/include/asm/state.h          |    5 ++
 arch/sandbox/include/asm/u-boot-sandbox.h |    1 +
 arch/sandbox/lib/board.c                  |    1 +
 include/os.h                              |   35 ++++++++++++
 7 files changed, 193 insertions(+), 0 deletions(-)

diff --git a/arch/sandbox/cpu/os.c b/arch/sandbox/cpu/os.c
index cb469e0..4b1c987 100644
--- a/arch/sandbox/cpu/os.c
+++ b/arch/sandbox/cpu/os.c
@@ -21,6 +21,7 @@
 
 #include <errno.h>
 #include <fcntl.h>
+#include <getopt.h>
 #include <stdlib.h>
 #include <termios.h>
 #include <time.h>
@@ -32,6 +33,7 @@
 #include <linux/types.h>
 
 #include <os.h>
+#include <asm/state.h>
 
 /* Operating System Interface */
 
@@ -155,3 +157,65 @@ u64 os_get_nsec(void)
        return tv.tv_sec * 1000000000ULL + tv.tv_usec * 1000;
 #endif
 }
+
+extern struct sb_cmdline_option *__u_boot_sb_getopt_start[],
+       *__u_boot_sb_getopt_end[];
+static char *short_opts;
+static struct option *long_opts;
+
+int os_parse_args(struct sandbox_state *state, int argc, char *argv[])
+{
+       struct sb_cmdline_option **sb_opt = __u_boot_sb_getopt_start;
+       size_t num_flags = __u_boot_sb_getopt_end - __u_boot_sb_getopt_start;
+       size_t i;
+
+       int hidden_short_opt;
+       size_t si;
+
+       int c;
+
+       if (short_opts || long_opts)
+               os_exit(1);
+
+       state->argc = argc;
+       state->argv = argv;
+
+       short_opts = os_malloc(sizeof(*short_opts) * (num_flags + 1));
+       long_opts = os_malloc(sizeof(*long_opts) * num_flags);
+       if (!short_opts || !long_opts)
+               os_exit(1);
+
+       si = 0;
+       hidden_short_opt = 0x80;
+       for (i = 0; i < num_flags; ++i) {
+               long_opts[i].name = sb_opt[i]->flag;
+               long_opts[i].has_arg = sb_opt[i]->has_arg ?
+                       required_argument : no_argument;
+               long_opts[i].flag = NULL;
+
+               if (sb_opt[i]->flag_short)
+                       short_opts[si++] = long_opts[i].val = 
sb_opt[i]->flag_short;
+               else
+                       long_opts[i].val = sb_opt[i]->flag_short = 
hidden_short_opt++;
+       }
+       short_opts[si] = '\0';
+
+       /* We need to handle output ourselves since u-boot provides printf */
+       opterr = 0;
+
+       while ((c = getopt_long(argc, argv, short_opts, long_opts, NULL)) != 
-1) {
+               for (i = 0; i < num_flags; ++i) {
+                       if (sb_opt[i]->flag_short == c) {
+                               sb_opt[i]->callback(state, optarg);
+                               break;
+                       }
+               }
+               if (i == num_flags) {
+                       /* store the faulting flag index for later */
+                       state->parse_err = -optind;
+                       break;
+               }
+       }
+
+       return 0;
+}
diff --git a/arch/sandbox/cpu/start.c b/arch/sandbox/cpu/start.c
index dc020ee..895ec49 100644
--- a/arch/sandbox/cpu/start.c
+++ b/arch/sandbox/cpu/start.c
@@ -22,19 +22,102 @@
 #include <common.h>
 #include <asm/state.h>
 
+#include <os.h>
+
+extern struct sb_cmdline_option *__u_boot_sb_getopt_start[],
+       *__u_boot_sb_getopt_end[];
+
+int sb_early_getopt_check(void)
+{
+       struct sandbox_state *state = state_get_current();
+       struct sb_cmdline_option **sb_opt = __u_boot_sb_getopt_start;
+       size_t num_flags = __u_boot_sb_getopt_end - __u_boot_sb_getopt_start;
+       size_t i;
+       int max_arg_len, max_noarg_len;
+
+       if (state->parse_err == 0)
+               return 0;
+
+       if (state->parse_err < 0)
+               printf("error: unknown option: %s\n\n",
+                       state->argv[-state->parse_err - 1]);
+
+       printf(
+               "u-boot, a command line test interface to U-Boot\n\n"
+               "Usage: u-boot [options]\n"
+               "Options:\n");
+
+       max_arg_len = 0;
+       for (i = 0; i < num_flags; ++i)
+               max_arg_len = max(strlen(sb_opt[i]->flag), max_arg_len);
+       max_noarg_len = max_arg_len + 7;
+
+       for (i = 0; i < num_flags; ++i) {
+               /* first output the short flag if it has one */
+               if (sb_opt[i]->flag_short >= 0x80)
+                       printf("      ");
+               else
+                       printf("  -%c, ", sb_opt[i]->flag_short);
+
+               /* then the long flag */
+               if (sb_opt[i]->has_arg)
+                       printf("--%-*s", max_noarg_len, sb_opt[i]->flag);
+               else
+                       printf("--%-*s <arg> ", max_arg_len, sb_opt[i]->flag);
+
+               /* finally the help text */
+               printf("  %s\n", sb_opt[i]->help);
+       }
+
+       os_exit(state->parse_err < 0 ? 1 : 0);
+}
+
+static int sb_cmdline_cb_help(struct sandbox_state *state, const char *arg)
+{
+       /* just flag to sb_early_getopt_check to show usage */
+       state->parse_err = 1;
+       return 0;
+}
+SB_CMDLINE_OPT_SHORT(help, 'h', 0, "Display help");
+
 int sb_main_loop_init(void)
 {
+       struct sandbox_state *state = state_get_current();
+
+       /* Execute command if required */
+       if (state->cmd) {
+               /* TODO: redo this when cmd tidy-up series lands */
+#ifdef CONFIG_SYS_HUSH_PARSER
+               run_command(state->cmd, 0);
+#else
+               parse_string_outer(state->cmd, FLAG_PARSE_SEMICOLON |
+                                   FLAG_EXIT_FROM_LOOP);
+#endif
+               os_exit(state->exit_type);
+       }
+
+       return 0;
+}
+
+static int sb_cmdline_cb_command(struct sandbox_state *state, const char *arg)
+{
+       state->cmd = arg;
        return 0;
 }
+SB_CMDLINE_OPT_SHORT(command, 'c', 1, "Execute U-Boot command");
 
 int main(int argc, char *argv[])
 {
+       struct sandbox_state *state;
        int err;
 
        err = state_init();
        if (err)
                return err;
 
+       state = state_get_current();
+       os_parse_args(state, argc, argv);
+
        /*
         * Do pre- and post-relocation init, then start up U-Boot. This will
         * never return.
diff --git a/arch/sandbox/cpu/u-boot.lds b/arch/sandbox/cpu/u-boot.lds
index 0c56aa7..2ca6b8c 100644
--- a/arch/sandbox/cpu/u-boot.lds
+++ b/arch/sandbox/cpu/u-boot.lds
@@ -28,6 +28,10 @@ SECTIONS
        _u_boot_cmd : { *(.u_boot_cmd) }
        __u_boot_cmd_end = .;
 
+       __u_boot_sb_getopt_start = .;
+       _u_boot_sb_getopt : { *(.u_boot_sb_getopt) }
+       __u_boot_sb_getopt_end = .;
+
        __bss_start = .;
 }
 
diff --git a/arch/sandbox/include/asm/state.h b/arch/sandbox/include/asm/state.h
index 5b34e94..edeef08 100644
--- a/arch/sandbox/include/asm/state.h
+++ b/arch/sandbox/include/asm/state.h
@@ -22,6 +22,8 @@
 #ifndef __SANDBOX_STATE_H
 #define __SANDBOX_STATE_H
 
+#include <config.h>
+
 /* How we exited U-Boot */
 enum exit_type_id {
        STATE_EXIT_NORMAL,
@@ -33,6 +35,9 @@ enum exit_type_id {
 struct sandbox_state {
        const char *cmd;                /* Command to execute */
        enum exit_type_id exit_type;    /* How we exited U-Boot */
+       int parse_err;                  /* Error to report from parsing */
+       int argc;                       /* Program arguments */
+       char **argv;
 };
 
 /**
diff --git a/arch/sandbox/include/asm/u-boot-sandbox.h 
b/arch/sandbox/include/asm/u-boot-sandbox.h
index f0e8b3c..8255e9d 100644
--- a/arch/sandbox/include/asm/u-boot-sandbox.h
+++ b/arch/sandbox/include/asm/u-boot-sandbox.h
@@ -36,6 +36,7 @@ int board_init(void);
 int dram_init(void);
 
 /* start.c */
+int sb_early_getopt_check(void);
 int sb_main_loop_init(void);
 
 #endif /* _U_BOOT_SANDBOX_H_ */
diff --git a/arch/sandbox/lib/board.c b/arch/sandbox/lib/board.c
index 1082e7d..5c6da5b 100644
--- a/arch/sandbox/lib/board.c
+++ b/arch/sandbox/lib/board.c
@@ -134,6 +134,7 @@ init_fnc_t *init_sequence[] = {
        env_init,               /* initialize environment */
        serial_init,            /* serial communications setup */
        console_init_f,         /* stage 1 init of console */
+       sb_early_getopt_check,
        display_banner,         /* say that we are here */
 #if defined(CONFIG_DISPLAY_CPUINFO)
        print_cpuinfo,          /* display cpu info (and speed) */
diff --git a/include/os.h b/include/os.h
index 6b7ee47..aea4503 100644
--- a/include/os.h
+++ b/include/os.h
@@ -27,6 +27,8 @@
 #ifndef __OS_H__
 #define __OS_H__
 
+struct sandbox_state;
+
 /**
  * Access to the OS read() system call
  *
@@ -122,4 +124,37 @@ void os_usleep(unsigned long usec);
  */
 u64 os_get_nsec(void);
 
+/**
+ * Parse arguments and update sandbox state.
+ *
+ * @param state                Sandbox state to update
+ * @param argc         Argument count
+ * @param argv         Argument vector
+ * @return 0 if ok, and program should continue;
+ *     1 if ok, but program should stop;
+ *     -1 on error: program should terminate.
+ */
+int os_parse_args(struct sandbox_state *state, int argc, char *argv[]);
+
+struct sb_cmdline_option {
+       const char *flag;
+       char flag_short;
+       const char *help;
+       int has_arg;
+       int (*callback)(struct sandbox_state *state, const char *opt);
+};
+#define _SB_CMDLINE_OPT(f, s, ha, h) \
+       static struct sb_cmdline_option sb_cmdline_option_##f = { \
+               .flag = #f, \
+               .flag_short = s, \
+               .help = h, \
+               .has_arg = ha, \
+               .callback = sb_cmdline_cb_##f, \
+       }; \
+       static __attribute__((section(".u_boot_sb_getopt"), used)) \
+               struct sb_cmdline_option *sb_cmdline_option_##f##_ptr = \
+               &sb_cmdline_option_##f
+#define SB_CMDLINE_OPT(f, ha, h) _SB_CMDLINE_OPT(f, 0, ha, h)
+#define SB_CMDLINE_OPT_SHORT(f, s, ha, h) _SB_CMDLINE_OPT(f, s, ha, h)
+
 #endif
-- 
1.7.8.4

_______________________________________________
U-Boot mailing list
U-Boot@lists.denx.de
http://lists.denx.de/mailman/listinfo/u-boot

Reply via email to