提交 945507d6 编写于 作者: P Peter Maydell

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: NPeter Maydell <peter.maydell@linaro.org>
......@@ -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);
......
......@@ -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;
......
......@@ -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);
}
......@@ -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);
}
......
......@@ -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;
}
......
......@@ -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;
......
......@@ -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
......
......@@ -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));
......
......@@ -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 {
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册