 de6e89b81f
			
		
	
	
		de6e89b81f
		
	
	
	
	
		
			
			No code change, only move code from main.c to xtensa/cpu_loop.c. Signed-off-by: Laurent Vivier <laurent@vivier.eu> Reviewed-by: Richard Henderson <richard.henderson@linaro.org> Message-Id: <20180411185651.21351-20-laurent@vivier.eu>
		
			
				
	
	
		
			268 lines
		
	
	
		
			8.8 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
			
		
		
	
	
			268 lines
		
	
	
		
			8.8 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
| /*
 | |
|  *  qemu user cpu loop
 | |
|  *
 | |
|  *  Copyright (c) 2003-2008 Fabrice Bellard
 | |
|  *
 | |
|  *  This program is free software; you can redistribute it and/or modify
 | |
|  *  it under the terms of the GNU General Public License as published by
 | |
|  *  the Free Software Foundation; either version 2 of the License, or
 | |
|  *  (at your option) any later version.
 | |
|  *
 | |
|  *  This program is distributed in the hope that it will be useful,
 | |
|  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
 | |
|  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 | |
|  *  GNU General Public License for more details.
 | |
|  *
 | |
|  *  You should have received a copy of the GNU General Public License
 | |
|  *  along with this program; if not, see <http://www.gnu.org/licenses/>.
 | |
|  */
 | |
| 
 | |
| #include "qemu/osdep.h"
 | |
| #include "qemu.h"
 | |
| #include "cpu_loop-common.h"
 | |
| 
 | |
| static void xtensa_rfw(CPUXtensaState *env)
 | |
| {
 | |
|     xtensa_restore_owb(env);
 | |
|     env->pc = env->sregs[EPC1];
 | |
| }
 | |
| 
 | |
| static void xtensa_rfwu(CPUXtensaState *env)
 | |
| {
 | |
|     env->sregs[WINDOW_START] |= (1 << env->sregs[WINDOW_BASE]);
 | |
|     xtensa_rfw(env);
 | |
| }
 | |
| 
 | |
| static void xtensa_rfwo(CPUXtensaState *env)
 | |
| {
 | |
|     env->sregs[WINDOW_START] &= ~(1 << env->sregs[WINDOW_BASE]);
 | |
|     xtensa_rfw(env);
 | |
| }
 | |
| 
 | |
| static void xtensa_overflow4(CPUXtensaState *env)
 | |
| {
 | |
|     put_user_ual(env->regs[0], env->regs[5] - 16);
 | |
|     put_user_ual(env->regs[1], env->regs[5] - 12);
 | |
|     put_user_ual(env->regs[2], env->regs[5] -  8);
 | |
|     put_user_ual(env->regs[3], env->regs[5] -  4);
 | |
|     xtensa_rfwo(env);
 | |
| }
 | |
| 
 | |
| static void xtensa_underflow4(CPUXtensaState *env)
 | |
| {
 | |
|     get_user_ual(env->regs[0], env->regs[5] - 16);
 | |
|     get_user_ual(env->regs[1], env->regs[5] - 12);
 | |
|     get_user_ual(env->regs[2], env->regs[5] -  8);
 | |
|     get_user_ual(env->regs[3], env->regs[5] -  4);
 | |
|     xtensa_rfwu(env);
 | |
| }
 | |
| 
 | |
| static void xtensa_overflow8(CPUXtensaState *env)
 | |
| {
 | |
|     put_user_ual(env->regs[0], env->regs[9] - 16);
 | |
|     get_user_ual(env->regs[0], env->regs[1] - 12);
 | |
|     put_user_ual(env->regs[1], env->regs[9] - 12);
 | |
|     put_user_ual(env->regs[2], env->regs[9] -  8);
 | |
|     put_user_ual(env->regs[3], env->regs[9] -  4);
 | |
|     put_user_ual(env->regs[4], env->regs[0] - 32);
 | |
|     put_user_ual(env->regs[5], env->regs[0] - 28);
 | |
|     put_user_ual(env->regs[6], env->regs[0] - 24);
 | |
|     put_user_ual(env->regs[7], env->regs[0] - 20);
 | |
|     xtensa_rfwo(env);
 | |
| }
 | |
| 
 | |
| static void xtensa_underflow8(CPUXtensaState *env)
 | |
| {
 | |
|     get_user_ual(env->regs[0], env->regs[9] - 16);
 | |
|     get_user_ual(env->regs[1], env->regs[9] - 12);
 | |
|     get_user_ual(env->regs[2], env->regs[9] -  8);
 | |
|     get_user_ual(env->regs[7], env->regs[1] - 12);
 | |
|     get_user_ual(env->regs[3], env->regs[9] -  4);
 | |
|     get_user_ual(env->regs[4], env->regs[7] - 32);
 | |
|     get_user_ual(env->regs[5], env->regs[7] - 28);
 | |
|     get_user_ual(env->regs[6], env->regs[7] - 24);
 | |
|     get_user_ual(env->regs[7], env->regs[7] - 20);
 | |
|     xtensa_rfwu(env);
 | |
| }
 | |
