rtl8195am - refactor bootloader and ota support

1. move ota region 1 from 0x00b000 to 0x040000
2. move ota region 2 from 0x0c0000 to 0x120000
3. refactor bootloader header as follows:

   uint32_t tag;
   uint32_t ver;
   uint64_t timestamp;
   uint32_t size;
   uint8_t hash[32];
   uint8_t campaign[16];
   uint32_t crc32;

   where,
   a. hash is the sha256 checksum of the payload.
   b. crc32 is the crc32 checksum of headers from tag to campaign.

4. Call NVIC_SystemReset for soft reset.

Signed-off-by: Tony Wu <tung7970@gmail.com>
pull/5531/head
Tony Wu 2017-11-12 22:46:32 +08:00
parent 985c2b0ec7
commit a4575a965f
6 changed files with 235 additions and 128 deletions

View File

@ -43,8 +43,7 @@
#include "rtl8195a_compiler.h"
#include "rtl8195a_platform.h"
#include "rtl8195a_crypto.h"
#define REG32(reg) (*(volatile uint32_t *)(reg))
#define REG16(reg) (*(volatile uint16_t *)(reg))

View File

@ -0,0 +1,24 @@
/* mbed Microcontroller Library
* Copyright (c) 2013-2017 Realtek Semiconductor Corp.
*
* SPDX-License-Identifier: Apache-2.0
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#ifndef MBED_RTL8195A_CRYPTO_H
#define MBED_RTL8195A_CRYPTO_H
extern _LONG_CALL_ uint32_t crc32_get(uint8_t *buf, int len);
#endif

View File

@ -13,7 +13,6 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include <stdio.h>
#include <string.h>
#include "mbed_wait_api.h"
@ -24,61 +23,105 @@
static flash_t flash_obj;
void OTA_GetImageInfo(imginfo_t *info)
void OTA_ReadHeader(uint32_t base, imginfo_t *img)
{
uint32_t ver_hi, ver_lo;
uint32_t epoch_hi, epoch_lo;
flash_ext_read_word(&flash_obj, info->base + TAG_OFS, &info->tag);
flash_ext_read_word(&flash_obj, info->base + VER_OFS, &ver_lo);
flash_ext_read_word(&flash_obj, info->base + VER_OFS + 4, &ver_hi);
if (info->tag == TAG_DOWNLOAD) {
info->ver = ((uint64_t)ver_hi << 32) | (uint64_t) ver_lo;
} else {
info->ver = 0;
}
}
uint32_t OTA_GetBase(void)
{
static uint32_t ota_base = 0;
imginfo_t region1, region2;
if (ota_base == OTA_REGION1 || ota_base == OTA_REGION2) {
return ota_base;
if (base != OTA_REGION1_BASE || base != OTA_REGION2_BASE) {
return;
}
region1.base = OTA_REGION1;
region2.base = OTA_REGION2;
flash_ext_read_word(&flash_obj, base + OTA_TAG_OFS, &img->tag);
flash_ext_read_word(&flash_obj, base + OTA_VER_OFS, &img->ver);
flash_ext_read_word(&flash_obj, base + OTA_EPOCH_OFS, &epoch_hi);
flash_ext_read_word(&flash_obj, base + OTA_EPOCH_OFS + 4, &epoch_lo);
img->timestamp = ((uint64_t)epoch_hi << 32) | (uint64_t) epoch_lo;
OTA_GetImageInfo(&region1);
OTA_GetImageInfo(&region2);
if (region1.ver >= region2.ver) {
ota_base = region2.base;
} else {
ota_base = region1.base;
}
return ota_base;
flash_ext_read_word(&flash_obj, base + OTA_SIZE_OFS, &img->size);
flash_ext_stream_read(&flash_obj, base + OTA_HASH_OFS, 32, img->hash);
flash_ext_stream_read(&flash_obj, base + OTA_CAMPAIGN_OFS, 16, img->campaign);
flash_ext_read_word(&flash_obj, base + OTA_CRC32_OFS, &img->crc32);
}
uint32_t OTA_MarkUpdateDone(void)
bool OTA_CheckHeader(imginfo_t *img)
{
uint32_t addr = OTA_GetBase() + TAG_OFS;
uint8_t *msg;
uint32_t crc;
return flash_ext_write_word(&flash_obj, addr, TAG_DOWNLOAD);
msg = (uint8_t *)img;
crc = crc32_get(msg, OTA_CRC32_LEN);
if (crc != img->crc32) {
return false;
}
if ((img->tag & OTA_TAG_CHIP_MSK) != (OTA_TAG_ID & OTA_TAG_CHIP_MSK)) {
return false;
}
return true;
}
uint32_t OTA_UpdateImage(uint32_t offset, uint32_t len, uint8_t *data)
void OTA_GetImageInfo(uint32_t base, imginfo_t *img)
{
OTA_ReadHeader(base, img);
if (!OTA_CheckHeader(img)) {
img->timestamp = 0;
img->valid = false;
}
img->valid = true;
}
uint32_t OTA_GetUpdateBase(void)
{
imginfo_t img1, img2;
OTA_GetImageInfo(OTA_REGION1_BASE, &img1);
OTA_GetImageInfo(OTA_REGION2_BASE, &img2);
if (img1.valid && img2.valid) {
if (img1.timestamp < img2.timestamp) {
return OTA_REGION1_BASE;
} else {
return OTA_REGION2_BASE;
}
}
if (img1.valid) {
return OTA_REGION2_BASE;
}
return OTA_REGION1_BASE;
}
uint32_t OTA_UpateHeader(uint32_t base, imginfo_t *img)
{
flash_ext_write_word(&flash_obj, base + OTA_TAG_OFS, img->tag);
flash_ext_write_word(&flash_obj, base + OTA_VER_OFS, img->ver);
flash_ext_write_word(&flash_obj, base + OTA_EPOCH_OFS, img->timestamp >> 32);
flash_ext_write_word(&flash_obj, base + OTA_EPOCH_OFS + 4, (img->timestamp << 32) >> 32);
flash_ext_write_word(&flash_obj, base + OTA_SIZE_OFS, img->size);
flash_ext_stream_write(&flash_obj, base + OTA_HASH_OFS, 32, img->hash);
flash_ext_stream_write(&flash_obj, base + OTA_CAMPAIGN_OFS, 16, img->campaign);
flash_ext_write_word(&flash_obj, base + OTA_CRC32_OFS, img->crc32);
return 0;
}
uint32_t OTA_UpdateImage(uint32_t base, uint32_t offset, uint32_t len, uint8_t *data)
{
uint32_t addr, start, end, count, shift;
uint8_t *pdata = data;
uint8_t buf[FLASH_SECTOR_SIZE];
start = OTA_GetBase() + offset;
start = base + offset;
end = start + len;
if (data == NULL || start > FLASH_TOP || end > FLASH_TOP) {
if (data == NULL ||
base != OTA_REGION1_BASE || base != OTA_REGION2_BASE ||
start > FLASH_TOP || end > FLASH_TOP) {
return 0;
}
@ -96,7 +139,6 @@ uint32_t OTA_UpdateImage(uint32_t offset, uint32_t len, uint8_t *data)
}
while (addr < end) {
printf("OTA: update addr=0x%lx, len=%ld\r\n", addr, len);
count = MIN(FLASH_SECTOR_SIZE, end - addr);
flash_ext_erase_sector(&flash_obj, addr);
flash_ext_stream_write(&flash_obj, addr, count, pdata);
@ -106,19 +148,20 @@ uint32_t OTA_UpdateImage(uint32_t offset, uint32_t len, uint8_t *data)
return len;
}
uint32_t OTA_ReadImage(uint32_t offset, uint32_t len, uint8_t *data)
uint32_t OTA_ReadImage(uint32_t base, uint32_t offset, uint32_t len, uint8_t *data)
{
uint32_t addr, endaddr;
uint32_t start, end;
addr = OTA_GetBase() + offset;
endaddr = addr + len;
start = base + offset;
end = start + len;
if (data == NULL || addr > FLASH_TOP || endaddr > FLASH_TOP) {
if (data == NULL ||
base != OTA_REGION1_BASE || base != OTA_REGION2_BASE ||
start > FLASH_TOP || end > FLASH_TOP) {
return 0;
}
printf("OTA: read addr=0x%lx\r\n", addr);
return flash_ext_stream_read(&flash_obj, addr, len, data);
return flash_ext_stream_read(&flash_obj, start, len, data);
}
void OTA_ResetTarget(void)
@ -126,11 +169,7 @@ void OTA_ResetTarget(void)
__RTK_CTRL_WRITE32(0x14, 0x00000021);
wait(1);
// write SCB->AIRCR
HAL_WRITE32(0xE000ED00, 0x0C,
(0x5FA << 16) | // VECTKEY
(HAL_READ32(0xE000ED00, 0x0C) & (7 << 8)) | // PRIGROUP
(1 << 2)); // SYSRESETREQ
NVIC_SystemReset();
// not reached
while (1);

View File

@ -1,33 +1,75 @@
/* mbed Microcontroller Library
* Copyright (c) 2013-2017 Realtek Semiconductor Corp.
*
* SPDX-License-Identifier: Apache-2.0
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#ifndef MBED_OTA_API_H
#define MBED_OTA_API_H
#define FLASH_TOP 0x200000
#define FLASH_SECTOR_SIZE 0x1000
#define FLASH_SECTOR_MASK ~(FLASH_SECTOR_SIZE - 1)
#define OTA_REGION1 0x0b000
#define OTA_REGION2 0xc0000
#define TAG_OFS 0xc
#define VER_OFS 0x10
#define FLASH_TOP 0x200000
#define FLASH_SECTOR_SIZE 0x1000
#define FLASH_SECTOR_MASK ~(FLASH_SECTOR_SIZE - 1)
#define TAG_DOWNLOAD 0x81950001
#define TAG_VERIFIED 0x81950003
#define OTA_REGION1_BASE 0x40000
#define OTA_REGION2_BASE 0x120000
#define OTA_REGION1_SIZE 0xe0000
#define OTA_REGION2_SIZE 0xe0000
#define OTA_REGION_SIZE 0xe0000
#define OTA_MBED_FS_BASE 0xb000
#define OTA_CRC32_LEN 0x44
#define OTA_HEADER_LEN 0x48
#define OTA_HEADER_OFS 0x0
#define OTA_TAG_OFS 0x0
#define OTA_VER_OFS 0x4
#define OTA_EPOCH_OFS 0x8
#define OTA_SIZE_OFS 0x10
#define OTA_HASH_OFS 0x14
#define OTA_CAMPAIGN_OFS 0x34
#define OTA_CRC32_OFS 0x44
#define OTA_IMAGE_OFS 0x48
#define OTA_TAG_ID 0x81950001
#define OTA_VER_ID 0x81950001
#define OTA_TAG_CHIP_MSK 0xFFFF0000
#define OTA_TAG_INFO_MSK 0x0000FFFF
typedef struct imginfo_s {
uint32_t base;
uint32_t tag;
uint64_t ver;
uint32_t ver;
uint64_t timestamp;
uint32_t size;
uint8_t hash[32];
uint8_t campaign[16];
uint32_t crc32;
bool valid;
} imginfo_t;
#ifdef __cplusplus
extern "C" {
#endif
extern void OTA_GetImageInfo(imginfo_t *info);
extern uint32_t OTA_GetBase(void);
extern void OTA_GetImageInfo(uint32_t base, imginfo_t *info);
extern uint32_t OTA_GetUpdateBase(void);
extern uint32_t OTA_UpdateImage(uint32_t offset, uint32_t len, uint8_t *data);
extern uint32_t OTA_ReadImage(uint32_t offset, uint32_t len, uint8_t *data);
extern uint32_t OTA_MarkUpdateDone(void);
extern uint32_t OTA_UpdateHeader(uint32_t base, imginfo_t *img);
extern uint32_t OTA_UpdateImage(uint32_t base, uint32_t offset, uint32_t len, uint8_t *data);
extern void OTA_ReadHeader(uint32_t base, imginfo_t *img);
extern uint32_t OTA_ReadImage(uint32_t base, uint32_t offset, uint32_t len, uint8_t *data);
extern void OTA_ResetTarget(void);
#ifdef __cplusplus
@ -35,4 +77,3 @@ extern void OTA_ResetTarget(void);
#endif
#endif /* MBED_OTA_API_H */

