Skip to content

Commit

Permalink
brom-dump: spft-replay: add mt6573 support
Browse files Browse the repository at this point in the history
  • Loading branch information
arzam16 committed Apr 1, 2023
1 parent a73340a commit 44486f5
Show file tree
Hide file tree
Showing 7 changed files with 151 additions and 2 deletions.
31 changes: 31 additions & 0 deletions brom-dump/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,8 @@
* [Hello, world!](#hello-world)
* [Figuring out I/O API](#figuring-out-io-api)
* [The usb-dump payload](#the-usb-dump-payload)
* [Dumping mt6573 BROM](#dumping-mt6573-brom)
* [SP Flash Tool issues](#sp-flash-tool-issues)
<!--te-->

# Dumping mt6589 BROM
Expand Down Expand Up @@ -220,3 +222,32 @@ Assembly is cool but when it comes to supporting more SoCs with different core t
2. Built init code as A32.
3. Changed DA patch from using `BL` instruction to `BLX`.
4. Bumped piggyback size to 0x800 bytes. This is 4 times more than the original but should be enough for whatever GCC outputs.

# Dumping mt6573 BROM

This SoC has ARM1176JZF-S core and if I wanted to keep writing in assembly I would definitely have had some issues regarding code compatibility. Having stuff written in C makes it GCC's headache, not mine.

My workflow to add mt6573 support will be similar to mt6589:
1. Capture SP Flash Tool traffic
2. Carve out the original DA
3. Teach `spft-replay` the traffic of mt6573
4. Patch original DA to make it jump to my code
5. ...
6. PROFIT!!!

## SP Flash Tool issues
My mt6573 device is old. Its on-board storage is NAND, not EMMC. Same version of SP Flash Tool I used for mt6589 successfully consumed a scatter for NAND but refused to do anything immediately after pushing DA. Looks like this version of software doesn't support NAND.

![NAND complaints from SP Flash Tool](../images/brom-dump-012.png)

I know SP Flash Tool for long enough to understand what kinds of bullshit can it generate. For example, having such an ouroboros is totally possible:

![SP Flash Tool trying to handle mt6573](../images/brom-dump-013.png)

The `MTK_AllInOne_DA.bin` found in the Linux distribution of SP Flash Tool v5.1648 **does** support mt6573:

![mt6573 DA in MTK_AllInOne_DA.bin from SPFT v5.1648](../images/brom-dump-014.png)

Looks like the NAND support depends on host SPFT application, not on DA itself. I started my Windows computer (the only reason for this is there are more archive versions for Windows than for Linux) and began testing SP Flash Tool distributions older than v5.1648 but I shoved them the DA from v5.1648. It took me some time to figure out that the latest version of SP Flash Tool for Windows that supports mt6573 with NAND is v5.1624.

I set up Wireshark and USBPcap and shortly after got the traffic dump I was looking for. The dumped traffic allowed me to carve out the original DA for mt6573 and implement support for this SoC in `spft-replay`.
5 changes: 5 additions & 0 deletions brom-dump/payloads/Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -69,6 +69,11 @@ $(OUT_DIR)/$(TARGET)-usb-dump-piggyback.o: usb-dump.c | $(OUT_DIR)
$(BUILD_DIR)/$(TARGET)-%-payload.bin: $(TARGET_DA_PATCHED) $(OUT_DIR)/$(TARGET)-%-piggyback.bin | $(BUILD_DIR) $(OUT_DIR)
cat $^ > "$@"

$(AUX_DIR)/mt6573-da-original.bin: $(AUX_DIR)/SP_Flash_Tool_v5.1648_Linux.zip | $(AUX_DIR)
7z x -so "$<" "SP_Flash_Tool_v5.1648_Linux/MTK_AllInOne_DA.bin" |\
tail -c +14813 | head -c 90932 \
> "$@"

$(AUX_DIR)/mt6589-da-original.bin: $(AUX_DIR)/SP_Flash_Tool_v5.1648_Linux.zip | $(AUX_DIR)
7z x -so "$<" "SP_Flash_Tool_v5.1648_Linux/MTK_AllInOne_DA.bin" |\
tail -c +767137 | head -c 141012 \
Expand Down
21 changes: 21 additions & 0 deletions brom-dump/spft-replay/src/device.py
Original file line number Diff line number Diff line change
Expand Up @@ -473,3 +473,24 @@ def set_power_reg(self, register, new_value, reference_value):
f"to {as_hex(new_value, 2)}, "
f"got {as_hex(pwr, 2)}"
)

# Inspired by mt6573 Wireshark dump
def write16_verify(self, register, new_value, reference_value):
# reference_value - a value obtained from the Wireshark dump of my device
old_value = self.read16(register)
if old_value != reference_value:
logging.warning(
f"Read {as_0x(register)}, "
f"got {as_hex(old_value, size=2)} but "
f"reference is {as_hex(reference_value, size=2)}"
)

self.write16(register, new_value)

check = self.read16(register)
if check != new_value:
logging.warning(
f"Set {as_0x(register)} "
f"to {as_hex(new_value, size=2)} but "
f"it is {as_hex(check, size=2)}"
)
96 changes: 94 additions & 2 deletions brom-dump/spft-replay/src/replay.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,13 +11,105 @@ def replay(dev, payload):
hw_code = dev.get_hw_code()
logging.replay(f"HW code: {as_hex(hw_code, 2)}")

if hw_code == 0x6583:
if hw_code == 0x6573:
replay_mt6573(dev, payload)
elif hw_code == 0x6583:
replay_mt6589(dev, payload) # The code is 0x6583 but the SoC is 6589
else:
logging.critical("Unsupported hardware!")
exit(1)


def replay_mt6573(dev, payload):
dev.get_hw_code() # Yes, SP Flash Tool requests it twice

hw_ver = dev.read16(0x70026000, check_status=False)
sw_ver = dev.read16(0x70026004, check_status=False)
logging.replay(f"HW version: {as_hex(hw_ver, size=2)}")
logging.replay(f"SW version: {as_hex(sw_ver, size=2)}")

logging.replay("Setting up PMIC")
dev.write16_verify(0x7002FE84, 0xFF04, 0xFF00) # KPLED_CON1
dev.write16_verify(0x7002FA0C, 0x2079, 0x3079) # CHR_CON3
dev.write16_verify(0x7002FA0C, 0x20F9, 0x2079) # CHR_CON3
dev.write16_verify(0x7002FA08, 0x5200, 0x4700) # CHR_CON2
dev.write16_verify(0x7002FA18, 0x0000, 0x0010) # CHR_CON6
dev.write16_verify(0x7002FA00, 0x7AB2, 0x62B2) # CHR_CON0
dev.write16_verify(0x7002FA20, 0x0800, 0x0000) # CHR_CON8
dev.write16_verify(0x7002FA28, 0x0100, 0x0000) # CHR_CON10
dev.write16_verify(0x7002FA24, 0x0180, 0x0080) # CHR_CON9

logging.replay("Disabling watchdog")
dev.write16(0x70025000, 0x2200)

# SP Flash Tool already knows the device is in BROM mode but still
# requests the preloader version
val = dev.get_preloader_version()

logging.replay("Setup RTC")
for addr in [0x70014000, 0x70014050, 0x70014054]:
val = dev.read16(addr)
logging.replay(f"RTC register {as_0x(addr)} == {as_hex(val, 2)}")

dev.write16(0x70014010, 0x0000) # Enable all alarm IRQs
dev.write16(0x70014008, 0x0000) # Disable all IRQ generations
dev.write16(0x7001400C, 0x0000) # Disable all counter IRQs
dev.write16(0x70014074, 0x0001) # Commit changes
val = dev.read16(0x70014000) # 0x0008

dev.write16(0x70014050, 0xA357) # Write reference value
dev.write16(0x70014054, 0x67D2) # Write reference value
dev.write16(0x70014074, 0x0001) # Commit changes
val = dev.read16(0x70014000) # 0x0008

dev.write16(0x70014068, 0x586A) # Unlock RTC protection (part 1)
dev.write16(0x70014074, 0x0001) # Commit changes
val = dev.read16(0x70014000) # 0x0008

dev.write16(0x70014068, 0x9136) # Unlock RTC protection (part 2)
dev.write16(0x70014074, 0x0001) # Commit changes
val = dev.read16(0x70014000) # 0x0008

dev.write16(0x70014000, 0x430E) # Enable bus writes, enable PMIC RTC and auto mode
dev.write16(0x70014074, 0x0001) # Commit changes
val = dev.read16(0x70014000) # 0x000E

val = dev.get_me_id()
logging.replay(f"ME ID: {as_hex(val)}")
val = dev.get_me_id() # Again

val = dev.get_target_config()
logging.replay(f"Target config: {val}")
val = dev.get_target_config()

val = dev.get_brom_version()
logging.replay(f"BROM version: {as_hex(val, 1)}")
val = dev.get_preloader_version()

# External memory interface
MT6573_EMI_GENA = 0x70000000
val = dev.read32(MT6573_EMI_GENA) # 00000000 on my device
dev.write32(MT6573_EMI_GENA, 0x00000002)
logging.replay(
f"EMI_GENA ({as_0x(MT6573_EMI_GENA)}) "
f"set to {as_hex(0x2)}, was {as_hex(val)}"
)

val = dev.send_da(0x90005000, len(payload), 0x100, payload)
logging.replay(f"Received DA checksum: {as_hex(val, 2)}")

dev.jump_da(0x90005000)

# Download Agent is running and sends some data we have to receive
# and ACK in order to get everything initialized before it will
# jump to custom payload.
logging.replay("Waiting for device to send remaining data")
logging.replay(f"<- DA: (unknown) {as_hex(dev.read(1))}") # C0
logging.replay(f"<- DA: (unknown) {as_hex(dev.read(1))}") # 03
logging.replay(f"<- DA: (unknown) {as_hex(dev.read(1))}") # 02
logging.replay(f"<- DA: (unknown) {as_hex(dev.read(1))}") # 83


def replay_mt6589(dev, payload):
hw_dict = dev.get_hw_sw_ver()
logging.replay(f"HW subcode: {as_hex(hw_dict[0], 2)}")
Expand Down Expand Up @@ -69,7 +161,7 @@ def replay_mt6589(dev, payload):

dev.jump_da(0x12000000)

# Download agent is running and sends some data we have to receive
# Download Agent is running and sends some data we have to receive
# and ACK in order to get everything initialized before it will
# jump to custom payload.
logging.replay("Waiting for device to send remaining data")
Expand Down
Binary file added images/brom-dump-012.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added images/brom-dump-013.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added images/brom-dump-014.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.

0 comments on commit 44486f5

Please sign in to comment.