Merge remote-tracking branch 'riku/linux-user-for-upstream' into staging
diff --git a/arm-semi.c b/arm-semi.c
index e9e6f89..5a62d03 100644
--- a/arm-semi.c
+++ b/arm-semi.c
@@ -440,15 +440,16 @@
/* Some C libraries assume the heap immediately follows .bss, so
allocate it using sbrk. */
if (!ts->heap_limit) {
- long ret;
+ abi_ulong ret;
ts->heap_base = do_brk(0);
limit = ts->heap_base + ARM_ANGEL_HEAP_SIZE;
/* Try a big heap, and reduce the size if that fails. */
for (;;) {
ret = do_brk(limit);
- if (ret != -1)
+ if (ret >= limit) {
break;
+ }
limit = (ts->heap_base >> 1) + (limit >> 1);
}
ts->heap_limit = limit;
diff --git a/linux-user/elfload.c b/linux-user/elfload.c
index dcfeb7a..b2746f2 100644
--- a/linux-user/elfload.c
+++ b/linux-user/elfload.c
@@ -927,7 +927,7 @@
#define TARGET_ELF_PAGESTART(_v) ((_v) & ~(unsigned long)(TARGET_ELF_EXEC_PAGESIZE-1))
#define TARGET_ELF_PAGEOFFSET(_v) ((_v) & (TARGET_ELF_EXEC_PAGESIZE-1))
-#define DLINFO_ITEMS 12
+#define DLINFO_ITEMS 13
static inline void memcpy_fromfs(void * to, const void * from, unsigned long n)
{
@@ -1202,6 +1202,9 @@
{
abi_ulong sp;
int size;
+ int i;
+ abi_ulong u_rand_bytes;
+ uint8_t k_rand_bytes[16];
abi_ulong u_platform;
const char *k_platform;
const int n = sizeof(elf_addr_t);
@@ -1231,6 +1234,20 @@
/* FIXME - check return value of memcpy_to_target() for failure */
memcpy_to_target(sp, k_platform, len);
}
+
+ /*
+ * Generate 16 random bytes for userspace PRNG seeding (not
+ * cryptically secure but it's not the aim of QEMU).
+ */
+ srand((unsigned int) time(NULL));
+ for (i = 0; i < 16; i++) {
+ k_rand_bytes[i] = rand();
+ }
+ sp -= 16;
+ u_rand_bytes = sp;
+ /* FIXME - check return value of memcpy_to_target() for failure */
+ memcpy_to_target(sp, k_rand_bytes, 16);
+
/*
* Force 16 byte _final_ alignment here for generality.
*/
@@ -1271,6 +1288,8 @@
NEW_AUX_ENT(AT_EGID, (abi_ulong) getegid());
NEW_AUX_ENT(AT_HWCAP, (abi_ulong) ELF_HWCAP);
NEW_AUX_ENT(AT_CLKTCK, (abi_ulong) sysconf(_SC_CLK_TCK));
+ NEW_AUX_ENT(AT_RANDOM, (abi_ulong) u_rand_bytes);
+
if (k_platform)
NEW_AUX_ENT(AT_PLATFORM, u_platform);
#ifdef ARCH_DLINFO
@@ -1288,6 +1307,78 @@
return sp;
}
+static void probe_guest_base(const char *image_name,
+ abi_ulong loaddr, abi_ulong hiaddr)
+{
+ /* Probe for a suitable guest base address, if the user has not set
+ * it explicitly, and set guest_base appropriately.
+ * In case of error we will print a suitable message and exit.
+ */
+#if defined(CONFIG_USE_GUEST_BASE)
+ const char *errmsg;
+ if (!have_guest_base && !reserved_va) {
+ unsigned long host_start, real_start, host_size;
+
+ /* Round addresses to page boundaries. */
+ loaddr &= qemu_host_page_mask;
+ hiaddr = HOST_PAGE_ALIGN(hiaddr);
+
+ if (loaddr < mmap_min_addr) {
+ host_start = HOST_PAGE_ALIGN(mmap_min_addr);
+ } else {
+ host_start = loaddr;
+ if (host_start != loaddr) {
+ errmsg = "Address overflow loading ELF binary";
+ goto exit_errmsg;
+ }
+ }
+ host_size = hiaddr - loaddr;
+ while (1) {
+ /* Do not use mmap_find_vma here because that is limited to the
+ guest address space. We are going to make the
+ guest address space fit whatever we're given. */
+ real_start = (unsigned long)
+ mmap((void *)host_start, host_size, PROT_NONE,
+ MAP_ANONYMOUS | MAP_PRIVATE | MAP_NORESERVE, -1, 0);
+ if (real_start == (unsigned long)-1) {
+ goto exit_perror;
+ }
+ if (real_start == host_start) {
+ break;
+ }
+ /* That address didn't work. Unmap and try a different one.
+ The address the host picked because is typically right at
+ the top of the host address space and leaves the guest with
+ no usable address space. Resort to a linear search. We
+ already compensated for mmap_min_addr, so this should not
+ happen often. Probably means we got unlucky and host
+ address space randomization put a shared library somewhere
+ inconvenient. */
+ munmap((void *)real_start, host_size);
+ host_start += qemu_host_page_size;
+ if (host_start == loaddr) {
+ /* Theoretically possible if host doesn't have any suitably
+ aligned areas. Normally the first mmap will fail. */
+ errmsg = "Unable to find space for application";
+ goto exit_errmsg;
+ }
+ }
+ qemu_log("Relocating guest address space from 0x"
+ TARGET_ABI_FMT_lx " to 0x%lx\n",
+ loaddr, real_start);
+ guest_base = real_start - loaddr;
+ }
+ return;
+
+exit_perror:
+ errmsg = strerror(errno);
+exit_errmsg:
+ fprintf(stderr, "%s: %s\n", image_name, errmsg);
+ exit(-1);
+#endif
+}
+
+
/* Load an ELF image into the address space.
IMAGE_NAME is the filename of the image, to use in error messages.
@@ -1373,63 +1464,7 @@
/* This is the main executable. Make sure that the low
address does not conflict with MMAP_MIN_ADDR or the
QEMU application itself. */
-#if defined(CONFIG_USE_GUEST_BASE)
- /*
- * In case where user has not explicitly set the guest_base, we
- * probe here that should we set it automatically.
- */
- if (!have_guest_base && !reserved_va) {
- unsigned long host_start, real_start, host_size;
-
- /* Round addresses to page boundaries. */
- loaddr &= qemu_host_page_mask;
- hiaddr = HOST_PAGE_ALIGN(hiaddr);
-
- if (loaddr < mmap_min_addr) {
- host_start = HOST_PAGE_ALIGN(mmap_min_addr);
- } else {
- host_start = loaddr;
- if (host_start != loaddr) {
- errmsg = "Address overflow loading ELF binary";
- goto exit_errmsg;
- }
- }
- host_size = hiaddr - loaddr;
- while (1) {
- /* Do not use mmap_find_vma here because that is limited to the
- guest address space. We are going to make the
- guest address space fit whatever we're given. */
- real_start = (unsigned long)
- mmap((void *)host_start, host_size, PROT_NONE,
- MAP_ANONYMOUS | MAP_PRIVATE | MAP_NORESERVE, -1, 0);
- if (real_start == (unsigned long)-1) {
- goto exit_perror;
- }
- if (real_start == host_start) {
- break;
- }
- /* That address didn't work. Unmap and try a different one.
- The address the host picked because is typically right at
- the top of the host address space and leaves the guest with
- no usable address space. Resort to a linear search. We
- already compensated for mmap_min_addr, so this should not
- happen often. Probably means we got unlucky and host
- address space randomization put a shared library somewhere
- inconvenient. */
- munmap((void *)real_start, host_size);
- host_start += qemu_host_page_size;
- if (host_start == loaddr) {
- /* Theoretically possible if host doesn't have any suitably
- aligned areas. Normally the first mmap will fail. */
- errmsg = "Unable to find space for application";
- goto exit_errmsg;
- }
- }
- qemu_log("Relocating guest address space from 0x"
- TARGET_ABI_FMT_lx " to 0x%lx\n", loaddr, real_start);
- guest_base = real_start - loaddr;
- }
-#endif
+ probe_guest_base(image_name, loaddr, hiaddr);
}
load_bias = load_addr - loaddr;
@@ -1643,9 +1678,9 @@
{
int i, shnum, nsyms, sym_idx = 0, str_idx = 0;
struct elf_shdr *shdr;
- char *strings;
- struct syminfo *s;
- struct elf_sym *syms, *new_syms;
+ char *strings = NULL;
+ struct syminfo *s = NULL;
+ struct elf_sym *new_syms, *syms = NULL;
shnum = hdr->e_shnum;
i = shnum * sizeof(struct elf_shdr);
@@ -1670,24 +1705,19 @@
/* Now know where the strtab and symtab are. Snarf them. */
s = malloc(sizeof(*s));
if (!s) {
- return;
+ goto give_up;
}
i = shdr[str_idx].sh_size;
s->disas_strtab = strings = malloc(i);
if (!strings || pread(fd, strings, i, shdr[str_idx].sh_offset) != i) {
- free(s);
- free(strings);
- return;
+ goto give_up;
}
i = shdr[sym_idx].sh_size;
syms = malloc(i);
if (!syms || pread(fd, syms, i, shdr[sym_idx].sh_offset) != i) {
- free(s);
- free(strings);
- free(syms);
- return;
+ goto give_up;
}
nsyms = i / sizeof(struct elf_sym);
@@ -1710,16 +1740,18 @@
}
}
+ /* No "useful" symbol. */
+ if (nsyms == 0) {
+ goto give_up;
+ }
+
/* Attempt to free the storage associated with the local symbols
that we threw away. Whether or not this has any effect on the
memory allocation depends on the malloc implementation and how
many symbols we managed to discard. */
new_syms = realloc(syms, nsyms * sizeof(*syms));
if (new_syms == NULL) {
- free(s);
- free(syms);
- free(strings);
- return;
+ goto give_up;
}
syms = new_syms;
@@ -1734,6 +1766,13 @@
s->lookup_symbol = lookup_symbolxx;
s->next = syminfos;
syminfos = s;
+
+ return;
+
+give_up:
+ free(s);
+ free(strings);
+ free(syms);
}
int load_elf_binary(struct linux_binprm * bprm, struct target_pt_regs * regs,
diff --git a/linux-user/flatload.c b/linux-user/flatload.c
index cd7af7c..1062da3 100644
--- a/linux-user/flatload.c
+++ b/linux-user/flatload.c
@@ -379,12 +379,11 @@
abi_long result;
abi_ulong realdatastart = 0;
abi_ulong text_len, data_len, bss_len, stack_len, flags;
- abi_ulong memp = 0; /* for finding the brk area */
abi_ulong extra;
abi_ulong reloc = 0, rp;
int i, rev, relocs = 0;
abi_ulong fpos;
- abi_ulong start_code, end_code;
+ abi_ulong start_code;
abi_ulong indx_len;
hdr = ((struct flat_hdr *) bprm->buf); /* exec-header */
@@ -491,7 +490,6 @@
}
reloc = datapos + (ntohl(hdr->reloc_start) - text_len);
- memp = realdatastart;
} else {
@@ -506,7 +504,6 @@
realdatastart = textpos + ntohl(hdr->data_start);
datapos = realdatastart + indx_len;
reloc = (textpos + ntohl(hdr->reloc_start) + indx_len);
- memp = textpos;
#ifdef CONFIG_BINFMT_ZFLAT
#error code needs checking
@@ -552,11 +549,10 @@
/* The main program needs a little extra setup in the task structure */
start_code = textpos + sizeof (struct flat_hdr);
- end_code = textpos + text_len;
DBG_FLT("%s %s: TEXT=%x-%x DATA=%x-%x BSS=%x-%x\n",
id ? "Lib" : "Load", bprm->filename,
- (int) start_code, (int) end_code,
+ (int) start_code, (int) (textpos + text_len),
(int) datapos,
(int) (datapos + data_len),
(int) (datapos + data_len),
diff --git a/linux-user/linuxload.c b/linux-user/linuxload.c
index ac8c486..62ebc7e 100644
--- a/linux-user/linuxload.c
+++ b/linux-user/linuxload.c
@@ -26,22 +26,6 @@
return 0;
}
-static int in_group_p(gid_t g)
-{
- /* return TRUE if we're in the specified group, FALSE otherwise */
- int ngroup;
- int i;
- gid_t grouplist[NGROUPS];
-
- ngroup = getgroups(NGROUPS, grouplist);
- for(i = 0; i < ngroup; i++) {
- if(grouplist[i] == g) {
- return 1;
- }
- }
- return 0;
-}
-
static int count(char ** vec)
{
int i;
@@ -57,7 +41,7 @@
{
struct stat st;
int mode;
- int retval, id_change;
+ int retval;
if(fstat(bprm->fd, &st) < 0) {
return(-errno);
@@ -73,14 +57,10 @@
bprm->e_uid = geteuid();
bprm->e_gid = getegid();
- id_change = 0;
/* Set-uid? */
if(mode & S_ISUID) {
bprm->e_uid = st.st_uid;
- if(bprm->e_uid != geteuid()) {
- id_change = 1;
- }
}
/* Set-gid? */
@@ -91,9 +71,6 @@
*/
if ((mode & (S_ISGID | S_IXGRP)) == (S_ISGID | S_IXGRP)) {
bprm->e_gid = st.st_gid;
- if (!in_group_p(bprm->e_gid)) {
- id_change = 1;
- }
}
retval = read(bprm->fd, bprm->buf, BPRM_BUF_SIZE);
diff --git a/linux-user/main.c b/linux-user/main.c
index 1c91c30..db5577b 100644
--- a/linux-user/main.c
+++ b/linux-user/main.c
@@ -318,7 +318,8 @@
env->regs[R_EDX],
env->regs[R_ESI],
env->regs[R_EDI],
- env->regs[R_EBP]);
+ env->regs[R_EBP],
+ 0, 0);
break;
#ifndef TARGET_ABI32
case EXCP_SYSCALL:
@@ -330,7 +331,8 @@
env->regs[R_EDX],
env->regs[10],
env->regs[8],
- env->regs[9]);
+ env->regs[9],
+ 0, 0);
env->eip = env->exception_next_eip;
break;
#endif
@@ -734,7 +736,8 @@
env->regs[2],
env->regs[3],
env->regs[4],
- env->regs[5]);
+ env->regs[5],
+ 0, 0);
}
} else {
goto error;
@@ -830,7 +833,8 @@
env->regs[2],
env->regs[3],
env->regs[4],
- env->regs[5]);
+ env->regs[5],
+ 0, 0);
}
} else {
goto error;
@@ -1017,7 +1021,8 @@
ret = do_syscall (env, env->gregs[1],
env->regwptr[0], env->regwptr[1],
env->regwptr[2], env->regwptr[3],
- env->regwptr[4], env->regwptr[5]);
+ env->regwptr[4], env->regwptr[5],
+ 0, 0);
if ((abi_ulong)ret >= (abi_ulong)(-515)) {
#if defined(TARGET_SPARC64) && !defined(TARGET_ABI32)
env->xcc |= PSR_CARRY;
@@ -1610,7 +1615,7 @@
env->crf[0] &= ~0x1;
ret = do_syscall(env, env->gpr[0], env->gpr[3], env->gpr[4],
env->gpr[5], env->gpr[6], env->gpr[7],
- env->gpr[8]);
+ env->gpr[8], 0, 0);
if (ret == (uint32_t)(-TARGET_QEMU_ESIGRETURN)) {
/* Returning from a successful sigreturn syscall.
Avoid corrupting register state. */
@@ -2071,7 +2076,7 @@
env->active_tc.gpr[5],
env->active_tc.gpr[6],
env->active_tc.gpr[7],
- arg5, arg6/*, arg7, arg8*/);
+ arg5, arg6, arg7, arg8);
}
if (ret == -TARGET_QEMU_ESIGRETURN) {
/* Returning from a successful sigreturn syscall.
@@ -2159,7 +2164,8 @@
env->gregs[6],
env->gregs[7],
env->gregs[0],
- env->gregs[1]);
+ env->gregs[1],
+ 0, 0);
env->gregs[0] = ret;
break;
case EXCP_INTERRUPT:
@@ -2228,7 +2234,8 @@
env->regs[12],
env->regs[13],
env->pregs[7],
- env->pregs[11]);
+ env->pregs[11],
+ 0, 0);
env->regs[10] = ret;
break;
case EXCP_DEBUG:
@@ -2287,7 +2294,8 @@
env->regs[7],
env->regs[8],
env->regs[9],
- env->regs[10]);
+ env->regs[10],
+ 0, 0);
env->regs[3] = ret;
env->sregs[SR_PC] = env->regs[14];
break;
@@ -2397,7 +2405,8 @@
env->dregs[3],
env->dregs[4],
env->dregs[5],
- env->aregs[0]);
+ env->aregs[0],
+ 0, 0);
}
break;
case EXCP_INTERRUPT:
@@ -2575,7 +2584,8 @@
sysret = do_syscall(env, trapnr,
env->ir[IR_A0], env->ir[IR_A1],
env->ir[IR_A2], env->ir[IR_A3],
- env->ir[IR_A4], env->ir[IR_A5]);
+ env->ir[IR_A4], env->ir[IR_A5],
+ 0, 0);
if (trapnr == TARGET_NR_sigreturn
|| trapnr == TARGET_NR_rt_sigreturn) {
break;
@@ -2706,7 +2716,8 @@
env->regs[4],
env->regs[5],
env->regs[6],
- env->regs[7]);
+ env->regs[7],
+ 0, 0);
}
break;
case EXCP_ADDR:
diff --git a/linux-user/qemu.h b/linux-user/qemu.h
index 237386c..627c8b3 100644
--- a/linux-user/qemu.h
+++ b/linux-user/qemu.h
@@ -192,7 +192,8 @@
void syscall_init(void);
abi_long do_syscall(void *cpu_env, int num, abi_long arg1,
abi_long arg2, abi_long arg3, abi_long arg4,
- abi_long arg5, abi_long arg6);
+ abi_long arg5, abi_long arg6, abi_long arg7,
+ abi_long arg8);
void gemu_log(const char *fmt, ...) GCC_FMT_ATTR(1, 2);
extern THREAD CPUState *thread_env;
void cpu_loop(CPUState *env);
diff --git a/linux-user/signal.c b/linux-user/signal.c
index 11b25be..7d168e1 100644
--- a/linux-user/signal.c
+++ b/linux-user/signal.c
@@ -981,8 +981,8 @@
env->regs[R_ECX] = tswapl(sc->ecx);
env->eip = tswapl(sc->eip);
- cpu_x86_load_seg(env, R_CS, lduw(&sc->cs) | 3);
- cpu_x86_load_seg(env, R_SS, lduw(&sc->ss) | 3);
+ cpu_x86_load_seg(env, R_CS, lduw_p(&sc->cs) | 3);
+ cpu_x86_load_seg(env, R_SS, lduw_p(&sc->ss) | 3);
tmpflags = tswapl(sc->eflags);
env->eflags = (env->eflags & ~0x40DD5) | (tmpflags & 0x40DD5);
@@ -2080,7 +2080,6 @@
uint32_t up_psr, pc, npc;
target_sigset_t set;
sigset_t host_set;
- abi_ulong fpu_save_addr;
int err, i;
sf_addr = env->regwptr[UREG_FP];
@@ -2120,10 +2119,11 @@
err |= __get_user(env->regwptr[i + UREG_I0], &sf->info.si_regs.u_regs[i+8]);
}
- err |= __get_user(fpu_save_addr, &sf->fpu_save);
-
- //if (fpu_save)
- // err |= restore_fpu_state(env, fpu_save);
+ /* FIXME: implement FPU save/restore:
+ * __get_user(fpu_save, &sf->fpu_save);
+ * if (fpu_save)
+ * err |= restore_fpu_state(env, fpu_save);
+ */
/* This is pretty much atomic, no amount locking would prevent
* the races which exist anyways.
@@ -2228,7 +2228,6 @@
target_mc_gregset_t *grp;
abi_ulong pc, npc, tstate;
abi_ulong fp, i7, w_addr;
- unsigned char fenab;
int err;
unsigned int i;
@@ -2293,7 +2292,11 @@
if (put_user(i7, w_addr + offsetof(struct target_reg_window, ins[7]),
abi_ulong) != 0)
goto do_sigsegv;
- err |= __get_user(fenab, &(ucp->tuc_mcontext.mc_fpregs.mcfpu_enab));
+ /* FIXME this does not match how the kernel handles the FPU in
+ * its sparc64_set_context implementation. In particular the FPU
+ * is only restored if fenab is non-zero in:
+ * __get_user(fenab, &(ucp->tuc_mcontext.mc_fpregs.mcfpu_enab));
+ */
err |= __get_user(env->fprs, &(ucp->tuc_mcontext.mc_fpregs.mcfpu_fprs));
{
uint32_t *src, *dst;
diff --git a/linux-user/syscall.c b/linux-user/syscall.c
index 5cb27c7..fed7a8f 100644
--- a/linux-user/syscall.c
+++ b/linux-user/syscall.c
@@ -550,6 +550,15 @@
size_t, sigsetsize)
#endif
+#if defined(TARGET_NR_pselect6)
+#ifndef __NR_pselect6
+# define __NR_pselect6 -1
+#endif
+#define __NR_sys_pselect6 __NR_pselect6
+_syscall6(int, sys_pselect6, int, nfds, fd_set *, readfds, fd_set *, writefds,
+ fd_set *, exceptfds, struct timespec *, timeout, void *, sig);
+#endif
+
extern int personality(int);
extern int flock(int, int);
extern int setfsuid(int);
@@ -709,49 +718,81 @@
static abi_ulong target_brk;
static abi_ulong target_original_brk;
+static abi_ulong brk_page;
void target_set_brk(abi_ulong new_brk)
{
target_original_brk = target_brk = HOST_PAGE_ALIGN(new_brk);
+ brk_page = HOST_PAGE_ALIGN(target_brk);
}
+//#define DEBUGF_BRK(message, args...) do { fprintf(stderr, (message), ## args); } while (0)
+#define DEBUGF_BRK(message, args...)
+
/* do_brk() must return target values and target errnos. */
abi_long do_brk(abi_ulong new_brk)
{
- abi_ulong brk_page;
abi_long mapped_addr;
int new_alloc_size;
- if (!new_brk)
- return target_brk;
- if (new_brk < target_original_brk)
- return target_brk;
+ DEBUGF_BRK("do_brk(%#010x) -> ", new_brk);
- brk_page = HOST_PAGE_ALIGN(target_brk);
+ if (!new_brk) {
+ DEBUGF_BRK("%#010x (!new_brk)\n", target_brk);
+ return target_brk;
+ }
+ if (new_brk < target_original_brk) {
+ DEBUGF_BRK("%#010x (new_brk < target_original_brk)\n", target_brk);
+ return target_brk;
+ }
- /* If the new brk is less than this, set it and we're done... */
- if (new_brk < brk_page) {
+ /* If the new brk is less than the highest page reserved to the
+ * target heap allocation, set it and we're almost done... */
+ if (new_brk <= brk_page) {
+ /* Heap contents are initialized to zero, as for anonymous
+ * mapped pages. */
+ if (new_brk > target_brk) {
+ memset(g2h(target_brk), 0, new_brk - target_brk);
+ }
target_brk = new_brk;
+ DEBUGF_BRK("%#010x (new_brk <= brk_page)\n", target_brk);
return target_brk;
}
- /* We need to allocate more memory after the brk... */
- new_alloc_size = HOST_PAGE_ALIGN(new_brk - brk_page + 1);
+ /* We need to allocate more memory after the brk... Note that
+ * we don't use MAP_FIXED because that will map over the top of
+ * any existing mapping (like the one with the host libc or qemu
+ * itself); instead we treat "mapped but at wrong address" as
+ * a failure and unmap again.
+ */
+ new_alloc_size = HOST_PAGE_ALIGN(new_brk - brk_page);
mapped_addr = get_errno(target_mmap(brk_page, new_alloc_size,
PROT_READ|PROT_WRITE,
- MAP_ANON|MAP_FIXED|MAP_PRIVATE, 0, 0));
+ MAP_ANON|MAP_PRIVATE, 0, 0));
+
+ if (mapped_addr == brk_page) {
+ target_brk = new_brk;
+ brk_page = HOST_PAGE_ALIGN(target_brk);
+ DEBUGF_BRK("%#010x (mapped_addr == brk_page)\n", target_brk);
+ return target_brk;
+ } else if (mapped_addr != -1) {
+ /* Mapped but at wrong address, meaning there wasn't actually
+ * enough space for this brk.
+ */
+ target_munmap(mapped_addr, new_alloc_size);
+ mapped_addr = -1;
+ DEBUGF_BRK("%#010x (mapped_addr != -1)\n", target_brk);
+ }
+ else {
+ DEBUGF_BRK("%#010x (otherwise)\n", target_brk);
+ }
#if defined(TARGET_ALPHA)
/* We (partially) emulate OSF/1 on Alpha, which requires we
return a proper errno, not an unchanged brk value. */
- if (is_error(mapped_addr)) {
- return -TARGET_ENOMEM;
- }
+ return -TARGET_ENOMEM;
#endif
-
- if (!is_error(mapped_addr)) {
- target_brk = new_brk;
- }
+ /* For everything else, return the previous break. */
return target_brk;
}
@@ -787,6 +828,20 @@
return 0;
}
+static inline abi_ulong copy_from_user_fdset_ptr(fd_set *fds, fd_set **fds_ptr,
+ abi_ulong target_fds_addr,
+ int n)
+{
+ if (target_fds_addr) {
+ if (copy_from_user_fdset(fds, target_fds_addr, n))
+ return -TARGET_EFAULT;
+ *fds_ptr = fds;
+ } else {
+ *fds_ptr = NULL;
+ }
+ return 0;
+}
+
static inline abi_long copy_to_user_fdset(abi_ulong target_fds_addr,
const fd_set *fds,
int n)
@@ -952,6 +1007,7 @@
}
#endif
+#if defined(TARGET_NR_select) || defined(TARGET_NR__newselect)
/* do_select() must return target values and target errnos. */
static abi_long do_select(int n,
abi_ulong rfd_addr, abi_ulong wfd_addr,
@@ -962,26 +1018,17 @@
struct timeval tv, *tv_ptr;
abi_long ret;
- if (rfd_addr) {
- if (copy_from_user_fdset(&rfds, rfd_addr, n))
- return -TARGET_EFAULT;
- rfds_ptr = &rfds;
- } else {
- rfds_ptr = NULL;
+ ret = copy_from_user_fdset_ptr(&rfds, &rfds_ptr, rfd_addr, n);
+ if (ret) {
+ return ret;
}
- if (wfd_addr) {
- if (copy_from_user_fdset(&wfds, wfd_addr, n))
- return -TARGET_EFAULT;
- wfds_ptr = &wfds;
- } else {
- wfds_ptr = NULL;
+ ret = copy_from_user_fdset_ptr(&wfds, &wfds_ptr, wfd_addr, n);
+ if (ret) {
+ return ret;
}
- if (efd_addr) {
- if (copy_from_user_fdset(&efds, efd_addr, n))
- return -TARGET_EFAULT;
- efds_ptr = &efds;
- } else {
- efds_ptr = NULL;
+ ret = copy_from_user_fdset_ptr(&efds, &efds_ptr, efd_addr, n);
+ if (ret) {
+ return ret;
}
if (target_tv_addr) {
@@ -1008,6 +1055,7 @@
return ret;
}
+#endif
static abi_long do_pipe2(int host_pipe[], int flags)
{
@@ -3751,10 +3799,10 @@
#ifndef TARGET_ABI32
static abi_long do_arch_prctl(CPUX86State *env, int code, abi_ulong addr)
{
- abi_long ret;
+ abi_long ret = 0;
abi_ulong val;
int idx;
-
+
switch(code) {
case TARGET_ARCH_SET_GS:
case TARGET_ARCH_SET_FS:
@@ -3773,13 +3821,13 @@
idx = R_FS;
val = env->segs[idx].base;
if (put_user(val, addr, abi_ulong))
- return -TARGET_EFAULT;
+ ret = -TARGET_EFAULT;
break;
default:
ret = -TARGET_EINVAL;
break;
}
- return 0;
+ return ret;
}
#endif
@@ -4484,7 +4532,8 @@
All errnos that do_syscall() returns must be -TARGET_<errcode>. */
abi_long do_syscall(void *cpu_env, int num, abi_long arg1,
abi_long arg2, abi_long arg3, abi_long arg4,
- abi_long arg5, abi_long arg6)
+ abi_long arg5, abi_long arg6, abi_long arg7,
+ abi_long arg8)
{
abi_long ret;
struct stat st;
@@ -5569,7 +5618,102 @@
#endif
#ifdef TARGET_NR_pselect6
case TARGET_NR_pselect6:
- goto unimplemented_nowarn;
+ {
+ abi_long rfd_addr, wfd_addr, efd_addr, n, ts_addr;
+ fd_set rfds, wfds, efds;
+ fd_set *rfds_ptr, *wfds_ptr, *efds_ptr;
+ struct timespec ts, *ts_ptr;
+
+ /*
+ * The 6th arg is actually two args smashed together,
+ * so we cannot use the C library.
+ */
+ sigset_t set;
+ struct {
+ sigset_t *set;
+ size_t size;
+ } sig, *sig_ptr;
+
+ abi_ulong arg_sigset, arg_sigsize, *arg7;
+ target_sigset_t *target_sigset;
+
+ n = arg1;
+ rfd_addr = arg2;
+ wfd_addr = arg3;
+ efd_addr = arg4;
+ ts_addr = arg5;
+
+ ret = copy_from_user_fdset_ptr(&rfds, &rfds_ptr, rfd_addr, n);
+ if (ret) {
+ goto fail;
+ }
+ ret = copy_from_user_fdset_ptr(&wfds, &wfds_ptr, wfd_addr, n);
+ if (ret) {
+ goto fail;
+ }
+ ret = copy_from_user_fdset_ptr(&efds, &efds_ptr, efd_addr, n);
+ if (ret) {
+ goto fail;
+ }
+
+ /*
+ * This takes a timespec, and not a timeval, so we cannot
+ * use the do_select() helper ...
+ */
+ if (ts_addr) {
+ if (target_to_host_timespec(&ts, ts_addr)) {
+ goto efault;
+ }
+ ts_ptr = &ts;
+ } else {
+ ts_ptr = NULL;
+ }
+
+ /* Extract the two packed args for the sigset */
+ if (arg6) {
+ sig_ptr = &sig;
+ sig.size = _NSIG / 8;
+
+ arg7 = lock_user(VERIFY_READ, arg6, sizeof(*arg7) * 2, 1);
+ if (!arg7) {
+ goto efault;
+ }
+ arg_sigset = tswapl(arg7[0]);
+ arg_sigsize = tswapl(arg7[1]);
+ unlock_user(arg7, arg6, 0);
+
+ if (arg_sigset) {
+ sig.set = &set;
+ target_sigset = lock_user(VERIFY_READ, arg_sigset,
+ sizeof(*target_sigset), 1);
+ if (!target_sigset) {
+ goto efault;
+ }
+ target_to_host_sigset(&set, target_sigset);
+ unlock_user(target_sigset, arg_sigset, 0);
+ } else {
+ sig.set = NULL;
+ }
+ } else {
+ sig_ptr = NULL;
+ }
+
+ ret = get_errno(sys_pselect6(n, rfds_ptr, wfds_ptr, efds_ptr,
+ ts_ptr, sig_ptr));
+
+ if (!is_error(ret)) {
+ if (rfd_addr && copy_to_user_fdset(rfd_addr, &rfds, n))
+ goto efault;
+ if (wfd_addr && copy_to_user_fdset(wfd_addr, &wfds, n))
+ goto efault;
+ if (efd_addr && copy_to_user_fdset(efd_addr, &efds, n))
+ goto efault;
+
+ if (ts_addr && host_to_target_timespec(ts_addr, &ts))
+ goto efault;
+ }
+ }
+ break;
#endif
case TARGET_NR_symlink:
{
@@ -6029,8 +6173,9 @@
#endif
#ifdef TARGET_NR_syscall
case TARGET_NR_syscall:
- ret = do_syscall(cpu_env,arg1 & 0xffff,arg2,arg3,arg4,arg5,arg6,0);
- break;
+ ret = do_syscall(cpu_env, arg1 & 0xffff, arg2, arg3, arg4, arg5,
+ arg6, arg7, arg8, 0);
+ break;
#endif
case TARGET_NR_wait4:
{
@@ -7058,7 +7203,7 @@
case TARGET_NR_osf_sigprocmask:
{
abi_ulong mask;
- int how = arg1;
+ int how;
sigset_t set, oldset;
switch(arg1) {
@@ -7077,7 +7222,7 @@
}
mask = arg2;
target_to_host_old_sigset(&set, &mask);
- sigprocmask(arg1, &set, &oldset);
+ sigprocmask(how, &set, &oldset);
host_to_target_old_sigset(&mask, &oldset);
ret = mask;
}
@@ -7717,8 +7862,13 @@
#if defined(TARGET_NR_sync_file_range)
case TARGET_NR_sync_file_range:
#if TARGET_ABI_BITS == 32
+#if defined(TARGET_MIPS)
+ ret = get_errno(sync_file_range(arg1, target_offset64(arg3, arg4),
+ target_offset64(arg5, arg6), arg7));
+#else
ret = get_errno(sync_file_range(arg1, target_offset64(arg2, arg3),
target_offset64(arg4, arg5), arg6));
+#endif /* !TARGET_MIPS */
#else
ret = get_errno(sync_file_range(arg1, arg2, arg3, arg4));
#endif
diff --git a/m68k-semi.c b/m68k-semi.c
index 0371089..7fde10e 100644
--- a/m68k-semi.c
+++ b/m68k-semi.c
@@ -370,7 +370,7 @@
TaskState *ts = env->opaque;
/* Allocate the heap using sbrk. */
if (!ts->heap_limit) {
- long ret;
+ abi_ulong ret;
uint32_t size;
uint32_t base;
@@ -379,8 +379,9 @@
/* Try a big heap, and reduce the size if that fails. */
for (;;) {
ret = do_brk(base + size);
- if (ret != -1)
+ if (ret >= (base + size)) {
break;
+ }
size >>= 1;
}
ts->heap_limit = base + size;