diff options
Diffstat (limited to 'linux-user/sparc/target_cpu.h')
| -rw-r--r-- | linux-user/sparc/target_cpu.h | 60 |
1 files changed, 44 insertions, 16 deletions
diff --git a/linux-user/sparc/target_cpu.h b/linux-user/sparc/target_cpu.h index 1ffc0ae9f2..14b2158969 100644 --- a/linux-user/sparc/target_cpu.h +++ b/linux-user/sparc/target_cpu.h @@ -20,20 +20,54 @@ #ifndef SPARC_TARGET_CPU_H #define SPARC_TARGET_CPU_H -static inline void cpu_clone_regs(CPUSPARCState *env, target_ulong newsp) +static inline void cpu_clone_regs_child(CPUSPARCState *env, target_ulong newsp, + unsigned flags) { + /* + * After cpu_copy, env->regwptr is pointing into the old env. + * Update the new cpu to use its own register window. + */ + env->regwptr = env->regbase + (env->cwp * 16); + if (newsp) { - env->regwptr[22] = newsp; + /* When changing stacks, do it with clean register windows. */ +#ifdef TARGET_SPARC64 + env->cansave = env->nwindows - 2; + env->cleanwin = env->nwindows - 2; + env->canrestore = 0; +#else + env->wim = 1 << env->cwp; +#endif + /* ??? The kernel appears to copy one stack frame to the new stack. */ + /* ??? The kernel force aligns the new stack. */ + env->regwptr[WREG_SP] = newsp; } - /* syscall return for clone child: 0, and clear CF since - * this counts as a success return value. - */ - env->regwptr[0] = 0; + + if (flags & CLONE_VM) { + /* + * Syscall return for clone child: %o0 = 0 and clear CF since this + * counts as a success return value. Advance the PC past the syscall. + * For fork child, all of this happens in cpu_loop, and we must not + * do the pc advance twice. + */ + env->regwptr[WREG_O0] = 0; #if defined(TARGET_SPARC64) && !defined(TARGET_ABI32) - env->xcc &= ~PSR_CARRY; + env->xcc &= ~PSR_CARRY; #else - env->psr &= ~PSR_CARRY; + env->psr &= ~PSR_CARRY; #endif + env->pc = env->npc; + env->npc = env->npc + 4; + } + + /* Set the second return value for the child: %o1 = 1. */ + env->regwptr[WREG_O1] = 1; +} + +static inline void cpu_clone_regs_parent(CPUSPARCState *env, unsigned flags) +{ + /* Set the second return value for the parent: %o1 = 0. */ + env->regwptr[WREG_O1] = 0; } static inline void cpu_set_tls(CPUSPARCState *env, target_ulong newtls) @@ -41,15 +75,9 @@ static inline void cpu_set_tls(CPUSPARCState *env, target_ulong newtls) env->gregs[7] = newtls; } -#ifndef UREG_I6 -#define UREG_I6 6 -#endif -#ifndef UREG_FP -#define UREG_FP UREG_I6 -#endif - static inline abi_ulong get_sp_from_cpustate(CPUSPARCState *state) { - return state->regwptr[UREG_FP]; + return state->regwptr[WREG_SP]; } + #endif |