| /***************************************************************************//** |
| * \file main.c |
| * \version 1.0 |
| ******************************************************************************** |
| * \copyright |
| * 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. |
| *******************************************************************************/ |
| #include <inttypes.h> |
| #include <stdbool.h> |
| |
| /* Cypress pdl headers */ |
| #include "cy_pdl.h" |
| #include "cyhal.h" |
| #include "cyhal_wdt.h" |
| |
| #include "cyw_platform_utils.h" |
| |
| #if defined CYW20829 |
| #include "cy_service_app.h" |
| #endif |
| |
| #include "cybsp.h" |
| #include "cy_retarget_io.h" |
| |
| #if defined(CY_BOOT_USE_EXTERNAL_FLASH) || defined(CYW20829) |
| #include "flash_qspi.h" |
| #endif /* defined(CY_BOOT_USE_EXTERNAL_FLASH) || defined(CYW20829) */ |
| |
| #include "cycfg_pins.h" |
| #include "cy_result.h" |
| #include "sysflash/sysflash.h" |
| #include "flash_map_backend/flash_map_backend.h" |
| |
| #include "bootutil/image.h" |
| #include "bootutil/bootutil.h" |
| #include "bootutil/sign_key.h" |
| |
| #include "bootutil/bootutil_log.h" |
| |
| #include "bootutil/fault_injection_hardening.h" |
| |
| #ifdef USE_EXEC_TIME_CHECK |
| #include "misc/timebase_us.h" |
| #include "misc/exec_time_check.h" |
| #endif /* USE_EXEC_TIME_CHECK */ |
| |
| #ifdef USE_LOG_TIMESTAMP |
| #include "timestamp.h" |
| #endif /* USE_LOG_TIMESTAMP */ |
| |
| #define CY_RSLT_MODULE_MCUBOOTAPP 0x500U |
| #define CY_RSLT_MODULE_MCUBOOTAPP_MAIN 0x51U |
| |
| /** General module error */ |
| #define MCUBOOTAPP_RSLT_ERR \ |
| (CY_RSLT_CREATE_EX(CY_RSLT_TYPE_ERROR, CY_RSLT_MODULE_MCUBOOTAPP, CY_RSLT_MODULE_MCUBOOTAPP_MAIN, 0)) |
| |
| /* WDT time out for reset mode, in milliseconds. */ |
| #define WDT_TIME_OUT_MS 4000 |
| |
| #ifdef CY_BOOT_USE_EXTERNAL_FLASH |
| /* Choose SMIF slot number (slave select). |
| * Acceptable values are: |
| * 0 - SMIF disabled (no external memory); |
| * 1, 2, 3 or 4 - slave select line memory module is connected to. |
| */ |
| #define SMIF_ID (1U) /* Assume SlaveSelect_0 is used for External Memory */ |
| #endif /* CY_BOOT_USE_EXTERNAL_FLASH */ |
| |
| #define BOOT_MSG_FINISH "MCUBoot Bootloader finished.\r\n" \ |
| "Deinitializing hardware..." |
| |
| static void hw_deinit(void); |
| |
| static inline __attribute__((always_inline)) |
| fih_uint calc_app_addr(uintptr_t flash_base, const struct boot_rsp *rsp) |
| { |
| return fih_uint_encode(flash_base + |
| rsp->br_image_off + |
| rsp->br_hdr->ih_hdr_size); |
| } |
| |
| /******************************************************************************* |
| * Function Name: fih_calc_app_addr |
| ******************************************************************************** |
| * Summary: |
| * Calculate start address of user application. |
| * |
| * Parameters: |
| * image_base - base address of flash; |
| * |
| * rsp - provided by the boot loader code; indicates where to jump |
| * to execute the main image; |
| * |
| * output - calculated address of application; |
| * |
| * Return: |
| * fih_int |
| * |
| *******************************************************************************/ |
| static inline __attribute__((always_inline)) fih_int fih_calc_app_addr( |
| uintptr_t image_base, const struct boot_rsp *rsp, fih_uint *app_address) |
| { |
| fih_int fih_rc = FIH_FAILURE; |
| |
| #if defined(MCUBOOT_RAM_LOAD) |
| if (IS_RAM_BOOTABLE(rsp->br_hdr) == true) { |
| if ((UINT32_MAX - rsp->br_hdr->ih_hdr_size) >= image_base) { |
| *app_address = |
| fih_uint_encode(image_base + rsp->br_hdr->ih_hdr_size); |
| fih_rc = FIH_SUCCESS; |
| } |
| } else |
| #endif |
| { |
| if (((UINT32_MAX - rsp->br_image_off) >= image_base) && |
| ((UINT32_MAX - rsp->br_hdr->ih_hdr_size) >= |
| (image_base + rsp->br_image_off))) { |
| *app_address = fih_uint_encode(image_base + rsp->br_image_off + |
| rsp->br_hdr->ih_hdr_size); |
| fih_rc = FIH_SUCCESS; |
| } |
| } |
| |
| FIH_RET(fih_rc); |
| } |
| |
| #if defined CYW20829 |
| |
| #if defined(CY_BOOT_USE_EXTERNAL_FLASH) && !defined(MCUBOOT_ENC_IMAGES_XIP) |
| CY_RAMFUNC_BEGIN /* SMIF will be deinitialized in this case! */ |
| #else |
| inline __attribute__((always_inline)) |
| #endif /* defined(CY_BOOT_USE_EXTERNAL_FLASH) && !defined(MCUBOOT_ENC_IMAGES_XIP) */ |
| __NO_RETURN |
| static void cyw20829_launch_app(fih_uint app_addr, uint32_t *key, uint32_t *iv) |
| { |
| #if defined(CY_BOOT_USE_EXTERNAL_FLASH) && !defined(MCUBOOT_ENC_IMAGES_XIP) |
| qspi_deinit(SMIF_ID); |
| #endif /* defined(CY_BOOT_USE_EXTERNAL_FLASH) && !defined(MCUBOOT_ENC_IMAGES_XIP) */ |
| platform_RunNextApp(app_addr, key, iv); |
| } |
| #if defined(CY_BOOT_USE_EXTERNAL_FLASH) && !defined(MCUBOOT_ENC_IMAGES_XIP) |
| CY_RAMFUNC_END /* SMIF will be deinitialized in this case! */ |
| #endif /* defined(CY_BOOT_USE_EXTERNAL_FLASH) && !defined(MCUBOOT_ENC_IMAGES_XIP) */ |
| |
| #endif /* defined CYW20829 */ |
| |
| static bool do_boot(struct boot_rsp *rsp) |
| { |
| uintptr_t flash_base = 0; |
| |
| #if defined CYW20829 |
| uint32_t *key = NULL; |
| uint32_t *iv = NULL; |
| #endif /* defined CYW20829 */ |
| |
| if ((rsp != NULL) && (rsp->br_hdr != NULL)) { |
| |
| if (flash_device_base(rsp->br_flash_dev_id, &flash_base) == 0) { |
| fih_uint app_addr = calc_app_addr(flash_base, rsp); |
| |
| BOOT_LOG_INF("Starting User Application (wait)..."); |
| if (IS_ENCRYPTED(rsp->br_hdr)) { |
| BOOT_LOG_DBG(" * User application is encrypted"); |
| } |
| BOOT_LOG_INF("Start slot Address: 0x%08" PRIx32, (uint32_t)fih_uint_decode(app_addr)); |
| |
| if (flash_device_base(rsp->br_flash_dev_id, &flash_base) != 0) { |
| return false; |
| } |
| |
| if (fih_uint_eq(calc_app_addr(flash_base, rsp), app_addr) != FIH_TRUE) { |
| return false; |
| } |
| |
| #if defined CYW20829 |
| |
| #ifdef MCUBOOT_ENC_IMAGES_XIP |
| if (IS_ENCRYPTED(rsp->br_hdr)) { |
| key = rsp->xip_key; |
| iv = rsp->xip_iv; |
| } else { |
| BOOT_LOG_ERR("User image is not encrypted, while MCUBootApp is compiled with encryption support."); |
| return false; |
| } |
| #endif /* MCUBOOT_ENC_IMAGES_XIP */ |
| |
| |
| #ifdef APP_CM33 |
| /* This function does not return */ |
| BOOT_LOG_INF("Launching app on CM33 core"); |
| BOOT_LOG_INF(BOOT_MSG_FINISH); |
| hw_deinit(); |
| cyw20829_launch_app(app_addr, key, iv); |
| #else |
| #error "Application should run on Cortex-M33" |
| #endif /* APP_CM33 */ |
| |
| #else /* defined CYW20829 */ |
| |
| #ifdef USE_XIP |
| BOOT_LOG_DBG("XIP: Switch to SMIF XIP mode"); |
| qspi_set_mode(CY_SMIF_MEMORY); |
| #endif /* USE_XIP */ |
| |
| #ifdef APP_CM4 |
| /* This function turns on CM4 and returns */ |
| BOOT_LOG_INF("Launching app on CM4 core"); |
| BOOT_LOG_INF(BOOT_MSG_FINISH); |
| hw_deinit(); |
| #ifdef BOOT_CM0P |
| Cy_SysEnableCM4(fih_uint_decode(app_addr)); |
| return true; |
| #else |
| psoc6_launch_cm4_app(app_addr); |
| #endif /* BOOT_CM0P */ |
| |
| #elif defined APP_CM0P |
| #ifdef BOOT_CM0P |
| /* This function does not return */ |
| BOOT_LOG_INF("Launching app on CM0P core"); |
| BOOT_LOG_INF(BOOT_MSG_FINISH); |
| hw_deinit(); |
| psoc6_launch_cm0p_app(app_addr); |
| #else |
| #error "Application should run on Cortex-M4" |
| #endif /* BOOT_CM0P */ |
| |
| #elif defined APP_CM7 |
| /* This function does not return */ |
| BOOT_LOG_INF("Launching app on CM7 core"); |
| BOOT_LOG_INF(BOOT_MSG_FINISH); |
| hw_deinit(); |
| xmc7000_launch_cm7_app(app_addr); |
| return true; |
| #else |
| #error "Application should run on either Cortex-M0+ or Cortex-M4" |
| #endif /* APP_CM4 */ |
| |
| #endif /* defined CYW20829 */ |
| } else { |
| BOOT_LOG_ERR("Flash device ID not found"); |
| return false; |
| } |
| } |
| |
| return false; |
| } |
| |
| static void DeepSleep_Prepare(void) |
| { |
| static cy_stc_syspm_callback_params_t syspmSleepAppParams; |
| static cy_stc_syspm_callback_t syspmAppSleepCallbackHandler = |
| { |
| Cy_SCB_UART_DeepSleepCallback, CY_SYSPM_DEEPSLEEP, 0u, &syspmSleepAppParams, |
| NULL, NULL, 0}; |
| |
| syspmSleepAppParams.base = cy_retarget_io_uart_obj.base; |
| syspmSleepAppParams.context = (void *)&(cy_retarget_io_uart_obj.context); |
| |
| if (!Cy_SysPm_RegisterCallback(&syspmAppSleepCallbackHandler)) { |
| BOOT_LOG_ERR("Failed to register syspmAppSleepCallbackHandler"); |
| CY_ASSERT(false); |
| } |
| } |
| |
| int main(void) |
| { |
| struct boot_rsp rsp = {}; |
| bool boot_succeeded = false; |
| fih_int fih_rc = FIH_FAILURE; |
| cy_rslt_t rc = cybsp_init(); |
| |
| |
| if (rc != CY_RSLT_SUCCESS) { |
| CY_ASSERT((bool)0); |
| /* Loop forever... */ |
| while (true) { |
| __WFI(); |
| } |
| } |
| |
| #ifdef USE_EXEC_TIME_CHECK |
| timebase_us_init(); |
| #endif /* USE_EXEC_TIME_CHECK */ |
| |
| #ifdef USE_LOG_TIMESTAMP |
| log_timestamp_init(); |
| #endif /* USE_LOG_TIMESTAMP */ |
| |
| /* enable interrupts */ |
| __enable_irq(); |
| |
| /* Certain PSoC 6 devices enable CM4 by default at startup. It must be |
| * either disabled or enabled & running a valid application for flash write |
| * to work from CM0+. Since flash write may happen in boot_go() for updating |
| * the image before this bootloader app can enable CM4 in do_boot(), we need |
| * to keep CM4 disabled. Note that debugging of CM4 is not supported when it |
| * is disabled. |
| */ |
| #if defined(CY_DEVICE_PSOC6ABLE2) && !defined(BOOT_CM4) |
| if (CY_SYS_CM4_STATUS_ENABLED == Cy_SysGetCM4Status()) { |
| Cy_SysDisableCM4(); |
| } |
| #endif /* defined(CY_DEVICE_PSOC6ABLE2) && !defined(BOOT_CM4) */ |
| /* Initialize retarget-io to use the debug UART port */ |
| rc = cy_retarget_io_init(CYBSP_DEBUG_UART_TX, |
| CYBSP_DEBUG_UART_RX, |
| CY_RETARGET_IO_BAUDRATE); |
| |
| if (rc != CY_RSLT_SUCCESS) { |
| CY_ASSERT((bool)0); |
| /* Loop forever... */ |
| while (true) { |
| __WFI(); |
| } |
| } |
| |
| BOOT_LOG_INF("MCUBoot Bootloader Started"); |
| |
| #ifdef CY_BOOT_USE_EXTERNAL_FLASH |
| { |
| cy_en_smif_status_t qspi_status = qspi_init_sfdp(SMIF_ID); |
| |
| if (CY_SMIF_SUCCESS == qspi_status) { |
| rc = CY_RSLT_SUCCESS; |
| BOOT_LOG_INF("External Memory initialized w/ SFDP."); |
| } else { |
| rc = MCUBOOTAPP_RSLT_ERR; |
| BOOT_LOG_ERR("External Memory initialization w/ SFDP FAILED: 0x%08" PRIx32, (uint32_t)qspi_status); |
| } |
| } |
| |
| if (CY_RSLT_SUCCESS == rc) |
| #endif /* CY_BOOT_USE_EXTERNAL_FLASH */ |
| { |
| #if defined(CYW20829) && defined(MCUBOOT_HW_ROLLBACK_PROT) |
| /* Check service application completion status */ |
| if (check_service_app_status() != 0) { |
| BOOT_LOG_ERR("Service application failed"); |
| CY_ASSERT((bool)0); |
| /* Loop forever... */ |
| while (true) { |
| __WFI(); |
| } |
| } |
| #endif /* CYW20829 && MCUBOOT_HW_ROLLBACK_PROT */ |
| |
| #ifdef USE_EXEC_TIME_CHECK |
| { |
| uint32_t exec_time; |
| EXEC_TIME_CHECK_BEGIN(&exec_time); |
| #endif /* USE_EXEC_TIME_CHECK */ |
| FIH_CALL(boot_go, fih_rc, &rsp); |
| #ifdef USE_EXEC_TIME_CHECK |
| EXEC_TIME_CHECK_END(); |
| BOOT_LOG_INF("Exec time: %" PRIu32 " [ms]", exec_time / 1000U); |
| } |
| #endif /* USE_EXEC_TIME_CHECK */ |
| if (FIH_TRUE == fih_eq(fih_rc, FIH_SUCCESS)) { |
| BOOT_LOG_INF("User Application validated successfully"); |
| /* initialize watchdog timer. it should be updated from user app |
| * to mark successful start up of this app. if the watchdog is not updated, |
| * reset will be initiated by watchdog timer and swap revert operation started |
| * to roll back to operable image. |
| */ |
| cyhal_wdt_t *wdt = NULL; |
| |
| rc = cyhal_wdt_init(wdt, WDT_TIME_OUT_MS); |
| |
| if (CY_RSLT_SUCCESS == rc) { |
| |
| boot_succeeded = do_boot(&rsp); |
| |
| if (!boot_succeeded) { |
| BOOT_LOG_ERR("Boot of next app failed"); |
| } |
| } else { |
| BOOT_LOG_ERR("Failed to init WDT"); |
| } |
| } else { |
| BOOT_LOG_ERR("MCUBoot Bootloader found none of bootable images"); |
| } |
| } |
| |
| DeepSleep_Prepare(); |
| |
| while (true) { |
| if (boot_succeeded) { |
| (void)Cy_SysPm_CpuEnterDeepSleep(CY_SYSPM_WAIT_FOR_INTERRUPT); |
| } else { |
| __WFI(); |
| } |
| } |
| } |
| |
| static void hw_deinit(void) |
| { |
| #if defined(CY_BOOT_USE_EXTERNAL_FLASH) && !defined(MCUBOOT_ENC_IMAGES_XIP) && !defined(USE_XIP) |
| qspi_deinit(SMIF_ID); |
| #endif /* defined(CY_BOOT_USE_EXTERNAL_FLASH) && !defined(MCUBOOT_ENC_IMAGES_XIP) */ |
| |
| /* Flush the TX buffer, need to be fixed in retarget_io */ |
| while(cy_retarget_io_is_tx_active()){} |
| cy_retarget_io_deinit(); |
| |
| #ifdef USE_EXEC_TIME_CHECK |
| timebase_us_deinit(); |
| #endif /* USE_EXEC_TIME_CHECK */ |
| |
| #ifdef USE_LOG_TIMESTAMP |
| log_timestamp_deinit(); |
| #endif /* USE_LOG_TIMESTAMP */ |
| } |