Ejemplo n.º 1
0
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)
Ejemplo n.º 2
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()
Ejemplo n.º 3
0
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
Ejemplo n.º 4
0
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()
Ejemplo n.º 5
0
 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 = {}
Ejemplo n.º 6
0
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)