aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-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;