Initial commit of OpenSPARC T2 architecture model.
[OpenSPARC-T2-SAM] / legion / src / procs / sparcv9 / magictraps.c
/*
* ========== Copyright Header Begin ==========================================
*
* OpenSPARC T2 Processor File: magictraps.c
* Copyright (c) 2006 Sun Microsystems, Inc. All Rights Reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES.
*
* The above named program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public
* License version 2 as published by the Free Software Foundation.
*
* The above named program 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
* General Public License for more details.
*
* You should have received a copy of the GNU General Public
* License along with this work; if not, write to the Free Software
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA.
*
* ========== Copyright Header End ============================================
*/
/*
* Copyright 2006 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
#pragma ident "@(#)magictraps.c 1.5 06/10/27 SMI"
#include <stdio.h>
#include <stdlib.h>
#include <strings.h>
#include "basics.h"
#include "fatal.h"
#include "simcore.h"
#include "config.h"
#include "tsparcv9.h"
#include "tsparcv9internal.h"
#include "sparcv9regs.h"
#include "magictraps.h"
#include "options.h"
#if ENABLE_MAGIC_TRAPS /* { */
static uint64_t
pabcopy(simcpu_t *sp, uint64_t pasrc, uint64_t padst, uint64_t size)
{
domain_t *domainp;
config_proc_t *config_procp;
config_addr_t *capsrc, *capdst;
uint8_t *srcbufp, *dstbufp;
tpaddr_t extent;
DBG( lprintf(sp->gid, "pabcopy(0x%llx, 0x%llx, 0x%llx)\n",
pasrc, padst, size); );
config_procp = sp->config_procp;
domainp = config_procp->domainp;
capsrc = find_domain_address(domainp, pasrc);
if (capsrc == NULL) {
EXEC_WARNING(("@ pc=0x%llx : simbcopy: src address not valid",
sp->pc));
return (-1);
}
/* try and get the buffer pointer */
extent = capsrc->config_devp->dev_typep->dev_cacheable(capsrc, DA_Load,
pasrc-capsrc->baseaddr, &srcbufp);
if (extent < size) {
EXEC_WARNING(("@ pc=0x%llx : pabcopy: src not large enough",
sp->pc));
return (-1);
}
capdst = find_domain_address(domainp, padst);
if (capdst == NULL) {
EXEC_WARNING(("@ pc=0x%llx : pabcopy: dest address not valid",
sp->pc));
return (-1);
}
/* try and get the buffer pointer */
extent = capdst->config_devp->dev_typep->dev_cacheable(capdst, DA_Store,
padst-capdst->baseaddr, &dstbufp);
if (extent < size) {
EXEC_WARNING(("@ pc=0x%llx : pabcopy: dest not large enough",
sp->pc));
return (-1);
}
bcopy(srcbufp, dstbufp, size);
return (0);
}
/*
* Called from a trap instruction implementation if a trap falls
* into the magic trap number range - see the macro SS_MAGIC_TRAP().
*
* Returns true to indicate the magic trap was actioned, false
* otherwise. Typically, the call sequence is:
*
* if (SS_MAGIC_TRAP(sp, tt)) {
* NEXT_INSTN(sp);
* return;
* }
*/
bool_t ss_magic_trap(simcpu_t * sp, uint32_t tt)
{
sparcv9_cpu_t * v9p;
if (!options.magic_traps)
return false;
v9p = (sparcv9_cpu_t *)(sp->specificp);
switch (tt) {
case MAGIC_TRAP_SETDBG:
if (v9p->state == V9_User)
return false;
{
uint64_t val;
int i;
#if NDEBUG /* { */
EXEC_WARNING(("Magic trap 0x%x: compiled with NDEBUG,"
"so no simulator debug output", tt));
val = 0;
#else /* } { */
val = debug_bits;
simcore_update_debug_bits( sp->intreg[Reg_sparcv9_o0] );
#endif /* } */
sp->intreg[Reg_sparcv9_o0] = val;
}
return true;
case MAGIC_TRAP_SIMEXIT:
if (v9p->state == V9_User)
break;
/* Use for dramatic exit */
log_flush();
warning("magic trap 0x%x requested exit(0x%llx)\n", tt,
sp->intreg[Reg_sparcv9_o0]);
exit(sp->intreg[Reg_sparcv9_o0]);
case MAGIC_TRAP_GOT_HERE: {
if (v9p->state == V9_User)
return false;
log_lock();
log_printf(sp->gid, "Got here: 0x%llx\n", sp->pc);
#if !defined(NDEBUG) /* { */
sparcv9_dump_state(sp);
#endif /* } */
log_flush_unlock();
return true;
}
case MAGIC_TRAP_LOG_DUMP: /* rot log dump */
if (v9p->state == V9_User)
return false;
#if !defined(NDEBUG) /* { */
log_dump();
#endif /* } */
return true;
case MAGIC_TRAP_PABCOPY: { /* pa bcopy */
if (v9p->state != V9_RED && v9p->state != V9_HyperPriv)
return false;
sp->intreg[Reg_sparcv9_g4] =
pabcopy(sp, sp->intreg[Reg_sparcv9_g1],
sp->intreg[Reg_sparcv9_g2],
sp->intreg[Reg_sparcv9_g3]);
return true;
}
case MAGIC_TRAP_INST_CNT: { /* instruction count */
uint64_t temp_flags;
simcycle_t count;
if (v9p->state == V9_User)
return false;
count = ICOUNT(sp);
temp_flags = sp->intreg[Reg_sparcv9_o0];
if (temp_flags & MT_INST_CNT_PRINT) {
lprintf(sp->gid, "At: %llu : "
"Instruction count = %llu\n", (uint64_t)count,
(uint64_t)(count - sp->magic_count));
}
if (temp_flags & MT_INST_CNT_SET_PREV) {
sp->magic_count = count;
}
return true;
}
case MAGIC_TRAP_ALLDBG: {
if (v9p->state == V9_User)
return false;
#if NDEBUG /* { */
EXEC_WARNING(("Magic trap 0x%x: compiled with NDEBUG,"
"so no simulator debug output", tt));
#else /* } { */
simcore_update_debug_bits(-1);
#endif /* } */
return true;
}
case MAGIC_TRAP_NO_DBG: {
if (v9p->state == V9_User)
return false;
#if NDEBUG /* { */
EXEC_WARNING(("Magic trap 0x%x: compiled with NDEBUG,"
"so no simulator debug output", tt));
#else /* } { */
simcore_update_debug_bits(0);
#endif /* } */
return true;
}
case MAGIC_TRAP_SAVE_STATE: {
flockfile(stdout);
lprintf(sp->gid, "MAGIC_TRAP_SAVE_STATE: Got here: 0x%llx (instn_cnt=%lld)\n",
sp->pc, ICOUNT(sp));
if (sp->config_procp->proc_typep->save_state(sp) == false) {
funlockfile(stdout);
fatal("Legion Save State Failed. Exiting!\n");
}
/* We are done, so terminate legion with a Message */
funlockfile(stdout);
lprintf(sp->gid, "Legion Save State Completed. Exiting\n");
exit(0);
}
default:
return false;
}
/* no return here - compiler will catch errors in the switch */
}
#endif /* } */