mirror of https://github.com/proxmox/mirror_qemu
Merge remote-tracking branch 'riku/linux-user-for-upstream' into staging
commit
cd59dd8734
|
@ -440,15 +440,16 @@ uint32_t do_arm_semihosting(CPUState *env)
|
||||||
/* Some C libraries assume the heap immediately follows .bss, so
|
/* Some C libraries assume the heap immediately follows .bss, so
|
||||||
allocate it using sbrk. */
|
allocate it using sbrk. */
|
||||||
if (!ts->heap_limit) {
|
if (!ts->heap_limit) {
|
||||||
long ret;
|
abi_ulong ret;
|
||||||
|
|
||||||
ts->heap_base = do_brk(0);
|
ts->heap_base = do_brk(0);
|
||||||
limit = ts->heap_base + ARM_ANGEL_HEAP_SIZE;
|
limit = ts->heap_base + ARM_ANGEL_HEAP_SIZE;
|
||||||
/* Try a big heap, and reduce the size if that fails. */
|
/* Try a big heap, and reduce the size if that fails. */
|
||||||
for (;;) {
|
for (;;) {
|
||||||
ret = do_brk(limit);
|
ret = do_brk(limit);
|
||||||
if (ret != -1)
|
if (ret >= limit) {
|
||||||
break;
|
break;
|
||||||
|
}
|
||||||
limit = (ts->heap_base >> 1) + (limit >> 1);
|
limit = (ts->heap_base >> 1) + (limit >> 1);
|
||||||
}
|
}
|
||||||
ts->heap_limit = limit;
|
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_PAGESTART(_v) ((_v) & ~(unsigned long)(TARGET_ELF_EXEC_PAGESIZE-1))
|
||||||
#define TARGET_ELF_PAGEOFFSET(_v) ((_v) & (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)
|
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;
|
abi_ulong sp;
|
||||||
int size;
|
int size;
|
||||||
|
int i;
|
||||||
|
abi_ulong u_rand_bytes;
|
||||||
|
uint8_t k_rand_bytes[16];
|
||||||
abi_ulong u_platform;
|
abi_ulong u_platform;
|
||||||
const char *k_platform;
|
const char *k_platform;
|
||||||
const int n = sizeof(elf_addr_t);
|
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 */
|
/* FIXME - check return value of memcpy_to_target() for failure */
|
||||||
memcpy_to_target(sp, k_platform, len);
|
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.
|
* 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_EGID, (abi_ulong) getegid());
|
||||||
NEW_AUX_ENT(AT_HWCAP, (abi_ulong) ELF_HWCAP);
|
NEW_AUX_ENT(AT_HWCAP, (abi_ulong) ELF_HWCAP);
|
||||||
NEW_AUX_ENT(AT_CLKTCK, (abi_ulong) sysconf(_SC_CLK_TCK));
|
NEW_AUX_ENT(AT_CLKTCK, (abi_ulong) sysconf(_SC_CLK_TCK));
|
||||||
|
NEW_AUX_ENT(AT_RANDOM, (abi_ulong) u_rand_bytes);
|
||||||
|
|
||||||
if (k_platform)
|
if (k_platform)
|
||||||
NEW_AUX_ENT(AT_PLATFORM, u_platform);
|
NEW_AUX_ENT(AT_PLATFORM, u_platform);
|
||||||
#ifdef ARCH_DLINFO
|
#ifdef ARCH_DLINFO
|
||||||
|
@ -1288,6 +1307,78 @@ static abi_ulong create_elf_tables(abi_ulong p, int argc, int envc,
|
||||||
return sp;
|
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.
|
/* Load an ELF image into the address space.
|
||||||
|
|
||||||
IMAGE_NAME is the filename of the image, to use in error messages.
|
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
|
/* This is the main executable. Make sure that the low
|
||||||
address does not conflict with MMAP_MIN_ADDR or the
|
address does not conflict with MMAP_MIN_ADDR or the
|
||||||
QEMU application itself. */
|
QEMU application itself. */
|
||||||
#if defined(CONFIG_USE_GUEST_BASE)
|
probe_guest_base(image_name, loaddr, hiaddr);
|
||||||
/*
|
|
||||||
* 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
|
|
||||||
}
|
}
|
||||||
load_bias = load_addr - loaddr;
|
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;
|
int i, shnum, nsyms, sym_idx = 0, str_idx = 0;
|
||||||
struct elf_shdr *shdr;
|
struct elf_shdr *shdr;
|
||||||
char *strings;
|
char *strings = NULL;
|
||||||
struct syminfo *s;
|
struct syminfo *s = NULL;
|
||||||
struct elf_sym *syms, *new_syms;
|
struct elf_sym *new_syms, *syms = NULL;
|
||||||
|
|
||||||
shnum = hdr->e_shnum;
|
shnum = hdr->e_shnum;
|
||||||
i = shnum * sizeof(struct elf_shdr);
|
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. */
|
/* Now know where the strtab and symtab are. Snarf them. */
|
||||||
s = malloc(sizeof(*s));
|
s = malloc(sizeof(*s));
|
||||||
if (!s) {
|
if (!s) {
|
||||||
return;
|
goto give_up;
|
||||||
}
|
}
|
||||||
|
|
||||||
i = shdr[str_idx].sh_size;
|
i = shdr[str_idx].sh_size;
|
||||||
s->disas_strtab = strings = malloc(i);
|
s->disas_strtab = strings = malloc(i);
|
||||||
if (!strings || pread(fd, strings, i, shdr[str_idx].sh_offset) != i) {
|
if (!strings || pread(fd, strings, i, shdr[str_idx].sh_offset) != i) {
|
||||||
free(s);
|
goto give_up;
|
||||||
free(strings);
|
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
i = shdr[sym_idx].sh_size;
|
i = shdr[sym_idx].sh_size;
|
||||||
syms = malloc(i);
|
syms = malloc(i);
|
||||||
if (!syms || pread(fd, syms, i, shdr[sym_idx].sh_offset) != i) {
|
if (!syms || pread(fd, syms, i, shdr[sym_idx].sh_offset) != i) {
|
||||||
free(s);
|
goto give_up;
|
||||||
free(strings);
|
|
||||||
free(syms);
|
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
nsyms = i / sizeof(struct elf_sym);
|
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
|
/* Attempt to free the storage associated with the local symbols
|
||||||
that we threw away. Whether or not this has any effect on the
|
that we threw away. Whether or not this has any effect on the
|
||||||
memory allocation depends on the malloc implementation and how
|
memory allocation depends on the malloc implementation and how
|
||||||
many symbols we managed to discard. */
|
many symbols we managed to discard. */
|
||||||
new_syms = realloc(syms, nsyms * sizeof(*syms));
|
new_syms = realloc(syms, nsyms * sizeof(*syms));
|
||||||
if (new_syms == NULL) {
|
if (new_syms == NULL) {
|
||||||
free(s);
|
goto give_up;
|
||||||
free(syms);
|
|
||||||
free(strings);
|
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
syms = new_syms;
|
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->lookup_symbol = lookup_symbolxx;
|
||||||
s->next = syminfos;
|
s->next = syminfos;
|
||||||
syminfos = s;
|
syminfos = s;
|
||||||
|
|
||||||
|
return;
|
||||||
|
|
||||||
|
give_up:
|
||||||
|
free(s);
|
||||||
|
free(strings);
|
||||||
|
free(syms);
|
||||||
}
|
}
|
||||||
|
|
||||||
int load_elf_binary(struct linux_binprm * bprm, struct target_pt_regs * regs,
|
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_long result;
|
||||||
abi_ulong realdatastart = 0;
|
abi_ulong realdatastart = 0;
|
||||||
abi_ulong text_len, data_len, bss_len, stack_len, flags;
|
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 extra;
|
||||||
abi_ulong reloc = 0, rp;
|
abi_ulong reloc = 0, rp;
|
||||||
int i, rev, relocs = 0;
|
int i, rev, relocs = 0;
|
||||||
abi_ulong fpos;
|
abi_ulong fpos;
|
||||||
abi_ulong start_code, end_code;
|
abi_ulong start_code;
|
||||||
abi_ulong indx_len;
|
abi_ulong indx_len;
|
||||||
|
|
||||||
hdr = ((struct flat_hdr *) bprm->buf); /* exec-header */
|
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);
|
reloc = datapos + (ntohl(hdr->reloc_start) - text_len);
|
||||||
memp = realdatastart;
|
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
|
|
||||||
|
@ -506,7 +504,6 @@ static int load_flat_file(struct linux_binprm * bprm,
|
||||||
realdatastart = textpos + ntohl(hdr->data_start);
|
realdatastart = textpos + ntohl(hdr->data_start);
|
||||||
datapos = realdatastart + indx_len;
|
datapos = realdatastart + indx_len;
|
||||||
reloc = (textpos + ntohl(hdr->reloc_start) + indx_len);
|
reloc = (textpos + ntohl(hdr->reloc_start) + indx_len);
|
||||||
memp = textpos;
|
|
||||||
|
|
||||||
#ifdef CONFIG_BINFMT_ZFLAT
|
#ifdef CONFIG_BINFMT_ZFLAT
|
||||||
#error code needs checking
|
#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 */
|
/* The main program needs a little extra setup in the task structure */
|
||||||
start_code = textpos + sizeof (struct flat_hdr);
|
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",
|
DBG_FLT("%s %s: TEXT=%x-%x DATA=%x-%x BSS=%x-%x\n",
|
||||||
id ? "Lib" : "Load", bprm->filename,
|
id ? "Lib" : "Load", bprm->filename,
|
||||||
(int) start_code, (int) end_code,
|
(int) start_code, (int) (textpos + text_len),
|
||||||
(int) datapos,
|
(int) datapos,
|
||||||
(int) (datapos + data_len),
|
(int) (datapos + data_len),
|
||||||
(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;
|
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)
|
static int count(char ** vec)
|
||||||
{
|
{
|
||||||
int i;
|
int i;
|
||||||
|
@ -57,7 +41,7 @@ static int prepare_binprm(struct linux_binprm *bprm)
|
||||||
{
|
{
|
||||||
struct stat st;
|
struct stat st;
|
||||||
int mode;
|
int mode;
|
||||||
int retval, id_change;
|
int retval;
|
||||||
|
|
||||||
if(fstat(bprm->fd, &st) < 0) {
|
if(fstat(bprm->fd, &st) < 0) {
|
||||||
return(-errno);
|
return(-errno);
|
||||||
|
@ -73,14 +57,10 @@ static int prepare_binprm(struct linux_binprm *bprm)
|
||||||
|
|
||||||
bprm->e_uid = geteuid();
|
bprm->e_uid = geteuid();
|
||||||
bprm->e_gid = getegid();
|
bprm->e_gid = getegid();
|
||||||
id_change = 0;
|
|
||||||
|
|
||||||
/* Set-uid? */
|
/* Set-uid? */
|
||||||
if(mode & S_ISUID) {
|
if(mode & S_ISUID) {
|
||||||
bprm->e_uid = st.st_uid;
|
bprm->e_uid = st.st_uid;
|
||||||
if(bprm->e_uid != geteuid()) {
|
|
||||||
id_change = 1;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Set-gid? */
|
/* Set-gid? */
|
||||||
|
@ -91,9 +71,6 @@ static int prepare_binprm(struct linux_binprm *bprm)
|
||||||
*/
|
*/
|
||||||
if ((mode & (S_ISGID | S_IXGRP)) == (S_ISGID | S_IXGRP)) {
|
if ((mode & (S_ISGID | S_IXGRP)) == (S_ISGID | S_IXGRP)) {
|
||||||
bprm->e_gid = st.st_gid;
|
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);
|
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_EDX],
|
||||||
env->regs[R_ESI],
|
env->regs[R_ESI],
|
||||||
env->regs[R_EDI],
|
env->regs[R_EDI],
|
||||||
env->regs[R_EBP]);
|
env->regs[R_EBP],
|
||||||
|
0, 0);
|
||||||
break;
|
break;
|
||||||
#ifndef TARGET_ABI32
|
#ifndef TARGET_ABI32
|
||||||
case EXCP_SYSCALL:
|
case EXCP_SYSCALL:
|
||||||
|
@ -330,7 +331,8 @@ void cpu_loop(CPUX86State *env)
|
||||||
env->regs[R_EDX],
|
env->regs[R_EDX],
|
||||||
env->regs[10],
|
env->regs[10],
|
||||||
env->regs[8],
|
env->regs[8],
|
||||||
env->regs[9]);
|
env->regs[9],
|
||||||
|
0, 0);
|
||||||
env->eip = env->exception_next_eip;
|
env->eip = env->exception_next_eip;
|
||||||
break;
|
break;
|
||||||
#endif
|
#endif
|
||||||
|
@ -734,7 +736,8 @@ void cpu_loop(CPUARMState *env)
|
||||||
env->regs[2],
|
env->regs[2],
|
||||||
env->regs[3],
|
env->regs[3],
|
||||||
env->regs[4],
|
env->regs[4],
|
||||||
env->regs[5]);
|
env->regs[5],
|
||||||
|
0, 0);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
goto error;
|
goto error;
|
||||||
|
@ -830,7 +833,8 @@ void cpu_loop(CPUState *env)
|
||||||
env->regs[2],
|
env->regs[2],
|
||||||
env->regs[3],
|
env->regs[3],
|
||||||
env->regs[4],
|
env->regs[4],
|
||||||
env->regs[5]);
|
env->regs[5],
|
||||||
|
0, 0);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
goto error;
|
goto error;
|
||||||
|
@ -1017,7 +1021,8 @@ void cpu_loop (CPUSPARCState *env)
|
||||||
ret = do_syscall (env, env->gregs[1],
|
ret = do_syscall (env, env->gregs[1],
|
||||||
env->regwptr[0], env->regwptr[1],
|
env->regwptr[0], env->regwptr[1],
|
||||||
env->regwptr[2], env->regwptr[3],
|
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 ((abi_ulong)ret >= (abi_ulong)(-515)) {
|
||||||
#if defined(TARGET_SPARC64) && !defined(TARGET_ABI32)
|
#if defined(TARGET_SPARC64) && !defined(TARGET_ABI32)
|
||||||
env->xcc |= PSR_CARRY;
|
env->xcc |= PSR_CARRY;
|
||||||
|
@ -1610,7 +1615,7 @@ void cpu_loop(CPUPPCState *env)
|
||||||
env->crf[0] &= ~0x1;
|
env->crf[0] &= ~0x1;
|
||||||
ret = do_syscall(env, env->gpr[0], env->gpr[3], env->gpr[4],
|
ret = do_syscall(env, env->gpr[0], env->gpr[3], env->gpr[4],
|
||||||
env->gpr[5], env->gpr[6], env->gpr[7],
|
env->gpr[5], env->gpr[6], env->gpr[7],
|
||||||
env->gpr[8]);
|
env->gpr[8], 0, 0);
|
||||||
if (ret == (uint32_t)(-TARGET_QEMU_ESIGRETURN)) {
|
if (ret == (uint32_t)(-TARGET_QEMU_ESIGRETURN)) {
|
||||||
/* Returning from a successful sigreturn syscall.
|
/* Returning from a successful sigreturn syscall.
|
||||||
Avoid corrupting register state. */
|
Avoid corrupting register state. */
|
||||||
|
@ -2071,7 +2076,7 @@ void cpu_loop(CPUMIPSState *env)
|
||||||
env->active_tc.gpr[5],
|
env->active_tc.gpr[5],
|
||||||
env->active_tc.gpr[6],
|
env->active_tc.gpr[6],
|
||||||
env->active_tc.gpr[7],
|
env->active_tc.gpr[7],
|
||||||
arg5, arg6/*, arg7, arg8*/);
|
arg5, arg6, arg7, arg8);
|
||||||
}
|
}
|
||||||
if (ret == -TARGET_QEMU_ESIGRETURN) {
|
if (ret == -TARGET_QEMU_ESIGRETURN) {
|
||||||
/* Returning from a successful sigreturn syscall.
|
/* Returning from a successful sigreturn syscall.
|
||||||
|
@ -2159,7 +2164,8 @@ void cpu_loop (CPUState *env)
|
||||||
env->gregs[6],
|
env->gregs[6],
|
||||||
env->gregs[7],
|
env->gregs[7],
|
||||||
env->gregs[0],
|
env->gregs[0],
|
||||||
env->gregs[1]);
|
env->gregs[1],
|
||||||
|
0, 0);
|
||||||
env->gregs[0] = ret;
|
env->gregs[0] = ret;
|
||||||
break;
|
break;
|
||||||
case EXCP_INTERRUPT:
|
case EXCP_INTERRUPT:
|
||||||
|
@ -2228,7 +2234,8 @@ void cpu_loop (CPUState *env)
|
||||||
env->regs[12],
|
env->regs[12],
|
||||||
env->regs[13],
|
env->regs[13],
|
||||||
env->pregs[7],
|
env->pregs[7],
|
||||||
env->pregs[11]);
|
env->pregs[11],
|
||||||
|
0, 0);
|
||||||
env->regs[10] = ret;
|
env->regs[10] = ret;
|
||||||
break;
|
break;
|
||||||
case EXCP_DEBUG:
|
case EXCP_DEBUG:
|
||||||
|
@ -2287,7 +2294,8 @@ void cpu_loop (CPUState *env)
|
||||||
env->regs[7],
|
env->regs[7],
|
||||||
env->regs[8],
|
env->regs[8],
|
||||||
env->regs[9],
|
env->regs[9],
|
||||||
env->regs[10]);
|
env->regs[10],
|
||||||
|
0, 0);
|
||||||
env->regs[3] = ret;
|
env->regs[3] = ret;
|
||||||
env->sregs[SR_PC] = env->regs[14];
|
env->sregs[SR_PC] = env->regs[14];
|
||||||
break;
|
break;
|
||||||
|
@ -2397,7 +2405,8 @@ void cpu_loop(CPUM68KState *env)
|
||||||
env->dregs[3],
|
env->dregs[3],
|
||||||
env->dregs[4],
|
env->dregs[4],
|
||||||
env->dregs[5],
|
env->dregs[5],
|
||||||
env->aregs[0]);
|
env->aregs[0],
|
||||||
|
0, 0);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case EXCP_INTERRUPT:
|
case EXCP_INTERRUPT:
|
||||||
|
@ -2575,7 +2584,8 @@ void cpu_loop (CPUState *env)
|
||||||
sysret = do_syscall(env, trapnr,
|
sysret = do_syscall(env, trapnr,
|
||||||
env->ir[IR_A0], env->ir[IR_A1],
|
env->ir[IR_A0], env->ir[IR_A1],
|
||||||
env->ir[IR_A2], env->ir[IR_A3],
|
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
|
if (trapnr == TARGET_NR_sigreturn
|
||||||
|| trapnr == TARGET_NR_rt_sigreturn) {
|
|| trapnr == TARGET_NR_rt_sigreturn) {
|
||||||
break;
|
break;
|
||||||
|
@ -2706,7 +2716,8 @@ void cpu_loop(CPUS390XState *env)
|
||||||
env->regs[4],
|
env->regs[4],
|
||||||
env->regs[5],
|
env->regs[5],
|
||||||
env->regs[6],
|
env->regs[6],
|
||||||
env->regs[7]);
|
env->regs[7],
|
||||||
|
0, 0);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case EXCP_ADDR:
|
case EXCP_ADDR:
|
||||||
|
|
|
@ -192,7 +192,8 @@ abi_long do_brk(abi_ulong new_brk);
|
||||||
void syscall_init(void);
|
void syscall_init(void);
|
||||||
abi_long do_syscall(void *cpu_env, int num, abi_long arg1,
|
abi_long do_syscall(void *cpu_env, int num, abi_long arg1,
|
||||||
abi_long arg2, abi_long arg3, abi_long arg4,
|
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);
|
void gemu_log(const char *fmt, ...) GCC_FMT_ATTR(1, 2);
|
||||||
extern THREAD CPUState *thread_env;
|
extern THREAD CPUState *thread_env;
|
||||||
void cpu_loop(CPUState *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->regs[R_ECX] = tswapl(sc->ecx);
|
||||||
env->eip = tswapl(sc->eip);
|
env->eip = tswapl(sc->eip);
|
||||||
|
|
||||||
cpu_x86_load_seg(env, R_CS, lduw(&sc->cs) | 3);
|
cpu_x86_load_seg(env, R_CS, lduw_p(&sc->cs) | 3);
|
||||||
cpu_x86_load_seg(env, R_SS, lduw(&sc->ss) | 3);
|
cpu_x86_load_seg(env, R_SS, lduw_p(&sc->ss) | 3);
|
||||||
|
|
||||||
tmpflags = tswapl(sc->eflags);
|
tmpflags = tswapl(sc->eflags);
|
||||||
env->eflags = (env->eflags & ~0x40DD5) | (tmpflags & 0x40DD5);
|
env->eflags = (env->eflags & ~0x40DD5) | (tmpflags & 0x40DD5);
|
||||||
|
@ -2080,7 +2080,6 @@ long do_sigreturn(CPUState *env)
|
||||||
uint32_t up_psr, pc, npc;
|
uint32_t up_psr, pc, npc;
|
||||||
target_sigset_t set;
|
target_sigset_t set;
|
||||||
sigset_t host_set;
|
sigset_t host_set;
|
||||||
abi_ulong fpu_save_addr;
|
|
||||||
int err, i;
|
int err, i;
|
||||||
|
|
||||||
sf_addr = env->regwptr[UREG_FP];
|
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(env->regwptr[i + UREG_I0], &sf->info.si_regs.u_regs[i+8]);
|
||||||
}
|
}
|
||||||
|
|
||||||
err |= __get_user(fpu_save_addr, &sf->fpu_save);
|
/* FIXME: implement FPU save/restore:
|
||||||
|
* __get_user(fpu_save, &sf->fpu_save);
|
||||||
//if (fpu_save)
|
* if (fpu_save)
|
||||||
// err |= restore_fpu_state(env, fpu_save);
|
* err |= restore_fpu_state(env, fpu_save);
|
||||||
|
*/
|
||||||
|
|
||||||
/* This is pretty much atomic, no amount locking would prevent
|
/* This is pretty much atomic, no amount locking would prevent
|
||||||
* the races which exist anyways.
|
* the races which exist anyways.
|
||||||
|
@ -2228,7 +2228,6 @@ void sparc64_set_context(CPUSPARCState *env)
|
||||||
target_mc_gregset_t *grp;
|
target_mc_gregset_t *grp;
|
||||||
abi_ulong pc, npc, tstate;
|
abi_ulong pc, npc, tstate;
|
||||||
abi_ulong fp, i7, w_addr;
|
abi_ulong fp, i7, w_addr;
|
||||||
unsigned char fenab;
|
|
||||||
int err;
|
int err;
|
||||||
unsigned int i;
|
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]),
|
if (put_user(i7, w_addr + offsetof(struct target_reg_window, ins[7]),
|
||||||
abi_ulong) != 0)
|
abi_ulong) != 0)
|
||||||
goto do_sigsegv;
|
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));
|
err |= __get_user(env->fprs, &(ucp->tuc_mcontext.mc_fpregs.mcfpu_fprs));
|
||||||
{
|
{
|
||||||
uint32_t *src, *dst;
|
uint32_t *src, *dst;
|
||||||
|
|
|
@ -550,6 +550,15 @@ _syscall5(int, sys_ppoll, struct pollfd *, fds, nfds_t, nfds,
|
||||||
size_t, sigsetsize)
|
size_t, sigsetsize)
|
||||||
#endif
|
#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 personality(int);
|
||||||
extern int flock(int, int);
|
extern int flock(int, int);
|
||||||
extern int setfsuid(int);
|
extern int setfsuid(int);
|
||||||
|
@ -709,49 +718,81 @@ char *target_strerror(int err)
|
||||||
|
|
||||||
static abi_ulong target_brk;
|
static abi_ulong target_brk;
|
||||||
static abi_ulong target_original_brk;
|
static abi_ulong target_original_brk;
|
||||||
|
static abi_ulong brk_page;
|
||||||
|
|
||||||
void target_set_brk(abi_ulong new_brk)
|
void target_set_brk(abi_ulong new_brk)
|
||||||
{
|
{
|
||||||
target_original_brk = target_brk = HOST_PAGE_ALIGN(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. */
|
/* do_brk() must return target values and target errnos. */
|
||||||
abi_long do_brk(abi_ulong new_brk)
|
abi_long do_brk(abi_ulong new_brk)
|
||||||
{
|
{
|
||||||
abi_ulong brk_page;
|
|
||||||
abi_long mapped_addr;
|
abi_long mapped_addr;
|
||||||
int new_alloc_size;
|
int new_alloc_size;
|
||||||
|
|
||||||
if (!new_brk)
|
DEBUGF_BRK("do_brk(%#010x) -> ", new_brk);
|
||||||
return target_brk;
|
|
||||||
if (new_brk < target_original_brk)
|
|
||||||
return target_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 the new brk is less than the highest page reserved to the
|
||||||
if (new_brk < brk_page) {
|
* 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;
|
target_brk = new_brk;
|
||||||
|
DEBUGF_BRK("%#010x (new_brk <= brk_page)\n", target_brk);
|
||||||
return target_brk;
|
return target_brk;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* We need to allocate more memory after the brk... */
|
/* We need to allocate more memory after the brk... Note that
|
||||||
new_alloc_size = HOST_PAGE_ALIGN(new_brk - brk_page + 1);
|
* 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,
|
mapped_addr = get_errno(target_mmap(brk_page, new_alloc_size,
|
||||||
PROT_READ|PROT_WRITE,
|
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)
|
#if defined(TARGET_ALPHA)
|
||||||
/* We (partially) emulate OSF/1 on Alpha, which requires we
|
/* We (partially) emulate OSF/1 on Alpha, which requires we
|
||||||
return a proper errno, not an unchanged brk value. */
|
return a proper errno, not an unchanged brk value. */
|
||||||
if (is_error(mapped_addr)) {
|
return -TARGET_ENOMEM;
|
||||||
return -TARGET_ENOMEM;
|
|
||||||
}
|
|
||||||
#endif
|
#endif
|
||||||
|
/* For everything else, return the previous break. */
|
||||||
if (!is_error(mapped_addr)) {
|
|
||||||
target_brk = new_brk;
|
|
||||||
}
|
|
||||||
return target_brk;
|
return target_brk;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -787,6 +828,20 @@ static inline abi_long copy_from_user_fdset(fd_set *fds,
|
||||||
return 0;
|
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,
|
static inline abi_long copy_to_user_fdset(abi_ulong target_fds_addr,
|
||||||
const fd_set *fds,
|
const fd_set *fds,
|
||||||
int n)
|
int n)
|
||||||
|
@ -952,6 +1007,7 @@ static inline abi_long copy_to_user_mq_attr(abi_ulong target_mq_attr_addr,
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#if defined(TARGET_NR_select) || defined(TARGET_NR__newselect)
|
||||||
/* do_select() must return target values and target errnos. */
|
/* do_select() must return target values and target errnos. */
|
||||||
static abi_long do_select(int n,
|
static abi_long do_select(int n,
|
||||||
abi_ulong rfd_addr, abi_ulong wfd_addr,
|
abi_ulong rfd_addr, abi_ulong wfd_addr,
|
||||||
|
@ -962,26 +1018,17 @@ static abi_long do_select(int n,
|
||||||
struct timeval tv, *tv_ptr;
|
struct timeval tv, *tv_ptr;
|
||||||
abi_long ret;
|
abi_long ret;
|
||||||
|
|
||||||
if (rfd_addr) {
|
ret = copy_from_user_fdset_ptr(&rfds, &rfds_ptr, rfd_addr, n);
|
||||||
if (copy_from_user_fdset(&rfds, rfd_addr, n))
|
if (ret) {
|
||||||
return -TARGET_EFAULT;
|
return ret;
|
||||||
rfds_ptr = &rfds;
|
|
||||||
} else {
|
|
||||||
rfds_ptr = NULL;
|
|
||||||
}
|
}
|
||||||
if (wfd_addr) {
|
ret = copy_from_user_fdset_ptr(&wfds, &wfds_ptr, wfd_addr, n);
|
||||||
if (copy_from_user_fdset(&wfds, wfd_addr, n))
|
if (ret) {
|
||||||
return -TARGET_EFAULT;
|
return ret;
|
||||||
wfds_ptr = &wfds;
|
|
||||||
} else {
|
|
||||||
wfds_ptr = NULL;
|
|
||||||
}
|
}
|
||||||
if (efd_addr) {
|
ret = copy_from_user_fdset_ptr(&efds, &efds_ptr, efd_addr, n);
|
||||||
if (copy_from_user_fdset(&efds, efd_addr, n))
|
if (ret) {
|
||||||
return -TARGET_EFAULT;
|
return ret;
|
||||||
efds_ptr = &efds;
|
|
||||||
} else {
|
|
||||||
efds_ptr = NULL;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (target_tv_addr) {
|
if (target_tv_addr) {
|
||||||
|
@ -1008,6 +1055,7 @@ static abi_long do_select(int n,
|
||||||
|
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
static abi_long do_pipe2(int host_pipe[], int flags)
|
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
|
#ifndef TARGET_ABI32
|
||||||
static abi_long do_arch_prctl(CPUX86State *env, int code, abi_ulong addr)
|
static abi_long do_arch_prctl(CPUX86State *env, int code, abi_ulong addr)
|
||||||
{
|
{
|
||||||
abi_long ret;
|
abi_long ret = 0;
|
||||||
abi_ulong val;
|
abi_ulong val;
|
||||||
int idx;
|
int idx;
|
||||||
|
|
||||||
switch(code) {
|
switch(code) {
|
||||||
case TARGET_ARCH_SET_GS:
|
case TARGET_ARCH_SET_GS:
|
||||||
case TARGET_ARCH_SET_FS:
|
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;
|
idx = R_FS;
|
||||||
val = env->segs[idx].base;
|
val = env->segs[idx].base;
|
||||||
if (put_user(val, addr, abi_ulong))
|
if (put_user(val, addr, abi_ulong))
|
||||||
return -TARGET_EFAULT;
|
ret = -TARGET_EFAULT;
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
ret = -TARGET_EINVAL;
|
ret = -TARGET_EINVAL;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
return 0;
|
return ret;
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
@ -4484,7 +4532,8 @@ int get_osversion(void)
|
||||||
All errnos that do_syscall() returns must be -TARGET_<errcode>. */
|
All errnos that do_syscall() returns must be -TARGET_<errcode>. */
|
||||||
abi_long do_syscall(void *cpu_env, int num, abi_long arg1,
|
abi_long do_syscall(void *cpu_env, int num, abi_long arg1,
|
||||||
abi_long arg2, abi_long arg3, abi_long arg4,
|
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;
|
abi_long ret;
|
||||||
struct stat st;
|
struct stat st;
|
||||||
|
@ -5569,7 +5618,102 @@ abi_long do_syscall(void *cpu_env, int num, abi_long arg1,
|
||||||
#endif
|
#endif
|
||||||
#ifdef TARGET_NR_pselect6
|
#ifdef TARGET_NR_pselect6
|
||||||
case 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
|
#endif
|
||||||
case TARGET_NR_symlink:
|
case TARGET_NR_symlink:
|
||||||
{
|
{
|
||||||
|
@ -6029,8 +6173,9 @@ abi_long do_syscall(void *cpu_env, int num, abi_long arg1,
|
||||||
#endif
|
#endif
|
||||||
#ifdef TARGET_NR_syscall
|
#ifdef TARGET_NR_syscall
|
||||||
case TARGET_NR_syscall:
|
case TARGET_NR_syscall:
|
||||||
ret = do_syscall(cpu_env,arg1 & 0xffff,arg2,arg3,arg4,arg5,arg6,0);
|
ret = do_syscall(cpu_env, arg1 & 0xffff, arg2, arg3, arg4, arg5,
|
||||||
break;
|
arg6, arg7, arg8, 0);
|
||||||
|
break;
|
||||||
#endif
|
#endif
|
||||||
case TARGET_NR_wait4:
|
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:
|
case TARGET_NR_osf_sigprocmask:
|
||||||
{
|
{
|
||||||
abi_ulong mask;
|
abi_ulong mask;
|
||||||
int how = arg1;
|
int how;
|
||||||
sigset_t set, oldset;
|
sigset_t set, oldset;
|
||||||
|
|
||||||
switch(arg1) {
|
switch(arg1) {
|
||||||
|
@ -7077,7 +7222,7 @@ abi_long do_syscall(void *cpu_env, int num, abi_long arg1,
|
||||||
}
|
}
|
||||||
mask = arg2;
|
mask = arg2;
|
||||||
target_to_host_old_sigset(&set, &mask);
|
target_to_host_old_sigset(&set, &mask);
|
||||||
sigprocmask(arg1, &set, &oldset);
|
sigprocmask(how, &set, &oldset);
|
||||||
host_to_target_old_sigset(&mask, &oldset);
|
host_to_target_old_sigset(&mask, &oldset);
|
||||||
ret = mask;
|
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)
|
#if defined(TARGET_NR_sync_file_range)
|
||||||
case TARGET_NR_sync_file_range:
|
case TARGET_NR_sync_file_range:
|
||||||
#if TARGET_ABI_BITS == 32
|
#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),
|
ret = get_errno(sync_file_range(arg1, target_offset64(arg2, arg3),
|
||||||
target_offset64(arg4, arg5), arg6));
|
target_offset64(arg4, arg5), arg6));
|
||||||
|
#endif /* !TARGET_MIPS */
|
||||||
#else
|
#else
|
||||||
ret = get_errno(sync_file_range(arg1, arg2, arg3, arg4));
|
ret = get_errno(sync_file_range(arg1, arg2, arg3, arg4));
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -370,7 +370,7 @@ void do_m68k_semihosting(CPUM68KState *env, int nr)
|
||||||
TaskState *ts = env->opaque;
|
TaskState *ts = env->opaque;
|
||||||
/* Allocate the heap using sbrk. */
|
/* Allocate the heap using sbrk. */
|
||||||
if (!ts->heap_limit) {
|
if (!ts->heap_limit) {
|
||||||
long ret;
|
abi_ulong ret;
|
||||||
uint32_t size;
|
uint32_t size;
|
||||||
uint32_t base;
|
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. */
|
/* Try a big heap, and reduce the size if that fails. */
|
||||||
for (;;) {
|
for (;;) {
|
||||||
ret = do_brk(base + size);
|
ret = do_brk(base + size);
|
||||||
if (ret != -1)
|
if (ret >= (base + size)) {
|
||||||
break;
|
break;
|
||||||
|
}
|
||||||
size >>= 1;
|
size >>= 1;
|
||||||
}
|
}
|
||||||
ts->heap_limit = base + size;
|
ts->heap_limit = base + size;
|
||||||
|
|
Loading…
Reference in New Issue