[SOLVED] Boot Different Partition from Application

chrismerck
Posts: 50
Joined: Tue May 29, 2018 8:00 pm

[SOLVED] Boot Different Partition from Application

Postby chrismerck » Mon Aug 27, 2018 1:26 pm

In my product, we have modified 2nd Stage Bootloader to always boot Factory. Then, the Factory image will wait a few seconds for a reset signal over network, then looks at otadata to decide which image to boot (or to stay in factory). --- The reason for this is, we want a way to recover from a bad firmware remotely --- this product does not have any user-accessible GPIOs.

I intend to use esp_ota_get_boot_partition() and then esp_image_verify(), but the missing piece is, I don't know an ESP API to boot a specified OTA image from application context.

I'm looking for something similar to the booloader_support functions bootloader_utility_load_boot_image() or load_image() which can be called from the full application.

I could try to pull pieces of bootloader_support into my application to get those functions working, but I expect to run into trouble given FreeRTOS running and other configuration that ESP-IDF performs.

Please advise.
Last edited by chrismerck on Wed Oct 24, 2018 4:01 pm, edited 1 time in total.

chegewara
Posts: 852
Joined: Wed Jun 14, 2017 9:00 pm

Re: Boot Different Partition from Application

Postby chegewara » Mon Aug 27, 2018 1:46 pm


ESP_igrr
Posts: 1521
Joined: Tue Dec 01, 2015 8:37 am

Re: Boot Different Partition from Application

Postby ESP_igrr » Mon Aug 27, 2018 3:06 pm

Storing a pointer to the desired partition in RTC memory and rebooting to let the bootloader load that partition is probably going to be the easiest way.

Indeed loading new application from a running application may be complex, as you need to make sure that the code that does the loading, stack, and any .data/.bss that the loading code needs do not overlap with the application being loaded. In bootloader this is achieved by using a special linker script. It places the .text section of the code needed to do the loading operation into the space normally used by APP CPU instruction cache. In your factory application this is probably going to be harder to achieve...

Ritesh
Posts: 1101
Joined: Tue Sep 06, 2016 9:37 am
Location: India
Contact:

Re: Boot Different Partition from Application

Postby Ritesh » Mon Aug 27, 2018 5:35 pm

ESP_igrr wrote:Storing a pointer to the desired partition in RTC memory and rebooting to let the bootloader load that partition is probably going to be the easiest way.

Indeed loading new application from a running application may be complex, as you need to make sure that the code that does the loading, stack, and any .data/.bss that the loading code needs do not overlap with the application being loaded. In bootloader this is achieved by using a special linker script. It places the .text section of the code needed to do the loading operation into the space normally used by APP CPU instruction cache. In your factory application this is probably going to be harder to achieve...
But, If we set firmware location partitiona into partition tables then can't it be easily manage using get boot firmware partition and set boot firmware partition APIs?

I think most of application developer are using OTA component to do that type of portion.
Regards,
Ritesh Prajapati

chrismerck
Posts: 50
Joined: Tue May 29, 2018 8:00 pm

Re: Boot Different Partition from Application

Postby chrismerck » Mon Aug 27, 2018 7:36 pm

ESP_igrr wrote:Storing a pointer to the desired partition in RTC memory and rebooting to let the bootloader load that partition is probably going to be the easiest way.
Thanks! We will give that a try. Should be easy to accomplish with one if-statement in a customized bootloader.

chrismerck
Posts: 50
Joined: Tue May 29, 2018 8:00 pm

Re: Boot Different Partition from Application

Postby chrismerck » Wed Oct 24, 2018 4:01 pm

Here's the solution we ended up using:

1. create a header file called xesp_rtc_defs.h which is shared between a custom bootloader component and our app. I've pasted the whole contents at the end of this post.

2. Use deepsleep instead of reboot from app, to preserve RTC mem.

3. When we want to use the OTA data partition, our app does XESP_RTC_ARM_REC(XESP_RTC_REC_USE_OTA) before deepsleep.

