Added timer/timeout-event support (+ event handler for addition, deletion and triggering).
git-svn-id: https://www4.informatik.uni-erlangen.de/i4svn/danceos/trunk/devel/fail@1244 8c4709b5-6ec9-48aa-a5cd-a96041d1645a
This commit is contained in:
@ -1,7 +1,10 @@
|
||||
#include <sstream>
|
||||
|
||||
#include "BochsController.hpp"
|
||||
#include "BochsMemory.hpp"
|
||||
#include "BochsRegister.hpp"
|
||||
#include "../Register.hpp"
|
||||
#include "../SALInst.hpp"
|
||||
|
||||
namespace sal
|
||||
{
|
||||
@ -94,8 +97,7 @@ void BochsController::onInstrPtrChanged(address_t instrPtr)
|
||||
fi::EventList::iterator it = m_EvList.begin();
|
||||
while(it != m_EvList.end())
|
||||
{
|
||||
// FIXME: Performance verbessern (dazu muss entsprechend auch die Speicherung
|
||||
// in EventList(.cc|.hpp) angepasst bzw. verbessert werden).
|
||||
// FIXME: Maybe we need to improve the performance of this check.
|
||||
fi::BPEvent* pEvBreakpt = dynamic_cast<fi::BPEvent*>(*it);
|
||||
if(pEvBreakpt && (instrPtr == pEvBreakpt->getWatchInstructionPointer() ||
|
||||
pEvBreakpt->getWatchInstructionPointer() == fi::ANY_ADDR))
|
||||
@ -184,4 +186,71 @@ void BochsController::fireInterruptDone()
|
||||
m_Flows.toggle(m_CurrFlow);
|
||||
}
|
||||
|
||||
void BochsController::m_onTimerTrigger(void* thisPtr)
|
||||
{
|
||||
// FIXME: The timer logic can be modified to use only one timer in Bochs.
|
||||
// (For now, this suffices.)
|
||||
fi::TimerEvent* pTmEv = static_cast<fi::TimerEvent*>(thisPtr);
|
||||
// Check for a matching TimerEvent. (In fact, we are only
|
||||
// interessted in the iterator pointing at pTmEv.):
|
||||
fi::EventList::iterator it = std::find(simulator.m_EvList.begin(),
|
||||
simulator.m_EvList.end(), pTmEv);
|
||||
// TODO: This has O(|m_EvList|) time complexity. We can further improve this
|
||||
// by creating a method such that makeActive(pTmEv) works as well,
|
||||
// reducing the time complexity to O(1).
|
||||
simulator.m_EvList.makeActive(it);
|
||||
simulator.m_EvList.fireActiveEvents();
|
||||
}
|
||||
|
||||
timer_id_t BochsController::m_registerTimer(fi::TimerEvent* pev)
|
||||
{
|
||||
assert(pev != NULL);
|
||||
return static_cast<timer_id_t>(
|
||||
bx_pc_system.register_timer(pev, m_onTimerTrigger, pev->getTimeout(), !pev->getOnceFlag(),
|
||||
1/*start immediately*/, "Fail*: BochsController"/*name*/));
|
||||
}
|
||||
|
||||
bool BochsController::m_unregisterTimer(fi::TimerEvent* pev)
|
||||
{
|
||||
assert(pev != NULL);
|
||||
bx_pc_system.deactivate_timer(static_cast<unsigned>(pev->getId()));
|
||||
return bx_pc_system.unregisterTimer(static_cast<unsigned>(pev->getId()));
|
||||
}
|
||||
|
||||
bool BochsController::onEventAddition(fi::BaseEvent* pev)
|
||||
{
|
||||
fi::TimerEvent* tmev;
|
||||
// Register the timer event in the Bochs simulator:
|
||||
if ((tmev = dynamic_cast<fi::TimerEvent*>(pev)) != NULL) {
|
||||
tmev->setId(m_registerTimer(tmev));
|
||||
if(tmev->getId() == -1)
|
||||
return false; // unable to register the timer (error in Bochs' function call)
|
||||
}
|
||||
// Note: Maybe more stuff to do here for other event types.
|
||||
return true;
|
||||
}
|
||||
|
||||
void BochsController::onEventDeletion(fi::BaseEvent* pev)
|
||||
{
|
||||
fi::TimerEvent* tmev;
|
||||
// Unregister the time event:
|
||||
if ((tmev = dynamic_cast<fi::TimerEvent*>(pev)) != NULL) {
|
||||
m_unregisterTimer(tmev);
|
||||
}
|
||||
// Note: Maybe more stuff to do here for other event types.
|
||||
}
|
||||
|
||||
void BochsController::onEventTrigger(fi::BaseEvent* pev)
|
||||
{
|
||||
fi::TimerEvent* tmev;
|
||||
// Unregister the time event, if once-flag is true:
|
||||
if ((tmev = dynamic_cast<fi::TimerEvent*>(pev)) != NULL) {
|
||||
if (tmev->getOnceFlag()) // deregister the timer (timer = single timeout)
|
||||
m_unregisterTimer(tmev);
|
||||
else // re-add the event (repetitive timer), tunneling the onEventAddition-handler
|
||||
m_EvList.add(tmev, tmev->getParent());
|
||||
}
|
||||
// Note: Maybe more stuff to do here for other event types.
|
||||
}
|
||||
|
||||
} // end-of-namespace: sal
|
||||
|
||||
@ -18,6 +18,7 @@
|
||||
#include "../../../bochs/cpu/cpu.h"
|
||||
#include "../../../bochs/config.h"
|
||||
#include "../../../bochs/iodev/iodev.h"
|
||||
#include "../../../bochs/pc_system.h"
|
||||
|
||||
using namespace std;
|
||||
|
||||
@ -34,31 +35,87 @@ namespace sal
|
||||
class BochsController : public SimulatorController
|
||||
{
|
||||
private:
|
||||
/**
|
||||
* stores the current flow for save/restore-operations
|
||||
*/
|
||||
fi::ExperimentFlow* m_CurrFlow;
|
||||
fi::ExperimentFlow* m_CurrFlow; //!< Stores the current flow for save/restore-operations
|
||||
#ifdef DEBUG
|
||||
unsigned m_Regularity;
|
||||
unsigned m_Counter;
|
||||
std::ostream* m_pDest;
|
||||
#endif
|
||||
/**
|
||||
* Static internal event handler for TimerEvents. This static function is
|
||||
* called when a previously registered (Bochs) timer triggers. This function
|
||||
* searches for the provided TimerEvent object within the EventList and
|
||||
* fires such an event by calling \c fireActiveEvents().
|
||||
* @param thisPtr a pointer to the TimerEvent-object triggered
|
||||
*
|
||||
* FIXME: Due to Bochs internal timer and ips-configuration related stuff,
|
||||
* the simulator sometimes panics with "keyboard error:21" (see line
|
||||
* 1777 in bios/rombios.c, function keyboard_init()) if a TimerEvent
|
||||
* is added *before* the bios has been loaded and initialized. To
|
||||
* reproduce this error, try adding a TimerEvent as the initial step
|
||||
* in your experiment code and wait for it (addEventAndWait()).
|
||||
*/
|
||||
static void m_onTimerTrigger(void *thisPtr);
|
||||
/**
|
||||
* Registers a timer in the Bochs simulator. This timer fires \a TimerEvents
|
||||
* to inform the corresponding experiment-flow. Note that the number of timers
|
||||
* (in Bochs) is limited to \c BX_MAX_TIMERS (defaults to 64 in v2.4.6).
|
||||
* @param pev a pointer to the (experiment flow-) allocated TimerEvent object,
|
||||
* providing all required information to start the time, e.g. the
|
||||
* timeout value.
|
||||
* @return \c The unique id of the timer recently created. This id is carried
|
||||
* along with the TimerEvent, @see getId(). On error, -1 is returned
|
||||
* (e.g. because a timer with the same id is already existing)
|
||||
*/
|
||||
timer_id_t m_registerTimer(fi::TimerEvent* pev);
|
||||
/**
|
||||
* Deletes a timer. No further events will be triggered by the timer.
|
||||
* @param pev a pointer to the TimerEvent-object to be removed
|
||||
* @return \c true if the timer with \a pev->getId() has been removed
|
||||
* successfully, \c false otherwise
|
||||
*/
|
||||
bool m_unregisterTimer(fi::TimerEvent* pev);
|
||||
public:
|
||||
// Initialize the controller.
|
||||
BochsController();
|
||||
~BochsController();
|
||||
/* ********************************************************************
|
||||
* Standard Event Handler API (SEH-API):
|
||||
* Standard Event Handler API:
|
||||
* ********************************************************************/
|
||||
/**
|
||||
* Instruction pointer modification handler. This method is called
|
||||
* (from the Breakpoints aspect) every time when the Bochs-internal IP
|
||||
* changes.
|
||||
* @param instrPtr
|
||||
* Instruction pointer modification handler. This method is called (from
|
||||
* the Breakpoints aspect) every time when the Bochs-internal IP changes.
|
||||
* @param instrPtr the new instruction pointer
|
||||
*/
|
||||
void onInstrPtrChanged(address_t instrPtr);
|
||||
/**
|
||||
* This method is called when an experiment flow adds a new event by
|
||||
* calling \c simulator.addEvent(pev) or \c simulator.addEventAndWait(pev).
|
||||
* More specifically, the event will be added to the event-list first
|
||||
* (buffer-list, to be precise) and then this event handler is called.
|
||||
* @param pev the event which has been added
|
||||
* @return You should return \c true to continue and \c false to prevent
|
||||
* the addition of the event \a pev.
|
||||
*/
|
||||
bool onEventAddition(fi::BaseEvent* pev);
|
||||
/**
|
||||
* This method is called when an experiment flow removes an event from
|
||||
* the event-management by calling \c removeEvent(prev), \c clearEvents()
|
||||
* or by deleting a complete flow (\c removeFlow). More specifically,
|
||||
* this event handler will be called *before* the event is actually deleted.
|
||||
* @param pev the event to be deleted when returning from the event handler
|
||||
*/
|
||||
void onEventDeletion(fi::BaseEvent* pev);
|
||||
/**
|
||||
* This method is called when an previously added event is about to be
|
||||
* triggered by the simulator-backend. More specifically, this event handler
|
||||
* will be called *before* the event is actually triggered, i.e. before the
|
||||
* corresponding coroutine is toggled.
|
||||
* @param pev the event to be triggered when returning from the event handler
|
||||
*/
|
||||
void onEventTrigger(fi::BaseEvent* pev);
|
||||
/* ********************************************************************
|
||||
* Simulator Controller & Access API (SCA-API):
|
||||
* Simulator Controller & Access API:
|
||||
* ********************************************************************/
|
||||
/**
|
||||
* Save simulator state.
|
||||
|
||||
Reference in New Issue
Block a user