Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

OTA implementation & fixes for RTL8720CF #302

Open
wants to merge 1 commit into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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
Loading