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