Ejemplo n.º 1
0
def test_read_mem__uboot(state: dict, script: str):
    """
    Read 512KiB of post-relocated U-Boot code/data to a u-boot.bin file in the
    resource directory in preparation for test_find_cmd() can be exercised.


    Populates state['config]', state['uboot_bin_file']
    """
    _READ_SIZE = 512 * 1024

    state['uboot_bin_file'] = os.path.join(state['test_dir'], 'uboot_512K.bin')
    uboot_addr = state['config']['gd']['bd']['relocaddr']['value']

    log.note('Reading 512K of U-Boot code/data to a binary file')

    args = [
        script,
        '-a',
        hex(uboot_addr),
        '-l',
        str(_READ_SIZE),
        '-f',
        state['uboot_bin_file'],
        '-A',
        '-R',
    ]
    run_script(args)
Ejemplo n.º 2
0
def test_stratagem(state: dict, script: str):
    """
    Produce a stratagem file to be used with depthcharge-write-mem.
    Uses state['write_data_file'] as input.

    """
    loadaddr = int(state['config']['env_vars']['loadaddr'], 0)

    stratagem = os.path.join(state['test_dir'], 'stratagem.json')
    state['stratagem'] = stratagem

    stratagem_payload = b'Hello World!'
    state['stratagem_payload'] = stratagem_payload

    state['payload_file'] = os.path.join(state['test_dir'], 'payload.bin')
    save_file(state['payload_file'], stratagem_payload, 'wb')

    log.note('  Producing CRC32MemoryWriter stratagem')
    args = [
        script,
        '-a', hex(loadaddr),
        '-f', state['write_data_file'],
        '-P', state['payload_file'],
        '-X', 'revlut_maxlen=512,max_iterations=10000',
        '-o', stratagem,
        '-s', 'crc32',
    ]
    run(args, check=True)
Ejemplo n.º 3
0
def test_help(_state: dict, script: str):
    """
    Confirm that the script doesn't explode before argument parsing takes place.
    """
    log.note('  Verifying help results in 0 return status')
    run([script, '-h'], stdout=DEVNULL, check=True)
    run([script, '--help'], stdout=DEVNULL, check=True)
Ejemplo n.º 4
0
def test_read_mem__readback(state: dict, script: str):
    """
    Read back data written by test_write_mem__deploy_stratagem()
    and verify it.

    Writes data to a file whose name is stored in state['readback_file']
    """

    zeros_preceeding = state['write_append_addr'] - state['zeroized_addr']
    zeros_following  = state['zeroized_len'] - zeros_preceeding - len(state['stratagem_payload'])

    expected  = state['write_data']
    expected += b'\x00' * zeros_preceeding
    expected += state['stratagem_payload']
    expected += b'\x00' * zeros_following

    read_len = len(expected)

    state['readback_file'] = os.path.join(state['test_dir'], 'readback.bin')

    loadaddr = int(state['config']['env_vars']['loadaddr'], 0)

    log.note('  Reading back data at $loadaddr.')
    args = [
        script,
        '-c', state['config_file'],
        '-a', hex(loadaddr),
        '-l', str(read_len),
        '-f', state['readback_file'],
        '-D',
    ]
    run(args, check=True)

    readback_data = load_file(state['readback_file'], 'rb')
    assert readback_data == expected
Ejemplo n.º 5
0
def test_inspect(state: dict, script: str):
    """
    Exercises depthcharge-inspect.

    Produces state['config_file'] that is used by later scripts.
    Loads state['config_file]'.
    """
    # TODO: Still need to exercise -C, -p, -b

    # Inspect device and produce config file
    args = [
        script, '-c', state['config_file'],
        '-X', '_unused_value=foo,_unused_bar',
        '-m', 'file:/dev/null',
    ]
    run(args, check=True)

    # Run again to force loading of config
    run(args, check=True)

    # This should trigger a timeout if -P is working;
    log.note('  Inducing a timeout to test -P ... please wait')
    env = os.environ.copy()
    env['DEPTHCHARGE_LOG_LEVEL'] = 'error'

    result = run(args + ['-P', 'BAD PROMPT >'], text=True, capture_output=True, env=env, check=False)
    if result.returncode != 1:
        raise ValueError('Expected returcode = 1, got ' + str(result.returncode))

    if 'Timed out' not in result.stderr:
        raise ValueError('Did not get expected timeout: ' + result.stderr)

    state['config'] = load_config(state['config_file'])
