Merge remote-tracking branch 'riku/linux-user-for-upstream' into staging
This commit is contained in:
commit
cd59dd8734
@ -440,15 +440,16 @@ uint32_t do_arm_semihosting(CPUState *env)
|
||||
/* 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;
|
||||
|
@ -927,7 +927,7 @@ struct exec
|
||||
#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 @@ static abi_ulong create_elf_tables(abi_ulong p, int argc, int envc,
|
||||
{
|
||||
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 @@ static abi_ulong create_elf_tables(abi_ulong p, int argc, int envc,
|
||||
/* 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 @@ static abi_ulong create_elf_tables(abi_ulong p, int argc, int envc,
|
||||
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 @@ static abi_ulong create_elf_tables(abi_ulong p, int argc, int envc,
|
||||
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 @@ static void load_elf_image(const char *image_name, int image_fd,
|
||||
/* 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 @@ static void load_symbols(struct elfhdr *hdr, int fd, abi_ulong load_bias)
|
||||
{
|
||||
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 @@ static void load_symbols(struct elfhdr *hdr, int fd, abi_ulong load_bias)
|
||||
/* 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 @@ static void load_symbols(struct elfhdr *hdr, int fd, abi_ulong load_bias)
|
||||
}
|
||||
}
|
||||
|
||||
/* 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 @@ static void load_symbols(struct elfhdr *hdr, int fd, abi_ulong load_bias)
|
||||
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,
|
||||
|
@ -379,12 +379,11 @@ static int load_flat_file(struct linux_binprm * bprm,
|
||||
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 @@ static int load_flat_file(struct linux_binprm * bprm,
|
||||
}
|
||||
|
||||
reloc = datapos + (ntohl(hdr->reloc_start) - text_len);
|
||||
memp = realdatastart;
|
||||
|
||||
} else {
|
||||
|
||||
@ -506,7 +504,6 @@ static int load_flat_file(struct linux_binprm * bprm,
|
||||
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 @@ static int load_flat_file(struct linux_binprm * bprm,
|
||||
|
||||
/* 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),
|
||||
|
@ -26,22 +26,6 @@ abi_long memcpy_to_target(abi_ulong dest, const void *src,
|
||||
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 @@ static int prepare_binprm(struct linux_binprm *bprm)
|
||||
{
|
||||
struct stat st;
|
||||
int mode;
|
||||
int retval, id_change;
|
||||
int retval;
|
||||
|
||||
if(fstat(bprm->fd, &st) < 0) {
|
||||
return(-errno);
|
||||
@ -73,14 +57,10 @@ static int prepare_binprm(struct linux_binprm *bprm)
|
||||
|
||||
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 @@ static int prepare_binprm(struct linux_binprm *bprm)
|
||||
*/
|
||||
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);
|
||||
|
@ -318,7 +318,8 @@ void cpu_loop(CPUX86State *env)
|
||||
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 @@ void cpu_loop(CPUX86State *env)
|
||||
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 @@ void cpu_loop(CPUARMState *env)
|
||||
env->regs[2],
|
||||
env->regs[3],
|
||||
env->regs[4],
|
||||
env->regs[5]);
|
||||
env->regs[5],
|
||||
0, 0);
|
||||
}
|
||||
} else {
|
||||
goto error;
|
||||
@ -830,7 +833,8 @@ void cpu_loop(CPUState *env)
|
||||
env->regs[2],
|
||||
env->regs[3],
|
||||
env->regs[4],
|
||||
env->regs[5]);
|
||||
env->regs[5],
|
||||
0, 0);
|
||||
}
|
||||
} else {
|
||||
goto error;
|
||||
@ -1017,7 +1021,8 @@ void cpu_loop (CPUSPARCState *env)
|
||||
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 @@ void cpu_loop(CPUPPCState *env)
|
||||
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 @@ void cpu_loop(CPUMIPSState *env)
|
||||
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 @@ void cpu_loop (CPUState *env)
|
||||
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 @@ void cpu_loop (CPUState *env)
|
||||
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 @@ void cpu_loop (CPUState *env)
|
||||
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 @@ void cpu_loop(CPUM68KState *env)
|
||||
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 @@ void cpu_loop (CPUState *env)
|
||||
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 @@ void cpu_loop(CPUS390XState *env)
|
||||
env->regs[4],
|
||||
env->regs[5],
|
||||
env->regs[6],
|
||||
env->regs[7]);
|
||||
env->regs[7],
|
||||
0, 0);
|
||||
}
|
||||
break;
|
||||
case EXCP_ADDR:
|
||||
|
@ -192,7 +192,8 @@ abi_long do_brk(abi_ulong new_brk);
|
||||
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);
|
||||
|
@ -981,8 +981,8 @@ restore_sigcontext(CPUX86State *env, struct target_sigcontext *sc, int *peax)
|
||||
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 @@ long do_sigreturn(CPUState *env)
|
||||
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 @@ long do_sigreturn(CPUState *env)
|
||||
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 @@ void sparc64_set_context(CPUSPARCState *env)
|
||||
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 @@ void sparc64_set_context(CPUSPARCState *env)
|
||||
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;
|
||||
|
@ -550,6 +550,15 @@ _syscall5(int, sys_ppoll, struct pollfd *, fds, nfds_t, nfds,
|
||||
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 @@ char *target_strerror(int err)
|
||||
|
||||
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 @@ static inline abi_long copy_from_user_fdset(fd_set *fds,
|
||||
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 @@ static inline abi_long copy_to_user_mq_attr(abi_ulong target_mq_attr_addr,
|
||||
}
|
||||
#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 @@ static abi_long do_select(int n,
|
||||
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 @@ static abi_long do_select(int n,
|
||||
|
||||
return ret;
|
||||
}
|
||||
#endif
|
||||
|
||||
static abi_long do_pipe2(int host_pipe[], int flags)
|
||||
{
|
||||
@ -3751,10 +3799,10 @@ static abi_long do_get_thread_area(CPUX86State *env, abi_ulong ptr)
|
||||
#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 @@ static abi_long do_arch_prctl(CPUX86State *env, int code, abi_ulong addr)
|
||||
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 @@ int get_osversion(void)
|
||||
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 @@ abi_long do_syscall(void *cpu_env, int num, abi_long arg1,
|
||||
#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 @@ abi_long do_syscall(void *cpu_env, int num, abi_long arg1,
|
||||
#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 @@ abi_long do_syscall(void *cpu_env, int num, abi_long arg1,
|
||||
case TARGET_NR_osf_sigprocmask:
|
||||
{
|
||||
abi_ulong mask;
|
||||
int how = arg1;
|
||||
int how;
|
||||
sigset_t set, oldset;
|
||||
|
||||
switch(arg1) {
|
||||
@ -7077,7 +7222,7 @@ abi_long do_syscall(void *cpu_env, int num, abi_long arg1,
|
||||
}
|
||||
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 @@ abi_long do_syscall(void *cpu_env, int num, abi_long arg1,
|
||||
#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
|
||||
|
@ -370,7 +370,7 @@ void do_m68k_semihosting(CPUM68KState *env, int nr)
|
||||
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 @@ void do_m68k_semihosting(CPUM68KState *env, int nr)
|
||||
/* 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;
|
||||
|
Loading…
Reference in New Issue
Block a user