diff options
author | Cédric VINCENT <cedric.vincent@st.com> | 2011-06-29 12:49:41 +0200 |
---|---|---|
committer | Riku Voipio <riku.voipio@linaro.org> | 2011-07-11 16:05:46 +0300 |
commit | 1c1b40c162a6964e1898e84304230a308f4d16c3 (patch) | |
tree | 466ba6790959c64478f8c8a7f5e1107d0e0d4794 | |
parent | 9312805d33e8b106bae356d13a8071fb37d75554 (diff) |
arm-semi: Provide access to CLI arguments passed through the "-append" option
This patch basically adapts the new semi-hosting command-line support
-- introduced by Wolfgang Schildbach in the commit 2e8785ac -- for use
in system-mode.
Note that the "arm_cmdline_len" and "host_cmdline_len" variables were
renamed respectively "input_size" and "output_size" because:
* in C, the term "length" is generally used to count the number of
character in a string, not to count the number of bytes in a
buffer (as it is the case here).
* in QEMU, the term "host" is used to name variables that are in
the host address space, not to name variables in the target
address space (as it is the case here).
* in the case of this system-call, the terms "input" and "output"
fit the semantic of the official ARM semi-hosting specification
quite well.
I know renaming can be considered harmful but I do think in this case
the semantic really matters to keep this code more understandable.
Signed-off-by: Cédric VINCENT <cedric.vincent@st.com>
Reviewed-by: Christophe Lyon <christophe.lyon@st.com>
Cc: Peter Maydell <peter.maydell@linaro.org>
Cc: Paul Brook <paul@codesourcery.com>
Cc: Wolfgang Schildbach <wschi@dolby.com>
Cc: Riku Voipio <riku.voipio@iki.fi>
Signed-off-by: Riku Voipio <riku.voipio@linaro.org>
-rw-r--r-- | arm-semi.c | 113 |
1 files changed, 67 insertions, 46 deletions
diff --git a/arm-semi.c b/arm-semi.c index 5a62d03b36..873518a20e 100644 --- a/arm-semi.c +++ b/arm-semi.c @@ -34,6 +34,7 @@ #else #include "qemu-common.h" #include "gdbstub.h" +#include "hw/arm-misc.h" #endif #define SYS_OPEN 0x01 @@ -369,68 +370,88 @@ uint32_t do_arm_semihosting(CPUState *env) return syscall_err; #endif case SYS_GET_CMDLINE: -#ifdef CONFIG_USER_ONLY - /* Build a commandline from the original argv. */ { - char *arm_cmdline_buffer; - const char *host_cmdline_buffer; + /* Build a command-line from the original argv. + * + * The inputs are: + * * ARG(0), pointer to a buffer of at least the size + * specified in ARG(1). + * * ARG(1), size of the buffer pointed to by ARG(0) in + * bytes. + * + * The outputs are: + * * ARG(0), pointer to null-terminated string of the + * command line. + * * ARG(1), length of the string pointed to by ARG(0). + */ - unsigned int i; - unsigned int arm_cmdline_len = ARG(1); - unsigned int host_cmdline_len = - ts->info->arg_end-ts->info->arg_start; + char *output_buffer; + size_t input_size = ARG(1); + size_t output_size; + int status = 0; - if (!arm_cmdline_len || host_cmdline_len > arm_cmdline_len) { - return -1; /* not enough space to store command line */ - } + /* Compute the size of the output string. */ +#if !defined(CONFIG_USER_ONLY) + output_size = strlen(ts->boot_info->kernel_filename) + + 1 /* Separating space. */ + + strlen(ts->boot_info->kernel_cmdline) + + 1; /* Terminating null byte. */ +#else + unsigned int i; - if (!host_cmdline_len) { + output_size = ts->info->arg_end - ts->info->arg_start; + if (!output_size) { /* We special-case the "empty command line" case (argc==0). Just provide the terminating 0. */ - arm_cmdline_buffer = lock_user(VERIFY_WRITE, ARG(0), 1, 0); - arm_cmdline_buffer[0] = 0; - unlock_user(arm_cmdline_buffer, ARG(0), 1); + output_size = 1; + } +#endif - /* Adjust the commandline length argument. */ - SET_ARG(1, 0); - return 0; + if (output_size > input_size) { + /* Not enough space to store command-line arguments. */ + return -1; } - /* lock the buffers on the ARM side */ - arm_cmdline_buffer = - lock_user(VERIFY_WRITE, ARG(0), host_cmdline_len, 0); - host_cmdline_buffer = - lock_user(VERIFY_READ, ts->info->arg_start, - host_cmdline_len, 1); + /* Adjust the command-line length. */ + SET_ARG(1, output_size - 1); - if (arm_cmdline_buffer && host_cmdline_buffer) - { - /* the last argument is zero-terminated; - no need for additional termination */ - memcpy(arm_cmdline_buffer, host_cmdline_buffer, - host_cmdline_len); + /* Lock the buffer on the ARM side. */ + output_buffer = lock_user(VERIFY_WRITE, ARG(0), output_size, 0); + if (!output_buffer) { + return -1; + } - /* separate arguments by white spaces */ - for (i = 0; i < host_cmdline_len-1; i++) { - if (arm_cmdline_buffer[i] == 0) { - arm_cmdline_buffer[i] = ' '; - } - } + /* Copy the command-line arguments. */ +#if !defined(CONFIG_USER_ONLY) + pstrcpy(output_buffer, output_size, ts->boot_info->kernel_filename); + pstrcat(output_buffer, output_size, " "); + pstrcat(output_buffer, output_size, ts->boot_info->kernel_cmdline); +#else + if (output_size == 1) { + /* Empty command-line. */ + output_buffer[0] = '\0'; + goto out; + } - /* Adjust the commandline length argument. */ - SET_ARG(1, host_cmdline_len-1); + if (copy_from_user(output_buffer, ts->info->arg_start, + output_size)) { + status = -1; + goto out; } - /* Unlock the buffers on the ARM side. */ - unlock_user(arm_cmdline_buffer, ARG(0), host_cmdline_len); - unlock_user((void*)host_cmdline_buffer, ts->info->arg_start, 0); + /* Separate arguments by white spaces. */ + for (i = 0; i < output_size - 1; i++) { + if (output_buffer[i] == 0) { + output_buffer[i] = ' '; + } + } + out: +#endif + /* Unlock the buffer on the ARM side. */ + unlock_user(output_buffer, ARG(0), output_size); - /* Return success if we could return a commandline. */ - return (arm_cmdline_buffer && host_cmdline_buffer) ? 0 : -1; + return status; } -#else - return -1; -#endif case SYS_HEAPINFO: { uint32_t *ptr; |