qemu/linux-user/hppa/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 abi_ulong hppa_lws(CPUHPPAState *env)
  25{
  26    uint32_t which = env->gr[20];
  27    abi_ulong addr = env->gr[26];
  28    abi_ulong old = env->gr[25];
  29    abi_ulong new = env->gr[24];
  30    abi_ulong size, ret;
  31
  32    switch (which) {
  33    default:
  34        return -TARGET_ENOSYS;
  35
  36    case 0: /* elf32 atomic 32bit cmpxchg */
  37        if ((addr & 3) || !access_ok(VERIFY_WRITE, addr, 4)) {
  38            return -TARGET_EFAULT;
  39        }
  40        old = tswap32(old);
  41        new = tswap32(new);
  42        ret = atomic_cmpxchg((uint32_t *)g2h(addr), old, new);
  43        ret = tswap32(ret);
  44        break;
  45
  46    case 2: /* elf32 atomic "new" cmpxchg */
  47        size = env->gr[23];
  48        if (size >= 4) {
  49            return -TARGET_ENOSYS;
  50        }
  51        if (((addr | old | new) & ((1 << size) - 1))
  52            || !access_ok(VERIFY_WRITE, addr, 1 << size)
  53            || !access_ok(VERIFY_READ, old, 1 << size)
  54            || !access_ok(VERIFY_READ, new, 1 << size)) {
  55            return -TARGET_EFAULT;
  56        }
  57        /* Note that below we use host-endian loads so that the cmpxchg
  58           can be host-endian as well.  */
  59        switch (size) {
  60        case 0:
  61            old = *(uint8_t *)g2h(old);
  62            new = *(uint8_t *)g2h(new);
  63            ret = atomic_cmpxchg((uint8_t *)g2h(addr), old, new);
  64            ret = ret != old;
  65            break;
  66        case 1:
  67            old = *(uint16_t *)g2h(old);
  68            new = *(uint16_t *)g2h(new);
  69            ret = atomic_cmpxchg((uint16_t *)g2h(addr), old, new);
  70            ret = ret != old;
  71            break;
  72        case 2:
  73            old = *(uint32_t *)g2h(old);
  74            new = *(uint32_t *)g2h(new);
  75            ret = atomic_cmpxchg((uint32_t *)g2h(addr), old, new);
  76            ret = ret != old;
  77            break;
  78        case 3:
  79            {
  80                uint64_t o64, n64, r64;
  81                o64 = *(uint64_t *)g2h(old);
  82                n64 = *(uint64_t *)g2h(new);
  83#ifdef CONFIG_ATOMIC64
  84                r64 = atomic_cmpxchg__nocheck((uint64_t *)g2h(addr), o64, n64);
  85                ret = r64 != o64;
  86#else
  87                start_exclusive();
  88                r64 = *(uint64_t *)g2h(addr);
  89                ret = 1;
  90                if (r64 == o64) {
  91                    *(uint64_t *)g2h(addr) = n64;
  92                    ret = 0;
  93                }
  94                end_exclusive();
  95#endif
  96            }
  97            break;
  98        }
  99        break;
 100    }
 101
 102    env->gr[28] = ret;
 103    return 0;
 104}
 105
 106void cpu_loop(CPUHPPAState *env)
 107{
 108    CPUState *cs = env_cpu(env);
 109    target_siginfo_t info;
 110    abi_ulong ret;
 111    int trapnr;
 112
 113    while (1) {
 114        cpu_exec_start(cs);
 115        trapnr = cpu_exec(cs);
 116        cpu_exec_end(cs);
 117        process_queued_cpu_work(cs);
 118
 119        switch (trapnr) {
 120        case EXCP_SYSCALL:
 121            ret = do_syscall(env, env->gr[20],
 122                             env->gr[26], env->gr[25],
 123                             env->gr[24], env->gr[23],
 124                             env->gr[22], env->gr[21], 0, 0);
 125            switch (ret) {
 126            default:
 127                env->gr[28] = ret;
 128                /* We arrived here by faking the gateway page.  Return.  */
 129                env->iaoq_f = env->gr[31];
 130                env->iaoq_b = env->gr[31] + 4;
 131                break;
 132            case -TARGET_ERESTARTSYS:
 133            case -TARGET_QEMU_ESIGRETURN:
 134                break;
 135            }
 136            break;
 137        case EXCP_SYSCALL_LWS:
 138            env->gr[21] = hppa_lws(env);
 139            /* We arrived here by faking the gateway page.  Return.  */
 140            env->iaoq_f = env->gr[31];
 141            env->iaoq_b = env->gr[31] + 4;
 142            break;
 143        case EXCP_ITLB_MISS:
 144        case EXCP_DTLB_MISS:
 145        case EXCP_NA_ITLB_MISS:
 146        case EXCP_NA_DTLB_MISS:
 147        case EXCP_IMP:
 148        case EXCP_DMP:
 149        case EXCP_DMB:
 150        case EXCP_PAGE_REF:
 151        case EXCP_DMAR:
 152        case EXCP_DMPI:
 153            info.si_signo = TARGET_SIGSEGV;
 154            info.si_errno = 0;
 155            info.si_code = TARGET_SEGV_ACCERR;
 156            info._sifields._sigfault._addr = env->cr[CR_IOR];
 157            queue_signal(env, info.si_signo, QEMU_SI_FAULT, &info);
 158            break;
 159        case EXCP_UNALIGN:
 160            info.si_signo = TARGET_SIGBUS;
 161            info.si_errno = 0;
 162            info.si_code = 0;
 163            info._sifields._sigfault._addr = env->cr[CR_IOR];
 164            queue_signal(env, info.si_signo, QEMU_SI_FAULT, &info);
 165            break;
 166        case EXCP_ILL:
 167        case EXCP_PRIV_OPR:
 168        case EXCP_PRIV_REG:
 169            info.si_signo = TARGET_SIGILL;
 170            info.si_errno = 0;
 171            info.si_code = TARGET_ILL_ILLOPN;
 172            info._sifields._sigfault._addr = env->iaoq_f;
 173            queue_signal(env, info.si_signo, QEMU_SI_FAULT, &info);
 174            break;
 175        case EXCP_OVERFLOW:
 176        case EXCP_COND:
 177        case EXCP_ASSIST:
 178            info.si_signo = TARGET_SIGFPE;
 179            info.si_errno = 0;
 180            info.si_code = 0;
 181            info._sifields._sigfault._addr = env->iaoq_f;
 182            queue_signal(env, info.si_signo, QEMU_SI_FAULT, &info);
 183            break;
 184        case EXCP_DEBUG:
 185            info.si_signo = TARGET_SIGTRAP;
 186            info.si_errno = 0;
 187            info.si_code = TARGET_TRAP_BRKPT;
 188            queue_signal(env, info.si_signo, QEMU_SI_FAULT, &info);
 189            break;
 190        case EXCP_INTERRUPT:
 191            /* just indicate that signals should be handled asap */
 192            break;
 193        default:
 194            g_assert_not_reached();
 195        }
 196        process_pending_signals(env);
 197    }
 198}
 199
 200void target_cpu_copy_regs(CPUArchState *env, struct target_pt_regs *regs)
 201{
 202    int i;
 203    for (i = 1; i < 32; i++) {
 204        env->gr[i] = regs->gr[i];
 205    }
 206    env->iaoq_f = regs->iaoq[0];
 207    env->iaoq_b = regs->iaoq[1];
 208}
 209