diff --git a/1_sanity_check.sh b/1_sanity_check.sh index 8a9165b..58e9067 100755 --- a/1_sanity_check.sh +++ b/1_sanity_check.sh @@ -1,6 +1,6 @@ #!/bin/bash -source config.sh placeHolder +source config.sh $@ echo "Running sanity checks..." if ! ${OPENOCD} -v >/dev/null 2>&1; then diff --git a/2_backup_flash.sh b/2_backup_flash.sh index b1756ed..609d631 100755 --- a/2_backup_flash.sh +++ b/2_backup_flash.sh @@ -1,14 +1,9 @@ #!/bin/bash -source config.sh $1 +source config.sh $@ -if [[ $# -ne 1 ]]; then - echo "Usage: backup_flash.sh " - exit 1 -fi - -if test -f backups/flash_backup.bin; then - echo "Already have a backup in backups/flash_backup.bin, refusing to overwrite." +if test -f backups/flash_backup_$TARGET.bin; then + echo "Already have a backup in backups/flash_backup_$TARGET.bin, refusing to overwrite." exit 1 fi @@ -16,32 +11,37 @@ echo "Make sure your Game & Watch is turned on and in the time screen. Press ret read -n 1 echo "Attempting to dump flash using adapter ${ADAPTER}." -echo "Running OpenOCD... (This will take roughly 30 seconds, your Game and Watch screen will blink in between.)" -if ! ${OPENOCD} -f openocd/flash_"${ADAPTER}".cfg >>logs/2_openocd.log 2>&1; then +echo "Running OpenOCD... (This can take up to a few minutes.)" +if ! ${OPENOCD} \ + -f "openocd/target_${TARGET}.cfg" \ + -f "openocd/interface_${ADAPTER}.cfg" \ + -f "openocd/flash.cfg" >> logs/2_openocd.log 2>&1; then echo "Failed to dump SPI flash from device. Verify debug connection and try again." exit 1 fi echo "Validating ITCM dump..." -if ! shasum --check shasums/itcm_backup.bin.sha1 >/dev/null 2>&1; then +if ! shasum --check shasums/itcm_backup_${TARGET}.bin.sha1 >/dev/null 2>&1; then echo "Failed to correctly dump ITCM. Restart Game & Watch and try again." exit 1 fi echo "Extracting checksummed part..." -if ! dd if=backups/flash_backup.bin of=backups/flash_backup_checksummed.bin count=1040384 bs=1 >/dev/null 2>&1; then - echo "Failed to access flash_backup.bin" +echo dd if=backups/flash_backup_${TARGET}.bin of=backups/flash_backup_checksummed_${TARGET}.bin bs=16 skip=${SPIFLASH_SKIP_16} count=${SPIFLASH_COUNT_16} + +if ! dd if=backups/flash_backup_${TARGET}.bin of=backups/flash_backup_checksummed_${TARGET}.bin bs=16 skip=${SPIFLASH_SKIP_16} count=${SPIFLASH_COUNT_16} >/dev/null 2>&1; then + echo "Failed to access flash_backup_${TARGET}.bin" echo "Verify openocd works correctly" exit 1 fi echo "Validating checksum..." -if ! shasum --check shasums/flash_backup_checksummed.bin.sha1 >/dev/null 2>&1; then - echo "Failed to verify checksum. Try again." +if ! shasum --check shasums/flash_backup_checksummed_${TARGET}.bin.sha1 >/dev/null 2>&1; then + echo "Failed to verify checksum of the external flash. Try again." exit 1 fi -rm backups/flash_backup_checksummed.bin +rm -f backups/flash_backup_checksummed_${TARGET}.bin -echo "Looks good! Successfully backed up the (encrypted) SPI flash to flash_backup.bin!" +echo "Looks good! Successfully backed up the (encrypted) SPI flash to backups/flash_backup_${TARGET}.bin!" diff --git a/3_backup_internal_flash.sh b/3_backup_internal_flash.sh index a1ed71c..eb572d0 100755 --- a/3_backup_internal_flash.sh +++ b/3_backup_internal_flash.sh @@ -2,27 +2,27 @@ set -e -source config.sh $1 +source config.sh $@ -if test -f backups/internal_flash_backup.bin; then - echo "Already have a backup in backups/internal_flash_backup.bin, refusing to overwrite." +if test -f backups/internal_flash_backup_${TARGET}.bin; then + echo "Already have a backup in backups/internal_flash_backup_${TARGET}.bin, refusing to overwrite." exit 1 fi -if ! dd if=backups/flash_backup.bin of=backups/flash_backup_checksummed.bin count=1016 bs=1024 >/dev/null 2>&1; then - echo "Failed to access flash_backup.bin" +if ! dd if=backups/flash_backup_${TARGET}.bin of=backups/flash_backup_checksummed_${TARGET}.bin bs=16 skip=${SPIFLASH_SKIP_16} count=${SPIFLASH_COUNT_16} >/dev/null 2>&1; then + echo "Failed to access flash_backup_${TARGET}.bin" echo "Please run ./2_backup_flash.sh again" exit 1 fi -if ! shasum --check shasums/flash_backup_checksummed.bin.sha1 >/dev/null 2>&1; then +if ! shasum --check shasums/flash_backup_checksummed_${TARGET}.bin.sha1 >/dev/null 2>&1; then echo "*** External flash backup does not verify correctly ***" echo "Please run ./2_backup_flash.sh again" rm backups/flash_backup_checksummed.bin exit 1 fi -rm backups/flash_backup_checksummed.bin +rm -f backups/flash_backup_checksummed_${TARGET}.bin echo "This step will overwrite the contents of the SPI flash chip that we backed up in step 2." echo "It will be restored in step 5. Continue? (y/N)" @@ -34,44 +34,53 @@ then fi echo "Generating encrypted flash image from backed up data..." -if ! python3 python/tcm_encrypt.py backups/flash_backup.bin backups/itcm_backup.bin payload/payload.bin new_flash_image.bin; then +if ! python3 python/tcm_encrypt.py \ + backups/flash_backup_${TARGET}.bin \ + ${FLASH_OFFSET} \ + backups/itcm_backup_${TARGET}.bin \ + payload/payload.bin \ + new_flash_image.bin; then echo "Failed to build encrypted flash image." exit 1 fi - -echo "Running flashloader..." - -if ! ./scripts/flashloader.sh $ADAPTER new_flash_image.bin; then - echo "Flashloader failed, check debug connection and try again." +echo "Programming payload to SPI flash..." +if ! ${OPENOCD} -f "openocd/target_${TARGET}.cfg" -f "openocd/interface_${ADAPTER}.cfg" \ + -c "init;" \ + -c "halt;" \ + -c "program new_flash_image.bin 0x90000000 verify;" \ + -c "exit;" >>logs/3_openocd.log 2>&1; then + echo "Writing payload to SPI flash failed. Check debug connection and try again." exit 1 fi -echo "Flash successfully flashed. Now do the following procedure:" +echo "Flash successfully programmed. Now do the following procedure:" echo "- Disconnect power from the device" echo "- Power it again" -echo "- Press and hold the power button" -echo "- Press return (while still holding the power button)!" +echo "- Press the power button on the device" +echo "- The LCD should show a blue screen" +echo "- If it's not blue, you can try pressing the Time button on the device" +echo "- Press return" read -n 1 echo "Dumping internal flash..." -if ! ${OPENOCD} -f openocd/interface_"${ADAPTER}".cfg \ +if ! ${OPENOCD} -f "openocd/interface_${ADAPTER}.cfg" \ -c "init;" \ -c "halt;" \ - -c "dump_image backups/internal_flash_backup.bin 0x24000000 131072" \ + -c "dump_image backups/internal_flash_backup_${TARGET}.bin 0x24000000 131072" \ -c "exit;" >>logs/3_openocd.log 2>&1; then echo "Dumping internal flash failed." exit 1 fi echo "Verifying internal flash backup..." -if ! shasum --check shasums/internal_flash_backup.bin.sha1 >/dev/null 2>&1; then +if ! shasum --check shasums/internal_flash_backup_${TARGET}.bin.sha1 >/dev/null 2>&1; then echo "The backup of the internal flash failed. Please try again." exit 1 fi -rm new_flash_image.bin +rm -f new_flash_image.bin echo "Device backed up successfully" diff --git a/4_unlock_device.sh b/4_unlock_device.sh index 1498d89..0997700 100755 --- a/4_unlock_device.sh +++ b/4_unlock_device.sh @@ -1,6 +1,6 @@ #!/bin/bash -source config.sh $1 +source config.sh $@ echo "Unlocking your device will erase its internal flash. Even though your backup" echo "is validated, this still can go wrong. Are you sure? (y/N)" @@ -12,13 +12,13 @@ then fi echo "Validating internal flash backup before proceeding..." -if ! shasum --check shasums/internal_flash_backup.bin.sha1 >/dev/null 2>&1; then +if ! shasum --check shasums/internal_flash_backup_${TARGET}.bin.sha1 >/dev/null 2>&1; then echo "Backup is not valid. Aborting." exit 1 fi echo "Unlocking device... (Takes up to 30 seconds.)" -if ! ${OPENOCD} -f openocd/interface_"${ADAPTER}".cfg \ +if ! ${OPENOCD} -f "openocd/interface_${ADAPTER}.cfg" \ -c "init;" \ -c "halt;" \ -f openocd/rdp0.cfg >>logs/4_openocd.log 2>&1; then diff --git a/5_restore.sh b/5_restore.sh index d2ce917..4f3beb6 100755 --- a/5_restore.sh +++ b/5_restore.sh @@ -1,36 +1,48 @@ #!/bin/bash -source config.sh $1 +source config.sh $@ -if ! test -f backups/internal_flash_backup.bin; then - echo "No backup of internal flash found in backups/internal_flash_backup.bin" +if [[ $TARGET == "mario" ]] && \ + test -f backups/flash_backup.bin && test -f backups/internal_flash_backup.bin && \ + ! test -f backups/flash_backup_$TARGET.bin && ! test -f backups/internal_flash_backup_$TARGET.bin \ + ; then + echo "Discovered mario backups with old names. Renaming files to the new format." + mv backups/flash_backup.bin backups/flash_backup_$TARGET.bin + mv backups/internal_flash_backup.bin backups/internal_flash_backup_$TARGET.bin +fi + +if ! test -f backups/internal_flash_backup_$TARGET.bin; then + echo "No backup of internal flash found in backups/internal_flash_backup_$TARGET.bin" exit 1 fi -if ! test -f backups/flash_backup.bin; then - echo "No backup of SPI flash found in backups/flash_backup.bin" +if ! test -f backups/flash_backup_$TARGET.bin; then + echo "No backup of SPI flash found in backups/flash_backup_$TARGET.bin" exit 1 fi echo "Ok, restoring original firmware! (We will not lock the device, so you won't have to repeat this procedure!)" - -echo "Restoring internal flash..." -if ! ${OPENOCD} -f openocd/interface_"${ADAPTER}".cfg \ +echo "Restoring SPI flash..." +if ! ${OPENOCD} -f "openocd/target_${TARGET}.cfg" -f "openocd/interface_${ADAPTER}.cfg" \ -c "init;" \ -c "halt;" \ - -c "program backups/internal_flash_backup.bin 0x08000000 verify;" \ + -c "program backups/flash_backup_${TARGET}.bin 0x90000000 verify;" \ + -c "exit;" >>logs/5_openocd.log 2>&1; then + echo "Restoring SPI flash failed. Check debug connection and try again." + exit 1 +fi + + +echo "Restoring internal flash..." +if ! ${OPENOCD} -f "openocd/target_${TARGET}.cfg" -f "openocd/interface_${ADAPTER}.cfg" \ + -c "init;" \ + -c "halt;" \ + -c "program backups/internal_flash_backup_${TARGET}.bin 0x08000000 verify;" \ -c "exit;" >>logs/5_openocd.log 2>&1; then echo "Restoring internal flash failed. Check debug connection and try again." exit 1 fi - -echo "Restoring SPI flash..." -if ! ./scripts/flashloader.sh $ADAPTER backups/flash_backup.bin; then - echo "Restoring SPI flash failed. Check debug connection and try again." - exit 1 -fi - echo "Success, your device should be running the original firmware again!" echo "(You should power-cycle the device now)" diff --git a/README.md b/README.md index 362d194..b6e9c7c 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,6 @@ # Game and Watch Backup and Restore tools -This repository contains pre-built tools for backing up & restoring the original Game and Watch firmware. +This repository contains pre-built tools for backing up & restoring the original Game and Watch firmware. Both the Mario and Zelda variants are supported. What you'll need: - A Game & Watch in original state @@ -27,6 +27,8 @@ Please note that we recommend either a (full-size, not mini) J-Link/J-Link Edu, When connecting the debugger ensure that at least SWDIO, SWDCLK and GND are connected. Do *not* under any circumstances connect 3.3V to the VDD connection. If your debug probe (for example ST-Link clones) does not have a VTREF connector, just leave VDD unconnected. Connecting 3.3V to VDD will likely destroy your SPI flash. +The debug connector of the Zelda variant shares pinout with the Mario variant, but has two extra connections (PB3 and N/C). The small triangle points to pin 1. + ### Supported Debuggers Please either use an official ST-Link (not one of the small USB stick clones) or a full-size J-Link. Others might work, a lot of them do not work with the 1.9V logic levels used on the Game and Watch. @@ -108,7 +110,7 @@ Your device was not modified by the scripts, so it should just continue to work Step 3 will change the internal flash of the device. If this step fails it will leave your device in a bricked state. To recover from it run: ``` -./scripts/flashloader.sh ./backups/flash_backup.bin +./restore_only_external_flash.sh ``` If the script can't connect to the device, press & hold down power on the device while running flashloader & try to FULLY powercycle the target between attempts. @@ -131,10 +133,3 @@ Other channels: - *#replacement-pcb* In here we discuss the possibilities and development of replacement PCBs for the Game and Watch. - [game-and-watch-hacking wiki](https://github.com/ghidraninja/game-and-watch-hacking/wiki) A reference wiki all things hacking the Game & Watch. Including internals. - -## Sources for binaries - -The binaries in firmware/ are based on: - -- [flashloader](https://github.com/ghidraninja/game-and-watch-flashloader) -- [flashdumper](https://github.com/ghidraninja/game-and-watch-flashdumper) diff --git a/config.sh b/config.sh index 18f3abb..4dab262 100755 --- a/config.sh +++ b/config.sh @@ -7,12 +7,39 @@ if [[ -z ${OPENOCD} ]]; then exit 2 fi +helptext() { + echo "Usage: $0 " +} + OPENOCD_VERSION=$(${OPENOCD} -v 2> >(cut -f 4 -d" " ) |head -1) ADAPTER=$1 +TARGET=$2 -mkdir -p logs backups +if [[ $TARGET == "mario" ]]; then + SPIFLASH_SKIP_16=0 + SPIFLASH_COUNT_16=$(( 0xfe000 / 16 )) + FLASH_OFFSET=0 +elif [[ $TARGET == "zelda" ]]; then + # 0x0000_0000 - 0x0000_008f volatile area + # 0x0000_1000 - 0x0000_108f volatile area + # 0x0000_2000 - 0x0000_2b1f volatile area + # 0x0000_4000 - 0x0000_4b1f volatile area + # 0x0000_6000 - 0x0000_6b1f volatile area + # 0x0000_8000 - 0x0000_8b1f volatile area + # 0x0002_0000 - 0x0032_549f ROM area + # 0x003e_0000 - 0x0040_0000 volatile area -if [[ $# -ne 1 ]] && [[ ! "$0" =~ .*"config.sh" ]]; then - echo "Usage: $0 " - exit 1 + SPIFLASH_SKIP_16=$(( 0x20000 / 16 )) + SPIFLASH_COUNT_16=$(( (0x3254a0 - 0x20000) / 16 )) + FLASH_OFFSET=$(( 0x30c3a8 )) +else + helptext + exit 1 fi + +if [[ $# -ne 2 ]] && [[ ! "$0" =~ .*"config.sh" ]]; then + helptext + exit 1 +fi + +mkdir -p logs backups \ No newline at end of file diff --git a/firmware/flash_dumper.elf b/firmware/flash_dumper.elf deleted file mode 100755 index ca294b4..0000000 Binary files a/firmware/flash_dumper.elf and /dev/null differ diff --git a/firmware/flash_programmer.elf b/firmware/flash_programmer.elf deleted file mode 100755 index 91712ec..0000000 Binary files a/firmware/flash_programmer.elf and /dev/null differ diff --git a/install_pwnadventure.sh b/install_pwnadventure.sh index f21a5a3..1c4cea6 100755 --- a/install_pwnadventure.sh +++ b/install_pwnadventure.sh @@ -1,22 +1,17 @@ #!/bin/bash -source config.sh $1 +source config.sh $@ echo "Installing on internal flash..." if ! ${OPENOCD} -f openocd/interface_"${ADAPTER}".cfg \ -c "init;" \ -c "halt;" \ -c "program prebuilt/gw_retrogo_nes.elf;" \ + -c "program prebuilt/gw_retrogo_nes_extflash.bin 0x90000000" -c "exit;" >>logs/5_openocd.log 2>&1; then echo "Installing on flash failed." exit 1 fi -echo "Installing data on SPI flash..." -if ! ./scripts/flashloader.sh $ADAPTER prebuilt/gw_retrogo_nes_extflash.bin; then - echo "Installing on SPI flash failed. Check debug connection and try again." - exit 1 -fi - echo "Success!" diff --git a/openocd/flash.cfg b/openocd/flash.cfg index e8dc4a5..b7516e3 100644 --- a/openocd/flash.cfg +++ b/openocd/flash.cfg @@ -1,20 +1,23 @@ init -echo "Dump ITCM area" -dump_image backups/itcm_backup.bin 0x0 1300 -echo "Reset and halt" -reset halt -echo "Load image" -load_image firmware/flash_dumper.elf -reset halt -sleep 1000 -echo "Set stack pointer" -reg sp [mrw 0x20000000] -reg pc [mrw 0x20000004] -echo "Continuing, wait ca. 10 seconds" -resume -sleep 10000 + halt -echo "Dumping" -dump_image backups/flash_backup.bin 0x24000000 1048576 -echo "Done!" -exit \ No newline at end of file + +echo "" +echo "Dump ITCM area: backups/itcm_backup_${TARGET}.bin ${ITCM_OFFSET} ${ITCM_LENGTH}" +echo "" +dump_image backups/itcm_backup_${TARGET}.bin ${ITCM_OFFSET} ${ITCM_LENGTH} + +echo "" +echo "Reset and halt" +echo "" +reset halt + +echo "" +echo "Starting to dump the external flash..." +echo "" +dump_image backups/flash_backup_${TARGET}.bin 0x90000000 ${SPIFLASH_SIZE} + +echo "" +echo "External flash dumped!" +echo "" +exit diff --git a/openocd/flash_jlink.cfg b/openocd/flash_jlink.cfg deleted file mode 100644 index 8c42360..0000000 --- a/openocd/flash_jlink.cfg +++ /dev/null @@ -1,4 +0,0 @@ -# Use this script to upload flash dumper using a JLink - -source [find openocd/interface_jlink.cfg] -source [find openocd/flash.cfg] diff --git a/openocd/flash_rpi.cfg b/openocd/flash_rpi.cfg deleted file mode 100644 index 402445d..0000000 --- a/openocd/flash_rpi.cfg +++ /dev/null @@ -1,2 +0,0 @@ -source [find openocd/interface_rpi.cfg] -source [find openocd/flash.cfg] diff --git a/openocd/flash_stlink.cfg b/openocd/flash_stlink.cfg deleted file mode 100644 index 491b527..0000000 --- a/openocd/flash_stlink.cfg +++ /dev/null @@ -1,4 +0,0 @@ -# Use this script to upload flash dumper using an STLink - -source [find openocd/interface_stlink.cfg] -source [find openocd/flash.cfg] diff --git a/openocd/interface_jlink.cfg b/openocd/interface_jlink.cfg index b1b595e..05bb365 100644 --- a/openocd/interface_jlink.cfg +++ b/openocd/interface_jlink.cfg @@ -1,4 +1,4 @@ source [find interface/jlink.cfg] adapter speed 500 transport select swd -source [find target/stm32h7x.cfg] +source [find openocd/stm32h7x_spiflash.cfg] diff --git a/openocd/interface_rpi.cfg b/openocd/interface_rpi.cfg index d827ad0..1f8dda4 100644 --- a/openocd/interface_rpi.cfg +++ b/openocd/interface_rpi.cfg @@ -1,5 +1,5 @@ source [find interface/sysfsgpio-raspberrypi.cfg] source [find openocd/rpi.cfg] transport select swd -source [find target/stm32h7x.cfg] +source [find openocd/stm32h7x_spiflash.cfg] reset_config none diff --git a/openocd/interface_stlink.cfg b/openocd/interface_stlink.cfg index abbfdd7..b25c673 100644 --- a/openocd/interface_stlink.cfg +++ b/openocd/interface_stlink.cfg @@ -1,6 +1,6 @@ source [find interface/stlink.cfg] adapter speed 500 transport select hla_swd -source [find target/stm32h7x.cfg] +source [find openocd/stm32h7x_spiflash.cfg] reset_config none diff --git a/openocd/stm32h7x_spiflash.cfg b/openocd/stm32h7x_spiflash.cfg new file mode 100644 index 0000000..a21d8b7 --- /dev/null +++ b/openocd/stm32h7x_spiflash.cfg @@ -0,0 +1,77 @@ +# Nintendo Game & Watch: Super Mario Bros. and Zelda + +set OCTOSPI1 1 +set OCTOSPI2 0 + +source [find target/stm32h7x.cfg] + +# HXA-001 QSPI initialization +# Based on https://forums.pimoroni.com/t/accessing-external-flash-from-openocd/12558 +# With contributions by https://github.com/jan2642 and https://github.com/GMMan +proc hxa-001_qspi_init { } { + echo "Initializing Octo-SPI interface" + + # PB01: OCTOSPIM_P1_IO0, PD12: OCTOSPIM_P1_IO1, PE02: OCTOSPIM_P1_IO2, + # PA01: OCTOSPIM_P1_IO3, PB02: OCTOSPIM_P1_CLK, PE11: OCTOSPIM_P1_NCS, + # PD01: 1.8V power + + # Enable GPIO clocks + mmw 0x58024540 0x0000001b 0x00000000 ;# RCC_AHB4ENR |= GPIOAEN | GPIOBEN | GPIODEN | GPIOEEN + # Enable Octo-SPI clocks + mmw 0x58024534 0x00204000 0x00000000 ;# RCC_AHB3ENR |= OCTOSPI1EN | OCTOSPIMEN (enable clocks) + sleep 1 ;# Wait for clock startup + + # Set GPIO ports (push-pull, no pull) + # Port A: PA01:AF09:V + mmw 0x58020000 0x00000000 0x00000004 ;# GPIOA_MODER + mmw 0x58020008 0x0000000c 0x00000000 ;# GPIOA_OSPEEDR + mmw 0x58020020 0x00000090 0x00000000 ;# GPIOA_AFRL + # Port B: PB01:AF11:V PB02:AF09:V + mmw 0x58020400 0x00000000 0x00000014 ;# GPIOB_MODER + mmw 0x58020408 0x0000003c 0x00000000 ;# GPIOB_OSPEEDR + mmw 0x58020420 0x000009b0 0x00000000 ;# GPIOB_AFRL + # Port D: PD01:OP:L PD12:AF09:V + mmw 0x58020c00 0x00000000 0x01000008 ;# GPIOD_MODER + mmw 0x58020c08 0x03000000 0x00000000 ;# GPIOD_OSPEEDR + mmw 0x58020c24 0x00090000 0x00000000 ;# GPIOD_AFRH + # Port E: PE02:AF09:V PE11:AF11:V + mmw 0x58021000 0x00000000 0x00400010 ;# GPIOE_MODER + mmw 0x58021008 0x00c00030 0x00000000 ;# GPIOE_OSPEEDR + mmw 0x58021020 0x00000900 0x00000000 ;# GPIOE_AFRL + mmw 0x58021024 0x0000b000 0x00000000 ;# GPIOE_AFRH + + # Reset Octo-SPI + mmw 0x5802447c 0x00204000 0x00000000 ;# RCC_AHB3RSTR |= OCTOSPIMRST | OCTOSPI1RST + # Take Octo-SPI out of reset + mmw 0x5802447c 0x00000000 0x00204000 ;# RCC_AHB3RSTR &= ~(OCTOSPIMRST | OCTOSPI1RST) + + # Turn on 1.8v power + mww 0x58020c18 0x00010000 ;# GPIOD_BSRR |= BR1 + + # Set up Octo-SPI interface + mww 0x52005000 0x00000400 ;# OCTOSPI_CR: FMODE=0x0, FTHRES=0x04 + mww 0x52005008 0x011B0208 ;# OCTOSPI_DCR1: MTYP=0x1, DEVSIZE=0x1B, CSHT=0x2, DLYBYP=0x1 + mww 0x5200500c 0x00000002 ;# OCTOSPI_DCR2: PRESCALER=0x02 + mmw 0x52005000 0x00000001 0x00000000 ;# OCTOSPI_CR: EN=0x1 + + # reset the Macronix flash + mww 0x52005100 0x00000001 ;# OCTOSPI_CCR: no data, no address, no alternate bytes, instruction on a single line + # indirect write mode without data, address and alternate bytes causes the following commands to be sent immediately + mww 0x52005110 0x00000066 ;# OCTOSPI_IR: Reset-Enable (RSTEN) + sleep 1 + mww 0x52005110 0x00000099 ;# OCTOSPI_IR: Reset (RST) + sleep 20 ;# wait for the flash to come out of reset + + mmw 0x52005000 0x30000000 0x00000001 ;# OCTOSPI_CR |= FMODE=0x3, &= ~EN + # OCTOSPI1: memory-mapped 1-line read mode with 3-byte addresses + mww 0x52005100 0x01002101 ;# OCTOSPI_CCR: DMODE=0x1, ABMODE=0x0, ADSIZE=0x2, ADMODE=0x1, ISIZE=0x0, IMODE=0x1 + mww 0x52005110 0x00000003 ;# OCTOSPI_IR: INSTR=READ + mmw 0x52005000 0x00000001 0x00000000 ;# OCTOSPI_CR |= EN + + flash probe 1 ;# load configuration from CR, TCR, CCR, IR register values +} + +$_CHIPNAME.cpu0 configure -event reset-end { + flash probe 0 + hxa-001_qspi_init +} diff --git a/openocd/target_mario.cfg b/openocd/target_mario.cfg new file mode 100644 index 0000000..9a2c99f --- /dev/null +++ b/openocd/target_mario.cfg @@ -0,0 +1,4 @@ +set TARGET "mario" +set SPIFLASH_SIZE 1048576 +set ITCM_OFFSET 0x00 +set ITCM_LENGTH 1300 diff --git a/openocd/target_zelda.cfg b/openocd/target_zelda.cfg new file mode 100644 index 0000000..d33824e --- /dev/null +++ b/openocd/target_zelda.cfg @@ -0,0 +1,4 @@ +set TARGET "zelda" +set SPIFLASH_SIZE 4194304 +set ITCM_OFFSET 0x20 +set ITCM_LENGTH 1300 diff --git a/prebuilt/gw_retrogo_nes_extflash.bin b/prebuilt/gw_retrogo_nes_extflash.bin deleted file mode 100755 index cf8e3fa..0000000 Binary files a/prebuilt/gw_retrogo_nes_extflash.bin and /dev/null differ diff --git a/python/tcm_encrypt.py b/python/tcm_encrypt.py index db5ee50..7fdf6cb 100644 --- a/python/tcm_encrypt.py +++ b/python/tcm_encrypt.py @@ -1,12 +1,12 @@ #!/usr/bin/env python3 import argparse -import sys parser = argparse.ArgumentParser(description='') parser = argparse.ArgumentParser() parser.add_argument('flash_image', nargs=1, type=argparse.FileType('rb')) -parser.add_argument('tcm_ram_image', nargs=1, type=argparse.FileType('rb')) +parser.add_argument('flash_offset', nargs=1, type=int) +parser.add_argument('itcm_image', nargs=1, type=argparse.FileType('rb')) parser.add_argument('code', nargs=1, type=argparse.FileType('rb')) parser.add_argument('flash_out', nargs=1, type=argparse.FileType('wb')) args = parser.parse_args() @@ -20,16 +20,16 @@ def xor(b1, b2): flash_image = args.flash_image[0].read() -tcm_ram_image = args.tcm_ram_image[0].read() +itcm_image = args.itcm_image[0].read() code = args.code[0].read() - -xor_image = xor(tcm_ram_image[:len(code)], flash_image) - +xor_image = xor(itcm_image[:len(code)], flash_image[args.flash_offset[0]:args.flash_offset[0]+len(code)]) new_flash_part = xor(code, xor_image) -flash_end = flash_image[len(code):] +flash_end = flash_image[args.flash_offset[0] + len(code):] +if (args.flash_offset[0] > 0): + args.flash_out[0].write(flash_image[:args.flash_offset[0]]) args.flash_out[0].write(new_flash_part) args.flash_out[0].write(flash_end) diff --git a/python/tcmhack.py b/python/tcmhack.py deleted file mode 100644 index db5ee50..0000000 --- a/python/tcmhack.py +++ /dev/null @@ -1,35 +0,0 @@ -#!/usr/bin/env python3 - -import argparse -import sys - -parser = argparse.ArgumentParser(description='') -parser = argparse.ArgumentParser() -parser.add_argument('flash_image', nargs=1, type=argparse.FileType('rb')) -parser.add_argument('tcm_ram_image', nargs=1, type=argparse.FileType('rb')) -parser.add_argument('code', nargs=1, type=argparse.FileType('rb')) -parser.add_argument('flash_out', nargs=1, type=argparse.FileType('wb')) -args = parser.parse_args() - - -def xor(b1, b2): - result = bytearray() - for b1, b2 in zip(b1, b2): - result.append(b1 ^ b2) - return result - - -flash_image = args.flash_image[0].read() -tcm_ram_image = args.tcm_ram_image[0].read() -code = args.code[0].read() - - -xor_image = xor(tcm_ram_image[:len(code)], flash_image) - - -new_flash_part = xor(code, xor_image) -flash_end = flash_image[len(code):] - - -args.flash_out[0].write(new_flash_part) -args.flash_out[0].write(flash_end) diff --git a/restore_only_external_flash.sh b/restore_only_external_flash.sh new file mode 100755 index 0000000..77cf86b --- /dev/null +++ b/restore_only_external_flash.sh @@ -0,0 +1,21 @@ +#!/bin/bash + +source config.sh $@ + +if ! test -f backups/flash_backup_$TARGET.bin; then + echo "No backup of SPI flash found in backups/flash_backup_$TARGET.bin" + exit 1 +fi + +echo "Restoring SPI flash..." +if ! ${OPENOCD} -f "openocd/target_${TARGET}.cfg" -f "openocd/interface_${ADAPTER}.cfg" \ + -c "init;" \ + -c "reset halt;" \ + -c "program backups/flash_backup_${TARGET}.bin 0x90000000 verify;" \ + -c "exit;" >>logs/5_openocd.log 2>&1; then + echo "Restoring SPI flash failed. Check debug connection and try again." + exit 1 +fi + +echo "Success, your device should be running the original firmware again!" +echo "(You should power-cycle the device now)" diff --git a/scripts/flashloader.sh b/scripts/flashloader.sh deleted file mode 100755 index 295ebf5..0000000 --- a/scripts/flashloader.sh +++ /dev/null @@ -1,62 +0,0 @@ -#!/bin/bash - -source config.sh $1 - -DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" >/dev/null 2>&1 && pwd )" -ELF=firmware/flash_programmer.elf -ADDRESS=0 -SIZE=$((1024 * 1024)) -MAGIC="0xdeadbeef" -ERASE=1 -IMAGE=$2 -objdump=${OBJDUMP:-arm-none-eabi-objdump} - -function get_symbol { - name=$1 - objdump_cmd="${objdump} -t ${ELF}" - size=$(${objdump_cmd} | grep " $name" | cut -d " " -f1 | tr 'a-f' 'A-F') - printf "$((16#${size}))\n" -} - -VAR_program_size=$(printf '0x%08x\n' $(get_symbol "program_size")) -VAR_program_address=$(printf '0x%08x\n' $(get_symbol "program_address")) -VAR_program_magic=$(printf '0x%08x\n' $(get_symbol "program_magic")) -VAR_program_done=$(printf '0x%08x\n' $(get_symbol "program_done")) -VAR_program_erase=$(printf '0x%08x\n' $(get_symbol "program_erase")) - - -if ! ${OPENOCD} -f openocd/interface_"${ADAPTER}".cfg \ - -c "init;" \ - -c "echo \"Resetting device\";" \ - -c "echo \"Programming ELF\";" \ - -c "load_image ${ELF};" \ - -c "reset halt;" \ - -c "sleep 100;" \ - -c "echo \"Loading image into RAM\";" \ - -c "load_image ${IMAGE} 0x24000000;" \ - -c "mww ${VAR_program_size} ${SIZE}" \ - -c "mww ${VAR_program_address} ${ADDRESS}" \ - -c "mww ${VAR_program_magic} ${MAGIC}" \ - -c "mww ${VAR_program_erase} ${ERASE}" \ - -c "reg sp [mrw 0x20000000];" \ - -c "reg pc [mrw 0x20000004];" \ - -c "echo \"Starting flash process\";" \ - -c "resume; exit;" >>logs/flashloader.log 2>&1; then - echo "Loading failed." - exit 1 -fi - - -echo "Loaded flashloader, flashing SPI, please wait." - -echo " (If this takes more than 2 minutes something went wrong.)" -echo " (If the screen blinks rapidly, something went wrong.)" -echo " (If the screen blinks slowly, everything worked but the script didn't detect it)" -while true; do - DONE_MAGIC=$(${OPENOCD} -f openocd/interface_${ADAPTER}.cfg -c "init; mdw ${VAR_program_done}" -c "exit;" 2>&1 | grep ${VAR_program_done} | cut -d" " -f2) - if [[ "$DONE_MAGIC" == "cafef00d" ]]; then - echo "Done!" - break; - fi - sleep 1 -done diff --git a/scripts/rdp1.sh b/scripts/rdp1.sh index e6b39a7..b42cdf2 100755 --- a/scripts/rdp1.sh +++ b/scripts/rdp1.sh @@ -1,6 +1,6 @@ #!/bin/bash -source config.sh $1 +source config.sh $@ echo "This will lock your device! Are you sure? (y/N)" read -n 1 -r @@ -11,13 +11,13 @@ then fi echo "Validating internal flash backup before proceeding..." -if ! shasum --check shasums/internal_flash_backup.bin.sha1 >/dev/null 2>&1; then +if ! shasum --check shasums/internal_flash_backup_$TARGET.bin.sha1 >/dev/null 2>&1; then echo "Backup is not valid. Aborting." exit 1 fi -echo "Locking device... (Takes up to 30 seconds.)" -if ! ${OPENOCD} -f openocd/interface_"${ADAPTER}".cfg \ +echo "Locking device... (Takes up to 30 seconds.)" +if ! ${OPENOCD} -f "openocd/interface_${ADAPTER}.cfg" \ -c "init;" \ -c "halt;" \ -f openocd/rdp1.cfg >>logs/rdp1_openocd.log 2>&1; then diff --git a/shasums/flash_backup_checksummed.bin.sha1 b/shasums/flash_backup_checksummed_mario.bin.sha1 similarity index 75% rename from shasums/flash_backup_checksummed.bin.sha1 rename to shasums/flash_backup_checksummed_mario.bin.sha1 index 3423f9c..0b876e8 100644 --- a/shasums/flash_backup_checksummed.bin.sha1 +++ b/shasums/flash_backup_checksummed_mario.bin.sha1 @@ -1 +1 @@ -eea70bb171afece163fb4b293c5364ddb90637ae backups/flash_backup_checksummed.bin +eea70bb171afece163fb4b293c5364ddb90637ae backups/flash_backup_checksummed_mario.bin diff --git a/shasums/flash_backup_checksummed_zelda.bin.sha1 b/shasums/flash_backup_checksummed_zelda.bin.sha1 new file mode 100644 index 0000000..463e0c5 --- /dev/null +++ b/shasums/flash_backup_checksummed_zelda.bin.sha1 @@ -0,0 +1 @@ +1c1c0ed66d07324e560dcd9e86a322ec5e4c1e96 backups/flash_backup_checksummed_zelda.bin \ No newline at end of file diff --git a/shasums/internal_flash_backup.bin.sha1 b/shasums/internal_flash_backup_mario.bin.sha1 similarity index 78% rename from shasums/internal_flash_backup.bin.sha1 rename to shasums/internal_flash_backup_mario.bin.sha1 index 3552896..2e4eab1 100644 --- a/shasums/internal_flash_backup.bin.sha1 +++ b/shasums/internal_flash_backup_mario.bin.sha1 @@ -1 +1 @@ -efa04c387ad7b40549e15799b471a6e1cd234c76 backups/internal_flash_backup.bin +efa04c387ad7b40549e15799b471a6e1cd234c76 backups/internal_flash_backup_mario.bin diff --git a/shasums/internal_flash_backup_zelda.bin.sha1 b/shasums/internal_flash_backup_zelda.bin.sha1 new file mode 100644 index 0000000..8549b98 --- /dev/null +++ b/shasums/internal_flash_backup_zelda.bin.sha1 @@ -0,0 +1 @@ +ac14bcea6e4ff68c88fd2302c021025a2fb47940 backups/internal_flash_backup_zelda.bin diff --git a/shasums/itcm_backup.bin.sha1 b/shasums/itcm_backup.bin.sha1 deleted file mode 100644 index ac04857..0000000 --- a/shasums/itcm_backup.bin.sha1 +++ /dev/null @@ -1 +0,0 @@ -ca71a54c0a22cca5c6ee129faee9f99f3a346ca0 backups/itcm_backup.bin diff --git a/shasums/itcm_backup_mario.bin.sha1 b/shasums/itcm_backup_mario.bin.sha1 new file mode 100644 index 0000000..d230679 --- /dev/null +++ b/shasums/itcm_backup_mario.bin.sha1 @@ -0,0 +1 @@ +ca71a54c0a22cca5c6ee129faee9f99f3a346ca0 backups/itcm_backup_mario.bin diff --git a/shasums/itcm_backup_zelda.bin.sha1 b/shasums/itcm_backup_zelda.bin.sha1 new file mode 100644 index 0000000..8f430a9 --- /dev/null +++ b/shasums/itcm_backup_zelda.bin.sha1 @@ -0,0 +1 @@ +2f70156235ffd871599facf64457040d549353b4 backups/itcm_backup_zelda.bin