diff --git a/brom-dump/README.md b/brom-dump/README.md index 5892b9f..a07f72e 100644 --- a/brom-dump/README.md +++ b/brom-dump/README.md @@ -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) # Dumping mt6589 BROM @@ -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`. diff --git a/brom-dump/payloads/Makefile b/brom-dump/payloads/Makefile index 483393f..e1458e8 100644 --- a/brom-dump/payloads/Makefile +++ b/brom-dump/payloads/Makefile @@ -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 \ diff --git a/brom-dump/spft-replay/src/device.py b/brom-dump/spft-replay/src/device.py index 32e7679..0641820 100644 --- a/brom-dump/spft-replay/src/device.py +++ b/brom-dump/spft-replay/src/device.py @@ -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)}" + ) diff --git a/brom-dump/spft-replay/src/replay.py b/brom-dump/spft-replay/src/replay.py index 13a8f42..c7e6c2d 100644 --- a/brom-dump/spft-replay/src/replay.py +++ b/brom-dump/spft-replay/src/replay.py @@ -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)}") @@ -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") diff --git a/images/brom-dump-012.png b/images/brom-dump-012.png new file mode 100644 index 0000000..83e68a6 Binary files /dev/null and b/images/brom-dump-012.png differ diff --git a/images/brom-dump-013.png b/images/brom-dump-013.png new file mode 100644 index 0000000..2d8e0cb Binary files /dev/null and b/images/brom-dump-013.png differ diff --git a/images/brom-dump-014.png b/images/brom-dump-014.png new file mode 100644 index 0000000..9d1ed02 Binary files /dev/null and b/images/brom-dump-014.png differ