diff --git a/sofia-ovp/FI.sh b/sofia-ovp/FI.sh index f8b3bf84..553bc020 100755 --- a/sofia-ovp/FI.sh +++ b/sofia-ovp/FI.sh @@ -93,7 +93,93 @@ function generateFaultList2 { fi # Not generating faults =register if [[ "$FAULT_TYPE" == "memory" ]]; then - CMD_FAULT_LIST="$CMD_FAULT_LIST --memlowaddress=$TARGET_MEM_BASE --memhighaddress=$TARGET_MEM_SIZE" + # Get the memory range from a target ELF section + if [[ "$WORKLOAD_TYPE" == "WORKLOAD_BAREMETAL" ]] && [[ -n "$APPLICATIONS_NAME" ]] && [[ -n "$TARGET_MEM_SECTION" ]]; then + echo "Target section: [$TARGET_MEM_SECTION]" + + # Select appropriate readelf based on architecture + if [[ "$ARCHITECTURE" =~ ^RISCV.* ]]; then + TARGET_READELF=$RISCV_TOOLCHAIN_BAREMETAL'/bin/'$RISCV_TOOLCHAIN_BAREMETAL_PREFIX'-readelf' + else + TARGET_READELF=$AARCH64_TOOLCHAIN_BAREMETAL'/bin/aarch64-none-elf-readelf' + fi + + if ! $TARGET_READELF -S "$APPLICATIONS_NAME" > applicationSections 2>/dev/null; then + echo "Error: Failed to read ELF sections from $APPLICATIONS_NAME" + exit 1 + fi + + # Function to extract section information + extract_section_info() { + local section_name="$1" + local section_info=$(grep -A 1 "\\.${section_name#.} " applicationSections) + + if [[ -n "$section_info" ]]; then + local address=$(echo "$section_info" | head -n1 | tr -s ' ' | cut -d' ' -f6) + local size=$(echo "$section_info" | tail -n1 | tr -s ' ' | cut -d' ' -f2) + echo "Found $section_name section at address: $address, size: $size" + + # Return values via global variables + SECTION_ADDRESS="$address" + SECTION_SIZE="$size" + return 0 + else + echo "Warning: Section $section_name not found" + SECTION_ADDRESS="" + SECTION_SIZE="" + return 1 + fi + } + + # Extract section information + if [[ "$TARGET_MEM_SECTION" == ".stack" ]]; then + # Stack range comes from golden run SP tracking, not from ELF + if [[ ! -f goldinformation ]]; then + echo "Error: goldinformation not found. Run golden first." + exit 1 + fi + SP_MIN=$(grep "Stack SP Min=" goldinformation | cut -d'=' -f2) + SP_INITIAL=$(grep "Stack SP Initial=" goldinformation | cut -d'=' -f2) + if [[ -z "$SP_MIN" || -z "$SP_INITIAL" ]]; then + echo "Error: Stack range not found in goldinformation." + echo " Re-run golden with updated faultInjector/intercept." + exit 1 + fi + MEM_LOW="$SP_MIN" + MEM_HIGH="$SP_INITIAL" + STACK_SIZE=$((MEM_HIGH - MEM_LOW)) + echo "Stack range: [$MEM_LOW] to [$MEM_HIGH] ($STACK_SIZE bytes)" + CMD_FAULT_LIST="$CMD_FAULT_LIST --memlowaddress=$MEM_LOW --memhighaddress=$MEM_HIGH" + elif extract_section_info "$TARGET_MEM_SECTION"; then + ADDRESS="$SECTION_ADDRESS" + SIZE="$SECTION_SIZE" + + # Calculate the final memory range + # Start: beginning of the section + # End: end of the section (address + size) + MEM_START_HEX="$ADDRESS" + MEM_END_HEX=$(printf "%016x" $((0x$ADDRESS + 0x$SIZE))) + + echo "Memory range calculated:" + echo " Final range: 0x$MEM_START_HEX to 0x$MEM_END_HEX" + + # Convert addresses to decimal for the fault list generator + MEM_LOW=$(echo "ibase=16;obase=A; $(echo "$MEM_START_HEX" | tr "a-z" "A-Z")" | bc) + MEM_HIGH=$(echo "ibase=16;obase=A; $(echo "$MEM_END_HEX" | tr "a-z" "A-Z")" | bc) + + # Log memory details + echo "$CURRENT_APPLICATION Memory Range for Physical Memory Fault Injection on $ARCHITECTURE" >> memory_details.log + echo "application, section, mem_start, mem_end, range_size_bytes" >> memory_details.log + echo "$CURRENT_APPLICATION, $TARGET_MEM_SECTION, $MEM_LOW, $MEM_HIGH, $((MEM_HIGH - MEM_LOW))" >> memory_details.log + CMD_FAULT_LIST="$CMD_FAULT_LIST --memlowaddress=$MEM_LOW --memhighaddress=$MEM_HIGH" + else + echo "Error: Could not find section $TARGET_MEM_SECTION" + exit 1 + fi + else + # Use provided TARGET_MEM_BASE and TARGET_MEM_SIZE for non-baremetal or when not extracting from ELF + CMD_FAULT_LIST="$CMD_FAULT_LIST --memlowaddress=$TARGET_MEM_BASE --memhighaddress=$TARGET_MEM_SIZE" + fi GENERATE_FAULT_LIST_DISTR=0 # Don't necessary fi @@ -503,12 +589,15 @@ function configureCommands { [[ "$ARCHITECTURE" = 'ARM_CORTEX_M33F' ]] ; then CMD_OVP="$CMD_OVP --override compatibility=nopBKPT " fi - #~ elif [[ "$ARCHITECTURE" = 'ARM_CORTEX_A53' ]] || [[ "$ARCHITECTURE" = 'ARM_CORTEX_A57' ]] || [[ "$ARCHITECTURE" = 'ARM_CORTEX_A72' ]]; then - #~ CMD_OVP="$CMD_OVP" - #~ elif [[ "$ARCHITECTURE" = 'ARM_CORTEX_M0' ]]; then - #~ CMD_OVP="$CMD_OVP --override compatibility=nopSVC " - #~ fi - + + # Enable floating-point for RISC-V variants with an FPU + if [[ "$ARCHITECTURE" = 'RISCV32GC' ]] || \ + [[ "$ARCHITECTURE" = 'RISCV64GC' ]] || \ + [[ "$ARCHITECTURE" =~ RISCV.*F.* ]] || \ + [[ "$ARCHITECTURE" =~ RISCV.*D.* ]]; then + CMD_OVP="$CMD_OVP --override mstatus_FS=1 " + fi + ;; # End baremetal WORKLOAD_LINUX) case "$ARCHITECTURE" in diff --git a/sofia-ovp/gui/classification.py b/sofia-ovp/gui/classification.py index 2647265f..3a97fc43 100644 --- a/sofia-ovp/gui/classification.py +++ b/sofia-ovp/gui/classification.py @@ -31,7 +31,14 @@ def possibleregisters(self,environment): elif environment==environmentsE.ovpmips.name: self.listOfpossibleRegisters = ["at","v0","v1","a0","a1","a2","a3","t0","t1","t2","t3","t4","t5","t6","t7","s0","s1","s2","s3","s4","s5","s6","s7","t8","t9","k0","k1","gp","sp","s8","ra","pc"] elif environment==environmentsE.riscv.name: - self.listOfpossibleRegisters = ["ra","sp","gp","tp","t0","t1","t2","s0","s1","a0","a1","a2","a3","a4","a5","a6","a7","s2","s3","s4","s5","s6","s7","s8","s9","s10","s11","t3","t4","t5","t6","pc"] + self.listOfpossibleRegisters = [ + # integer ABI + "ra","sp","gp","tp","t0","t1","t2","s0","s1","a0","a1","a2","a3","a4","a5","a6","a7", + "s2","s3","s4","s5","s6","s7","s8","s9","s10","s11","t3","t4","t5","t6","pc", + # floating-point ABI + "ft0","ft1","ft2","ft3","ft4","ft5","ft6","ft7","fs0","fs1", + "fa0","fa1","fa2","fa3","fa4","fa5","fa6","fa7", + "fs2","fs3","fs4","fs5","fs6","fs7","fs8","fs9","fs10","fs11","ft8","ft9","ft10","ft11"] else: parser.error("One environment is required") diff --git a/sofia-ovp/gui/faultlist.py b/sofia-ovp/gui/faultlist.py index ca2a89cd..c1a4254f 100644 --- a/sofia-ovp/gui/faultlist.py +++ b/sofia-ovp/gui/faultlist.py @@ -191,7 +191,17 @@ def createfaultlist(self): possibletargetcores.remove(faultCore) # insertion time -- each core has a different instruction count - faultTime = randint(0, int(int(coreinstcount[faultCore]) - int(corebegin[faultCore])) ) + int(corebegin[faultCore]) + # Apply minimum fault time if specified (skip early initialization) + minFaultTime = int(corebegin[faultCore]) + if hasattr(self.options, 'minfaulttime') and self.options.minfaulttime > 0: + minFaultTime = max(minFaultTime, int(corebegin[faultCore]) + self.options.minfaulttime) + + maxFaultTime = int(coreinstcount[faultCore]) + if minFaultTime >= maxFaultTime: + # If min time exceeds execution, use the last 10% of execution + minFaultTime = int(maxFaultTime * 0.9) + + faultTime = randint(minFaultTime, maxFaultTime) # # Fault target and mask for each fault type diff --git a/sofia-ovp/gui/options.py b/sofia-ovp/gui/options.py index a0f60c9e..32f066c6 100644 --- a/sofia-ovp/gui/options.py +++ b/sofia-ovp/gui/options.py @@ -48,7 +48,8 @@ def __init__(self): self.options.append(optionsFIM(name="Trace Symbol", buttom="string", buttomobj=None, entry=None, module="TR", command="--tracesymbol", action="store", type="string", dest="tracesymbol", default="", help="Trace:")) self.options.append(optionsFIM(name="Number of Bit Flips", buttom="string", buttomobj=None, entry=None, module="FI", command="--bitflips", action="store", type="int", dest="bitFlips", default=1, help="Number of bits to flip")) self.options.append(optionsFIM(name="Sequential Bit Flips", buttom="tick", buttomobj=None, entry=None, module="FI", command="--seqflip", action="store_true", dest="sequentialBits", default=False, help="Flip n sequential bits")) - + self.options.append(optionsFIM(name="Min Fault Time", buttom="string", buttomobj=None, entry=None, module="FI", command="--minfaulttime", action="store", type="int", dest="minfaulttime", default="0", help="Fault generation: minimum instruction count before starting fault injection (skip early initialization)")) + def getOptionL(self): return self.options diff --git a/sofia-ovp/platformOP/commonStructsAndEnumerators.h b/sofia-ovp/platformOP/commonStructsAndEnumerators.h index 7a7dc0ba..39d31894 100755 --- a/sofia-ovp/platformOP/commonStructsAndEnumerators.h +++ b/sofia-ovp/platformOP/commonStructsAndEnumerators.h @@ -3,11 +3,25 @@ ///////////////////////////////////////////////////////////////////////// #define END_LIST "EndList@" -char possibleRegisters[50][10]; +// Working buffer that holds the active arch's register list (copied in faultInjector.c). +// Must cover the largest list: ARMv8 int(33)+SIMD(32)+END = 66 entries already exceed 50. +// MAX_REGISTERS gives headroom; bump it if a longer list is ever added. +#define MAX_REGISTERS 80 +#define MAX_REGISTER_NAME_LEN 10 +char possibleRegisters[MAX_REGISTERS][MAX_REGISTER_NAME_LEN]; int numberOfRegistersToCompare; const char possibleRegistersV7[][10] ={"r0","r1","r2","r3","r4","r5","r6","r7","r8","r9","r10","r11","r12","sp","lr","pc","d0","d1","d2","d3","d4","d5","d6","d7","d8","d9","d10","d11","d12","d13","d14","d15",END_LIST}; const char possibleRegistersV8[][10] ={"x0","x1","x2","x3","x4","x5","x6","x7","x8","x9","x10","x11","x12","x13","x14","x15","x16","x17","x18","x19","x20","x21","x22","x23","x24","x25","x26","x27","x28","x29","x30","sp","pc","v0","v1","v2","v3","v4","v5","v6","v7","v8","v9","v10","v11","v12","v13","v14","v15","v16","v17","v18","v19","v20","v21","v22","v23","v24","v25","v26","v27","v28","v29","v30","v31",END_LIST}; -const char possibleRegistersRV[][10] ={"ra","sp","gp","tp","t0","t1","t2","s0","s1","a0","a1","a2","a3","a4","a5","a6","a7","s2","s3","s4","s5","s6","s7","s8","s9","s10","s11","t3","t4","t5","t6","pc",END_LIST}; +// RISC-V: integer ABI (RV64I) + floating-point ABI (RV64D/F) +const char possibleRegistersRV[][10] ={ + // Integer + "ra","sp","gp","tp","t0","t1","t2","s0","s1","a0","a1","a2","a3","a4","a5","a6","a7", + "s2","s3","s4","s5","s6","s7","s8","s9","s10","s11","t3","t4","t5","t6","pc", + // Floating-point + "ft0","ft1","ft2","ft3","ft4","ft5","ft6","ft7","fs0","fs1", + "fa0","fa1","fa2","fa3","fa4","fa5","fa6","fa7", + "fs2","fs3","fs4","fs5","fs6","fs7","fs8","fs9","fs10","fs11","ft8","ft9","ft10","ft11", + END_LIST}; #include "options.h" diff --git a/sofia-ovp/platformOP/harness/faultInjector.c b/sofia-ovp/platformOP/harness/faultInjector.c index e6294bb9..55ffab4a 100755 --- a/sofia-ovp/platformOP/harness/faultInjector.c +++ b/sofia-ovp/platformOP/harness/faultInjector.c @@ -186,6 +186,8 @@ void initialize() { do {numberOfRegistersToCompare++;} while(strcmp(END_LIST,possibleRegistersV7[numberOfRegistersToCompare]) != 0 ); + if(numberOfRegistersToCompare > MAX_REGISTERS) numberOfRegistersToCompare = MAX_REGISTERS; + for(int i=0; i MAX_REGISTERS) numberOfRegistersToCompare = MAX_REGISTERS; + for(int i=0; i MAX_REGISTERS) numberOfRegistersToCompare = MAX_REGISTERS; + for(int i=0; i NOP operation or 0X4770bf00 ARMv7-M NOP or 0X477046c0 ARMv6-M NOP or 0Xd503201f AARCH64-a NOP ) - if(checker!=0xe320f000 && checker!=0X4770bf00 && checker!=0X477046c0 && checker!=0Xd503201f) + if(checker!=NOP_ARMV7A && checker!=NOP_ARMV7M && checker!=NOP_ARMV6M && + checker!=NOP_AARCH64 && checker!=NOP_RISCV && checker!=NOP_RISCV_C) return; /// update the return code @@ -559,6 +596,27 @@ static VMIOS_INTERCEPT_FN(serviceHandler) { fclose(fileTrace); } + // Write stack range to file for stack injection campaigns + if (sp_tracking_active) { + FILE *stackFile = fopen(FOLDER_DUMPS"/stack_range.txt", "w"); + if (stackFile) { + fprintf(stackFile, "Stack SP Initial=" FMT_64u "\n", sp_initial); + fprintf(stackFile, "Stack SP Min=" FMT_64u "\n", sp_min); + fprintf(stackFile, "Stack Size=%lu\n", (unsigned long)(sp_initial - sp_min)); + fclose(stackFile); + vmiMessage("I", PREFIX_FIM, + "Stack range: 0x%llx - 0x%llx (%lu bytes)\n", + (unsigned long long)sp_min, + (unsigned long long)sp_initial, + (unsigned long)(sp_initial - sp_min)); + } + // Remove the watchpoint + if (spWatchHandle) { + vmirtDeleteRegisterWatchCallback(spWatchHandle); + spWatchHandle = NULL; + } + } + } else { // Fault Injection Platform /// XXXXExecutes in both gold and fault injection platform @@ -713,6 +771,17 @@ VMIOS_MORPH_FN(instrTrace) { static VMIOS_CONSTRUCTOR_FN(constructor) { paramValuesP params = parameterValues; processorData = (processorDataP) params->processorData; + + // Register SP write watchpoint for stack range tracking + vmiRegInfoCP spReg = vmiosGetRegDesc(processor, "sp"); + if (spReg) { + spWatchHandle = vmirtAddRegisterWatchCallback( + processor, spReg, spValueChanged, NULL + ); + vmiMessage("I", PREFIX_FIM, "SP write watchpoint registered in constructor\n"); + } else { + vmiMessage("W", PREFIX_FIM, "SP register not found - stack tracking disabled\n"); + } } // diff --git a/sofia-ovp/support/tools/classification.py b/sofia-ovp/support/tools/classification.py index 37106b68..08067d8d 100755 --- a/sofia-ovp/support/tools/classification.py +++ b/sofia-ovp/support/tools/classification.py @@ -32,7 +32,14 @@ def getListOfpossibleRegisters(self,options,parser): elif options.environment==archtecturesE.ovpmips.name: self.listOfpossibleRegisters = ["at","v0","v1","a0","a1","a2","a3","t0","t1","t2","t3","t4","t5","t6","t7","s0","s1","s2","s3","s4","s5","s6","s7","t8","t9","k0","k1","gp","sp","s8","ra","pc"] elif options.environment==archtecturesE.riscv.name: - self.listOfpossibleRegisters = ["ra","sp","gp","tp","t0","t1","t2","s0","s1","a0","a1","a2","a3","a4","a5","a6","a7","s2","s3","s4","s5","s6","s7","s8","s9","s10","s11","t3","t4","t5","t6","pc"] + self.listOfpossibleRegisters = [ + # integer ABI + "ra","sp","gp","tp","t0","t1","t2","s0","s1","a0","a1","a2","a3","a4","a5","a6","a7", + "s2","s3","s4","s5","s6","s7","s8","s9","s10","s11","t3","t4","t5","t6","pc", + # floating-point ABI + "ft0","ft1","ft2","ft3","ft4","ft5","ft6","ft7","fs0","fs1", + "fa0","fa1","fa2","fa3","fa4","fa5","fa6","fa7", + "fs2","fs3","fs4","fs5","fs6","fs7","fs8","fs9","fs10","fs11","ft8","ft9","ft10","ft11"] else: parser.error("One environment is required")