Fail* directories reorganized, Code-cleanup (-> coding-style), Typos+comments fixed.
git-svn-id: https://www4.informatik.uni-erlangen.de/i4svn/danceos/trunk/devel/fail@1321 8c4709b5-6ec9-48aa-a5cd-a96041d1645a
This commit is contained in:
25
src/core/sal/bochs/BochsConfig.hpp
Normal file
25
src/core/sal/bochs/BochsConfig.hpp
Normal file
@ -0,0 +1,25 @@
|
||||
/**
|
||||
* \brief Type definitions and configuration settings for
|
||||
* the Bochs simulator.
|
||||
*/
|
||||
|
||||
#ifndef __BOCHS_CONFIG_HPP__
|
||||
#define __BOCHS_CONFIG_HPP__
|
||||
|
||||
#include "bochs.h"
|
||||
#include "config.h"
|
||||
|
||||
namespace fail {
|
||||
|
||||
typedef bx_address guest_address_t; //!< the guest memory address type
|
||||
typedef Bit8u* host_address_t; //!< the host memory address type
|
||||
#if BX_SUPPORT_X86_64
|
||||
typedef Bit64u register_data_t; //!< register data type (64 bit)
|
||||
#else
|
||||
typedef Bit32u register_data_t; //!< register data type (32 bit)
|
||||
#endif
|
||||
typedef int timer_t; //!< type of timer IDs
|
||||
|
||||
} // end-of-namespace: fail
|
||||
|
||||
#endif // __BOCHS_CONFIG_HPP__
|
||||
322
src/core/sal/bochs/BochsController.cc
Normal file
322
src/core/sal/bochs/BochsController.cc
Normal file
@ -0,0 +1,322 @@
|
||||
#include <sstream>
|
||||
|
||||
#include "BochsController.hpp"
|
||||
#include "BochsMemory.hpp"
|
||||
#include "BochsRegister.hpp"
|
||||
#include "../Register.hpp"
|
||||
#include "../SALInst.hpp"
|
||||
|
||||
namespace fail {
|
||||
|
||||
#ifdef DANCEOS_RESTORE
|
||||
bx_bool restore_bochs_request = false;
|
||||
bx_bool save_bochs_request = false;
|
||||
std::string sr_path = "";
|
||||
#endif
|
||||
|
||||
bx_bool reboot_bochs_request = false;
|
||||
bx_bool interrupt_injection_request = false;
|
||||
int interrupt_to_fire = -1;
|
||||
|
||||
BochsController::BochsController()
|
||||
: SimulatorController(new BochsRegisterManager(), new BochsMemoryManager())
|
||||
{
|
||||
// -------------------------------------
|
||||
// Add the general purpose register:
|
||||
#if BX_SUPPORT_X86_64
|
||||
// -- 64 bit register --
|
||||
const std::string names[] = { "RAX", "RCX", "RDX", "RBX", "RSP", "RBP", "RSI",
|
||||
"RDI", "R8", "R9", "R10", "R11", "R12", "R13",
|
||||
"R14", "R15" };
|
||||
for(unsigned short i = 0; i < 16; i++)
|
||||
{
|
||||
BxGPReg* pReg = new BxGPReg(i, 64, &(BX_CPU(0)->gen_reg[i].rrx));
|
||||
pReg->setName(names[i]);
|
||||
m_Regs->add(pReg);
|
||||
}
|
||||
#else
|
||||
// -- 32 bit register --
|
||||
const std::string names[] = { "EAX", "ECX", "EDX", "EBX", "ESP", "EBP", "ESI",
|
||||
"EDI" };
|
||||
for(unsigned short i = 0; i < 8; i++)
|
||||
{
|
||||
BxGPReg* pReg = new BxGPReg(i, 32, &(BX_CPU(0)->gen_reg[i].dword.erx));
|
||||
pReg->setName(names[i]);
|
||||
m_Regs->add(pReg);
|
||||
}
|
||||
#endif // BX_SUPPORT_X86_64
|
||||
#ifdef DEBUG
|
||||
m_Regularity = 0; // disabled
|
||||
m_Counter = 0;
|
||||
m_pDest = NULL;
|
||||
#endif
|
||||
// -------------------------------------
|
||||
// Add the Program counter register:
|
||||
#if BX_SUPPORT_X86_64
|
||||
BxPCReg* pPCReg = new BxPCReg(RID_PC, 64, &(BX_CPU(0)->gen_reg[BX_64BIT_REG_RIP].rrx));
|
||||
pPCReg->setName("RIP");
|
||||
#else
|
||||
BxPCReg* pPCReg = new BxPCReg(RID_PC, 32, &(BX_CPU(0)->gen_reg[BX_32BIT_REG_EIP].dword.erx));
|
||||
pPCReg->setName("EIP");
|
||||
#endif // BX_SUPPORT_X86_64
|
||||
// -------------------------------------
|
||||
// Add the Status register (x86 cpu FLAGS):
|
||||
BxFlagsReg* pFlagReg = new BxFlagsReg(RID_FLAGS, reinterpret_cast<regdata_t*>(&(BX_CPU(0)->eflags)));
|
||||
// Note: "eflags" is (always) of type Bit32u which matches the regdata_t only in
|
||||
// case of the 32 bit version (id est !BX_SUPPORT_X86_64). Therefor we need
|
||||
// to ensure to assign only 32 bit to the Bochs internal register variable
|
||||
// (see SAL/bochs/BochsRegister.hpp, setData) if we are in 64 bit mode.
|
||||
pFlagReg->setName("FLAGS");
|
||||
m_Regs->add(pFlagReg);
|
||||
m_Regs->add(pPCReg);
|
||||
}
|
||||
|
||||
BochsController::~BochsController()
|
||||
{
|
||||
for(RegisterManager::iterator it = m_Regs->begin(); it != m_Regs->end(); it++)
|
||||
delete (*it); // free the memory, allocated in the constructor
|
||||
m_Regs->clear();
|
||||
delete m_Regs;
|
||||
delete m_Mem;
|
||||
}
|
||||
|
||||
#ifdef DEBUG
|
||||
void BochsController::dbgEnableInstrPtrOutput(unsigned regularity, std::ostream* dest)
|
||||
{
|
||||
m_Regularity = regularity;
|
||||
m_pDest = dest;
|
||||
m_Counter = 0;
|
||||
}
|
||||
#endif // DEBUG
|
||||
|
||||
void BochsController::onInstrPtrChanged(address_t instrPtr, address_t address_space)
|
||||
{
|
||||
#if 0
|
||||
//the original code - performs magnitudes worse than
|
||||
//the code below and is responsible for most (~87 per cent)
|
||||
//of the slowdown of FailBochs
|
||||
#ifdef DEBUG
|
||||
if(m_Regularity != 0 && ++m_Counter % m_Regularity == 0)
|
||||
(*m_pDest) << "0x" << std::hex << instrPtr;
|
||||
#endif
|
||||
// Check for active breakpoint-events:
|
||||
EventList::iterator it = m_EvList.begin();
|
||||
while(it != m_EvList.end())
|
||||
{
|
||||
// FIXME: Maybe we need to improve the performance of this check.
|
||||
BPEvent* pEvBreakpt = dynamic_cast<BPEvent*>(*it);
|
||||
if(pEvBreakpt && pEvBreakpt->isMatching(instrPtr, address_space))
|
||||
{
|
||||
pEvBreakpt->setTriggerInstructionPointer(instrPtr);
|
||||
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();
|
||||
#endif
|
||||
//this code is highly optimised for the average case, so it me appear a bit ugly
|
||||
bool do_fire = false;
|
||||
unsigned i = 0;
|
||||
BufferCache<BPEvent*> *buffer_cache = m_EvList.getBPBuffer();
|
||||
while(i < buffer_cache->getCount()) {
|
||||
BPEvent *pEvBreakpt = buffer_cache->get(i);
|
||||
if(pEvBreakpt->isMatching(instrPtr, address_space)) {
|
||||
pEvBreakpt->setTriggerInstructionPointer(instrPtr);
|
||||
|
||||
//transition to STL: find the element we are working on in the Event List
|
||||
EventList::iterator it = std::find(m_EvList.begin(), m_EvList.end(), pEvBreakpt);
|
||||
it = m_EvList.makeActive(it);
|
||||
//find out how much elements need to be skipped to get in sync again
|
||||
//(should be one or none, the loop is just to make sure)
|
||||
for(unsigned j = i; j < buffer_cache->getCount(); j++) {
|
||||
if(buffer_cache->get(j) == (*it)) {
|
||||
i = j;
|
||||
break;
|
||||
}
|
||||
}
|
||||
// we now know we need to fire the active events - usually we do not have to
|
||||
do_fire = true;
|
||||
// "i" has already been set to the next element (by calling
|
||||
// makeActive()):
|
||||
continue; // -> skip loop increment
|
||||
}
|
||||
i++;
|
||||
}
|
||||
if(do_fire)
|
||||
m_EvList.fireActiveEvents();
|
||||
// Note: SimulatorController::onBreakpointEvent will not be invoked in this
|
||||
// implementation.
|
||||
}
|
||||
|
||||
void BochsController::onIOPortEvent(unsigned char data, unsigned port, bool out) {
|
||||
// Check for active breakpoint-events:
|
||||
EventList::iterator it = m_EvList.begin();
|
||||
while(it != m_EvList.end())
|
||||
{
|
||||
// FIXME: Maybe we need to improve the performance of this check.
|
||||
IOPortEvent* pIOPt = dynamic_cast<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 std::string& path)
|
||||
{
|
||||
int stat;
|
||||
|
||||
stat = mkdir(path.c_str(), 0777);
|
||||
if(!(stat == 0 || errno == EEXIST))
|
||||
std::cout << "[FAIL] Can not create target-directory to save!" << std::endl;
|
||||
// TODO: (Non-)Verbose-Mode? Log-level? Maybe better: use return value to indicate failure?
|
||||
|
||||
save_bochs_request = true;
|
||||
sr_path = path;
|
||||
m_CurrFlow = m_Flows.getCurrent();
|
||||
m_Flows.resume();
|
||||
}
|
||||
|
||||
void BochsController::saveDone()
|
||||
{
|
||||
save_bochs_request = false;
|
||||
m_Flows.toggle(m_CurrFlow);
|
||||
}
|
||||
|
||||
void BochsController::restore(const std::string& path)
|
||||
{
|
||||
clearEvents();
|
||||
restore_bochs_request = true;
|
||||
sr_path = path;
|
||||
m_CurrFlow = m_Flows.getCurrent();
|
||||
m_Flows.resume();
|
||||
}
|
||||
|
||||
void BochsController::restoreDone()
|
||||
{
|
||||
restore_bochs_request = false;
|
||||
m_Flows.toggle(m_CurrFlow);
|
||||
}
|
||||
|
||||
void BochsController::reboot()
|
||||
{
|
||||
clearEvents();
|
||||
reboot_bochs_request = true;
|
||||
m_CurrFlow = m_Flows.getCurrent();
|
||||
m_Flows.resume();
|
||||
}
|
||||
|
||||
void BochsController::rebootDone()
|
||||
{
|
||||
reboot_bochs_request = false;
|
||||
m_Flows.toggle(m_CurrFlow);
|
||||
}
|
||||
|
||||
void BochsController::fireInterrupt(unsigned irq)
|
||||
{
|
||||
interrupt_injection_request = true;
|
||||
interrupt_to_fire = irq;
|
||||
m_CurrFlow = m_Flows.getCurrent();
|
||||
m_Flows.resume();
|
||||
}
|
||||
|
||||
void BochsController::fireInterruptDone()
|
||||
{
|
||||
interrupt_injection_request = false;
|
||||
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.)
|
||||
TimerEvent* pTmEv = static_cast<TimerEvent*>(thisPtr);
|
||||
// Check for a matching TimerEvent. (In fact, we are only
|
||||
// interessted in the iterator pointing at pTmEv.):
|
||||
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(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(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(BaseEvent* pev)
|
||||
{
|
||||
TimerEvent* tmev;
|
||||
// Register the timer event in the Bochs simulator:
|
||||
if ((tmev = dynamic_cast<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(BaseEvent* pev)
|
||||
{
|
||||
TimerEvent* tmev;
|
||||
// Unregister the time event:
|
||||
if ((tmev = dynamic_cast<TimerEvent*>(pev)) != NULL) {
|
||||
m_unregisterTimer(tmev);
|
||||
}
|
||||
// Note: Maybe more stuff to do here for other event types.
|
||||
}
|
||||
|
||||
void BochsController::onEventTrigger(BaseEvent* pev)
|
||||
{
|
||||
TimerEvent* tmev;
|
||||
// Unregister the time event, if once-flag is true:
|
||||
if ((tmev = dynamic_cast<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.
|
||||
}
|
||||
|
||||
const std::string& BochsController::getMnemonic() const
|
||||
{
|
||||
static std::string str;
|
||||
bxICacheEntry_c* pEntry = BX_CPU(0)->getICacheEntry();
|
||||
assert(pEntry != NULL && "FATAL ERROR: Bochs internal function returned NULL (not expected)!");
|
||||
bxInstruction_c* pInstr = pEntry->i;
|
||||
assert(pInstr != NULL && "FATAL ERROR: Bochs internal member was NULL (not expected)!");
|
||||
const char* pszName = get_bx_opcode_name(pInstr->getIaOpcode());
|
||||
if (pszName != NULL)
|
||||
str = pszName;
|
||||
else
|
||||
str.clear();
|
||||
return str;
|
||||
}
|
||||
|
||||
} // end-of-namespace: fail
|
||||
181
src/core/sal/bochs/BochsController.hpp
Normal file
181
src/core/sal/bochs/BochsController.hpp
Normal file
@ -0,0 +1,181 @@
|
||||
#ifndef __BOCHS_CONTROLLER_HPP__
|
||||
#define __BOCHS_CONTROLLER_HPP__
|
||||
|
||||
#include <string>
|
||||
#include <cassert>
|
||||
#include <iostream>
|
||||
#include <iomanip>
|
||||
#include <string.h>
|
||||
|
||||
#include "FailBochsGlobals.hpp"
|
||||
|
||||
#include "../SimulatorController.hpp"
|
||||
#include "../Event.hpp"
|
||||
|
||||
#include "bochs.h"
|
||||
#include "cpu/cpu.h"
|
||||
#include "config.h"
|
||||
#include "iodev/iodev.h"
|
||||
#include "pc_system.h"
|
||||
|
||||
namespace fail {
|
||||
|
||||
class ExperimentFlow;
|
||||
|
||||
/**
|
||||
* \class BochsController
|
||||
* Bochs-specific implementation of a SimulatorController.
|
||||
*/
|
||||
class BochsController : public SimulatorController {
|
||||
private:
|
||||
ExperimentFlow* m_CurrFlow; //!< Stores the current flow for save/restore-operations
|
||||
#ifdef DEBUG
|
||||
unsigned m_Regularity; //! regularity of instruction ptr output
|
||||
unsigned m_Counter; //! current instr-ptr counter
|
||||
std::ostream* m_pDest; //! debug output object (defaults to \c std::cout)
|
||||
#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(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(TimerEvent* pev);
|
||||
public:
|
||||
// Initialize the controller.
|
||||
BochsController();
|
||||
~BochsController();
|
||||
/* ********************************************************************
|
||||
* 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 the new instruction pointer
|
||||
* @param address_space the address space the CPU is currently in
|
||||
*/
|
||||
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
|
||||
* 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(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(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(BaseEvent* pev);
|
||||
/* ********************************************************************
|
||||
* Simulator Controller & Access API:
|
||||
* ********************************************************************/
|
||||
/**
|
||||
* Save simulator state.
|
||||
* @param path Location to store state information
|
||||
*/
|
||||
void save(const std::string& path);
|
||||
/**
|
||||
* Save finished: Callback from Simulator
|
||||
*/
|
||||
void saveDone();
|
||||
/**
|
||||
* Restore simulator state. Clears all Events.
|
||||
* @param path Location to previously saved state information
|
||||
*/
|
||||
void restore(const std::string& path);
|
||||
/**
|
||||
* Restore finished: Callback from Simulator
|
||||
*/
|
||||
void restoreDone();
|
||||
/**
|
||||
* Reboot simulator. Clears all Events.
|
||||
*/
|
||||
void reboot();
|
||||
/**
|
||||
* Reboot finished: Callback from Simulator
|
||||
*/
|
||||
void rebootDone();
|
||||
/**
|
||||
* Fire an interrupt.
|
||||
* @param irq Interrupt to be fired
|
||||
*/
|
||||
void fireInterrupt(unsigned irq);
|
||||
/**
|
||||
* Fire done: Callback from Simulator
|
||||
*/
|
||||
void fireInterruptDone();
|
||||
/* ********************************************************************
|
||||
* BochsController-specific (not implemented in SimulatorController!):
|
||||
* ********************************************************************/
|
||||
#ifdef DEBUG
|
||||
/**
|
||||
* Enables instruction pointer debugging output.
|
||||
* @param regularity the output regularity; 1 to display every
|
||||
* instruction pointer, 0 to disable
|
||||
* @param dest specifies the output destition; defaults to \c std::cout
|
||||
*/
|
||||
void dbgEnableInstrPtrOutput(unsigned regularity, std::ostream* dest = &std::cout);
|
||||
#endif
|
||||
/**
|
||||
* Retrieves the textual description (mnemonic) for the current
|
||||
* instruction. The format of the returned string is Bochs-specific.
|
||||
* @return the mnemonic of the current instruction whose address
|
||||
* is given by \c Register::getInstructionPointer(). On errors,
|
||||
* the returned string is empty
|
||||
*/
|
||||
const std::string& getMnemonic() const;
|
||||
};
|
||||
|
||||
} // end-of-namespace: fail
|
||||
|
||||
#endif // __BOCHS_CONTROLLER_HPP__
|
||||
15
src/core/sal/bochs/BochsHelpers.hpp
Normal file
15
src/core/sal/bochs/BochsHelpers.hpp
Normal file
@ -0,0 +1,15 @@
|
||||
#ifndef __BOCHS_HELPERS_HPP__
|
||||
#define __BOCHS_HELPERS_HPP__
|
||||
|
||||
#include "cpu/cpu.h"
|
||||
|
||||
static inline BX_CPU_C *getCPU(BX_CPU_C *that)
|
||||
{
|
||||
#if BX_USE_CPU_SMF == 0
|
||||
return that;
|
||||
#else
|
||||
return BX_CPU_THIS;
|
||||
#endif
|
||||
}
|
||||
|
||||
#endif // __BOCHS_HELPERS_HPP__
|
||||
110
src/core/sal/bochs/BochsMemory.hpp
Normal file
110
src/core/sal/bochs/BochsMemory.hpp
Normal file
@ -0,0 +1,110 @@
|
||||
#ifndef __BOCHS_MEMORY_HPP__
|
||||
#define __BOCHS_MEMORY_HPP__
|
||||
|
||||
#include "../Memory.hpp"
|
||||
|
||||
namespace fail {
|
||||
|
||||
/**
|
||||
* \class BochsMemoryManager
|
||||
* Represents a concrete implemenation of the abstract
|
||||
* MemoryManager to provide access to Bochs' memory pool.
|
||||
*/
|
||||
class BochsMemoryManager : public MemoryManager {
|
||||
public:
|
||||
/**
|
||||
* Constructs a new MemoryManager object and initializes
|
||||
* it's attributes appropriately.
|
||||
*/
|
||||
BochsMemoryManager() : MemoryManager() { }
|
||||
/**
|
||||
* Retrieves the size of the available simulated memory.
|
||||
* @return the size of the memory pool in bytes
|
||||
*/
|
||||
size_t getPoolSize() const { return static_cast<size_t>(BX_MEM(0)->get_memory_len()); }
|
||||
/**
|
||||
* Retrieves the starting address of the host memory. This is the
|
||||
* first valid address in memory.
|
||||
* @return the starting address
|
||||
*/
|
||||
host_address_t getStartAddr() const { return 0; }
|
||||
/**
|
||||
* Retrieves the byte at address \a addr in the memory.
|
||||
* @param addr The guest address where the byte is located.
|
||||
* The address is expected to be valid.
|
||||
* @return the byte at \a addr
|
||||
*/
|
||||
byte_t getByte(guest_address_t addr)
|
||||
{
|
||||
host_address_t haddr = guestToHost(addr);
|
||||
assert(haddr != (host_address_t)ADDR_INV && "FATAL ERROR: Invalid guest address provided!");
|
||||
return static_cast<byte_t>(*reinterpret_cast<Bit8u*>(haddr));
|
||||
}
|
||||
/**
|
||||
* Retrieves \a cnt bytes at address \a addr from the memory.
|
||||
* @param addr The guest address where the bytes are located.
|
||||
* The address is expected to be valid.
|
||||
* @param cnt The number of bytes to be retrieved. \a addr + \a cnt
|
||||
* is expected to not exceed the memory limit.
|
||||
* @param dest Pointer to destination buffer to copy the data to.
|
||||
*/
|
||||
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] = getByte(addr + i);
|
||||
}
|
||||
/**
|
||||
* Writes the byte \a data to memory.
|
||||
* @param addr The guest address to write.
|
||||
* The address is expected to be valid.
|
||||
* @param data The new byte to write
|
||||
*/
|
||||
void setByte(guest_address_t addr, byte_t data)
|
||||
{
|
||||
host_address_t haddr = guestToHost(addr);
|
||||
assert(haddr != (host_address_t)ADDR_INV &&
|
||||
"FATAL ERROR: Invalid guest address provided!");
|
||||
*reinterpret_cast<Bit8u*>(haddr) = data;
|
||||
}
|
||||
/**
|
||||
* Copies data to memory.
|
||||
* @param addr The guest address to write.
|
||||
* The address is expected to be valid.
|
||||
* @param cnt The number of bytes to be retrieved. \a addr + \a cnt
|
||||
* is expected to not exceed the memory limit.
|
||||
* @param src Pointer to data to be copied.
|
||||
*/
|
||||
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]);
|
||||
}
|
||||
/**
|
||||
* Transforms the guest address \a addr to a host address.
|
||||
* @param addr The (logical) guest address to be transformed
|
||||
* @return the transformed (host) address or \c ADDR_INV on errors
|
||||
*/
|
||||
host_address_t guestToHost(guest_address_t addr)
|
||||
{
|
||||
const unsigned SEGMENT_SELECTOR_IDX = 2; // always the code segment
|
||||
const bx_address logicalAddr = static_cast<bx_address>(addr); // offset within the segment
|
||||
// Get the linear address:
|
||||
Bit32u linearAddr = BX_CPU(0)->get_laddr32(SEGMENT_SELECTOR_IDX/*seg*/, logicalAddr/*offset*/);
|
||||
// Map the linear address to the physical address:
|
||||
bx_phy_address physicalAddr;
|
||||
bx_bool fValid = BX_CPU(0)->dbg_xlate_linear2phy(linearAddr, (bx_phy_address*)&physicalAddr);
|
||||
// Determine the *host* address of the physical address:
|
||||
Bit8u* hostAddr = BX_MEM(0)->getHostMemAddr(BX_CPU(0), physicalAddr, BX_READ);
|
||||
// Now, hostAddr contains the "final" address
|
||||
if (!fValid)
|
||||
return ((host_address_t)ADDR_INV); // error
|
||||
else
|
||||
return (reinterpret_cast<host_address_t>(hostAddr)); // okay
|
||||
}
|
||||
};
|
||||
|
||||
} // end-of-namespace: fail
|
||||
|
||||
#endif // __BOCHS_MEMORY_HPP__
|
||||
53
src/core/sal/bochs/BochsNonVerbose.ah
Normal file
53
src/core/sal/bochs/BochsNonVerbose.ah
Normal file
@ -0,0 +1,53 @@
|
||||
#ifndef __BOCHS_NON_VERBOSE_AH__
|
||||
#define __BOCHS_NON_VERBOSE_AH__
|
||||
|
||||
#include "config/FailConfig.hpp"
|
||||
|
||||
#ifdef CONFIG_BOCHS_NON_VERBOSE
|
||||
|
||||
#include "bochs.h"
|
||||
|
||||
/*
|
||||
// Doesn't work because AspectC++ doesn't deal properly with variadic parameter
|
||||
// lists:
|
||||
aspect BochsNonVerbose {
|
||||
// Needed to suppress Bochs output *before* a state restore finished
|
||||
// FIXME: ac++ segfaults if we use call() instead of execution().
|
||||
advice execution("% logfunctions::debug(...)")
|
||||
|| execution("% logfunctions::info(...)")
|
||||
|| execution("% logfunctions::pass(...)")
|
||||
|| execution("% logfunctions::error(...)")
|
||||
: around () { }
|
||||
};
|
||||
*/
|
||||
|
||||
aspect BochsNonVerbose {
|
||||
// needed to suppress Bochs output *before* a state restore finished
|
||||
advice call("int logfunctions::get_default_action(int)")
|
||||
: around ()
|
||||
{
|
||||
int action;
|
||||
switch (*(tjp->arg<0>())) {
|
||||
case LOGLEV_DEBUG:
|
||||
case LOGLEV_PASS:
|
||||
case LOGLEV_INFO:
|
||||
action = ACT_IGNORE;
|
||||
break;
|
||||
case LOGLEV_ERROR:
|
||||
action = ACT_REPORT;
|
||||
break;
|
||||
case LOGLEV_PANIC:
|
||||
default:
|
||||
action = ACT_FATAL;
|
||||
}
|
||||
*(tjp->result()) = action;
|
||||
}
|
||||
|
||||
// No credits header
|
||||
advice call("void bx_print_header()")
|
||||
: around () { }
|
||||
};
|
||||
|
||||
#endif // CONFIG_BOCHS_NON_VERBOSE
|
||||
|
||||
#endif // __BOCHS_NON_VERBOSE_AH__
|
||||
238
src/core/sal/bochs/BochsRegister.hpp
Normal file
238
src/core/sal/bochs/BochsRegister.hpp
Normal file
@ -0,0 +1,238 @@
|
||||
#ifndef __BOCHS_REGISTER_HPP__
|
||||
#define __BOCHS_REGISTER_HPP__
|
||||
|
||||
#include "../Register.hpp"
|
||||
|
||||
#include "bochs.h"
|
||||
|
||||
#include <iostream>
|
||||
#include <cassert>
|
||||
|
||||
namespace fail {
|
||||
|
||||
/**
|
||||
* \class BochsRegister
|
||||
* Bochs-specific implementation of x86 registers.
|
||||
*/
|
||||
class BochsRegister : public Register {
|
||||
protected:
|
||||
regdata_t* m_pData;
|
||||
public:
|
||||
/**
|
||||
* Constructs a new register object.
|
||||
* @param id the global unique id
|
||||
* @param width width of the register (8, 16, 32 or 64 bit should
|
||||
* suffice)
|
||||
* @param link pointer to bochs interal register memory
|
||||
* @param t type of the register
|
||||
*/
|
||||
BochsRegister(unsigned int id, regwidth_t width, regdata_t* link, RegisterType t)
|
||||
: Register(id, t, width), m_pData(link) { }
|
||||
/**
|
||||
* Retrieves the data of the register.
|
||||
* @return the current register data
|
||||
*/
|
||||
regdata_t getData() { return (*m_pData); }
|
||||
/**
|
||||
* Sets the content of the register.
|
||||
* @param data the new register data to be written
|
||||
*/
|
||||
void setData(regdata_t data) { *m_pData = data; }
|
||||
};
|
||||
|
||||
/**
|
||||
* \class BxGPReg
|
||||
* Bochs-specific implementation of x86 general purpose (GP) registers.
|
||||
*/
|
||||
class BxGPReg : public BochsRegister {
|
||||
public:
|
||||
/**
|
||||
* Constructs a new general purpose register.
|
||||
* @param id the global unique id
|
||||
* @param width width of the register (8, 16, 32 or 64 bit should
|
||||
* suffice)
|
||||
* @param link pointer to bochs interal register memory
|
||||
*/
|
||||
BxGPReg(unsigned int id, regwidth_t width, regdata_t* link)
|
||||
: BochsRegister(id, width, link, RT_GP) { }
|
||||
};
|
||||
|
||||
/**
|
||||
* \enum GPRegisterId
|
||||
* Symbolic identifier to access Bochs' general purpose register
|
||||
* (within the corresponding GP set), e.g.
|
||||
* \code
|
||||
* // Print %eax register data:
|
||||
* BochsController bc(...);
|
||||
* cout << bc.getRegisterManager().getSetOfType(RT_GP)
|
||||
* .getRegister(RID_EAX)->getData();
|
||||
* \endcode
|
||||
*/
|
||||
enum GPRegisterId {
|
||||
#if BX_SUPPORT_X86_64 // 64 bit register id's:
|
||||
RID_RAX = 0, RID_RCX, RID_RDX, RID_RBX, RID_RSP, RID_RBP, RID_RSI, RID_RDI,
|
||||
RID_R8, RID_R9, RID_R10, RID_R11, RID_R12, RID_R13, RID_R14, RID_R15,
|
||||
#else // 32 bit register id's:
|
||||
RID_EAX = 0, RID_ECX, RID_EDX, RID_EBX, RID_ESP, RID_EBP, RID_ESI, RID_EDI,
|
||||
#endif
|
||||
RID_CAX = 0, RID_CCX, RID_CDX, RID_CBX, RID_CSP, RID_CBP, RID_CSI, RID_CDI,
|
||||
RID_LAST_GP_ID
|
||||
};
|
||||
|
||||
/**
|
||||
* \enum PCRegisterId
|
||||
* Symbolic identifier to access Bochs' program counter register.
|
||||
*/
|
||||
enum PCRegisterId { RID_PC = RID_LAST_GP_ID, RID_LAST_PC_ID };
|
||||
|
||||
/**
|
||||
* \enum FlagsRegisterId
|
||||
* Symbolic identifier to access Bochs' flags register.
|
||||
*/
|
||||
enum FlagsRegisterId { RID_FLAGS = RID_LAST_PC_ID };
|
||||
|
||||
/**
|
||||
* \class BxPCReg
|
||||
* Bochs-specific implementation of the x86 program counter register.
|
||||
*/
|
||||
class BxPCReg : public BochsRegister {
|
||||
public:
|
||||
/**
|
||||
* Constructs a new program counter register.
|
||||
* @param id the global unique id
|
||||
* @param width width of the register (8, 16, 32 or 64 bit should
|
||||
* suffice)
|
||||
* @param link pointer to bochs internal register memory
|
||||
*/
|
||||
BxPCReg(unsigned int id, regwidth_t width, regdata_t* link)
|
||||
: BochsRegister(id, width, link, RT_PC) { }
|
||||
};
|
||||
|
||||
/**
|
||||
* \class BxFlagsReg
|
||||
* Bochs-specific implementation of the FLAGS status register.
|
||||
*/
|
||||
class BxFlagsReg : public BochsRegister {
|
||||
public:
|
||||
/**
|
||||
* Constructs a new FLAGS status register. The refenced FLAGS are
|
||||
* allocated as follows:
|
||||
* --------------------------------------------------
|
||||
* 31|30|29|28| 27|26|25|24| 23|22|21|20| 19|18|17|16
|
||||
* ==|==|=====| ==|==|==|==| ==|==|==|==| ==|==|==|==
|
||||
* 0| 0| 0| 0| 0| 0| 0| 0| 0| 0|ID|VP| VF|AC|VM|RF
|
||||
*
|
||||
* 15|14|13|12| 11|10| 9| 8| 7| 6| 5| 4| 3| 2| 1| 0
|
||||
* ==|==|=====| ==|==|==|==| ==|==|==|==| ==|==|==|==
|
||||
* 0|NT| IOPL| OF|DF|IF|TF| SF|ZF| 0|AF| 0|PF| 1|CF
|
||||
* --------------------------------------------------
|
||||
* @param id the global unique id
|
||||
* @param link pointer to bochs internal register memory
|
||||
*/
|
||||
BxFlagsReg(unsigned int id, regdata_t* link)
|
||||
: BochsRegister(id, 32, link, RT_ST) { }
|
||||
|
||||
/**
|
||||
* Returns \c true if the corresponding flag is set, or \c false
|
||||
* otherwise.
|
||||
*/
|
||||
bool getCarryFlag() const { return (BX_CPU(0)->get_CF()); }
|
||||
bool getParityFlag() const { return (BX_CPU(0)->get_PF()); }
|
||||
bool getZeroFlag() const { return (BX_CPU(0)->get_ZF()); }
|
||||
bool getSignFlag() const { return (BX_CPU(0)->get_SF()); }
|
||||
bool getOverflowFlag() const { return (BX_CPU(0)->get_OF()); }
|
||||
|
||||
bool getTrapFlag() const { return (BX_CPU(0)->get_TF()); }
|
||||
bool getInterruptFlag() const { return (BX_CPU(0)->get_IF()); }
|
||||
bool getDirectionFlag() const { return (BX_CPU(0)->get_DF()); }
|
||||
unsigned getIOPrivilegeLevel() const { return (BX_CPU(0)->get_IOPL()); }
|
||||
bool getNestedTaskFlag() const { return (BX_CPU(0)->get_NT()); }
|
||||
bool getResumeFlag() const { return (BX_CPU(0)->get_RF()); }
|
||||
bool getVMFlag() const { return (BX_CPU(0)->get_VM()); }
|
||||
bool getAlignmentCheckFlag() const { return (BX_CPU(0)->get_AC()); }
|
||||
bool getVInterruptFlag() const { return (BX_CPU(0)->get_VIF()); }
|
||||
bool getVInterruptPendingFlag() const { return (BX_CPU(0)->get_VIP()); }
|
||||
bool getIdentificationFlag() const { return (BX_CPU(0)->get_ID()); }
|
||||
|
||||
/**
|
||||
* Sets/resets various status FLAGS.
|
||||
*/
|
||||
void setCarryFlag(bool bit) { BX_CPU(0)->set_CF(bit); }
|
||||
void setParityFlag(bool bit) { BX_CPU(0)->set_PF(bit); }
|
||||
void setZeroFlag(bool bit) { BX_CPU(0)->set_ZF(bit); }
|
||||
void setSignFlag(bool bit) { BX_CPU(0)->set_SF(bit); }
|
||||
void setOverflowFlag(bool bit) { BX_CPU(0)->set_OF(bit); }
|
||||
|
||||
void setTrapFlag(bool bit) { BX_CPU(0)->set_TF(bit); }
|
||||
void setInterruptFlag(bool bit) { BX_CPU(0)->set_IF(bit); }
|
||||
void setDirectionFlag(bool bit) { BX_CPU(0)->set_DF(bit); }
|
||||
void setIOPrivilegeLevel(unsigned lvl) { BX_CPU(0)->set_IOPL(lvl); }
|
||||
void setNestedTaskFlag(bool bit) { BX_CPU(0)->set_NT(bit); }
|
||||
void setResumeFlag(bool bit) { BX_CPU(0)->set_RF(bit); }
|
||||
void setVMFlag(bool bit) { BX_CPU(0)->set_VM(bit); }
|
||||
void setAlignmentCheckFlag(bool bit) { BX_CPU(0)->set_AC(bit); }
|
||||
void setVInterruptFlag(bool bit) { BX_CPU(0)->set_VIF(bit); }
|
||||
void setVInterruptPendingFlag(bool bit) { BX_CPU(0)->set_VIP(bit); }
|
||||
void setIdentificationFlag(bool bit) { BX_CPU(0)->set_ID(bit); }
|
||||
|
||||
/**
|
||||
* Sets the content of the status register.
|
||||
* @param data the new register data to be written; note that only the
|
||||
* 32 lower bits are used (bits 32-63 are ignored in 64 bit mode)
|
||||
*/
|
||||
void setData(regdata_t data)
|
||||
{
|
||||
#ifdef BX_SUPPORT_X86_64
|
||||
// We are in 64 bit mode: Just assign the lower 32 bits!
|
||||
(*m_pData) = ((*m_pData) & 0xFFFFFFFF00000000ULL) |
|
||||
(data & 0xFFFFFFFFULL);
|
||||
#else
|
||||
*m_pData = data;
|
||||
#endif
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* \class BochsRegister
|
||||
* Bochs-specific implementation of the RegisterManager.
|
||||
*/
|
||||
class BochsRegisterManager : public RegisterManager {
|
||||
public:
|
||||
/**
|
||||
* Returns the current instruction pointer.
|
||||
* @return the current eip
|
||||
*/
|
||||
address_t getInstructionPointer()
|
||||
{
|
||||
return (static_cast<address_t>(getSetOfType(RT_PC)->first()->getData()));
|
||||
}
|
||||
/**
|
||||
* Retruns the top address of the stack.
|
||||
* @return the starting address of the stack
|
||||
*/
|
||||
address_t getStackPointer()
|
||||
{
|
||||
#if BX_SUPPORT_X86_64
|
||||
return (static_cast<address_t>(getRegister(RID_RSP)->getData()));
|
||||
#else
|
||||
return (static_cast<address_t>(getRegister(RID_ESP)->getData()));
|
||||
#endif
|
||||
}
|
||||
/**
|
||||
* Retrieves the base ptr (holding the address of the
|
||||
* current stack frame).
|
||||
* @return the base pointer
|
||||
*/
|
||||
address_t getBasePointer()
|
||||
{
|
||||
#if BX_SUPPORT_X86_64
|
||||
return (static_cast<address_t>(getRegister(RID_RBP)->getData()));
|
||||
#else
|
||||
return (static_cast<address_t>(getRegister(RID_EBP)->getData()));
|
||||
#endif
|
||||
}
|
||||
};
|
||||
|
||||
} // end-of-namespace: fail
|
||||
|
||||
#endif // __BOCHS_REGISTER_HPP__
|
||||
32
src/core/sal/bochs/Breakpoints.ah
Normal file
32
src/core/sal/bochs/Breakpoints.ah
Normal file
@ -0,0 +1,32 @@
|
||||
#ifndef __BREAKPOINTS_AH__
|
||||
#define __BREAKPOINTS_AH__
|
||||
|
||||
#include "config/FailConfig.hpp"
|
||||
|
||||
#ifdef CONFIG_EVENT_BREAKPOINTS
|
||||
|
||||
#include "bochs.h"
|
||||
#include "cpu/cpu.h"
|
||||
|
||||
#include "../SALInst.hpp"
|
||||
|
||||
aspect Breakpoints {
|
||||
pointcut cpuLoop() = "void defineCPULoopJoinPoint(...)";
|
||||
|
||||
advice execution (cpuLoop()) : after () // Event source: "instruction pointer"
|
||||
{
|
||||
// Points to the cpu class: "this" if BX_USE_CPU_SMF == 0,
|
||||
// BX_CPU(0) otherwise
|
||||
BX_CPU_C* pThis = *(tjp->arg<0>());
|
||||
// Points to the *current* bxInstruction-object
|
||||
//bxInstruction_c* pInstr = *(tjp->arg<1>());
|
||||
|
||||
// report this event to the Bochs controller:
|
||||
fail::simulator.onInstrPtrChanged(pThis->get_instruction_pointer(), pThis->cr3);
|
||||
// Note: get_bx_opcode_name(pInstr->getIaOpcode()) retrieves the mnemonics.
|
||||
}
|
||||
};
|
||||
|
||||
#endif // CONFIG_EVENT_BREAKPOINTS
|
||||
|
||||
#endif // __BREAKPOINTS_AH__
|
||||
29
src/core/sal/bochs/Credits.ah
Normal file
29
src/core/sal/bochs/Credits.ah
Normal file
@ -0,0 +1,29 @@
|
||||
#ifndef __CREDITS_AH__
|
||||
#define __CREDITS_AH__
|
||||
|
||||
#include <string.h>
|
||||
#include <stdio.h>
|
||||
|
||||
aspect Credits {
|
||||
bool first;
|
||||
Credits() : first(true) {}
|
||||
|
||||
advice call ("% bx_center_print(...)")
|
||||
&& within ("void bx_print_header()")
|
||||
&& args(file, line, maxwidth)
|
||||
: around (FILE *file, const char *line, unsigned maxwidth)
|
||||
{
|
||||
if (!first) {
|
||||
tjp->proceed();
|
||||
return;
|
||||
}
|
||||
// FIXME take version from global configuration
|
||||
char buf[256] = "FailBochs 0.0.1, based on the ";
|
||||
strncat(buf, line, 128);
|
||||
first = false;
|
||||
*(tjp->arg<1>()) = buf;
|
||||
tjp->proceed();
|
||||
}
|
||||
};
|
||||
|
||||
#endif // __CREDITS_AH__
|
||||
26
src/core/sal/bochs/DisableKeyboardInterrupt.ah
Normal file
26
src/core/sal/bochs/DisableKeyboardInterrupt.ah
Normal file
@ -0,0 +1,26 @@
|
||||
#ifndef __DISABLE_KEYBOARD_INTERRUPT_AH__
|
||||
#define __DISABLE_KEYBOARD_INTERRUPT_AH__
|
||||
|
||||
#include "config/FailConfig.hpp"
|
||||
|
||||
#ifdef CONFIG_DISABLE_KEYB_INTERRUPTS
|
||||
|
||||
#include "iodev/iodev.h"
|
||||
#include "iodev/keyboard.h"
|
||||
|
||||
aspect DisableKeyboardInterrupt {
|
||||
pointcut heyboard_interrupt() =
|
||||
"void bx_keyb_c::timer_handler(...)";
|
||||
|
||||
advice execution (heyboard_interrupt()) : around ()
|
||||
{
|
||||
bx_keyb_c *class_ptr = (bx_keyb_c*)tjp->arg<0>();
|
||||
unsigned retval;
|
||||
|
||||
retval = class_ptr->periodic(1);
|
||||
}
|
||||
};
|
||||
|
||||
#endif // CONFIG_DISABLE_KEYB_INTERRUPTS
|
||||
|
||||
#endif // __DISABLE_KEYBOARD_INTERRUPT_AH__
|
||||
19
src/core/sal/bochs/DisableLogFunctions.ah
Normal file
19
src/core/sal/bochs/DisableLogFunctions.ah
Normal file
@ -0,0 +1,19 @@
|
||||
#ifndef __DISABLE_ADD_REMOVE_LOGFN_AH__
|
||||
#define __DISABLE_ADD_REMOVE_LOGFN_AH__
|
||||
|
||||
/* Hack to prevent Bochs' logfunctions list (bochs.h) to overflow if the
|
||||
* experiment restores simulator state more than ~1000 times.
|
||||
*
|
||||
* The "proper" fix would be to completely unregister all log functions before
|
||||
* restore, i.e. to destroy all objects deriving from class logfunctions. We
|
||||
* decided to simply ignore this tiny memory leak and to hack around the
|
||||
* problem by disabling iofunctions::add/remove_logfn().
|
||||
*/
|
||||
aspect DisableLogFunctions {
|
||||
pointcut add_remove_logfn() =
|
||||
"void iofunctions::add_logfn(...)" ||
|
||||
"void iofunctions::remove_logfn(...)";
|
||||
advice execution (add_remove_logfn()) : around () { }
|
||||
};
|
||||
|
||||
#endif // __DISABLE_ADD_REMOVE_LOGFN_AH__
|
||||
22
src/core/sal/bochs/FailBochsGlobals.hpp
Normal file
22
src/core/sal/bochs/FailBochsGlobals.hpp
Normal file
@ -0,0 +1,22 @@
|
||||
#ifndef __FAIL_BOCHS_GLOBALS_HPP__
|
||||
#define __FAIL_BOCHS_GLOBALS_HPP__
|
||||
|
||||
#include <string>
|
||||
|
||||
#include "config.h"
|
||||
|
||||
namespace fail {
|
||||
|
||||
#ifdef DANCEOS_RESTORE
|
||||
extern bx_bool restore_bochs_request;
|
||||
extern bx_bool save_bochs_request;
|
||||
extern std::string sr_path;
|
||||
#endif
|
||||
|
||||
extern bx_bool reboot_bochs_request;
|
||||
extern bx_bool interrupt_injection_request;
|
||||
extern int interrupt_to_fire;
|
||||
|
||||
} // end-of-namespace: fail
|
||||
|
||||
#endif // __FAIL_BOCHS_GLOBALS_HPP__
|
||||
13
src/core/sal/bochs/FailBochsInit.ah
Normal file
13
src/core/sal/bochs/FailBochsInit.ah
Normal file
@ -0,0 +1,13 @@
|
||||
#ifndef __FAIL_BOCHS_INIT_AH__
|
||||
#define __FAIL_BOCHS_INIT_AH__
|
||||
|
||||
#include "../SALInst.hpp"
|
||||
|
||||
aspect FailBochsInit {
|
||||
advice call("int bxmain()") : before ()
|
||||
{
|
||||
fail::simulator.startup();
|
||||
}
|
||||
};
|
||||
|
||||
#endif // __FAIL_BOCHS_INIT_AH__
|
||||
45
src/core/sal/bochs/FireInterrupt.ah
Normal file
45
src/core/sal/bochs/FireInterrupt.ah
Normal file
@ -0,0 +1,45 @@
|
||||
#ifndef __FIREINTERRUPT_AH__
|
||||
#define __FIREINTERRUPT_AH__
|
||||
|
||||
#include "config/FailConfig.hpp"
|
||||
|
||||
#ifdef CONFIG_FIRE_INTERRUPTS
|
||||
|
||||
#include "bochs.h"
|
||||
#include "cpu/cpu.h"
|
||||
#include "iodev/iodev.h"
|
||||
#include "../SALInst.hpp"
|
||||
|
||||
aspect FireInterrupt {
|
||||
pointcut cpuLoop() = "void defineCPULoopJoinPoint(...)";
|
||||
|
||||
advice execution (cpuLoop()) : before ()
|
||||
{
|
||||
if (!fail::interrupt_injection_request) {
|
||||
return;
|
||||
} else {
|
||||
BX_SET_INTR(fail::interrupt_to_fire);
|
||||
DEV_pic_raise_irq(fail::interrupt_to_fire);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
aspect InterruptDone {
|
||||
pointcut interrupt_method() = "void bx_cpu_c::interrupt(...)";
|
||||
|
||||
advice execution (interrupt_method()) : before ()
|
||||
{
|
||||
if (!fail::interrupt_injection_request) {
|
||||
return;
|
||||
} else {
|
||||
if (*(tjp->arg<0>()) == 32 + fail::interrupt_to_fire) {
|
||||
DEV_pic_lower_irq(fail::interrupt_to_fire);
|
||||
fail::simulator.fireInterruptDone();
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
#endif // CONFIG_FIRE_INTERRUPTS
|
||||
|
||||
#endif // __FIREINTERRUPT_AH__
|
||||
33
src/core/sal/bochs/GuestSysCom.ah
Normal file
33
src/core/sal/bochs/GuestSysCom.ah
Normal file
@ -0,0 +1,33 @@
|
||||
#ifndef __GUEST_SYS_COM_AH__
|
||||
#define __GUEST_SYS_COM_AH__
|
||||
|
||||
#include "config/FailConfig.hpp"
|
||||
|
||||
#ifdef CONFIG_EVENT_GUESTSYS
|
||||
|
||||
#include "bochs.h"
|
||||
#include "cpu/cpu.h"
|
||||
|
||||
#include "../SALInst.hpp"
|
||||
#include "BochsHelpers.hpp"
|
||||
|
||||
// Fixed "port number" for "Guest system >> Bochs" communication
|
||||
#define BOCHS_COM_PORT 0x378
|
||||
|
||||
// FIXME: This #define should be located in a config or passed within the event object...
|
||||
|
||||
aspect GuestSysCom {
|
||||
pointcut outInstructions() = "% ...::bx_cpu_c::OUT_DX%(...)";
|
||||
|
||||
advice execution (outInstructions()) : after () // Event source: "guest system"
|
||||
{
|
||||
unsigned rDX = getCPU(tjp->that())->gen_reg[2].word.rx; // port number
|
||||
unsigned rAL = getCPU(tjp->that())->gen_reg[0].word.byte.rl; // data
|
||||
if (rDX == BOCHS_COM_PORT)
|
||||
fail::simulator.onGuestSystemEvent((char)rAL, rDX);
|
||||
}
|
||||
};
|
||||
|
||||
#endif // CONFIG_EVENT_GUESTSYS
|
||||
|
||||
#endif // __GUEST_SYS_COM_AH__
|
||||
39
src/core/sal/bochs/IOPortCom.ah
Normal file
39
src/core/sal/bochs/IOPortCom.ah
Normal file
@ -0,0 +1,39 @@
|
||||
#ifndef __IOPORT_COM_AH__
|
||||
#define __IOPORT_COM_AH__
|
||||
|
||||
#include "config/FailConfig.hpp"
|
||||
|
||||
#ifdef CONFIG_EVENT_IOPORT
|
||||
|
||||
#include "bochs.h"
|
||||
#include "cpu/cpu.h"
|
||||
|
||||
#include "../SALInst.hpp"
|
||||
|
||||
#include "BochsHelpers.hpp"
|
||||
|
||||
// TODO: ATM only capturing bytewise output (most common, I suppose)
|
||||
|
||||
aspect IOPortCom {
|
||||
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
|
||||
fail::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
|
||||
fail::simulator.onIOPortEvent(rAL, rDX, false);
|
||||
}
|
||||
};
|
||||
|
||||
#endif // CONFIG_EVENT_IOPORT
|
||||
|
||||
#endif // __IOPORT_COM_AH__
|
||||
39
src/core/sal/bochs/Interrupt.ah
Normal file
39
src/core/sal/bochs/Interrupt.ah
Normal file
@ -0,0 +1,39 @@
|
||||
#ifndef __INTERRUPT_AH__
|
||||
#define __INTERRUPT_AH__
|
||||
|
||||
#include "config/FailConfig.hpp"
|
||||
|
||||
#ifdef CONFIG_EVENT_INTERRUPT
|
||||
|
||||
#include "bochs.h"
|
||||
#include "cpu/cpu.h"
|
||||
|
||||
#include "../SALInst.hpp"
|
||||
|
||||
aspect Interrupt {
|
||||
pointcut interrupt_method() = "void bx_cpu_c::interrupt(...)"; // cpu/exception.cc
|
||||
|
||||
advice execution (interrupt_method()) : before ()
|
||||
{
|
||||
// There are six different type-arguments for the interrupt-method
|
||||
// in cpu.h (lines 3867-3872):
|
||||
// - BX_EXTERNAL_INTERRUPT = 0,
|
||||
// - BX_NMI = 2,
|
||||
// - BX_HARDWARE_EXCEPTION = 3,
|
||||
// - BX_SOFTWARE_INTERRUPT = 4,
|
||||
// - BX_PRIVILEGED_SOFTWARE_INTERRUPT = 5,
|
||||
// - BX_SOFTWARE_EXCEPTION = 6
|
||||
// Only the first and the second types are relevant for this aspect.
|
||||
|
||||
unsigned vector = *(tjp->arg<0>());
|
||||
unsigned type = *(tjp->arg<1>());
|
||||
if (type == BX_EXTERNAL_INTERRUPT)
|
||||
fail::simulator.onInterruptEvent(vector, false);
|
||||
else if (type == BX_NMI)
|
||||
fail::simulator.onInterruptEvent(vector, true);
|
||||
}
|
||||
};
|
||||
|
||||
#endif // CONFIG_EVENT_INTERRUPT
|
||||
|
||||
#endif // __INTERRUPT_AH__
|
||||
27
src/core/sal/bochs/InterruptSuppression.ah
Normal file
27
src/core/sal/bochs/InterruptSuppression.ah
Normal file
@ -0,0 +1,27 @@
|
||||
#ifndef __INTERRUPT_SUPPRESSION_AH__
|
||||
#define __INTERRUPT_SUPPRESSION_AH__
|
||||
|
||||
#include "config/FailConfig.hpp"
|
||||
|
||||
#ifdef CONFIG_SUPPRESS_INTERRUPTS
|
||||
|
||||
#include "bochs.h"
|
||||
#include "cpu/cpu.h"
|
||||
|
||||
#include "../SALInst.hpp"
|
||||
|
||||
aspect InterruptSuppression {
|
||||
pointcut interrupt_method() = "void bx_cpu_c::interrupt(...)";
|
||||
|
||||
advice execution (interrupt_method()) : around ()
|
||||
{
|
||||
unsigned vector = *(tjp->arg<0>());
|
||||
if (!fail::simulator.isSuppressedInterrupt(vector)) {
|
||||
tjp->proceed();
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
#endif // CONFIG_SUPPRESS_INTERRUPTS
|
||||
|
||||
#endif // __INTERRUPT_SUPPRESSION_AH__
|
||||
140
src/core/sal/bochs/Jump.ah
Normal file
140
src/core/sal/bochs/Jump.ah
Normal file
@ -0,0 +1,140 @@
|
||||
#ifndef __JUMP_AH__
|
||||
#define __JUMP_AH__
|
||||
|
||||
#include "config/FailConfig.hpp"
|
||||
|
||||
#ifdef CONFIG_EVENT_JUMP
|
||||
|
||||
#include <iostream>
|
||||
#include <cstdlib>
|
||||
#include <string>
|
||||
#include <ctime>
|
||||
|
||||
#include "bochs.h"
|
||||
|
||||
#include "../SALInst.hpp"
|
||||
|
||||
// FIXME: This seems (partial) deprecated/incomplete as well...
|
||||
|
||||
aspect Jump {
|
||||
// Note: Have a look at the Bochs-Code (cpu/cpu.h) and the Intel
|
||||
// Architecture Software Developer's Manual - Instruction Set Reference
|
||||
// p. 3-329 (PDF p. 369) for further information:
|
||||
// http://www.intel.com/design/intarch/manuals/243191.htm
|
||||
|
||||
// Default conditional-jump instructions: they are evaluating the FLAGS,
|
||||
// defined in ctrl_xfer[16 | 32 | 64].cc, Postfix: 16-Bit: w, 32-Bit: d, 64-Bit: q
|
||||
pointcut defJumpInstructions() =
|
||||
"% ...::bx_cpu_c::JO_J%(...)" ||
|
||||
"% ...::bx_cpu_c::JNO_J%(...)" ||
|
||||
"% ...::bx_cpu_c::JB_J%(...)" ||
|
||||
"% ...::bx_cpu_c::JNB_J%(...)" ||
|
||||
"% ...::bx_cpu_c::JZ_J%(...)" ||
|
||||
"% ...::bx_cpu_c::JNZ_J%(...)" ||
|
||||
"% ...::bx_cpu_c::JBE_J%(...)" ||
|
||||
"% ...::bx_cpu_c::JNBE_J%(...)" ||
|
||||
"% ...::bx_cpu_c::JS_J%(...)" ||
|
||||
"% ...::bx_cpu_c::JNS_J%(...)" ||
|
||||
"% ...::bx_cpu_c::JP_J%(...)" ||
|
||||
"% ...::bx_cpu_c::JNP_J%(...)" ||
|
||||
"% ...::bx_cpu_c::JL_J%(...)" ||
|
||||
"% ...::bx_cpu_c::JNL_J%(...)" ||
|
||||
"% ...::bx_cpu_c::JLE_J%(...)" ||
|
||||
"% ...::bx_cpu_c::JNLE_J%(...)";
|
||||
|
||||
// Special cases: they are evaluating the content of the CX-/ECX-/RCX-registers
|
||||
// (NOT the FLAGS):
|
||||
pointcut regJumpInstructions() =
|
||||
"% ...::bx_cpu_c::JCXZ_Jb(...)" || // ctrl_xfer16.cc
|
||||
"% ...::bx_cpu_c::JECXZ_Jb(...)" || // ctrl_xfer32.cc
|
||||
"% ...::bx_cpu_c::JRCXZ_Jb(...)"; // ctrl_xfer64.cc
|
||||
|
||||
/* TODO: Loop-Instructions needed? Example: "LOOPNE16_Jb"
|
||||
pointcut loopInstructions() = ...;
|
||||
|
||||
*/
|
||||
/* TODO: Conditional-Data-Moves needed? Example: "CMOVZ_GwEwR"
|
||||
pointcut dataMoveInstructions() = ...;
|
||||
|
||||
*/
|
||||
advice execution (defJumpInstructions()) : around()
|
||||
{
|
||||
bxInstruction_c* pInstr = *(tjp->arg<0>()); // bxInstruction_c-object
|
||||
fail::simulator.onJumpEvent(true, pInstr->getIaOpcode());
|
||||
/*
|
||||
JoinPoint::That* pThis = tjp->that();
|
||||
if(pThis == NULL)
|
||||
pThis = BX_CPU(0);
|
||||
assert(pThis != NULL && "FATAL ERROR: tjp->that() returned null ptr! (Maybe called on a static instance?)");
|
||||
// According to the Intel-Spec (p. 3-329f), the following flags are relevant:
|
||||
bool fZeroFlag = pThis->get_ZF();
|
||||
bool fCarryFlag = pThis->get_CF();
|
||||
bool fSignFlag = pThis->get_SF();
|
||||
bool fOverflowFlag = pThis->get_OF();
|
||||
bool fParityFlag = pThis->get_PF();
|
||||
|
||||
//
|
||||
// Step-1: Modify one or more of the fxxxFlag according to the error you want to inject
|
||||
// (using pThis->set_XX(new_val))
|
||||
// Step-2: Call tjp->proceed();
|
||||
// Step-3: Eventually, unwind the changes of Step-1
|
||||
//
|
||||
|
||||
// Example:
|
||||
if(g_fEnableInjection) // event fired?
|
||||
{
|
||||
g_fEnableInjection = false;
|
||||
// Obviously, this advice matches *all* jump-instructions so that it is not clear
|
||||
// which flag have to be modified in order to invert the jump. For simplification,
|
||||
// we will invert *all* flags. This avoids a few case differentiations.
|
||||
cout << ">>> Manipulating jump-destination (inverted)... \"" << tjp->signature() << "\" ";
|
||||
pThis->set_ZF(!fZeroFlag);
|
||||
pThis->set_SF(!fSignFlag);
|
||||
pThis->set_CF(!fCarryFlag);
|
||||
pThis->set_OF(!fOverflowFlag);
|
||||
pThis->set_PF(!fParityFlag);
|
||||
tjp->proceed();
|
||||
pThis->set_ZF(fZeroFlag);
|
||||
pThis->set_SF(fSignFlag);
|
||||
pThis->set_CF(fCarryFlag);
|
||||
pThis->set_OF(fOverflowFlag);
|
||||
pThis->set_PF(fParityFlag);
|
||||
cout << "finished (jump taken)!" << endl;
|
||||
}
|
||||
else
|
||||
*/
|
||||
tjp->proceed();
|
||||
}
|
||||
|
||||
advice execution (regJumpInstructions()) : around ()
|
||||
{
|
||||
bxInstruction_c* pInstr = *(tjp->arg<0>()); // bxInstruction_c-object
|
||||
fail::simulator.onJumpEvent(false, pInstr->getIaOpcode());
|
||||
/*
|
||||
JoinPoint::That* pThis = tjp->that();
|
||||
|
||||
assert(pThis != NULL && "Unexpected: tjp->that() returned null ptr! (Maybe called on a static instance?)");
|
||||
|
||||
// Note: Direct access to the registers using the bochs-macros (defined in
|
||||
// bochs.h) is not possibly due to the fact that they are using the this-ptr.
|
||||
|
||||
Bit16u CX = (Bit16u)(pThis->gen_reg[1].word.rx);
|
||||
Bit32u ECX = (Bit32u)(pThis->gen_reg[1].dword.erx);
|
||||
#if BX_SUPPORT_X86_64
|
||||
Bit64u RCX = (Bit64u)(pThis->gen_reg[1].rrx);
|
||||
#endif
|
||||
|
||||
//
|
||||
// Step-1: Modify CX, ECX or RCX according to the error you want to inject
|
||||
// Step-2: Call tjp->proceed();
|
||||
// Step-3: Eventually, unwind the changes of Step-1
|
||||
//
|
||||
*/
|
||||
tjp->proceed();
|
||||
}
|
||||
};
|
||||
|
||||
#endif // CONFIG_EVENT_JUMP
|
||||
|
||||
#endif // __JUMP_AH__
|
||||
|
||||
158
src/core/sal/bochs/MemAccess.ah
Normal file
158
src/core/sal/bochs/MemAccess.ah
Normal file
@ -0,0 +1,158 @@
|
||||
#ifndef __MEM_ACCESS_AH__
|
||||
#define __MEM_ACCESS_AH__
|
||||
|
||||
#include "config/FailConfig.hpp"
|
||||
|
||||
#if defined(CONFIG_EVENT_MEMREAD) || defined(CONFIG_EVENT_MEMWRITE)
|
||||
|
||||
#include <iostream>
|
||||
|
||||
#include "bochs.h"
|
||||
#include "cpu/cpu.h"
|
||||
|
||||
#include "../SALInst.hpp"
|
||||
#include "BochsHelpers.hpp"
|
||||
|
||||
// FIXME: We currently assume a "flat" memory model and ignore the segment
|
||||
// parameter of all memory accesses.
|
||||
// TODO: Instruction fetch?
|
||||
// TODO: Warn on uncovered memory accesses.
|
||||
|
||||
aspect MemAccess {
|
||||
fail::address_t rmw_address;
|
||||
|
||||
pointcut write_methods() =
|
||||
"% ...::bx_cpu_c::write_virtual_%(...)" && // -> access32/64.cc
|
||||
// not an actual memory access:
|
||||
!"% ...::bx_cpu_c::write_virtual_checks(...)";
|
||||
pointcut write_methods_RMW() =
|
||||
"% ...::bx_cpu_c::write_RMW_virtual_%(...)";
|
||||
pointcut write_methods_new_stack() =
|
||||
"% ...::bx_cpu_c::write_new_stack_%(...)" && // -> access32.cc
|
||||
!"% ...::bx_cpu_c::write_new_stack_%_64(...)";
|
||||
pointcut write_methods_new_stack_64() =
|
||||
"% ...::bx_cpu_c::write_new_stack_%_64(...)"; // -> access64.cc
|
||||
pointcut write_methods_system() =
|
||||
"% ...::bx_cpu_c::system_write_%(...)"; // -> access.cc
|
||||
// FIXME not covered:
|
||||
/* "% ...::bx_cpu_c::v2h_write_byte(...)"; // -> access.cc */
|
||||
|
||||
pointcut read_methods() =
|
||||
"% ...::bx_cpu_c::read_virtual_%(...)" &&
|
||||
// sizeof() doesn't work here (see next pointcut)
|
||||
!"% ...::bx_cpu_c::read_virtual_dqword_%(...)" && // -> access32/64.cc
|
||||
// not an actual memory access:
|
||||
!"% ...::bx_cpu_c::read_virtual_checks(...)";
|
||||
pointcut read_methods_dqword() =
|
||||
"% ...::bx_cpu_c::read_virtual_dqword_%(...)"; // -> access32/64.cc
|
||||
pointcut read_methods_RMW() =
|
||||
"% ...::bx_cpu_c::read_RMW_virtual_%(...)";
|
||||
pointcut read_methods_system() =
|
||||
"% ...::bx_cpu_c::system_read_%(...)"; // -> access.cc
|
||||
// FIXME not covered:
|
||||
/* "% ...::bx_cpu_c::v2h_read_byte(...)"; // -> access.cc */
|
||||
|
||||
//
|
||||
// Fire a memory-write-event each time the guest system requests
|
||||
// to write data to RAM:
|
||||
//
|
||||
// Event source: "memory write access"
|
||||
//
|
||||
#ifdef CONFIG_EVENT_MEMWRITE
|
||||
advice execution (write_methods()) : after ()
|
||||
{
|
||||
fail::simulator.onMemoryAccessEvent(
|
||||
*(tjp->arg<1>()), sizeof(*(tjp->arg<2>())), true,
|
||||
getCPU(tjp->that())->prev_rip);
|
||||
}
|
||||
|
||||
advice execution (write_methods_RMW()) : after ()
|
||||
{
|
||||
fail::simulator.onMemoryAccessEvent(
|
||||
rmw_address, sizeof(*(tjp->arg<0>())), true,
|
||||
getCPU(tjp->that())->prev_rip);
|
||||
}
|
||||
|
||||
advice execution (write_methods_new_stack()) : after ()
|
||||
{
|
||||
std::cerr << "WOOOOOT write_methods_new_stack" << std::endl;
|
||||
// TODO: Log-level?
|
||||
fail::simulator.onMemoryAccessEvent(
|
||||
*(tjp->arg<1>()), sizeof(*(tjp->arg<3>())), true,
|
||||
getCPU(tjp->that())->prev_rip);
|
||||
}
|
||||
|
||||
advice execution (write_methods_new_stack_64()) : after ()
|
||||
{
|
||||
std::cerr << "WOOOOOT write_methods_new_stack_64" << std::endl;
|
||||
// TODO: Log-level?
|
||||
fail::simulator.onMemoryAccessEvent(
|
||||
*(tjp->arg<0>()), sizeof(*(tjp->arg<2>())), true,
|
||||
getCPU(tjp->that())->prev_rip);
|
||||
}
|
||||
|
||||
advice execution (write_methods_system()) : after ()
|
||||
{
|
||||
// We don't do anything here for now: This type of memory
|
||||
// access is used when the hardware itself needs to access
|
||||
// memory (e.g., to read vectors from the interrupt vector
|
||||
// table).
|
||||
/*
|
||||
fail::simulator.onMemoryAccessEvent(
|
||||
*(tjp->arg<0>()), sizeof(*(tjp->arg<1>())), true,
|
||||
getCPU(tjp->that())->prev_rip);
|
||||
*/
|
||||
}
|
||||
#endif
|
||||
|
||||
//
|
||||
// Fire a memory-read-event each time the guest system requests
|
||||
// to read data in RAM:
|
||||
//
|
||||
// Event source: "memory read access"
|
||||
//
|
||||
#ifdef CONFIG_EVENT_MEMREAD
|
||||
advice execution (read_methods()) : before ()
|
||||
{
|
||||
fail::simulator.onMemoryAccessEvent(
|
||||
*(tjp->arg<1>()), sizeof(*(tjp->result())), false,
|
||||
getCPU(tjp->that())->prev_rip);
|
||||
}
|
||||
|
||||
advice execution (read_methods_dqword()) : before ()
|
||||
{
|
||||
fail::simulator.onMemoryAccessEvent(
|
||||
*(tjp->arg<1>()), 16, false,
|
||||
getCPU(tjp->that())->prev_rip);
|
||||
}
|
||||
#endif
|
||||
|
||||
advice execution (read_methods_RMW()) : before ()
|
||||
{
|
||||
rmw_address = *(tjp->arg<1>());
|
||||
#ifdef CONFIG_EVENT_MEMREAD
|
||||
fail::simulator.onMemoryAccessEvent(
|
||||
*(tjp->arg<1>()), sizeof(*(tjp->result())), false,
|
||||
getCPU(tjp->that())->prev_rip);
|
||||
#endif
|
||||
}
|
||||
|
||||
#ifdef CONFIG_EVENT_MEMREAD
|
||||
advice execution (read_methods_system()) : before ()
|
||||
{
|
||||
// We don't do anything here for now: This type of memory
|
||||
// access is used when the hardware itself needs to access
|
||||
// memory (e.g., to read vectors from the interrupt vector
|
||||
// table).
|
||||
/*
|
||||
fail::simulator.onMemoryAccessEvent(
|
||||
*(tjp->arg<0>()), sizeof(*(tjp->result())), false,
|
||||
getCPU(tjp->that())->prev_rip);
|
||||
*/
|
||||
}
|
||||
#endif
|
||||
};
|
||||
|
||||
#endif // CONFIG_EVENT_MEMACCESS
|
||||
|
||||
#endif // __MEM_ACCESS_AH__
|
||||
29
src/core/sal/bochs/Reboot.ah
Normal file
29
src/core/sal/bochs/Reboot.ah
Normal file
@ -0,0 +1,29 @@
|
||||
#ifndef __REBOOT_AH__
|
||||
#define __REBOOT_AH__
|
||||
|
||||
#include "config/FailConfig.hpp"
|
||||
|
||||
#ifdef CONFIG_SR_REBOOT
|
||||
|
||||
#include "bochs.h"
|
||||
#include "../SALInst.hpp"
|
||||
|
||||
aspect Reboot {
|
||||
pointcut cpuLoop() = "void defineCPULoopJoinPoint(...)";
|
||||
|
||||
advice execution (cpuLoop()) : after ()
|
||||
{
|
||||
if (!fail::reboot_bochs_request) {
|
||||
return;
|
||||
}
|
||||
|
||||
bx_gui_c::reset_handler();
|
||||
std::cout << "[FAIL] Reboot finished" << std::endl;
|
||||
// TODO: Log-level?
|
||||
fail::simulator.rebootDone();
|
||||
}
|
||||
};
|
||||
|
||||
#endif // CONFIG_SR_REBOOT
|
||||
|
||||
#endif // __REBOOT_AH__
|
||||
27
src/core/sal/bochs/RestoreState.ah
Normal file
27
src/core/sal/bochs/RestoreState.ah
Normal file
@ -0,0 +1,27 @@
|
||||
#ifndef __RESTORE_STATE_AH__
|
||||
#define __RESTORE_STATE_AH__
|
||||
|
||||
#include "config/FailConfig.hpp"
|
||||
|
||||
#ifdef CONFIG_SR_RESTORE
|
||||
|
||||
#include <iostream>
|
||||
|
||||
#include "bochs.h"
|
||||
|
||||
#include "../SALInst.hpp"
|
||||
|
||||
aspect RestoreState {
|
||||
pointcut restoreState() = "void bx_sr_after_restore_state()";
|
||||
|
||||
advice execution (restoreState()) : after ()
|
||||
{
|
||||
std::cout << "[FAIL] Restore finished" << std::endl;
|
||||
// TODO: Log-Level?
|
||||
fail::simulator.restoreDone();
|
||||
}
|
||||
};
|
||||
|
||||
#endif // CONFIG_SR_RESTORE
|
||||
|
||||
#endif // __RESTORE_STATE_AH__
|
||||
33
src/core/sal/bochs/SaveState.ah
Normal file
33
src/core/sal/bochs/SaveState.ah
Normal file
@ -0,0 +1,33 @@
|
||||
#ifndef _SAVE_STATE_AH__
|
||||
#define _SAVE_STATE_AH__
|
||||
|
||||
#include "config/FailConfig.hpp"
|
||||
|
||||
#ifdef CONFIG_SR_SAVE
|
||||
|
||||
#include "bochs.h"
|
||||
|
||||
#include "../SALInst.hpp"
|
||||
|
||||
aspect SaveState {
|
||||
pointcut cpuLoop() = "void defineCPULoopJoinPoint(...)";
|
||||
|
||||
// make sure the "SaveState" aspect comes *after* the breakpoint stuff: In
|
||||
// an "after" advice this means it must get a *higher* precedence,
|
||||
// therefore it's first in the order list.
|
||||
advice execution (cpuLoop()) : order ("SaveState", "Breakpoints");
|
||||
|
||||
advice execution (cpuLoop()) : after () {
|
||||
if (!fail::save_bochs_request)
|
||||
return;
|
||||
assert(fail::sr_path.size() > 0 && "FATAL ERROR: tried to save state without valid path");
|
||||
SIM->save_state(fail::sr_path.c_str());
|
||||
std::cout << "[FAIL] Save finished" << std::endl;
|
||||
// TODO: Log-Level?
|
||||
fail::simulator.saveDone();
|
||||
}
|
||||
};
|
||||
|
||||
#endif // CONFIG_SR_SAVE
|
||||
|
||||
#endif // _SAVE_STATE_AH__
|
||||
26
src/core/sal/bochs/Trap.ah
Normal file
26
src/core/sal/bochs/Trap.ah
Normal file
@ -0,0 +1,26 @@
|
||||
#ifndef __TRAP_AH__
|
||||
#define __TRAP_AH__
|
||||
|
||||
#include "config/FailConfig.hpp"
|
||||
|
||||
#ifdef CONFIG_EVENT_TRAP
|
||||
|
||||
#include "bochs.h"
|
||||
#include "cpu/cpu.h"
|
||||
|
||||
#include "../SALInst.hpp"
|
||||
|
||||
aspect Trap {
|
||||
pointcut exception_method() = "void bx_cpu_c::exception(...)";
|
||||
|
||||
advice execution (exception_method()) : before ()
|
||||
{
|
||||
fail::simulator.onTrapEvent(*(tjp->arg<0>()));
|
||||
// TODO: There are some different types of exceptions at cpu.h (line 265-281)
|
||||
// Which kind of a trap are these types?
|
||||
}
|
||||
};
|
||||
|
||||
#endif // CONFIG_EVENT_TRAP
|
||||
|
||||
#endif // __TRAP_AH__
|
||||
Reference in New Issue
Block a user