View File

@ -7,16 +7,26 @@ RTL8195A elf2bin script
import sys, array, struct, os, re, subprocess
import hashlib
import shutil
import time
import binascii
from tools.paths import TOOLS_BOOTLOADERS
from tools.toolchains import TOOLCHAIN_PATHS
from datetime import datetime
# Constant Variables
RAM2_RSVD = 0x00000000
RAM2_VER = 0x8195FFFF00000000
RAM2_TAG = 0x81950001
RAM2_SHA = '0'
TAG = 0x81950001
VER = 0x81950001
CAMPAIGN = binascii.hexlify('FFFFFFFFFFFFFFFF')
RAM2_HEADER = {
'tag': 0,
'ver': 0,
'timestamp': 0,
'size': 72,
'hash': 'FF',
'campaign': 'FF',
'crc32': 0xFFFFFFFF,
}
def format_number(number, width):
# convert to string
@ -53,6 +63,9 @@ def write_padding_bytes(output_name, size):
output.write('\377' * padcount)
output.close()
def crc32_checksum(string):
return binascii.crc32(string) & 0xFFFFFFFF
def sha256_checksum(filename, block_size=65536):
sha256 = hashlib.sha256()
with open(filename, 'rb') as f:
@ -60,42 +73,9 @@ def sha256_checksum(filename, block_size=65536):
sha256.update(block)
return sha256.hexdigest()
def get_version_by_time():
secs = int((datetime.now()-datetime(2016,11,1)).total_seconds())
return RAM2_VER + secs
# ----------------------------
# main function
# ----------------------------
def prepend(image, entry, segment, image_ram2, image_ota):
# parse input arguments
output = open(image_ram2, "wb")
write_number(os.stat(image).st_size, 8, output)
write_number(int(entry), 8, output)
write_number(int(segment), 8, output)
RAM2_SHA = sha256_checksum(image)
write_number(RAM2_TAG, 8, output)
write_number(get_version_by_time(), 16, output)
write_string(RAM2_SHA, 64, output)
write_number(RAM2_RSVD, 8, output)
append_image_file(image, output)
output.close()
ota = open(image_ota, "wb")
write_number(os.stat(image).st_size, 8, ota)
write_number(int(entry), 8, ota)
write_number(int(segment), 8, ota)
write_number(0xFFFFFFFF, 8, ota)
write_number(get_version_by_time(), 16, ota)
write_string(RAM2_SHA, 64, ota)
write_number(RAM2_RSVD, 8, ota)
append_image_file(image, ota)
ota.close()
def epoch_timestamp():
epoch = int(time.time())
return epoch
def find_symbol(toolchain, mapfile, symbol):
ret = None
@ -235,9 +215,15 @@ def parse_load_segment(toolchain, image_elf):
else:
return []
def write_load_segment(image_elf, image_bin, segment):
def create_payload(image_elf, ram2_bin, entry, segment):
file_elf = open(image_elf, "rb")
file_bin = open(image_bin, "wb")
file_bin = open(ram2_bin, "wb")
write_number(int(entry), 8, file_bin)
write_number(int(len(segment)), 8, file_bin)
write_number(0xFFFFFFFF, 8, file_bin)
write_number(0xFFFFFFFF, 8, file_bin)
for (offset, addr, size) in segment:
file_elf.seek(offset)
# write image header - size & addr
@ -252,30 +238,48 @@ def write_load_segment(image_elf, image_bin, segment):
file_bin.close()
file_elf.close()
# ----------------------------
# main function
# ----------------------------
def rtl8195a_elf2bin(t_self, image_elf, image_bin):
def create_daplink(image_bin, ram1_bin, ram2_bin):
# remove target binary file/path
if os.path.isfile(image_bin):
os.remove(image_bin)
else:
shutil.rmtree(image_bin)
segment = parse_load_segment(t_self.name, image_elf)
write_load_segment(image_elf, image_bin, segment)
RAM2_HEADER['tag'] = format_number(TAG, 8)
RAM2_HEADER['ver'] = format_number(VER, 8)
RAM2_HEADER['timestamp'] = format_number(epoch_timestamp(), 16)
RAM2_HEADER['size'] = format_number(os.stat(ram2_bin).st_size + 72, 8)
RAM2_HEADER['hash'] = format_string(sha256_checksum(ram2_bin))
RAM2_HEADER['campaign'] = format_string(CAMPAIGN)
output = open(image_bin, "wb")
append_image_file(ram1_bin, output)
line = ""
for key in ['tag', 'ver', 'timestamp', 'size', 'hash', 'campaign']:
line += RAM2_HEADER[key]
output.write(RAM2_HEADER[key])
RAM2_HEADER['crc32'] = format_number(crc32_checksum(line), 8)
output.write(RAM2_HEADER['crc32'])
append_image_file(ram2_bin, output)
output.close()
# ----------------------------
# main function
# ----------------------------
def rtl8195a_elf2bin(t_self, image_elf, image_bin):
image_name = os.path.splitext(image_elf)[0]
image_map = image_name + '.map'
ram2_ent = find_symbol(t_self.name, image_map, "PLAT_Start")
ram1_bin = os.path.join(TOOLS_BOOTLOADERS, "REALTEK_RTL8195AM", "ram_1.bin")
ram2_bin = image_name + '-ram_2.bin'
ota_bin = image_name + '-ota.bin'
prepend(image_bin, ram2_ent, len(segment), ram2_bin, ota_bin)
ram2_bin = image_name + '-payload.bin'
# write output file
output = open(image_bin, "wb")
append_image_file(ram1_bin, output)
append_image_file(ram2_bin, output)
output.close()
entry = find_symbol(t_self.name, image_map, "PLAT_Start")
segment = parse_load_segment(t_self.name, image_elf)
create_payload(image_elf, ram2_bin, entry, segment)
create_daplink(image_bin, ram1_bin, ram2_bin)