Documentation / corrected Bochs timer

git-svn-id: https://www4.informatik.uni-erlangen.de/i4svn/danceos/trunk/devel/fail@1718 8c4709b5-6ec9-48aa-a5cd-a96041d1645a
This commit is contained in:
unzner
2012-10-05 09:41:41 +00:00
parent 0c3d365368
commit 42a75fa128
5 changed files with 107 additions and 48 deletions

View File

@ -37,8 +37,10 @@ aspect BochsListener {
{ {
assert(pev != NULL && "FATAL ERROR: TimerListener object ptr cannot be NULL!"); assert(pev != NULL && "FATAL ERROR: TimerListener object ptr cannot be NULL!");
return static_cast<timer_id_t>( return static_cast<timer_id_t>(
bx_pc_system.register_timer(pev, fail::onTimerTrigger, pev->getTimeout(), bx_pc_system.register_timer(pev, fail::onTimerTrigger,
false, 1/*start immediately*/, "Fail*: BochsController"/*name*/)); pev->getTimeout() * 1000 /*timeout in microseconds*/,
false /*non-continuous*/,
true /*start immediately*/, "Fail*: BochsController"/*name*/));
} }
bool m_unregisterTimer(TimerListener* pev) bool m_unregisterTimer(TimerListener* pev)
{ {

View File

@ -1,3 +1,4 @@
#include "../SALInst.hpp"
#include "BochsListener.hpp" #include "BochsListener.hpp"
#include "../SALInst.hpp" #include "../SALInst.hpp"

View File

@ -45,47 +45,45 @@ void BochsALUInstructions::buildEquivalenceClasses() {
} }
} }
void BochsALUInstructions::bochsInstrToInstrStruct(bxInstruction_c const *src, BochsALUInstr *dest) const { void BochsALUInstructions::bochsInstrToInstrStruct(bxInstruction_c const &src, BochsALUInstr &dest) const {
if (dest == NULL) return;
//Note: it may be necessary to introduce a solution for two-byte //Note: it may be necessary to introduce a solution for two-byte
//opcodes once they overlap with one-byte ones //opcodes once they overlap with one-byte ones
for (size_t i = 0; i < allInstrSize; i++) { for (size_t i = 0; i < allInstrSize; i++) {
// first, check the opcode // first, check the opcode
if (allInstr[i].opcodeRegisterOffset <= BochsALUInstr::REG_COUNT) { if (allInstr[i].opcodeRegisterOffset <= BochsALUInstr::REG_COUNT) {
// the opcode listed in allInstr is the starting value for a range // the opcode listed in allInstr is the starting value for a range
if (src->b1() < allInstr[i].opcode || if (src.b1() < allInstr[i].opcode ||
src->b1() > allInstr[i].opcode + BochsALUInstr::REG_COUNT) { src.b1() > allInstr[i].opcode + BochsALUInstr::REG_COUNT) {
continue; continue;
} }
} else if (src->b1() != allInstr[i].opcode) { } else if (src.b1() != allInstr[i].opcode) {
// normal case -- just compare the opcode // normal case -- just compare the opcode
continue; continue;
} }
// second, check the opcode extension // second, check the opcode extension
if (allInstr[i].reg < BochsALUInstr::REG_COUNT && if (allInstr[i].reg < BochsALUInstr::REG_COUNT &&
allInstr[i].reg != src->nnn()) { allInstr[i].reg != src.nnn()) {
continue; continue;
} }
// found it - now copy // found it - now copy
if (allInstr[i].opcodeRegisterOffset <= BochsALUInstr::REG_COUNT) { if (allInstr[i].opcodeRegisterOffset <= BochsALUInstr::REG_COUNT) {
BochsALUInstr result = { allInstr[i].bochs_operation, dest.bochs_operation = allInstr[i].bochs_operation;
src->b1(), dest.opcode = src.b1();
allInstr[i].reg, dest.reg = allInstr[i].reg;
src->rm(), dest.opcodeRegisterOffset = src.rm();
allInstr[i].aluClass}; dest.aluClass = allInstr[i].aluClass;
memcpy(dest, &result, sizeof(BochsALUInstr));
} else { } else {
memcpy(dest, &allInstr[i], sizeof(BochsALUInstr)); dest = allInstr[i];
} }
return; return;
} }
// not found - marking it undefined // not found - marking it undefined
dest->aluClass = ALU_UNDEF; dest.aluClass = ALU_UNDEF;
} }
bool BochsALUInstructions::isALUInstruction(const bxInstruction_c *src) { bool BochsALUInstructions::isALUInstruction(bxInstruction_c const *src) {
lastOrigInstr = src; memcpy(&lastOrigInstr, src, sizeof(bxInstruction_c));
bochsInstrToInstrStruct(src, &lastInstr); bochsInstrToInstrStruct(lastOrigInstr, lastInstr);
if (lastInstr.aluClass != ALU_UNDEF) { if (lastInstr.aluClass != ALU_UNDEF) {
return true; return true;
} }
@ -97,7 +95,7 @@ bxInstruction_c BochsALUInstructions::randomEquivalent() const {
X86AluClass equClassID = lastInstr.aluClass; X86AluClass equClassID = lastInstr.aluClass;
if (equClassID == ALU_UNDEF) { if (equClassID == ALU_UNDEF) {
// something went wrong - just return the original instruction // something went wrong - just return the original instruction
return *lastOrigInstr; return lastOrigInstr;
} }
InstrList const &destList = equivalenceClasses.at(equClassID); InstrList const &destList = equivalenceClasses.at(equClassID);
@ -106,11 +104,10 @@ bxInstruction_c BochsALUInstructions::randomEquivalent() const {
do { do {
int index = rand() % destList.size(); int index = rand() % destList.size();
dest = destList[index]; dest = destList[index];
} while (!memcmp(&dest, &lastInstr, sizeof(BochsALUInstr))); } while (memcmp(&dest, &lastInstr, sizeof(BochsALUInstr)) == 0);
// first, copy everything // first, copy everything
bxInstruction_c result; bxInstruction_c result = lastOrigInstr;
memcpy(&result, lastOrigInstr, sizeof(bxInstruction_c));
// then change what has to be different // then change what has to be different
// execute functions // execute functions

View File

@ -8,12 +8,16 @@
#include "cpu/instr.h" #include "cpu/instr.h"
/** /**
* Trying to order X86 ALU instructions. * \enum X86AluClass
*
* \brief An attempt to order X86 ALU instructions.
*
* An attempt to order X86 ALU instructions.
* Each instruction class contains instructions * Each instruction class contains instructions
* of roughly equal length and operands, so that * of roughly equal length and operands, so that
* all the bxInstruction_c structures residing within * all the bxInstruction_c structures residing within
* one class contain the same member fields (except for * one class contain the same member fields (except for
* b1, rm and the execute pointers). * b1, rm and the execute function pointers).
*/ */
enum X86AluClass { enum X86AluClass {
ALU_UNDEF = 0, ALU_UNDEF = 0,
@ -32,6 +36,8 @@ enum X86AluClass {
}; };
/** /**
* \struct BochsALUInstr
*
* A struct describing a specific x86 * A struct describing a specific x86
* ALU instruction in terms of Bochs. * ALU instruction in terms of Bochs.
*/ */
@ -73,11 +79,9 @@ struct BochsALUInstr {
/** /**
* Array containing most (all?) Bochs ALU commands. * \var aluInstructions
* Attention: here, \a reg and \a opcodeRegisterOffset, if less than 8, *
* define the maximum value possible in this field, * Array containing the Bochs IA-32 Integer ALU commands.
* according to the Bochs instruction decoder function.
* (see the BxOpcodeInfoG... arrays in cpu/fetchdecode.h)
*/ */
const BochsALUInstr aluInstructions [] = { const BochsALUInstr aluInstructions [] = {
// Now is a great time to open Volume 2 of Intel's IA-32 documentation. // Now is a great time to open Volume 2 of Intel's IA-32 documentation.
@ -266,33 +270,81 @@ const BochsALUInstr aluInstructions [] = {
/* --- \\\ BINARY OPERATIONS /// --- */ /* --- \\\ BINARY OPERATIONS /// --- */
}; };
const size_t aluInstructionsSize = sizeof(aluInstructions); /**
* \var aluInstructionsSize
*
* the size of aluInstructions, in bytes
*/
size_t const aluInstructionsSize = sizeof(aluInstructions);
/**
* \class BochsALUInstructions
*
* \brfief This class handles Bochs ALU instructions.
*
* This class analyses a given bxInstruction_c object:
* if it belongs to the instructions listed in
* \a allInstr, the user can request a random
* ALU instruction with an equivalent addressing mode.
*/
class BochsALUInstructions { class BochsALUInstructions {
public: public:
/** /**
* * A list of Bochs instructions
*/ */
typedef std::vector<BochsALUInstr> InstrList; typedef std::vector<BochsALUInstr> InstrList;
/**
* This data structure assigns lists of instructions on their ALU equivalence
* class.
*
* \see X86AluClass
*/
typedef std::map<X86AluClass, InstrList> EquivClassMap; typedef std::map<X86AluClass, InstrList> EquivClassMap;
/** /**
* * Creates a new BochsALUInstructions object.
* @param initial_array initialises \a allInstr
* @param array_size the size of initial_array
*/ */
BochsALUInstructions(const BochsALUInstr *initial_array, size_t array_size); BochsALUInstructions(const BochsALUInstr *initial_array, size_t array_size);
/**
* Destroys the BochsALUInstructions object.
*/
~BochsALUInstructions() { free(allInstr); } ~BochsALUInstructions() { free(allInstr); }
/**
* Determines if a given Bochs instruction is an ALU instruction.
* @param src the instruction to examine. It is stored internally
* to be reused with \a randomEquivalent
* @returns \c true if the given instruction is an ALU instruction,
* \c false otherwise
*/
bool isALUInstruction(const bxInstruction_c *src); bool isALUInstruction(const bxInstruction_c *src);
/**
* Determines a new bxInstruction_c object with an equivalent
* addressing mode.
* @returns a bxInstruction_c object as described above
*/
bxInstruction_c randomEquivalent() const; bxInstruction_c randomEquivalent() const;
protected: protected:
void bochsInstrToInstrStruct(const bxInstruction_c *src, BochsALUInstr *dest) const; /**
* Convert a bxInstruction_c object into its matching BochsALUInstr object.
* @params src the Bochs instruction to examine
* @params dest the resulting BochsALUInstr object. Its \a aluClass field
* is set to \c ALU_UNDEF in case no matching ALU instruction
* could be found. In this case, all other fields of dest are invalid.
*/
void bochsInstrToInstrStruct(bxInstruction_c const &src, BochsALUInstr &dest) const;
private: private:
BochsALUInstr *allInstr; BochsALUInstr *allInstr; //<! array that contains all known ALU instructions of the object
BochsALUInstr lastInstr; size_t allInstrSize; //<! the element count of the allInstr array
const bxInstruction_c *lastOrigInstr; BochsALUInstr lastInstr; //<! a buffer for the last generated ALU instruction
size_t allInstrSize; bxInstruction_c lastOrigInstr; //!< a buffer for the last examined Bochs instruction
EquivClassMap equivalenceClasses; EquivClassMap equivalenceClasses; //!< the object's \a EquivClassMap (see there)
/**
* A function to build the equivalence classes from the given instructions.
*/
void buildEquivalenceClasses(); void buildEquivalenceClasses();
#ifdef DEBUG #ifdef DEBUG
void printNestedMap(); void printNestedMap(); //!< prints the \a EquivClassMap of the oject
#endif #endif
}; };

View File

@ -163,8 +163,9 @@ void L4SysExperiment::injectInstruction(bxInstruction_c *oldInstr, bxInstruction
} }
unsigned L4SysExperiment::calculateTimeout() { unsigned L4SysExperiment::calculateTimeout() {
// the timeout in seconds, plus one backup second (avoids rounding overhead)
// [instr] / [instr / s] = [s] // [instr] / [instr / s] = [s]
unsigned seconds = L4SYS_NUMINSTR / L4SYS_BOCHS_IPS; unsigned seconds = L4SYS_NUMINSTR / L4SYS_BOCHS_IPS + 1;
// 1.1 (+10 percent) * 1000 ms/s * [s] // 1.1 (+10 percent) * 1000 ms/s * [s]
return 1100 * seconds; return 1100 * seconds;
} }
@ -200,9 +201,11 @@ bool L4SysExperiment::run() {
} else { } else {
kernel++; kernel++;
} }
// log << "EIP = " << hex << simulator.getRegisterManager().getInstructionPointer() << endl;
} }
log << "test function calculation position reached after " << dec << count << " instructions; " log << "EIP = " << hex
<< simulator.getRegisterManager().getInstructionPointer() << endl;
log << "test function calculation position reached after "
<< dec << count << " instructions; "
<< "ul: " << ul << ", kernel: " << kernel << endl; << "ul: " << ul << ", kernel: " << kernel << endl;
#elif PREPARATION_STEP == 3 #elif PREPARATION_STEP == 3
// STEP 3: determine the output of a "golden run" // STEP 3: determine the output of a "golden run"
@ -222,7 +225,8 @@ bool L4SysExperiment::run() {
log << "Output successfully logged!" << endl; log << "Output successfully logged!" << endl;
} else { } else {
log log
<< "Obviously, there is some trouble with the events registered - aborting simulation!" << "Obviously, there is some trouble with"
<< " the events registered - aborting simulation!"
<< endl; << endl;
golden_run_file.close(); golden_run_file.close();
simulator.terminate(10); simulator.terminate(10);
@ -238,7 +242,8 @@ bool L4SysExperiment::run() {
* You would probably need some kind of loop detection, * You would probably need some kind of loop detection,
* but for the moment, I have to focus on different issues. * but for the moment, I have to focus on different issues.
*/ */
if (stat(L4SYS_INSTRUCTION_LIST, &teststruct) == -1 || stat(L4SYS_ALU_INSTRUCTIONS, &teststruct) == -1) { if (stat(L4SYS_INSTRUCTION_LIST, &teststruct) == -1 ||
stat(L4SYS_ALU_INSTRUCTIONS, &teststruct) == -1) {
log << "restoring state" << endl; log << "restoring state" << endl;
simulator.restore(L4SYS_STATE_FOLDER); simulator.restore(L4SYS_STATE_FOLDER);
log << "EIP = " << hex log << "EIP = " << hex
@ -296,7 +301,8 @@ bool L4SysExperiment::run() {
#elif PREPARATION_STEP == 0 #elif PREPARATION_STEP == 0
// LAST STEP: The actual experiment. // LAST STEP: The actual experiment.
struct stat teststruct; struct stat teststruct;
if (stat(L4SYS_STATE_FOLDER, &teststruct) == -1 || stat(L4SYS_CORRECT_OUTPUT, &teststruct) == -1) { if (stat(L4SYS_STATE_FOLDER, &teststruct) == -1 ||
stat(L4SYS_CORRECT_OUTPUT, &teststruct) == -1) {
log << "Important data missing - call \"prepare\" first." << endl; log << "Important data missing - call \"prepare\" first." << endl;
simulator.terminate(10); simulator.terminate(10);
} }
@ -526,7 +532,7 @@ bool L4SysExperiment::run() {
} }
} else if (exp_type == param.msg.ALUINSTR) { } else if (exp_type == param.msg.ALUINSTR) {
BochsALUInstructions aluInstrObject(aluInstructions, aluInstructionsSize); static BochsALUInstructions aluInstrObject(aluInstructions, aluInstructionsSize);
// find the closest ALU instruction after the current IP // find the closest ALU instruction after the current IP
bxInstruction_c *currInstr; bxInstruction_c *currInstr;
@ -536,7 +542,7 @@ bool L4SysExperiment::run() {
} }
// now exchange it with a random equivalent // now exchange it with a random equivalent
bxInstruction_c newInstr = aluInstrObject.randomEquivalent(); bxInstruction_c newInstr = aluInstrObject.randomEquivalent();
if (!memcmp(&newInstr, currInstr, sizeof(bxInstruction_c))) { if (memcmp(&newInstr, currInstr, sizeof(bxInstruction_c)) == 0) {
// something went wrong - exit experiment // something went wrong - exit experiment
param.msg.set_resulttype(param.msg.UNKNOWN); param.msg.set_resulttype(param.msg.UNKNOWN);
param.msg.set_resultdata( param.msg.set_resultdata(
@ -561,6 +567,7 @@ bool L4SysExperiment::run() {
BPSingleListener ev_incomplete(ANY_ADDR, L4SYS_ADDRESS_SPACE); BPSingleListener ev_incomplete(ANY_ADDR, L4SYS_ADDRESS_SPACE);
ev_incomplete.setCounter(static_cast<unsigned>(L4SYS_NUMINSTR * 1.1)); ev_incomplete.setCounter(static_cast<unsigned>(L4SYS_NUMINSTR * 1.1));
simulator.addListener(&ev_incomplete); simulator.addListener(&ev_incomplete);
log << calculateTimeout() << endl;
TimerListener ev_timeout(calculateTimeout()); TimerListener ev_timeout(calculateTimeout());
simulator.addListener(&ev_timeout); simulator.addListener(&ev_timeout);