def receive_packet(netdimm: NetDimm) -> Optional[bytes]: with netdimm.connection(): # First, attempt to grab the next packet available. status = read_send_status_register(netdimm) if status is None: return None # Now, grab the length of the available packet. length = (status >> 12) & 0xFFF if length == 0: return None # Now, see if the transfer was partially done, if so rewind it. loc = status & 0xFFF if loc > 0: write_send_status_register(netdimm, 0) # Now, grab and assemble the data itself. data: List[Optional[int]] = [None] * length tries: int = 0 while any(d is None for d in data): chunk = netdimm.peek(DATA_REGISTER, PeekPokeTypeEnum.TYPE_LONG) if ((chunk & 0xFF000000) >> 24) in {0x00, 0xFF}: tries += 1 if tries > MAX_EMPTY_READS: # We need to figure out where we left off. for loc, val in enumerate(data): if val is None: # We found a spot to resume from. write_send_status_register(netdimm, loc & 0xFFF) tries = 0 break else: # We should always find a spot to resume from or there's an issue, # since in this case we should be done. raise Exception("Logic error!") else: # Grab the location for this chunk, stick the data in the right spot. location = (((chunk >> 24) & 0xFF) - 1) * 3 for off, shift in enumerate([16, 8, 0]): actual = off + location if actual < length: data[actual] = (chunk >> shift) & 0xFF # Grab the actual return data. bytedata = bytes([d for d in data if d is not None]) if len(bytedata) != length: raise Exception("Logic error!") # Acknowledge the data transfer completed. write_send_status_register(netdimm, length & 0xFFF) # Return the actual data! return bytedata
def read_recv_status_register(netdimm: NetDimm) -> Optional[int]: with netdimm.connection(): valid = False status: int = 0 start = time.time() while not valid: status = 0 while status == 0 or status == 0xFFFFFFFF and ( time.time() - start <= MAX_READ_TIMEOUT): status = netdimm.peek(RECV_STATUS_REGISTER, PeekPokeTypeEnum.TYPE_LONG) valid = checksum_valid(status, RECV_STATUS_REGISTER_SEED) if not valid and (time.time() - start > MAX_READ_TIMEOUT): return None return status
def read_config_register(netdimm: NetDimm) -> Optional[int]: with netdimm.connection(): valid = False config: int = 0 start = time.time() while not valid: config = 0 while config == 0 or config == 0xFFFFFFFF and ( time.time() - start <= MAX_READ_TIMEOUT): config = netdimm.peek(CONFIG_REGISTER, PeekPokeTypeEnum.TYPE_LONG) valid = checksum_valid(config, CONFIG_REGISTER_SEED) if not valid and (time.time() - start > MAX_READ_TIMEOUT): return None return config
def main() -> int: parser = argparse.ArgumentParser( description= "Tools for peeking/poking values into running memory on a Naomi/Triforce/Chihiro.", ) subparsers = parser.add_subparsers(help='Action to take', dest='action') peek_parser = subparsers.add_parser( 'peek', help='Peek at a value in an 8/16/32-bit memory location', description='Peek at a value in an 8/16/32-bit memory location', ) peek_parser.add_argument( "ip", metavar="IP", type=str, help="The IP address that the NetDimm is configured on.", ) peek_parser.add_argument( "address", metavar="ADDR", type=str, help="The hex address of memory that you would like to peek into.", ) peek_parser.add_argument( "size", metavar="SIZE", type=int, help="The size in bytes you want to read. Valid values are 1, 2 and 4.", ) poke_parser = subparsers.add_parser( 'poke', help='Poke a value into an 8/16/32-bit memory location', description='Poke a value into an 8/16/32-bit memory location', ) poke_parser.add_argument( "ip", metavar="IP", type=str, help="The IP address that the NetDimm is configured on.", ) poke_parser.add_argument( "address", metavar="ADDR", type=str, help="The hex address of memory that you would like to poke into.", ) poke_parser.add_argument( "size", metavar="SIZE", type=int, help= "The size in bytes you want to write. Valid values are 1, 2 and 4.", ) poke_parser.add_argument( "data", metavar="VALUE", type=str, help="The hex value you wish to write into the address.", ) dump_parser = subparsers.add_parser( 'dump', help='Dump data from a memory location.', description='Dump data from a memory location.', ) dump_parser.add_argument( "ip", metavar="IP", type=str, help="The IP address that the NetDimm is configured on.", ) dump_parser.add_argument( "file", metavar="FILE", type=str, help="The file you want to dump data to.", ) dump_parser.add_argument( "address", metavar="ADDR", type=str, help="The hex address of memory that you would like to dump from.", ) dump_parser.add_argument( "size", metavar="SIZE", type=int, help="The size in bytes you want to read.", ) load_parser = subparsers.add_parser( 'load', help='Load data to a memory location.', description='Load data to a memory location.', ) load_parser.add_argument( "ip", metavar="IP", type=str, help="The IP address that the NetDimm is configured on.", ) load_parser.add_argument( "file", metavar="FILE", type=str, help="The file you want to load data to.", ) load_parser.add_argument( "address", metavar="ADDR", type=str, help="The hex address of memory that you would like to load to.", ) args = parser.parse_args() netdimm = NetDimm(args.ip) if args.action == "peek": if args.size == 1: data = netdimm.peek(int(args.address, 16), PeekPokeTypeEnum.TYPE_BYTE) & 0xFF elif args.size == 2: data = netdimm.peek(int(args.address, 16), PeekPokeTypeEnum.TYPE_SHORT) & 0xFFFF elif args.size == 4: data = netdimm.peek(int(args.address, 16), PeekPokeTypeEnum.TYPE_LONG) & 0xFFFFFFFF else: raise Exception(f"Invalid size selection {args.size}!") hexdata = hex(data)[2:] while len(hexdata) < (2 * args.size): hexdata = "0" + hexdata print(hexdata) elif args.action == "poke": if args.size == 1: netdimm.poke(int(args.address, 16), PeekPokeTypeEnum.TYPE_BYTE, int(args.data, 16) & 0xFF) elif args.size == 2: netdimm.poke(int(args.address, 16), PeekPokeTypeEnum.TYPE_SHORT, int(args.data, 16) & 0xFFFF) elif args.size == 4: netdimm.poke(int(args.address, 16), PeekPokeTypeEnum.TYPE_LONG, int(args.data, 16) & 0xFFFFFFFF) else: raise Exception(f"Invalid size selection {args.size}!") elif args.action == "dump": with open(args.file, "wb") as bfp: for i in range(args.size): data = netdimm.peek( int(args.address, 16) + i, PeekPokeTypeEnum.TYPE_BYTE) & 0xFF bfp.write(struct.pack("B", data)) print(f"Dumped {args.size} bytes to {args.file}") elif args.action == "load": with open(args.file, "rb") as bfp: for amount, b in enumerate(bfp.read()): netdimm.poke( int(args.address, 16) + amount, PeekPokeTypeEnum.TYPE_BYTE, b) print(f"Loaded {amount} bytes from {args.file}") return 0
def read_scratch2_register(netdimm: NetDimm) -> Optional[int]: with netdimm.connection(): return netdimm.peek(SCRATCH2_REGISTER, PeekPokeTypeEnum.TYPE_LONG)