mirror of https://github.com/ARMmbed/mbed-os.git
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
parent
985c2b0ec7
commit
a4575a965f
|
@ -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))
|
||||
|
|
|
@ -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
|
|
@ -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(®ion1);
|
||||
OTA_GetImageInfo(®ion2);
|
||||
|
||||
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);
|
||||
|
|
|
@ -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 */
|
||||
|
||||
|
|
Binary file not shown.
|
@ -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)
|
||||
|
|
Loading…
Reference in New Issue