symbian-qemu-0.9.1-12/qemu-symbian-svp/target-cris/helper.c
author Gareth Stockwell <gareth.stockwell@accenture.com>
Mon, 06 Sep 2010 16:25:43 +0100
changeset 107 3bc1a978be44
parent 1 2fb8b9db1c86
permissions -rw-r--r--
Fix for Bug 3671 - QEMU GDB stub listens on IPv6-only port on Windows 7 The connection string used by the GDB stub does not specify which version of the Internet Protocol should be used by the port on which it listens. On host platforms with IPv6 support, such as Windows 7, this means that the stub listens on an IPv6-only port. Since the GDB client uses IPv4, this means that the client cannot connect to QEMU.

/*
 *  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, write to the Free Software
 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
 */

#include <stdio.h>
#include <string.h>

#include "config.h"
#include "cpu.h"
#include "mmu.h"
#include "exec-all.h"
#include "host-utils.h"

#define D(x)

#if defined(CONFIG_USER_ONLY)

void do_interrupt (CPUState *env)
{
	env->exception_index = -1;
	env->pregs[PR_ERP] = env->pc;
}

int cpu_cris_handle_mmu_fault(CPUState * env, target_ulong address, int rw,
                             int mmu_idx, int is_softmmu)
{
	env->exception_index = 0xaa;
	env->pregs[PR_EDA] = address;
	cpu_dump_state(env, stderr, fprintf, 0);
	return 1;
}

target_phys_addr_t cpu_get_phys_page_debug(CPUState * env, target_ulong addr)
{
	return addr;
}

#else /* !CONFIG_USER_ONLY */


static void cris_shift_ccs(CPUState *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 (CPUState *env, target_ulong address, int rw,
                               int mmu_idx, int is_softmmu)
{
	struct cris_mmu_result_t 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));
	address &= TARGET_PAGE_MASK;
	miss = cris_mmu_translate(&res, env, address, rw, mmu_idx);
	if (miss)
	{
		if (env->exception_index == EXCP_BUSFAULT)
			cpu_abort(env, 
				  "CRIS: Illegal recursive bus fault."
				  "addr=%x rw=%d\n",
				  address, rw);

		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;
		r = tlb_set_page(env, address, phy, prot, mmu_idx, is_softmmu);
	}
	if (r > 0)
		D(fprintf(logfile, "%s returns %d irqreq=%x addr=%x"
			  " phy=%x ismmu=%d vec=%x pc=%x\n", 
			  __func__, r, env->interrupt_request, 
			  address, res.phy, is_softmmu, res.bf_vec, env->pc));
	return r;
}

void do_interrupt(CPUState *env)
{
	int ex_vec = -1;

	D(fprintf (logfile, "exception index=%d interrupt_req=%d\n",
		   env->exception_index,
		   env->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;
			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(fprintf(logfile, "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;
	}
	
	env->pc = ldl_code(env->pregs[PR_EBP] + ex_vec * 4);

	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);
	D(fprintf (logfile, "%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]));
}

target_phys_addr_t cpu_get_phys_page_debug(CPUState * env, target_ulong addr)
{
	uint32_t phy = addr;
	struct cris_mmu_result_t res;
	int miss;
	miss = cris_mmu_translate(&res, env, addr, 0, 0);
	if (!miss)
		phy = res.phy;
	D(fprintf(stderr, "%s %x -> %x\n", __func__, addr, phy));
	return phy;
}
#endif