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 write_scratch2_register(netdimm: NetDimm, value: int) -> None: with netdimm.connection(): netdimm.poke(SCRATCH2_REGISTER, PeekPokeTypeEnum.TYPE_LONG, value)
def write_send_status_register(netdimm: NetDimm, value: int) -> None: with netdimm.connection(): netdimm.poke(SEND_STATUS_REGISTER, PeekPokeTypeEnum.TYPE_LONG, checksum_stamp(value, SEND_STATUS_REGISTER_SEED))
def send_packet(netdimm: NetDimm, data: bytes) -> bool: length = len(data) if length > MAX_PACKET_LENGTH: raise Exception("Packet is too long to send!") with netdimm.connection(): start = time.time() sent_length = False while True: if time.time() - start > MAX_READ_TIMEOUT: # Failed to request a new packet send in time. return False # First, attempt to see if there is any existing transfer in progress. status = read_recv_status_register(netdimm) if status is None: return False # Now, grab the length of the available packet. newlength = (status >> 12) & 0xFFF if newlength == 0: # Ready to start transferring! write_recv_status_register(netdimm, (length << 12) & 0xFFF000) sent_length = True elif sent_length is False or newlength != length: # Cancel old transfer. write_recv_status_register(netdimm, 0) sent_length = False elif newlength == length: # Ready to send data. break else: # Shouldn't be possible. raise Exception("Logic error!") # Now set the current transfer location. This can be rewound by the target # if it failed to receive all of the data. location = 0 while True: while location < length: # Sum up the next amount of data, up to 3 bytes. chunk: int = ((((location // 3) + 1) << 24) & 0xFF000000) for shift in [16, 8, 0]: if location < length: chunk |= (data[location] & 0xFF) << shift location += 1 else: break # Send it. netdimm.poke(DATA_REGISTER, PeekPokeTypeEnum.TYPE_LONG, chunk) # Now, see if the data transfer was successful. status = read_recv_status_register(netdimm) if status is None: # Give up, we can't read from the status. return False # See if the packet was sent successfully. If not, then our location will # be set to where the target needs data sent from. newlength = (status >> 12) & 0xFFF location = status & 0xFFF if newlength == 0 and location == 0: # We succeeded! Time to exit return True elif newlength != length: raise Exception("Logic error!")