This thread has been locked.

If you have a related question, please click the "Ask a related question" button in the top right corner. The newly created question will be automatically linked to this question.

MCU-PLUS-SDK-AM263X: QSPI SBL support for primary and secondary application image

Part Number: MCU-PLUS-SDK-AM263X

I'm trying to update the default QSPI SBL provided by the SDK to support a primary and a secondary application image.  From syscfg I created CONFIG_BOOTLOADER0 (primary application image) and CONFIG_BOOTLOADER1 (secondary application image).  I modified the default QSPI SBL to boot from the primary application image.  If the primary application image failed for any reason, it would try the secondary application image.  Just like the default QSPI SBL, it will load and run the applications on the 3 cores that are not running the SBL.  Then, it will load and run the application on r5f0-0.

If I corrupt the multi-core image header of the primary application image, my SBL correctly detect and switch to boot from the secondary application image.  All cores resulted in running from the secondary application image.

However, if I corrupt the r5f0-0 RPRC header, my SBL successfully load and run the primary application image on the other 3 cores.  When the SBL tries to load the image for r5f0-0, it encounters the error in the RPRC header.  Then, it attempts to start over and boot from the secondary application image.  The problem is r5f1 is already running the primary applications  Just reloading/rerunning with the new application doesn't work (maybe because the cores are already out of reset).  The end result is both cores on r5f0 have the secondary application image and both cores on r5f1 have the primary application image.  What I wanted is to have all 4 cores run the same secondary application image.

Part of my goal is to avoid writing a flag to the flash to indicate which application image to load and have the SBL read this flash prior to loading the application image.  My question is if there is a function I can call or steps I can take to put the cores in a state where I can reload/rerun the application?

