Patchwork arm-semi: Provide access to CLI arguments passed through the "-append" option

login
register
mail settings
Submitter vincent
Date June 16, 2011, 3:06 p.m.
Message ID <1308236761-476-1-git-send-email-cedric.vincent@st.com>
Download mbox | patch
Permalink /patch/100664/
State New
Headers show

Comments

vincent - June 16, 2011, 3:06 p.m.
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: Wolfgang Schildbach <wschi@dolby.com>
Cc: Riku Voipio <riku.voipio@iki.fi>
---
 arm-semi.c |  113 +++++++++++++++++++++++++++++++++++------------------------
 1 files changed, 67 insertions(+), 46 deletions(-)
vincent - June 28, 2011, 2:35 p.m.
Ping.

On 06/16/2011, Cedric VINCENT wrote:
> This patch basically adapts the new semi-hosting command-line support
> -- introduced by Wolfgang Schildbach in the commit 2e8785ac -- for use
> in system-mode.
Peter Maydell - June 28, 2011, 5:22 p.m.
2011/6/16 Cédric VINCENT <cedric.vincent@st.com>:
> This patch basically adapts the new semi-hosting command-line support
> -- introduced by Wolfgang Schildbach in the commit 2e8785ac -- for use
> in system-mode.

Generally looks OK. Some nits:

> -        /* Build a commandline from the original argv.  */
> +        /* Build a command-line from the original argv.
> +         *

If you're going to expand this into a multiline comment I'd prefer
it to be inside the brace rather than outside.

> +            if (!input_size || output_size > input_size) {
> +                 /* Not enough space to store command-line arguments.  */
> +                return -1;

You can drop the check for !input_size here, because you've eliminated
the case where output_size == 0, and so a zero input_size will be
caught by the other half of the conditional.

> +            /* Separate arguments by white spaces.  */
> +            for (i = 0; i < output_size; i++) {
> +                if (output_buffer[i] == 0) {
> +                    output_buffer[i] = ' ';
> +                }
> +            }

This will turn the final trailing NUL into a space -- should
be "i < output_size - 1".

> +        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
> +        /* Never reached.  */

This is kind of obvious so I think the comment is unnecessary.

-- PMM

Patch

diff --git a/arm-semi.c b/arm-semi.c
index e9e6f89..eac09bf 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.  */
+        /* 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 *arm_cmdline_buffer;
-            const char *host_cmdline_buffer;
+            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);
+                output_size = 1;
+            }
+#endif
 
-                /* Adjust the commandline length argument. */
-                SET_ARG(1, 0);
-                return 0;
+            if (!input_size || 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; 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
+        /* Never reached.  */
     case SYS_HEAPINFO:
         {
             uint32_t *ptr;