linux-user: handle POWERPC_EXCP_STCX
We handle conditional stores as an exception so we can ensure that no other thread is changing memory out from underneath us. Signed-off-by: Nathan Froyd <froydnj@codesourcery.com> Signed-off-by: malc <av1474@comtv.ru>
This commit is contained in:
		
							parent
							
								
									4425265beb
								
							
						
					
					
						commit
						56f066bb17
					
				| 
						 | 
				
			
			@ -1060,6 +1060,63 @@ do {                                                                    \
 | 
			
		|||
        log_cpu_state(env, 0);                                          \
 | 
			
		||||
} while (0)
 | 
			
		||||
 | 
			
		||||
static int do_store_exclusive(CPUPPCState *env)
 | 
			
		||||
{
 | 
			
		||||
    target_ulong addr;
 | 
			
		||||
    target_ulong page_addr;
 | 
			
		||||
    target_ulong val;
 | 
			
		||||
    int flags;
 | 
			
		||||
    int segv = 0;
 | 
			
		||||
 | 
			
		||||
    addr = env->reserve_ea;
 | 
			
		||||
    page_addr = addr & TARGET_PAGE_MASK;
 | 
			
		||||
    start_exclusive();
 | 
			
		||||
    mmap_lock();
 | 
			
		||||
    flags = page_get_flags(page_addr);
 | 
			
		||||
    if ((flags & PAGE_READ) == 0) {
 | 
			
		||||
        segv = 1;
 | 
			
		||||
    } else {
 | 
			
		||||
        int reg = env->reserve_info & 0x1f;
 | 
			
		||||
        int size = (env->reserve_info >> 5) & 0xf;
 | 
			
		||||
        int stored = 0;
 | 
			
		||||
 | 
			
		||||
        if (addr == env->reserve_addr) {
 | 
			
		||||
            switch (size) {
 | 
			
		||||
            case 1: segv = get_user_u8(val, addr); break;
 | 
			
		||||
            case 2: segv = get_user_u16(val, addr); break;
 | 
			
		||||
            case 4: segv = get_user_u32(val, addr); break;
 | 
			
		||||
#if defined(TARGET_PPC64)
 | 
			
		||||
            case 8: segv = get_user_u64(val, addr); break;
 | 
			
		||||
#endif
 | 
			
		||||
            default: abort();
 | 
			
		||||
            }
 | 
			
		||||
            if (!segv && val == env->reserve_val) {
 | 
			
		||||
                val = env->gpr[reg];
 | 
			
		||||
                switch (size) {
 | 
			
		||||
                case 1: segv = put_user_u8(val, addr); break;
 | 
			
		||||
                case 2: segv = put_user_u16(val, addr); break;
 | 
			
		||||
                case 4: segv = put_user_u32(val, addr); break;
 | 
			
		||||
#if defined(TARGET_PPC64)
 | 
			
		||||
                case 8: segv = put_user_u64(val, addr); break;
 | 
			
		||||
#endif
 | 
			
		||||
                default: abort();
 | 
			
		||||
                }
 | 
			
		||||
                if (!segv) {
 | 
			
		||||
                    stored = 1;
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
        env->crf[0] = (stored << 1) | xer_so;
 | 
			
		||||
        env->reserve_addr = (target_ulong)-1;
 | 
			
		||||
    }
 | 
			
		||||
    if (!segv) {
 | 
			
		||||
        env->nip += 4;
 | 
			
		||||
    }
 | 
			
		||||
    mmap_unlock();
 | 
			
		||||
    end_exclusive();
 | 
			
		||||
    return segv;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void cpu_loop(CPUPPCState *env)
 | 
			
		||||
{
 | 
			
		||||
    target_siginfo_t info;
 | 
			
		||||
| 
						 | 
				
			
			@ -1067,7 +1124,9 @@ void cpu_loop(CPUPPCState *env)
 | 
			
		|||
    uint32_t ret;
 | 
			
		||||
 | 
			
		||||
    for(;;) {
 | 
			
		||||
        cpu_exec_start(env);
 | 
			
		||||
        trapnr = cpu_ppc_exec(env);
 | 
			
		||||
        cpu_exec_end(env);
 | 
			
		||||
        switch(trapnr) {
 | 
			
		||||
        case POWERPC_EXCP_NONE:
 | 
			
		||||
            /* Just go on */
 | 
			
		||||
| 
						 | 
				
			
			@ -1447,6 +1506,15 @@ void cpu_loop(CPUPPCState *env)
 | 
			
		|||
            printf("syscall returned 0x%08x (%d)\n", ret, ret);
 | 
			
		||||
#endif
 | 
			
		||||
            break;
 | 
			
		||||
        case POWERPC_EXCP_STCX:
 | 
			
		||||
            if (do_store_exclusive(env)) {
 | 
			
		||||
                info.si_signo = TARGET_SIGSEGV;
 | 
			
		||||
                info.si_errno = 0;
 | 
			
		||||
                info.si_code = TARGET_SEGV_MAPERR;
 | 
			
		||||
                info._sifields._sigfault._addr = env->nip;
 | 
			
		||||
                queue_signal(env, info.si_signo, &info);
 | 
			
		||||
            }
 | 
			
		||||
            break;
 | 
			
		||||
        case EXCP_DEBUG:
 | 
			
		||||
            {
 | 
			
		||||
                int sig;
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
		Loading…
	
		Reference in New Issue