Skip to content

Commit

Permalink
Scripts: OB recovery (#2964)
Browse files Browse the repository at this point in the history
* Scripts: OB recovery
* Scripts: slightly different ob
* Scripts: remove excessive return
* Scripts: simplifying work with registers
* Make PVS happy

Co-authored-by: SG <[email protected]>
  • Loading branch information
skotopes and DrZlo13 authored Aug 10, 2023
1 parent c976ff1 commit 2702c00
Show file tree
Hide file tree
Showing 6 changed files with 149 additions and 86 deletions.
4 changes: 2 additions & 2 deletions firmware/targets/f7/furi_hal/furi_hal_crypto.c
Original file line number Diff line number Diff line change
Expand Up @@ -500,7 +500,7 @@ bool furi_hal_crypto_ctr(
size_t length) {
/* prepare IV and counter */
uint8_t iv_and_counter[CRYPTO_CTR_IV_LEN + CRYPTO_CTR_CTR_LEN];
memcpy(iv_and_counter, iv, CRYPTO_CTR_IV_LEN);
memcpy(iv_and_counter, iv, CRYPTO_CTR_IV_LEN); //-V1086
furi_hal_crypto_ctr_prep_iv(iv_and_counter);

/* load key and IV and set the mode to CTR */
Expand Down Expand Up @@ -648,7 +648,7 @@ bool furi_hal_crypto_gcm(

/* prepare IV and counter */
uint8_t iv_and_counter[CRYPTO_GCM_IV_LEN + CRYPTO_GCM_CTR_LEN];
memcpy(iv_and_counter, iv, CRYPTO_GCM_IV_LEN);
memcpy(iv_and_counter, iv, CRYPTO_GCM_IV_LEN); //-V1086
furi_hal_crypto_gcm_prep_iv(iv_and_counter);

/* load key and IV and set the mode to CTR */
Expand Down
4 changes: 4 additions & 0 deletions scripts/flipper/utils/programmer.py
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,10 @@ def option_bytes_validate(self, file_path: str) -> bool:
def option_bytes_set(self, file_path: str) -> bool:
pass

@abstractmethod
def option_bytes_recover(self) -> bool:
pass

@abstractmethod
def otp_write(self, address: int, file_path: str) -> bool:
pass
55 changes: 32 additions & 23 deletions scripts/flipper/utils/programmer_openocd.py
Original file line number Diff line number Diff line change
Expand Up @@ -44,11 +44,11 @@ def __init__(
self.logger = logging.getLogger()

def reset(self, mode: Programmer.RunMode = Programmer.RunMode.Run) -> bool:
stm32 = STM32WB55()
stm32 = STM32WB55(self.openocd)
if mode == Programmer.RunMode.Run:
stm32.reset(self.openocd, stm32.RunMode.Run)
stm32.reset(stm32.RunMode.Run)
elif mode == Programmer.RunMode.Stop:
stm32.reset(self.openocd, stm32.RunMode.Init)
stm32.reset(stm32.RunMode.Init)
else:
raise Exception("Unknown mode")

Expand Down Expand Up @@ -96,11 +96,11 @@ def _ob_print_diff_table(self, ob_reference: bytes, ob_read: bytes, print_fn):

def option_bytes_validate(self, file_path: str) -> bool:
# Registers
stm32 = STM32WB55()
stm32 = STM32WB55(self.openocd)

# OpenOCD
self.openocd.start()
stm32.reset(self.openocd, stm32.RunMode.Init)
stm32.reset(stm32.RunMode.Init)

# Generate Option Bytes data
ob_data = OptionBytesData(file_path)
Expand Down Expand Up @@ -133,7 +133,7 @@ def option_bytes_validate(self, file_path: str) -> bool:
self._ob_print_diff_table(ob_reference, ob_compare, self.logger.error)

# Stop OpenOCD
stm32.reset(self.openocd, stm32.RunMode.Run)
stm32.reset(stm32.RunMode.Run)
self.openocd.stop()

return return_code
Expand All @@ -143,11 +143,11 @@ def _unpack_u32(self, data: bytes, offset: int):

def option_bytes_set(self, file_path: str) -> bool:
# Registers
stm32 = STM32WB55()
stm32 = STM32WB55(self.openocd)

# OpenOCD
self.openocd.start()
stm32.reset(self.openocd, stm32.RunMode.Init)
stm32.reset(stm32.RunMode.Init)

# Generate Option Bytes data
ob_data = OptionBytesData(file_path)
Expand All @@ -159,11 +159,11 @@ def option_bytes_set(self, file_path: str) -> bool:
ob_dwords = int(ob_length / 8)

# Clear flash errors
stm32.clear_flash_errors(self.openocd)
stm32.clear_flash_errors()

# Unlock Flash and Option Bytes
stm32.flash_unlock(self.openocd)
stm32.option_bytes_unlock(self.openocd)
stm32.flash_unlock()
stm32.option_bytes_unlock()

ob_need_to_apply = False

Expand Down Expand Up @@ -194,16 +194,16 @@ def option_bytes_set(self, file_path: str) -> bool:
self.openocd.write_32(device_reg_addr, ob_value)

if ob_need_to_apply:
stm32.option_bytes_apply(self.openocd)
stm32.option_bytes_apply()
else:
self.logger.info("Option Bytes are already correct")

# Load Option Bytes
# That will reset and also lock the Option Bytes and the Flash
stm32.option_bytes_load(self.openocd)
stm32.option_bytes_load()

# Stop OpenOCD
stm32.reset(self.openocd, stm32.RunMode.Run)
stm32.reset(stm32.RunMode.Run)
self.openocd.stop()

return True
Expand Down Expand Up @@ -233,19 +233,18 @@ def otp_write(self, address: int, file_path: str) -> OpenOCDProgrammerResult:
self.logger.debug(f"Data: {data.hex().upper()}")

# Start OpenOCD
oocd = self.openocd
oocd.start()
self.openocd.start()

# Registers
stm32 = STM32WB55()
stm32 = STM32WB55(self.openocd)

try:
# Check that OTP is empty for the given address
# Also check that data is already written
already_written = True
for i in range(0, data_size, 4):
file_word = int.from_bytes(data[i : i + 4], "little")
device_word = oocd.read_32(address + i)
device_word = self.openocd.read_32(address + i)
if device_word != 0xFFFFFFFF and device_word != file_word:
self.logger.error(
f"OTP memory at {address + i:08X} is not empty: {device_word:08X}"
Expand All @@ -260,7 +259,7 @@ def otp_write(self, address: int, file_path: str) -> OpenOCDProgrammerResult:
return OpenOCDProgrammerResult.Success

self.reset(self.RunMode.Stop)
stm32.clear_flash_errors(oocd)
stm32.clear_flash_errors()

# Write OTP memory by 8 bytes
for i in range(0, data_size, 8):
Expand All @@ -269,26 +268,36 @@ def otp_write(self, address: int, file_path: str) -> OpenOCDProgrammerResult:
self.logger.debug(
f"Writing {word_1:08X} {word_2:08X} to {address + i:08X}"
)
stm32.write_flash_64(oocd, address + i, word_1, word_2)
stm32.write_flash_64(address + i, word_1, word_2)

# Validate OTP memory
validation_result = True

for i in range(0, data_size, 4):
file_word = int.from_bytes(data[i : i + 4], "little")
device_word = oocd.read_32(address + i)
device_word = self.openocd.read_32(address + i)
if file_word != device_word:
self.logger.error(
f"Validation failed: {file_word:08X} != {device_word:08X} at {address + i:08X}"
)
validation_result = False
finally:
# Stop OpenOCD
stm32.reset(oocd, stm32.RunMode.Run)
oocd.stop()
stm32.reset(stm32.RunMode.Run)
self.openocd.stop()

return (
OpenOCDProgrammerResult.Success
if validation_result
else OpenOCDProgrammerResult.ErrorValidation
)

def option_bytes_recover(self) -> bool:
try:
self.openocd.start()
stm32 = STM32WB55(self.openocd)
stm32.reset(stm32.RunMode.Halt)
stm32.option_bytes_recover()
return True
finally:
self.openocd.stop()
17 changes: 13 additions & 4 deletions scripts/flipper/utils/register.py
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ def __init__(self, address: int, definition_list: list[RegisterBitDefinition]):
self.names = [definition.name for definition in definition_list] # typecheck
self.address = address
self.definition_list = definition_list
self.openocd = None

# Validate that the definitions are not overlapping
for i in range(len(definition_list)):
Expand Down Expand Up @@ -76,6 +77,14 @@ def __setattr__(self, attr, value):
def __dir__(self):
return self.names

def set_openocd(self, openocd: OpenOCD):
self.openocd = openocd

def get_openocd(self) -> OpenOCD:
if self.openocd is None:
raise RuntimeError("OpenOCD is not installed")
return self.openocd

def set(self, value: int):
for definition in self.definition_list:
definition.value = (value >> definition.offset) & (
Expand All @@ -88,8 +97,8 @@ def get(self) -> int:
value |= definition.value << definition.offset
return value

def load(self, openocd: OpenOCD):
self.set(openocd.read_32(self.address))
def load(self):
self.set(self.get_openocd().read_32(self.address))

def store(self, openocd: OpenOCD):
openocd.write_32(self.address, self.get())
def store(self):
self.get_openocd().write_32(self.address, self.get())
Loading

0 comments on commit 2702c00

Please sign in to comment.