T32: Integrated Register read/write calls
* Tested without connected Lauterbach. T32_* functions are mocked via aspect. * New target t32cli, for sending T32 command cia cli. (for testing) git-svn-id: https://www4.informatik.uni-erlangen.de/i4svn/danceos/trunk/devel/fail@2103 8c4709b5-6ec9-48aa-a5cd-a96041d1645a
This commit is contained in:
@ -60,8 +60,12 @@ elseif(BUILD_T32)
|
||||
Register.cc
|
||||
SimulatorController.cc
|
||||
t32/T32Controller.cc
|
||||
t32/wrappers.cc
|
||||
)
|
||||
if(BUILD_ARM)
|
||||
set(SRCS ${SRCS}
|
||||
t32/T32ArmCPU.cc
|
||||
)
|
||||
endif(BUILD_ARM)
|
||||
endif(BUILD_BOCHS)
|
||||
|
||||
if(BUILD_X86)
|
||||
|
||||
@ -15,6 +15,11 @@
|
||||
#include "qemu/QEMUConfig.hpp"
|
||||
#elif defined BUILD_T32
|
||||
#include "t32/T32Config.hpp"
|
||||
#if defined BUILD_ARM
|
||||
#include "t32/T32ArmCPU.hpp"
|
||||
#else
|
||||
#error Active config currently not supported!
|
||||
#endif
|
||||
#else
|
||||
#error SAL Config Target not defined
|
||||
#endif
|
||||
|
||||
@ -10,7 +10,7 @@ namespace fail {
|
||||
|
||||
/**
|
||||
* \class Gem5ArmCPU
|
||||
*
|
||||
*
|
||||
* \c Gem5ArmCPU is the concrete CPU implementation for the gem5 ARM simulator. It
|
||||
* implements the CPU interfaces \c ArmArchitecture and \c ArmCPUState.
|
||||
* \c ArmArchitecture refers to architectural information (e.g. register \a count)
|
||||
|
||||
@ -10,7 +10,7 @@ namespace fail {
|
||||
|
||||
/**
|
||||
* \class Gem5Controller
|
||||
*
|
||||
*
|
||||
* Gem5-specific implementation of a SimulatorController.
|
||||
*/
|
||||
class Gem5Controller : public SimulatorController {
|
||||
|
||||
@ -19,7 +19,7 @@ namespace fail {
|
||||
class Gem5MemoryManager : public MemoryManager {
|
||||
public:
|
||||
Gem5MemoryManager(System* system) : m_System(system), m_Mem(&system->getPhysMem()) { }
|
||||
|
||||
|
||||
size_t getPoolSize() const { return m_Mem->totalSize(); }
|
||||
host_address_t getStartAddr() const { return 0; }
|
||||
|
||||
|
||||
53
src/core/sal/t32/T32ArmCPU.cc
Normal file
53
src/core/sal/t32/T32ArmCPU.cc
Normal file
@ -0,0 +1,53 @@
|
||||
#include "T32ArmCPU.hpp"
|
||||
#include <t32.h>
|
||||
#include <iostream>
|
||||
|
||||
namespace fail {
|
||||
|
||||
regdata_t T32ArmCPU::getRegisterContent(Register* reg) const
|
||||
{
|
||||
// T32_ReadRegister wants a mask of bits representig the registers to read:
|
||||
// e.g., reading R1 and R4 and R63
|
||||
// mask1
|
||||
// 0000 0000 0000 0000 0001 0010 -> R1/R4
|
||||
// mask2
|
||||
// 1000 0000 0000 0000 0001 0010 -> R63
|
||||
uint64_t mask = (1 << reg->getIndex());
|
||||
|
||||
if(mask){
|
||||
if( T32_ReadRegister(static_cast<dword>(mask & 0xffffffff), static_cast<dword>(mask >> 32), m_regbuffer) == 0 ){
|
||||
// No error, return value.
|
||||
return m_regbuffer[reg->getIndex()];
|
||||
} else {
|
||||
/// TODO Error handling!
|
||||
}
|
||||
}
|
||||
return 0; // we should not come here.
|
||||
}
|
||||
|
||||
void T32ArmCPU::setRegisterContent(Register* reg, regdata_t value)
|
||||
{
|
||||
uint64_t mask = (1 << reg->getIndex());
|
||||
|
||||
if(mask){
|
||||
if( T32_WriteRegister(static_cast<dword>(mask & 0xffffffff), static_cast<dword>(mask >> 32), m_regbuffer) == 0 ){
|
||||
// No error, return value.
|
||||
return;
|
||||
} else {
|
||||
/// TODO Error handling!
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
address_t T32ArmCPU::getInstructionPointer() const
|
||||
{
|
||||
// TODO: programpointer is only valid when Emulation is stopped! -> T32_GetState)
|
||||
address_t programpointer;
|
||||
T32_ReadPP( &programpointer );
|
||||
return programpointer;
|
||||
}
|
||||
|
||||
} // end-of-namespace: fail
|
||||
|
||||
|
||||
75
src/core/sal/t32/T32ArmCPU.hpp
Normal file
75
src/core/sal/t32/T32ArmCPU.hpp
Normal file
@ -0,0 +1,75 @@
|
||||
#ifndef __T32_ARM_CPU_HPP__
|
||||
#define __T32_ARM_CPU_HPP__
|
||||
|
||||
#include "../arm/Architecture.hpp"
|
||||
#include "../arm/CPUState.hpp"
|
||||
#include <t32.h>
|
||||
|
||||
namespace fail {
|
||||
|
||||
/**
|
||||
* \class T32ArmCPU
|
||||
*
|
||||
* \c T32ArmCPU is the concrete CPU implementation for the T32 ARM debugger. It
|
||||
* implements the CPU interfaces \c ArmArchitecture and \c ArmCPUState.
|
||||
* \c ArmArchitecture refers to architectural information (e.g. register \a count)
|
||||
* while \c ArmCPUState encapsulates the CPU state (e.g. register \a content).
|
||||
*/
|
||||
class T32ArmCPU : public ArmArchitecture, public ArmCPUState {
|
||||
public:
|
||||
/**
|
||||
* Creates a new gem5 CPU for ARM based targets.
|
||||
* @param id the unique ID of the CPU to be created (the first CPU0 has ID 0)
|
||||
* @param system the gem5 system object
|
||||
*/
|
||||
T32ArmCPU(unsigned int id = 0) : m_Id(id) { }
|
||||
virtual ~T32ArmCPU() { }
|
||||
/**
|
||||
* Retrieves the register content from the current CPU.
|
||||
* @param reg the destination register whose content should be retrieved
|
||||
* @return the content of register \c reg
|
||||
*/
|
||||
regdata_t getRegisterContent(Register* reg) const;
|
||||
/**
|
||||
* Sets the register content for the \a current CPU.
|
||||
* @param reg the (initialized) register object whose content should be set
|
||||
* @param value the new content of the register \c reg
|
||||
*/
|
||||
void setRegisterContent(Register* reg, regdata_t value);
|
||||
/**
|
||||
* Retrieves the current instruction pointer (IP aka program counter, PC for short)
|
||||
* for the current CPU \c this.
|
||||
* @return the current instruction ptr address
|
||||
*/
|
||||
address_t getInstructionPointer() const;
|
||||
|
||||
/**
|
||||
* Retrieves the current stack pointer for the current CPU \c this.
|
||||
* @return the current stack ptr address
|
||||
*/
|
||||
address_t getStackPointer() const { return getRegisterContent(getRegister(RI_SP)); }
|
||||
/**
|
||||
* Retrieves the link register (return address when a function returns) for
|
||||
* the current CPU \c this. See
|
||||
* http://infocenter.arm.com/help/index.jsp?topic=/com.arm.doc.ddi0211h/ch02s08s01.html
|
||||
* for further information.
|
||||
* @return the current link register address
|
||||
*/
|
||||
address_t getLinkRegister() const { return getRegisterContent(getRegister(RI_LR)); }
|
||||
/**
|
||||
* Returns the ID of the current CPU.
|
||||
* @return the unique ID of \c this CPU object
|
||||
*/
|
||||
unsigned int getId() const { return m_Id; }
|
||||
private:
|
||||
unsigned int m_Id; //!< the unique ID of this CPU
|
||||
mutable dword m_regbuffer[64]; //!< internal buffer for reading/writing registers, wow mutable really makes sense sometimes.
|
||||
// char* cpuname? OMAP4430APP1 ??
|
||||
|
||||
};
|
||||
|
||||
typedef T32ArmCPU ConcreteCPU; //!< the concrete CPU type for ARM + T32
|
||||
|
||||
} // end-of-namespace: fail
|
||||
|
||||
#endif // __T32_ARM_CPU_HPP__
|
||||
@ -1,6 +1,6 @@
|
||||
/**
|
||||
* \brief Type definitions and configuration settings for the
|
||||
* T32 target backend.
|
||||
* T32 target backend.
|
||||
*/
|
||||
|
||||
#ifndef __T32_CONFIG_HPP__
|
||||
@ -13,7 +13,8 @@ namespace fail {
|
||||
typedef uint32_t guest_address_t; //!< the guest memory address type
|
||||
typedef unsigned char* host_address_t; //!< the host memory address type
|
||||
typedef uint32_t register_data_t; //!< register data type (64 bit)
|
||||
typedef T32Timer* timer_t; //!< type of timer IDs
|
||||
typedef int timer_t; //!< type of timer IDs
|
||||
//typedef T32Timer* timer_t; //!< type of timer IDs
|
||||
|
||||
} // end-of-namespace: fail
|
||||
|
||||
|
||||
56
src/core/sal/t32/T32Connector.cc
Normal file
56
src/core/sal/t32/T32Connector.cc
Normal file
@ -0,0 +1,56 @@
|
||||
/**
|
||||
* FailT32 -- Fault Injection on the Lauterbach Trace32 System
|
||||
*
|
||||
* 1. Invoke t32 executable with appropriate Lauterbach Skript
|
||||
* - Script has to load binary
|
||||
* - and let system run until entry point
|
||||
* -> Then we have a readily configured system
|
||||
*
|
||||
* @author Martin Hoffmann <hoffmann@cs.fau.de>
|
||||
* @date 15.02.2013
|
||||
*/
|
||||
|
||||
#include <t32.h>
|
||||
#include <iostream>
|
||||
#include <string.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
using namespace std;
|
||||
|
||||
/* Default T32 error handler */
|
||||
void err(int ernum){
|
||||
if(err != 0){
|
||||
cerr << "Error: " << err << endl;
|
||||
//exit(-1);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
/* Here we go... */
|
||||
int main(int argc, char** argv){
|
||||
|
||||
// Evaluate arguments
|
||||
|
||||
// Setup connection to Lauterbach
|
||||
cout << "Lauterbach remote connection" << endl;
|
||||
int error;
|
||||
char hostname[] = "localhost";
|
||||
char packlen[] = "1024";
|
||||
char port[] = "20010";
|
||||
|
||||
cout << "[T32] Connecting to " << hostname << ":" << port << " Packlen: " << packlen << endl;
|
||||
T32_Config("NODE=", hostname);
|
||||
T32_Config("PACKLEN=", packlen);
|
||||
T32_Config("PORT=", port);
|
||||
|
||||
cout << "[T32] Init." << endl;
|
||||
err(T32_Init());
|
||||
|
||||
cout << "[T32] Attach." << endl;
|
||||
err(T32_Attach(T32_DEV_ICD));
|
||||
|
||||
|
||||
// Let simulatorcontroller do the work.
|
||||
|
||||
}
|
||||
24
src/core/sal/t32/T32Connector.hpp
Normal file
24
src/core/sal/t32/T32Connector.hpp
Normal file
@ -0,0 +1,24 @@
|
||||
#ifndef __T32_CONNECTOR_HPP__
|
||||
#define __T32_CONNECTOR_HPP__
|
||||
|
||||
#include <t32.h>
|
||||
|
||||
namespace fail {
|
||||
|
||||
/**
|
||||
* \class T32Connector
|
||||
*/
|
||||
class T32Connector {
|
||||
public:
|
||||
|
||||
|
||||
/**
|
||||
* Save simulator state. Quite hard on real hardware! Also safe all HW registers!
|
||||
* @param path Location to store state information
|
||||
* @return \c true if the state has been successfully saved, \c false otherwise
|
||||
*/
|
||||
};
|
||||
|
||||
} // end-of-namespace: fail
|
||||
|
||||
#endif // __T32_CONNECTOR_HPP__
|
||||
@ -1,23 +1,26 @@
|
||||
#include <sstream>
|
||||
|
||||
#include "T32Controller.hpp"
|
||||
#include "T32Memory.hpp"
|
||||
#include "T32Register.hpp"
|
||||
#include "../Register.hpp"
|
||||
#include "../SALInst.hpp"
|
||||
#include "T32Connector.hpp"
|
||||
|
||||
#include "../Listener.hpp"
|
||||
|
||||
|
||||
namespace fail {
|
||||
|
||||
T32Controller::T32Controller()
|
||||
: SimulatorController(new T32RegisterManager(), new T32MemoryManager())
|
||||
{
|
||||
// TODO: probably do additional RegisterManager initializations
|
||||
void T32Controller::startup(){
|
||||
// Do some T32-specific startup
|
||||
addCPU(new ConcreteCPU(0));
|
||||
// Startup generic SimulatorController
|
||||
SimulatorController::startup();
|
||||
}
|
||||
|
||||
|
||||
T32Controller::~T32Controller()
|
||||
{
|
||||
delete m_Regs;
|
||||
delete m_Mem;
|
||||
std::vector<ConcreteCPU*>::iterator it = m_CPUs.begin();
|
||||
while (it != m_CPUs.end()) {
|
||||
delete *it;
|
||||
it = m_CPUs.erase(it);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
@ -1,27 +1,18 @@
|
||||
#ifndef __T32_CONTROLLER_HPP__
|
||||
#define __T32_CONTROLLER_HPP__
|
||||
|
||||
#include <string>
|
||||
#include <cassert>
|
||||
#include <iostream>
|
||||
#include <iomanip>
|
||||
#include <string.h>
|
||||
|
||||
#include "../SimulatorController.hpp"
|
||||
#include "T32Memory.hpp"
|
||||
|
||||
namespace fail {
|
||||
|
||||
class ExperimentFlow;
|
||||
class TimerListener;
|
||||
|
||||
/**
|
||||
* \class T32Controller
|
||||
* Very rudimentary, T32-specific implementation of a SimulatorController.
|
||||
*/
|
||||
class T32Controller : public SimulatorController {
|
||||
public:
|
||||
// Initialize the controller.
|
||||
T32Controller();
|
||||
void startup();
|
||||
~T32Controller();
|
||||
|
||||
|
||||
@ -29,8 +20,7 @@ public:
|
||||
* Simulator Controller & Access API:
|
||||
* ********************************************************************/
|
||||
/**
|
||||
* Save simulator state. Quite hard on real hardware! Also safe all
|
||||
* HW registers!
|
||||
* Save simulator state. Quite hard on real hardware! Also safe all HW registers! TODO
|
||||
* @param path Location to store state information
|
||||
* @return \c true if the state has been successfully saved, \c false otherwise
|
||||
*/
|
||||
|
||||
@ -1,8 +1,8 @@
|
||||
#ifndef __T32LISTENER_AH__
|
||||
#define __T32LISTENER_AH__
|
||||
|
||||
#include "config/VariantConfig.hpp"
|
||||
#include "config/FailConfig.hpp"
|
||||
#include "config/VariantConfig.hpp"
|
||||
|
||||
#if defined(BUILD_T32) && defined(CONFIG_EVENT_BREAKPOINTS)
|
||||
|
||||
@ -10,23 +10,22 @@
|
||||
|
||||
aspect T32Listener
|
||||
|
||||
advice "fail::MemWriteListener" : slice class
|
||||
advice "fail::BPSingleListener" : slice class
|
||||
{
|
||||
public:
|
||||
bool onAddition()
|
||||
{
|
||||
//std::cout << "T32MemWriteListener::onAddition" << std::endl;
|
||||
//if (failqemu_add_watchpoint(simulator.m_cpuenv, m_WatchAddr, m_WatchWidth, 1) != 0) {
|
||||
// std::cout << "adding watchpoint failed!" << std::endl;
|
||||
return false;
|
||||
//}
|
||||
//return true;
|
||||
|
||||
// Setup Breakpoint in T32
|
||||
std::cout << "T32Listener::onAddition" << std::endl;
|
||||
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void onDeletion()
|
||||
{
|
||||
//std::cout << "T32MemWriteListener::onDeletion" << std::endl;
|
||||
//failqemu_remove_watchpoint(simulator.m_cpuenv, m_WatchAddr, m_WatchWidth, 1);
|
||||
// Delete Breakpoint in T32
|
||||
}
|
||||
};
|
||||
};
|
||||
|
||||
@ -3,6 +3,8 @@
|
||||
|
||||
#include "../Memory.hpp"
|
||||
|
||||
#include <t32.h>
|
||||
|
||||
namespace fail {
|
||||
|
||||
/**
|
||||
@ -11,29 +13,44 @@ namespace fail {
|
||||
* MemoryManager to provide access to T32's memory pool.
|
||||
*/
|
||||
class T32MemoryManager : public MemoryManager {
|
||||
|
||||
enum ACCESS_CLASS {
|
||||
data_access = 0,
|
||||
program_access = 1,
|
||||
AD_access = 12,
|
||||
AP_access = 13,
|
||||
USR_access = 15,
|
||||
};
|
||||
|
||||
public:
|
||||
size_t getPoolSize() const { return 0; /* TODO */ }
|
||||
|
||||
host_address_t getStartAddr() const { return 0; }
|
||||
|
||||
byte_t getByte(guest_address_t addr)
|
||||
{
|
||||
return 0; //failqemu_mem_read_byte(addr);
|
||||
}
|
||||
char b;
|
||||
getBytes(addr, 1, &b);
|
||||
return b;
|
||||
}
|
||||
|
||||
void getBytes(guest_address_t addr, size_t cnt, void *dest)
|
||||
{
|
||||
char *d = static_cast<char *>(dest);
|
||||
for (size_t i = 0; i < cnt; ++i)
|
||||
d[i] = 0; //getByte(addr + i);
|
||||
int access = data_access; // TODO what access class do we need?!
|
||||
T32_ReadMemory( addr, access, (byte*)(dest), cnt);
|
||||
}
|
||||
|
||||
void setByte(guest_address_t addr, byte_t data)
|
||||
{
|
||||
//failqemu_mem_write_byte(addr, data);
|
||||
setBytes(addr, 1, &data);
|
||||
}
|
||||
|
||||
void setBytes(guest_address_t addr, size_t cnt, void const *src)
|
||||
{
|
||||
//char const *s = static_cast<char const *>(src);
|
||||
for (size_t i = 0; i < cnt; ++i)
|
||||
; //setByte(addr + i, s[i]);
|
||||
int access = data_access; // TODO what access class do we really need?!
|
||||
T32_WriteMemory(addr, access, (byte*)(src), cnt);
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
} // end-of-namespace: fail
|
||||
|
||||
26
src/core/sal/t32/T32Mock.ah
Normal file
26
src/core/sal/t32/T32Mock.ah
Normal file
@ -0,0 +1,26 @@
|
||||
#ifndef __T32MOCK_AH__
|
||||
#define __T32MOCK_AH__
|
||||
|
||||
#include <iostream>
|
||||
|
||||
#if defined(BUILD_T32) // && defined(T32MOCK)
|
||||
|
||||
/* Mock aspect for testing without T32 HW attached. */
|
||||
aspect T32Mock
|
||||
{
|
||||
advice call("% T32_% (...)") : around ()
|
||||
{
|
||||
std::cout << "[T32 MOCK] " << JoinPoint::signature() << " (";
|
||||
|
||||
for(int i = 0; i < tjp->args(); i++) {
|
||||
std::cout << std::hex << *((int*)( tjp->arg(i) ) );
|
||||
if(i < tjp->args()-1) std::cout << ", ";
|
||||
}
|
||||
std::cout << ")" << std::endl;
|
||||
|
||||
*tjp->result() = 0;
|
||||
}
|
||||
};
|
||||
|
||||
#endif // BUILD_T32 && CONFIG_EVENT_BREAKPOINTS
|
||||
#endif // __T32MOCK_AH__
|
||||
@ -1,45 +0,0 @@
|
||||
#ifndef __T32_REGISTER_HPP__
|
||||
#define __T32_REGISTER_HPP__
|
||||
|
||||
#include "../Register.hpp"
|
||||
|
||||
#include <iostream>
|
||||
#include <cassert>
|
||||
|
||||
namespace fail {
|
||||
|
||||
/**
|
||||
* \class T32Register
|
||||
* T32-specific implementation of ?? registers. TODO.
|
||||
*/
|
||||
class T32Register : public Register {
|
||||
public:
|
||||
T32Register(unsigned int id, regwidth_t width, regdata_t* link, RegisterType t)
|
||||
: Register(id, t, width) { }
|
||||
regdata_t getData() { return 0; /* TODO */ }
|
||||
void setData(regdata_t data) { /* TODO */ }
|
||||
};
|
||||
|
||||
/**
|
||||
* \class T32RegisterManager
|
||||
* T32-specific implementation of the RegisterManager. TODO.
|
||||
*/
|
||||
class T32RegisterManager : public RegisterManager {
|
||||
public:
|
||||
address_t getInstructionPointer()
|
||||
{
|
||||
return static_cast<address_t>(0); /* TODO */
|
||||
}
|
||||
address_t getStackPointer()
|
||||
{
|
||||
return static_cast<address_t>(0); /* TODO */
|
||||
}
|
||||
address_t getBasePointer()
|
||||
{
|
||||
return static_cast<address_t>(0); /* TODO */
|
||||
}
|
||||
};
|
||||
|
||||
} // end-of-namespace: fail
|
||||
|
||||
#endif // __T32_REGISTER_HPP__
|
||||
Reference in New Issue
Block a user