| 
 | |
| static void xtensa_overflow12(CPUXtensaState *env)
 | |
| {
 | |
|     put_user_ual(env->regs[0],  env->regs[13] - 16);
 | |
|     get_user_ual(env->regs[0],  env->regs[1]  - 12);
 | |
|     put_user_ual(env->regs[1],  env->regs[13] - 12);
 | |
|     put_user_ual(env->regs[2],  env->regs[13] -  8);
 | |
|     put_user_ual(env->regs[3],  env->regs[13] -  4);
 | |
|     put_user_ual(env->regs[4],  env->regs[0]  - 48);
 | |
|     put_user_ual(env->regs[5],  env->regs[0]  - 44);
 | |
|     put_user_ual(env->regs[6],  env->regs[0]  - 40);
 | |
|     put_user_ual(env->regs[7],  env->regs[0]  - 36);
 | |
|     put_user_ual(env->regs[8],  env->regs[0]  - 32);
 | |
|     put_user_ual(env->regs[9],  env->regs[0]  - 28);
 | |
|     put_user_ual(env->regs[10], env->regs[0]  - 24);
 | |
|     put_user_ual(env->regs[11], env->regs[0]  - 20);
 | |
|     xtensa_rfwo(env);
 | |
| }
 | |
| 
 | |
| static void xtensa_underflow12(CPUXtensaState *env)
 | |
| {
 | |
|     get_user_ual(env->regs[0],  env->regs[13] - 16);
 | |
|     get_user_ual(env->regs[1],  env->regs[13] - 12);
 | |
|     get_user_ual(env->regs[2],  env->regs[13] -  8);
 | |
|     get_user_ual(env->regs[11], env->regs[1]  - 12);
 | |
|     get_user_ual(env->regs[3],  env->regs[13] -  4);
 | |
|     get_user_ual(env->regs[4],  env->regs[11] - 48);
 | |
|     get_user_ual(env->regs[5],  env->regs[11] - 44);
 | |
|     get_user_ual(env->regs[6],  env->regs[11] - 40);
 | |
|     get_user_ual(env->regs[7],  env->regs[11] - 36);
 | |
|     get_user_ual(env->regs[8],  env->regs[11] - 32);
 | |
|     get_user_ual(env->regs[9],  env->regs[11] - 28);
 | |
|     get_user_ual(env->regs[10], env->regs[11] - 24);
 | |
|     get_user_ual(env->regs[11], env->regs[11] - 20);
 | |
|     xtensa_rfwu(env);
 | |
| }
 | |
| 
 | |
| void cpu_loop(CPUXtensaState *env)
 | |
