
Signed-off-by: Mike Frysinger vapier@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