Skip to content

Commit

Permalink
[realtek-ambz2] Implement OTA
Browse files Browse the repository at this point in the history
  • Loading branch information
prokoma committed Dec 17, 2024
1 parent 3d23211 commit 7082519
Show file tree
Hide file tree
Showing 3 changed files with 136 additions and 7 deletions.
27 changes: 24 additions & 3 deletions builder/family/realtek-ambz2.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
from os.path import isfile, join
from shutil import copyfile

from ltchiptool.soc.ambz2.util.models.config import ImageConfig
from platformio.platform.base import PlatformBase
from platformio.platform.board import PlatformBoardConfig
from SCons.Script import DefaultEnvironment, Environment
Expand All @@ -15,6 +16,22 @@

COMPONENT_DIR = join("$SDK_DIR", "component")


# Get image decryption public key
def get_public_key(private: bytes) -> bytes:
from ltchiptool.util.curve25519 import X25519PrivateKey

key = X25519PrivateKey.from_private_bytes(private)
return key.public_key()


def encode_for_define(data: bytes) -> str:
# we need to escape both shell and the C string
return '\\"' + "".join(f"\\\\x{byte:02x}" for byte in data) + '\\"'


public_key_bytes = get_public_key(ImageConfig(**board.get("image")).keys.decryption)