| {
 | |
|     CPUState *cs = CPU(xtensa_env_get_cpu(env));
 | |
|     target_siginfo_t info;
 | |
|     abi_ulong ret;
 | |
|     int trapnr;
 | |
| 
 | |
|     while (1) {
 | |
|         cpu_exec_start(cs);
 | |
|         trapnr = cpu_exec(cs);
 | |
|         cpu_exec_end(cs);
 | |
|         process_queued_cpu_work(cs);
 | |
| 
 | |
|         env->sregs[PS] &= ~PS_EXCM;
 | |
|         switch (trapnr) {
 | |
|         case EXCP_INTERRUPT:
 | |
|             break;
 | |
| 
 | |
|         case EXC_WINDOW_OVERFLOW4:
 | |
|             xtensa_overflow4(env);
 | |
|             break;
 | |
|         case EXC_WINDOW_UNDERFLOW4:
 | |
|             xtensa_underflow4(env);
 | |
|             break;
 | |
|         case EXC_WINDOW_OVERFLOW8:
 | |
|             xtensa_overflow8(env);
 | |
|             break;
 | |
|         case EXC_WINDOW_UNDERFLOW8:
 | |
|             xtensa_underflow8(env);
 | |
|             break;
 | |
|         case EXC_WINDOW_OVERFLOW12:
 | |
|             xtensa_overflow12(env);
 | |
|             break;
 | |
|         case EXC_WINDOW_UNDERFLOW12:
 | |
|             xtensa_underflow12(env);
 | |
|             break;
 | |
| 
 | |
|         case EXC_USER:
 | |
|             switch (env->sregs[EXCCAUSE]) {
 | |
|             case ILLEGAL_INSTRUCTION_CAUSE:
 | |
|             case PRIVILEGED_CAUSE:
 | |
|                 info.si_signo = TARGET_SIGILL;
 | |
|                 info.si_errno = 0;
 | |
|                 info.si_code =
 | |
|                     env->sregs[EXCCAUSE] == ILLEGAL_INSTRUCTION_CAUSE ?
 | |
|                     TARGET_ILL_ILLOPC : TARGET_ILL_PRVOPC;
 | |
|                 info._sifields._sigfault._addr = env->sregs[EPC1];
 | |
|                 queue_signal(env, info.si_signo, QEMU_SI_FAULT, &info);
 | |
|                 break;
 | |
| 
 | |
|             case SYSCALL_CAUSE:
 | |
|                 env->pc += 3;
 | |
|                 ret = do_syscall(env, env->regs[2],
 | |
|                                  env->regs[6], env->regs[3],
 | |
|                                  env->regs[4], env->regs[5],
 | |
|                                  env->regs[8], env->regs[9], 0, 0);
 | |
|                 switch (ret) {
 | |
|                 default:
 | |
|                     env->regs[2] = ret;
 | |
|                     break;
 | |
| 
 | |
|                 case -TARGET_ERESTARTSYS:
 | |
|                     env->pc -= 3;
 | |
|                     break;
 | |
| 
 | |
|                 case -TARGET_QEMU_ESIGRETURN:
 | |
|                     break;
 | |
|                 }
 | |
|                 break;
 | |
| 
 | |
|             case ALLOCA_CAUSE:
 | |
|                 env->sregs[PS] = deposit32(env->sregs[PS],
 | |
|                                            PS_OWB_SHIFT,
 | |
|                                            PS_OWB_LEN,
 | |
|                                            env->sregs[WINDOW_BASE]);
 | |
| 
 | |
|                 switch (env->regs[0] & 0xc0000000) {
 | |
|                 case 0x00000000:
 | |
|                 case 0x40000000:
 | |
|                     xtensa_rotate_window(env, -1);
 | |
|                     xtensa_underflow4(env);
 | |
|                     break;
 | |
| 
 | |
|                 case 0x80000000:
 | |
|                     xtensa_rotate_window(env, -2);
 | |
|                     xtensa_underflow8(env);
 | |
|                     break;
 | |
| 
 | |
|                 case 0xc0000000:
 | |
|                     xtensa_rotate_window(env, -3);
 | |
|                     xtensa_underflow12(env);
 | |
|                     break;
 | |
|                 }
 | |
|                 break;
 | |
| 
 | |
|             case INTEGER_DIVIDE_BY_ZERO_CAUSE:
 | |
|                 info.si_signo = TARGET_SIGFPE;
 | |
|                 info.si_errno = 0;
 | |
|                 info.si_code = TARGET_FPE_INTDIV;
 | |
|                 info._sifields._sigfault._addr = env->sregs[EPC1];
 | |
|                 queue_signal(env, info.si_signo, QEMU_SI_FAULT, &info);
 | |
|                 break;
 | |
| 
 | |
|             case LOAD_PROHIBITED_CAUSE:
 | |
|             case STORE_PROHIBITED_CAUSE:
 | |
|                 info.si_signo = TARGET_SIGSEGV;
 | |
|                 info.si_errno = 0;
 | |
|                 info.si_code = TARGET_SEGV_ACCERR;
 | |
|                 info._sifields._sigfault._addr = env->sregs[EXCVADDR];
 | |
|                 queue_signal(env, info.si_signo, QEMU_SI_FAULT, &info);
 | |
|                 break;
 | |
| 
 | |
|             default:
 | |
|                 fprintf(stderr, "exccause = %d\n", env->sregs[EXCCAUSE]);
 | |
|                 g_assert_not_reached();
 | |
|             }
 | |
|             break;
 | |
|         case EXCP_DEBUG:
 | |
|             trapnr = gdb_handlesig(cs, TARGET_SIGTRAP);
 | |
|             if (trapnr) {
 | |
|                 info.si_signo = trapnr;
 | |
|                 info.si_errno = 0;
 | |
|                 info.si_code = TARGET_TRAP_BRKPT;
 | |
|                 queue_signal(env, trapnr, QEMU_SI_FAULT, &info);
 | |
|             }
 | |
|             break;
 | |
|         case EXC_DEBUG:
 | |
|         default:
 | |
|             fprintf(stderr, "trapnr = %d\n", trapnr);
 | |
|             g_assert_not_reached();
 | |
|         }
 | |
|         process_pending_signals(env);
 | |
|     }
 | |
| }
 | |
| 
 | |
| void target_cpu_copy_regs(CPUArchState *env, struct target_pt_regs *regs)
 | |
| {
 | |
|     int i;
 | |
|     for (i = 0; i < 16; ++i) {
 | |
|         env->regs[i] = regs->areg[i];
 | |
|     }
 | |
|     env->sregs[WINDOW_START] = regs->windowstart;
 | |
|     env->pc = regs->pc;
 | |
| }
 |