Simulating Linux Kernel Automatic Initialization on STM32

Hello everyone, I would like to recommend an article by my friend, the mixed bag master.

There are many programming ideas to learn in Linux, and many experts apply these ideas and mechanisms to microcontroller programming.

For example: cola_os introduced in the Embedded Mixed Bag Weekly | Issue 4, and the well-known RT-Thread.

Also, the code from the roof sparrow:

Simulating Linux Kernel Automatic Initialization on STM32
Simulating Linux Kernel Automatic Initialization on STM32

This time, I am sharing an article: STM32 Simulating the Linux kernel automatic initialization process, which is also mentioned in the Embedded Mixed Bag Weekly | Issue 4. You can read the original article at the end. Here is the original text:

Usually, when we write programs, we follow this routine, executing one function after another in logical order.

Simulating Linux Kernel Automatic Initialization on STM32

If the logic is very complex and involves multiple modules, then this sequential execution code can become bloated, with tightly coupled modules. In the Linux kernel, there are various peripheral drivers, and it is almost impossible to execute them in a sequential logical order.

The kernel code has such a large amount of code, yet remains organized, effectively separating different layers and modules, while a large amount of code is logically organized together. This is critically important to the initcall mechanism.

By mimicking this approach, we can finally clear the main function code shown in the image, separate this logic, and achieve the same functionality.

To achieve such functionality, some background knowledge is required:

1. Organization of program code

2. Knowledge related to linker scripts.

3. Application of function pointers.

Simulating Linux Kernel Automatic Initialization on STM32

The organization of code, as shown in the image, requires knowing where the variables a, b, and function pointers f, f2 are stored in the program. You can refer to this article on STM32 startup code implementation|C language, where a and f are stored in the bss segment, while b and f2 are stored in the data segment, because they have been given initial values. The initcall mechanism will place the data that needs to be automatically initialized into a custom segment, like .initcall.

To place it into a specific segment, we need to use the attribute((section)) keyword to change the data storage segment.

Currently, the program compiled uses these segments, besides .isr_vector which is also added, the others are defaults from the compiler.

Simulating Linux Kernel Automatic Initialization on STM32

First, add segment code:

Simulating Linux Kernel Automatic Initialization on STM32

Of course, this is not enough; we also need to tell the linker (LD) to link the .initcall segment into the program, so this part also needs modification.

Simulating Linux Kernel Automatic Initialization on STM32

This segment is aligned to 8 bytes, defining two global variables, and linking these data in the order of 0-5. After these two modifications, let’s take a look at the situation of each segment of the program.

As shown in the image:

Simulating Linux Kernel Automatic Initialization on STM32

The red box indicates the .initcalls segment, which is a total of 8 bytes, starting from 0x80005a8.

Now, let’s take a look at the details of this segment using the readelf tool.

Simulating Linux Kernel Automatic Initialization on STM32

And the size tool above matches, while the green box address is SystemInit(0x08000231, little-endian).

Simulating Linux Kernel Automatic Initialization on STM32

Thus, through attributes and modifying the linker script, we have placed the function pointer variable into the .initcall segment.

Now, how to call this function is similar to how we initialized the data segment, by traversing this segment, extracting the function address, forcibly converting the address in the segment into a function pointer, and then calling it directly.

Simulating Linux Kernel Automatic Initialization on STM32
Simulating Linux Kernel Automatic Initialization on STM32

The implementation shown in this image extracts the function address from the .initcall segment and calls it directly, which makes it very easy to confuse the function address with the address of this function pointer variable.

Modifying the code like this allows us to automatically initialize functions, but writing such a long static initcall_t __ attribute__(( __ used__,__ section__(“.initcall.0.init”))) every time is not comfortable. The Linux kernel uses macros to modify this.

This is the same.

Simulating Linux Kernel Automatic Initialization on STM32

Add some macros for executing in logical order of the program:

0. low_level_init, for initializing the basic system clock.

1. arch_init, for CPU architecture initialization, such as initializing NVIC.

2. dev_init, for peripheral module initialization, such as i2c, flash, spi, etc.

3. board_init, for specific hardware board settings.

4. os_init, for operating system settings like file systems, network protocol stacks, etc.

5. app_init, to run user programs last.

Modify your own program using macros instead. This way, calling do_initcalls will execute in the order of 0, 1 to 5.

Simulating Linux Kernel Automatic Initialization on STM32
Simulating Linux Kernel Automatic Initialization on STM32

Finally, let’s take a look at the initcall segment:

Simulating Linux Kernel Automatic Initialization on STM32
Simulating Linux Kernel Automatic Initialization on STM32
Simulating Linux Kernel Automatic Initialization on STM32
Simulating Linux Kernel Automatic Initialization on STM32

Thus, as long as you add something like dev_init(), app_init() to the functions that require automatic initialization, they will be automatically called, without needing to execute them one by one in the main function.

For example, the initialization of i2c control can be placed in dev_init, and many i2c slave devices can be initialized using app_init, even if a new device is added, it can be initialized using app_init without changing the original code, greatly reducing the coupling between modules.

Thus, simulating Linux kernel initialization has been successfully validated, and the library is finally available.

https://gitee.com/android_life/stm32_freertos_opensource/tree/master/bareos/initcall

If you’re interested, you can take a look and follow along.

Copyright Statement:This article is sourced from the internet, freely conveying knowledge, and the copyright belongs to the original author. If there are any copyright issues, please contact me for deletion.

Simulating Linux Kernel Automatic Initialization on STM32

Simulating Linux Kernel Automatic Initialization on STM32

Leave a Comment

×