Ejemplo n.º 6
0
def find_devices(ctx, buses):
    results = []
    for bus in buses:
        log.note('Probing bus {:d}'.format(bus))
        try:

            cmd = 'i2c dev {:d}'.format(bus)
            # Raise an exception on error via check=True
            resp = ctx.send_command(cmd, check=True)

            # This may fail for buses (or pinmux settings) that are configured
            # appropriately. Thus, we drop check=True and just look results
            resp = ctx.send_command('i2c probe')

            match = re.match(r'Valid chip addresses: ([0-9a-fA-F\t ]+)', resp)
            if not match:
                # A failing bus will spew failures for a while. Keep trying
                # to interrupt it (Ctrl-C) until we know we're back at a prompt.
                log.warning('No devices or bus failing. Waiting for prompt.')
                ctx.interrupt(timeout=120)
                continue

            for addr in match.group(1).split():
                addr = int(addr, 16)
                log.info('Found device: Bus={:d}, Address=0x{:02x}'.format(
                    bus, addr))
                results.append((bus, addr))

        except OperationFailed as error:
            log.error('Command failed: ' + cmd + os.linesep + str(error))

    return results
Ejemplo n.º 7
0
def test_help(_state: dict, script: str):
    """
    Confirm that the script doesn't explode before argument parsing takes place.
    """
    log.note('  Verifying help results in 0 return status')

    # No --arch shouldn't matter. Confirm.
    run_script([script, '-h'], stdout=DEVNULL, arch=None)
    run_script([script, '--help'], stdout=DEVNULL, arch=None)

    run_script([script, '-h'], stdout=DEVNULL)
    run_script([script, '--help'], stdout=DEVNULL)
Ejemplo n.º 8
0
def get_buses(ctx):
    buses = []

    resp = ctx.send_command('i2c bus')
    for line in resp.splitlines():
        match = re.match(r'Bus (\d+)', line)
        if match:
            busno = int(match.group(1))
            log.note('Available: Bus {:d}'.format(busno))
            buses.append(busno)

    return buses
Ejemplo n.º 9
0
def read_nand_to_file(ctx, filename: str, name: str, load_addr: int,
                      nand_addr: int, size: int):

    # Copy NAND contents to ${loadaddr}
    cmd = 'nand read 0x{loadaddr:x} 0x{nand_addr:x} 0x{size:x}'
    cmd = cmd.format(loadaddr=load_addr, nand_addr=nand_addr, size=size)

    log.info('Copying ' + name + ' to RAM buffer')
    resp = ctx.send_command(cmd, check=True)
    log.note('Device response: ' + resp.strip())

    log.info('Reading RAM buffer to file: ' + filename)
    ctx.read_memory_to_file(load_addr, size, filename)
Ejemplo n.º 10
0
def test_find_cmd(state: dict, script):
    """
    Confirm that a command table is found in state['uboot_bin_file'] for
    a few different settings.
    """

    image_file = state['uboot_bin_file']
    uboot_addr = state['config']['gd']['bd']['relocaddr']['value']

    log.note('  Testing default-usage of depthcharge-find-cmd')
    args = [
        script,
        '-a', hex(uboot_addr),
        '-f', image_file,
    ]
    results = run(args, capture_output=True, text=True, check=True)
    assert 'Command table @ 0x' in results.stdout
    assert 'cmd_rep' not in results.stdout

    log.note('  Testing depthcharge-find-cmd with additional arguments')
    args = [
        script,
        '-a', hex(uboot_addr),
        '-A', state['config']['arch'],
        '-f', image_file,
        '--details',
        '--subcmds',
        '--threshold', '6'
    ]
    results = run(args, capture_output=True, text=True, check=True)
    assert 'Command table @ 0x' in results.stdout
    assert 'cmd_rep' in results.stdout

    log.note('  Testing depthcharge-find-cmd with --longhelp and --autocomplete')
    args = [
        script,
        '-a', hex(uboot_addr),
        '-A', state['config']['arch'],
        '-f', image_file,
        '--longhelp', 'Y',
        '--autocomplete', 'Y'
    ]
    results = run(args, capture_output=True, text=True, check=True)
    assert 'Command table @ 0x' in results.stdout
    assert 'cmd_rep' not in results.stdout

    log.note('  Testing depthcharge-find-cmd with incorrect --longhelp and --autocomplete')
    args = [
        script,
        '-a', hex(uboot_addr),
        '-A', state['config']['arch'],
        '-f', image_file,
        '--longhelp', 'N',
        '--autocomplete', 'N'
    ]
    results = run(args, capture_output=True, text=True, check=True)
    assert len(results.stdout) == 0
