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>
This commit is contained in:
parent
9312805d33
commit
1c1b40c162
129
arm-semi.c
129
arm-semi.c
@ -34,6 +34,7 @@
|
|||||||
#else
|
#else
|
||||||
#include "qemu-common.h"
|
#include "qemu-common.h"
|
||||||
#include "gdbstub.h"
|
#include "gdbstub.h"
|
||||||
|
#include "hw/arm-misc.h"
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#define SYS_OPEN 0x01
|
#define SYS_OPEN 0x01
|
||||||
@ -369,68 +370,88 @@ uint32_t do_arm_semihosting(CPUState *env)
|
|||||||
return syscall_err;
|
return syscall_err;
|
||||||
#endif
|
#endif
|
||||||
case SYS_GET_CMDLINE:
|
case SYS_GET_CMDLINE:
|
||||||
#ifdef CONFIG_USER_ONLY
|
|
||||||
/* Build a commandline from the original argv. */
|
|
||||||
{
|
{
|
||||||
char *arm_cmdline_buffer;
|
/* Build a command-line from the original argv.
|
||||||
const char *host_cmdline_buffer;
|
*
|
||||||
|
* 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 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) {
|
output_size = ts->info->arg_end - ts->info->arg_start;
|
||||||
return -1; /* not enough space to store command line */
|
if (!output_size) {
|
||||||
}
|
|
||||||
|
|
||||||
if (!host_cmdline_len) {
|
|
||||||
/* We special-case the "empty command line" case (argc==0).
|
/* We special-case the "empty command line" case (argc==0).
|
||||||
Just provide the terminating 0. */
|
Just provide the terminating 0. */
|
||||||
arm_cmdline_buffer = lock_user(VERIFY_WRITE, ARG(0), 1, 0);
|
output_size = 1;
|
||||||
arm_cmdline_buffer[0] = 0;
|
|
||||||
unlock_user(arm_cmdline_buffer, ARG(0), 1);
|
|
||||||
|
|
||||||
/* Adjust the commandline length argument. */
|
|
||||||
SET_ARG(1, 0);
|
|
||||||
return 0;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* 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
|
#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:
|
case SYS_HEAPINFO:
|
||||||
{
|
{
|
||||||
uint32_t *ptr;
|
uint32_t *ptr;
|
||||||
|
Loading…
Reference in New Issue
Block a user