aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorCédric VINCENT <cedric.vincent@st.com>2011-06-29 12:49:41 +0200
committerRiku Voipio <riku.voipio@linaro.org>2011-07-11 16:05:46 +0300
commit1c1b40c162a6964e1898e84304230a308f4d16c3 (patch)
tree466ba6790959c64478f8c8a7f5e1107d0e0d4794
parent9312805d33e8b106bae356d13a8071fb37d75554 (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.c113
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;