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

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

View File

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

View File

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

View File

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

View File

@ -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; }

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
* 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

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 "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);
}
}

View File

@ -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
*/

View File

@ -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
}
};
};

View File

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

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/Listener.hpp"
#include "sal/bochs/BochsListener.hpp"
#include <string>
using namespace std;
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()
{
m_log << "STARTING EXPERIMENT" << endl;
printEIP();
m_log << "Instruction Pointer: 0x" << hex << simulator.getCPU(0).getInstructionPointer() << endl;
#if(SAVESTATE)
m_log << "Booting, and saving state at ";
BPSingleListener bp;
// STEP 1: run until interesting function starts, and save state
bp.setWatchInstructionPointer(m_elf.getAddressByName("main"));
if(simulator.addListenerAndResume(&bp) == &bp){
m_log << "test function entry reached, saving state" << endl;
}
printEIP();
//simulator.terminate();
simulator.save("vezs.state");
Register* reg = simulator.getCPU(0).getRegister(RI_R1);
m_log << "Register R2: 0x" << hex << simulator.getCPU(0).getRegisterContent(reg) << endl;
reg = simulator.getCPU(0).getRegister(RI_R2);
m_log << "Register R1: 0x" << hex << simulator.getCPU(0).getRegisterContent(reg) << endl;
simulator.getCPU(0).setRegisterContent(reg, 0x23);
// Explicitly terminate, or the simulator will continue to run.
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__
#define __CHECKSUM_OOSTUBS_EXPERIMENT_HPP__
#include "efw/ExperimentFlow.hpp"
#include "efw/JobClient.hpp"
#include "util/Logger.hpp"
#include "util/ElfReader.hpp"
class VEZSExperiment : public fail::ExperimentFlow {
fail::JobClient m_jc;
fail::ElfReader m_elf;
fail::Logger m_log;
void printEIP();
public:
VEZSExperiment() : m_log("VEZS-example", false) {};
bool run();