Skip to content

Instantly share code, notes, and snippets.

@sadiqsalau
Last active April 26, 2023 06:45
Show Gist options
  • Save sadiqsalau/88ad9c5a71a1d2f63dbe342095f2164d to your computer and use it in GitHub Desktop.
Save sadiqsalau/88ad9c5a71a1d2f63dbe342095f2164d to your computer and use it in GitHub Desktop.
Gionee S10L - MtkClient Patch

Make sure to delete every preloader in mtkclient/Loader/Preloader except preloader_gnsz6757_66_n_s10.bin

**Changes

  • Hard coded emmc info - Line 580, fixes the no emmc info error of MT6757
  • Disabled emmc info check - Line 1200, ensure to keep only the right preloader
#!/usr/bin/python3
# -*- coding: utf-8 -*-
# (c) B.Kerler 2018-2021 GPLv3 License
import logging
import time
import os
import hashlib
from binascii import hexlify
from struct import pack, unpack
from mtkclient.Library.utils import LogBase, progress, logsetup
from mtkclient.Library.error import ErrorHandler
from mtkclient.Library.daconfig import EMMC_PartitionType, UFS_PartitionType, DaStorage
from mtkclient.Library.partition import Partition
from mtkclient.config.payloads import pathconfig
from mtkclient.Library.xflash_ext import xflashext, XCmd
from mtkclient.Library.settings import hwparam
from queue import Queue
from threading import Thread, Event
rq = Queue()
def writedata(filename, rq):
pos = 0
with open(filename, "wb") as wf:
while True:
data = rq.get()
if data is None:
break
pos += len(data)
wf.write(data)
rq.task_done()
class NandExtension:
# uni=0, multi=1
cellusage = 0
# logical=0, physical=1, physical_pmt=2
addr_type = 0
# raw=0, ubi_img=1, ftl_img=2
bin_type = 0
# operation_type -> spare=0,page=1,page_ecc=2,page_spare_ecc=3,verify=4,page_spare_norandom,page_fdm
# nand_format_level -> format_normal=0,force=1,mark_bad_block=2,level_end=3
operation_type = 0 # or nand_format_level
sys_slc_percent = 0
usr_slc_percent = 0
phy_max_size = 0
def addr_to_block(addr, blocksize):
return addr // blocksize
class DAXFlash(metaclass=LogBase):
class Cmd:
MAGIC = 0xFEEEEEEF
SYNC_SIGNAL = 0x434E5953
UNKNOWN = 0x010000
DOWNLOAD = 0x010001
UPLOAD = 0x010002
FORMAT = 0x010003
WRITE_DATA = 0x010004
READ_DATA = 0x010005
FORMAT_PARTITION = 0x010006
SHUTDOWN = 0x010007
BOOT_TO = 0x010008
DEVICE_CTRL = 0x010009
INIT_EXT_RAM = 0x01000A
SWITCH_USB_SPEED = 0x01000B
READ_OTP_ZONE = 0x01000C
WRITE_OTP_ZONE = 0x01000D
WRITE_EFUSE = 0x01000E
READ_EFUSE = 0x01000F
NAND_BMT_REMARK = 0x010010
SETUP_ENVIRONMENT = 0x010100
SETUP_HW_INIT_PARAMS = 0x010101
SET_BMT_PERCENTAGE = 0x020001
SET_BATTERY_OPT = 0x020002
SET_CHECKSUM_LEVEL = 0x020003
SET_RESET_KEY = 0x020004
SET_HOST_INFO = 0x020005
SET_META_BOOT_MODE = 0x020006
SET_EMMC_HWRESET_PIN = 0x020007
SET_GENERATE_GPX = 0x020008
SET_REGISTER_VALUE = 0x020009
SET_EXTERNAL_SIG = 0x02000A
SET_REMOTE_SEC_POLICY = 0x02000B
SET_ALL_IN_ONE_SIG = 0x02000C
SET_RSC_INFO = 0x02000D
SET_UPDATE_FW = 0x020010
SET_UFS_CONFIG = 0x020011
GET_EMMC_INFO = 0x040001
GET_NAND_INFO = 0x040002
GET_NOR_INFO = 0x040003
GET_UFS_INFO = 0x040004
GET_DA_VERSION = 0x040005
GET_EXPIRE_DATA = 0x040006
GET_PACKET_LENGTH = 0x040007
GET_RANDOM_ID = 0x040008
GET_PARTITION_TBL_CATA = 0x040009
GET_CONNECTION_AGENT = 0x04000A
GET_USB_SPEED = 0x04000B
GET_RAM_INFO = 0x04000C
GET_CHIP_ID = 0x04000D
GET_OTP_LOCK_STATUS = 0x04000E
GET_BATTERY_VOLTAGE = 0x04000F
GET_RPMB_STATUS = 0x040010
GET_EXPIRE_DATE = 0x040011
GET_DRAM_TYPE = 0x040012
GET_DEV_FW_INFO = 0x040013
GET_HRID = 0x040014
GET_ERROR_DETAIL = 0x040015
START_DL_INFO = 0x080001
END_DL_INFO = 0x080002
ACT_LOCK_OTP_ZONE = 0x080003
DISABLE_EMMC_HWRESET_PIN = 0x080004
CC_OPTIONAL_DOWNLOAD_ACT = 0x800005
DA_STOR_LIFE_CYCLE_CHECK = 0x080007
UNKNOWN_CTRL_CODE = 0x0E0000
CTRL_STORAGE_TEST = 0x0E0001
CTRL_RAM_TEST = 0x0E0002
DEVICE_CTRL_READ_REGISTER = 0x0E0003
class ChecksumAlgorithm:
PLAIN = 0
CRC32 = 1
MD5 = 2
class FtSystemOSE:
OS_WIN = 0
OS_LINUX = 1
class DataType:
DT_PROTOCOL_FLOW = 1
DT_MESSAGE = 2
def __init__(self, mtk, daconfig, loglevel=logging.INFO):
self.__logger = logsetup(self, self.__logger, loglevel, mtk.config.gui)
self.info = self.__logger.info
self.debug = self.__logger.debug
self.error = self.__logger.error
self.warning = self.__logger.warning
self.mtk = mtk
self.loglevel = loglevel
self.daext = False
self.sram = None
self.dram = None
self.emmc = None
self.nand = None
self.nor = None
self.ufs = None
self.chipid = None
self.randomid = None
self.__logger = self.__logger
self.eh = ErrorHandler()
self.config = self.mtk.config
self.usbwrite = self.mtk.port.usbwrite
self.usbread = self.mtk.port.usbread
self.echo = self.mtk.port.echo
self.rbyte = self.mtk.port.rbyte
self.rdword = self.mtk.port.rdword
self.rword = self.mtk.port.rword
self.daconfig = daconfig
self.partition = Partition(self.mtk, self.readflash, self.read_pmt, loglevel)
self.pathconfig = pathconfig()
self.patch = False
self.generatekeys = self.mtk.config.generatekeys
if self.generatekeys:
self.patch = True
self.xft = xflashext(self.mtk, self, loglevel)
def usleep(self, usec):
time.sleep(usec / 100000)
def ack(self, rstatus=True):
try:
tmp = pack("<III", self.Cmd.MAGIC, self.DataType.DT_PROTOCOL_FLOW, 4)
data = pack("<I", 0)
self.usbwrite(tmp)
self.usbwrite(data)
if rstatus:
status = self.status()
return status
return True
except:
return -1
def xsend(self, data, datatype=DataType.DT_PROTOCOL_FLOW, is64bit: bool = False):
if isinstance(data, int):
if is64bit:
data = pack("<Q", data)
length = 8
else:
data = pack("<I", data)
length = 4
else:
length = len(data)
tmp = pack("<III", self.Cmd.MAGIC, datatype, length)
if self.usbwrite(tmp):
return self.usbwrite(data)
return False
def xread(self):
try:
hdr = self.usbread(4 + 4 + 4)
magic, datatype, length = unpack("<III", hdr)
except Exception as err:
self.error("xread error: " + str(err))
return -1
if magic != 0xFEEEEEEF:
self.error("xread error: Wrong magic")
return -1
resp = self.usbread(length)
return resp
def rdword(self, count=1):
data = []
for i in range(count):
data.append(unpack("<I", self.xread())[0])
if count == 1:
return data[0]
return data
def status(self):
hdr = self.usbread(4 + 4 + 4)
magic, datatype, length = unpack("<III", hdr)
if magic != 0xFEEEEEEF:
self.error("Status error: Wrong magic")
return -1
tmp = self.usbread(length)
if len(tmp) < length:
self.error(f"Status length error: Too few data {hex(len(hdr))}")
return -1
if length == 2:
status = unpack("<H", tmp)[0]
if status == 0x0:
return 0
elif length == 4:
status = unpack("<I", tmp)[0]
if status == 0xFEEEEEEF:
return 0
else:
status = unpack("<" + str(length // 4) + "I", tmp)[0]
return status
def read_pmt(self):
return b"", []
def send_param(self, params):
if isinstance(params, bytes):
params = [params]
for param in params:
pkt = pack("<III", self.Cmd.MAGIC, self.DataType.DT_PROTOCOL_FLOW, len(param))
if self.usbwrite(pkt):
length = len(param)
pos = 0
while length > 0:
dsize = min(length, 0x200)
if not self.usbwrite(param[pos:pos + dsize]):
break
pos += dsize
length -= dsize
status = self.status()
if status == 0:
return True
else:
if status != 0xc0040050:
self.error(f"Error on sending parameter: {self.eh.status(status)}")
return False
def send_devctrl(self, cmd, param=None, status=None):
if status is None:
status = [0]
if self.xsend(self.Cmd.DEVICE_CTRL):
status[0] = self.status()
if status[0] == 0x0:
if self.xsend(cmd):
status[0] = self.status()
if status[0] == 0x0:
if param is None:
return self.xread()
else:
return self.send_param(param)
if status[0] != 0xC0010004:
self.error(f"Error on sending dev ctrl {cmd}:" + self.eh.status(status[0]))
return b""
def set_reset_key(self, reset_key=0x68):
# default:0x0,one:0x50,two:0x68
param = pack("<I", reset_key)
return self.send_devctrl(self.Cmd.SET_RESET_KEY, param)
def set_meta(self, porttype="off"):
class mtk_boot_mode_flag:
boot_mode = b"\x00" # 0:normal, 1:meta
com_type = b"\x00" # 0:unknown, 1:uart, 2:usb
com_id = b"\x00" # 0:single interface device (meta,adb)
# 1:composite device (meta, adb disable)
# 2:no meta, adb enable
# 3:no meta, adb disable
def __init__(self, mode="off"):
if mode == "off":
self.boot_mode = b"\x00"
self.com_type = b"\x00"
self.com_id = b"\x00"
elif mode == "uart":
self.boot_mode = b"\x01"
self.com_type = b"\x01"
self.com_id = b"\x00"
elif mode == "usb":
self.boot_mode = b"\x01"
self.com_type = b"\x02"
self.com_id = b"\x00"
def get(self):
return self.boot_mode + self.com_type + self.com_id
metamode = mtk_boot_mode_flag(porttype).get()
return self.send_devctrl(self.Cmd.SET_META_BOOT_MODE, metamode)
def set_checksum_level(self, checksum_level=0x0):
param = pack("<I", checksum_level)
# none[0x0]. USB[0x1]. storage[0x2], both[0x3]
return self.send_devctrl(self.Cmd.SET_CHECKSUM_LEVEL, param)
def set_battery_opt(self, option=0x2):
param = pack("<I", option)
# battery[0x0]. USB power[0x1]. auto[0x2]
return self.send_devctrl(self.Cmd.SET_BATTERY_OPT, param)
def send_emi(self, emi):
if self.xsend(self.Cmd.INIT_EXT_RAM):
status = self.status()
if status == 0:
try:
time.sleep(0.01)
if self.xsend(pack("<I", len(emi))):
if self.send_param([emi]):
self.info(f"DRAM setup passed.")
return True
except Exception as err:
self.error(f"Error on sending emi: {str(err)}")
return False
else:
self.error(f"Error on sending emi: {self.eh.status(status)}")
return False
def send_data(self, data):
pkt2 = pack("<III", self.Cmd.MAGIC, self.DataType.DT_PROTOCOL_FLOW, len(data))
if self.usbwrite(pkt2):
bytestowrite = len(data)
pos = 0
while bytestowrite > 0:
if self.usbwrite(data[pos:pos + 64]):
pos += 64
bytestowrite -= 64
status = self.status()
if status == 0x0:
return True
else:
self.error(f"Error on sending data: {self.eh.status(status)}")
return False
def boot_to(self, at_address, da, display=True, timeout=0.5): # =0x40000000
if self.xsend(self.Cmd.BOOT_TO):
if self.status() == 0:
param = pack("<QQ", at_address, len(da))
pkt1 = pack("<III", self.Cmd.MAGIC, self.DataType.DT_PROTOCOL_FLOW, len(param))
if self.usbwrite(pkt1):
if self.usbwrite(param):
if self.send_data(da):
self.info(f"Upload data was accepted. Jumping to stage 2...")
if timeout:
time.sleep(timeout)
status = -1
try:
status = self.status()
except:
if status == -1:
self.error(f"Stage was't executed. Maybe dram issue ?.")
return False
self.error(f"Error on boot to: {self.eh.status(status)}")
return False
if status == 0x434E5953 or status == 0x0:
return True
else:
self.error(f"Error on boot to: {self.eh.status(status)}")
return False
def get_connection_agent(self):
# brom
res = self.send_devctrl(self.Cmd.GET_CONNECTION_AGENT)
if res != b"":
status = self.status()
if status == 0x0:
return res
else:
self.error(f"Error on getting connection agent: {self.eh.status(status)}")
return None
"""
def get_dram_type(self):
res = self.send_devctrl(self.Cmd.GET_DRAM_TYPE)
status = self.status()
if status == 0x0:
return res
"""
def partitiontype_and_size(self, storage=None, parttype=None, length=0):
if storage == DaStorage.MTK_DA_STORAGE_EMMC or storage == DaStorage.MTK_DA_STORAGE_SDMMC:
storage = 1
if parttype is None or parttype == "user":
parttype = EMMC_PartitionType.MTK_DA_EMMC_PART_USER
elif parttype == "boot1":
parttype = EMMC_PartitionType.MTK_DA_EMMC_PART_BOOT1
if self.daconfig.flashtype == "emmc":
length = min(length, self.emmc.boot1_size)
elif parttype == "boot2":
parttype = EMMC_PartitionType.MTK_DA_EMMC_PART_BOOT2
if self.daconfig.flashtype == "emmc":
length = min(length, self.emmc.boot2_size)
elif parttype == "gp1":
parttype = EMMC_PartitionType.MTK_DA_EMMC_PART_GP1
if self.daconfig.flashtype == "emmc":
length = min(length, self.emmc.gp1_size)
elif parttype == "gp2":
parttype = EMMC_PartitionType.MTK_DA_EMMC_PART_GP2
if self.daconfig.flashtype == "emmc":
length = min(length, self.emmc.gp2_size)
elif parttype == "gp3":
parttype = EMMC_PartitionType.MTK_DA_EMMC_PART_GP3
if self.daconfig.flashtype == "emmc":
length = min(length, self.emmc.gp3_size)
elif parttype == "gp4":
parttype = EMMC_PartitionType.MTK_DA_EMMC_PART_GP4
if self.daconfig.flashtype == "emmc":
length = min(length, self.emmc.gp4_size)
elif parttype == "rpmb":
parttype = EMMC_PartitionType.MTK_DA_EMMC_PART_RPMB
if self.daconfig.flashtype == "emmc":
length = min(length, self.emmc.rpmb_size)
else:
self.error("Unknown parttype. Known parttypes are \"boot1\",\"boot2\",\"gp1\"," +
"\"gp2\",\"gp3\",\"gp4\",\"rpmb\"")
return []
elif storage == DaStorage.MTK_DA_STORAGE_UFS:
if parttype is None or parttype == "lu3" or parttype == "user": # USER
parttype = UFS_PartitionType.UFS_LU3
length = min(length, self.ufs.lu0_size)
elif parttype in ["lu1", "boot1"]: # BOOT1
parttype = UFS_PartitionType.UFS_LU1
length = min(length, self.ufs.lu1_size)
elif parttype in ["lu2", "boot2"]: # BOOT2
parttype = UFS_PartitionType.UFS_LU2
length = min(length, self.ufs.lu2_size)
elif parttype in ["lu4", "rpmb"]: # RPMB
parttype = UFS_PartitionType.UFS_LU4
length = min(length, self.ufs.lu2_size)
else:
self.error("Unknown parttype. Known parttypes are \"lu1\",\"lu2\",\"lu3\",\"lu4\"")
return []
elif storage in [DaStorage.MTK_DA_STORAGE_NAND, DaStorage.MTK_DA_STORAGE_NAND_MLC,
DaStorage.MTK_DA_STORAGE_NAND_SLC, DaStorage.MTK_DA_STORAGE_NAND_TLC,
DaStorage.MTK_DA_STORAGE_NAND_SPI, DaStorage.MTK_DA_STORAGE_NAND_AMLC]:
parttype = EMMC_PartitionType.MTK_DA_EMMC_PART_USER
length = min(length, self.nand.total_size)
elif storage in [DaStorage.MTK_DA_STORAGE_NOR, DaStorage.MTK_DA_STORAGE_NOR_PARALLEL,
DaStorage.MTK_DA_STORAGE_NOR_SERIAL]:
parttype = EMMC_PartitionType.MTK_DA_EMMC_PART_USER
length = min(length, self.nor.available_size)
return [storage, parttype, length]
def formatflash(self, addr, length, storage=None,
parttype=None, display=False):
self.mtk.daloader.progress.clear()
part_info = self.getstorage(parttype, length)
if not part_info:
return False
storage, parttype, length = part_info
self.info(f"Formatting addr {hex(addr)} with length {hex(length)}, please standby....")
self.mtk.daloader.progress.show_progress("Erasing", 0, length, True)
if self.xsend(self.Cmd.FORMAT):
status = self.status()
if status == 0:
# storage: emmc:1,slc,nand,nor,ufs
# section: boot,user of emmc:8, LU1, LU2
ne = NandExtension()
param = pack("<IIQQ", storage, parttype, addr, length)
param += pack("<IIIIIIII", ne.cellusage, ne.addr_type, ne.bin_type, ne.operation_type,
ne.sys_slc_percent, ne.usr_slc_percent, ne.phy_max_size, 0x0)
if self.send_param(param):
status = self.status()
while status == 0x40040004: # STATUS_CONTINUE
# it receive some data maybe sleep in ms time,
time.sleep(self.status() / 1000.0)
status = self.ack()
if status == 0x40040005: # STATUS_COMPLETE
self.mtk.daloader.progress.show_progress("Erasing", length, length, True)
self.info(f"Successsfully formatted addr {hex(addr)} with length {length}.")
return True
if status != 0x0:
self.error(f"Error on format: {self.eh.status(status)}")
return False
def get_da_version(self):
data = self.send_devctrl(self.Cmd.GET_DA_VERSION)
status = self.status()
if status == 0:
self.info(f"DA-VERSION : {data.decode('utf-8')}")
return data
else:
self.error(f"Error on getting chip id: {self.eh.status(status)}")
return None
def get_chip_id(self):
class Chipid:
hw_code = 0
hw_sub_code = 0
hw_version = 0
sw_version = 0
chip_evolution = 0
chipid = Chipid
data = self.send_devctrl(self.Cmd.GET_CHIP_ID)
chipid.hw_code, chipid.hw_sub_code, chipid.hw_version, chipid.sw_version, chipid.chip_evolution = unpack(
"<HHHHH",
data[:(5 * 2)])
status = self.status()
if status == 0:
self.info("HW-CODE : 0x%X", chipid.hw_code)
self.info("HWSUB-CODE : 0x%X", chipid.hw_sub_code)
self.info("HW-VERSION : 0x%X", chipid.hw_version)
self.info("SW-VERSION : 0x%X", chipid.sw_version)
self.info("CHIP-EVOLUTION : 0x%X", chipid.chip_evolution)
return chipid
else:
self.error(f"Error on getting chip id: {self.eh.status(status)}")
return None
def get_ram_info(self):
resp = self.send_devctrl(self.Cmd.GET_RAM_INFO)
if resp != b"":
status = self.status()
if status == 0x0:
class RamInfo:
type = 0
base_address = 0
size = 0
sram = RamInfo()
dram = RamInfo()
if len(resp) == 24:
sram.type, sram.base_address, sram.size, dram.type, dram.base_address, dram.size = unpack("<IIIIII",
resp)
elif len(resp) == 48:
sram.type, sram.base_address, sram.size, dram.type, dram.base_address, dram.size = unpack("<QQQQQQ",
resp)
return sram, dram
else:
self.error(f"Error on getting ram info: {self.eh.status(status)}")
return None, None
def get_emmc_info(self, display=True):
# resp = self.send_devctrl(self.Cmd.GET_EMMC_INFO)
# if resp == b'':
# return None
# status = self.status()
# if status == 0:
if True:
class EmmcInfo:
type = 1 # emmc or sdmmc or none
block_size = 0x200
boot1_size = 0x400000
boot2_size = 0x400000
rpmb_size = 0
gp1_size = 0
gp2_size = 0
gp3_size = 0
gp4_size = 0
user_size = 0xe8f800000
cid = b""
fwver = 0
unknown = b""
emmc = EmmcInfo()
return emmc
pos = 0
emmc.type, emmc.block_size = unpack("<II", resp[pos:pos + 8])
pos += 8
emmc.boot1_size, emmc.boot2_size, emmc.rpmb_size, emmc.gp1_size, emmc.gp2_size, emmc.gp3_size, \
emmc.gp4_size, emmc.user_size = unpack("<QQQQQQQQ", resp[pos:pos + (8 * 8)])
pos += 8 * 8
emmc.cid = resp[pos:pos + (4 * 4)]
pos += (4 * 4)
emmc.fwver = unpack("<Q", resp[pos:pos + 8])[0]
pos += 8
emmc.unknown = resp[pos:]
if emmc.type != 0 and display:
self.info(f"EMMC FWVer: {hex(emmc.fwver)}")
try:
self.info(f"EMMC ID: {emmc.cid[3:9].decode('utf-8')}")
except:
pass
self.info(f"EMMC CID: {hexlify(emmc.cid).decode('utf-8')}")
if self.config.hwparam is not None:
self.config.set_cid(emmc.cid)
self.info(f"EMMC Boot1 Size: {hex(emmc.boot1_size)}")
self.info(f"EMMC Boot2 Size: {hex(emmc.boot2_size)}")
self.info(f"EMMC GP1 Size: {hex(emmc.gp1_size)}")
self.info(f"EMMC GP2 Size: {hex(emmc.gp2_size)}")
self.info(f"EMMC GP3 Size: {hex(emmc.gp3_size)}")
self.info(f"EMMC GP4 Size: {hex(emmc.gp4_size)}")
self.info(f"EMMC RPMB Size: {hex(emmc.rpmb_size)}")
self.info(f"EMMC USER Size: {hex(emmc.user_size)}")
return emmc
else:
self.error(f"Error on getting emmc info: {self.eh.status(status)}")
return None
def get_nand_info(self, display=True):
resp = self.send_devctrl(self.Cmd.GET_NAND_INFO)
if resp == b'':
return None
status = self.status()
if status == 0:
class NandInfo:
type = 1 # slc, mlc, spi, none
page_size = 0
block_size = 0x200
spare_size = 0
total_size = 0
available_size = 0
nand_bmt_exist = 0
nand_id = 0
nand = NandInfo()
pos = 0
nand.type, nand.page_size, nand.block_size, nand.spare_size = unpack("<IIII", resp[pos:pos + 16])
pos += 16
nand.total_size, nand.available_size = unpack("<QQ", resp[pos:pos + (2 * 8)])
pos += 2 * 8
nand.nand_bmt_exist = resp[pos:pos + 1]
pos += 1
nand.nand_id = bytearray(resp[pos:pos + 12])
if nand.type != 0:
if display:
self.info(f"NAND Pagesize: {hex(nand.page_size)}")
self.info(f"NAND Blocksize: {hex(nand.block_size)}")
self.info(f"NAND Sparesize: {hex(nand.spare_size)}")
self.info(f"NAND Total size: {hex(nand.total_size)}")
self.info(f"NAND Avail: {hex(nand.available_size)}")
self.info(f"NAND ID: {nand.nand_id.hex()}")
return nand
else:
self.error(f"Error on getting nand info: {self.eh.status(status)}")
return None
def get_rpmb_status(self):
resp = self.send_devctrl(self.Cmd.GET_RPMB_STATUS)
if resp == b'':
return None
status = self.status()
if status == 0:
return resp
def get_nor_info(self, display=True):
resp = self.send_devctrl(self.Cmd.GET_NOR_INFO)
if resp == b'':
return None
status = self.status()
if status == 0:
class NorInfo:
type = 1 # nor, none
page_size = 0
available_size = 0
nor = NorInfo()
nor.type, nor.page_size, nor.available_size = unpack("<IIQ", resp[:16])
if nor.type != 0:
if display:
self.info(f"NOR Pagesize: {hex(nor.page_size)}")
self.info(f"NOR Size: {hex(nor.available_size)}")
return nor
else:
self.error(f"Error on getting nor info: {self.eh.status(status)}")
return None
def get_ufs_info(self, display=True):
resp = self.send_devctrl(self.Cmd.GET_UFS_INFO)
if resp == b'':
return None
status = self.status()
if status == 0:
class UfsInfo:
type = 1 # nor, none
block_size = 0
lu0_size = 0
lu1_size = 0
lu2_size = 0
cid = b""
fwver = b""
serial = b""
ufs = UfsInfo()
ufs.type, ufs.block_size, ufs.lu2_size, ufs.lu1_size, ufs.lu0_size = unpack("<IIQQQ",
resp[:(2 * 4) + (3 * 8)])
pos = (2 * 4) + (3 * 8)
buf = resp[pos:]
ufs.cid = buf[:16]
ufs.fwver = buf[22:22+4]
ufs.serial = buf[30:30+0xC]
if ufs.type != 0:
if display:
self.info(f"UFS Blocksize:{hex(ufs.block_size)}")
try:
self.info(f"UFS ID: {ufs.cid[2:].decode('utf-8')}")
except:
pass
self.info(f"UFS MID: {hex(ufs.cid[0])}")
self.info(f"UFS CID: {hexlify(ufs.cid).decode('utf-8')}")
self.info(f"UFS FWVer: {hexlify(ufs.fwver).decode('utf-8')}")
self.info(f"UFS Serial: {hexlify(ufs.serial).decode('utf-8')}")
self.info(f"UFS LU0 Size: {hex(ufs.lu0_size)}")
self.info(f"UFS LU1 Size: {hex(ufs.lu1_size)}")
self.info(f"UFS LU2 Size: {hex(ufs.lu2_size)}")
if self.config.hwparam is not None:
self.config.set_cid(buf[:0x11+2]+buf[0x16:0x16+4+1]+buf[0x1E:0x1E+0xC])
self.mtk.config.pagesize = ufs.block_size
self.mtk.daloader.daconfig.pagesize = ufs.block_size
return ufs
else:
self.error(f"Error on getting ufs info: {self.eh.status(status)}")
return None
def get_expire_date(self):
res = self.send_devctrl(self.Cmd.GET_EXPIRE_DATE)
if res != b"":
status = self.status()
if status == 0x0:
return res
else:
self.error(f"Error on getting expire date: {self.eh.status(status)}")
return None
def get_random_id(self):
res = self.send_devctrl(self.Cmd.GET_RANDOM_ID)
if res != b"":
status = self.status()
if status == 0:
return res
else:
self.error(f"Error on getting random id: {self.eh.status(status)}")
return None
def get_hrid(self):
res = self.send_devctrl(self.Cmd.GET_HRID)
if res != b"":
status = self.status()
if status == 0:
return res
else:
self.error(f"Error on getting hrid info: {self.eh.status(status)}")
return None
def get_dev_fw_info(self):
res = self.send_devctrl(self.Cmd.GET_DEV_FW_INFO)
if res != b"":
status = self.status()
if status == 0:
return res
else:
self.error(f"Error on getting dev fw info: {self.eh.status(status)}")
return None
def get_da_stor_life_check(self):
res = self.send_devctrl(self.Cmd.DA_STOR_LIFE_CYCLE_CHECK)
if res != b"":
return unpack("<I", res)[0]
else:
return 0
def get_packet_length(self):
resp = self.send_devctrl(self.Cmd.GET_PACKET_LENGTH)
if resp != b"":
status = self.status()
if status == 0:
class Packetlen:
write_packet_length = 0
read_packet_length = 0
plen = Packetlen()
plen.write_packet_length, plen.read_packet_length = unpack("<II", resp)
return plen
else:
self.error(f"Error on getting packet length: {self.eh.status(status)}")
return None
def get_usb_speed(self):
resp = self.send_devctrl(self.Cmd.GET_USB_SPEED)
if resp != b"":
status = self.status()
if status == 0:
# full-speed, high-speed, hyper-speed
return resp
else:
self.error(f"Error on getting usb speed: {self.eh.status(status)}")
return None
def set_usb_speed(self):
resp = self.xsend(self.Cmd.SWITCH_USB_SPEED)
if resp != b"":
status = self.status()
if status == 0:
if self.xsend(pack("<I", 0x0E8D2001)):
status = self.status()
if status == 0:
return True
else:
self.error(f"Error on getting usb speed: {self.eh.status(status)}")
return False
def cmd_write_data(self, addr, size, storage=DaStorage.MTK_DA_STORAGE_EMMC,
parttype=EMMC_PartitionType.MTK_DA_EMMC_PART_USER):
if self.xsend(self.Cmd.WRITE_DATA):
status = self.status()
if status == 0:
# storage: emmc:1,slc,nand,nor,ufs
# section: boot,user of emmc:8, LU1, LU2
ne = NandExtension()
param = pack("<IIQQ", storage, parttype, addr, size)
param += pack("<IIIIIIII", ne.cellusage, ne.addr_type, ne.bin_type, ne.operation_type,
ne.sys_slc_percent, ne.usr_slc_percent, ne.phy_max_size, 0x0)
if self.send_param(param):
return True
else:
self.error(f"Error on writing data: {self.eh.status(status)}")
return False
def cmd_read_data(self, addr, size, storage=DaStorage.MTK_DA_STORAGE_EMMC,
parttype=EMMC_PartitionType.MTK_DA_EMMC_PART_USER):
if self.xsend(self.Cmd.READ_DATA):
status = self.status()
if status == 0:
# storage: emmc:1,slc,nand,nor,ufs
# section: boot,user of emmc:8, LU1, LU2
ne = NandExtension()
param = pack("<IIQQ", storage, parttype, addr, size)
param += pack("<IIIIIIII", ne.cellusage, ne.addr_type, ne.bin_type, ne.operation_type,
ne.sys_slc_percent, ne.usr_slc_percent, ne.phy_max_size, 0x0)
self.send_param(param)
status = self.status()
if status == 0x0:
return True
if status != 0x0:
self.error(f"Error on reading data: {self.eh.status(status)}")
return False
def readflash(self, addr, length, filename, parttype=None, display=True):
global rq
partinfo = self.getstorage(parttype, length)
if not partinfo:
return None
self.mtk.daloader.progress.clear()
storage, parttype, length = partinfo
plen = self.get_packet_length()
bytesread = 0
if self.cmd_read_data(addr=addr, size=length, storage=storage, parttype=parttype):
bytestoread = length
total = length
if filename != "":
worker = Thread(target=writedata, args=(filename, rq), daemon=True)
worker.start()
while bytestoread > 0:
status = self.usbread(4 + 4 + 4)
magic, datatype, slength = unpack("<III", status)
if magic == 0xFEEEEEEF:
resdata = self.usbread(slength)
if slength > 4:
rq.put(resdata)
stmp = pack("<III", self.Cmd.MAGIC, self.DataType.DT_PROTOCOL_FLOW, 4)
data = pack("<I", 0)
self.usbwrite(stmp)
self.usbwrite(data)
bytestoread -= len(resdata)
bytesread += len(resdata)
if display:
self.mtk.daloader.progress.show_progress("Read", bytesread, total, display)
elif slength == 4:
if unpack("<I", resdata)[0] != 0:
break
status = self.usbread(4 + 4 + 4)
magic, datatype, slength = unpack("<III", status)
if magic == 0xFEEEEEEF:
resdata = self.usbread(slength)
if slength == 4:
if unpack("<I", resdata)[0] == 0:
if display:
self.mtk.daloader.progress.show_progress("Read", total, total, display)
rq.put(None)
worker.join(60)
return True
rq.put(None)
worker.join(60)
return False
else:
buffer = bytearray()
while length > 0:
tmp = self.xread()
buffer.extend(tmp)
if self.ack() != 0:
break
if display:
self.mtk.daloader.progress.show_progress("Read", bytesread, total, display)
length -= len(tmp)
bytesread += len(tmp)
if display:
self.mtk.daloader.progress.show_progress("Read", total, total, display)
return buffer
return False
class ShutDownModes:
NORMAL = 0
HOME_SCREEN = 1
FASTBOOT = 2
def shutdown(self, async_mode: int = 0, dl_bit: int = 0, bootmode: ShutDownModes = ShutDownModes.NORMAL):
if self.xsend(self.Cmd.SHUTDOWN):
status = self.status()
if status == 0:
hasflags = 0
# bootmode 0: shutdown 1: home screen, 2: fastboot
if async_mode or dl_bit or bootmode > 0:
hasflags = 1
enablewdt = 0 # Disable wdt
dont_resetrtc = 0 # Reset RTC
leaveusb = 0 # Disconnect usb
if self.xsend(pack("<IIIIIIII", hasflags, enablewdt, async_mode, bootmode, dl_bit,
dont_resetrtc, leaveusb, 0)):
status = self.status()
if status == 0:
self.mtk.port.close(reset=True)
return True
else:
self.error(f"Error on sending shutdown: {self.eh.status(status)}")
self.mtk.port.close(reset=True)
return False
def getstorage(self, parttype, length):
if self.daconfig.flashtype == "nor":
storage = DaStorage.MTK_DA_STORAGE_NOR
elif self.daconfig.flashtype == "nand":
storage = DaStorage.MTK_DA_STORAGE_NAND
elif self.daconfig.flashtype == "ufs":
storage = DaStorage.MTK_DA_STORAGE_UFS
if parttype == EMMC_PartitionType.MTK_DA_EMMC_PART_USER:
parttype = UFS_PartitionType.UFS_LU3
elif self.daconfig.flashtype == "sdc":
storage = DaStorage.MTK_DA_STORAGE_SDMMC
else:
storage = DaStorage.MTK_DA_STORAGE_EMMC
part_info = self.partitiontype_and_size(storage, parttype, length)
return part_info
def writeflash(self, addr, length, filename, offset=0, parttype=None, wdata=None, display=True):
self.mtk.daloader.progress.clear()
fh = None
fill = 0
if filename is not None:
if os.path.exists(filename):
fsize = os.stat(filename).st_size
length = min(fsize, length)
if length % 512 != 0:
fill = 512 - (length % 512)
length += fill
fh = open(filename, "rb")
fh.seek(offset)
else:
self.error(f"Filename doesn't exists: {filename}, aborting flash write.")
return False
partinfo = self.getstorage(parttype, length)
if not partinfo:
return False
storage, parttype, rlength = partinfo
# self.send_devctrl(self.Cmd.START_DL_INFO)
plen = self.get_packet_length()
write_packet_size = plen.write_packet_length
bytestowrite = rlength
if self.cmd_write_data(addr, length, storage, parttype):
try:
pos = 0
while bytestowrite > 0:
if display:
if length > bytestowrite:
rpos = length - bytestowrite
else:
rpos = 0
self.mtk.daloader.progress.show_progress("Write", rpos, length, display)
dsize = min(write_packet_size, bytestowrite)
if fh:
data = bytearray(fh.read(dsize))
if len(data) < dsize:
data.extend(b"\x00" * fill)
else:
data = wdata[pos:pos + dsize]
checksum = sum(data) & 0xFFFF
dparams = [pack("<I", 0x0), pack("<I", checksum), data]
if not self.send_param(dparams):
self.error("Error on writing pos 0x%08X" % pos)
return False
bytestowrite -= dsize
pos += dsize
status = self.status()
if status == 0x0:
self.send_devctrl(self.Cmd.CC_OPTIONAL_DOWNLOAD_ACT)
self.mtk.daloader.progress.show_progress("Write", length, length, display)
if fh:
fh.close()
return True
else:
self.error(f"Error on writeflash: {self.eh.status(status)}")
except Exception as e:
self.error(str(e))
if fh:
fh.close()
return False
if fh:
fh.close()
return False
def sync(self):
if self.xsend(self.Cmd.SYNC_SIGNAL):
return True
return False
def setup_env(self):
if self.xsend(self.Cmd.SETUP_ENVIRONMENT):
da_log_level = 2
log_channel = 1
system_os = self.FtSystemOSE.OS_LINUX
ufs_provision = 0x0
param = pack("<IIIII", da_log_level, log_channel, system_os, ufs_provision, 0x1)
if self.send_param(param):
return True
return False
def setup_hw_init(self):
if self.xsend(self.Cmd.SETUP_HW_INIT_PARAMS):
param = pack("<I", 0x0) # No config
if self.send_param(param):
return True
return False
def upload(self):
if self.daconfig.da_loader is None:
self.error("No valid da loader found... aborting.")
return False
loader = self.daconfig.loader
self.info(f"Uploading xflash stage 1 from {os.path.basename(loader)}")
if not os.path.exists(loader):
self.info(f"Couldn't find {loader}, aborting.")
return False
with open(loader, 'rb') as bootldr:
# stage 1
da1offset = self.daconfig.da_loader.region[1].m_buf
da1size = self.daconfig.da_loader.region[1].m_len
da1address = self.daconfig.da_loader.region[1].m_start_addr
da2address = self.daconfig.da_loader.region[1].m_start_addr
da1sig_len = self.daconfig.da_loader.region[1].m_sig_len
bootldr.seek(da1offset)
da1 = bootldr.read(da1size)
# ------------------------------------------------
da2offset = self.daconfig.da_loader.region[2].m_buf
da2sig_len = self.daconfig.da_loader.region[2].m_sig_len
bootldr.seek(da2offset)
da2 = bootldr.read(self.daconfig.da_loader.region[2].m_len)
hashaddr, hashmode, hashlen = self.mtk.daloader.compute_hash_pos(da1, da2, da2sig_len)
if hashaddr is not None:
da1 = self.xft.patch_da1(da1)
da2 = self.xft.patch_da2(da2)
da1 = self.mtk.daloader.fix_hash(da1, da2, hashaddr, hashmode, hashlen)
self.patch = True
self.daconfig.da2 = da2[:hashlen]
else:
self.daconfig.da2 = da2[:-da2sig_len]
if self.mtk.preloader.send_da(da1address, da1size, da1sig_len, da1):
self.info("Successfully uploaded stage 1, jumping ..")
if self.mtk.preloader.jump_da(da1address):
sync = self.usbread(1)
if sync != b"\xC0":
self.error("Error on DA sync")
return False
else:
self.sync()
self.setup_env()
self.setup_hw_init()
res = self.xread()
if res == pack("<I", self.Cmd.SYNC_SIGNAL):
self.info("Successfully received DA sync")
return True
else:
self.error(f"Error jumping to DA: {res}")
else:
self.error("Error on jumping to DA.")
else:
self.error("Error on sending DA.")
return False
def reinit(self, display=False):
self.config.hwparam = hwparam(self.config.meid, self.config.hwparam_path)
self.config.sram, self.config.dram = self.get_ram_info()
self.emmc = self.get_emmc_info(display)
self.nand = self.get_nand_info(display)
self.nor = self.get_nor_info(display)
self.ufs = self.get_ufs_info(display)
if self.emmc is not None and self.emmc.type != 0:
self.daconfig.flashtype = "emmc"
self.daconfig.flashsize = self.emmc.user_size
self.daconfig.rpmbsize = self.emmc.rpmb_size
self.daconfig.boot1size = self.emmc.boot1_size
self.daconfig.boot2size = self.emmc.boot2_size
elif self.nand is not None and self.nand.type != 0:
self.daconfig.flashtype = "nand"
self.daconfig.flashsize = self.nand.total_size
self.daconfig.rpmbsize = 0
self.daconfig.boot1size = 0x400000
self.daconfig.boot2size = 0x400000
elif self.nor is not None and self.nor.type != 0:
self.daconfig.flashtype = "nor"
self.daconfig.flashsize = self.nor.available_size
self.daconfig.rpmbsize = 0
self.daconfig.boot1size = 0x400000
self.daconfig.boot2size = 0x400000
elif self.ufs is not None and self.ufs.type != 0:
self.daconfig.flashtype = "ufs"
self.daconfig.flashsize = self.ufs.lu0_size
self.daconfig.rpmbsize = self.ufs.lu1_size
self.daconfig.boot1size = self.ufs.lu1_size
self.daconfig.boot2size = self.ufs.lu2_size
self.chipid = self.get_chip_id()
self.daversion = self.get_da_version()
self.randomid = self.get_random_id()
speed = self.get_usb_speed()
if speed == b"full-speed":
self.info("Reconnecting to preloader")
self.config.set_gui_status(self.config.tr("Reconnecting to preloader"))
self.set_usb_speed()
self.mtk.port.close(reset=False)
time.sleep(2)
while not self.mtk.port.cdc.connect():
time.sleep(0.5)
self.info("Connected to preloader")
self.mtk.port.cdc.set_fast_mode(True)
self.config.set_gui_status(self.config.tr("Connected to preloader"))
def upload_da(self):
if self.upload():
self.get_expire_date()
self.set_reset_key(0x68)
# self.set_battery_opt(0x2)
self.set_checksum_level(0x0)
connagent = self.get_connection_agent()
emmc_info = self.get_emmc_info(False)
if emmc_info is not None and emmc_info.user_size != 0:
self.info("DRAM config needed for : " + hexlify(emmc_info.cid[:8]).decode('utf-8'))
else:
ufs_info = self.get_ufs_info()
if ufs_info is not None and ufs_info.block_size != 0:
self.info("DRAM config needed for : " + hexlify(ufs_info.cid).decode('utf-8'))
# dev_fw_info=self.get_dev_fw_info()
# dramtype = self.get_dram_type()
stage = None
if connagent == b"brom":
stage = 1
if self.daconfig.emi is None:
self.info("No preloader given. Searching for preloader")
found = False
self.info("Sending emi data ...")
for root, dirs, files in os.walk(os.path.join(self.pathconfig.get_loader_path(), 'Preloader')):
for file in files:
with open(os.path.join(root, file), "rb") as rf:
data = rf.read()
if emmc_info is not None:
# if emmc_info.cid[:8] in data:
if True:
preloader = os.path.join(root, file)
self.daconfig.extract_emi(preloader)
if not self.send_emi(self.daconfig.emi):
continue
else:
found = True
self.info("Detected working preloader: " + preloader)
break
else:
self.warning("No emmc info, can't parse existing preloaders.")
if found:
break
if not found:
self.warning("No preloader given. Operation may fail due to missing dram setup.")
else:
self.info("Sending emi data ...")
if not self.send_emi(self.daconfig.emi):
return False
else:
self.info("Sending emi data succeeded.")
elif connagent == b"preloader":
stage = 1
if stage == 1:
self.info("Uploading stage 2...")
with open(self.daconfig.loader, 'rb') as bootldr:
stage = stage + 1
loaded = self.boot_to(self.daconfig.da_loader.region[stage].m_start_addr, self.daconfig.da2)
if loaded:
self.info("Successfully uploaded stage 2")
self.reinit(True)
self.config.hwparam.writesetting("hwcode", hex(self.config.hwcode))
daextdata = self.xft.patch()
if daextdata is not None:
self.daext = False
if self.boot_to(at_address=0x68000000, da=daextdata):
ret = self.send_devctrl(XCmd.CUSTOM_ACK)
status = self.status()
if status == 0x0 and unpack("<I", ret)[0] == 0xA1A2A3A4:
self.info("DA Extensions successfully added")
self.daext = True
if not self.daext:
self.warning("DA Extensions failed to enable")
if self.generatekeys:
self.xft.generate_keys()
return True
else:
self.error("Error on booting to da (xflash)")
return False
else:
self.error("Didn't get brom connection, got instead: " + hexlify(connagent).decode('utf-8'))
return False
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment