ecos: split valid mem access range
When eCos is built as a multiboot binary, some of its data structures are still at very low (<<1M) addresses, but the rest moves to addresses >1M. This change makes sure our invalid mem access detection is not overly generous. Change-Id: If8265a407b3706a4ff71562b316e05aa22255f62
This commit is contained in:
@ -43,20 +43,26 @@ bool EcosKernelTestCampaign::readMemoryMap(fail::MemoryMap &mm, char const * con
|
|||||||
return (count > 0);
|
return (count > 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool EcosKernelTestCampaign::writeTraceInfo(unsigned instr_counter, unsigned timeout, unsigned lowest_addr, unsigned highest_addr,
|
bool EcosKernelTestCampaign::writeTraceInfo(unsigned instr_counter, unsigned timeout,
|
||||||
|
unsigned mem1_low, unsigned mem1_high, // < 1M
|
||||||
|
unsigned mem2_low, unsigned mem2_high, // >= 1M
|
||||||
const std::string& variant, const std::string& benchmark) {
|
const std::string& variant, const std::string& benchmark) {
|
||||||
ofstream ti(filename_traceinfo(variant, benchmark).c_str(), ios::out);
|
ofstream ti(filename_traceinfo(variant, benchmark).c_str(), ios::out);
|
||||||
if (!ti.is_open()) {
|
if (!ti.is_open()) {
|
||||||
cout << "failed to open " << filename_traceinfo(variant, benchmark) << endl;
|
cout << "failed to open " << filename_traceinfo(variant, benchmark) << endl;
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
ti << instr_counter << endl << timeout << endl << lowest_addr << endl << highest_addr << endl;
|
ti << instr_counter << endl << timeout << endl
|
||||||
|
<< mem1_low << endl << mem1_high << endl
|
||||||
|
<< mem2_low << endl << mem2_high << endl;
|
||||||
ti.flush();
|
ti.flush();
|
||||||
ti.close();
|
ti.close();
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool EcosKernelTestCampaign::readTraceInfo(unsigned &instr_counter, unsigned &timeout, unsigned &lowest_addr, unsigned &highest_addr,
|
bool EcosKernelTestCampaign::readTraceInfo(unsigned &instr_counter, unsigned &timeout,
|
||||||
|
unsigned &mem1_low, unsigned &mem1_high, // < 1M
|
||||||
|
unsigned &mem2_low, unsigned &mem2_high, // >= 1M
|
||||||
const std::string& variant, const std::string& benchmark) {
|
const std::string& variant, const std::string& benchmark) {
|
||||||
ifstream file(filename_traceinfo(variant, benchmark).c_str());
|
ifstream file(filename_traceinfo(variant, benchmark).c_str());
|
||||||
if (!file.is_open()) {
|
if (!file.is_open()) {
|
||||||
@ -77,17 +83,23 @@ bool EcosKernelTestCampaign::readTraceInfo(unsigned &instr_counter, unsigned &ti
|
|||||||
ss >> timeout;
|
ss >> timeout;
|
||||||
break;
|
break;
|
||||||
case 2:
|
case 2:
|
||||||
ss >> lowest_addr;
|
ss >> mem1_low;
|
||||||
break;
|
break;
|
||||||
case 3:
|
case 3:
|
||||||
ss >> highest_addr;
|
ss >> mem1_high;
|
||||||
|
break;
|
||||||
|
case 4:
|
||||||
|
ss >> mem2_low;
|
||||||
|
break;
|
||||||
|
case 5:
|
||||||
|
ss >> mem2_high;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
count++;
|
count++;
|
||||||
}
|
}
|
||||||
file.close();
|
file.close();
|
||||||
assert(count == 4);
|
assert(count == 6);
|
||||||
return (count == 4);
|
return (count == 6);
|
||||||
}
|
}
|
||||||
|
|
||||||
std::string EcosKernelTestCampaign::filename_memorymap(const std::string& variant, const std::string& benchmark)
|
std::string EcosKernelTestCampaign::filename_memorymap(const std::string& variant, const std::string& benchmark)
|
||||||
@ -196,8 +208,9 @@ bool EcosKernelTestCampaign::run()
|
|||||||
|
|
||||||
// read trace info
|
// read trace info
|
||||||
unsigned instr_counter, estimated_timeout, lowest_addr, highest_addr;
|
unsigned instr_counter, estimated_timeout, lowest_addr, highest_addr;
|
||||||
|
// FIXME properly deal with 2nd memory range
|
||||||
EcosKernelTestCampaign::readTraceInfo(instr_counter,
|
EcosKernelTestCampaign::readTraceInfo(instr_counter,
|
||||||
estimated_timeout, lowest_addr, highest_addr, variant, benchmark);
|
estimated_timeout, lowest_addr, highest_addr, lowest_addr, highest_addr, variant, benchmark);
|
||||||
|
|
||||||
// a map of addresses of ECC protected objects
|
// a map of addresses of ECC protected objects
|
||||||
MemoryMap mm;
|
MemoryMap mm;
|
||||||
|
|||||||
@ -49,8 +49,8 @@ public:
|
|||||||
count_exp(0), count_exp_jobs(0), count_known(0), count_known_jobs(0) {}
|
count_exp(0), count_exp_jobs(0), count_known(0), count_known_jobs(0) {}
|
||||||
virtual bool run();
|
virtual bool run();
|
||||||
static bool readMemoryMap(fail::MemoryMap &mm, char const * const filename);
|
static bool readMemoryMap(fail::MemoryMap &mm, char const * const filename);
|
||||||
static bool writeTraceInfo(unsigned instr_counter, unsigned timeout, unsigned lowest_addr, unsigned highest_addr, const std::string& variant = "", const std::string& benchmark = "");
|
static bool writeTraceInfo(unsigned instr_counter, unsigned timeout, unsigned mem1_low, unsigned mem1_high, unsigned mem2_low, unsigned mem2_high, const std::string& variant = "", const std::string& benchmark = "");
|
||||||
static bool readTraceInfo(unsigned &instr_counter, unsigned &timeout, unsigned &lowest_addr, unsigned &highest_addr, const std::string& variant = "", const std::string& benchmark = "");
|
static bool readTraceInfo(unsigned &instr_counter, unsigned &timeout, unsigned &mem1_low, unsigned &mem1_high, unsigned &mem2_low, unsigned &mem2_high, const std::string& variant = "", const std::string& benchmark = "");
|
||||||
static std::string filename_memorymap(const std::string& variant = "", const std::string& benchmark = "");
|
static std::string filename_memorymap(const std::string& variant = "", const std::string& benchmark = "");
|
||||||
static std::string filename_state(unsigned instr_offset, const std::string& variant = "", const std::string& benchmark = "");
|
static std::string filename_state(unsigned instr_offset, const std::string& variant = "", const std::string& benchmark = "");
|
||||||
static std::string filename_trace(const std::string& variant = "", const std::string& benchmark = "");
|
static std::string filename_trace(const std::string& variant = "", const std::string& benchmark = "");
|
||||||
|
|||||||
@ -209,8 +209,12 @@ bool EcosKernelTestExperiment::performTrace(guest_address_t addr_entry, guest_ad
|
|||||||
// on the way, record lowest and highest memory address accessed
|
// on the way, record lowest and highest memory address accessed
|
||||||
MemAccessListener ev_mem(ANY_ADDR, MemAccessEvent::MEM_READWRITE);
|
MemAccessListener ev_mem(ANY_ADDR, MemAccessEvent::MEM_READWRITE);
|
||||||
simulator.addListener(&ev_mem);
|
simulator.addListener(&ev_mem);
|
||||||
unsigned lowest_addr = 0xFFFFFFFFUL;
|
// range for mem accesses < 1M
|
||||||
unsigned highest_addr = 0;
|
unsigned mem1_low = 0xFFFFFFFFUL;
|
||||||
|
unsigned mem1_high = 0;
|
||||||
|
// range for mem accesses >= 1M
|
||||||
|
unsigned mem2_low = 0xFFFFFFFFUL;
|
||||||
|
unsigned mem2_high = 0;
|
||||||
|
|
||||||
// do the job, 'till the end
|
// do the job, 'till the end
|
||||||
BaseListener* ev = simulator.resume();
|
BaseListener* ev = simulator.resume();
|
||||||
@ -233,11 +237,14 @@ bool EcosKernelTestExperiment::performTrace(guest_address_t addr_entry, guest_ad
|
|||||||
unsigned lo = ev_mem.getTriggerAddress();
|
unsigned lo = ev_mem.getTriggerAddress();
|
||||||
unsigned hi = lo + ev_mem.getTriggerWidth() - 1;
|
unsigned hi = lo + ev_mem.getTriggerWidth() - 1;
|
||||||
|
|
||||||
if (hi > highest_addr && (hi < VIDEOMEM_START || hi >= VIDEOMEM_END)) {
|
if (lo < VIDEOMEM_START || lo >= VIDEOMEM_END) {
|
||||||
highest_addr = hi;
|
if (hi < 1024*1024) { // < 1M
|
||||||
}
|
if (hi > mem1_high) { mem1_high = hi; }
|
||||||
if (lo < lowest_addr && (lo < VIDEOMEM_START || lo >= VIDEOMEM_END)) {
|
if (lo < mem1_low) { mem1_low = lo; }
|
||||||
lowest_addr = lo;
|
} else { // >= 1M
|
||||||
|
if (hi > mem2_high) { mem2_high = hi; }
|
||||||
|
if (lo < mem2_low) { mem2_low = lo; }
|
||||||
|
}
|
||||||
}
|
}
|
||||||
simulator.addListener(&ev_mem);
|
simulator.addListener(&ev_mem);
|
||||||
}
|
}
|
||||||
@ -252,12 +259,20 @@ bool EcosKernelTestExperiment::performTrace(guest_address_t addr_entry, guest_ad
|
|||||||
unsigned estimated_timeout = (unsigned)estimated_timeout_overflow_check;
|
unsigned estimated_timeout = (unsigned)estimated_timeout_overflow_check;
|
||||||
|
|
||||||
log << dec << "tracing finished after " << instr_counter << " instructions" << endl;
|
log << dec << "tracing finished after " << instr_counter << " instructions" << endl;
|
||||||
log << hex << "all memory accesses within [ 0x" << lowest_addr << " , 0x" << highest_addr << " ] (ignoring VGA mem)" << endl;
|
log << hex << "all memory accesses within [0x" << mem1_low << ", 0x" << mem1_high << "] u [0x" << mem2_low << ", 0x" << mem2_high << "] (ignoring VGA mem)" << endl;
|
||||||
log << dec << "elapsed simulated time (plus safety margin): " << (estimated_timeout * TIMER_GRANULARITY / 1000000.0) << "s" << endl;
|
log << dec << "elapsed simulated time (plus safety margin): " << (estimated_timeout * TIMER_GRANULARITY / 1000000.0) << "s" << endl;
|
||||||
|
|
||||||
|
// sanitize memory ranges
|
||||||
|
if (mem1_low > mem1_high) {
|
||||||
|
mem1_low = mem1_high = 0;
|
||||||
|
}
|
||||||
|
if (mem2_low > mem2_high) {
|
||||||
|
mem2_low = mem2_high = 1024*1024;
|
||||||
|
}
|
||||||
|
|
||||||
// save these values for experiment STEP 3
|
// save these values for experiment STEP 3
|
||||||
EcosKernelTestCampaign::writeTraceInfo(instr_counter, estimated_timeout,
|
EcosKernelTestCampaign::writeTraceInfo(instr_counter, estimated_timeout,
|
||||||
lowest_addr, highest_addr, m_variant, m_benchmark);
|
mem1_low, mem1_high, mem2_low, mem2_high, m_variant, m_benchmark);
|
||||||
|
|
||||||
simulator.removeFlow(&tp);
|
simulator.removeFlow(&tp);
|
||||||
|
|
||||||
@ -277,7 +292,7 @@ bool EcosKernelTestExperiment::faultInjection() {
|
|||||||
log << "STEP 3: The actual experiment." << endl;
|
log << "STEP 3: The actual experiment." << endl;
|
||||||
|
|
||||||
// trace info
|
// trace info
|
||||||
unsigned instr_counter, estimated_timeout, lowest_addr, highest_addr;
|
unsigned instr_counter, estimated_timeout, mem1_low, mem1_high, mem2_low, mem2_high;
|
||||||
// ELF symbol addresses
|
// ELF symbol addresses
|
||||||
guest_address_t addr_entry, addr_finish, addr_test_output, addr_errors_corrected,
|
guest_address_t addr_entry, addr_finish, addr_test_output, addr_errors_corrected,
|
||||||
addr_panic, addr_text_start, addr_text_end;
|
addr_panic, addr_text_start, addr_text_end;
|
||||||
@ -317,7 +332,7 @@ bool EcosKernelTestExperiment::faultInjection() {
|
|||||||
int mem_addr = param.msg.mem_addr();
|
int mem_addr = param.msg.mem_addr();
|
||||||
|
|
||||||
EcosKernelTestCampaign::readTraceInfo(instr_counter, estimated_timeout,
|
EcosKernelTestCampaign::readTraceInfo(instr_counter, estimated_timeout,
|
||||||
lowest_addr, highest_addr, m_variant, m_benchmark);
|
mem1_low, mem1_high, mem2_low, mem2_high, m_variant, m_benchmark);
|
||||||
readELFSymbols(addr_entry, addr_finish, addr_test_output,
|
readELFSymbols(addr_entry, addr_finish, addr_test_output,
|
||||||
addr_errors_corrected, addr_panic, addr_text_start, addr_text_end);
|
addr_errors_corrected, addr_panic, addr_text_start, addr_text_end);
|
||||||
|
|
||||||
@ -433,19 +448,25 @@ bool EcosKernelTestExperiment::faultInjection() {
|
|||||||
simulator.addListener(&ev_below_text);
|
simulator.addListener(&ev_below_text);
|
||||||
simulator.addListener(&ev_beyond_text);
|
simulator.addListener(&ev_beyond_text);
|
||||||
|
|
||||||
// memory access outside of bound determined in the golden run [lowest_addr, highest_addr]
|
// memory access outside of bound determined in the golden run
|
||||||
|
// [mem1_low, mem1_high] u [mem2_low, mem2_high]
|
||||||
// video memory accesses are OK, too
|
// video memory accesses are OK, too
|
||||||
// FIXME: It would be nice to have a MemAccessListener that accepts a MemoryMap.
|
// FIXME: It would be nice to have a MemAccessListener that accepts a
|
||||||
assert(lowest_addr < highest_addr && highest_addr < VIDEOMEM_START);
|
// MemoryMap, to have MemoryMaps that store addresses in a compact way,
|
||||||
MemAccessListener ev_mem_low(0x0, MemAccessEvent::MEM_READWRITE);
|
// and that are invertible.
|
||||||
ev_mem_low.setWatchWidth(lowest_addr);
|
assert(mem1_low < mem1_high && mem1_high < VIDEOMEM_START && VIDEOMEM_END < mem2_low && mem2_low < mem2_high);
|
||||||
MemAccessListener ev_mem_high(highest_addr + 1, MemAccessEvent::MEM_READWRITE);
|
MemAccessListener ev_mem_outside1(0x0, MemAccessEvent::MEM_READWRITE);
|
||||||
ev_mem_high.setWatchWidth(VIDEOMEM_START - (highest_addr + 1));
|
ev_mem_outside1.setWatchWidth(mem1_low);
|
||||||
MemAccessListener ev_mem_veryhigh(VIDEOMEM_END, MemAccessEvent::MEM_READWRITE);
|
MemAccessListener ev_mem_outside2(mem1_high + 1, MemAccessEvent::MEM_READWRITE);
|
||||||
ev_mem_high.setWatchWidth(0xFFFFFFFFU - VIDEOMEM_END);
|
ev_mem_outside2.setWatchWidth(VIDEOMEM_START - (mem1_high + 1));
|
||||||
simulator.addListener(&ev_mem_low);
|
MemAccessListener ev_mem_outside3(VIDEOMEM_END, MemAccessEvent::MEM_READWRITE);
|
||||||
simulator.addListener(&ev_mem_high);
|
ev_mem_outside3.setWatchWidth(mem2_low - VIDEOMEM_END);
|
||||||
simulator.addListener(&ev_mem_veryhigh);
|
MemAccessListener ev_mem_outside4(mem2_high + 1, MemAccessEvent::MEM_READWRITE);
|
||||||
|
ev_mem_outside4.setWatchWidth(0xFFFFFFFFU - (mem2_high + 1));
|
||||||
|
simulator.addListener(&ev_mem_outside1);
|
||||||
|
simulator.addListener(&ev_mem_outside2);
|
||||||
|
simulator.addListener(&ev_mem_outside3);
|
||||||
|
simulator.addListener(&ev_mem_outside4);
|
||||||
|
|
||||||
// timeout (e.g., stuck in a HLT instruction)
|
// timeout (e.g., stuck in a HLT instruction)
|
||||||
TimerListener ev_timeout(estimated_timeout);
|
TimerListener ev_timeout(estimated_timeout);
|
||||||
@ -555,7 +576,8 @@ bool EcosKernelTestExperiment::faultInjection() {
|
|||||||
} else if (ev == &ev_below_text || ev == &ev_beyond_text) {
|
} else if (ev == &ev_below_text || ev == &ev_beyond_text) {
|
||||||
log << "Result OUTSIDE" << endl;
|
log << "Result OUTSIDE" << endl;
|
||||||
result->set_resulttype(result->OUTSIDE);
|
result->set_resulttype(result->OUTSIDE);
|
||||||
} else if (ev == &ev_mem_low || ev == &ev_mem_high || ev == &ev_mem_veryhigh) {
|
} else if (ev == &ev_mem_outside1 || ev == &ev_mem_outside2
|
||||||
|
|| ev == &ev_mem_outside3 || ev == &ev_mem_outside4) {
|
||||||
log << "Result MEMORYACCESS" << endl;
|
log << "Result MEMORYACCESS" << endl;
|
||||||
result->set_resulttype(result->MEMORYACCESS);
|
result->set_resulttype(result->MEMORYACCESS);
|
||||||
} else if (ev == &ev_trap) {
|
} else if (ev == &ev_trap) {
|
||||||
|
|||||||
Reference in New Issue
Block a user