# Flags
queue.AppendPublic(
CCFLAGS=[
Expand All @@ -39,6 +56,7 @@
("__ARM_ARCH_8M_MAIN__", "1"),
("CONFIG_BUILD_RAM", "1"),
"V8M_STKOVF",
("IMAGE_PUBLIC_KEY", encode_for_define(public_key_bytes)),
],
CPPPATH=[
# allow including <ctype.h> from GCC instead of RTL SDK
Expand Down Expand Up @@ -419,17 +437,20 @@
image_part_table = "${BUILD_DIR}/image_part_table.${FLASH_PART_TABLE_OFFSET}.bin"
image_bootloader = "${BUILD_DIR}/image_bootloader.${FLASH_BOOT_OFFSET}.bin"
image_firmware_is = "${BUILD_DIR}/image_firmware_is.${FLASH_OTA1_OFFSET}.bin"
image_firmware_is_ota = "${BUILD_DIR}/image_firmware_is_ota.${FLASH_OTA1_OFFSET}.bin"
env.Replace(
# linker command (dual .bin outputs)
LINK='${LTCHIPTOOL} link2bin ${BOARD_JSON} "" ""',
# UF2OTA input list
UF2OTA=[
# same OTA images for flasher and device
f"{image_firmware_is},{image_firmware_is}=device:ota1,ota2;flasher:ota1,ota2",
# use unmodified image for flasher
f"{image_firmware_is},{image_firmware_is}=flasher:ota1,ota2",
# use patched OTA image for device
f"{image_firmware_is_ota},{image_firmware_is_ota}=device:ota1,ota2",
# having flashed an application image, update the bootloader and partition table (incl. keys)
f"{image_bootloader},{image_bootloader}=flasher:boot,boot",
f"{image_part_table},{image_part_table}=flasher:part_table,part_table",
# clearing headers of the "other" OTA image (hence the indexes are swapped)
f"{image_ota_clear},{image_ota_clear}=device:ota2,ota1;flasher:ota2,ota1",
f"{image_ota_clear},{image_ota_clear}=flasher:ota2,ota1",
],
)
115 changes: 111 additions & 4 deletions cores/realtek-ambz2/base/api/lt_ota.c
Original file line number Diff line number Diff line change
Expand Up @@ -2,23 +2,130 @@

#include <libretiny.h>
#include <sdk_private.h>
#include <osdep_service.h>
#include <device_lock.h>

// from SDK
extern uint32_t sys_update_ota_get_curr_fw_idx(void);

#define FLASH_SECTOR_SIZE 0x1000
// IMAGE_PUBLIC_KEY is defined by the build script
#define IMAGE_PUBLIC_KEY_OFFSET 32
#define IMAGE_PUBLIC_KEY_LENGTH 32

typedef enum {
INVALID = 0,
DISABLED = 1,
ENABLED = 2,
} lt_ota_image_state_t;

static bool lt_ota_get_image_offset(uint8_t index, uint32_t *offset) {
switch (index) {
case 1:
*offset = FLASH_OTA1_OFFSET;
break;
case 2:
*offset = FLASH_OTA2_OFFSET;
break;
default:
return false;
}
return true;
}

static uint8_t lt_ota_get_other_index(uint8_t index) {
return index ^ 0b11; // 1 -> 2, 2 -> 1
}

static lt_ota_image_state_t lt_ota_get_image_state(uint8_t index) {
uint32_t offset;
if (!lt_ota_get_image_offset(index, &offset))
return INVALID;

uint8_t public_key[IMAGE_PUBLIC_KEY_LENGTH];
uint32_t num_read = lt_flash_read(offset + IMAGE_PUBLIC_KEY_OFFSET, public_key, sizeof(public_key));
if (num_read != sizeof(public_key))
return INVALID;

if (memcmp(public_key, IMAGE_PUBLIC_KEY, sizeof(public_key)) == 0)
return ENABLED;

public_key[0] = ~(public_key[0]);
if (memcmp(public_key, IMAGE_PUBLIC_KEY, sizeof(public_key)) == 0)
return DISABLED;

return INVALID;
}

static bool lt_ota_set_image_enabled(uint8_t index, bool new_enabled) {
uint32_t offset;
if (!lt_ota_get_image_offset(index, &offset))
return false;

_irqL irqL;
uint8_t *header = (uint8_t *)malloc(FLASH_SECTOR_SIZE);

rtw_enter_critical(NULL, &irqL);
device_mutex_lock(RT_DEV_LOCK_FLASH);
flash_stream_read(&lt_flash_obj, offset, FLASH_SECTOR_SIZE, header);

bool enabled = header[IMAGE_PUBLIC_KEY_OFFSET] == IMAGE_PUBLIC_KEY[0];
if (enabled != new_enabled) {
// negate first byte of OTA signature
header[0] = ~(header[0]);
// negate first byte of public key
header[IMAGE_PUBLIC_KEY_OFFSET] = ~(header[IMAGE_PUBLIC_KEY_OFFSET]);

// write to flash
hal_flash_sector_erase(lt_flash_obj.phal_spic_adaptor, offset);
hal_flash_burst_write(lt_flash_obj.phal_spic_adaptor, FLASH_SECTOR_SIZE, offset, header);
}

device_mutex_unlock(RT_DEV_LOCK_FLASH);
rtw_exit_critical(NULL, &irqL);
free(header);

return true;
}

// public interface implementation

lt_ota_type_t lt_ota_get_type() {
return OTA_TYPE_DUAL;
}

bool lt_ota_is_valid(uint8_t index) {
return false;
return lt_ota_get_image_state(index) != INVALID;
}

uint8_t lt_ota_dual_get_current() {
return 0;
// ambz2 uses virtual memory, so we can't use function address to determine active image
// use the SDK instead
return sys_update_ota_get_curr_fw_idx();
}

uint8_t lt_ota_dual_get_stored() {
return 0;
// bootloader prioritizes FW1 if both are valid
return lt_ota_get_image_state(1) == ENABLED ? 1 : 2;
}

bool lt_ota_switch(bool revert) {
return false;
uint8_t current = lt_ota_dual_get_current();
uint8_t stored = lt_ota_dual_get_stored();
if ((current == stored) == revert)
return true;

uint8_t to_enable = lt_ota_get_other_index(stored);
uint8_t to_disable = stored;

if (!lt_ota_is_valid(to_enable))
return false;

// enable first, so there is always at least one enabled image
if (!lt_ota_set_image_enabled(to_enable, true))
return false;
if (!lt_ota_set_image_enabled(to_disable, false))
return false;

return true;
}
1 change: 1 addition & 0 deletions cores/realtek-ambz2/base/lt_defs.h
Original file line number Diff line number Diff line change
Expand Up @@ -7,4 +7,5 @@
#define LT_HAS_LWIP2 1
#define LT_HAS_MBEDTLS 1
#define LT_HAS_PRINTF 1
#define LT_HAS_OTA 1
#define LT_HW_BLE 1

0 comments on commit 7082519

Please sign in to comment.