-----BEGIN PGP SIGNATURE-----

iQIcBAABAgAGBQJYtKUTAAoJEPMMOL0/L748EhIQAKex3++PF/CcEv1iO11TTtkl
 79y1/C8WU68dLK4V1O6iw10Fakw9Iap7gROb0mvMVfWPq+IPg+jvSxQYW2+Kjeju
 /TlgOXdxzvaZUU4Z5PEelV75rUI+i81haK1FtcS8qTTRf3hDGwaFL3Kdr62pucxv
 j+ZYozFJwmpbO0v8Pnli3iSdYZYtUQ+rpuyDMZjCTLXO9uNiZi45B5F03qpFLbpx
 cA8p24l94lljb+4FW/6lLlgxEuHI8ir2VFz2noMU/kTZIpRhdcqa9VQdNteL9+eM
 hhQJzUgco1etbb3sKGxFBaKLSRpV9cZ/ZAEp01pOaypSP32UX/gBCuzPWW64nRrJ
 eLYtWmVQoqS01dskfoe8qT9JqZGXKiarqy4lKBaseuXwNSGfRYfF3Yokbtdwq0jH
 JK1DjEmn5UHSCE2W5YnooVf3MD5E8ir8Zkd4l+8JHTAsWLgtdP1FmT6OKi5Q1Apz
 6MX+mTY5iL3gDYbKSA+uFOlCtkfsOvC+TvLkmKEayol8MIROQ6cR93nNTshZqK+O
 pnXzGb0MqVTdoAQ6qhqcWr+lunlWvv+l3yktKe7rbo8pP/0pBRQ97MSM/fhApnFM
 TGXmvDJq1slVOy0tyONazrgr+j8mX8eOJNajHVo0pRjtTKpKDzfDP4vmx5SMZhDr
 xiBrafrUM1vI4UEYFu4a
 =LrI6
 -----END PGP SIGNATURE-----

Merge remote-tracking branch 'remotes/vivier2/tags/linux-user-for-upstream-pull-request' into staging

# gpg: Signature made Mon 27 Feb 2017 22:15:47 GMT
# gpg:                using RSA key 0xF30C38BD3F2FBE3C
# gpg: Good signature from "Laurent Vivier <lvivier@redhat.com>"
# gpg:                 aka "Laurent Vivier <laurent@vivier.eu>"
# gpg:                 aka "Laurent Vivier (Red Hat) <lvivier@redhat.com>"
# Primary key fingerprint: CD2F 75DD C8E3 A4DC 2E4F  5173 F30C 38BD 3F2F BE3C

* remotes/vivier2/tags/linux-user-for-upstream-pull-request:
  syscall: fixed mincore(2) not failing with ENOMEM
  linux-user: fix do_rt_sigreturn on m68k linux userspace emulation
  linux-user: correctly manage SR in ucontext
  linux-user: Add signal handling support for x86_64
  linux-user: Add sockopts for IPv6 ping and IPv6 traceroute
  linux-user: fix fork()

Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
This commit is contained in:
Peter Maydell 2017-02-28 12:03:36 +00:00
commit 105d86ff38
5 changed files with 395 additions and 61 deletions

View File

