Microcontroller simulates Linux automatic initialization process

Follow+Starred PublicNo., don’t miss exciting content

4f147cd514abbf9c9d9225f9549150fd.gif

Source | Embedded Hodgepodge

Usually when we write programs, we follow this routine. Function after function is executed one by one according to sequential logic.

b140c90216f36c4dccf3991078069967.jpeg

If the logic is very complex and involves many modules, then the code executed sequentially will be bloated and the modules will be very tightly coupled. There are various peripheral drivers in the Linux kernel, and it is almost impossible to execute them logically in a sequence.

The kenrel code can have such a large amount of code, it is large but not messy, it effectively separates each level and each module, and a large amount of code is logically organized together, and this initcall plays a vital role.

By imitating this method, we finally clear the main function code in the picture, separate this logic, and achieve the same function.

How to implement such a function requires some background knowledge:

1. Organization of program code

2. Knowledge related to link scripts.

3. Application of function pointers.

8ee3f141c349db61ecf1b665b50589ee.jpeg

1. The organization of the code. For example, in the picture, you need to know which sections of the program the variables a, b and function pointers f and f2 are stored in. You can take a look at this stm32 startup code implementation | C language. The above a and f are all Stored in the bss segment, b, f2 are stored in the data segment, because the initial value has been given, and implementing this intcall will put the data that needs to be automatically initialized into a custom segment, such as .initcall.

How to put it in a specific section, you need to use the attribute((section)) keyword to change the data storage section.

The current program is compiled using these segments. Except for .isr_vector, which is also added, the others are the default ones of the compiler.

02101744ba478ddf83ae8129672e5f71.png

First add some code:

3bafdec496cc5305f7011f3bf77a5e81.png

Of course, this is not enough. You also need to tell the linker (LD) to link the .initcall section into the program, so this section also needs to be modified.

4ee981173b2f1f24508d86b96606ef75.jpeg

This section is aligned by 8 bytes, two global variables are defined, and these data are linked in order 0-5. With these two modifications, let's take a look at each section of the program.

As picture:

e5850e74a3933ffea46dcd1bc3e3102e.png

There is an extra red box for the .initcalls section. This section is 8 bytes in total, starting from 0x80005a8.

Let's take a look at the specific situation of this paragraph, using the readelf tool.

d2f15f2be6b4bace73e94ec2aa198359.png

It matches the size tool above, and the address of the green box is SystemInit (0x08000231, little endian mode.)

cf5acabcb2d863f52785b898681a425e.png

So through attribute and modifying the link script, the function pointer variable is placed in the .initcall section.

So how to call this function is similar to the previous initialization data segment data. It traverses this segment, then takes out the function address, and then forcibly converts the address in the segment into a function pointer, and then calls it directly.

6c6accc5f749cae2ae7b7aeed522d05c.png a1b32c603bf711b9ac6d2918777eb84b.png

The picture implemented is to take the function address from the .initcall section and then call it directly. It is very easy to confuse the address of the function with the address of the function pointer variable.

With the code modified like this, the automatic initialization function can indeed be adjusted, but every time I have to write such a long section of static initcall_t __ attribute__(( __ used__,__ section__(".initcall.0.init"))), that is Uncomfortable. Modified through macros in the Linux kernel.

Same goes for this one.

53d04746a28f9b0a3b539a25cf8e825a.png

Add some macros that are executed in the logical order of the program

0, low_level_init, such as initializing the system basic clock

1. arch_init, for example, put some initialization of the CPU architecture such as initializing NVIC.

2. dev_init initializes peripheral modules, such as i2c, flash, spi, etc.

3. board_init makes some settings for specific hardware boards.

4. Some settings of os_init operating system, such as file system, network protocol stack, etc.

5. app_init finally runs the user program.

Modify your own program and use macros instead. In this way, the call to do_initcalls will be executed in the order of 0, 1-to 5.

1ee37af4ddd1d682960efd09f5fa403d.png e16a9664417816d8fb3e258a34e58e1a.png

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

f46b7f757633e81c6e7153040215eb45.png 7705de425e5370246b724895cf759978.png 8da8e2b9597cd8391983dcf53b77ea21.jpeg 0f9db6626c93de0e0dacc0d8d79b6acc.jpeg

In this way, just add something like dev_init(), app_init() to the automatic initialization function, and it will be called automatically, without the need to execute them one by one in the main function.

For example, the initialization of i2c control is placed in dev_init. There are many i2c slave devices hanging below. You only need to initialize each slave device with app_init. Even if a new one comes, just use this app_init to initialize it. There is no need to change the original one. , a high degree of coupling between separated modules.

In this way, Linux kenerl is simulated, initialization and verification are successful, and finally uploaded to the library.

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

If you are interested, you can take a look, follow and forward.

Original text: https://www.toutiao.com/a6906858875912307203/?log_from=16f51be0430a9_1647178471075

Statement:The material of this article comes from the Internet, and the copyright belongs to the original author. If there is any copyright issue with the work, please contact me to delete it.

------------ END ------------

d1dade8d2e370d9994231b81af498962.gif

●Column "Embedded Tools"

●Column "Embedded Development"

●Column "Keil Tutorial"

●Embedded column selected tutorials

Follow the public account and reply "Join the group" Join the technical exchange group according to the rules and reply "1024 " See more.

9cf3a14f14fc96031907535fc9fe40e2.jpeg

7dde13dc19089b7ce4c3b9c901af65a8.png

Click "Read the original text" to view more shares.

Guess you like

Origin blog.csdn.net/ybhuangfugui/article/details/135007758