xref: /openbmc/qemu/linux-user/hppa/cpu_loop.c (revision 423be09ab9492735924e73a2d36069784441ebc6)
1cd71c089SLaurent Vivier /*
2cd71c089SLaurent Vivier  *  qemu user cpu loop
3cd71c089SLaurent Vivier  *
4cd71c089SLaurent Vivier  *  Copyright (c) 2003-2008 Fabrice Bellard
5cd71c089SLaurent Vivier  *
6cd71c089SLaurent Vivier  *  This program is free software; you can redistribute it and/or modify
7cd71c089SLaurent Vivier  *  it under the terms of the GNU General Public License as published by
8cd71c089SLaurent Vivier  *  the Free Software Foundation; either version 2 of the License, or
9cd71c089SLaurent Vivier  *  (at your option) any later version.
10cd71c089SLaurent Vivier  *
11cd71c089SLaurent Vivier  *  This program is distributed in the hope that it will be useful,
12cd71c089SLaurent Vivier  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
13cd71c089SLaurent Vivier  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14cd71c089SLaurent Vivier  *  GNU General Public License for more details.
15cd71c089SLaurent Vivier  *
16cd71c089SLaurent Vivier  *  You should have received a copy of the GNU General Public License
17cd71c089SLaurent Vivier  *  along with this program; if not, see <http://www.gnu.org/licenses/>.
18cd71c089SLaurent Vivier  */
19cd71c089SLaurent Vivier 
20cd71c089SLaurent Vivier #include "qemu/osdep.h"
21cd71c089SLaurent Vivier #include "qemu.h"
223b249d26SPeter Maydell #include "user-internals.h"
23cd71c089SLaurent Vivier #include "cpu_loop-common.h"
242113aed6SPeter Maydell #include "signal-common.h"
25cd71c089SLaurent Vivier 
hppa_lws(CPUHPPAState * env)261d8d0b4eSLaurent Vivier static abi_ulong hppa_lws(CPUHPPAState *env)
271d8d0b4eSLaurent Vivier {
283e8f1628SRichard Henderson     CPUState *cs = env_cpu(env);
291d8d0b4eSLaurent Vivier     uint32_t which = env->gr[20];
301d8d0b4eSLaurent Vivier     abi_ulong addr = env->gr[26];
311d8d0b4eSLaurent Vivier     abi_ulong old = env->gr[25];
321d8d0b4eSLaurent Vivier     abi_ulong new = env->gr[24];
331d8d0b4eSLaurent Vivier     abi_ulong size, ret;
341d8d0b4eSLaurent Vivier 
351d8d0b4eSLaurent Vivier     switch (which) {
361d8d0b4eSLaurent Vivier     default:
371d8d0b4eSLaurent Vivier         return -TARGET_ENOSYS;
381d8d0b4eSLaurent Vivier 
391d8d0b4eSLaurent Vivier     case 0: /* elf32 atomic 32bit cmpxchg */
40c7169b02SRichard Henderson         if ((addr & 3) || !access_ok(cs, VERIFY_WRITE, addr, 4)) {
411d8d0b4eSLaurent Vivier             return -TARGET_EFAULT;
421d8d0b4eSLaurent Vivier         }
431d8d0b4eSLaurent Vivier         old = tswap32(old);
441d8d0b4eSLaurent Vivier         new = tswap32(new);
453e8f1628SRichard Henderson         ret = qatomic_cmpxchg((uint32_t *)g2h(cs, addr), old, new);
461d8d0b4eSLaurent Vivier         ret = tswap32(ret);
471d8d0b4eSLaurent Vivier         break;
481d8d0b4eSLaurent Vivier 
491d8d0b4eSLaurent Vivier     case 2: /* elf32 atomic "new" cmpxchg */
501d8d0b4eSLaurent Vivier         size = env->gr[23];
511d8d0b4eSLaurent Vivier         if (size >= 4) {
521d8d0b4eSLaurent Vivier             return -TARGET_ENOSYS;
531d8d0b4eSLaurent Vivier         }
541d8d0b4eSLaurent Vivier         if (((addr | old | new) & ((1 << size) - 1))
55c7169b02SRichard Henderson             || !access_ok(cs, VERIFY_WRITE, addr, 1 << size)
56c7169b02SRichard Henderson             || !access_ok(cs, VERIFY_READ, old, 1 << size)
57c7169b02SRichard Henderson             || !access_ok(cs, VERIFY_READ, new, 1 << size)) {
581d8d0b4eSLaurent Vivier             return -TARGET_EFAULT;
591d8d0b4eSLaurent Vivier         }
601d8d0b4eSLaurent Vivier         /* Note that below we use host-endian loads so that the cmpxchg
611d8d0b4eSLaurent Vivier            can be host-endian as well.  */
621d8d0b4eSLaurent Vivier         switch (size) {
631d8d0b4eSLaurent Vivier         case 0:
643e8f1628SRichard Henderson             old = *(uint8_t *)g2h(cs, old);
653e8f1628SRichard Henderson             new = *(uint8_t *)g2h(cs, new);
663e8f1628SRichard Henderson             ret = qatomic_cmpxchg((uint8_t *)g2h(cs, addr), old, new);
671d8d0b4eSLaurent Vivier             ret = ret != old;
681d8d0b4eSLaurent Vivier             break;
691d8d0b4eSLaurent Vivier         case 1:
703e8f1628SRichard Henderson             old = *(uint16_t *)g2h(cs, old);
713e8f1628SRichard Henderson             new = *(uint16_t *)g2h(cs, new);
723e8f1628SRichard Henderson             ret = qatomic_cmpxchg((uint16_t *)g2h(cs, addr), old, new);
731d8d0b4eSLaurent Vivier             ret = ret != old;
741d8d0b4eSLaurent Vivier             break;
751d8d0b4eSLaurent Vivier         case 2:
763e8f1628SRichard Henderson             old = *(uint32_t *)g2h(cs, old);
773e8f1628SRichard Henderson             new = *(uint32_t *)g2h(cs, new);
783e8f1628SRichard Henderson             ret = qatomic_cmpxchg((uint32_t *)g2h(cs, addr), old, new);
791d8d0b4eSLaurent Vivier             ret = ret != old;
801d8d0b4eSLaurent Vivier             break;
811d8d0b4eSLaurent Vivier         case 3:
821d8d0b4eSLaurent Vivier             {
831d8d0b4eSLaurent Vivier                 uint64_t o64, n64, r64;
843e8f1628SRichard Henderson                 o64 = *(uint64_t *)g2h(cs, old);
853e8f1628SRichard Henderson                 n64 = *(uint64_t *)g2h(cs, new);
861d8d0b4eSLaurent Vivier #ifdef CONFIG_ATOMIC64
879ef0c6d6SRichard Henderson                 r64 = qatomic_cmpxchg__nocheck((aligned_uint64_t *)g2h(cs, addr),
88d73415a3SStefan Hajnoczi                                                o64, n64);
891d8d0b4eSLaurent Vivier                 ret = r64 != o64;
901d8d0b4eSLaurent Vivier #else
911d8d0b4eSLaurent Vivier                 start_exclusive();
923e8f1628SRichard Henderson                 r64 = *(uint64_t *)g2h(cs, addr);
931d8d0b4eSLaurent Vivier                 ret = 1;
941d8d0b4eSLaurent Vivier                 if (r64 == o64) {
953e8f1628SRichard Henderson                     *(uint64_t *)g2h(cs, addr) = n64;
961d8d0b4eSLaurent Vivier                     ret = 0;
971d8d0b4eSLaurent Vivier                 }
981d8d0b4eSLaurent Vivier                 end_exclusive();
991d8d0b4eSLaurent Vivier #endif
1001d8d0b4eSLaurent Vivier             }
1011d8d0b4eSLaurent Vivier             break;
102*0d0f95c7SMarc-André Lureau         default:
103*0d0f95c7SMarc-André Lureau             g_assert_not_reached();
1041d8d0b4eSLaurent Vivier         }
1051d8d0b4eSLaurent Vivier         break;
1061d8d0b4eSLaurent Vivier     }
1071d8d0b4eSLaurent Vivier 
1081d8d0b4eSLaurent Vivier     env->gr[28] = ret;
1091d8d0b4eSLaurent Vivier     return 0;
1101d8d0b4eSLaurent Vivier }
1111d8d0b4eSLaurent Vivier 
cpu_loop(CPUHPPAState * env)1121d8d0b4eSLaurent Vivier void cpu_loop(CPUHPPAState *env)
1131d8d0b4eSLaurent Vivier {
11425f32708SRichard Henderson     CPUState *cs = env_cpu(env);
1151d8d0b4eSLaurent Vivier     abi_ulong ret;
1161d8d0b4eSLaurent Vivier     int trapnr;
1171d8d0b4eSLaurent Vivier 
1181d8d0b4eSLaurent Vivier     while (1) {
1191d8d0b4eSLaurent Vivier         cpu_exec_start(cs);
1201d8d0b4eSLaurent Vivier         trapnr = cpu_exec(cs);
1211d8d0b4eSLaurent Vivier         cpu_exec_end(cs);
1221d8d0b4eSLaurent Vivier         process_queued_cpu_work(cs);
1231d8d0b4eSLaurent Vivier 
1241d8d0b4eSLaurent Vivier         switch (trapnr) {
1251d8d0b4eSLaurent Vivier         case EXCP_SYSCALL:
1261d8d0b4eSLaurent Vivier             ret = do_syscall(env, env->gr[20],
1271d8d0b4eSLaurent Vivier                              env->gr[26], env->gr[25],
1281d8d0b4eSLaurent Vivier                              env->gr[24], env->gr[23],
1291d8d0b4eSLaurent Vivier                              env->gr[22], env->gr[21], 0, 0);
1301d8d0b4eSLaurent Vivier             switch (ret) {
1311d8d0b4eSLaurent Vivier             default:
1321d8d0b4eSLaurent Vivier                 env->gr[28] = ret;
1331d8d0b4eSLaurent Vivier                 /* We arrived here by faking the gateway page.  Return.  */
1343c13b0ffSRichard Henderson                 env->iaoq_f = env->gr[31] | PRIV_USER;
1353c13b0ffSRichard Henderson                 env->iaoq_b = env->iaoq_f + 4;
1361d8d0b4eSLaurent Vivier                 break;
137af254a27SRichard Henderson             case -QEMU_ERESTARTSYS:
13857a0c938SRichard Henderson             case -QEMU_ESIGRETURN:
1391d8d0b4eSLaurent Vivier                 break;
1401d8d0b4eSLaurent Vivier             }
1411d8d0b4eSLaurent Vivier             break;
1421d8d0b4eSLaurent Vivier         case EXCP_SYSCALL_LWS:
1431d8d0b4eSLaurent Vivier             env->gr[21] = hppa_lws(env);
1441d8d0b4eSLaurent Vivier             /* We arrived here by faking the gateway page.  Return.  */
1453c13b0ffSRichard Henderson             env->iaoq_f = env->gr[31] | PRIV_USER;
1463c13b0ffSRichard Henderson             env->iaoq_b = env->iaoq_f + 4;
1471d8d0b4eSLaurent Vivier             break;
148bd4b7fd6SHelge Deller         case EXCP_IMP:
149bd4b7fd6SHelge Deller             force_sig_fault(TARGET_SIGSEGV, TARGET_SEGV_MAPERR, env->iaoq_f);
150bd4b7fd6SHelge Deller             break;
1511d8d0b4eSLaurent Vivier         case EXCP_ILL:
152dcd86148SHelge Deller             force_sig_fault(TARGET_SIGILL, TARGET_ILL_ILLOPC, env->iaoq_f);
1531d8d0b4eSLaurent Vivier             break;
1547337adeaSRichard Henderson         case EXCP_PRIV_OPR:
155dcd86148SHelge Deller             /* check for glibc ABORT_INSTRUCTION "iitlbp %r0,(%sr0, %r0)" */
156dcd86148SHelge Deller             if (env->cr[CR_IIR] == 0x04000000) {
157dcd86148SHelge Deller                 force_sig_fault(TARGET_SIGILL, TARGET_ILL_ILLOPC, env->iaoq_f);
158dcd86148SHelge Deller             } else {
1597337adeaSRichard Henderson                 force_sig_fault(TARGET_SIGILL, TARGET_ILL_PRVOPC, env->iaoq_f);
160dcd86148SHelge Deller             }
1617337adeaSRichard Henderson             break;
1627337adeaSRichard Henderson         case EXCP_PRIV_REG:
1637337adeaSRichard Henderson             force_sig_fault(TARGET_SIGILL, TARGET_ILL_PRVREG, env->iaoq_f);
1647337adeaSRichard Henderson             break;
1651d8d0b4eSLaurent Vivier         case EXCP_OVERFLOW:
1667337adeaSRichard Henderson             force_sig_fault(TARGET_SIGFPE, TARGET_FPE_INTOVF, env->iaoq_f);
1677337adeaSRichard Henderson             break;
1681d8d0b4eSLaurent Vivier         case EXCP_COND:
1690edf34c9SRichard Henderson             force_sig_fault(TARGET_SIGFPE, TARGET_FPE_CONDTRAP, env->iaoq_f);
1700edf34c9SRichard Henderson             break;
1711d8d0b4eSLaurent Vivier         case EXCP_ASSIST:
172f6485968SRichard Henderson             force_sig_fault(TARGET_SIGFPE, 0, env->iaoq_f);
1731d8d0b4eSLaurent Vivier             break;
174dcd86148SHelge Deller         case EXCP_BREAK:
1753c13b0ffSRichard Henderson             force_sig_fault(TARGET_SIGTRAP, TARGET_TRAP_BRKPT, env->iaoq_f);
176dcd86148SHelge Deller             break;
1771d8d0b4eSLaurent Vivier         case EXCP_DEBUG:
178f6485968SRichard Henderson             force_sig_fault(TARGET_SIGTRAP, TARGET_TRAP_BRKPT, env->iaoq_f);
1791d8d0b4eSLaurent Vivier             break;
1801d8d0b4eSLaurent Vivier         case EXCP_INTERRUPT:
1811d8d0b4eSLaurent Vivier             /* just indicate that signals should be handled asap */
1821d8d0b4eSLaurent Vivier             break;
1831d8d0b4eSLaurent Vivier         default:
18412640b4fSHelge Deller             EXCP_DUMP(env, "qemu: unhandled CPU exception 0x%x - aborting\n", trapnr);
18512640b4fSHelge Deller             abort();
1861d8d0b4eSLaurent Vivier         }
1871d8d0b4eSLaurent Vivier         process_pending_signals(env);
1881d8d0b4eSLaurent Vivier     }
1891d8d0b4eSLaurent Vivier }
1901d8d0b4eSLaurent Vivier 
target_cpu_copy_regs(CPUArchState * env,struct target_pt_regs * regs)191cd71c089SLaurent Vivier void target_cpu_copy_regs(CPUArchState *env, struct target_pt_regs *regs)
192cd71c089SLaurent Vivier {
1931d8d0b4eSLaurent Vivier     int i;
1941d8d0b4eSLaurent Vivier     for (i = 1; i < 32; i++) {
1951d8d0b4eSLaurent Vivier         env->gr[i] = regs->gr[i];
1961d8d0b4eSLaurent Vivier     }
1971d8d0b4eSLaurent Vivier     env->iaoq_f = regs->iaoq[0];
1981d8d0b4eSLaurent Vivier     env->iaoq_b = regs->iaoq[1];
199cd71c089SLaurent Vivier }
200