qemu-patch-raspberry4/target-cris/helper.c
Andreas Färber 259186a7d2 cpu: Move halted and interrupt_request fields to CPUState
Both fields are used in VMState, thus need to be moved together.
Explicitly zero them on reset since they were located before
breakpoints.

Pass PowerPCCPU to kvmppc_handle_halt().

Signed-off-by: Andreas Färber <afaerber@suse.de>
2013-03-12 10:35:55 +01:00

269 lines
7.6 KiB
C

/*
* CRIS helper routines.
*
* Copyright (c) 2007 AXIS Communications AB
* Written by Edgar E. Iglesias.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, see <http://www.gnu.org/licenses/>.
*/
#include "cpu.h"
#include "mmu.h"
#include "qemu/host-utils.h"
//#define CRIS_HELPER_DEBUG
#ifdef CRIS_HELPER_DEBUG
#define D(x) x
#define D_LOG(...) qemu_log(__VA_ARGS__)
#else
#define D(x)
#define D_LOG(...) do { } while (0)
#endif
#if defined(CONFIG_USER_ONLY)
void do_interrupt(CPUCRISState *env)
{
env->exception_index = -1;
env->pregs[PR_ERP] = env->pc;
}
int cpu_cris_handle_mmu_fault(CPUCRISState * env, target_ulong address, int rw,
int mmu_idx)
{
env->exception_index = 0xaa;
env->pregs[PR_EDA] = address;
cpu_dump_state(env, stderr, fprintf, 0);
return 1;
}
#else /* !CONFIG_USER_ONLY */
static void cris_shift_ccs(CPUCRISState *env)
{
uint32_t ccs;
/* Apply the ccs shift. */
ccs = env->pregs[PR_CCS];
ccs = ((ccs & 0xc0000000) | ((ccs << 12) >> 2)) & ~0x3ff;
env->pregs[PR_CCS] = ccs;
}
int cpu_cris_handle_mmu_fault(CPUCRISState *env, target_ulong address, int rw,
int mmu_idx)
{
D(CPUState *cpu = CPU(cris_env_get_cpu(env)));
struct cris_mmu_result res;
int prot, miss;
int r = -1;
target_ulong phy;
D(printf("%s addr=%x pc=%x rw=%x\n", __func__, address, env->pc, rw));
miss = cris_mmu_translate(&res, env, address & TARGET_PAGE_MASK,
rw, mmu_idx, 0);
if (miss) {
if (env->exception_index == EXCP_BUSFAULT) {
cpu_abort(env,
"CRIS: Illegal recursive bus fault."
"addr=%x rw=%d\n",
address, rw);
}
env->pregs[PR_EDA] = address;
env->exception_index = EXCP_BUSFAULT;
env->fault_vector = res.bf_vec;
r = 1;
} else {
/*
* Mask off the cache selection bit. The ETRAX busses do not
* see the top bit.
*/
phy = res.phy & ~0x80000000;
prot = res.prot;
tlb_set_page(env, address & TARGET_PAGE_MASK, phy,
prot, mmu_idx, TARGET_PAGE_SIZE);
r = 0;
}
if (r > 0) {
D_LOG("%s returns %d irqreq=%x addr=%x phy=%x vec=%x pc=%x\n",
__func__, r, cpu->interrupt_request, address, res.phy,
res.bf_vec, env->pc);
}
return r;
}
static void do_interruptv10(CPUCRISState *env)
{
D(CPUState *cs = CPU(cris_env_get_cpu(env)));
int ex_vec = -1;
D_LOG("exception index=%d interrupt_req=%d\n",
env->exception_index,
cs->interrupt_request);
assert(!(env->pregs[PR_CCS] & PFIX_FLAG));
switch (env->exception_index) {
case EXCP_BREAK:
/* These exceptions are genereated by the core itself.
ERP should point to the insn following the brk. */
ex_vec = env->trap_vector;
env->pregs[PRV10_BRP] = env->pc;
break;
case EXCP_NMI:
/* NMI is hardwired to vector zero. */
ex_vec = 0;
env->pregs[PR_CCS] &= ~M_FLAG_V10;
env->pregs[PRV10_BRP] = env->pc;
break;
case EXCP_BUSFAULT:
cpu_abort(env, "Unhandled busfault");
break;
default:
/* The interrupt controller gives us the vector. */
ex_vec = env->interrupt_vector;
/* Normal interrupts are taken between
TB's. env->pc is valid here. */
env->pregs[PR_ERP] = env->pc;
break;
}
if (env->pregs[PR_CCS] & U_FLAG) {
/* Swap stack pointers. */
env->pregs[PR_USP] = env->regs[R_SP];
env->regs[R_SP] = env->ksp;
}
/* Now that we are in kernel mode, load the handlers address. */
env->pc = cpu_ldl_code(env, env->pregs[PR_EBP] + ex_vec * 4);
env->locked_irq = 1;
env->pregs[PR_CCS] |= F_FLAG_V10; /* set F. */
qemu_log_mask(CPU_LOG_INT, "%s isr=%x vec=%x ccs=%x pid=%d erp=%x\n",
__func__, env->pc, ex_vec,
env->pregs[PR_CCS],
env->pregs[PR_PID],
env->pregs[PR_ERP]);
}
void do_interrupt(CPUCRISState *env)
{
D(CPUState *cs = CPU(cris_env_get_cpu(env)));
int ex_vec = -1;
if (env->pregs[PR_VR] < 32) {
return do_interruptv10(env);
}
D_LOG("exception index=%d interrupt_req=%d\n",
env->exception_index,
cs->interrupt_request);
switch (env->exception_index) {
case EXCP_BREAK:
/* These exceptions are genereated by the core itself.
ERP should point to the insn following the brk. */
ex_vec = env->trap_vector;
env->pregs[PR_ERP] = env->pc;
break;
case EXCP_NMI:
/* NMI is hardwired to vector zero. */
ex_vec = 0;
env->pregs[PR_CCS] &= ~M_FLAG_V32;
env->pregs[PR_NRP] = env->pc;
break;
case EXCP_BUSFAULT:
ex_vec = env->fault_vector;
env->pregs[PR_ERP] = env->pc;
break;
default:
/* The interrupt controller gives us the vector. */
ex_vec = env->interrupt_vector;
/* Normal interrupts are taken between
TB's. env->pc is valid here. */
env->pregs[PR_ERP] = env->pc;
break;
}
/* Fill in the IDX field. */
env->pregs[PR_EXS] = (ex_vec & 0xff) << 8;
if (env->dslot) {
D_LOG("excp isr=%x PC=%x ds=%d SP=%x"
" ERP=%x pid=%x ccs=%x cc=%d %x\n",
ex_vec, env->pc, env->dslot,
env->regs[R_SP],
env->pregs[PR_ERP], env->pregs[PR_PID],
env->pregs[PR_CCS],
env->cc_op, env->cc_mask);
/* We loose the btarget, btaken state here so rexec the
branch. */
env->pregs[PR_ERP] -= env->dslot;
/* Exception starts with dslot cleared. */
env->dslot = 0;
}
if (env->pregs[PR_CCS] & U_FLAG) {
/* Swap stack pointers. */
env->pregs[PR_USP] = env->regs[R_SP];
env->regs[R_SP] = env->ksp;
}
/* Apply the CRIS CCS shift. Clears U if set. */
cris_shift_ccs(env);
/* Now that we are in kernel mode, load the handlers address.
This load may not fault, real hw leaves that behaviour as
undefined. */
env->pc = cpu_ldl_code(env, env->pregs[PR_EBP] + ex_vec * 4);
/* Clear the excption_index to avoid spurios hw_aborts for recursive
bus faults. */
env->exception_index = -1;
D_LOG("%s isr=%x vec=%x ccs=%x pid=%d erp=%x\n",
__func__, env->pc, ex_vec,
env->pregs[PR_CCS],
env->pregs[PR_PID],
env->pregs[PR_ERP]);
}
hwaddr cpu_get_phys_page_debug(CPUCRISState * env, target_ulong addr)
{
uint32_t phy = addr;
struct cris_mmu_result res;
int miss;
miss = cris_mmu_translate(&res, env, addr, 0, 0, 1);
/* If D TLB misses, try I TLB. */
if (miss) {
miss = cris_mmu_translate(&res, env, addr, 2, 0, 1);
}
if (!miss) {
phy = res.phy;
}
D(fprintf(stderr, "%s %x -> %x\n", __func__, addr, phy));
return phy;
}
#endif