mirror of
https://github.com/espressif/esptool.git
synced 2025-10-20 22:09:59 +08:00
fix: enable ESP32-P4 ECO5 chip detection
Register was read in order to detect SDM, this cannot be done with new ESP32-P4 ECO5, because it has different address space and crashes when trying to read current magic address. This also improves detection for ESP32-S2 as is is only chip that has SDM support and is detected by reading magic address.
This commit is contained in:

committed by
Radim Karniš

parent
9cb4e7de81
commit
0b3460fa12
@@ -150,21 +150,16 @@ def detect_chip(
|
||||
continue
|
||||
if chip_id == cls.IMAGE_CHIP_ID:
|
||||
inst = cls(detect_port._port, baud, trace_enabled=trace_enabled)
|
||||
try:
|
||||
inst.read_reg(
|
||||
ESPLoader.CHIP_DETECT_MAGIC_REG_ADDR
|
||||
) # Dummy read to check Secure Download mode
|
||||
except UnsupportedCommandError:
|
||||
inst.secure_download_mode = True
|
||||
si = inst.get_security_info()
|
||||
inst.secure_download_mode = si["parsed_flags"]["SECURE_DOWNLOAD_ENABLE"]
|
||||
inst = check_if_stub(inst)
|
||||
inst._post_connect()
|
||||
break
|
||||
else:
|
||||
err_msg = f"Unexpected chip ID value {chip_id}."
|
||||
except (UnsupportedCommandError, struct.error, FatalError):
|
||||
except (UnsupportedCommandError, FatalError):
|
||||
# UnsupportedCommandError: ESP8266/ESP32 ROM
|
||||
# struct.error: ESP32-S2
|
||||
# FatalError: ESP8266/ESP32 STUB
|
||||
# FatalError: ESP8266/ESP32 STUB or ESP32-S2
|
||||
try:
|
||||
chip_magic_value = detect_port.read_reg(
|
||||
ESPLoader.CHIP_DETECT_MAGIC_REG_ADDR
|
||||
@@ -1495,30 +1490,9 @@ def get_security_info(esp: ESPLoader) -> None:
|
||||
Args:
|
||||
esp: Initiated esp object connected to a real device.
|
||||
"""
|
||||
# The following mapping was taken from the ROM code
|
||||
# This mapping is same across all targets in the ROM
|
||||
SECURITY_INFO_FLAG_MAP = {
|
||||
"SECURE_BOOT_EN": (1 << 0),
|
||||
"SECURE_BOOT_AGGRESSIVE_REVOKE": (1 << 1),
|
||||
"SECURE_DOWNLOAD_ENABLE": (1 << 2),
|
||||
"SECURE_BOOT_KEY_REVOKE0": (1 << 3),
|
||||
"SECURE_BOOT_KEY_REVOKE1": (1 << 4),
|
||||
"SECURE_BOOT_KEY_REVOKE2": (1 << 5),
|
||||
"SOFT_DIS_JTAG": (1 << 6),
|
||||
"HARD_DIS_JTAG": (1 << 7),
|
||||
"DIS_USB": (1 << 8),
|
||||
"DIS_DOWNLOAD_DCACHE": (1 << 9),
|
||||
"DIS_DOWNLOAD_ICACHE": (1 << 10),
|
||||
}
|
||||
|
||||
# Get the status of respective security flag
|
||||
def get_security_flag_status(flag_name, flags_value):
|
||||
try:
|
||||
return (flags_value & SECURITY_INFO_FLAG_MAP[flag_name]) != 0
|
||||
except KeyError:
|
||||
raise ValueError(f"Invalid flag name: {flag_name}")
|
||||
|
||||
si = esp.get_security_info()
|
||||
parsed_flags = si["parsed_flags"]
|
||||
|
||||
title = "Security Information:"
|
||||
log.print(title)
|
||||
log.print("=" * len(title))
|
||||
@@ -1537,11 +1511,9 @@ def get_security_info(esp: ESPLoader) -> None:
|
||||
log.print("Chip ID: {}".format(si["chip_id"]))
|
||||
log.print("API Version: {}".format(si["api_version"]))
|
||||
|
||||
flags = si["flags"]
|
||||
|
||||
if get_security_flag_status("SECURE_BOOT_EN", flags):
|
||||
if parsed_flags["SECURE_BOOT_EN"]:
|
||||
log.print("Secure Boot: Enabled")
|
||||
if get_security_flag_status("SECURE_BOOT_AGGRESSIVE_REVOKE", flags):
|
||||
if parsed_flags["SECURE_BOOT_AGGRESSIVE_REVOKE"]:
|
||||
log.print("Secure Boot Aggressive key revocation: Enabled")
|
||||
|
||||
revoked_keys = []
|
||||
@@ -1552,7 +1524,7 @@ def get_security_info(esp: ESPLoader) -> None:
|
||||
"SECURE_BOOT_KEY_REVOKE2",
|
||||
]
|
||||
):
|
||||
if get_security_flag_status(key, flags):
|
||||
if parsed_flags[key]:
|
||||
revoked_keys.append(i)
|
||||
|
||||
if len(revoked_keys) > 0:
|
||||
@@ -1575,19 +1547,19 @@ def get_security_info(esp: ESPLoader) -> None:
|
||||
|
||||
log.print(f"{CRYPT_CNT_STRING}: {si['flash_crypt_cnt']:#x}")
|
||||
|
||||
if get_security_flag_status("DIS_DOWNLOAD_DCACHE", flags):
|
||||
if parsed_flags["DIS_DOWNLOAD_DCACHE"]:
|
||||
log.print("Dcache in UART download mode: Disabled")
|
||||
|
||||
if get_security_flag_status("DIS_DOWNLOAD_ICACHE", flags):
|
||||
if parsed_flags["DIS_DOWNLOAD_ICACHE"]:
|
||||
log.print("Icache in UART download mode: Disabled")
|
||||
|
||||
hard_dis_jtag = get_security_flag_status("HARD_DIS_JTAG", flags)
|
||||
soft_dis_jtag = get_security_flag_status("SOFT_DIS_JTAG", flags)
|
||||
hard_dis_jtag = parsed_flags["HARD_DIS_JTAG"]
|
||||
soft_dis_jtag = parsed_flags["SOFT_DIS_JTAG"]
|
||||
if hard_dis_jtag:
|
||||
log.print("JTAG: Permanently Disabled")
|
||||
elif soft_dis_jtag:
|
||||
log.print("JTAG: Software Access Disabled")
|
||||
if get_security_flag_status("DIS_USB", flags):
|
||||
if parsed_flags["DIS_USB"]:
|
||||
log.print("USB Access: Disabled")
|
||||
|
||||
|
||||
|
@@ -292,7 +292,7 @@ class ESPLoader(object):
|
||||
IROM_MAP_END = 0x40300000
|
||||
|
||||
# The number of bytes in the UART response that signify command status
|
||||
STATUS_BYTES_LENGTH = 2
|
||||
STATUS_BYTES_LENGTH = 4
|
||||
|
||||
# Bootloader flashing offset
|
||||
BOOTLOADER_FLASH_OFFSET = 0x0
|
||||
@@ -345,9 +345,9 @@ class ESPLoader(object):
|
||||
# Device-and-runtime-specific cache
|
||||
self.cache = {
|
||||
"flash_id": None,
|
||||
"chip_id": None,
|
||||
"uart_no": None,
|
||||
"usb_pid": None,
|
||||
"security_info": None,
|
||||
}
|
||||
|
||||
if isinstance(port, str):
|
||||
@@ -773,17 +773,26 @@ class ESPLoader(object):
|
||||
if not detecting:
|
||||
from .targets import ROM_LIST
|
||||
|
||||
# Perform a dummy read_reg to check if the chip is in secure download mode
|
||||
try:
|
||||
chip_magic_value = self.read_reg(ESPLoader.CHIP_DETECT_MAGIC_REG_ADDR)
|
||||
except UnsupportedCommandError:
|
||||
self.secure_download_mode = True
|
||||
|
||||
# Check if chip supports reading chip ID from the get-security-info command
|
||||
try:
|
||||
# get_chip_id() raises FatalError if the chip does not have a chip ID
|
||||
# (ESP32-S2)
|
||||
chip_id = self.get_chip_id()
|
||||
except (UnsupportedCommandError, struct.error, FatalError):
|
||||
si = self.get_security_info()
|
||||
self.secure_download_mode = si["parsed_flags"]["SECURE_DOWNLOAD_ENABLE"]
|
||||
except (UnsupportedCommandError, FatalError):
|
||||
chip_id = None
|
||||
# Try to read the chip magic value to verify the chip type
|
||||
# (ESP8266, ESP32, ESP32-S2)
|
||||
try:
|
||||
chip_magic_value = self.read_reg(
|
||||
ESPLoader.CHIP_DETECT_MAGIC_REG_ADDR
|
||||
)
|
||||
except UnsupportedCommandError:
|
||||
# If the chip does not support reading the chip magic value,
|
||||
# it is ESP32-S2 in SDM
|
||||
chip_magic_value = None
|
||||
self.secure_download_mode = True
|
||||
|
||||
detected = None
|
||||
chip_arg_wrong = False
|
||||
@@ -807,18 +816,14 @@ class ESPLoader(object):
|
||||
if cls.USES_MAGIC_VALUE and chip_magic_value == cls.MAGIC_VALUE:
|
||||
detected = cls
|
||||
break
|
||||
# If we can't read chip ID and the chip is in SDM (ESP32 or ESP32-S2),
|
||||
# we can't verify
|
||||
elif not chip_id and self.secure_download_mode:
|
||||
if self.CHIP_NAME not in ["ESP32", "ESP32-S2"]:
|
||||
chip_arg_wrong = True
|
||||
detected = "ESP32 or ESP32-S2"
|
||||
else:
|
||||
log.note(
|
||||
f"Can't verify this chip is {self.CHIP_NAME} "
|
||||
"because of active Secure Download Mode. "
|
||||
"Please check it manually."
|
||||
)
|
||||
# If we can't read chip ID and the chip is in SDM, it is ESP32-S2
|
||||
elif (
|
||||
not chip_id
|
||||
and self.secure_download_mode
|
||||
and self.CHIP_NAME != "ESP32-S2"
|
||||
):
|
||||
chip_arg_wrong = True
|
||||
detected = "ESP32-S2"
|
||||
|
||||
if chip_arg_wrong:
|
||||
if warnings and detected is None:
|
||||
@@ -1051,30 +1056,76 @@ class ESPLoader(object):
|
||||
"""Read flash type bit field from eFuse. Returns 0, 1, None (not present)"""
|
||||
return None # not implemented for all chip targets
|
||||
|
||||
def get_security_info(self):
|
||||
def get_security_info(self, cache=True):
|
||||
"""
|
||||
Get security information from the ESP device including flags,
|
||||
flash encryption count,
|
||||
key purposes, chip ID, and API version.
|
||||
|
||||
The security info command response format according to the ESP32-S3
|
||||
documentation:
|
||||
- 32 bits flags
|
||||
- 1 byte flash_crypt_cnt
|
||||
- 7x1 byte key_purposes
|
||||
- 32-bit word chip_id (ESP32-S3 and later)
|
||||
- 32-bit word eco_version/api_version (ESP32-S3 and later)
|
||||
|
||||
Returns a dictionary with parsed security information and individual
|
||||
flag status.
|
||||
"""
|
||||
if cache and self.cache["security_info"] is not None:
|
||||
return self.cache["security_info"]
|
||||
|
||||
# The following mapping was taken from the ROM code
|
||||
# This mapping is same across all targets in the ROM
|
||||
SECURITY_INFO_FLAG_MAP = {
|
||||
"SECURE_BOOT_EN": (1 << 0),
|
||||
"SECURE_BOOT_AGGRESSIVE_REVOKE": (1 << 1),
|
||||
"SECURE_DOWNLOAD_ENABLE": (1 << 2),
|
||||
"SECURE_BOOT_KEY_REVOKE0": (1 << 3),
|
||||
"SECURE_BOOT_KEY_REVOKE1": (1 << 4),
|
||||
"SECURE_BOOT_KEY_REVOKE2": (1 << 5),
|
||||
"SOFT_DIS_JTAG": (1 << 6),
|
||||
"HARD_DIS_JTAG": (1 << 7),
|
||||
"DIS_USB": (1 << 8),
|
||||
"DIS_DOWNLOAD_DCACHE": (1 << 9),
|
||||
"DIS_DOWNLOAD_ICACHE": (1 << 10),
|
||||
}
|
||||
|
||||
def parse_security_flags(flags_value):
|
||||
"""Parse security flags into individual boolean values"""
|
||||
parsed_flags = {}
|
||||
for flag_name, flag_mask in SECURITY_INFO_FLAG_MAP.items():
|
||||
parsed_flags[flag_name] = (flags_value & flag_mask) != 0
|
||||
return parsed_flags
|
||||
|
||||
res = self.check_command(
|
||||
"get security info", self.ESP_CMDS["GET_SECURITY_INFO"], b""
|
||||
)
|
||||
esp32s2 = True if len(res) == 12 else False
|
||||
res = struct.unpack("<IBBBBBBBB" if esp32s2 else "<IBBBBBBBBII", res)
|
||||
return {
|
||||
|
||||
security_info = {
|
||||
"flags": res[0],
|
||||
"flash_crypt_cnt": res[1],
|
||||
"key_purposes": res[2:9],
|
||||
"chip_id": None if esp32s2 else res[9],
|
||||
"api_version": None if esp32s2 else res[10],
|
||||
"parsed_flags": parse_security_flags(res[0]),
|
||||
}
|
||||
|
||||
self.cache["security_info"] = security_info
|
||||
return security_info
|
||||
|
||||
def get_chip_id(self):
|
||||
if self.cache["chip_id"] is None:
|
||||
res = self.check_command(
|
||||
"get security info", self.ESP_CMDS["GET_SECURITY_INFO"], b""
|
||||
chip_id = self.get_security_info()["chip_id"]
|
||||
if chip_id is None:
|
||||
raise FatalError(
|
||||
"Security info command does not contain chip ID. "
|
||||
"This is expected for ESP32-S2 which doesn't support chip ID "
|
||||
"in security info."
|
||||
)
|
||||
res = struct.unpack(
|
||||
"<IBBBBBBBBI", res[:16]
|
||||
) # 4b flags, 1b flash_crypt_cnt, 7*1b key_purposes, 4b chip_id
|
||||
self.cache["chip_id"] = res[9] # 2/4 status bytes invariant
|
||||
return self.cache["chip_id"]
|
||||
return chip_id
|
||||
|
||||
def get_uart_no(self):
|
||||
"""
|
||||
|
@@ -29,6 +29,8 @@ class ESP8266ROM(ESPLoader):
|
||||
|
||||
UART_CLKDIV_REG = 0x60000014
|
||||
|
||||
STATUS_BYTES_LENGTH = 2
|
||||
|
||||
XTAL_CLK_DIVIDER = 2
|
||||
|
||||
FLASH_SIZES = {
|
||||
|
Reference in New Issue
Block a user