Skip to content

Commit

Permalink
Add --no-attack-time option to rowhammer scripts
Browse files Browse the repository at this point in the history
Signed-off-by: Michal Sieron <[email protected]>
  • Loading branch information
michalsieron authored and mtdudek committed Jul 12, 2023
1 parent 3e5960e commit dca184c
Show file tree
Hide file tree
Showing 3 changed files with 66 additions and 19 deletions.
10 changes: 10 additions & 0 deletions docs/source/usage.md
Original file line number Diff line number Diff line change
Expand Up @@ -206,6 +206,16 @@ Different attack and row selection modes can be used, but only one of them can b
(venv) $ python hw_rowhammer.py --row-pairs random --start-row 4 --nrows 10
```
- `--no-attack-time <time>`
Instead of performing a rowhammer attack, the script will load the RAM with selected pattern and sleep for `time` nanoseconds.
After this time, it will check for any bitflips that could have happened.
This option does not imply `--no-refresh`!
```sh
(venv) $ python hw_rowhammer.py --no-attack-time 100e9 --no-refresh
```
### Patterns
User can choose a pattern that memory will be initially filled with:
Expand Down
25 changes: 14 additions & 11 deletions rowhammer_tester/scripts/hw_rowhammer.py
Original file line number Diff line number Diff line change
Expand Up @@ -113,17 +113,20 @@ def run(self, row_pairs, pattern_generator, read_count, row_progress=16, verify_
print('\nDisabling refresh ...')
self.wb.regs.controller_settings_refresh.write(0)

print('\nRunning Rowhammer attacks ...')
for i, row_tuple in enumerate(row_pairs, start=1):
s = 'Iter {:{n}} / {:{n}}'.format(i, len(row_pairs), n=len(str(len(row_pairs))))
if self.payload_executor:
self.payload_executor_attack(read_count=read_count, row_tuple=row_tuple)
else:
if len(row_tuple) & (len(row_tuple) - 1) != 0:
print("ERROR: BIST only supports power of 2 rows\n")
return

self.attack(row_tuple, read_count=read_count, progress_header=s)
if self.no_attack_time is not None:
self.no_attack_sleep()
else:
print('\nRunning Rowhammer attacks ...')
for i, row_tuple in enumerate(row_pairs, start=1):
s = 'Iter {:{n}} / {:{n}}'.format(i, len(row_pairs), n=len(str(len(row_pairs))))
if self.payload_executor:
self.payload_executor_attack(read_count=read_count, row_tuple=row_tuple)
else:
if len(row_tuple) & (len(row_tuple) - 1) != 0:
print("ERROR: BIST only supports power of 2 rows\n")
return

self.attack(row_tuple, read_count=read_count, progress_header=s)

if self.no_refresh:
print('\nReenabling refresh ...')
Expand Down
50 changes: 42 additions & 8 deletions rowhammer_tester/scripts/rowhammer.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,9 +9,10 @@
import os

from pathlib import Path

from rowhammer_tester.scripts.utils import (
memfill, memcheck, memwrite, DRAMAddressConverter, litex_server, RemoteClient,
get_litedram_settings, get_generated_defs, execute_payload, read_ident)
get_litedram_settings, get_generated_defs, execute_payload, read_ident, _progress)
from rowhammer_tester.scripts.playbook.lib import (generate_payload_from_row_list)

################################################################################
Expand All @@ -37,6 +38,7 @@ def __init__(
no_refresh=False,
verbose=False,
payload_executor=False,
no_attack_time=None,
data_inversion=False):
for name, val in locals().items():
setattr(self, name, val)
Expand Down Expand Up @@ -204,6 +206,16 @@ def display_errors(self, row_errors, read_count, do_error_summary=False):
if do_error_summary:
return err_dict

def no_attack_sleep(self):
sleep_time = self.no_attack_time / 1e9
print(f"\nSleeping for {sleep_time} s as `--no-attack-time` flag was used ...")

for slept in range(int(10 * sleep_time)): # refresh every 0.1 s
time.sleep(0.1)
_progress((slept + 1) / 10, sleep_time, last=False, opt=f"Sleeping for {sleep_time} s")

print()

def run(self, row_pairs, pattern_generator, read_count, row_progress=16, verify_initial=False):
"""
Main part of the script.
Expand Down Expand Up @@ -244,13 +256,16 @@ def run(self, row_pairs, pattern_generator, read_count, row_progress=16, verify_
print('\nDisabling refresh ...')
self.wb.regs.controller_settings_refresh.write(0)

print('\nRunning Rowhammer attacks ...')
for i, row_tuple in enumerate(row_pairs, start=1):
s = 'Iter {:{n}} / {:{n}}'.format(i, len(row_pairs), n=len(str(len(row_pairs))))
if self.payload_executor:
self.payload_executor_attack(read_count=read_count, row_tuple=row_tuple)
else:
self.attack(row_tuple, read_count=read_count, progress_header=s)
if self.no_attack_time is not None:
self.no_attack_sleep()
else:
print('\nRunning Rowhammer attacks ...')
for i, row_tuple in enumerate(row_pairs, start=1):
s = 'Iter {:{n}} / {:{n}}'.format(i, len(row_pairs), n=len(str(len(row_pairs))))
if self.payload_executor:
self.payload_executor_attack(read_count=read_count, row_tuple=row_tuple)
else:
self.attack(row_tuple, read_count=read_count, progress_header=s)

if self.no_refresh:
print('\nReenabling refresh ...')
Expand Down Expand Up @@ -349,6 +364,10 @@ def main(row_hammer_cls):
'--all-rows',
action='store_true',
help='Run whole test sequence on all rows. Optionally, set --row-jump and --start-row')
row_selector_group.add_argument(
'--no-attack-time',
type=float,
help='Don\'t attack. Instead sleep for provided nanoseconds')
parser.add_argument(
'--row-pair-distance',
type=int,
Expand Down Expand Up @@ -436,6 +455,9 @@ def rand_row():
return rng.randint(args.start_row, args.start_row + args.nrows)

row_pairs = [(rand_row(), rand_row()) for i in range(args.nrows)]
elif args.no_attack_time is not None:
if args.no_attack_time < 0:
parser.error("No attack time can't be negative")
else:
parser.error("No operation specified")

Expand All @@ -462,6 +484,7 @@ def rand_row():
no_refresh=args.no_refresh,
payload_executor=args.payload_executor,
data_inversion=args.data_inversion,
no_attack_time=args.no_attack_time,
)

if args.log_dir:
Expand Down Expand Up @@ -503,6 +526,17 @@ def rand_row():
"hammer_row_2": pair[1],
"errors_in_rows": err_in_rows
}
elif args.no_attack_time is not None:
err_in_rows = row_hammer.run( # dummy row pair and read count
row_pairs=[(0, 0)], read_count=0, pattern_generator=pattern)

row_hammer.err_summary = {
"no_attack_time": {
str(args.no_attack_time): {
"errors_in_rows": err_in_rows,
},
},
}
else:
err_in_rows = row_hammer.run(
row_pairs=row_pairs, read_count=count, pattern_generator=pattern)
Expand Down

0 comments on commit dca184c

Please sign in to comment.