diff --git a/src/experiments/ecos_kernel_test/campaign.cc b/src/experiments/ecos_kernel_test/campaign.cc index 0e16fd96..9be02c4d 100644 --- a/src/experiments/ecos_kernel_test/campaign.cc +++ b/src/experiments/ecos_kernel_test/campaign.cc @@ -12,8 +12,6 @@ #include "util/ProtoStream.hpp" #include "util/MemoryMap.hpp" -#include "ecc_region.hpp" - #include "../plugins/tracing/TracingPlugin.hpp" //#define PRUNING_DEBUG_OUTPUT @@ -23,6 +21,29 @@ using namespace fail; char const * const trace_filename = "trace.tc"; char const * const results_filename = "ecos_kernel_test.csv"; +char const * const mm_filename = "memory_map.txt"; //TODO: sync with experiment.cc + +bool EcosKernelTestCampaign::readMemoryMap(fail::MemoryMap &mm, char const * const filename) { + ifstream file(filename); + if (!file.is_open()) { + cout << "failed to open " << filename << endl; + return false; + } + + string buf; + stringstream ss(ios::in); + unsigned guest_addr, guest_len; + unsigned count = 0; + + while (getline(file, buf)) { + ss.str(buf); + ss >> guest_addr >> guest_len; + mm.add(guest_addr, guest_len); + count++; + } + file.close(); + return (count > 0); +} // equivalence class type: addr, [i1, i2] // addr: byte to inject a bit-flip into @@ -60,9 +81,7 @@ bool EcosKernelTestCampaign::run() // a map of addresses of ECC protected objects MemoryMap mm; - for (unsigned i = 0; i < sizeof(memoryMap)/sizeof(*memoryMap); ++i) { - mm.add(memoryMap[i][0], memoryMap[i][1]); - } + EcosKernelTestCampaign::readMemoryMap(mm, mm_filename); // set of equivalence classes that need one (rather: eight, one for // each bit in that byte) experiment to determine them all diff --git a/src/experiments/ecos_kernel_test/campaign.hpp b/src/experiments/ecos_kernel_test/campaign.hpp index 5dee77f6..f0779479 100644 --- a/src/experiments/ecos_kernel_test/campaign.hpp +++ b/src/experiments/ecos_kernel_test/campaign.hpp @@ -3,6 +3,7 @@ #include "cpn/Campaign.hpp" #include "comm/ExperimentData.hpp" #include "ecos_kernel_test.pb.h" +#include "util/MemoryMap.hpp" class EcosKernelTestExperimentData : public fail::ExperimentData { public: @@ -13,5 +14,6 @@ public: class EcosKernelTestCampaign : public fail::Campaign { public: virtual bool run(); + static bool readMemoryMap(fail::MemoryMap &mm, char const * const filename); }; diff --git a/src/experiments/ecos_kernel_test/ecc_region.hpp b/src/experiments/ecos_kernel_test/ecc_region.hpp deleted file mode 100644 index eb74ead1..00000000 --- a/src/experiments/ecos_kernel_test/ecc_region.hpp +++ /dev/null @@ -1,82 +0,0 @@ -// generated from STEP 0 output with region2array.sh -static const unsigned memoryMap[][2] = { -{0x9bec, 4}, -{0xade0, 4}, -{0xade4, 4}, -{0xade8, 4}, -{0xadf0, 4}, -{0xadf4, 4}, -{0xadf8, 4}, -{0xadfc, 4}, -{0xae00, 4}, -{0xae04, 4}, -{0xae08, 4}, -{0xae0c, 4}, -{0xae10, 4}, -{0xae14, 2}, -{0xae44, 4}, -{0xae48, 4}, -{0xae4c, 24}, -{0xae64, 4}, -{0xae68, 4}, -{0xae6c, 4}, -{0xae70, 4}, -{0xae74, 4}, -{0xae7c, 4}, -{0xae80, 4}, -{0xae84, 4}, -{0xae88, 4}, -{0xae8c, 4}, -{0xae90, 4}, -{0xae94, 4}, -{0xae98, 4}, -{0xae9c, 4}, -{0xaea0, 2}, -{0xaed0, 4}, -{0xaed4, 4}, -{0xaed8, 24}, -{0xaef0, 4}, -{0xaef4, 4}, -{0xca48, 4}, -{0xca60, 4}, -{0xca64, 4}, -{0xca68, 4}, -{0xca70, 4}, -{0xca74, 4}, -{0xca78, 4}, -{0xca7c, 4}, -{0xca80, 4}, -{0xca84, 4}, -{0xca88, 4}, -{0xca8c, 4}, -{0xca90, 4}, -{0xca94, 2}, -{0xcac4, 4}, -{0xcac8, 4}, -{0xcacc, 24}, -{0xcae4, 4}, -{0xcae8, 4}, -{0xd314, 4}, -{0xd318, 4}, -{0xd320, 4}, -{0xd324, 128}, -{0xd3a4, 4}, -{0xd3c0, 4}, -{0xd3c4, 4}, -{0xd3c8, 4}, -{0xd3d0, 4}, -{0xd3d4, 4}, -{0xd3d8, 4}, -{0xd3dc, 4}, -{0xd3e0, 4}, -{0xd3e4, 4}, -{0xd3e8, 4}, -{0xd3ec, 4}, -{0xd3f0, 4}, -{0xd3f4, 2}, -{0xd424, 4}, -{0xd428, 4}, -{0xd42c, 24}, -{0xd444, 4}, -{0xd448, 4}, -}; diff --git a/src/experiments/ecos_kernel_test/experiment.cc b/src/experiments/ecos_kernel_test/experiment.cc index 02ce2ded..e940fe62 100644 --- a/src/experiments/ecos_kernel_test/experiment.cc +++ b/src/experiments/ecos_kernel_test/experiment.cc @@ -1,5 +1,6 @@ #include #include +//#include // getpid #include @@ -19,8 +20,6 @@ // You need to have the tracing plugin enabled for this #include "../plugins/tracing/TracingPlugin.hpp" -#include "ecc_region.hpp" - #define LOCAL 0 using namespace std; @@ -32,6 +31,9 @@ using namespace fail; #error This experiment needs: breakpoints, traps, save, and restore. Enable these in the configuration. #endif + +char const * const mm_filename = "memory_map.txt"; + bool EcosKernelTestExperiment::run() { char const *statename = "ecos_kernel_test.state"; @@ -40,88 +42,160 @@ bool EcosKernelTestExperiment::run() log << "startup" << endl; -#if 0 - // STEP 0: record memory map with addresses of "interesting" objects - GuestEvent g; - while (true) { - simulator.addEventAndWait(&g); - cout << g.getData() << flush; + log << "STEP 0: record memory map with addresses of 'interesting' objects" << endl; + { + // workaround for 00002808875p[BIOS ] >>PANIC<< Keyboard error:21 + bp.setWatchInstructionPointer(ANY_ADDR); + simulator.addEventAndWait(&bp); + + GuestEvent g; + simulator.addEvent(&g); + + // 10000us = 500000 instructions + TimerEvent record_timeout(50000000); //TODO: how long to wait? + simulator.addEvent(&record_timeout); + + // memory map serialization + ofstream mm(mm_filename, ios::out | ios::app); + if (!mm.is_open()) { + log << "failed to open " << mm_filename << endl; + return false; + } + + string *str = new string; // buffer for guest events + unsigned number_of_guest_events = 0; + + while (simulator.waitAny() != &record_timeout) { + simulator.addEvent(&g); + str->push_back(g.getData()); + + if (g.getData() == '\t') { + // addr complete? + //cout << "full: " << *str << "sub: " << str->substr(str->find_last_of('x') - 1) << endl; + // interpret the string obtained by the guest events as address in hex + unsigned guest_addr; + stringstream converter(str->substr(str->find_last_of('x') + 1)); + converter >> hex >> guest_addr; + mm << guest_addr << '\t'; + str->clear(); + } else if (g.getData() == '\n') { + // len complete? + // interpret the string obtained by the guest events as length in decimal + unsigned guest_len; + stringstream converter(*str); + converter >> dec >> guest_len; + mm << guest_len << '\n'; + str->clear(); + number_of_guest_events++; + } + } + assert(number_of_guest_events > 0); + cout << "Record timeout reached: created memory map (" << number_of_guest_events << " entries)" << endl; + delete str; + + // close serialized mm + mm.flush(); + mm.close(); + + // clean up simulator and reboot the guest system + simulator.clearEvents(); + log << "rebooting ..." << endl; + simulator.reboot(); } -#elif 0 - // STEP 1: run until interesting function starts, and save state - bp.setWatchInstructionPointer(ECOS_FUNC_ENTRY); - simulator.addEventAndWait(&bp); - log << "test function entry reached, saving state" << endl; - log << "EIP = " << hex << bp.getTriggerInstructionPointer() << endl; - //log << "error_corrected = " << dec << ((int)simulator.getMemoryManager().getByte(OOSTUBS_ERROR_CORRECTED)) << endl; - simulator.save(statename); - assert(bp.getTriggerInstructionPointer() == ECOS_FUNC_ENTRY); - assert(simulator.getRegisterManager().getInstructionPointer() == ECOS_FUNC_ENTRY); -#elif 0 - // STEP 2: record trace for fault-space pruning - log << "restoring state" << endl; - simulator.restore(statename); - log << "EIP = " << hex << simulator.getRegisterManager().getInstructionPointer() << endl; - assert(simulator.getRegisterManager().getInstructionPointer() == ECOS_FUNC_ENTRY); - log << "enabling tracing" << endl; - TracingPlugin tp; + log << "STEP 1: run until interesting function starts, and save state" << endl; + { + GuestEvent g; - // restrict memory access logging to injection target - MemoryMap mm; - for (unsigned i = 0; i < sizeof(memoryMap)/sizeof(*memoryMap); ++i) { - mm.add(memoryMap[i][0], memoryMap[i][1]); + while (true) { + simulator.addEventAndWait(&g); + if(g.getData() == 'Q') { + cout << "Guest system triggered: " << g.getData() << endl; + break; + } + } + + bp.setWatchInstructionPointer(ECOS_FUNC_ENTRY); + simulator.addEventAndWait(&bp); + log << "test function entry reached, saving state" << endl; + log << "EIP = " << hex << bp.getTriggerInstructionPointer() << endl; + //log << "error_corrected = " << dec << ((int)simulator.getMemoryManager().getByte(OOSTUBS_ERROR_CORRECTED)) << endl; + simulator.save(statename); + assert(bp.getTriggerInstructionPointer() == ECOS_FUNC_ENTRY); + assert(simulator.getRegisterManager().getInstructionPointer() == ECOS_FUNC_ENTRY); + + // clean up simulator and reboot the guest system + simulator.clearEvents(); + log << "rebooting ..." << endl; + simulator.reboot(); } - tp.restrictMemoryAddresses(&mm); - // record trace - char const *tracefile = "trace.tc"; - ofstream of(tracefile); - tp.setTraceFile(&of); + log << "STEP 2: record trace for fault-space pruning" << endl; + { + log << "restoring state" << endl; + simulator.restore(statename); + log << "EIP = " << hex << simulator.getRegisterManager().getInstructionPointer() << endl; + assert(simulator.getRegisterManager().getInstructionPointer() == ECOS_FUNC_ENTRY); - // this must be done *after* configuring the plugin: - simulator.addFlow(&tp); + log << "enabling tracing" << endl; + TracingPlugin tp; + + // restrict memory access logging to injection target + MemoryMap mm; + EcosKernelTestCampaign::readMemoryMap(mm, mm_filename); + + tp.restrictMemoryAddresses(&mm); + + // record trace + char const *tracefile = "trace.tc"; + ofstream of(tracefile); + tp.setTraceFile(&of); + + // this must be done *after* configuring the plugin: + simulator.addFlow(&tp); #if 1 - // trace WEATHER_NUMITER_TRACING measurement loop iterations - // -> calibration - bp.setWatchInstructionPointer(ECOS_FUNC_FINISH); - //bp.setCounter(WEATHER_NUMITER_TRACING); // single event, only + // trace WEATHER_NUMITER_TRACING measurement loop iterations + // -> calibration + bp.setWatchInstructionPointer(ECOS_FUNC_FINISH); + //bp.setCounter(WEATHER_NUMITER_TRACING); // single event, only #else - // FIXME this doesn't work properly: trace is one instruction too short as - // tp is removed before all events were delivered - // trace WEATHER_NUMINSTR_TRACING instructions - // -> campaign-ready traces with identical lengths - bp.setWatchInstructionPointer(ANY_ADDR); - bp.setCounter(OOSTUBS_NUMINSTR); + // FIXME this doesn't work properly: trace is one instruction too short as + // tp is removed before all events were delivered + // trace WEATHER_NUMINSTR_TRACING instructions + // -> campaign-ready traces with identical lengths + bp.setWatchInstructionPointer(ANY_ADDR); + bp.setCounter(OOSTUBS_NUMINSTR); #endif - simulator.addEvent(&bp); - BPSingleEvent ev_count(ANY_ADDR); - simulator.addEvent(&ev_count); - - // count instructions - // FIXME add SAL functionality for this? - int instr_counter = 0; - while (simulator.waitAny() == &ev_count) { - ++instr_counter; + simulator.addEvent(&bp); + BPSingleEvent ev_count(ANY_ADDR); simulator.addEvent(&ev_count); - } - log << dec << "tracing finished after " << instr_counter << " instructions" << endl; + // count instructions + // FIXME add SAL functionality for this? + int instr_counter = 0; + while (simulator.waitAny() == &ev_count) { + ++instr_counter; + simulator.addEvent(&ev_count); + } + + log << dec << "tracing finished after " << instr_counter << " instructions" << endl; + //TODO: safe this value for experiment STEP 3 - simulator.removeFlow(&tp); + simulator.removeFlow(&tp); - // serialize trace to file - if (of.fail()) { - log << "failed to write " << tracefile << endl; - simulator.clearEvents(this); - return false; + // serialize trace to file + if (of.fail()) { + log << "failed to write " << tracefile << endl; + simulator.clearEvents(this); + return false; + } + of.close(); + log << "trace written to " << tracefile << endl; } - of.close(); - log << "trace written to " << tracefile << endl; -#elif 1 +#if 0 // STEP 3: The actual experiment. #if !LOCAL for (int i = 0; i < 400; ++i) { // more than 400 will be very slow (500 is max) diff --git a/src/experiments/ecos_kernel_test/experimentInfo.hpp b/src/experiments/ecos_kernel_test/experimentInfo.hpp index 05cf3d0c..e708ec83 100644 --- a/src/experiments/ecos_kernel_test/experimentInfo.hpp +++ b/src/experiments/ecos_kernel_test/experimentInfo.hpp @@ -1,40 +1,28 @@ #pragma once -// FIXME autogenerate this +// autogenerated, don't edit! -#if 1 // with ECC +// user-specified start-function address: +// nm -C thread1.elf|fgrep cyg_start +#define ECOS_FUNC_ENTRY 0x0000406c +// cyg_test_exit address +#define ECOS_FUNC_FINISH 0x00005eb0 +// cyg_test_output address +#define ECOS_FUNC_TEST_OUTPUT 0x00005eb8 +// the variable that's increased if ECC corrects an error: +#define ECOS_ERROR_CORRECTED 0x99999999 -// the task function's entry address: -// nm -C thread1 | fgrep cyg_start -#define ECOS_FUNC_ENTRY 0x00003cc0 -// empty function that is called explicitly when the experiment finished -// nm -C thread1 | fgrep cyg_test_exit -#define ECOS_FUNC_FINISH 0x000058dc -// nm -C thread1 | fgrep "cyg_test_output" -#define ECOS_FUNC_TEST_OUTPUT 0x000058e4 +// text begin: +// nm -C thread1.elf|fgrep _stext +#define ECOS_TEXT_START 0x00003000 +// text end: +// nm -C thread1.elf|fgrep _etext +#define ECOS_TEXT_END 0x00013c9e -// nm -C thread1 | grep "_[se]text" -#define ECOS_TEXT_START 0x00003000 -#define ECOS_TEXT_END 0x000092ce - -// number of instructions the target executes under non-error conditions from ENTRY to DONE: -// (result of experiment's step #2) -#define ECOS_NUMINSTR 12390 +// number of instructions the target executes under non-error conditions from ENTRY to FINISH: +#define ECOS_NUMINSTR 71618 // number of instructions that are executed additionally for error corrections // (this is a rough guess ... TODO) #define ECOS_RECOVERYINSTR 0x2000 -// the variable that's increased if ECC corrects an error: -// nm -C thread1|fgrep errors_corrected -#define ECOS_ERROR_CORRECTED 0x0010adec //FIXME TODO XXX -#else // without ECC - -#define COOL_ECC_FUNC_ENTRY 0x00200a90 -#define COOL_ECC_CALCDONE 0x00200ab7 -#define COOL_ECC_NUMINSTR 97 -#define COOL_ECC_OBJUNDERTEST 0x0021263c -#define COOL_ECC_OBJUNDERTEST_SIZE 10 -#define COOL_ECC_ERROR_CORRECTED 0x002127b0 // dummy - -#endif diff --git a/src/experiments/ecos_kernel_test/experimentInfo.hpp.sh b/src/experiments/ecos_kernel_test/experimentInfo.hpp.sh new file mode 100755 index 00000000..61ba9066 --- /dev/null +++ b/src/experiments/ecos_kernel_test/experimentInfo.hpp.sh @@ -0,0 +1,47 @@ +#!/bin/bash +set -e +TARGET=experimentInfo.hpp + +[ ! -e "$1" ] && echo "usage: $0 ecos_binary.elf" && exit 1 + +function addrof() { nm -C $1 | (fgrep "$2" || echo 99999999) | awk '{print $1}'; } + +cat >$TARGET <>$TARGET +cat >>$TARGET <