From 1c1b40c162a6964e1898e84304230a308f4d16c3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?C=C3=A9dric=20VINCENT?= Date: Wed, 29 Jun 2011 12:49:41 +0200 Subject: [PATCH] arm-semi: Provide access to CLI arguments passed through the "-append" option MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 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 Reviewed-by: Christophe Lyon Cc: Peter Maydell Cc: Paul Brook Cc: Wolfgang Schildbach Cc: Riku Voipio Signed-off-by: Riku Voipio --- arm-semi.c | 129 +++++++++++++++++++++++++++++++---------------------- 1 file changed, 75 insertions(+), 54 deletions(-) diff --git a/arm-semi.c b/arm-semi.c index 5a62d03b3..873518a20 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). + */ + char *output_buffer; + size_t input_size = ARG(1); + size_t output_size; + int status = 0; + + /* 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; - unsigned int arm_cmdline_len = ARG(1); - unsigned int host_cmdline_len = - ts->info->arg_end-ts->info->arg_start; - if (!arm_cmdline_len || host_cmdline_len > arm_cmdline_len) { - return -1; /* not enough space to store command line */ - } - - 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); - - /* Adjust the commandline length argument. */ - SET_ARG(1, 0); - return 0; + output_size = 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); - - 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); - - /* separate arguments by white spaces */ - for (i = 0; i < host_cmdline_len-1; i++) { - if (arm_cmdline_buffer[i] == 0) { - arm_cmdline_buffer[i] = ' '; - } - } - - /* Adjust the commandline length argument. */ - SET_ARG(1, host_cmdline_len-1); - } - - /* 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); - - /* Return success if we could return a commandline. */ - return (arm_cmdline_buffer && host_cmdline_buffer) ? 0 : -1; - } -#else - return -1; #endif + + if (output_size > input_size) { + /* Not enough space to store command-line arguments. */ + return -1; + } + + /* Adjust the command-line length. */ + SET_ARG(1, output_size - 1); + + /* Lock the buffer on the ARM side. */ + output_buffer = lock_user(VERIFY_WRITE, ARG(0), output_size, 0); + if (!output_buffer) { + return -1; + } + + /* 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; + } + + if (copy_from_user(output_buffer, ts->info->arg_start, + output_size)) { + status = -1; + goto out; + } + + /* 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 status; + } case SYS_HEAPINFO: { uint32_t *ptr;