aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorPeter Maydell <peter.maydell@linaro.org>2015-10-02 16:04:25 +0100
committerPeter Maydell <peter.maydell@linaro.org>2015-10-02 16:04:26 +0100
commit945507d6bcde334f42b00cae134b4d47301d1821 (patch)
tree17def01738f02281bb54424f3021be8a57d884ac
parent37dd86a44cc4298f58ac370e0190b069469b6d25 (diff)
parent86abac06c142d20772b3f2e04c9bf02b7936a0b3 (diff)
downloadqemu-945507d6bcde334f42b00cae134b4d47301d1821.zip
qemu-945507d6bcde334f42b00cae134b4d47301d1821.tar.gz
qemu-945507d6bcde334f42b00cae134b4d47301d1821.tar.bz2
Merge remote-tracking branch 'remotes/riku/tags/pull-linux-user-20151002' into staging
First set of Linux-user que patches for 2.5 # gpg: Signature made Fri 02 Oct 2015 13:38:00 BST using RSA key ID DE3C9BC0 # gpg: Good signature from "Riku Voipio <riku.voipio@iki.fi>" # gpg: aka "Riku Voipio <riku.voipio@linaro.org>" * remotes/riku/tags/pull-linux-user-20151002: linux-user: assert that target_mprotect cannot fail linux-user/signal.c: Use setup_rt_frame() instead of setup_frame() for target openrisc linux-user/syscall.c: Add EAGAIN to host_to_target_errno_table for linux-user: add name_to_handle_at/open_by_handle_at linux-user: Return target error number in do_fork() linux-user: fix cmsg conversion in case of multiple headers linux-user: remove MAX_ARG_PAGES limit linux-user: remove unused image_info members linux-user: Treat --foo options the same as -foo linux-user: use EXIT_SUCCESS and EXIT_FAILURE linux-user: Add proper error messages for bad options linux-user: Add -help linux-user: Exit 0 when -h is used Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
-rw-r--r--linux-user/elfload.c113
-rw-r--r--linux-user/flatload.c2
-rw-r--r--linux-user/linuxload.c7
-rw-r--r--linux-user/main.c88
-rw-r--r--linux-user/mmap.c5
-rw-r--r--linux-user/qemu.h9
-rw-r--r--linux-user/signal.c9
-rw-r--r--linux-user/syscall.c124
-rw-r--r--linux-user/syscall_defs.h14
9 files changed, 228 insertions, 143 deletions
diff --git a/linux-user/elfload.c b/linux-user/elfload.c
index a7ff58c..fdae6a6 100644
--- a/linux-user/elfload.c
+++ b/linux-user/elfload.c
@@ -1373,66 +1373,69 @@ static bool elf_check_ehdr(struct elfhdr *ehdr)
* to be put directly into the top of new user memory.
*
*/
-static abi_ulong copy_elf_strings(int argc,char ** argv, void **page,
- abi_ulong p)
+static abi_ulong copy_elf_strings(int argc, char **argv, char *scratch,
+ abi_ulong p, abi_ulong stack_limit)
{
- char *tmp, *tmp1, *pag = NULL;
- int len, offset = 0;
+ char *tmp;
+ int len, offset;
+ abi_ulong top = p;
if (!p) {
return 0; /* bullet-proofing */
}
+
+ offset = ((p - 1) % TARGET_PAGE_SIZE) + 1;
+
while (argc-- > 0) {
tmp = argv[argc];
if (!tmp) {
fprintf(stderr, "VFS: argc is wrong");
exit(-1);
}
- tmp1 = tmp;
- while (*tmp++);
- len = tmp - tmp1;
- if (p < len) { /* this shouldn't happen - 128kB */
+ len = strlen(tmp) + 1;
+ tmp += len;
+
+ if (len > (p - stack_limit)) {
return 0;
}
while (len) {
- --p; --tmp; --len;
- if (--offset < 0) {
- offset = p % TARGET_PAGE_SIZE;
- pag = (char *)page[p/TARGET_PAGE_SIZE];
- if (!pag) {
- pag = g_try_malloc0(TARGET_PAGE_SIZE);
- page[p/TARGET_PAGE_SIZE] = pag;
- if (!pag)
- return 0;
- }
- }
- if (len == 0 || offset == 0) {
- *(pag + offset) = *tmp;
- }
- else {
- int bytes_to_copy = (len > offset) ? offset : len;
- tmp -= bytes_to_copy;
- p -= bytes_to_copy;
- offset -= bytes_to_copy;
- len -= bytes_to_copy;
- memcpy_fromfs(pag + offset, tmp, bytes_to_copy + 1);
+ int bytes_to_copy = (len > offset) ? offset : len;
+ tmp -= bytes_to_copy;
+ p -= bytes_to_copy;
+ offset -= bytes_to_copy;
+ len -= bytes_to_copy;
+
+ memcpy_fromfs(scratch + offset, tmp, bytes_to_copy);
+
+ if (offset == 0) {
+ memcpy_to_target(p, scratch, top - p);
+ top = p;
+ offset = TARGET_PAGE_SIZE;
}
}
}
+ if (offset) {
+ memcpy_to_target(p, scratch + offset, top - p);
+ }
+
return p;
}
-static abi_ulong setup_arg_pages(abi_ulong p, struct linux_binprm *bprm,
+/* Older linux kernels provide up to MAX_ARG_PAGES (default: 32) of
+ * argument/environment space. Newer kernels (>2.6.33) allow more,
+ * dependent on stack size, but guarantee at least 32 pages for
+ * backwards compatibility.
+ */
+#define STACK_LOWER_LIMIT (32 * TARGET_PAGE_SIZE)
+
+static abi_ulong setup_arg_pages(struct linux_binprm *bprm,
struct image_info *info)
{
- abi_ulong stack_base, size, error, guard;
- int i;
+ abi_ulong size, error, guard;
- /* Create enough stack to hold everything. If we don't use
- it for args, we'll use it for something else. */
size = guest_stack_size;
- if (size < MAX_ARG_PAGES*TARGET_PAGE_SIZE) {
- size = MAX_ARG_PAGES*TARGET_PAGE_SIZE;
+ if (size < STACK_LOWER_LIMIT) {
+ size = STACK_LOWER_LIMIT;
}
guard = TARGET_PAGE_SIZE;
if (guard < qemu_real_host_page_size) {
@@ -1450,19 +1453,8 @@ static abi_ulong setup_arg_pages(abi_ulong p, struct linux_binprm *bprm,
target_mprotect(error, guard, PROT_NONE);
info->stack_limit = error + guard;
- stack_base = info->stack_limit + size - MAX_ARG_PAGES*TARGET_PAGE_SIZE;
- p += stack_base;
-
- for (i = 0 ; i < MAX_ARG_PAGES ; i++) {
- if (bprm->page[i]) {
- info->rss++;
- /* FIXME - check return value of memcpy_to_target() for failure */
- memcpy_to_target(stack_base, bprm->page[i], TARGET_PAGE_SIZE);
- g_free(bprm->page[i]);
- }
- stack_base += TARGET_PAGE_SIZE;
- }
- return p;
+
+ return info->stack_limit + size - sizeof(void *);
}
/* Map and zero the bss. We need to explicitly zero any fractional pages
@@ -2204,10 +2196,9 @@ int load_elf_binary(struct linux_binprm *bprm, struct image_info *info)
struct image_info interp_info;
struct elfhdr elf_ex;
char *elf_interpreter = NULL;
+ char *scratch;
info->start_mmap = (abi_ulong)ELF_START_MMAP;
- info->mmap = 0;
- info->rss = 0;
load_elf_image(bprm->filename, bprm->fd, info,
&elf_interpreter, bprm->buf);
@@ -2217,18 +2208,24 @@ int load_elf_binary(struct linux_binprm *bprm, struct image_info *info)
when we load the interpreter. */
elf_ex = *(struct elfhdr *)bprm->buf;
- bprm->p = copy_elf_strings(1, &bprm->filename, bprm->page, bprm->p);
- bprm->p = copy_elf_strings(bprm->envc,bprm->envp,bprm->page,bprm->p);
- bprm->p = copy_elf_strings(bprm->argc,bprm->argv,bprm->page,bprm->p);
+ /* Do this so that we can load the interpreter, if need be. We will
+ change some of these later */
+ bprm->p = setup_arg_pages(bprm, info);
+
+ scratch = g_new0(char, TARGET_PAGE_SIZE);
+ bprm->p = copy_elf_strings(1, &bprm->filename, scratch,
+ bprm->p, info->stack_limit);
+ bprm->p = copy_elf_strings(bprm->envc, bprm->envp, scratch,
+ bprm->p, info->stack_limit);
+ bprm->p = copy_elf_strings(bprm->argc, bprm->argv, scratch,
+ bprm->p, info->stack_limit);
+ g_free(scratch);
+
if (!bprm->p) {
fprintf(stderr, "%s: %s\n", bprm->filename, strerror(E2BIG));
exit(-1);
}
- /* Do this so that we can load the interpreter, if need be. We will
- change some of these later */
- bprm->p = setup_arg_pages(bprm->p, bprm, info);
-
if (elf_interpreter) {
load_elf_interp(elf_interpreter, &interp_info, bprm->buf);
diff --git a/linux-user/flatload.c b/linux-user/flatload.c
index 566a7a8..ceacb98 100644
--- a/linux-user/flatload.c
+++ b/linux-user/flatload.c
@@ -707,7 +707,7 @@ static int load_flat_shared_library(int id, struct lib_info *libs)
int load_flt_binary(struct linux_binprm *bprm, struct image_info *info)
{
struct lib_info libinfo[MAX_SHARED_LIBS];
- abi_ulong p = bprm->p;
+ abi_ulong p;
abi_ulong stack_len;
abi_ulong start_addr;
abi_ulong sp;
diff --git a/linux-user/linuxload.c b/linux-user/linuxload.c
index 506e837..dbaf0ec 100644
--- a/linux-user/linuxload.c
+++ b/linux-user/linuxload.c
@@ -135,10 +135,7 @@ int loader_exec(int fdexec, const char *filename, char **argv, char **envp,
struct linux_binprm *bprm)
{
int retval;
- int i;
- bprm->p = TARGET_PAGE_SIZE*MAX_ARG_PAGES-sizeof(unsigned int);
- memset(bprm->page, 0, sizeof(bprm->page));
bprm->fd = fdexec;
bprm->filename = (char *)filename;
bprm->argc = count(argv);
@@ -172,9 +169,5 @@ int loader_exec(int fdexec, const char *filename, char **argv, char **envp,
return retval;
}
- /* Something went wrong, return the inode and free the argument pages*/
- for (i=0 ; i<MAX_ARG_PAGES ; i++) {
- g_free(bprm->page[i]);
- }
return(retval);
}
diff --git a/linux-user/main.c b/linux-user/main.c
index 25cf875..6599a41 100644
--- a/linux-user/main.c
+++ b/linux-user/main.c
@@ -63,7 +63,7 @@ unsigned long reserved_va = 0xf7000000;
unsigned long reserved_va;
#endif
-static void usage(void);
+static void usage(int exitcode);
static const char *interp_prefix = CONFIG_QEMU_INTERP_PREFIX;
const char *qemu_uname_release;
@@ -1414,7 +1414,7 @@ void cpu_loop (CPUSPARCState *env)
default:
printf ("Unhandled trap: 0x%x\n", trapnr);
cpu_dump_state(cs, stderr, fprintf, 0);
- exit (1);
+ exit(EXIT_FAILURE);
}
process_pending_signals (env);
}
@@ -2662,7 +2662,7 @@ void cpu_loop(CPUOpenRISCState *env)
switch (trapnr) {
case EXCP_RESET:
qemu_log("\nReset request, exit, pc is %#x\n", env->pc);
- exit(1);
+ exit(EXIT_FAILURE);
break;
case EXCP_BUSERR:
qemu_log("\nBus error, exit, pc is %#x\n", env->pc);
@@ -2726,7 +2726,7 @@ void cpu_loop(CPUOpenRISCState *env)
if (gdbsig) {
gdb_handlesig(cs, gdbsig);
if (gdbsig != TARGET_SIGTRAP) {
- exit(1);
+ exit(EXIT_FAILURE);
}
}
@@ -2791,7 +2791,7 @@ void cpu_loop(CPUSH4State *env)
default:
printf ("Unhandled trap: 0x%x\n", trapnr);
cpu_dump_state(cs, stderr, fprintf, 0);
- exit (1);
+ exit(EXIT_FAILURE);
}
process_pending_signals (env);
}
@@ -2852,7 +2852,7 @@ void cpu_loop(CPUCRISState *env)
default:
printf ("Unhandled trap: 0x%x\n", trapnr);
cpu_dump_state(cs, stderr, fprintf, 0);
- exit (1);
+ exit(EXIT_FAILURE);
}
process_pending_signals (env);
}
@@ -2933,7 +2933,7 @@ void cpu_loop(CPUMBState *env)
printf ("Unhandled hw-exception: 0x%x\n",
env->sregs[SR_ESR] & ESR_EC_MASK);
cpu_dump_state(cs, stderr, fprintf, 0);
- exit (1);
+ exit(EXIT_FAILURE);
break;
}
break;
@@ -2954,7 +2954,7 @@ void cpu_loop(CPUMBState *env)
default:
printf ("Unhandled trap: 0x%x\n", trapnr);
cpu_dump_state(cs, stderr, fprintf, 0);
- exit (1);
+ exit(EXIT_FAILURE);
}
process_pending_signals (env);
}
@@ -3123,17 +3123,17 @@ void cpu_loop(CPUAlphaState *env)
switch (trapnr) {
case EXCP_RESET:
fprintf(stderr, "Reset requested. Exit\n");
- exit(1);
+ exit(EXIT_FAILURE);
break;
case EXCP_MCHK:
fprintf(stderr, "Machine check exception. Exit\n");
- exit(1);
+ exit(EXIT_FAILURE);
break;
case EXCP_SMP_INTERRUPT:
case EXCP_CLK_INTERRUPT:
case EXCP_DEV_INTERRUPT:
fprintf(stderr, "External interrupt. Exit\n");
- exit(1);
+ exit(EXIT_FAILURE);
break;
case EXCP_MMFAULT:
env->lock_addr = -1;
@@ -3283,7 +3283,7 @@ void cpu_loop(CPUAlphaState *env)
default:
printf ("Unhandled trap: 0x%x\n", trapnr);
cpu_dump_state(cs, stderr, fprintf, 0);
- exit (1);
+ exit(EXIT_FAILURE);
}
process_pending_signals (env);
}
@@ -3387,7 +3387,7 @@ void cpu_loop(CPUS390XState *env)
default:
fprintf(stderr, "Unhandled program exception: %#x\n", n);
cpu_dump_state(cs, stderr, fprintf, 0);
- exit(1);
+ exit(EXIT_FAILURE);
}
break;
@@ -3404,7 +3404,7 @@ void cpu_loop(CPUS390XState *env)
default:
fprintf(stderr, "Unhandled trap: 0x%x\n", trapnr);
cpu_dump_state(cs, stderr, fprintf, 0);
- exit(1);
+ exit(EXIT_FAILURE);
}
process_pending_signals (env);
}
@@ -3700,7 +3700,7 @@ CPUArchState *cpu_copy(CPUArchState *env)
static void handle_arg_help(const char *arg)
{
- usage();
+ usage(EXIT_SUCCESS);
}
static void handle_arg_log(const char *arg)
@@ -3710,7 +3710,7 @@ static void handle_arg_log(const char *arg)
mask = qemu_str_to_log_mask(arg);
if (!mask) {
qemu_print_log_usage(stdout);
- exit(1);
+ exit(EXIT_FAILURE);
}
qemu_set_log(mask);
}
@@ -3726,7 +3726,7 @@ static void handle_arg_set_env(const char *arg)
r = p = strdup(arg);
while ((token = strsep(&p, ",")) != NULL) {
if (envlist_setenv(envlist, token) != 0) {
- usage();
+ usage(EXIT_FAILURE);
}
}
free(r);
@@ -3738,7 +3738,7 @@ static void handle_arg_unset_env(const char *arg)
r = p = strdup(arg);
while ((token = strsep(&p, ",")) != NULL) {
if (envlist_unsetenv(envlist, token) != 0) {
- usage();
+ usage(EXIT_FAILURE);
}
}
free(r);
@@ -3754,7 +3754,7 @@ static void handle_arg_stack_size(const char *arg)
char *p;
guest_stack_size = strtoul(arg, &p, 0);
if (guest_stack_size == 0) {
- usage();
+ usage(EXIT_FAILURE);
}
if (*p == 'M') {
@@ -3775,7 +3775,7 @@ static void handle_arg_pagesize(const char *arg)
if (qemu_host_page_size == 0 ||
(qemu_host_page_size & (qemu_host_page_size - 1)) != 0) {
fprintf(stderr, "page size must be a power of two\n");
- exit(1);
+ exit(EXIT_FAILURE);
}
}
@@ -3785,7 +3785,7 @@ static void handle_arg_randseed(const char *arg)
if (parse_uint_full(arg, &seed, 0) != 0 || seed > UINT_MAX) {
fprintf(stderr, "Invalid seed number: %s\n", arg);
- exit(1);
+ exit(EXIT_FAILURE);
}
srand(seed);
}
@@ -3808,7 +3808,7 @@ static void handle_arg_cpu(const char *arg)
#if defined(cpu_list)
cpu_list(stdout, &fprintf);
#endif
- exit(1);
+ exit(EXIT_FAILURE);
}
}
@@ -3845,12 +3845,12 @@ static void handle_arg_reserved_va(const char *arg)
#endif
) {
fprintf(stderr, "Reserved virtual address too big\n");
- exit(1);
+ exit(EXIT_FAILURE);
}
}
if (*p) {
fprintf(stderr, "Unrecognised -R size suffix '%s'\n", p);
- exit(1);
+ exit(EXIT_FAILURE);
}
}
@@ -3868,7 +3868,7 @@ static void handle_arg_version(const char *arg)
{
printf("qemu-" TARGET_NAME " version " QEMU_VERSION QEMU_PKGVERSION
", Copyright (c) 2003-2008 Fabrice Bellard\n");
- exit(0);
+ exit(EXIT_SUCCESS);
}
struct qemu_argument {
@@ -3883,6 +3883,8 @@ struct qemu_argument {
static const struct qemu_argument arg_table[] = {
{"h", "", false, handle_arg_help,
"", "print this help"},
+ {"help", "", false, handle_arg_help,
+ "", ""},
{"g", "QEMU_GDB", true, handle_arg_gdb,
"port", "wait gdb connection to 'port'"},
{"L", "QEMU_LD_PREFIX", true, handle_arg_ld_prefix,
@@ -3921,7 +3923,7 @@ static const struct qemu_argument arg_table[] = {
{NULL, NULL, false, NULL, NULL, NULL}
};
-static void usage(void)
+static void usage(int exitcode)
{
const struct qemu_argument *arginfo;
int maxarglen;
@@ -3988,7 +3990,7 @@ static void usage(void)
"Note that if you provide several changes to a single variable\n"
"the last change will stay in effect.\n");
- exit(1);
+ exit(exitcode);
}
static int parse_args(int argc, char **argv)
@@ -4022,12 +4024,18 @@ static int parse_args(int argc, char **argv)
if (!strcmp(r, "-")) {
break;
}
+ /* Treat --foo the same as -foo. */
+ if (r[0] == '-') {
+ r++;
+ }
for (arginfo = arg_table; arginfo->handle_opt != NULL; arginfo++) {
if (!strcmp(r, arginfo->argv)) {
if (arginfo->has_arg) {
if (optind >= argc) {
- usage();
+ (void) fprintf(stderr,
+ "qemu: missing argument for option '%s'\n", r);
+ exit(EXIT_FAILURE);
}
arginfo->handle_opt(argv[optind]);
optind++;
@@ -4040,12 +4048,14 @@ static int parse_args(int argc, char **argv)
/* no option matched the current argv */
if (arginfo->handle_opt == NULL) {
- usage();
+ (void) fprintf(stderr, "qemu: unknown option '%s'\n", r);
+ exit(EXIT_FAILURE);
}
}
if (optind >= argc) {
- usage();
+ (void) fprintf(stderr, "qemu: no user program specified\n");
+ exit(EXIT_FAILURE);
}
filename = argv[optind];
@@ -4074,7 +4084,7 @@ int main(int argc, char **argv, char **envp)
if ((envlist = envlist_create()) == NULL) {
(void) fprintf(stderr, "Unable to allocate envlist\n");
- exit(1);
+ exit(EXIT_FAILURE);
}
/* add current environment into the list */
@@ -4160,7 +4170,7 @@ int main(int argc, char **argv, char **envp)
cpu = cpu_init(cpu_model);
if (!cpu) {
fprintf(stderr, "Unable to find CPU definition\n");
- exit(1);
+ exit(EXIT_FAILURE);
}
env = cpu->env_ptr;
cpu_reset(cpu);
@@ -4192,7 +4202,7 @@ int main(int argc, char **argv, char **envp)
"space for use as guest address space (check your virtual "
"memory ulimit setting or reserve less using -R option)\n",
reserved_va);
- exit(1);
+ exit(EXIT_FAILURE);
}
if (reserved_va) {
@@ -4225,7 +4235,7 @@ int main(int argc, char **argv, char **envp)
target_argv = calloc(target_argc + 1, sizeof (char *));
if (target_argv == NULL) {
(void) fprintf(stderr, "Unable to allocate memory for target_argv\n");
- exit(1);
+ exit(EXIT_FAILURE);
}
/*
@@ -4254,7 +4264,7 @@ int main(int argc, char **argv, char **envp)
execfd = open(filename, O_RDONLY);
if (execfd < 0) {
printf("Error while loading %s: %s\n", filename, strerror(errno));
- _exit(1);
+ _exit(EXIT_FAILURE);
}
}
@@ -4262,7 +4272,7 @@ int main(int argc, char **argv, char **envp)
info, &bprm);
if (ret != 0) {
printf("Error while loading %s: %s\n", filename, strerror(-ret));
- _exit(1);
+ _exit(EXIT_FAILURE);
}
for (wrk = target_environ; *wrk; wrk++) {
@@ -4308,7 +4318,7 @@ int main(int argc, char **argv, char **envp)
/* enable 64 bit mode if possible */
if (!(env->features[FEAT_8000_0001_EDX] & CPUID_EXT2_LM)) {
fprintf(stderr, "The selected x86 CPU does not support 64 bit mode\n");
- exit(1);
+ exit(EXIT_FAILURE);
}
env->cr[4] |= CR4_PAE_MASK;
env->efer |= MSR_EFER_LMA | MSR_EFER_LME;
@@ -4418,7 +4428,7 @@ int main(int argc, char **argv, char **envp)
if (!(arm_feature(env, ARM_FEATURE_AARCH64))) {
fprintf(stderr,
"The selected ARM CPU does not support 64 bit mode\n");
- exit(1);
+ exit(EXIT_FAILURE);
}
for (i = 0; i < 31; i++) {
@@ -4630,7 +4640,7 @@ int main(int argc, char **argv, char **envp)
if (gdbserver_start(gdbstub_port) < 0) {
fprintf(stderr, "qemu: could not open gdbserver on port %d\n",
gdbstub_port);
- exit(1);
+ exit(EXIT_FAILURE);
}
gdb_handlesig(cpu, 0);
}
diff --git a/linux-user/mmap.c b/linux-user/mmap.c
index b2126c7..5606bcd 100644
--- a/linux-user/mmap.c
+++ b/linux-user/mmap.c
@@ -514,10 +514,7 @@ abi_long target_mmap(abi_ulong start, abi_ulong len, int prot,
goto fail;
if (!(prot & PROT_WRITE)) {
ret = target_mprotect(start, len, prot);
- if (ret != 0) {
- start = ret;
- goto the_end;
- }
+ assert(ret == 0);
}
goto the_end;
}
diff --git a/linux-user/qemu.h b/linux-user/qemu.h
index e8606b2..bd90cc3 100644
--- a/linux-user/qemu.h
+++ b/linux-user/qemu.h
@@ -36,8 +36,6 @@ struct image_info {
abi_ulong start_brk;
abi_ulong brk;
abi_ulong start_mmap;
- abi_ulong mmap;
- abi_ulong rss;
abi_ulong start_stack;
abi_ulong stack_limit;
abi_ulong entry;
@@ -145,12 +143,6 @@ extern const char *qemu_uname_release;
extern unsigned long mmap_min_addr;
/* ??? See if we can avoid exposing so much of the loader internals. */
-/*
- * MAX_ARG_PAGES defines the number of pages allocated for arguments
- * and envelope for the new program. 32 should suffice, this gives
- * a maximum env+arg of 128kB w/4KB pages!
- */
-#define MAX_ARG_PAGES 33
/* Read a good amount of data initially, to hopefully get all the
program headers loaded. */
@@ -162,7 +154,6 @@ extern unsigned long mmap_min_addr;
*/
struct linux_binprm {
char buf[BPRM_BUF_SIZE] __attribute__((aligned));
- void *page[MAX_ARG_PAGES];
abi_ulong p;
int fd;
int e_uid, e_gid;
diff --git a/linux-user/signal.c b/linux-user/signal.c
index 502efd9..ac82baa 100644
--- a/linux-user/signal.c
+++ b/linux-user/signal.c
@@ -3900,12 +3900,6 @@ static inline abi_ulong get_sigframe(struct target_sigaction *ka,
return sp;
}
-static void setup_frame(int sig, struct target_sigaction *ka,
- target_sigset_t *set, CPUOpenRISCState *env)
-{
- qemu_log("Not implement.\n");
-}
-
static void setup_rt_frame(int sig, struct target_sigaction *ka,
target_siginfo_t *info,
target_sigset_t *set, CPUOpenRISCState *env)
@@ -5662,7 +5656,8 @@ void process_pending_signals(CPUArchState *cpu_env)
}
#endif
/* prepare the stack frame of the virtual CPU */
-#if defined(TARGET_ABI_MIPSN32) || defined(TARGET_ABI_MIPSN64)
+#if defined(TARGET_ABI_MIPSN32) || defined(TARGET_ABI_MIPSN64) \
+ || defined(TARGET_OPENRISC)
/* These targets do not have traditional signals. */
setup_rt_frame(sig, sa, &q->info, &target_old_set, cpu_env);
#else
diff --git a/linux-user/syscall.c b/linux-user/syscall.c
index d1d3eb2..98b5766 100644
--- a/linux-user/syscall.c
+++ b/linux-user/syscall.c
@@ -457,6 +457,7 @@ static uint16_t target_to_host_errno_table[ERRNO_TABLE_SIZE] = {
* minus the errnos that are not actually generic to all archs.
*/
static uint16_t host_to_target_errno_table[ERRNO_TABLE_SIZE] = {
+ [EAGAIN] = TARGET_EAGAIN,
[EIDRM] = TARGET_EIDRM,
[ECHRNG] = TARGET_ECHRNG,
[EL2NSYNC] = TARGET_EL2NSYNC,
@@ -1181,7 +1182,7 @@ static inline abi_long target_to_host_cmsg(struct msghdr *msgh,
struct cmsghdr *cmsg = CMSG_FIRSTHDR(msgh);
abi_long msg_controllen;
abi_ulong target_cmsg_addr;
- struct target_cmsghdr *target_cmsg;
+ struct target_cmsghdr *target_cmsg, *target_cmsg_start;
socklen_t space = 0;
msg_controllen = tswapal(target_msgh->msg_controllen);
@@ -1189,6 +1190,7 @@ static inline abi_long target_to_host_cmsg(struct msghdr *msgh,
goto the_end;
target_cmsg_addr = tswapal(target_msgh->msg_control);
target_cmsg = lock_user(VERIFY_READ, target_cmsg_addr, msg_controllen, 1);
+ target_cmsg_start = target_cmsg;
if (!target_cmsg)
return -TARGET_EFAULT;
@@ -1247,7 +1249,8 @@ static inline abi_long target_to_host_cmsg(struct msghdr *msgh,
}
cmsg = CMSG_NXTHDR(msgh, cmsg);
- target_cmsg = TARGET_CMSG_NXTHDR(target_msgh, target_cmsg);
+ target_cmsg = TARGET_CMSG_NXTHDR(target_msgh, target_cmsg,
+ target_cmsg_start);
}
unlock_user(target_cmsg, target_cmsg_addr, 0);
the_end:
@@ -1261,7 +1264,7 @@ static inline abi_long host_to_target_cmsg(struct target_msghdr *target_msgh,
struct cmsghdr *cmsg = CMSG_FIRSTHDR(msgh);
abi_long msg_controllen;
abi_ulong target_cmsg_addr;
- struct target_cmsghdr *target_cmsg;
+ struct target_cmsghdr *target_cmsg, *target_cmsg_start;
socklen_t space = 0;
msg_controllen = tswapal(target_msgh->msg_controllen);
@@ -1269,6 +1272,7 @@ static inline abi_long host_to_target_cmsg(struct target_msghdr *target_msgh,
goto the_end;
target_cmsg_addr = tswapal(target_msgh->msg_control);
target_cmsg = lock_user(VERIFY_WRITE, target_cmsg_addr, msg_controllen, 0);
+ target_cmsg_start = target_cmsg;
if (!target_cmsg)
return -TARGET_EFAULT;
@@ -1382,14 +1386,15 @@ static inline abi_long host_to_target_cmsg(struct target_msghdr *target_msgh,
}
target_cmsg->cmsg_len = tswapal(tgt_len);
- tgt_space = TARGET_CMSG_SPACE(tgt_len);
+ tgt_space = TARGET_CMSG_SPACE(len);
if (msg_controllen < tgt_space) {
tgt_space = msg_controllen;
}
msg_controllen -= tgt_space;
space += tgt_space;
cmsg = CMSG_NXTHDR(msgh, cmsg);
- target_cmsg = TARGET_CMSG_NXTHDR(target_msgh, target_cmsg);
+ target_cmsg = TARGET_CMSG_NXTHDR(target_msgh, target_cmsg,
+ target_cmsg_start);
}
unlock_user(target_cmsg, target_cmsg_addr, space);
the_end:
@@ -4622,8 +4627,9 @@ static int do_fork(CPUArchState *env, unsigned int flags, abi_ulong newsp,
pthread_mutex_unlock(&clone_lock);
} else {
/* if no CLONE_VM, we consider it is a fork */
- if ((flags & ~(CSIGNAL | CLONE_NPTL_FLAGS2)) != 0)
- return -EINVAL;
+ if ((flags & ~(CSIGNAL | CLONE_NPTL_FLAGS2)) != 0) {
+ return -TARGET_EINVAL;
+ }
fork_start();
ret = fork();
if (ret == 0) {
@@ -5246,6 +5252,94 @@ static int do_futex(target_ulong uaddr, int op, int val, target_ulong timeout,
return -TARGET_ENOSYS;
}
}
+#if defined(TARGET_NR_name_to_handle_at) && defined(CONFIG_OPEN_BY_HANDLE)
+static abi_long do_name_to_handle_at(abi_long dirfd, abi_long pathname,
+ abi_long handle, abi_long mount_id,
+ abi_long flags)
+{
+ struct file_handle *target_fh;
+ struct file_handle *fh;
+ int mid = 0;
+ abi_long ret;
+ char *name;
+ unsigned int size, total_size;
+
+ if (get_user_s32(size, handle)) {
+ return -TARGET_EFAULT;
+ }
+
+ name = lock_user_string(pathname);
+ if (!name) {
+ return -TARGET_EFAULT;
+ }
+
+ total_size = sizeof(struct file_handle) + size;
+ target_fh = lock_user(VERIFY_WRITE, handle, total_size, 0);
+ if (!target_fh) {
+ unlock_user(name, pathname, 0);
+ return -TARGET_EFAULT;
+ }
+
+ fh = g_malloc0(total_size);
+ fh->handle_bytes = size;
+
+ ret = get_errno(name_to_handle_at(dirfd, path(name), fh, &mid, flags));
+ unlock_user(name, pathname, 0);
+
+ /* man name_to_handle_at(2):
+ * Other than the use of the handle_bytes field, the caller should treat
+ * the file_handle structure as an opaque data type
+ */
+
+ memcpy(target_fh, fh, total_size);
+ target_fh->handle_bytes = tswap32(fh->handle_bytes);
+ target_fh->handle_type = tswap32(fh->handle_type);
+ g_free(fh);
+ unlock_user(target_fh, handle, total_size);
+
+ if (put_user_s32(mid, mount_id)) {
+ return -TARGET_EFAULT;
+ }
+
+ return ret;
+
+}
+#endif
+
+#if defined(TARGET_NR_open_by_handle_at) && defined(CONFIG_OPEN_BY_HANDLE)
+static abi_long do_open_by_handle_at(abi_long mount_fd, abi_long handle,
+ abi_long flags)
+{
+ struct file_handle *target_fh;
+ struct file_handle *fh;
+ unsigned int size, total_size;
+ abi_long ret;
+
+ if (get_user_s32(size, handle)) {
+ return -TARGET_EFAULT;
+ }
+
+ total_size = sizeof(struct file_handle) + size;
+ target_fh = lock_user(VERIFY_READ, handle, total_size, 1);
+ if (!target_fh) {
+ return -TARGET_EFAULT;
+ }
+
+ fh = g_malloc0(total_size);
+ memcpy(fh, target_fh, total_size);
+ fh->handle_bytes = size;
+ fh->handle_type = tswap32(target_fh->handle_type);
+
+ ret = get_errno(open_by_handle_at(mount_fd, fh,
+ target_to_host_bitmask(flags, fcntl_flags_tbl)));
+
+ g_free(fh);
+
+ unlock_user(target_fh, handle, total_size);
+
+ return ret;
+}
+#endif
/* Map host to target signal numbers for the wait family of syscalls.
Assume all other status bits are the same. */
@@ -5658,6 +5752,16 @@ abi_long do_syscall(void *cpu_env, int num, abi_long arg1,
arg4));
unlock_user(p, arg2, 0);
break;
+#if defined(TARGET_NR_name_to_handle_at) && defined(CONFIG_OPEN_BY_HANDLE)
+ case TARGET_NR_name_to_handle_at:
+ ret = do_name_to_handle_at(arg1, arg2, arg3, arg4, arg5);
+ break;
+#endif
+#if defined(TARGET_NR_open_by_handle_at) && defined(CONFIG_OPEN_BY_HANDLE)
+ case TARGET_NR_open_by_handle_at:
+ ret = do_open_by_handle_at(arg1, arg2, arg3);
+ break;
+#endif
case TARGET_NR_close:
ret = get_errno(close(arg1));
break;
@@ -5808,12 +5912,6 @@ abi_long do_syscall(void *cpu_env, int num, abi_long arg1,
}
*q = NULL;
- /* This case will not be caught by the host's execve() if its
- page size is bigger than the target's. */
- if (total_size > MAX_ARG_PAGES * TARGET_PAGE_SIZE) {
- ret = -TARGET_E2BIG;
- goto execve_end;
- }
if (!(p = lock_user_string(arg1)))
goto execve_efault;
ret = get_errno(execve(p, argp, envp));
diff --git a/linux-user/syscall_defs.h b/linux-user/syscall_defs.h
index cdc8db4..7ca33a6 100644
--- a/linux-user/syscall_defs.h
+++ b/linux-user/syscall_defs.h
@@ -235,7 +235,8 @@ struct target_cmsghdr {
};
#define TARGET_CMSG_DATA(cmsg) ((unsigned char *) ((struct target_cmsghdr *) (cmsg) + 1))
-#define TARGET_CMSG_NXTHDR(mhdr, cmsg) __target_cmsg_nxthdr (mhdr, cmsg)
+#define TARGET_CMSG_NXTHDR(mhdr, cmsg, cmsg_start) \
+ __target_cmsg_nxthdr(mhdr, cmsg, cmsg_start)
#define TARGET_CMSG_ALIGN(len) (((len) + sizeof (abi_long) - 1) \
& (size_t) ~(sizeof (abi_long) - 1))
#define TARGET_CMSG_SPACE(len) (TARGET_CMSG_ALIGN (len) \
@@ -243,17 +244,20 @@ struct target_cmsghdr {
#define TARGET_CMSG_LEN(len) (TARGET_CMSG_ALIGN (sizeof (struct target_cmsghdr)) + (len))
static __inline__ struct target_cmsghdr *
-__target_cmsg_nxthdr (struct target_msghdr *__mhdr, struct target_cmsghdr *__cmsg)
+__target_cmsg_nxthdr(struct target_msghdr *__mhdr,
+ struct target_cmsghdr *__cmsg,
+ struct target_cmsghdr *__cmsg_start)
{
struct target_cmsghdr *__ptr;
__ptr = (struct target_cmsghdr *)((unsigned char *) __cmsg
+ TARGET_CMSG_ALIGN (tswapal(__cmsg->cmsg_len)));
- if ((unsigned long)((char *)(__ptr+1) - (char *)(size_t)tswapal(__mhdr->msg_control))
- > tswapal(__mhdr->msg_controllen))
+ if ((unsigned long)((char *)(__ptr+1) - (char *)__cmsg_start)
+ > tswapal(__mhdr->msg_controllen)) {
/* No more entries. */
return (struct target_cmsghdr *)0;
- return __cmsg;
+ }
+ return __ptr;
}
struct target_mmsghdr {