在上一篇文章中,我们了解了RT-Thread的版本以及开发环境,使用RT-Thread Studio成功创建了一个工程。
但是要了解一个操作系统,内核的了解是必不可少的,
我们今天就在前面我们RT-Thread Studio工程基础之上讲一讲RT-Thread内核启动流程
.. 更新一个说明,SMP是对多核处理器的支持相关部分 2022/3/15
RT-Thread startup process
1. Basic introduction
The link to the official introduction of the kernel startup process is as follows:
RT-Thread official kernel startup process introduction
In my STM32 column, I have a separate blog post about the startup of STM32:
STM32 startup process (startup_xxxx.s file analysis)
In a bare metal program, generally jump to in the .s file _main
to jump to the main()
function startup, while RT-Thread startup will first jump to its startup function rtthread_startup()
to perform a series of necessary initializations, and finally jump to the main()
function.
Simply put: When the program starts, jump to the RT-Thread startup function rtthread_startup()
(C language) through the startup_xxxx.s file (assembly language), and then rtthread_startup()
jump to the main()
(C language) function through .
The official picture shows this process in great detail:
In RT-Thread, the main()
function is treated as a thread. rtthread_startup()
This will main()
create a thread, and in addition, two threads, a thread and an idle thread , rtthread_startup()
will be created .timer
Combined with the above figure, let's illustrate this process through the sample code created in the previous article.
2. Source code analysis
2.1 Assembly part - startup_xxxx.s description
Open the RT-Thread Studio project, where to find the startup_xxxx.s
file , see the following picture:
We have found the startup file, which can be opened and viewed. The description of the startup file is described in detail in my other blog post.
It has been explained in more detail, here I will only briefly explain the main ones. As mentioned in the recommended blog post above, two files are needed to start the GCC environment, one is a startup_xxxx.s
file and the other is a .ld
link file. Let's take a look at the link file first:
As mentioned before, the link file under GCC mainly formulates the entry function, the stack size and the overall layout of the data segment. In the above image we see that the value defines the size of the system stack and does not define the size of the heap.
Why only define the system stack here?
Although we have said in other blog posts that if you don't use the malloc
function , you don't need to use the heap. There is no definition here because the size of the heap will be defined according to whether the heap is used or not during the initialization later.
Instructions are described in the panel-level hardware initialization section below this document.
Then simply take a look at the startup_xxxx.s
file . First, we find the first command to be executed when the power is turned on Reset_Handler
(the chip is powered on, it is a power-on reset, and it will trigger directly Reset_Handler
):
If you don't understand the operations in the above figure, you can view the blog post:
Memory management related to STM32 (memory architecture, memory management, map file analysis)
After the data transfer is completed, it is the basic initialization of the system, as shown in the figure below:
After the basic initialization is completed, the MCU can run, and then jump to the entry function mentioned in our basic introduction above, as shown in the figure below:
Through the above steps, finally from . The assembly in s jumps to the C language part, and jumps to the rtthread_startup
function . We will explain what rtthread_startup
RT-Thread does after entering the function through the following introduction.
2.2 Section C - rtthread_startup Description
In the basic introduction in the first section of this article, an official picture shows the rtthread_startup
operations that will be performed after entering. We also explained how the project enters the rtthread_startup
function , and rtthread_startup
what operations are performed after entering the function, as shown in the following figure:
Supplement Description: The SMP in the above figure is related to the settings related to multi-core processors.
The above process is easy to understand. The main tasks are as follows:
1. Basic hardware initialization;
2. The main thread will be created;
3. Create a timer thread according to whether a software timer is used;
4. An idle thread will be created;
5. Initialize the scheduler;
There are some initializations that we can take a closer look at the specific operations:
2.2.1 Board Hardware Initialization - rt_hw_board_init
rt_hw_board_init
Hardware-related initialization is performed using the function, as shown below:
2.2.2 RT-Thread Heap and Stack Space Description (different from FreeRTOS)
In the above picture, there is something special, that is, the initialization of the heap space. What we have encountered before is to define the stack space in the startup file. When we analyzed the RT-Thread startup file above, we only defined the stack space. , the heap space is not defined, it is actually placed in this place :
At the beginning, there was still a question here. HEAP uses all the remaining RAM. According to the previous understanding, the system stack should be in the last position. What is going on here?
Regarding the position of the system stack, you can refer to the blog post: RTOS task stack and system stack
The conclusion we saw through the source code above is different from what this blog post said (the bare metal and FreeRTOS were used as examples at that time), and then under RT-Thread, where is the position of the system stack, so I looked back Look at the link file that defines the overall layout of the data segment:
through the link file we can infer the location of the .stack, so to confirm, we can view the .map file after the program is compiled:
In the RAM data segment, we can view the location where the data is stored and find the location part about the system stack:
It is confirmed that in RT-Thread, the position of the system stack is indeed stored between the .data segment and .bss, so there is no problem even if the heap space uses all the remaining ram space.
2.2.3 main thread creation - rt_application_init
In RT-Thread, "main"
a to call main()
the function, which is in the rtthread_startup
function rt_application_init()
, as shown below:
2.2.4 Scheduler Description
The scheduler is the core knowledge of the operating system. The scheduler operates based on the linked list. The specific principle will be described in a separate article in the future. Here we will briefly go over it and know the purpose of the function.
In the rtthread_startup
function, use the rt_system_scheduler_init();
initialization scheduler, rt_system_scheduler_start();
turn on the scheduler, and after the scheduler is turned on, the threads will switch according to certain rules (time slice, priority):
After the scheduler is turned on, the thread with the highest priority will be found in the ready list, and then jump to the corresponding position to execute by setting the thread pointer (PSP):
What does the thread pointer mean, you can refer to the blog post: FreeRTOS record (3. Analysis of the principle of FreeRTOS task scheduling _Systick, PendSV, SVC)
At this point, the whole system runs normally, and then the user runs what he wants to do, he can design his own application code in the main, or create a thread.