Ejemplo n.º 11
0
def test_print(state: dict, script: str):
    """
    Exercise depthcharge-print.

    Requires state['config_file'].
    """

    items = ('all', 'arch', 'commands', 'commands=detail', 'env', 'env=expand',
             'gd', 'version')

    output_dir = create_resource_dir(os.path.join(state['test_dir'], 'print'))
    for item in items:
        args = [script, '-c', state['config_file'], '-i', item]
        filename = os.path.join(output_dir, item.replace(':', '_'))
        log.note('  Printing ' + item + ' > ' + filename)
        with open(filename, 'w') as outfile:
            run_script(args, stdout=outfile)
Ejemplo n.º 12
0
def test_write_mem__deploy_stratagem(state: dict, script: str):
    """
    Append to our write payload using a Stratagem produced by CRC32MemoryWriter.

    Uses state['stratagem'] and state['stratagem_payload'] produced by test_stratagem.
    """

    loadaddr = int(state['config']['env_vars']['loadaddr'], 0)
    target_addr = loadaddr + len(state['write_data'])

    # We'll begin zeroizing memory here to <this address> + 32 bytes
    # The deployed payload will land within this region
    zero_addr = target_addr
    state['zeroized_addr'] = zero_addr

    # Align on an 8-byte boundary to ensure this works across architectures...
    target_addr = (target_addr + 7) // 8 * 8

    state['write_append_addr'] = target_addr

    # This just aims to ensure we're working from a clean memory state, such
    # that a previously run successful test test doesn't result in a false
    # negative for a failure in the current test to actually write any data.
    log.note('  Zeroizing target memory')
    state['zeroized_len'] = 32
    args = [
        script,
        '-c', state['config_file'],
        '-a', hex(zero_addr),
        '-d', '00' * state['zeroized_len'],
    ]
    run(args, check=True)

    log.note('  Executing CRC32MemoryWriter stratagem')
    args = [
        script,
        '-c', state['config_file'],
        '-a', hex(target_addr),
        '-s', state['stratagem'],
    ]
    run(args, check=True)
Ejemplo n.º 13
0
def test_read_mem__readback(state: dict, script: str):
    """
    Read back data written by test_write_mem__deploy_stratagem()
    and verify it.

    Writes data to a file whose name is stored in state['readback_file']
    """
    zeros_preceeding = state['write_append_addr'] - state['zeroized_addr']
    zeros_following = state['zeroized_len'] - zeros_preceeding - len(
        state['stratagem_payload'])

    expected = b'\x00' * zeros_preceeding + state[
        'stratagem_payload'] + b'\x00' * zeros_following
    read_len = len(expected)

    expected_file = os.path.join(state['test_dir'], 'readback.expected.bin')
    with open(expected_file, 'wb') as outfile:
        outfile.write(expected)

    state['readback_file'] = os.path.join(state['test_dir'], 'readback.bin')

    addr = state['zeroized_addr']

    log.note('  Reading back data at $loadaddr.')
    args = [
        script,
        '-c',
        state['config_file'],
        '-a',
        hex(addr),
        '-l',
        str(read_len),
        '-f',
        state['readback_file'],
        '-S',
        '-R',
    ]
    run_script(args)

    readback_data = load_file(state['readback_file'], 'rb')
    assert readback_data == expected
Ejemplo n.º 14
0
def validate_requirements(ctx):
    REQUIRED_CMDS = ('nand', )

    log.note('Checking for required target commands.')
    cmds = ctx.commands()
    for cmd in REQUIRED_CMDS:
        if cmd not in cmds:
            msg = 'Command not present in target environment: ' + cmd
            raise ValueError(msg)

    REQUIRED_VARS = ('loadaddr', 'dtbimage', 'dtb_offset', 'dtb_size', 'image',
                     'kernel_offset', 'kernel_size')

    log.note('Checking for required target environment variables.')
    env = ctx.environment()
    for var in REQUIRED_VARS:
        if var not in env:
            msg = 'Variable not present in target environment: ' + var
            raise ValueError(msg)

    return env
Ejemplo n.º 15
0
def load_resource(filename: str,
                  load_file_func,
                  test_dir='',
                  test_subdir='',
                  msg_pfx=''):
    """
    Load a resource file a test-specific specific directory and subdirectory.

    `load_file_func` should take a single filename argument. This function
    returns that of `load_file_func()`.
    """
    resource_dir = create_resource_dir(test_dir, test_subdir)

    file_path = path.join(resource_dir, filename)
    ret = load_file_func(file_path)

    if msg_pfx is not None:
        if msg_pfx == '':
            msg_pfx = 'Loaded resource from prior test: {:s}'
        log.note(msg_pfx.format(file_path))

    return ret
