def execute(wb): depth = wb.mems.payload.size // 4 # bytes to 32-bit instructions program = [w for w in PAYLOAD] program += [0] * (wb.mems.payload.size // 4 - len(program) ) # fill with NOOPs # Write some data to the column we are reading to check that scratchpad gets filled converter = DRAMAddressConverter() data = list(itertools.islice(word_gen(3), 128)) memwrite(wb, data, base=converter.encode_bus(bank=0, row=100, col=200)) print('\nTransferring the payload ...') memwrite(wb, program, base=wb.mems.payload.base) def ready(): status = wb.regs.payload_executor_status.read() return (status & 1) != 0 print('\nExecuting ...') assert ready() wb.regs.payload_executor_start.write(1) while not ready(): time.sleep(0.001) print('Finished') print('\nScratchpad contents:') scratchpad = memread(wb, n=512 // 4, base=wb.mems.scratchpad.base) memdump(scratchpad, base=0)
def __init__(self, wb, *, nrows, bankbits, rowbits, colbits, column, bank, rows_start=0, no_refresh=False, verbose=False, plot=False, payload_executor=False): for name, val in locals().items(): setattr(self, name, val) self.converter = DRAMAddressConverter(colbits=colbits, rowbits=rowbits) self.addresses_per_row = self._addresses_per_row()
def get_range_from_rows(wb, settings, row_nums): conv = DRAMAddressConverter.load() min_row = min(row_nums) max_row = max(row_nums) + 1 start = conv.encode_bus(bank=0, row=min_row, col=0) if max_row < 2**settings.geom.rowbits: end = conv.encode_bus(bank=0, row=max_row, col=0) else: end = wb.mems.main_ram.base + wb.mems.main_ram.size return start - wb.mems.main_ram.base, end - start
def main(): valid_keys = set( [ "payload_generator", "payload_generator_config", "inversion_divisor", "inversion_mask", "row_pattern" ]) parser = argparse.ArgumentParser() parser.add_argument("config_file", type=open) args = parser.parse_args() config_string = "" config_lines = args.config_file.readlines() for line in config_lines: index = line.find('#') if index >= 0: line = line[0:index] line += '\n' config_string += line config = json.loads(config_string) assert validate_keys(config, valid_keys) args.config_file.close() pg = PayloadGenerator.get_by_name(config["payload_generator"]) pg.initialize(config) wb = RemoteClient() wb.open() settings = get_litedram_settings() inversion_divisor = 0 inversion_mask = 0 inversion_divisor = config.get("inversion_divisor", 0) inversion_mask = int(config.get("inversion_mask", "0"), 0) row_pattern = config.get("row_pattern", 0) setup_inverters(wb, inversion_divisor, inversion_mask) while not pg.done(): offset, size = pg.get_memset_range(wb, settings) hw_memset(wb, offset, size, [row_pattern]) converter = DRAMAddressConverter.load() bank = 0 sys_clk_freq = float(get_generated_defs()['SYS_CLK_FREQ']) payload = pg.get_payload( settings=settings, bank=bank, payload_mem_size=wb.mems.payload.size, sys_clk_freq=sys_clk_freq) execute_payload(wb, payload) offset, size = pg.get_memtest_range(wb, settings) errors = hw_memtest(wb, offset, size, [row_pattern]) row_errors = decode_errors(wb, settings, converter, bank, errors) pg.process_errors(settings, row_errors) pg.summarize() wb.close()
def __init__(self, wb, *, settings, nrows, column, bank, rows_start=0, no_refresh=False, verbose=False, plot=False, payload_executor=False): for name, val in locals().items(): setattr(self, name, val) self.converter = DRAMAddressConverter.load() self._addresses_per_row = {}
class RowHammer: def __init__(self, wb, *, nrows, bankbits, rowbits, colbits, column, bank, rows_start=0, no_refresh=False, verbose=False, plot=False, payload_executor=False): for name, val in locals().items(): setattr(self, name, val) self.converter = DRAMAddressConverter(colbits=colbits, rowbits=rowbits) self.addresses_per_row = self._addresses_per_row() @property def rows(self): return list(range(self.rows_start, self.nrows)) def _addresses_per_row(self): addresses = {} for row in self.rows: addresses[row] = [self.converter.encode_bus(bank=self.bank, col=col, row=row) for col in range(2**self.colbits)] return addresses def attack(self, row1, row2, read_count, progress_header=''): # Make sure that the row hammer module is in reset state self.wb.regs.rowhammer_enabled.write(0) self.wb.regs.rowhammer_count.read() # clears the value # Configure the row hammer attacker addresses = [self.converter.encode_dma(bank=self.bank, col=self.column, row=r) for r in [row1, row2]] self.wb.regs.rowhammer_address1.write(addresses[0]) self.wb.regs.rowhammer_address2.write(addresses[1]) self.wb.regs.rowhammer_enabled.write(1) row_strw = len(str(2**self.rowbits - 1)) def progress(count): s = ' {}'.format(progress_header + ' ' if progress_header else '') s += 'Rows = ({:{n}d},{:{n}d}), Count = {:5.2f}M / {:5.2f}M'.format( row1, row2, count/1e6, read_count/1e6, n=row_strw) print(s, end=' \r') while True: count = self.wb.regs.rowhammer_count.read() progress(count) if count >= read_count: break self.wb.regs.rowhammer_enabled.write(0) progress(self.wb.regs.rowhammer_count.read()) # also clears the value print() def row_access_iterator(self, burst=16): for row, addresses in self.addresses_per_row.items(): n = (max(addresses) - min(addresses)) // 4 base_addr = addresses[0] yield row, n, base_addr def check_errors(self, row_patterns, row_progress=16): row_errors = {} for row, n, base in self.row_access_iterator(): row_errors[row] = memcheck(self.wb, n, pattern=row_patterns[row], base=base, burst=255) if row % row_progress == 0: print('.', end='', flush=True) return row_errors def errors_count(self, row_errors): return sum(1 if len(e) > 0 else 0 for e in row_errors.values()) def display_errors(self, row_errors): for row in row_errors: if len(row_errors[row]) > 0: print("row_errors for row={:{n}}: {}".format( row, len(row_errors[row]), n=len(str(2**self.rowbits-1)))) if self.verbose: for i, word in row_errors[row]: base_addr = min(self.addresses_per_row[row]) addr = base_addr + 4*i bank, _row, col = self.converter.decode_bus(addr) print("Error: 0x{:08x}: 0x{:08x} (row={}, col={})".format( addr, word, _row, col)) if self.plot: from matplotlib import pyplot as plt row_err_counts = [len(row_errors.get(row, [])) for row in self.rows] plt.bar(self.rows, row_err_counts, width=1) plt.grid(True) plt.xlabel('Row') plt.ylabel('Errors') plt.show() def run(self, row_pairs, pattern_generator, read_count, row_progress=16, verify_initial=False): print('\nPreparing ...') row_patterns = pattern_generator(self.rows) print('\nFilling memory with data ...') for row, n, base in self.row_access_iterator(): memfill(self.wb, n, pattern=row_patterns[row], base=base, burst=255) if row % row_progress == 0: print('.', end='', flush=True) if verify_initial: print('\nVerifying written memory ...') errors = self.check_errors(row_patterns, row_progress=row_progress) if self.errors_count(errors) == 0: print('OK') else: print() self.display_errors(errors) return if self.no_refresh: print('\nDisabling refresh ...') self.wb.regs.controller_settings_refresh.write(0) print('\nRunning row hammer attacks ...') for i, (row1, row2) in enumerate(row_pairs): 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=row1) else: self.attack(row1, row2, read_count=read_count, progress_header=s) if self.no_refresh: print('\nReenabling refresh ...') self.wb.regs.controller_settings_refresh.write(1) print('\nVerifying attacked memory ...') errors = self.check_errors(row_patterns, row_progress=row_progress) if self.errors_count(errors) == 0: print('OK') else: print() self.display_errors(errors) return def payload_executor_attack(self, read_count, row): # FIXME: read from dedicated status registers tras = 5 trp = 3 encoder = Encoder(bankbits=self.bankbits) payload = [ encoder(OpCode.NOOP, timeslice=30), ] # fill payload so that we have >= desired read_count count_max = 2**Decoder.LOOP_COUNT - 1 n_loops = ceil(read_count / (count_max + 1)) for _ in range(n_loops): payload.extend([ encoder(OpCode.ACT, timeslice=tras, address=encoder.address(bank=self.bank, row=row)), encoder(OpCode.PRE, timeslice=trp, address=encoder.address(col=1 << 10)), # all encoder(OpCode.LOOP, count=count_max, jump=2), ]) payload.append(encoder(OpCode.NOOP, timeslice=30)) toggle_count = (count_max + 1) * n_loops print(' Payload size = {:5.2f}KB / {:5.2f}KB'.format(4*len(payload)/2**10, self.wb.mems.payload.size/2**10)) print(' Payload row toggle count = {:5.2f}M'.format(toggle_count/1e6)) assert len(payload) < self.wb.mems.payload.size//4 payload += [0] * (self.wb.mems.payload.size//4 - len(payload)) # fill with NOOPs print('\nTransferring the payload ...') memwrite(self.wb, payload, base=self.wb.mems.payload.base) def ready(): status = self.wb.regs.payload_executor_status.read() return (status & 1) != 0 print('\nExecuting ...') assert ready() self.wb.regs.payload_executor_start.write(1) while not ready(): time.sleep(0.001)