4. Bootloader checks XESP_RTC_IS_ARMED(XESP_RTC_REC_USE_OTA). If false, then it overrides boot_index, setting to -1 to cause factory to be forced.

5. Crucially, bootloader does XESP_RTC_SPEND_REC(XESP_RTC_REC_USE_OTA) before booting app, so that the USE_OTA signal is only obeyed once.

---

Header:

Code: Select all

#pragma once

#include <stdint.h>
#include <inttypes.h>

/********
 * RTC Slow Memory Allocation
 ********/

/*
 *  We use RTC slow memory, one 32-bit word at a time,
 *  starting at the end of the 8kB region,
 *  because if we ever want to run a ULP program,
 *  it will need to be in the beginning of this region.
 */

/** signal to bootloader to obey otadata partition */
#define XESP_RTC_REC_USE_OTA     0x50001FFC


/********
 * RTC Slow Memory Constants
 ********/

/** load this value into a record to arm it */
#define XESP_RTC_REC_CONST_ARMED 0x1BADBABE

/** set this value in a record after it has been spent */
#define XESP_RTC_REC_CONST_SPENT 0x2BADBABE


/********
 * Macros
 ********/

#define XESP_RTC_READ_REC(rec)   (*((uint32_t*)(rec)))
#define XESP_RTC_IS_ARMED(rec)   (XESP_RTC_READ_REC(rec) == XESP_RTC_REC_CONST_ARMED)
#define XESP_RTC_ARM_REC(rec)    (*((uint32_t*)(rec))=XESP_RTC_REC_CONST_ARMED)
#define XESP_RTC_SPEND_REC(rec)  (*((uint32_t*)(rec))=XESP_RTC_REC_CONST_SPENT)


jerome
Posts: 37
Joined: Wed Jan 23, 2019 2:28 pm

Re: [SOLVED] Boot Different Partition from Application

Postby jerome » Mon Mar 18, 2019 10:30 am

Hi
I'm thinking about using a similar approach to define from which partition the device should boot.
Those two defines are arbitrary values you decided to use ?

#define XESP_RTC_REC_CONST_ARMED 0x1BADBABE
#define XESP_RTC_REC_CONST_SPENT 0x2BADBABE

Would it be possible to share the code that handles those booting approach from your custom bootloader (I guess you override the espressif bootloader), as well as the code from your factory app and main app ?

Thanks
Jerome

chrismerck
Posts: 50
Joined: Tue May 29, 2018 8:00 pm

Re: [SOLVED] Boot Different Partition from Application

Postby chrismerck » Thu Jun 06, 2019 1:42 pm

Hi Jerome,

So I'm late, but better late than never?
Those two defines are arbitrary values you decided to use ?
Yes, they are essentially arbitrary.

Values to avoid are 0x0, 0xFFFFFFFF, 0xCCCCCCCC, and 0x55555555, since those may be default conditions.

The 1/2BADBABE is chosen because it is immediately recognizable on a terminal as pseudo-english.

the code that handles those booting approach from your custom bootloader
It's a closed-source project, but I can share some pointers.

Yes, we override the bootloader component.

We modify bootloader_start.c to read from RTC and then manipulate `boot_index` variable to -1 if we want to force booting from factory image, rather than OTA.
the code from your factory app

Code: Select all

void Osal_Reboot()
{
  SysUser("Rebooting NOW!");
  Osal_Sleep_Ms(100);
  /* Leave the RTC slow memory powered during deep sleep.
     Without this, we get corruption and a bootloop */
  esp_sleep_pd_config(ESP_PD_DOMAIN_RTC_SLOW_MEM, ESP_PD_OPTION_ON);
  /* We do not use esp_restart() because that would cause RTC mem to be init */
  /* WARNING: ESP-IDF docs warn that we should shutdown WiFi + BLE prior to
     calling esp_deep_sleep. However, we are not doing that... */
  esp_deep_sleep(1000 /* 1 ms */);
  /* never reaches here */
  while (1); /* just in case */
}

Who is online

Users browsing this forum: roland and 25 guests