Ejemplo n.º 16
0
def run_tests(ctx, reader, writer, address):
    report = []
    log.info('  Currently testing: {} / {}'.format(reader.name, writer.name))

    for (data, pattern_name) in test_cases():
        try:
            if isinstance(writer, StratagemMemoryWriter):
                stratagem = setup_stratagem(ctx, data, pattern_name, writer)
                msg = '    Using {:d}-entry stratagem for {:d}-byte payload with {:s}'
                msg = msg.format(len(stratagem), len(data), pattern_name.replace('_', ' '))
            else:
                msg = '    Using {:d}-byte payload with {:s}'
                msg = msg.format(len(data), pattern_name.replace('_', ' '))
                stratagem = None

            log.note(msg)
            result = run_test(ctx, reader, writer, address, data, stratagem)
        except (StratagemCreationFailed, OperationAlignmentError):
            result = 'Skipped (Alignment)'
        entry = {'size': len(data), 'pattern': pattern_name, 'status': result}
        report.append(entry)

    return report
Ejemplo n.º 17
0
def locate_scripts() -> dict:
    """
    Return full paths to each depthcharge script.

    Dict keys are the script names, with the 'depthcharge-' prefix removed.
    Values are the full paths to the script.

    """
    script_dir = realpath(os.path.join(_THIS_DIR, '../../scripts'))
    log.note('Searching for scripts in: ' + script_dir)

    ret = {}
    for root, _, files in os.walk(script_dir):
        for filename in files:
            script = os.path.join(root, filename)
            key = basename(script).replace('depthcharge-', '')
            ret[key] = script

    for key in _EXPECTED:
        if key not in ret:
            raise FileNotFoundError('Failed to locate depthcharge-' + key)

    return ret
Ejemplo n.º 18
0
            log.info(msg)

            # Give the user a moment to digest this
            countdown = ctx.create_progress_indicator('countdown', 5, desc='Delaying')
            for _ in range(0, 5):
                time.sleep(1)
                countdown.update(1)
            ctx.close_progress_indicator(countdown)

            # Close the serial console we were using
            ctx.console.close()

            # Now re-inspect the device in its unlocked state by creating a new context
            # This will require crashing the device to obtain register r9 from ,
            # So we need to re-perform the unlock bypass after this reset.
            args.config = None  # Zap this so we perform inspection

            ctx = create_depthcharge_ctx(args,
                                         post_reboot_cb=post_reboot_cb,
                                         post_reboot_cb_data='self',
                                         console_kwargs=console_kwargs)

            ctx.save(_INSPECT_CFG)

        if args.boot:
            log.info('Sending sonosboot command. Device will enter fallback root shell.')
            log.note('Refer to /etc/Configure and /etc/inittab to finish initializing the platform.')
            ctx.send_command('sonosboot', read_response=False)
    else:
        sys.exit(1)
Ejemplo n.º 19
0
if __name__ == '__main__':

    if len(sys.argv) < 2 or '-h' in sys.argv or '--help' in sys.argv:
        print('MT7628 (MediaTek/Ralink) boot menu example')
        print('Usage: <serial port> [baud rate]')
        print('Baud rate defaults to 57600.')
        print()
        sys.exit(1 if len(sys.argv) < 1 else 0)

    uart_device = sys.argv[1]
    try:
        baud_rate = sys.argv[2]
        print(baud_rate)
    except IndexError:
        baud_rate = '57600'

    console = Console(uart_device, baudrate=baud_rate)
    log.note('Opened ' + uart_device + ': ' + baud_rate)

    try:
        read_loop(console)
    except KeyboardInterrupt:
        print('\r', end='')  # Overwrite "^C" on terminal
        log.warning('Interrupted! Exiting.')
        sys.exit(1)

    msg = ('You may now run the following command to inspect the platform.\n'
           '  depthcharge-inspect -i {:s}:{:s} -c rp-wd008.cfg [-m term]')

    log.info(msg.format(uart_device, baud_rate))
Ejemplo n.º 20
0

if __name__ == '__main__':
    args = handle_cmdline()

    try:
        scripts = locate_scripts()
    except FileNotFoundError as error:
        log.error(str(error))
        sys.exit(1)

    tests = load_tests(args)
    state = load_state(args)

    t_start = time.time()

    for test in tests:
        script = test_name_to_script(test.__name__)
        log.note('Running ' + test.__name__)
        test_help(state, script)
        test(state, script)
        save_state(state)

    t_end = time.time()
    t_elapsed = timedelta(seconds=(t_end - t_start))

    msg = ('=' * 76 + os.linesep + '  Tests complete successfully.' +
           os.linesep + '  Elapsed: ' + str(t_elapsed) + os.linesep)

    log.info(msg)