qemu/linux-user/xtensa/cpu_loop.c
<<
>>
Prefs
   1/*
   2 *  qemu user cpu loop
   3 *
   4 *  Copyright (c) 2003-2008 Fabrice Bellard
   5 *
   6 *  This program is free software; you can redistribute it and/or modify
   7 *  it under the terms of the GNU General Public License as published by
   8 *  the Free Software Foundation; either version 2 of the License, or
   9 *  (at your option) any later version.
  10 *
  11 *  This program is distributed in the hope that it will be useful,
  12 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
  13 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  14 *  GNU General Public License for more details.
  15 *
  16 *  You should have received a copy of the GNU General Public License
  17 *  along with this program; if not, see <http://www.gnu.org/licenses/>.
  18 */
  19
  20#include "qemu/osdep.h"
  21#include "qemu.h"
  22#include "cpu_loop-common.h"
  23
  24static void xtensa_rfw(CPUXtensaState *env)
  25{
  26    xtensa_restore_owb(env);
  27    env->pc = env->sregs[EPC1];
  28}
  29
  30static void xtensa_rfwu(CPUXtensaState *env)
  31{
  32    env->sregs[WINDOW_START] |= (1 << env->sregs[WINDOW_BASE]);
  33    xtensa_rfw(env);
  34}
  35
  36static void xtensa_rfwo(CPUXtensaState *env)
  37{
  38    env->sregs[WINDOW_START] &= ~(1 << env->sregs[WINDOW_BASE]);
  39    xtensa_rfw(env);
  40}
  41
  42static void xtensa_overflow4(CPUXtensaState *env)
  43{
  44    put_user_ual(env->regs[0], env->regs[5] - 16);
  45    put_user_ual(env->regs[1], env->regs[5] - 12);
  46    put_user_ual(env->regs[2], env->regs[5] -  8);
  47    put_user_ual(env->regs[3], env->regs[5] -  4);
  48    xtensa_rfwo(env);
  49}
  50
  51static void xtensa_underflow4(CPUXtensaState *env)
  52{
  53    get_user_ual(env->regs[0], env->regs[5] - 16);
  54    get_user_ual(env->regs[1], env->regs[5] - 12);
  55    get_user_ual(env->regs[2], env->regs[5] -  8);
  56    get_user_ual(env->regs[3], env->regs[5] -  4);
  57    xtensa_rfwu(env);
  58}
  59
  60static void xtensa_overflow8(CPUXtensaState *env)
  61{
  62    put_user_ual(env->regs[0], env->regs[9] - 16);
  63    get_user_ual(env->regs[0], env->regs[1] - 12);
  64    put_user_ual(env->regs[1], env->regs[9] - 12);
  65    put_user_ual(env->regs[2], env->regs[9] -  8);
  66    put_user_ual(env->regs[3], env->regs[9] -  4);
  67    put_user_ual(env->regs[4], env->regs[0] - 32);
  68    put_user_ual(env->regs[5], env->regs[0] - 28);
  69    put_user_ual(env->regs[6], env->regs[0] - 24);
  70    put_user_ual(env->regs[7], env->regs[0] - 20);
  71    xtensa_rfwo(env);
  72}
  73
  74static void xtensa_underflow8(CPUXtensaState *env)
  75{
  76    get_user_ual(env->regs[0], env->regs[9] - 16);
  77    get_user_ual(env->regs[1], env->regs[9] - 12);
  78    get_user_ual(env->regs[2], env->regs[9] -  8);
  79    get_user_ual(env->regs[7], env->regs[1] - 12);
  80    get_user_ual(env->regs[3], env->regs[9] -  4);
  81    get_user_ual(env->regs[4], env->regs[7] - 32);
  82    get_user_ual(env->regs[5], env->regs[7] - 28);
  83    get_user_ual(env->regs[6], env->regs[7] - 24);
  84    get_user_ual(env->regs[7], env->regs[7] - 20);
  85    xtensa_rfwu(env);
  86}
  87
  88static void xtensa_overflow12(CPUXtensaState *env)
  89{
  90    put_user_ual(env->regs[0],  env->regs[13] - 16);
  91    get_user_ual(env->regs[0],  env->regs[1]  - 12);
  92    put_user_ual(env->regs[1],  env->regs[13] - 12);
  93    put_user_ual(env->regs[2],  env->regs[13] -  8);
  94    put_user_ual(env->regs[3],  env->regs[13] -  4);
  95    put_user_ual(env->regs[4],  env->regs[0]  - 48);
  96    put_user_ual(env->regs[5],  env->regs[0]  - 44);
  97    put_user_ual(env->regs[6],  env->regs[0]  - 40);
  98    put_user_ual(env->regs[7],  env->regs[0]  - 36);
  99    put_user_ual(env->regs[8],  env->regs[0]  - 32);
 100    put_user_ual(env->regs[9],  env->regs[0]  - 28);
 101    put_user_ual(env->regs[10], env->regs[0]  - 24);
 102    put_user_ual(env->regs[11], env->regs[0]  - 20);
 103    xtensa_rfwo(env);
 104}
 105
 106static void xtensa_underflow12(CPUXtensaState *env)
 107{
 108    get_user_ual(env->regs[0],  env->regs[13] - 16);
 109    get_user_ual(env->regs[1],  env->regs[13] - 12);
 110    get_user_ual(env->regs[2],  env->regs[13] -  8);
 111    get_user_ual(env->regs[11], env->regs[1]  - 12);
 112    get_user_ual(env->regs[3],  env->regs[13] -  4);
 113    get_user_ual(env->regs[4],  env->regs[11] - 48);
 114    get_user_ual(env->regs[5],  env->regs[11] - 44);
 115    get_user_ual(env->regs[6],  env->regs[11] - 40);
 116    get_user_ual(env->regs[7],  env->regs[11] - 36);
 117    get_user_ual(env->regs[8],  env->regs[11] - 32);
 118    get_user_ual(env->regs[9],  env->regs[11] - 28);
 119    get_user_ual(env->regs[10], env->regs[11] - 24);
 120    get_user_ual(env->regs[11], env->regs[11] - 20);
 121    xtensa_rfwu(env);
 122}
 123
 124void cpu_loop(CPUXtensaState *env)
 125{
 126    CPUState *cs = env_cpu(env);
 127    target_siginfo_t info;
 128    abi_ulong ret;
 129    int trapnr;
 130
 131    while (1) {
 132        cpu_exec_start(cs);
 133        trapnr = cpu_exec(cs);
 134        cpu_exec_end(cs);
 135        process_queued_cpu_work(cs);
 136
 137        env->sregs[PS] &= ~PS_EXCM;
 138        switch (trapnr) {
 139        case EXCP_INTERRUPT:
 140            break;
 141
 142        case EXC_WINDOW_OVERFLOW4:
 143            xtensa_overflow4(env);
 144            break;
 145        case EXC_WINDOW_UNDERFLOW4:
 146            xtensa_underflow4(env);
 147            break;
 148        case EXC_WINDOW_OVERFLOW8:
 149            xtensa_overflow8(env);
 150            break;
 151        case EXC_WINDOW_UNDERFLOW8:
 152            xtensa_underflow8(env);
 153            break;
 154        case EXC_WINDOW_OVERFLOW12:
 155            xtensa_overflow12(env);
 156            break;
 157        case EXC_WINDOW_UNDERFLOW12:
 158            xtensa_underflow12(env);
 159            break;
 160
 161        case EXC_USER:
 162            switch (env->sregs[EXCCAUSE]) {
 163            case ILLEGAL_INSTRUCTION_CAUSE:
 164            case PRIVILEGED_CAUSE:
 165                info.si_signo = TARGET_SIGILL;
 166                info.si_errno = 0;
 167                info.si_code =
 168                    env->sregs[EXCCAUSE] == ILLEGAL_INSTRUCTION_CAUSE ?
 169                    TARGET_ILL_ILLOPC : TARGET_ILL_PRVOPC;
 170                info._sifields._sigfault._addr = env->sregs[EPC1];
 171                queue_signal(env, info.si_signo, QEMU_SI_FAULT, &info);
 172                break;
 173
 174            case SYSCALL_CAUSE:
 175                env->pc += 3;
 176                ret = do_syscall(env, env->regs[2],
 177                                 env->regs[6], env->regs[3],
 178                                 env->regs[4], env->regs[5],
 179                                 env->regs[8], env->regs[9], 0, 0);
 180                switch (ret) {
 181                default:
 182                    env->regs[2] = ret;
 183                    break;
 184
 185                case -TARGET_ERESTARTSYS:
 186                    env->pc -= 3;
 187                    break;
 188
 189                case -TARGET_QEMU_ESIGRETURN:
 190                    break;
 191                }
 192                break;
 193
 194            case ALLOCA_CAUSE:
 195                env->sregs[PS] = deposit32(env->sregs[PS],
 196                                           PS_OWB_SHIFT,
 197                                           PS_OWB_LEN,
 198                                           env->sregs[WINDOW_BASE]);
 199
 200                switch (env->regs[0] & 0xc0000000) {
 201                case 0x00000000:
 202                case 0x40000000:
 203                    xtensa_rotate_window(env, -1);
 204                    xtensa_underflow4(env);
 205                    break;
 206
 207                case 0x80000000:
 208                    xtensa_rotate_window(env, -2);
 209                    xtensa_underflow8(env);
 210                    break;
 211
 212                case 0xc0000000:
 213                    xtensa_rotate_window(env, -3);
 214                    xtensa_underflow12(env);
 215                    break;
 216                }
 217                break;
 218
 219            case INTEGER_DIVIDE_BY_ZERO_CAUSE:
 220                info.si_signo = TARGET_SIGFPE;
 221                info.si_errno = 0;
 222                info.si_code = TARGET_FPE_INTDIV;
 223                info._sifields._sigfault._addr = env->sregs[EPC1];
 224                queue_signal(env, info.si_signo, QEMU_SI_FAULT, &info);
 225                break;
 226
 227            case LOAD_PROHIBITED_CAUSE:
 228            case STORE_PROHIBITED_CAUSE:
 229                info.si_signo = TARGET_SIGSEGV;
 230                info.si_errno = 0;
 231                info.si_code = TARGET_SEGV_ACCERR;
 232                info._sifields._sigfault._addr = env->sregs[EXCVADDR];
 233                queue_signal(env, info.si_signo, QEMU_SI_FAULT, &info);
 234                break;
 235
 236            default:
 237                fprintf(stderr, "exccause = %d\n", env->sregs[EXCCAUSE]);
 238                g_assert_not_reached();
 239            }
 240            break;
 241        case EXCP_DEBUG:
 242            info.si_signo = TARGET_SIGTRAP;
 243            info.si_errno = 0;
 244            info.si_code = TARGET_TRAP_BRKPT;
 245            queue_signal(env, info.si_signo, QEMU_SI_FAULT, &info);
 246            break;
 247        case EXC_DEBUG:
 248        default:
 249            fprintf(stderr, "trapnr = %d\n", trapnr);
 250            g_assert_not_reached();
 251        }
 252        process_pending_signals(env);
 253    }
 254}
 255
 256void target_cpu_copy_regs(CPUArchState *env, struct target_pt_regs *regs)
 257{
 258    int i;
 259    for (i = 0; i < 16; ++i) {
 260        env->regs[i] = regs->areg[i];
 261    }
 262    env->sregs[WINDOW_START] = regs->windowstart;
 263    env->pc = regs->pc;
 264}
 265