Thanks in advance.  

  • Hi Peter,

    What is your intent ? In case of failure of r50-0 image load, do you intend to boot all the CPUs from secondary location or do you intend to boot r50-0 only from booting from secondary location ?

    Best Regards,
    Aakash

  • If r5f0-0 failed to load, I intend to boot all the CPUs from secondary location.  However, since r5f1-0 and r5f1-1 are already loaded and running, I'm unable to reload/rerun them from the secondary locations.  Thanks.

  • Hi Peter Pan,

    I need to try the flow as you have requested. Can I request for time till Monday to come back with results ?

    Best Regards,
    Aakash

  • Sure.  Thank you.

  • Hi Peter,

    Can you try a change like this ?

    /*
     *  Copyright (C) 2018-2024 Texas Instruments Incorporated
     *
     *  Redistribution and use in source and binary forms, with or without
     *  modification, are permitted provided that the following conditions
     *  are met:
     *
     *    Redistributions of source code must retain the above copyright
     *    notice, this list of conditions and the following disclaimer.
     *
     *    Redistributions in binary form 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.
     *
     *    Neither the name of Texas Instruments Incorporated nor the names of
     *    its contributors may be used to endorse or promote products derived
     *    from this software without specific prior written permission.
     *
     *  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
     *  "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
     *  LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
     *  A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
     *  OWNER 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 <stdlib.h>
    #include "ti_drivers_config.h"
    #include "ti_drivers_open_close.h"
    #include "ti_board_open_close.h"
    #include <drivers/bootloader.h>
    #include <drivers/hsmclient/soc/am263x/hsmRtImg.h> /* hsmRt bin   header file */
    
    const uint8_t gHsmRtFw[HSMRT_IMG_SIZE_IN_BYTES]__attribute__((section(".rodata.hsmrt")))
        = HSMRT_IMG;
    
    extern HsmClient_t gHSMClient ;
    
    /* call this API to stop the booting process and spin, do that you can connect
     * debugger, load symbols and then make the 'loop' variable as 0 to continue execution
     * with debugger connected.
     */
    void loop_forever(void)
    {
        volatile uint32_t loop = 1;
        while(loop)
            ;
    }
    
    /*  this API is a weak function definition for keyring_init function
        which is defined in generated files if keyring module is enabled
        in syscfg
    */
    __attribute__((weak)) int32_t Keyring_init(HsmClient_t *gHSMClient)
    {
        return SystemP_SUCCESS;
    }
    
    extern Bootloader_FlashArgs gBootloader0Args;
    
    int32_t run_boot(bool isInputPrimary)
    {
        int32_t status = SystemP_FAILURE;
    
        Bootloader_BootImageInfo bootImageInfo;
        Bootloader_Params bootParams;
        Bootloader_Handle bootHandle;
    
        if(isInputPrimary == FALSE)
        {
            gBootloader0Args.appImageOffset = 0x00180000;
        }
    
        Bootloader_Params_init(&bootParams);
        Bootloader_BootImageInfo_init(&bootImageInfo);
    
        bootHandle = Bootloader_open(CONFIG_BOOTLOADER0, &bootParams);
        if(bootHandle != NULL)
        {
            status = Bootloader_parseMultiCoreAppImage(bootHandle, &bootImageInfo);
            /* Load CPUs */
            if((status == SystemP_SUCCESS) && (TRUE == Bootloader_isCorePresent(bootHandle, CSL_CORE_ID_R5FSS1_1)))
            {
                bootImageInfo.cpuInfo[CSL_CORE_ID_R5FSS1_1].clkHz = Bootloader_socCpuGetClkDefault(CSL_CORE_ID_R5FSS1_1);
                Bootloader_profileAddCore(CSL_CORE_ID_R5FSS1_1);
                status = Bootloader_loadCpu(bootHandle, &bootImageInfo.cpuInfo[CSL_CORE_ID_R5FSS1_1]);
            }
            if ((status == SystemP_SUCCESS) && (TRUE == Bootloader_isCorePresent(bootHandle, CSL_CORE_ID_R5FSS1_0)))
            {
                bootImageInfo.cpuInfo[CSL_CORE_ID_R5FSS1_0].clkHz = Bootloader_socCpuGetClkDefault(CSL_CORE_ID_R5FSS1_0);
                Bootloader_profileAddCore(CSL_CORE_ID_R5FSS1_0);
                status = Bootloader_loadCpu(bootHandle, &bootImageInfo.cpuInfo[CSL_CORE_ID_R5FSS1_0]);
            }
            if ((status == SystemP_SUCCESS) && (TRUE == Bootloader_isCorePresent(bootHandle, CSL_CORE_ID_R5FSS0_1)))
            {
                bootImageInfo.cpuInfo[CSL_CORE_ID_R5FSS0_1].clkHz = Bootloader_socCpuGetClkDefault(CSL_CORE_ID_R5FSS0_1);
                Bootloader_profileAddCore(CSL_CORE_ID_R5FSS0_1);
                status = Bootloader_loadCpu(bootHandle, &bootImageInfo.cpuInfo[CSL_CORE_ID_R5FSS0_1]);
            }
            if((status == SystemP_SUCCESS) && (TRUE == Bootloader_isCorePresent(bootHandle, CSL_CORE_ID_R5FSS0_0)))
            {
                bootImageInfo.cpuInfo[CSL_CORE_ID_R5FSS0_0].clkHz = Bootloader_socCpuGetClkDefault(CSL_CORE_ID_R5FSS0_0);
                Bootloader_profileAddCore(CSL_CORE_ID_R5FSS0_0);
                /* Skip the image load by passing TRUE, so that image load on self core doesnt corrupt the SBLs IVT. Load the image later before the reset release of the self core  */
                status = Bootloader_loadSelfCpu(bootHandle, &bootImageInfo.cpuInfo[CSL_CORE_ID_R5FSS0_0], TRUE);
            }
    
            if(status != SystemP_SUCCESS)
            {
                Bootloader_close(bootHandle);
                return status;
            }
    
            Bootloader_profileAddProfilePoint("CPU load");
            Bootloader_profileUpdateAppimageSize(Bootloader_getMulticoreImageSize(bootHandle));
            QSPI_Handle qspiHandle = QSPI_getHandle(CONFIG_QSPI0);
            Bootloader_profileUpdateMediaAndClk(BOOTLOADER_MEDIA_FLASH, QSPI_getInputClk(qspiHandle));
    
            if(status == SystemP_SUCCESS)
            {
                Bootloader_profileAddProfilePoint("SBL End");
                Bootloader_profilePrintProfileLog();
                DebugP_log("Image loading done, switching to application ...\r\n");
                UART_flushTxFifo(gUartHandle[CONFIG_UART0]);
            }
    
            /* Run CPUs */
            if((status == SystemP_SUCCESS) && (TRUE == Bootloader_isCorePresent(bootHandle, CSL_CORE_ID_R5FSS1_1)))
            {
                status = Bootloader_runCpu(bootHandle, &bootImageInfo.cpuInfo[CSL_CORE_ID_R5FSS1_1]);
            }
            if((status == SystemP_SUCCESS) && (TRUE == Bootloader_isCorePresent(bootHandle, CSL_CORE_ID_R5FSS1_0)))
            {
                status = Bootloader_runCpu(bootHandle, &bootImageInfo.cpuInfo[CSL_CORE_ID_R5FSS1_0]);
            }
            if((status == SystemP_SUCCESS) && (TRUE == Bootloader_isCorePresent(bootHandle, CSL_CORE_ID_R5FSS0_1)))
            {
                status = Bootloader_runCpu(bootHandle, &bootImageInfo.cpuInfo[CSL_CORE_ID_R5FSS0_1]);
            }
            if((status == SystemP_SUCCESS) && (TRUE == Bootloader_isCorePresent(bootHandle, CSL_CORE_ID_R5FSS0_0)))
            {
                /* Load the image on self core now */
                if( bootImageInfo.cpuInfo[CSL_CORE_ID_R5FSS0_0].rprcOffset != BOOTLOADER_INVALID_ID)
                {
                    status = Bootloader_rprcImageLoad(bootHandle, &bootImageInfo.cpuInfo[CSL_CORE_ID_R5FSS0_0]);
                }
                /* If any of the R5 core 0 have valid image reset the R5 core. */
                status = Bootloader_runSelfCpu(bootHandle, &bootImageInfo);
            }
    
            /* it should not return here, if it does, then there was some error */
            Bootloader_close(bootHandle);
        }
    
        return status;
    }
    
    int main(void)
    {
        int32_t status;
    
        Bootloader_profileReset();
        Bootloader_socConfigurePll();
        Bootloader_socSetAutoClock();
    
        System_init();
        Bootloader_profileAddProfilePoint("System_init");
    
        Drivers_open();
        Bootloader_profileAddProfilePoint("Drivers_open");
    
        DebugP_log("\r\n");
        Bootloader_socLoadHsmRtFw(&gHSMClient, gHsmRtFw, HSMRT_IMG_SIZE_IN_BYTES);
        Bootloader_socInitL2MailBoxMemory();
        Bootloader_profileAddProfilePoint("LoadHsmRtFw");
    
        status = Keyring_init(&gHSMClient);
        DebugP_assert(status == SystemP_SUCCESS);
    
        DebugP_log("Starting QSPI Bootloader ... \r\n");
    
        status = Board_driversOpen();
        DebugP_assert(status == SystemP_SUCCESS);
        Bootloader_profileAddProfilePoint("Board_driversOpen");
    
        if(SystemP_SUCCESS == status)
        {
            run_boot(TRUE);
        }
        else
        {
            run_boot(FALSE);
        }
    
        if(status != SystemP_SUCCESS )
        {
            DebugP_log("Some tests have failed!!\r\n");
        }
        Drivers_close();
        System_deinit();
    
        return 0;
    }
    

    I have not tested this..  But this will give you an idea how to make the following change ?

    Most of the changes are on the latest SDK development flow. You can remove the changes which you don't require.

    Best Regards,
    Aakash

  • Hi Aakash,

    Thanks for the code example.  This is basically the same QSPI SBL code example I followed with the additon of Keyring_init().  Looking at the code, the secondary image will never be exercised.  Execution will never get to line 192 if status is not success because of DebugP_assert().  For the sake of this discussion, assume status is success and we call run_boot(TRUE).  What happens when line 151 fails?  This is the issue I'm having.  When I corrupt the rprc header for r5f0-0, line 151 fails.  I want to be able to re-loading/re-running all the CPUs so they all run from the secondary image.  I am not able to re-load/re-run r5f1-0 and r5f1-1.  I suspect because the CPUs are out of reset.  The end result is r5f1-0 and r5f1-1 are running with the primary image and r5f0-0 and r5f0-1 are running with the secondary image.  I want to be able to put the CPUs back to a state where I can re-load/re-run all the CPU with secondary image.

    Thanks again for your help.

  • Hi Peter Pan,

    In your case, you would prefer loading the image at the beginning of the run.

    You need to modify this to FALSEThis will ensure that the RPRC is loaded at the beginning only.

    I hope this solves your problem.

    Best Regards,
    Aakash

    PS : Ignore the KeyRing etc. as I have mentioned, I am working on the latest git tip.

  • Hi Aakash,

    I have already tried your suggestion.  IIRC, it did resolve my issue.  However, my concern is the comment right above Bootload_loadSelfCpu().  It implies setting the parameter to FALSE would corrupt the SBLs IVT.  Can you clarify why it is safe to set the parameter to FALSE.  Thanks.

  • Hi ,

    Of course, its not safe to do so. But your requirement is such that you want all the CPUs to be loaded first. In doing so, you will end up corrupting the IVT of the self core as you would be overwriting the same.

    There are 2 options here -

    • Save your IVT data into a scratchpad memory, load the image completely. Now revert the SBL's IVT till the completion of the execution. After the execution is completed, and control needs to be given back to Application for self core, revert the IVT and reset the self core.

    • Modify the rprc_load in the bootloader library -


      Skip loading the IVT location of Application i.e. 0x0 with size 48B and save the same in the SBL scratchpad memory.

      Now, just before the run, you can revert the IVT back to application's IVT which was stored in SBL scratchpad memory.

    I hope this helps.

    Best Regards,
    Aakash

  • Hi Aakash,

    Thanks for the explanation.  My requirement is not to load all the CPUs first.  I would prefer to follow the boot flow of the example QSPI SBL.  I just want to be able to put the running CPUs back into a state where I can reload them upon error without actually doing a reset which would reload the SBL.  Is there functions I can call or registers I can set to accomplish this?  If not, I will have to implement something like what you've suggested.

  • Hi Peter Pan,

    I don't think that would be feasible. Resetting the CPU requires the CPU to be in WFI. Can you ensure in your application that they remain in WFI, till all the CPUs are up ?

    Best Regards,
    Aakash

  • I was hoping to put the CPU in a state where I can reload them without having to reset the CPU.  Looks like it's not feasible.  Not sure what you mean by "ensure in your application that they remain in reset, till all the CPUs are up".  My QSPI SBL basically follows the example  QSPI SBL.  I just added a loop to try to load secondary image upon failure.  In the example QSPI SBL the very last thing it does is to load and run the image for r5f0-0 after other CPUs are loaded and running.  Since this is the boot flow TI recommends, I will keep the same boot flow.  I will either implement something you suggested earlier or extract all the error checking from the load and run functions to make sure the image is good before actually load and run the CPUs.  Thanks.