@ -254,7 +254,7 @@ int do_sigprocmask(int how, const sigset_t *set, sigset_t *oldset)
} }
#if !defined(TARGET_OPENRISC) && !defined(TARGET_UNICORE32) && \ #if !defined(TARGET_OPENRISC) && !defined(TARGET_UNICORE32) && \
!defined(TARGET_X86_64) && !defined(TARGET_NIOS2) !defined(TARGET_NIOS2)
/* Just set the guest's signal mask to the specified value; the /* Just set the guest's signal mask to the specified value; the
* caller is assumed to have called block_signals() already. * caller is assumed to have called block_signals() already.
*/ */
@ -512,7 +512,7 @@ void signal_init(void)
} }
} }
#if !(defined(TARGET_X86_64) || defined(TARGET_UNICORE32)) #ifndef TARGET_UNICORE32
/* Force a synchronously taken signal. The kernel force_sig() function /* Force a synchronously taken signal. The kernel force_sig() function
* also forces the signal to "not blocked, not ignored", but for QEMU * also forces the signal to "not blocked, not ignored", but for QEMU
* that work is done in process_pending_signals(). * that work is done in process_pending_signals().
@ -819,9 +819,8 @@ int do_sigaction(int sig, const struct target_sigaction *act,
return ret; return ret;
} }
#if defined(TARGET_I386) && TARGET_ABI_BITS == 32 #if defined(TARGET_I386)
/* from the Linux kernel - /arch/x86/include/uapi/asm/sigcontext.h */
/* from the Linux kernel */
struct target_fpreg { struct target_fpreg {
uint16_t significand[4]; uint16_t significand[4];
@ -835,58 +834,120 @@ struct target_fpxreg {
}; };
struct target_xmmreg { struct target_xmmreg {
abi_ulong element[4]; uint32_t element[4];
}; };
struct target_fpstate { struct target_fpstate_32 {
/* Regular FPU environment */ /* Regular FPU environment */
abi_ulong cw; uint32_t cw;
abi_ulong sw; uint32_t sw;
abi_ulong tag; uint32_t tag;
abi_ulong ipoff; uint32_t ipoff;
abi_ulong cssel; uint32_t cssel;
abi_ulong dataoff; uint32_t dataoff;
abi_ulong datasel; uint32_t datasel;
struct target_fpreg _st[8]; struct target_fpreg st[8];
uint16_t status; uint16_t status;
uint16_t magic; /* 0xffff = regular FPU data only */ uint16_t magic; /* 0xffff = regular FPU data only */
/* FXSR FPU environment */ /* FXSR FPU environment */
abi_ulong _fxsr_env[6]; /* FXSR FPU env is ignored */ uint32_t _fxsr_env[6]; /* FXSR FPU env is ignored */
abi_ulong mxcsr; uint32_t mxcsr;
abi_ulong reserved; uint32_t reserved;
struct target_fpxreg _fxsr_st[8]; /* FXSR FPU reg data is ignored */ struct target_fpxreg fxsr_st[8]; /* FXSR FPU reg data is ignored */
struct target_xmmreg _xmm[8]; struct target_xmmreg xmm[8];
abi_ulong padding[56]; uint32_t padding[56];
}; };
#define X86_FXSR_MAGIC 0x0000 struct target_fpstate_64 {
/* FXSAVE format */
uint16_t cw;
uint16_t sw;
uint16_t twd;
uint16_t fop;
uint64_t rip;
uint64_t rdp;
uint32_t mxcsr;
uint32_t mxcsr_mask;
uint32_t st_space[32];
uint32_t xmm_space[64];
uint32_t reserved[24];
};
struct target_sigcontext { #ifndef TARGET_X86_64
# define target_fpstate target_fpstate_32
#else
# define target_fpstate target_fpstate_64
#endif
struct target_sigcontext_32 {
uint16_t gs, __gsh; uint16_t gs, __gsh;
uint16_t fs, __fsh; uint16_t fs, __fsh;
uint16_t es, __esh; uint16_t es, __esh;
uint16_t ds, __dsh; uint16_t ds, __dsh;
abi_ulong edi; uint32_t edi;
abi_ulong esi; uint32_t esi;
abi_ulong ebp; uint32_t ebp;
abi_ulong esp; uint32_t esp;
abi_ulong ebx; uint32_t ebx;
abi_ulong edx; uint32_t edx;
abi_ulong ecx; uint32_t ecx;
abi_ulong eax; uint32_t eax;
abi_ulong trapno; uint32_t trapno;
abi_ulong err; uint32_t err;
abi_ulong eip; uint32_t eip;
uint16_t cs, __csh; uint16_t cs, __csh;
abi_ulong eflags; uint32_t eflags;
abi_ulong esp_at_signal; uint32_t esp_at_signal;
uint16_t ss, __ssh; uint16_t ss, __ssh;
abi_ulong fpstate; /* pointer */ uint32_t fpstate; /* pointer */
abi_ulong oldmask; uint32_t oldmask;
abi_ulong cr2; uint32_t cr2;
}; };
struct target_sigcontext_64 {
uint64_t r8;
uint64_t r9;
uint64_t r10;
uint64_t r11;
uint64_t r12;
uint64_t r13;
uint64_t r14;
uint64_t r15;
uint64_t rdi;
uint64_t rsi;
uint64_t rbp;
uint64_t rbx;
uint64_t rdx;
uint64_t rax;
uint64_t rcx;
uint64_t rsp;
uint64_t rip;
uint64_t eflags;
uint16_t cs;
uint16_t gs;
uint16_t fs;
uint16_t ss;
uint64_t err;
uint64_t trapno;
uint64_t oldmask;
uint64_t cr2;
uint64_t fpstate; /* pointer */
uint64_t padding[8];
};
#ifndef TARGET_X86_64
# define target_sigcontext target_sigcontext_32
#else
# define target_sigcontext target_sigcontext_64
#endif
/* see Linux/include/uapi/asm-generic/ucontext.h */
struct target_ucontext { struct target_ucontext {
abi_ulong tuc_flags; abi_ulong tuc_flags;
abi_ulong tuc_link; abi_ulong tuc_link;
@ -895,8 +956,8 @@ struct target_ucontext {
target_sigset_t tuc_sigmask; /* mask last for extensibility */ target_sigset_t tuc_sigmask; /* mask last for extensibility */
}; };
struct sigframe #ifndef TARGET_X86_64
{ struct sigframe {
abi_ulong pretcode; abi_ulong pretcode;
int sig; int sig;
struct target_sigcontext sc; struct target_sigcontext sc;
@ -905,8 +966,7 @@ struct sigframe
char retcode[8]; char retcode[8];
}; };
struct rt_sigframe struct rt_sigframe {
{
abi_ulong pretcode; abi_ulong pretcode;
int sig; int sig;
abi_ulong pinfo; abi_ulong pinfo;
@ -917,6 +977,17 @@ struct rt_sigframe
char retcode[8]; char retcode[8];
}; };
#else
struct rt_sigframe {
abi_ulong pretcode;
struct target_ucontext uc;
struct target_siginfo info;
struct target_fpstate fpstate;
};
#endif
/* /*
* Set up a signal frame. * Set up a signal frame.
*/ */
@ -927,6 +998,7 @@ static void setup_sigcontext(struct target_sigcontext *sc,
abi_ulong fpstate_addr) abi_ulong fpstate_addr)
{ {
CPUState *cs = CPU(x86_env_get_cpu(env)); CPUState *cs = CPU(x86_env_get_cpu(env));
#ifndef TARGET_X86_64
uint16_t magic; uint16_t magic;
/* already locked in setup_frame() */ /* already locked in setup_frame() */
@ -959,6 +1031,44 @@ static void setup_sigcontext(struct target_sigcontext *sc,
/* non-iBCS2 extensions.. */ /* non-iBCS2 extensions.. */
__put_user(mask, &sc->oldmask); __put_user(mask, &sc->oldmask);
__put_user(env->cr[2], &sc->cr2); __put_user(env->cr[2], &sc->cr2);
#else
__put_user(env->regs[R_EDI], &sc->rdi);
__put_user(env->regs[R_ESI], &sc->rsi);
__put_user(env->regs[R_EBP], &sc->rbp);
__put_user(env->regs[R_ESP], &sc->rsp);
__put_user(env->regs[R_EBX], &sc->rbx);
__put_user(env->regs[R_EDX], &sc->rdx);
__put_user(env->regs[R_ECX], &sc->rcx);
__put_user(env->regs[R_EAX], &sc->rax);
__put_user(env->regs[8], &sc->r8);
__put_user(env->regs[9], &sc->r9);
__put_user(env->regs[10], &sc->r10);
__put_user(env->regs[11], &sc->r11);
__put_user(env->regs[12], &sc->r12);
__put_user(env->regs[13], &sc->r13);
__put_user(env->regs[14], &sc->r14);
__put_user(env->regs[15], &sc->r15);
__put_user(cs->exception_index, &sc->trapno);
__put_user(env->error_code, &sc->err);
__put_user(env->eip, &sc->rip);
__put_user(env->eflags, &sc->eflags);
__put_user(env->segs[R_CS].selector, &sc->cs);
__put_user((uint16_t)0, &sc->gs);
__put_user((uint16_t)0, &sc->fs);
__put_user(env->segs[R_SS].selector, &sc->ss);
__put_user(mask, &sc->oldmask);
__put_user(env->cr[2], &sc->cr2);
/* fpstate_addr must be 16 byte aligned for fxsave */
assert(!(fpstate_addr & 0xf));
cpu_x86_fxsave(env, fpstate_addr);
__put_user(fpstate_addr, &sc->fpstate);
#endif
} }
/* /*
@ -972,23 +1082,34 @@ get_sigframe(struct target_sigaction *ka, CPUX86State *env, size_t frame_size)
/* Default to using normal stack */ /* Default to using normal stack */
esp = env->regs[R_ESP]; esp = env->regs[R_ESP];
#ifdef TARGET_X86_64
esp -= 128; /* this is the redzone */
#endif
/* This is the X/Open sanctioned signal stack switching. */ /* This is the X/Open sanctioned signal stack switching. */
if (ka->sa_flags & TARGET_SA_ONSTACK) { if (ka->sa_flags & TARGET_SA_ONSTACK) {
if (sas_ss_flags(esp) == 0) { if (sas_ss_flags(esp) == 0) {
esp = target_sigaltstack_used.ss_sp + target_sigaltstack_used.ss_size; esp = target_sigaltstack_used.ss_sp + target_sigaltstack_used.ss_size;
} }
} else { } else {
#ifndef TARGET_X86_64
/* This is the legacy signal stack switching. */ /* This is the legacy signal stack switching. */
if ((env->segs[R_SS].selector & 0xffff) != __USER_DS && if ((env->segs[R_SS].selector & 0xffff) != __USER_DS &&
!(ka->sa_flags & TARGET_SA_RESTORER) && !(ka->sa_flags & TARGET_SA_RESTORER) &&
ka->sa_restorer) { ka->sa_restorer) {
esp = (unsigned long) ka->sa_restorer; esp = (unsigned long) ka->sa_restorer;
} }
#endif
} }
#ifndef TARGET_X86_64
return (esp - frame_size) & -8ul; return (esp - frame_size) & -8ul;
#else
return ((esp - frame_size) & (~15ul)) - 8;
#endif
} }
#ifndef TARGET_X86_64
/* compare linux/arch/i386/kernel/signal.c:setup_frame() */ /* compare linux/arch/i386/kernel/signal.c:setup_frame() */
static void setup_frame(int sig, struct target_sigaction *ka, static void setup_frame(int sig, struct target_sigaction *ka,
target_sigset_t *set, CPUX86State *env) target_sigset_t *set, CPUX86State *env)
@ -1029,7 +1150,6 @@ static void setup_frame(int sig, struct target_sigaction *ka,
__put_user(val16, (uint16_t *)(frame->retcode+6)); __put_user(val16, (uint16_t *)(frame->retcode+6));
} }
/* Set up registers for signal handler */ /* Set up registers for signal handler */
env->regs[R_ESP] = frame_addr; env->regs[R_ESP] = frame_addr;
env->eip = ka->_sa_handler; env->eip = ka->_sa_handler;
@ -1047,13 +1167,17 @@ static void setup_frame(int sig, struct target_sigaction *ka,
give_sigsegv: give_sigsegv:
force_sigsegv(sig); force_sigsegv(sig);
} }
#endif
/* compare linux/arch/i386/kernel/signal.c:setup_rt_frame() */ /* compare linux/arch/x86/kernel/signal.c:setup_rt_frame() */
static void setup_rt_frame(int sig, struct target_sigaction *ka, static void setup_rt_frame(int sig, struct target_sigaction *ka,
target_siginfo_t *info, target_siginfo_t *info,
target_sigset_t *set, CPUX86State *env) target_sigset_t *set, CPUX86State *env)
{ {
abi_ulong frame_addr, addr; abi_ulong frame_addr;
#ifndef TARGET_X86_64
abi_ulong addr;
#endif
struct rt_sigframe *frame; struct rt_sigframe *frame;
int i; int i;
@ -1063,12 +1187,17 @@ static void setup_rt_frame(int sig, struct target_sigaction *ka,
if (!lock_user_struct(VERIFY_WRITE, frame, frame_addr, 0)) if (!lock_user_struct(VERIFY_WRITE, frame, frame_addr, 0))
goto give_sigsegv; goto give_sigsegv;
/* These fields are only in rt_sigframe on 32 bit */
#ifndef TARGET_X86_64
__put_user(sig, &frame->sig); __put_user(sig, &frame->sig);
addr = frame_addr + offsetof(struct rt_sigframe, info); addr = frame_addr + offsetof(struct rt_sigframe, info);
__put_user(addr, &frame->pinfo); __put_user(addr, &frame->pinfo);
addr = frame_addr + offsetof(struct rt_sigframe, uc); addr = frame_addr + offsetof(struct rt_sigframe, uc);
__put_user(addr, &frame->puc); __put_user(addr, &frame->puc);
#endif
if (ka->sa_flags & TARGET_SA_SIGINFO) {
tswap_siginfo(&frame->info, info); tswap_siginfo(&frame->info, info);
}
/* Create the ucontext. */ /* Create the ucontext. */
__put_user(0, &frame->uc.tuc_flags); __put_user(0, &frame->uc.tuc_flags);
@ -1087,6 +1216,7 @@ static void setup_rt_frame(int sig, struct target_sigaction *ka,
/* Set up to return from userspace. If provided, use a stub /* Set up to return from userspace. If provided, use a stub
already in userspace. */ already in userspace. */
#ifndef TARGET_X86_64
if (ka->sa_flags & TARGET_SA_RESTORER) { if (ka->sa_flags & TARGET_SA_RESTORER) {
__put_user(ka->sa_restorer, &frame->pretcode); __put_user(ka->sa_restorer, &frame->pretcode);
} else { } else {
@ -1099,15 +1229,31 @@ static void setup_rt_frame(int sig, struct target_sigaction *ka,
val16 = 0x80cd; val16 = 0x80cd;
__put_user(val16, (uint16_t *)(frame->retcode+5)); __put_user(val16, (uint16_t *)(frame->retcode+5));
} }
#else
/* XXX: Would be slightly better to return -EFAULT here if test fails
assert(ka->sa_flags & TARGET_SA_RESTORER); */
__put_user(ka->sa_restorer, &frame->pretcode);
#endif
/* Set up registers for signal handler */ /* Set up registers for signal handler */
env->regs[R_ESP] = frame_addr; env->regs[R_ESP] = frame_addr;
env->eip = ka->_sa_handler; env->eip = ka->_sa_handler;
#ifndef TARGET_X86_64
env->regs[R_EAX] = sig;
env->regs[R_EDX] = (unsigned long)&frame->info;
env->regs[R_ECX] = (unsigned long)&frame->uc;
#else
env->regs[R_EAX] = 0;
env->regs[R_EDI] = sig;
env->regs[R_ESI] = (unsigned long)&frame->info;
env->regs[R_EDX] = (unsigned long)&frame->uc;
#endif
cpu_x86_load_seg(env, R_DS, __USER_DS); cpu_x86_load_seg(env, R_DS, __USER_DS);
cpu_x86_load_seg(env, R_ES, __USER_DS); cpu_x86_load_seg(env, R_ES, __USER_DS);
cpu_x86_load_seg(env, R_SS, __USER_DS);
cpu_x86_load_seg(env, R_CS, __USER_CS); cpu_x86_load_seg(env, R_CS, __USER_CS);
cpu_x86_load_seg(env, R_SS, __USER_DS);
env->eflags &= ~TF_MASK; env->eflags &= ~TF_MASK;
unlock_user_struct(frame, frame_addr, 1); unlock_user_struct(frame, frame_addr, 1);
@ -1125,6 +1271,7 @@ restore_sigcontext(CPUX86State *env, struct target_sigcontext *sc)
abi_ulong fpstate_addr; abi_ulong fpstate_addr;
unsigned int tmpflags; unsigned int tmpflags;
#ifndef TARGET_X86_64
cpu_x86_load_seg(env, R_GS, tswap16(sc->gs)); cpu_x86_load_seg(env, R_GS, tswap16(sc->gs));
cpu_x86_load_seg(env, R_FS, tswap16(sc->fs)); cpu_x86_load_seg(env, R_FS, tswap16(sc->fs));
cpu_x86_load_seg(env, R_ES, tswap16(sc->es)); cpu_x86_load_seg(env, R_ES, tswap16(sc->es));
@ -1138,7 +1285,29 @@ restore_sigcontext(CPUX86State *env, struct target_sigcontext *sc)
env->regs[R_EDX] = tswapl(sc->edx); env->regs[R_EDX] = tswapl(sc->edx);
env->regs[R_ECX] = tswapl(sc->ecx); env->regs[R_ECX] = tswapl(sc->ecx);
env->regs[R_EAX] = tswapl(sc->eax); env->regs[R_EAX] = tswapl(sc->eax);
env->eip = tswapl(sc->eip); env->eip = tswapl(sc->eip);
#else
env->regs[8] = tswapl(sc->r8);
env->regs[9] = tswapl(sc->r9);
env->regs[10] = tswapl(sc->r10);
env->regs[11] = tswapl(sc->r11);
env->regs[12] = tswapl(sc->r12);
env->regs[13] = tswapl(sc->r13);
env->regs[14] = tswapl(sc->r14);
env->regs[15] = tswapl(sc->r15);
env->regs[R_EDI] = tswapl(sc->rdi);
env->regs[R_ESI] = tswapl(sc->rsi);
env->regs[R_EBP] = tswapl(sc->rbp);
env->regs[R_EBX] = tswapl(sc->rbx);
env->regs[R_EDX] = tswapl(sc->rdx);
env->regs[R_EAX] = tswapl(sc->rax);
env->regs[R_ECX] = tswapl(sc->rcx);
env->regs[R_ESP] = tswapl(sc->rsp);
env->eip = tswapl(sc->rip);
#endif
cpu_x86_load_seg(env, R_CS, lduw_p(&sc->cs) | 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); cpu_x86_load_seg(env, R_SS, lduw_p(&sc->ss) | 3);
@ -1152,7 +1321,11 @@ restore_sigcontext(CPUX86State *env, struct target_sigcontext *sc)
if (!access_ok(VERIFY_READ, fpstate_addr, if (!access_ok(VERIFY_READ, fpstate_addr,
sizeof(struct target_fpstate))) sizeof(struct target_fpstate)))
goto badframe; goto badframe;
#ifndef TARGET_X86_64
cpu_x86_frstor(env, fpstate_addr, 1); cpu_x86_frstor(env, fpstate_addr, 1);
#else
cpu_x86_fxrstor(env, fpstate_addr);
#endif
} }
return err; return err;
@ -1160,6 +1333,8 @@ badframe:
return 1; return 1;
} }
/* Note: there is no sigreturn on x86_64, there is only rt_sigreturn */
#ifndef TARGET_X86_64
long do_sigreturn(CPUX86State *env) long do_sigreturn(CPUX86State *env)
{ {
struct sigframe *frame; struct sigframe *frame;
@ -1191,6 +1366,7 @@ badframe:
force_sig(TARGET_SIGSEGV); force_sig(TARGET_SIGSEGV);
return -TARGET_QEMU_ESIGRETURN; return -TARGET_QEMU_ESIGRETURN;
} }
#endif
long do_rt_sigreturn(CPUX86State *env) long do_rt_sigreturn(CPUX86State *env)
{ {
@ -1198,7 +1374,7 @@ long do_rt_sigreturn(CPUX86State *env)
struct rt_sigframe *frame; struct rt_sigframe *frame;
sigset_t set; sigset_t set;
frame_addr = env->regs[R_ESP] - 4; frame_addr = env->regs[R_ESP] - sizeof(abi_ulong);
trace_user_do_rt_sigreturn(env, frame_addr); trace_user_do_rt_sigreturn(env, frame_addr);
if (!lock_user_struct(VERIFY_READ, frame, frame_addr, 1)) if (!lock_user_struct(VERIFY_READ, frame, frame_addr, 1))
goto badframe; goto badframe;
@ -5500,6 +5676,7 @@ static inline int target_rt_setup_ucontext(struct target_ucontext *uc,
CPUM68KState *env) CPUM68KState *env)
{ {
target_greg_t *gregs = uc->tuc_mcontext.gregs; target_greg_t *gregs = uc->tuc_mcontext.gregs;
uint32_t sr = cpu_m68k_get_ccr(env);
__put_user(TARGET_MCONTEXT_VERSION, &uc->tuc_mcontext.version); __put_user(TARGET_MCONTEXT_VERSION, &uc->tuc_mcontext.version);
__put_user(env->dregs[0], &gregs[0]); __put_user(env->dregs[0], &gregs[0]);
@ -5519,7 +5696,7 @@ static inline int target_rt_setup_ucontext(struct target_ucontext *uc,
__put_user(env->aregs[6], &gregs[14]); __put_user(env->aregs[6], &gregs[14]);
__put_user(env->aregs[7], &gregs[15]); __put_user(env->aregs[7], &gregs[15]);
__put_user(env->pc, &gregs[16]); __put_user(env->pc, &gregs[16]);
__put_user(env->sr, &gregs[17]); __put_user(sr, &gregs[17]);
return 0; return 0;
} }
@ -5553,7 +5730,7 @@ static inline int target_rt_restore_ucontext(CPUM68KState *env,
__get_user(env->aregs[7], &gregs[15]); __get_user(env->aregs[7], &gregs[15]);
__get_user(env->pc, &gregs[16]); __get_user(env->pc, &gregs[16]);
__get_user(temp, &gregs[17]); __get_user(temp, &gregs[17]);
env->sr = (env->sr & 0xff00) | (temp & 0xff); cpu_m68k_set_ccr(env, temp);
return 0; return 0;
@ -5674,14 +5851,13 @@ long do_rt_sigreturn(CPUM68KState *env)
{ {
struct target_rt_sigframe *frame; struct target_rt_sigframe *frame;
abi_ulong frame_addr = env->aregs[7] - 4; abi_ulong frame_addr = env->aregs[7] - 4;
target_sigset_t target_set;
sigset_t set; sigset_t set;
trace_user_do_rt_sigreturn(env, frame_addr); trace_user_do_rt_sigreturn(env, frame_addr);
if (!lock_user_struct(VERIFY_READ, frame, frame_addr, 1)) if (!lock_user_struct(VERIFY_READ, frame, frame_addr, 1))
goto badframe; goto badframe;
target_to_host_sigset_internal(&set, &target_set); target_to_host_sigset(&set, &frame->uc.tuc_sigmask);
set_sigmask(&set); set_sigmask(&set);
/* restore registers */ /* restore registers */
@ -6418,7 +6594,7 @@ static void handle_pending_signal(CPUArchState *cpu_env, int sig,
#if defined(TARGET_ABI_MIPSN32) || defined(TARGET_ABI_MIPSN64) \ #if defined(TARGET_ABI_MIPSN32) || defined(TARGET_ABI_MIPSN64) \
|| defined(TARGET_OPENRISC) || defined(TARGET_TILEGX) \ || defined(TARGET_OPENRISC) || defined(TARGET_TILEGX) \
|| defined(TARGET_PPC64) || defined(TARGET_HPPA) \ || defined(TARGET_PPC64) || defined(TARGET_HPPA) \
|| defined(TARGET_NIOS2) || defined(TARGET_NIOS2) || defined(TARGET_X86_64)
/* These targets do not have traditional signals. */ /* These targets do not have traditional signals. */
setup_rt_frame(sig, sa, &k->info, &target_old_set, cpu_env); setup_rt_frame(sig, sa, &k->info, &target_old_set, cpu_env);
#else #else

View File

@ -57,6 +57,8 @@ int __clone2(int (*fn)(void *), void *child_stack_base,
#include <netinet/tcp.h> #include <netinet/tcp.h>
#include <linux/wireless.h> #include <linux/wireless.h>
#include <linux/icmp.h> #include <linux/icmp.h>
#include <linux/icmpv6.h>
#include <linux/errqueue.h>
#include "qemu-common.h" #include "qemu-common.h"
#ifdef CONFIG_TIMERFD #ifdef CONFIG_TIMERFD
#include <sys/timerfd.h> #include <sys/timerfd.h>
@ -1634,6 +1636,11 @@ static inline abi_long host_to_target_sockaddr(abi_ulong target_addr,
struct sockaddr_ll *target_ll = (struct sockaddr_ll *)target_saddr; struct sockaddr_ll *target_ll = (struct sockaddr_ll *)target_saddr;
target_ll->sll_ifindex = tswap32(target_ll->sll_ifindex); target_ll->sll_ifindex = tswap32(target_ll->sll_ifindex);
target_ll->sll_hatype = tswap16(target_ll->sll_hatype); target_ll->sll_hatype = tswap16(target_ll->sll_hatype);
} else if (addr->sa_family == AF_INET6 &&
len >= sizeof(struct target_sockaddr_in6)) {
struct target_sockaddr_in6 *target_in6 =
(struct target_sockaddr_in6 *)target_saddr;
target_in6->sin6_scope_id = tswap16(target_in6->sin6_scope_id);
} }
unlock_user(target_saddr, target_addr, len); unlock_user(target_saddr, target_addr, len);
@ -1839,6 +1846,78 @@ static inline abi_long host_to_target_cmsg(struct target_msghdr *target_msgh,
} }
break; break;
case SOL_IP:
switch (cmsg->cmsg_type) {
case IP_TTL:
{
uint32_t *v = (uint32_t *)data;
uint32_t *t_int = (uint32_t *)target_data;
__put_user(*v, t_int);
break;
}
case IP_RECVERR:
{
struct errhdr_t {
struct sock_extended_err ee;
struct sockaddr_in offender;
};
struct errhdr_t *errh = (struct errhdr_t *)data;
struct errhdr_t *target_errh =
(struct errhdr_t *)target_data;
__put_user(errh->ee.ee_errno, &target_errh->ee.ee_errno);
__put_user(errh->ee.ee_origin, &target_errh->ee.ee_origin);
__put_user(errh->ee.ee_type, &target_errh->ee.ee_type);
__put_user(errh->ee.ee_code, &target_errh->ee.ee_code);
__put_user(errh->ee.ee_pad, &target_errh->ee.ee_pad);
__put_user(errh->ee.ee_info, &target_errh->ee.ee_info);
__put_user(errh->ee.ee_data, &target_errh->ee.ee_data);
host_to_target_sockaddr((unsigned long) &target_errh->offender,
(void *) &errh->offender, sizeof(errh->offender));
break;
}
default:
goto unimplemented;
}
break;
case SOL_IPV6:
switch (cmsg->cmsg_type) {
case IPV6_HOPLIMIT:
{
uint32_t *v = (uint32_t *)data;
uint32_t *t_int = (uint32_t *)target_data;
__put_user(*v, t_int);
break;
}
case IPV6_RECVERR:
{
struct errhdr6_t {
struct sock_extended_err ee;
struct sockaddr_in6 offender;
};
struct errhdr6_t *errh = (struct errhdr6_t *)data;
struct errhdr6_t *target_errh =
(struct errhdr6_t *)target_data;
__put_user(errh->ee.ee_errno, &target_errh->ee.ee_errno);
__put_user(errh->ee.ee_origin, &target_errh->ee.ee_origin);
__put_user(errh->ee.ee_type, &target_errh->ee.ee_type);
__put_user(errh->ee.ee_code, &target_errh->ee.ee_code);
__put_user(errh->ee.ee_pad, &target_errh->ee.ee_pad);
__put_user(errh->ee.ee_info, &target_errh->ee.ee_info);
__put_user(errh->ee.ee_data, &target_errh->ee.ee_data);
host_to_target_sockaddr((unsigned long) &target_errh->offender,
(void *) &errh->offender, sizeof(errh->offender));
break;
}
default:
goto unimplemented;
}
break;
default: default:
unimplemented: unimplemented:
gemu_log("Unsupported ancillary data: %d/%d\n", gemu_log("Unsupported ancillary data: %d/%d\n",
@ -2768,6 +2847,7 @@ static abi_long do_setsockopt(int sockfd, int level, int optname,
case IP_PKTINFO: case IP_PKTINFO:
case IP_MTU_DISCOVER: case IP_MTU_DISCOVER:
case IP_RECVERR: case IP_RECVERR:
case IP_RECVTTL:
case IP_RECVTOS: case IP_RECVTOS:
#ifdef IP_FREEBIND #ifdef IP_FREEBIND
case IP_FREEBIND: case IP_FREEBIND:
@ -2817,6 +2897,11 @@ static abi_long do_setsockopt(int sockfd, int level, int optname,
case IPV6_MTU: case IPV6_MTU:
case IPV6_V6ONLY: case IPV6_V6ONLY:
case IPV6_RECVPKTINFO: case IPV6_RECVPKTINFO:
case IPV6_UNICAST_HOPS:
case IPV6_RECVERR:
case IPV6_RECVHOPLIMIT:
case IPV6_2292HOPLIMIT:
case IPV6_CHECKSUM:
val = 0; val = 0;
if (optlen < sizeof(uint32_t)) { if (optlen < sizeof(uint32_t)) {
return -TARGET_EINVAL; return -TARGET_EINVAL;
@ -2827,6 +2912,50 @@ static abi_long do_setsockopt(int sockfd, int level, int optname,
ret = get_errno(setsockopt(sockfd, level, optname, ret = get_errno(setsockopt(sockfd, level, optname,
&val, sizeof(val))); &val, sizeof(val)));
break; break;
case IPV6_PKTINFO:
{
struct in6_pktinfo pki;
if (optlen < sizeof(pki)) {
return -TARGET_EINVAL;
}
if (copy_from_user(&pki, optval_addr, sizeof(pki))) {
return -TARGET_EFAULT;
}
pki.ipi6_ifindex = tswap32(pki.ipi6_ifindex);
ret = get_errno(setsockopt(sockfd, level, optname,
&pki, sizeof(pki)));
break;
}
default:
goto unimplemented;
}
break;
case SOL_ICMPV6:
switch (optname) {
case ICMPV6_FILTER:
{
struct icmp6_filter icmp6f;
if (optlen > sizeof(icmp6f)) {
optlen = sizeof(icmp6f);
}
if (copy_from_user(&icmp6f, optval_addr, optlen)) {
return -TARGET_EFAULT;
}
for (val = 0; val < 8; val++) {
icmp6f.data[val] = tswap32(icmp6f.data[val]);
}
ret = get_errno(setsockopt(sockfd, level, optname,
&icmp6f, optlen));
break;
}
default: default:
goto unimplemented; goto unimplemented;
} }
@ -2834,7 +2963,8 @@ static abi_long do_setsockopt(int sockfd, int level, int optname,
case SOL_RAW: case SOL_RAW:
switch (optname) { switch (optname) {
case ICMP_FILTER: case ICMP_FILTER:
/* struct icmp_filter takes an u32 value */ case IPV6_CHECKSUM:
/* those take an u32 value */
if (optlen < sizeof(uint32_t)) { if (optlen < sizeof(uint32_t)) {
return -TARGET_EINVAL; return -TARGET_EINVAL;
} }
@ -7680,7 +7810,7 @@ abi_long do_syscall(void *cpu_env, int num, abi_long arg1,
break; break;
#ifdef TARGET_NR_fork #ifdef TARGET_NR_fork
case TARGET_NR_fork: case TARGET_NR_fork:
ret = get_errno(do_fork(cpu_env, SIGCHLD, 0, 0, 0, 0)); ret = get_errno(do_fork(cpu_env, TARGET_SIGCHLD, 0, 0, 0, 0));
break; break;
#endif #endif
#ifdef TARGET_NR_waitpid #ifdef TARGET_NR_waitpid
@ -10490,7 +10620,8 @@ abi_long do_syscall(void *cpu_env, int num, abi_long arg1,
#endif #endif
#ifdef TARGET_NR_vfork #ifdef TARGET_NR_vfork
case TARGET_NR_vfork: case TARGET_NR_vfork:
ret = get_errno(do_fork(cpu_env, CLONE_VFORK | CLONE_VM | SIGCHLD, ret = get_errno(do_fork(cpu_env,
CLONE_VFORK | CLONE_VM | TARGET_SIGCHLD,
0, 0, 0, 0)); 0, 0, 0, 0));
break; break;
#endif #endif
@ -11063,11 +11194,16 @@ abi_long do_syscall(void *cpu_env, int num, abi_long arg1,
case TARGET_NR_mincore: case TARGET_NR_mincore:
{ {
void *a; void *a;
ret = -TARGET_ENOMEM;
a = lock_user(VERIFY_READ, arg1, arg2, 0);
if (!a) {
goto fail;
}
ret = -TARGET_EFAULT; ret = -TARGET_EFAULT;
if (!(a = lock_user(VERIFY_READ, arg1,arg2, 0))) p = lock_user_string(arg3);
goto efault; if (!p) {
if (!(p = lock_user_string(arg3)))
goto mincore_fail; goto mincore_fail;
}
ret = get_errno(mincore(a, arg2, p)); ret = get_errno(mincore(a, arg2, p));
unlock_user(p, arg3, ret); unlock_user(p, arg3, ret);
mincore_fail: mincore_fail:

View File

@ -164,6 +164,14 @@ struct target_sockaddr_in {
sizeof(struct target_in_addr)]; sizeof(struct target_in_addr)];
}; };
struct target_sockaddr_in6 {
uint16_t sin6_family;
uint16_t sin6_port; /* big endian */
uint32_t sin6_flowinfo; /* big endian */
struct in6_addr sin6_addr; /* IPv6 address, big endian */
uint32_t sin6_scope_id;
};
struct target_sock_filter { struct target_sock_filter {
abi_ushort code; abi_ushort code;
uint8_t jt; uint8_t jt;

View File

@ -1417,6 +1417,8 @@ floatx80 cpu_set_fp80(uint64_t mant, uint16_t upper);
void cpu_x86_load_seg(CPUX86State *s, int seg_reg, int selector); void cpu_x86_load_seg(CPUX86State *s, int seg_reg, int selector);
void cpu_x86_fsave(CPUX86State *s, target_ulong ptr, int data32); void cpu_x86_fsave(CPUX86State *s, target_ulong ptr, int data32);
void cpu_x86_frstor(CPUX86State *s, target_ulong ptr, int data32); void cpu_x86_frstor(CPUX86State *s, target_ulong ptr, int data32);
void cpu_x86_fxsave(CPUX86State *s, target_ulong ptr);
void cpu_x86_fxrstor(CPUX86State *s, target_ulong ptr);
/* you can call this signal handler from your SIGBUS and SIGSEGV /* you can call this signal handler from your SIGBUS and SIGSEGV
signal handlers to inform the virtual CPU of exceptions. non zero signal handlers to inform the virtual CPU of exceptions. non zero

View File

@ -1377,6 +1377,18 @@ void helper_fxrstor(CPUX86State *env, target_ulong ptr)
} }
} }
#if defined(CONFIG_USER_ONLY)
void cpu_x86_fxsave(CPUX86State *env, target_ulong ptr)
{
helper_fxsave(env, ptr);
}
void cpu_x86_fxrstor(CPUX86State *env, target_ulong ptr)
{
helper_fxrstor(env, ptr);
}
#endif
void helper_xrstor(CPUX86State *env, target_ulong ptr, uint64_t rfbm) void helper_xrstor(CPUX86State *env, target_ulong ptr, uint64_t rfbm)
{ {
uintptr_t ra = GETPC(); uintptr_t ra = GETPC();