1

I'm working on a bare-metal embedded system project that aims for low power consumption, and the system memory is divided into two parts: always-on memory and non-always-on memory as depicted below. The always-on memory maintains the minimal system operation, and the non-always-on memory is powered on only when full system operation is needed.

|-------------------------|
|                         |
|   Always-on Memory      |
|                         |
|-------------------------|
|                         |
|   Non-always-on Memory  |
|                         |
|-------------------------|

To match up the hardware architecture, I also divide the firmware into two parts: 1st-stage firmware and 2nd-stage firmware. These two parts are two individual images, that is, they have their own .bss, .text, and .data output sections. The execution flow might be as follows:

  1. The 1st-stage firmware runs initially for minimal system operation
  2. The non-always-on memory is powered on and the 2nd-stage firmware is loaded
  3. CPU jumps to the entry point of the 2nd-stage firmware and continues execution for full system operation
  4. CPU jumps back to the entry point of the 1st-stage firmware for minimal system operation
  5. The non-always-on memory is powered off to reduce power consumption
+-------------------------+
|                         |            +-------------------------+
|   1st-stage firmware    |            |                         |
|   (.bss, .text, .data)  |===========>|   Always-on Memory      |
+-------------------------+            |                         |
                                       +-------------------------+
+-------------------------+            |                         |
|                         |===========>|   Non-always-on Memory  |
|   2nd-stage firmware    |            |                         |
|   (.bss, .text, .data)  |            +-------------------------+
+-------------------------+

This firmware architecture works fine so far, however, it has one main drawback, that is, some functions are common in both minimal and full system operation, and they are duplicated in the 1st and the 2nd stage firmware since they reside in two individual images.

To overcome this drawback, I tried to merge these two individual images into a single one but with two groups of output sections to be loaded into two parts of memory accordingly as depicted below.

+-------------------------+            +-------------------------+
|                         |            |                         |
|   1st-stage firmware    |===========>|   Always-on Memory      |
|(.bss_1, .text_1, data_1)|            |                         |
+-------------------------+            +-------------------------+
|                         |            |                         |
|   2nd-stage firmware    |===========>|   Non-always-on Memory  |
|   (.bss, .text, .data)  |            |                         |
+-------------------------+            +-------------------------+

I left the output section names of the 2nd-stage firmware unchanged since most functions reside in it, and I changed the output section names of the 1st-stage firmware to be .bss_1, .text_1, and .data_1. Almost everything works fine, however, I found there are some symbols in the 1st-stage firmware that I can't change their output section:

  1. Static local variables in function. They seem to be always placed in default .data section even the belonging function is not placed in default .text section. Of course I could move the static local variables to global scope with explicit section attribute declaration. I just want to know if there is any way to assign their output section without modifying the source code.
void __attribute__((section (".text_1"))) func( void )
{
    static int localVar;
    ...
}
  1. Implicit declared identifiers such as __func__. I have no idea at all how to assign its section.
void __attribute__((section (".text_1"))) func( void )
{
    printf("%s", __func__)
    ...
} 

I searched on stackoverflow and found my question is similar to Building a two-part firmware image using GCC toolchain, however the system requirements are not the same or even in contrary. I'd like to know whether or not merging two firmware images into a single one with two groups of output sections is applicable. If yes, how to change the output section of implicit declared identifiers. If no, should I keep the original solution that maintains two firmware images with duplicated functions.

odomchen
  • 45
  • 7
  • "one main drawback, some functions are duplicated in the 1st and the 2nd stage firmware since they reside in two individual images." That doesn't sound like much of a drawback to me, especially relative to the effort/complexity to avoid it. – kkrambo Jun 22 '21 at 21:40
  • The main reason why duplicated functions are regarded as a drawback is that they consume space in both parts of memory, and further they cost more time to be loaded. The 1st-stage firmware is about 100KB, and the 2nd-stage firmware is about 500KB. Maybe 10% functions in the 2nd-stage firmware are duplicated from the 1st-stage firmware. – odomchen Jun 23 '21 at 09:33
  • The other reason is firmware developing and maintaining effort. My colleagues and I have to make sure the modification of common functions is synchronized in both firmware images. – odomchen Jun 23 '21 at 09:38

0 Answers0