Adding x86 I/O port communication capabilities (see IOPortEvent)
git-svn-id: https://www4.informatik.uni-erlangen.de/i4svn/danceos/trunk/devel/fail@1295 8c4709b5-6ec9-48aa-a5cd-a96041d1645a
This commit is contained in:
@ -117,6 +117,28 @@ void BochsController::onInstrPtrChanged(address_t instrPtr, address_t address_sp
|
|||||||
// implementation.
|
// implementation.
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void BochsController::onIOPortEvent(unsigned char data, unsigned port, bool out) {
|
||||||
|
// Check for active breakpoint-events:
|
||||||
|
fi::EventList::iterator it = m_EvList.begin();
|
||||||
|
while(it != m_EvList.end())
|
||||||
|
{
|
||||||
|
// FIXME: Maybe we need to improve the performance of this check.
|
||||||
|
fi::IOPortEvent* pIOPt = dynamic_cast<fi::IOPortEvent*>(*it);
|
||||||
|
if(pIOPt && pIOPt->isMatching(port, out))
|
||||||
|
{
|
||||||
|
pIOPt->setData(data);
|
||||||
|
it = m_EvList.makeActive(it);
|
||||||
|
// "it" has already been set to the next element (by calling
|
||||||
|
// makeActive()):
|
||||||
|
continue; // -> skip iterator increment
|
||||||
|
}
|
||||||
|
it++;
|
||||||
|
}
|
||||||
|
m_EvList.fireActiveEvents();
|
||||||
|
// Note: SimulatorController::onBreakpointEvent will not be invoked in this
|
||||||
|
// implementation.
|
||||||
|
}
|
||||||
|
|
||||||
void BochsController::save(const string& path)
|
void BochsController::save(const string& path)
|
||||||
{
|
{
|
||||||
int stat;
|
int stat;
|
||||||
|
|||||||
@ -86,9 +86,17 @@ class BochsController : public SimulatorController
|
|||||||
* Instruction pointer modification handler. This method is called (from
|
* Instruction pointer modification handler. This method is called (from
|
||||||
* the Breakpoints aspect) every time when the Bochs-internal IP changes.
|
* the Breakpoints aspect) every time when the Bochs-internal IP changes.
|
||||||
* @param instrPtr the new instruction pointer
|
* @param instrPtr the new instruction pointer
|
||||||
* @param address_space
|
* @param address_space the address space the CPU is currently in
|
||||||
*/
|
*/
|
||||||
void onInstrPtrChanged(address_t instrPtr, address_t address_space);
|
void onInstrPtrChanged(address_t instrPtr, address_t address_space);
|
||||||
|
/**
|
||||||
|
* I/O port communication handler. This method is called (from
|
||||||
|
* the IOPortCom aspect) every time when Bochs performs a port I/O operation.
|
||||||
|
* @param data the data transmitted
|
||||||
|
* @param port the port it was transmitted on
|
||||||
|
* @param out true if the I/O traffic has been outbound, false otherwise
|
||||||
|
*/
|
||||||
|
void onIOPortEvent(unsigned char data, unsigned port, bool out);
|
||||||
/**
|
/**
|
||||||
* This method is called when an experiment flow adds a new event by
|
* This method is called when an experiment flow adds a new event by
|
||||||
* calling \c simulator.addEvent(pev) or \c simulator.addEventAndWait(pev).
|
* calling \c simulator.addEvent(pev) or \c simulator.addEventAndWait(pev).
|
||||||
|
|||||||
38
core/SAL/bochs/IOPortCom.ah
Normal file
38
core/SAL/bochs/IOPortCom.ah
Normal file
@ -0,0 +1,38 @@
|
|||||||
|
#ifndef __IOPORT_COM_AH__
|
||||||
|
#define __IOPORT_COM_AH__
|
||||||
|
|
||||||
|
#include "config/FailConfig.hpp"
|
||||||
|
|
||||||
|
#ifdef CONFIG_EVENT_IOPORT
|
||||||
|
|
||||||
|
#include "../../../bochs/bochs.h"
|
||||||
|
#include "../../../bochs/cpu/cpu.h"
|
||||||
|
#include "../SALInst.hpp"
|
||||||
|
|
||||||
|
#include "bochs_helpers.hpp"
|
||||||
|
|
||||||
|
aspect IOPortCom
|
||||||
|
{
|
||||||
|
// ATM only capturing bytewise output (most common, I suppose)
|
||||||
|
pointcut outInstruction() = "% ...::bx_cpu_c::OUT_DXAL%(...)";
|
||||||
|
|
||||||
|
advice execution (outInstruction()) : after ()
|
||||||
|
{
|
||||||
|
unsigned rDX = getCPU(tjp->that())->gen_reg[2].word.rx; // port number
|
||||||
|
unsigned char rAL = getCPU(tjp->that())->gen_reg[0].word.byte.rl; // data
|
||||||
|
sal::simulator.onIOPortEvent(rAL, rDX, true);
|
||||||
|
}
|
||||||
|
|
||||||
|
pointcut inInstruction() = "% ...::bx_cpu_c::IN_ALDX%(...)";
|
||||||
|
|
||||||
|
advice execution (inInstruction()) : after ()
|
||||||
|
{
|
||||||
|
unsigned rDX = getCPU(tjp->that())->gen_reg[2].word.rx; // port number
|
||||||
|
unsigned char rAL = getCPU(tjp->that())->gen_reg[0].word.byte.rl; // data
|
||||||
|
sal::simulator.onIOPortEvent(rAL, rDX, false);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif // CONFIG_EVENT_IOPORT
|
||||||
|
|
||||||
|
#endif /* __IOPORT_COM_AH__ */
|
||||||
@ -6,6 +6,7 @@ OPTION(CONFIG_EVENT_BREAKPOINTS "Event source: Breakpoints" OFF)
|
|||||||
OPTION(CONFIG_EVENT_MEMREAD "Event source: Memory reads" OFF)
|
OPTION(CONFIG_EVENT_MEMREAD "Event source: Memory reads" OFF)
|
||||||
OPTION(CONFIG_EVENT_MEMWRITE "Event source: Memory writes" OFF)
|
OPTION(CONFIG_EVENT_MEMWRITE "Event source: Memory writes" OFF)
|
||||||
OPTION(CONFIG_EVENT_GUESTSYS "Event source: Outbound guest-system communication" OFF)
|
OPTION(CONFIG_EVENT_GUESTSYS "Event source: Outbound guest-system communication" OFF)
|
||||||
|
OPTION(CONFIG_EVENT_IOPORT "Event source: I/O port communication" OFF)
|
||||||
OPTION(CONFIG_EVENT_INTERRUPT "Event source: Interrupts" OFF)
|
OPTION(CONFIG_EVENT_INTERRUPT "Event source: Interrupts" OFF)
|
||||||
OPTION(CONFIG_EVENT_TRAP "Event source: Traps" OFF)
|
OPTION(CONFIG_EVENT_TRAP "Event source: Traps" OFF)
|
||||||
OPTION(CONFIG_EVENT_JUMP "Event source: Branch instructions" OFF)
|
OPTION(CONFIG_EVENT_JUMP "Event source: Branch instructions" OFF)
|
||||||
|
|||||||
@ -10,6 +10,7 @@
|
|||||||
#cmakedefine CONFIG_EVENT_MEMREAD
|
#cmakedefine CONFIG_EVENT_MEMREAD
|
||||||
#cmakedefine CONFIG_EVENT_MEMWRITE
|
#cmakedefine CONFIG_EVENT_MEMWRITE
|
||||||
#cmakedefine CONFIG_EVENT_GUESTSYS
|
#cmakedefine CONFIG_EVENT_GUESTSYS
|
||||||
|
#cmakedefine CONFIG_EVENT_IOPORT
|
||||||
#cmakedefine CONFIG_EVENT_INTERRUPT
|
#cmakedefine CONFIG_EVENT_INTERRUPT
|
||||||
#cmakedefine CONFIG_EVENT_TRAP
|
#cmakedefine CONFIG_EVENT_TRAP
|
||||||
#cmakedefine CONFIG_EVENT_JUMP
|
#cmakedefine CONFIG_EVENT_JUMP
|
||||||
|
|||||||
@ -477,6 +477,60 @@ class GuestEvent : virtual public BaseEvent
|
|||||||
void setPort(unsigned port) { m_Port = port; }
|
void setPort(unsigned port) { m_Port = port; }
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* \class IOPortEvent
|
||||||
|
* Observes I/O access on architectures with a separate I/O access mechanism (e.g. IA-32)
|
||||||
|
*/
|
||||||
|
class IOPortEvent : virtual public BaseEvent
|
||||||
|
{
|
||||||
|
private:
|
||||||
|
unsigned char m_Data;
|
||||||
|
unsigned m_Port;
|
||||||
|
bool m_Out;
|
||||||
|
public:
|
||||||
|
/**
|
||||||
|
* Initialises an IOPortEvent
|
||||||
|
*
|
||||||
|
* @param port the port the event ist listening on
|
||||||
|
* @param out Defines the direction of the event.
|
||||||
|
* \arg \c true Output on the given port is captured.
|
||||||
|
* \arg \c false Input on the given port is captured.
|
||||||
|
*/
|
||||||
|
IOPortEvent(unsigned port, bool out) : m_Data(0), m_Port(port), m_Out(out) { }
|
||||||
|
/**
|
||||||
|
* Returns the data sent to the specified port
|
||||||
|
*/
|
||||||
|
unsigned char getData() const { return (m_Data); }
|
||||||
|
/**
|
||||||
|
* Sets the data which had been transmitted.
|
||||||
|
*/
|
||||||
|
void setData(unsigned char data) { m_Data = data; }
|
||||||
|
/**
|
||||||
|
* Retrieves the port which this event is bound to.
|
||||||
|
*/
|
||||||
|
unsigned getPort() const { return (m_Port); }
|
||||||
|
/**
|
||||||
|
* Sets the port which this event is bound to.
|
||||||
|
*/
|
||||||
|
void setPort(unsigned port) { m_Port = port; }
|
||||||
|
/**
|
||||||
|
* Checks whether a given port number is matching.
|
||||||
|
* @param p The port number an I/O event occured on
|
||||||
|
* @param out True if the communication was outbound, false otherwise
|
||||||
|
*/
|
||||||
|
bool isMatching(unsigned p, bool out) const { return ( out = isOutEvent() && p == getPort()); }
|
||||||
|
/**
|
||||||
|
* Tells you if this event is capturing outbound communication (inbound if false)
|
||||||
|
*/
|
||||||
|
bool isOutEvent() const { return m_Out; }
|
||||||
|
/**
|
||||||
|
* Change the event direction.
|
||||||
|
* \arg \c true Output on the given port is captured.
|
||||||
|
* \arg \c false Input on the given port is captured.
|
||||||
|
*/
|
||||||
|
void setOut(bool out) { m_Out = out; }
|
||||||
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* \class JumpEvent
|
* \class JumpEvent
|
||||||
* JumpEvents are used to observe conditional jumps (if...else if...else).
|
* JumpEvents are used to observe conditional jumps (if...else if...else).
|
||||||
|
|||||||
@ -15,7 +15,7 @@
|
|||||||
#include "SAL/Memory.hpp"
|
#include "SAL/Memory.hpp"
|
||||||
#include "SAL/bochs/BochsRegister.hpp"
|
#include "SAL/bochs/BochsRegister.hpp"
|
||||||
#include "controller/Event.hpp"
|
#include "controller/Event.hpp"
|
||||||
#include "config/AspectConfig.hpp"
|
#include "config/FailConfig.hpp"
|
||||||
|
|
||||||
#include "l4sys.pb.h"
|
#include "l4sys.pb.h"
|
||||||
|
|
||||||
@ -24,9 +24,9 @@ using std::endl;
|
|||||||
// Check if configuration dependencies are satisfied:
|
// Check if configuration dependencies are satisfied:
|
||||||
#if !defined(CONFIG_EVENT_BREAKPOINTS) || !defined(CONFIG_SR_RESTORE) || \
|
#if !defined(CONFIG_EVENT_BREAKPOINTS) || !defined(CONFIG_SR_RESTORE) || \
|
||||||
!defined(CONFIG_SR_SAVE) || !defined(CONFIG_SUPPRESS_INTERRUPTS) || \
|
!defined(CONFIG_SR_SAVE) || !defined(CONFIG_SUPPRESS_INTERRUPTS) || \
|
||||||
!defined(CONFIG_EVENT_TRAP) || !defined(CONFIG_EVENT_GUESTSYS) || \
|
!defined(CONFIG_EVENT_TRAP) || !defined(CONFIG_EVENT_IOPORT) || \
|
||||||
!defined(CONFIG_EVENT_INTERRUPT)
|
!defined(CONFIG_EVENT_INTERRUPT)
|
||||||
#error This experiment needs: breakpoints, suppressed-interrupts, traps, guest system and interrupt events, \
|
#error This experiment needs: breakpoints, suppressed-interrupts, traps, I/O port and interrupt events, \
|
||||||
save, and restore. Enable these in the configuration.
|
save, and restore. Enable these in the configuration.
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
@ -56,17 +56,17 @@ std::string L4SysExperiment::sanitised(std::string in_str) {
|
|||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
fi::BaseEvent* L4SysExperiment::waitGuestOrOther(bool clear_output) {
|
fi::BaseEvent* L4SysExperiment::waitIOOrOther(bool clear_output) {
|
||||||
fi::GuestEvent ev_guest;
|
fi::IOPortEvent ev_ioport(0x3F8, true);
|
||||||
fi::BaseEvent* ev = NULL;
|
fi::BaseEvent* ev = NULL;
|
||||||
if (clear_output)
|
if (clear_output)
|
||||||
output.clear();
|
output.clear();
|
||||||
while (true) {
|
while (true) {
|
||||||
sal::simulator.addEvent(&ev_guest);
|
sal::simulator.addEvent(&ev_ioport);
|
||||||
ev = sal::simulator.waitAny();
|
ev = sal::simulator.waitAny();
|
||||||
sal::simulator.removeEvent(&ev_guest);
|
sal::simulator.removeEvent(&ev_ioport);
|
||||||
if (ev == &ev_guest) {
|
if (ev == &ev_ioport) {
|
||||||
output += ev_guest.getData();
|
output += ev_ioport.getData();
|
||||||
} else {
|
} else {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@ -149,7 +149,7 @@ bool L4SysExperiment::run() {
|
|||||||
bp.setWatchInstructionPointer(COOL_ECC_CALCDONE);
|
bp.setWatchInstructionPointer(COOL_ECC_CALCDONE);
|
||||||
bp.setCounter(times_run);
|
bp.setCounter(times_run);
|
||||||
sal::simulator.addEvent(&bp);
|
sal::simulator.addEvent(&bp);
|
||||||
fi::BaseEvent* ev = waitGuestOrOther(true);
|
fi::BaseEvent* ev = waitIOOrOther(true);
|
||||||
if (ev == &bp) {
|
if (ev == &bp) {
|
||||||
golden_run.assign(output.c_str());
|
golden_run.assign(output.c_str());
|
||||||
golden_run_file << output.c_str();
|
golden_run_file << output.c_str();
|
||||||
@ -206,7 +206,7 @@ bool L4SysExperiment::run() {
|
|||||||
bp.setWatchInstructionPointer(instr_list[instr_offset]);
|
bp.setWatchInstructionPointer(instr_list[instr_offset]);
|
||||||
sal::simulator.addEvent(&bp);
|
sal::simulator.addEvent(&bp);
|
||||||
//and log the output
|
//and log the output
|
||||||
waitGuestOrOther(true);
|
waitIOOrOther(true);
|
||||||
|
|
||||||
// inject
|
// inject
|
||||||
sal::RegisterManager& rm = sal::simulator.getRegisterManager();
|
sal::RegisterManager& rm = sal::simulator.getRegisterManager();
|
||||||
@ -254,7 +254,7 @@ bool L4SysExperiment::run() {
|
|||||||
sal::simulator.addEvent(&ev_intr);
|
sal::simulator.addEvent(&ev_intr);
|
||||||
|
|
||||||
//do not discard output recorded so far
|
//do not discard output recorded so far
|
||||||
fi::BaseEvent *ev = waitGuestOrOther(false);
|
fi::BaseEvent *ev = waitIOOrOther(false);
|
||||||
|
|
||||||
/* copying a string object that contains control sequences
|
/* copying a string object that contains control sequences
|
||||||
* unfortunately does not work with the library I am using,
|
* unfortunately does not work with the library I am using,
|
||||||
|
|||||||
@ -11,7 +11,7 @@ public:
|
|||||||
bool run();
|
bool run();
|
||||||
private:
|
private:
|
||||||
std::string sanitised(std::string in_str);
|
std::string sanitised(std::string in_str);
|
||||||
fi::BaseEvent* waitGuestOrOther(bool clear_output);
|
fi::BaseEvent* waitIOOrOther(bool clear_output);
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|||||||
Reference in New Issue
Block a user