/*
|
* Copyright (c) 2019-2023 Beijing Hanwei Innovation Technology Ltd. Co. and
|
* its subsidiaries and affiliates (collectly called MKSEMI).
|
*
|
* All rights reserved.
|
*
|
* Redistribution and use in source and binary forms, with or without
|
* modification, are permitted provided that the following conditions are met:
|
*
|
* 1. Redistributions of source code must retain the above copyright notice,
|
* this list of conditions and the following disclaimer.
|
*
|
* 2. Redistributions in binary form, except as embedded into an MKSEMI
|
* integrated circuit in a product or a software update for such product,
|
* must reproduce the above copyright notice, this list of conditions and
|
* the following disclaimer in the documentation and/or other materials
|
* provided with the distribution.
|
*
|
* 3. Neither the name of MKSEMI nor the names of its contributors may be used
|
* to endorse or promote products derived from this software without
|
* specific prior written permission.
|
*
|
* 4. This software, with or without modification, must only be used with a
|
* MKSEMI integrated circuit.
|
*
|
* 5. Any software provided in binary form under this license must not be
|
* reverse engineered, decompiled, modified and/or disassembled.
|
*
|
* THIS SOFTWARE IS PROVIDED BY MKSEMI "AS IS" AND ANY EXPRESS OR IMPLIED
|
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
|
* MERCHANTABILITY, NONINFRINGEMENT, AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
* DISCLAIMED. IN NO EVENT SHALL MKSEMI OR CONTRIBUTORS BE LIABLE FOR ANY
|
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
|
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
|
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
*/
|
|
#include "mk_sbl.h"
|
#include "mk_flash.h"
|
#include "mk_clock.h"
|
#include "mk_trace.h"
|
|
#if !defined(FACT_BAK_MODE) && !defined(AB_CYCLE_MODE)
|
#define AB_CYCLE_MODE
|
#endif
|
|
#if defined(FACT_BAK_MODE)
|
#include "LzmaDec.h"
|
#define NORMAL_IMAGE_LOAD_ADDR IMAGE2_LOAD_ADDR
|
#define FACT_IMAGE_LOAD_ADDR IMAGE1_LOAD_ADDR
|
#endif
|
|
/*
|
AB_CYCLE_MODE example
|
+---------+--------------+---------+
|
| area | start | length |
|
+---------+--------------+---------+
|
| sbl | 0x04000000 | 12*1024 |
|
+---------+--------------+---------+
|
| active | | |
|
|img flag | 0x04003000 | 4*1024 |
|
+---------+--------------+---------+
|
| img1 | 0x04004000 | 128*1024|
|
+---------+--------------+---------+
|
| img2 | 0x04024000 | 128*1024|
|
+---------+--------------+---------+
|
|
FACT_BAK_MODE example
|
+----------+--------------+---------+
|
| area | start | length |
|
+----------+--------------+---------+
|
| sbl | 0x04000000 | 12*1024 |
|
+----------+--------------+---------+
|
|compressed| | |
|
| factory | 0x04004000 | 128*1024|
|
| img | | |
|
+----------+--------------+---------+
|
|normal img| 0x04024000 | 128*1024|
|
+----------+--------------+---------+
|
|
The address and length of each area can be determined based on actual conditions
|
|
*/
|
|
#if defined(FACT_BAK_MODE)
|
|
static char lzma_heap_flag = 0;
|
static char lzma_heap[16 * 1024];
|
|
static void *lzma_alloc(ISzAllocPtr p, size_t size)
|
{
|
if (lzma_heap_flag == 0 && size < sizeof(lzma_heap))
|
{
|
return lzma_heap;
|
}
|
|
return NULL;
|
}
|
|
static void lzma_free(ISzAllocPtr p, void *address)
|
{
|
if (address == lzma_heap)
|
{
|
lzma_heap_flag = 0;
|
}
|
}
|
|
static ISzAlloc allocator = {lzma_alloc, lzma_free};
|
|
#endif
|
|
/*
|
* Check whether there is a valid image at the specified address
|
*/
|
int sbl_check_image(uint32_t img_addr, uint32_t *img_cp_len, uint32_t *sp, uint32_t *entry)
|
{
|
uint32_t *p = (uint32_t *)img_addr;
|
struct BOOT_DESC_T *desc;
|
|
if ((p[0] < SRAM_BASE) || (p[0] > (SRAM_BASE + SRAM_SIZE)))
|
{
|
return -1;
|
}
|
|
if (p[1] > (CODE_BASE + SRAM_SIZE))
|
{
|
return -1;
|
}
|
|
if ((p[9] > (CODE_BASE + SRAM_SIZE)) || ((p[9] & 0x03) != 0))
|
{
|
return -1;
|
}
|
|
desc = (struct BOOT_DESC_T *)(img_addr + p[9]);
|
|
if (desc->header_marker != BOOT_HEADER_MARKER)
|
{
|
return -1;
|
}
|
|
if (img_cp_len != NULL)
|
{
|
*img_cp_len = desc->copy_len;
|
}
|
|
if (sp != NULL)
|
{
|
*sp = p[0];
|
}
|
|
if (entry != NULL)
|
{
|
*entry = p[1] + SRAM_BASE;
|
}
|
|
return 0;
|
}
|
|
/*
|
* Get the address where the activated image is located
|
*/
|
uint32_t sbl_get_active_image(void)
|
{
|
#if defined(AB_CYCLE_MODE)
|
uint32_t img = REG_READ(IMAGE_FLAG_ADDR);
|
|
if ((img == IMAGE1_LOAD_ADDR) || (img == IMAGE2_LOAD_ADDR))
|
{
|
return img;
|
}
|
else
|
{
|
return 0;
|
}
|
#else
|
return NORMAL_IMAGE_LOAD_ADDR;
|
#endif
|
}
|
|
/*
|
* Set the address of the activated image
|
*/
|
void sbl_set_active_image(uint32_t img)
|
{
|
#if defined(AB_CYCLE_MODE)
|
if ((img != IMAGE1_LOAD_ADDR) && (img != IMAGE2_LOAD_ADDR))
|
{
|
return;
|
}
|
|
if (sbl_get_active_image() == img)
|
{
|
return;
|
}
|
|
uint32_t flag[64];
|
flag[0] = img;
|
|
flash_erase(FLASH_ID0, IMAGE_FLAG_ADDR, FLASH_SECTOR_SIZE);
|
flash_write(FLASH_ID0, IMAGE_FLAG_ADDR, (uint8_t *)flag, FLASH_PAGE_SIZE);
|
#endif
|
}
|
|
/*
|
* Get the address where the OTA image is stored
|
*/
|
uint32_t sbl_get_addr_for_ota(void)
|
{
|
#if defined(AB_CYCLE_MODE)
|
uint32_t len;
|
|
if (sbl_check_image(SRAM_BASE, &len, NULL, NULL) == 0)
|
{
|
if (memcmp((uint8_t *)IMAGE1_LOAD_ADDR, (uint8_t *)SRAM_BASE, len) == 0)
|
{
|
return IMAGE2_LOAD_ADDR;
|
}
|
|
if (memcmp((uint8_t *)IMAGE2_LOAD_ADDR, (uint8_t *)SRAM_BASE, len) == 0)
|
{
|
return IMAGE1_LOAD_ADDR;
|
}
|
}
|
|
ASSERT(0, "A critical error has occurred in flash or RAM\r\n");
|
|
return IMAGE1_LOAD_ADDR;
|
#else
|
return NORMAL_IMAGE_LOAD_ADDR;
|
#endif
|
}
|
|
/*
|
* Run the specified image
|
*/
|
static RAM_FUNC void sbl_run_image(uint32_t addr, uint32_t len, uint32_t sp, uint32_t entry);
|
|
#if defined(__ARMCC_VERSION) && (__ARMCC_VERSION >= 6100100)
|
#pragma clang optimize off
|
#elif defined(__GNUC__)
|
#pragma GCC diagnostic push
|
#pragma GCC optimize("O0")
|
#else
|
#pragma optimize = none
|
#endif
|
|
static void sbl_run_image(uint32_t addr, uint32_t len, uint32_t sp, uint32_t entry)
|
{
|
static reset_handler_t *sbl2app;
|
|
if (addr != SRAM_BASE)
|
{
|
memcpy((char *)SRAM_BASE, (char *)addr, len);
|
}
|
|
flash_handle[0].base->CMD = FLASH_CMD_DATALEN(0) | FLASH_CMD_POLL(false) | FLASH_CMD_DOUT(FLASH_DATA_OUT) | FLASH_CMD_INTLEN(0) |
|
FLASH_CMD_FIELDFORM(FLASH_CMD_ALL_SERIAL) | FLASH_CMD_FRAMEFORM(FLASH_CMD_OP_ONLY) | FLASH_CMD_OPCODE(0xB9);
|
SYSCON->SYS_CMU &= ~(1U << CLOCK_FLASH_CTRL);
|
sbl2app = (reset_handler_t *)entry;
|
__set_MSP(sp);
|
sbl2app();
|
}
|
|
#if defined(__ARMCC_VERSION) && (__ARMCC_VERSION >= 6100100)
|
#pragma clang optimize on
|
#elif defined(__GNUC__)
|
#pragma GCC diagnostic pop
|
#endif
|
|
/*
|
* Main process of the second boot loader
|
*/
|
void sbl_main(void)
|
{
|
uint32_t len, sp, entry, act_img;
|
|
act_img = sbl_get_active_image();
|
|
#if defined(AB_CYCLE_MODE)
|
if (act_img == IMAGE1_LOAD_ADDR || act_img == IMAGE2_LOAD_ADDR)
|
{
|
if (sbl_check_image(act_img, &len, &sp, &entry) == 0)
|
{
|
sbl_run_image(act_img, len, sp, entry);
|
}
|
}
|
|
if (sbl_check_image(IMAGE1_LOAD_ADDR, &len, &sp, &entry) == 0)
|
{
|
sbl_run_image(IMAGE1_LOAD_ADDR, len, sp, entry);
|
}
|
else if (sbl_check_image(IMAGE2_LOAD_ADDR, &len, &sp, &entry) == 0)
|
{
|
sbl_run_image(IMAGE2_LOAD_ADDR, len, sp, entry);
|
}
|
else
|
{
|
while (1)
|
;
|
}
|
#else
|
if (act_img == NORMAL_IMAGE_LOAD_ADDR)
|
{
|
if (sbl_check_image(act_img, &len, &sp, &entry) == 0)
|
{
|
sbl_run_image(act_img, len, sp, entry);
|
}
|
}
|
|
ELzmaStatus status;
|
SizeT lzma_hdrlen = LZMA_PROPS_SIZE + sizeof(UInt64);
|
SizeT srclen = 128 * 1024 - lzma_hdrlen;
|
SizeT deslen = ROM_SIZE;
|
SRes res;
|
|
res = LzmaDecode((Byte *)SRAM_BASE, &deslen, (Byte *)FACT_IMAGE_LOAD_ADDR + lzma_hdrlen, &srclen, (Byte *)FACT_IMAGE_LOAD_ADDR,
|
LZMA_PROPS_SIZE + sizeof(UInt64), LZMA_FINISH_END, &status, &allocator);
|
|
if (res != SZ_OK || status != LZMA_STATUS_FINISHED_WITH_MARK)
|
{
|
while (1)
|
;
|
}
|
|
if (sbl_check_image(SRAM_BASE, &len, &sp, &entry) == 0)
|
{
|
sbl_run_image(SRAM_BASE, len, sp, entry);
|
}
|
else
|
{
|
while (1)
|
;
|
}
|
#endif
|
}
|