qemu
223 строки · 7.9 Кб
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 "user-internals.h"23#include "cpu_loop-common.h"24#include "signal-common.h"25#include "qemu/guest-random.h"26#include "semihosting/common-semi.h"27#include "target/arm/syndrome.h"28#include "target/arm/cpu-features.h"29
30#define get_user_code_u32(x, gaddr, env) \31({ abi_long __r = get_user_u32((x), (gaddr)); \32if (!__r && bswap_code(arm_sctlr_b(env))) { \33(x) = bswap32(x); \34} \35__r; \36})37
38#define get_user_code_u16(x, gaddr, env) \39({ abi_long __r = get_user_u16((x), (gaddr)); \40if (!__r && bswap_code(arm_sctlr_b(env))) { \41(x) = bswap16(x); \42} \43__r; \44})45
46#define get_user_data_u32(x, gaddr, env) \47({ abi_long __r = get_user_u32((x), (gaddr)); \48if (!__r && arm_cpu_bswap_data(env)) { \49(x) = bswap32(x); \50} \51__r; \52})53
54#define get_user_data_u16(x, gaddr, env) \55({ abi_long __r = get_user_u16((x), (gaddr)); \56if (!__r && arm_cpu_bswap_data(env)) { \57(x) = bswap16(x); \58} \59__r; \60})61
62#define put_user_data_u32(x, gaddr, env) \63({ typeof(x) __x = (x); \64if (arm_cpu_bswap_data(env)) { \65__x = bswap32(__x); \66} \67put_user_u32(__x, (gaddr)); \68})69
70#define put_user_data_u16(x, gaddr, env) \71({ typeof(x) __x = (x); \72if (arm_cpu_bswap_data(env)) { \73__x = bswap16(__x); \74} \75put_user_u16(__x, (gaddr)); \76})77
78/* AArch64 main loop */
79void cpu_loop(CPUARMState *env)80{
81CPUState *cs = env_cpu(env);82int trapnr, ec, fsc, si_code, si_signo;83abi_long ret;84
85for (;;) {86cpu_exec_start(cs);87trapnr = cpu_exec(cs);88cpu_exec_end(cs);89process_queued_cpu_work(cs);90
91switch (trapnr) {92case EXCP_SWI:93/* On syscall, PSTATE.ZA is preserved, PSTATE.SM is cleared. */94aarch64_set_svcr(env, 0, R_SVCR_SM_MASK);95ret = do_syscall(env,96env->xregs[8],97env->xregs[0],98env->xregs[1],99env->xregs[2],100env->xregs[3],101env->xregs[4],102env->xregs[5],1030, 0);104if (ret == -QEMU_ERESTARTSYS) {105env->pc -= 4;106} else if (ret != -QEMU_ESIGRETURN) {107env->xregs[0] = ret;108}109break;110case EXCP_INTERRUPT:111/* just indicate that signals should be handled asap */112break;113case EXCP_UDEF:114force_sig_fault(TARGET_SIGILL, TARGET_ILL_ILLOPN, env->pc);115break;116case EXCP_PREFETCH_ABORT:117case EXCP_DATA_ABORT:118ec = syn_get_ec(env->exception.syndrome);119switch (ec) {120case EC_DATAABORT:121case EC_INSNABORT:122/* Both EC have the same format for FSC, or close enough. */123fsc = extract32(env->exception.syndrome, 0, 6);124switch (fsc) {125case 0x04 ... 0x07: /* Translation fault, level {0-3} */126si_signo = TARGET_SIGSEGV;127si_code = TARGET_SEGV_MAPERR;128break;129case 0x09 ... 0x0b: /* Access flag fault, level {1-3} */130case 0x0d ... 0x0f: /* Permission fault, level {1-3} */131si_signo = TARGET_SIGSEGV;132si_code = TARGET_SEGV_ACCERR;133break;134case 0x11: /* Synchronous Tag Check Fault */135si_signo = TARGET_SIGSEGV;136si_code = TARGET_SEGV_MTESERR;137break;138case 0x21: /* Alignment fault */139si_signo = TARGET_SIGBUS;140si_code = TARGET_BUS_ADRALN;141break;142default:143g_assert_not_reached();144}145break;146case EC_PCALIGNMENT:147si_signo = TARGET_SIGBUS;148si_code = TARGET_BUS_ADRALN;149break;150default:151g_assert_not_reached();152}153force_sig_fault(si_signo, si_code, env->exception.vaddress);154break;155case EXCP_DEBUG:156case EXCP_BKPT:157force_sig_fault(TARGET_SIGTRAP, TARGET_TRAP_BRKPT, env->pc);158break;159case EXCP_SEMIHOST:160do_common_semihosting(cs);161env->pc += 4;162break;163case EXCP_YIELD:164/* nothing to do here for user-mode, just resume guest code */165break;166case EXCP_ATOMIC:167cpu_exec_step_atomic(cs);168break;169default:170EXCP_DUMP(env, "qemu: unhandled CPU exception 0x%x - aborting\n", trapnr);171abort();172}173
174/* Check for MTE asynchronous faults */175if (unlikely(env->cp15.tfsr_el[0])) {176env->cp15.tfsr_el[0] = 0;177force_sig_fault(TARGET_SIGSEGV, TARGET_SEGV_MTEAERR, 0);178}179
180process_pending_signals(env);181/* Exception return on AArch64 always clears the exclusive monitor,182* so any return to running guest code implies this.
183*/
184env->exclusive_addr = -1;185}186}
187
188void target_cpu_copy_regs(CPUArchState *env, struct target_pt_regs *regs)189{
190ARMCPU *cpu = env_archcpu(env);191CPUState *cs = env_cpu(env);192TaskState *ts = get_task_state(cs);193struct image_info *info = ts->info;194int i;195
196if (!(arm_feature(env, ARM_FEATURE_AARCH64))) {197fprintf(stderr,198"The selected ARM CPU does not support 64 bit mode\n");199exit(EXIT_FAILURE);200}201
202for (i = 0; i < 31; i++) {203env->xregs[i] = regs->regs[i];204}205env->pc = regs->pc;206env->xregs[31] = regs->sp;207#if TARGET_BIG_ENDIAN208env->cp15.sctlr_el[1] |= SCTLR_E0E;209for (i = 1; i < 4; ++i) {210env->cp15.sctlr_el[i] |= SCTLR_EE;211}212arm_rebuild_hflags(env);213#endif214
215if (cpu_isar_feature(aa64_pauth, cpu)) {216qemu_guest_getrandom_nofail(&env->keys, sizeof(env->keys));217}218
219ts->stack_base = info->start_stack;220ts->heap_base = info->brk;221/* This will be filled in on the first SYS_HEAPINFO call. */222ts->heap_limit = 0;223}
224