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:
hoffmann
2013-02-15 18:06:02 +00:00
parent a7e5d2373f
commit 39a6415001
30 changed files with 439 additions and 201 deletions

View File

@ -51,7 +51,8 @@ elseif(BUILD_OVP)
elseif(BUILD_QEMU) elseif(BUILD_QEMU)
include_directories(simulators) include_directories(simulators)
elseif(BUILD_T32) elseif(BUILD_T32)
add_subdirectory(hwdebuggers/t32) include_directories(debuggers/t32/include src/core)
add_subdirectory(debuggers/t32)
endif(BUILD_BOCHS) endif(BUILD_BOCHS)
## Additional compiler and linker flags ## ## Additional compiler and linker flags ##

1
debuggers/gdb/README Normal file
View File

@ -0,0 +1 @@
TODO: a nice GDB backend.

View File

@ -91,7 +91,7 @@ extern struct hostent * gethostbyaddr();
# define FD_ISSET(fd,fdset) (*fdset & (1<<(fd))) # define FD_ISSET(fd,fdset) (*fdset & (1<<(fd)))
#endif #endif
#if defined(DEC_VMS) || defined(MS_WINDOWS) || defined(OS_9) || defined(LINUX) #if defined(DEC_VMS) || defined(MS_WINDOWS) || defined(OS_9) || defined(LINUX)
# define RECEIVEADDR (&ReceiveSocketAddress) # define RECEIVEADDR (&ReceiveSocketAddress)
static struct sockaddr ReceiveSocketAddress; static struct sockaddr ReceiveSocketAddress;
#else #else
@ -106,7 +106,7 @@ struct LineStruct {
unsigned short ReceivePort; /* Receiver Port */ unsigned short ReceivePort; /* Receiver Port */
unsigned short TransmitPort; /* Transmitter Port in T32 */ unsigned short TransmitPort; /* Transmitter Port in T32 */
int PacketSize; /* Max. size of UDP-packet data */ int PacketSize; /* Max. size of UDP-packet data */
int PollTimeSec; int PollTimeSec;
int ReceiveToggleBit; int ReceiveToggleBit;
unsigned char MessageId; unsigned char MessageId;
int LineUp; int LineUp;
@ -227,28 +227,28 @@ int LINE_LineConfig(char * in)
} }
if (!strncmp((char *) in, "PORT=", 5)) { if (!strncmp((char *) in, "PORT=", 5)) {
x = str2dec (in+5); x = str2dec (in+5);
if (x == -1) if (x == -1)
return -1; return -1;
line->TransmitPort = x; line->TransmitPort = x;
return 1; return 1;
} }
if (!strncmp((char *) in, "HOSTPORT=", 9)) { if (!strncmp((char *) in, "HOSTPORT=", 9)) {
x = str2dec (in+9); x = str2dec (in+9);
if (x == -1) if (x == -1)
return -1; return -1;
line->HostPort = x; line->HostPort = x;
return 1; return 1;
} }
if (!strncmp((char *) in, "PACKLEN=", 8)) { if (!strncmp((char *) in, "PACKLEN=", 8)) {
x = str2dec (in+8); x = str2dec (in+8);
if (x == -1) if (x == -1)
return -1; return -1;
line->PacketSize = x; line->PacketSize = x;
return 1; return 1;
} }
if (!strncmp((char *) in, "TIMEOUT=", 8)) { if (!strncmp((char *) in, "TIMEOUT=", 8)) {
x = str2dec (in+8); x = str2dec (in+8);
if (x == -1) if (x == -1)
return -1; return -1;
line->PollTimeSec = x; line->PollTimeSec = x;
return 1; return 1;
@ -353,7 +353,7 @@ void LINE_LineExit(void)
if (line->CommSocket != -1) { if (line->CommSocket != -1) {
for (i = 0; i < 5; i++) for (i = 0; i < 5; i++)
sendto(line->CommSocket, (char *) discon, 16, 0, sendto(line->CommSocket, (char *) discon, 16, 0,
(struct sockaddr *) &(line->SocketAddress), sizeof(line->SocketAddress)); (struct sockaddr *) &(line->SocketAddress), sizeof(line->SocketAddress));
#ifdef MS_WINDOWS #ifdef MS_WINDOWS
@ -516,7 +516,7 @@ void T32_UnInstallAsyncSelect(HWND hwnd)
/** /**
Sends a message to T32. Handles segmentation of _message_ into (one Sends a message to T32. Handles segmentation of _message_ into (one
or multiple) _packages_. or multiple) _packages_.
@param in pointer to outgoing message (already includes 5 byte message header) @param in pointer to outgoing message (already includes 5 byte message header)
@param size size of message @param size size of message
@note the message must be allocated such that there is space in @note the message must be allocated such that there is space in
@ -533,11 +533,11 @@ int LINE_LineTransmit(unsigned char * in, int size)
line->LastTransmitSize = size; line->LastTransmitSize = size;
line->LastTransmitSeq = line->TransmitSeq; line->LastTransmitSeq = line->TransmitSeq;
in -= 4; /* space for packet header */ in -= 4; /* space for packet header */
do { do {
packetSize = (size > line->PacketSize - 4) ? line->PacketSize - 4 : size; packetSize = (size > line->PacketSize - 4) ? line->PacketSize - 4 : size;
/* When sending multiple packets, the packet header is written inside the /* When sending multiple packets, the packet header is written inside the
message's payload. Original contents needs to be saved/restored */ message's payload. Original contents needs to be saved/restored */
SETLONGVAR(tmpl, in[0]); /* save */ SETLONGVAR(tmpl, in[0]); /* save */
@ -547,7 +547,7 @@ int LINE_LineTransmit(unsigned char * in, int size)
SETWORDVAR(in[2], line->TransmitSeq); /* packet sequence ID */ SETWORDVAR(in[2], line->TransmitSeq); /* packet sequence ID */
if (sendto(line->CommSocket, if (sendto(line->CommSocket,
(char *) in, (char *) in,
packetSize + 4, 0, packetSize + 4, 0,
(struct sockaddr *) & line->SocketAddress, sizeof(line->SocketAddress) (struct sockaddr *) & line->SocketAddress, sizeof(line->SocketAddress)
) != packetSize + 4) { ) != packetSize + 4) {
@ -576,9 +576,9 @@ static int ReceiveWithTimeout(struct timeval *tim, unsigned char *dest, int size
socklen_t length; socklen_t length;
struct timeval timeout; struct timeval timeout;
LineStruct* line = pLineParams; LineStruct* line = pLineParams;
timeout = *tim; timeout = *tim;
#ifdef POLL_NET #ifdef POLL_NET
DWORD endpoll; DWORD endpoll;
static struct timeval tival = {0}; static struct timeval tival = {0};
@ -657,11 +657,11 @@ retry:
/* multiple packets are merged in-place: backup data that is /* multiple packets are merged in-place: backup data that is
overwritten package aby header */ overwritten package aby header */
SETLONGVAR(tmpl, dest[0]); SETLONGVAR(tmpl, dest[0]);
do { do {
struct timeval PollTime = {0, 0}; struct timeval PollTime = {0, 0};
PollTime.tv_sec = line->PollTimeSec; PollTime.tv_sec = line->PollTimeSec;
if ((i = ReceiveWithTimeout(&PollTime, dest, line->PacketSize)) <= 0) { if ((i = ReceiveWithTimeout(&PollTime, dest, line->PacketSize)) <= 0) {
if (i == -2) if (i == -2)
goto retry; goto retry;
@ -670,17 +670,17 @@ retry:
if (i <= 4) { if (i <= 4) {
return -1; return -1;
} }
/* Detect and enqeue async notification that slipped into a request/reply pair */ /* Detect and enqeue async notification that slipped into a request/reply pair */
if (dest[0] == T32_API_NOTIFICATION) if (dest[0] == T32_API_NOTIFICATION)
{ {
T32_NotificationPackage *newPackage, *oldHead; T32_NotificationPackage *newPackage, *oldHead;
newPackage = reinterpret_cast<T32_NotificationPackage*>( malloc(sizeof(T32_NotificationPackage)) ); newPackage = reinterpret_cast<T32_NotificationPackage*>( malloc(sizeof(T32_NotificationPackage)) );
if (newPackage==NULL) if (newPackage==NULL)
return -1; return -1;
memcpy(newPackage, dest, i); /* in theory i should always be the package size, at least for ethernet */ memcpy(newPackage, dest, i); /* in theory i should always be the package size, at least for ethernet */
oldHead = T32_NotificationHead; oldHead = T32_NotificationHead;
newPackage->prev = NULL; newPackage->prev = NULL;
@ -693,12 +693,12 @@ retry:
} }
goto retry; goto retry;
} }
if (dest[0] != T32_API_RECEIVE) { if (dest[0] != T32_API_RECEIVE) {
return -1; return -1;
} }
SETWORDVAR(tmpw, dest[2]); SETWORDVAR(tmpw, dest[2]);
if (tmpw == line->LastReceiveSeq && line->LastTransmitSize) { if (tmpw == line->LastReceiveSeq && line->LastTransmitSize) {
line->TransmitSeq = line->LastTransmitSeq; line->TransmitSeq = line->LastTransmitSeq;
LINE_LineTransmit(line->LastTransmitBuffer, line->LastTransmitSize); LINE_LineTransmit(line->LastTransmitBuffer, line->LastTransmitSize);
@ -736,7 +736,7 @@ retry:
function until it returns -1. function until it returns -1.
@param package output buffer of size T32_PCKLEN_MAX for the package @param package output buffer of size T32_PCKLEN_MAX for the package
@return -1 no notification pending, @return -1 no notification pending,
>=0 notificataion type T32_E_BREAK, T32_E_EDIT, T32_E_BREAKPOINTCONFIG >=0 notificataion type T32_E_BREAK, T32_E_EDIT, T32_E_BREAKPOINTCONFIG
*/ */
@ -746,7 +746,7 @@ int LINE_ReceiveNotifyMessage(unsigned char* package)
{ {
int len; int len;
static struct timeval LongTime = {0, 0}; static struct timeval LongTime = {0, 0};
/* Check for asynchronous notifications */ /* Check for asynchronous notifications */
if (T32_NotificationTail) { if (T32_NotificationTail) {
T32_NotificationPackage *prev = T32_NotificationTail->prev; T32_NotificationPackage *prev = T32_NotificationTail->prev;
@ -762,10 +762,10 @@ int LINE_ReceiveNotifyMessage(unsigned char* package)
if (len < 2) if (len < 2)
return -1; return -1;
} }
if (package[0] != T32_API_NOTIFICATION) if (package[0] != T32_API_NOTIFICATION)
return -1; return -1;
return package[1]; /* type of notification: T32_E_BREAK, T32_E_EDIT, T32_E_BREAKPOINTCONFIG */ return package[1]; /* type of notification: T32_E_BREAK, T32_E_EDIT, T32_E_BREAKPOINTCONFIG */
} }
@ -811,7 +811,7 @@ retry:
line->LastReceiveSeq = line->ReceiveSeq - 100; line->LastReceiveSeq = line->ReceiveSeq - 100;
packet[0] = T32_API_SYNCBACK; packet[0] = T32_API_SYNCBACK;
packet[1] = 0; packet[1] = 0;
SETWORDVAR(packet[2], line->TransmitSeq); SETWORDVAR(packet[2], line->TransmitSeq);
SETWORDCONST(packet[4], 0); SETWORDCONST(packet[4], 0);

View File

@ -1,3 +1,5 @@
#ifndef __T32_H__
#define __T32_H__
#include <config/VariantConfig.hpp> #include <config/VariantConfig.hpp>
@ -120,14 +122,14 @@ typedef unsigned int dword;
/* Callbacks should have the following protoypes */ /* Callbacks should have the following protoypes */
/************************* WARNING *****************************/ /************************* WARNING *****************************/
/* /*
* If you add more callback functions here, make sure you ONLY * If you add more callback functions here, make sure you ONLY
* use 'int', 'unsigned int', 'integral-type *' or 'float-type *' as parameters. * use 'int', 'unsigned int', 'integral-type *' or 'float-type *' as parameters.
* *
* No 'long', no 'long long', no 'short', no 'char', no floats, no typedefs * No 'long', no 'long long', no 'short', no 'char', no floats, no typedefs
* and no function pointers! * and no function pointers!
* This is because we absolutely need to avoid portability problems here. * This is because we absolutely need to avoid portability problems here.
* *
* Explanation: * Explanation:
* The T32_NotificationCallback_t typedef'd below has an empty parameter list, * The T32_NotificationCallback_t typedef'd below has an empty parameter list,
* which we can't change anymore to a va_list because of backwards compatibility. * which we can't change anymore to a va_list because of backwards compatibility.
@ -360,3 +362,5 @@ extern void* T32_GetChannel0(void);
#ifdef __cplusplus #ifdef __cplusplus
} }
#endif #endif
#endif

View File

@ -1,5 +1,5 @@
set(SRCS set(SRCS
t32connector.cc T32Connector.cc
) )
add_executable(fail-client ${SRCS}) add_executable(fail-client ${SRCS})
@ -7,3 +7,5 @@ target_link_libraries(fail-client -Wl,-whole-archive t32api -Wl,-no-whole-archiv
install(TARGETS fail-client RUNTIME DESTINATION bin) install(TARGETS fail-client RUNTIME DESTINATION bin)
add_executable(t32cli t32cli.cc)
target_link_libraries(t32cli -Wl,-whole-archive t32api -Wl,-no-whole-archive)

View File

@ -0,0 +1,61 @@
/**
* 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>
#include "config/VariantConfig.hpp"
#include "sal/SALInst.hpp"
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 the SimulatorController do the dirty work.
fail::simulator.startup();
return 0;
}

View 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__

BIN
doc/t32_remote_api.pdf Normal file

Binary file not shown.

View File

@ -60,8 +60,12 @@ elseif(BUILD_T32)
Register.cc Register.cc
SimulatorController.cc SimulatorController.cc
t32/T32Controller.cc t32/T32Controller.cc
t32/wrappers.cc
) )
if(BUILD_ARM)
set(SRCS ${SRCS}
t32/T32ArmCPU.cc
)
endif(BUILD_ARM)
endif(BUILD_BOCHS) endif(BUILD_BOCHS)
if(BUILD_X86) if(BUILD_X86)

View File

@ -15,6 +15,11 @@
#include "qemu/QEMUConfig.hpp" #include "qemu/QEMUConfig.hpp"
#elif defined BUILD_T32 #elif defined BUILD_T32
#include "t32/T32Config.hpp" #include "t32/T32Config.hpp"
#if defined BUILD_ARM
#include "t32/T32ArmCPU.hpp"
#else
#error Active config currently not supported!
#endif
#else #else
#error SAL Config Target not defined #error SAL Config Target not defined
#endif #endif

View File

@ -10,7 +10,7 @@ namespace fail {
/** /**
* \class Gem5ArmCPU * \class Gem5ArmCPU
* *
* \c Gem5ArmCPU is the concrete CPU implementation for the gem5 ARM simulator. It * \c Gem5ArmCPU is the concrete CPU implementation for the gem5 ARM simulator. It
* implements the CPU interfaces \c ArmArchitecture and \c ArmCPUState. * implements the CPU interfaces \c ArmArchitecture and \c ArmCPUState.
* \c ArmArchitecture refers to architectural information (e.g. register \a count) * \c ArmArchitecture refers to architectural information (e.g. register \a count)

View File

@ -10,7 +10,7 @@ namespace fail {
/** /**
* \class Gem5Controller * \class Gem5Controller
* *
* Gem5-specific implementation of a SimulatorController. * Gem5-specific implementation of a SimulatorController.
*/ */
class Gem5Controller : public SimulatorController { class Gem5Controller : public SimulatorController {

View File

@ -19,7 +19,7 @@ namespace fail {
class Gem5MemoryManager : public MemoryManager { class Gem5MemoryManager : public MemoryManager {
public: public:
Gem5MemoryManager(System* system) : m_System(system), m_Mem(&system->getPhysMem()) { } Gem5MemoryManager(System* system) : m_System(system), m_Mem(&system->getPhysMem()) { }
size_t getPoolSize() const { return m_Mem->totalSize(); } size_t getPoolSize() const { return m_Mem->totalSize(); }
host_address_t getStartAddr() const { return 0; } host_address_t getStartAddr() const { return 0; }

View 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

View 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__

View File

@ -1,6 +1,6 @@
/** /**
* \brief Type definitions and configuration settings for the * \brief Type definitions and configuration settings for the
* T32 target backend. * T32 target backend.
*/ */
#ifndef __T32_CONFIG_HPP__ #ifndef __T32_CONFIG_HPP__
@ -13,7 +13,8 @@ namespace fail {
typedef uint32_t guest_address_t; //!< the guest memory address type typedef uint32_t guest_address_t; //!< the guest memory address type
typedef unsigned char* host_address_t; //!< the host 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 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 } // end-of-namespace: fail

View 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.
}

View 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__

View File

@ -1,23 +1,26 @@
#include <sstream>
#include "T32Controller.hpp" #include "T32Controller.hpp"
#include "T32Memory.hpp" #include "T32Connector.hpp"
#include "T32Register.hpp"
#include "../Register.hpp" #include "../Listener.hpp"
#include "../SALInst.hpp"
namespace fail { namespace fail {
T32Controller::T32Controller() void T32Controller::startup(){
: SimulatorController(new T32RegisterManager(), new T32MemoryManager()) // Do some T32-specific startup
{ addCPU(new ConcreteCPU(0));
// TODO: probably do additional RegisterManager initializations // Startup generic SimulatorController
SimulatorController::startup();
} }
T32Controller::~T32Controller() T32Controller::~T32Controller()
{ {
delete m_Regs; std::vector<ConcreteCPU*>::iterator it = m_CPUs.begin();
delete m_Mem; while (it != m_CPUs.end()) {
delete *it;
it = m_CPUs.erase(it);
}
} }

View File

@ -1,27 +1,18 @@
#ifndef __T32_CONTROLLER_HPP__ #ifndef __T32_CONTROLLER_HPP__
#define __T32_CONTROLLER_HPP__ #define __T32_CONTROLLER_HPP__
#include <string>
#include <cassert>
#include <iostream>
#include <iomanip>
#include <string.h>
#include "../SimulatorController.hpp" #include "../SimulatorController.hpp"
#include "T32Memory.hpp"
namespace fail { namespace fail {
class ExperimentFlow;
class TimerListener;
/** /**
* \class T32Controller * \class T32Controller
* Very rudimentary, T32-specific implementation of a SimulatorController. * Very rudimentary, T32-specific implementation of a SimulatorController.
*/ */
class T32Controller : public SimulatorController { class T32Controller : public SimulatorController {
public: public:
// Initialize the controller. void startup();
T32Controller();
~T32Controller(); ~T32Controller();
@ -29,8 +20,7 @@ public:
* Simulator Controller & Access API: * Simulator Controller & Access API:
* ********************************************************************/ * ********************************************************************/
/** /**
* Save simulator state. Quite hard on real hardware! Also safe all * Save simulator state. Quite hard on real hardware! Also safe all HW registers! TODO
* HW registers!
* @param path Location to store state information * @param path Location to store state information
* @return \c true if the state has been successfully saved, \c false otherwise * @return \c true if the state has been successfully saved, \c false otherwise
*/ */

View File

@ -1,8 +1,8 @@
#ifndef __T32LISTENER_AH__ #ifndef __T32LISTENER_AH__
#define __T32LISTENER_AH__ #define __T32LISTENER_AH__
#include "config/VariantConfig.hpp"
#include "config/FailConfig.hpp" #include "config/FailConfig.hpp"
#include "config/VariantConfig.hpp"
#if defined(BUILD_T32) && defined(CONFIG_EVENT_BREAKPOINTS) #if defined(BUILD_T32) && defined(CONFIG_EVENT_BREAKPOINTS)
@ -10,23 +10,22 @@
aspect T32Listener aspect T32Listener
advice "fail::MemWriteListener" : slice class advice "fail::BPSingleListener" : slice class
{ {
public: public:
bool onAddition() bool onAddition()
{ {
//std::cout << "T32MemWriteListener::onAddition" << std::endl;
//if (failqemu_add_watchpoint(simulator.m_cpuenv, m_WatchAddr, m_WatchWidth, 1) != 0) { // Setup Breakpoint in T32
// std::cout << "adding watchpoint failed!" << std::endl; std::cout << "T32Listener::onAddition" << std::endl;
return false;
//}
//return true; return true;
} }
void onDeletion() void onDeletion()
{ {
//std::cout << "T32MemWriteListener::onDeletion" << std::endl; // Delete Breakpoint in T32
//failqemu_remove_watchpoint(simulator.m_cpuenv, m_WatchAddr, m_WatchWidth, 1);
} }
}; };
}; };

View File

@ -3,6 +3,8 @@
#include "../Memory.hpp" #include "../Memory.hpp"
#include <t32.h>
namespace fail { namespace fail {
/** /**
@ -11,29 +13,44 @@ namespace fail {
* MemoryManager to provide access to T32's memory pool. * MemoryManager to provide access to T32's memory pool.
*/ */
class T32MemoryManager : public MemoryManager { class T32MemoryManager : public MemoryManager {
enum ACCESS_CLASS {
data_access = 0,
program_access = 1,
AD_access = 12,
AP_access = 13,
USR_access = 15,
};
public: public:
size_t getPoolSize() const { return 0; /* TODO */ } size_t getPoolSize() const { return 0; /* TODO */ }
host_address_t getStartAddr() const { return 0; } host_address_t getStartAddr() const { return 0; }
byte_t getByte(guest_address_t addr) 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) void getBytes(guest_address_t addr, size_t cnt, void *dest)
{ {
char *d = static_cast<char *>(dest); int access = data_access; // TODO what access class do we need?!
for (size_t i = 0; i < cnt; ++i) T32_ReadMemory( addr, access, (byte*)(dest), cnt);
d[i] = 0; //getByte(addr + i);
} }
void setByte(guest_address_t addr, byte_t data) 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) void setBytes(guest_address_t addr, size_t cnt, void const *src)
{ {
//char const *s = static_cast<char const *>(src); int access = data_access; // TODO what access class do we really need?!
for (size_t i = 0; i < cnt; ++i) T32_WriteMemory(addr, access, (byte*)(src), cnt);
; //setByte(addr + i, s[i]);
} }
}; };
} // end-of-namespace: fail } // end-of-namespace: fail

View 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__

View File

@ -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__

View File

@ -14,83 +14,24 @@
#include "sal/Memory.hpp" #include "sal/Memory.hpp"
#include "sal/Listener.hpp" #include "sal/Listener.hpp"
#include "sal/bochs/BochsListener.hpp"
#include <string> #include <string>
using namespace std; using namespace std;
using namespace fail; using namespace fail;
// Check if configuration dependencies are satisfied:
#if !defined(CONFIG_EVENT_BREAKPOINTS) || !defined(CONFIG_SR_RESTORE) || \
!defined(CONFIG_SR_SAVE)
#error This experiment needs: breakpoints, traps, save, and restore. Enable these in the configuration.
#endif
#define SAVESTATE (0)
void VEZSExperiment::printEIP() {
m_log << "EIP = 0x" << hex << simulator.getCPU(0).getInstructionPointer() <<" "<< m_elf.getNameByAddress(simulator.getCPU(0).getInstructionPointer()) << endl;
}
std::vector<string> v;
bool VEZSExperiment::run() bool VEZSExperiment::run()
{ {
m_log << "STARTING EXPERIMENT" << endl; m_log << "STARTING EXPERIMENT" << endl;
printEIP(); m_log << "Instruction Pointer: 0x" << hex << simulator.getCPU(0).getInstructionPointer() << endl;
#if(SAVESTATE) Register* reg = simulator.getCPU(0).getRegister(RI_R1);
m_log << "Booting, and saving state at "; m_log << "Register R2: 0x" << hex << simulator.getCPU(0).getRegisterContent(reg) << endl;
BPSingleListener bp;
// STEP 1: run until interesting function starts, and save state reg = simulator.getCPU(0).getRegister(RI_R2);
bp.setWatchInstructionPointer(m_elf.getAddressByName("main")); m_log << "Register R1: 0x" << hex << simulator.getCPU(0).getRegisterContent(reg) << endl;
if(simulator.addListenerAndResume(&bp) == &bp){
m_log << "test function entry reached, saving state" << endl; simulator.getCPU(0).setRegisterContent(reg, 0x23);
} // Explicitly terminate, or the simulator will continue to run.
printEIP();
//simulator.terminate();
simulator.save("vezs.state");
simulator.terminate(); simulator.terminate();
#else
simulator.restore("vezs.state");
//m_elf.printDemangled();
BPSingleListener bpt0;
BPSingleListener bpt1;
BPSingleListener bpt2;
//BPSingleListener inst(ANY_ADDR);
//bpt0.setWatchInstructionPointer(m_elf.getAddressByName("c17_Main_m4_dumpResults_console"));
//bpt0.setWatchInstructionPointer(m_elf.getAddressByName("keso_throw_error"));
//bpt1.setWatchInstructionPointer(m_elf.getAddressByName("c17_Main_m3_run"));
bpt2.setWatchInstructionPointer(m_elf.getAddressByName("os::krn::OSControl::shutdownOS"));
//simulator.addListener(&bpt0);
//simulator.addListener(&bpt1);
//simulator.addListener(&bpt2);
simulator.addListener(&bpt2);
fail::BaseListener* l = simulator.resume();
printEIP();
simulator.terminate();
while(1){
if(simulator.getCPU(0).getInstructionPointer() == m_elf.getAddressByName("os::krn::OSControl::shutdownOS")) {
printEIP();
break;
}else{
//std::string name = m_elf.getNameByAddress(simulator.getCPU(0).getInstructionPointer());
//if(name != ElfReader::NOTFOUND){
// v.push_back(name);
//}
printEIP();
l = simulator.addListenerAndResume(l);
}
}
// simulator.clearListeners();
// bpt1.setWatchInstructionPointer(m_elf.getAddressByName("os::krn::SchedImpl::superDispatch_impl"));
// for(;;){
// simulator.addListenerAndResume(&bpt1);
// printEIP();
// }
// Explicitly terminate, or the simulator will continue to run.
#endif
simulator.terminate();
} }

View File

@ -1,19 +1,15 @@
#ifndef __CHECKSUM_OOSTUBS_EXPERIMENT_HPP__ #ifndef __CHECKSUM_OOSTUBS_EXPERIMENT_HPP__
#define __CHECKSUM_OOSTUBS_EXPERIMENT_HPP__ #define __CHECKSUM_OOSTUBS_EXPERIMENT_HPP__
#include "efw/ExperimentFlow.hpp" #include "efw/ExperimentFlow.hpp"
#include "efw/JobClient.hpp" #include "efw/JobClient.hpp"
#include "util/Logger.hpp" #include "util/Logger.hpp"
#include "util/ElfReader.hpp"
class VEZSExperiment : public fail::ExperimentFlow { class VEZSExperiment : public fail::ExperimentFlow {
fail::JobClient m_jc; fail::JobClient m_jc;
fail::ElfReader m_elf;
fail::Logger m_log; fail::Logger m_log;
void printEIP();
public: public:
VEZSExperiment() : m_log("VEZS-example", false) {}; VEZSExperiment() : m_log("VEZS-example", false) {};
bool run(); bool run();