Bootstrap
people who have experience in installing computer systems know the concept of BIOS. Little friends who have brushed Android phones have heard of Bootloader. What is the relationship between these concepts and mobile phone startup?
first of all, the operating system does not start directly when the computer or mobile phone is turned on. It helps to start the operating system through the boot program. For the computer, the BIOS plays this function, and for the mobile phone, the Bootloader plays this important role. Some people may wonder why the boot of computers and mobile phones does not directly start the operating system, but needs to be assisted by boot programs. This is mainly determined by the current hardware structure. As we all know, both computer and mobile phone operating systems run in RAM, and ram cannot run programs until it is powered on without certain initialization. Therefore, before ram runs the operating system, a program is needed to complete the corresponding initialization. This arduous task is handed over to the boot program.
how does the boot program work? When the system is powered on, The CPU will read the first line of running code from a fixed location according to the configuration (e.g. configuration from EMMC/SDCARD, etc.), where the boot program is stored. After the boot program is running, carry out necessary (minimum) initialization (e.g. clock, MMU, etc.), and move the operating system stored in ROM to a location in RAM (decompression may also be involved), and then the boot program will transfer control to the operating system in RAM and start the operating system.
First instruction of operating system
from the above analysis, as long as you find the first instruction (statement) of the operating system, you can follow this clue to clarify the startup process. The link file (key statement) compiled by Hongmeng image is as follows:
// ~/kernel/liteos_a/tools/build/liteos_llvm.ld ENTRY(reset_vector)
that is, the entry function of Hongmeng image is reset_vector. The definition of this function is as follows:
// ~/kernel/liteos_a/arch/arm/arm/src/startup/reset_vector_up.S reset_vector: //Necessary initialization ...... bl main .....
Including (the same below):
- "..." represents the omitted code that interferes with the logic of the subject
- The content after the first line / / represents the source file of the code segment
The world of C language
we have entered the familiar C language environment since the main function. Its main work can be explored from the following code.
# ~/kernel/liteos_a/platform/main.c main() OsSetMainTask(); // one OsCurrTaskSet(OsGetMainTask()); //Writes the information of the current task to the register ...... OsSystemInfo(); //Print system information ...... uwRet = OsMain(); // two ...... OsStart(); // three while (1) { __asm volatile("wfi"); }
from the above code segment, we can see that the main function mainly does three aspects. Next, we will start the process analysis from this function.
Step 1: OsSetMainTask()
// ~/kernel/liteos_a/kernel/base/core/los_task.c LITE_OS_SEC_BSS STATIC LosTaskCB g_mainTask[LOSCFG_KERNEL_CORE_NUM]; OsSetMainTask() ... for (i = 0; i < LOSCFG_KERNEL_CORE_NUM; i++) { g_mainTask[i].taskStatus = OS_TASK_STATUS_UNUSED; g_mainTask[i].taskID = LOSCFG_BASE_CORE_TSK_LIMIT; g_mainTask[i].priority = OS_TASK_PRIORITY_LOWEST; #if (LOSCFG_KERNEL_SMP_LOCKDEP == YES) g_mainTask[i].lockDep.lockDepth = 0; g_mainTask[i].lockDep.waitLock = NULL; #endif ret = memcpy_s(g_mainTask[i].taskName, OS_TCB_NAME_LEN, name, strlen(name)); if (ret != EOK) { g_mainTask[i].taskName[0] = '\0'; } LOS_ListInit(&g_mainTask[i].lockList); } ...
from the code of OsSetMainTask(), you can clearly see that loscfg is initialized in this function_ KERNEL_ CORE_ Num LosTaskCB, This LosTaskCB array is used to record the Control Block of tasks in the current system, including priority, status, flag ID, lock status, etc. you can know a little according to the name. The LOSCFG_KERNEL_CORE_NUM variable is generally selected and numeric according to the master chip. For modification, refer to relevant documents, not the key information for starting the process.
Step 2: OsMain()
the main code of OsMain() function is as follows:
// ~/kernel/liteos_a/kernel/common/los_config.c OsMain() osRegister(); ...... OsExcInit(); OsTickInit(); ...... ret = OsTaskInit(); ...... ret = OsIpcInit(); ...... OsSysMemInit(); ...... SyscallHandleInit(); ....... ret = OsKernelInitProcess(); //1 ...... ret = OsSystemInit(); //2 ...... ret = OsFutexInit(); ...... ret = OomTaskInit();
&esmp; As can be seen from the process of OsMain() function, the following work is done in sequence during startup:
- register
- abnormal
- Clock
- OsTaskInit
- Interprocess communication
- Memory
- OsKernelInitProcess
- System initialization
- wait
we will not analyze all these initialization work, but focus on the system initialization function ossysteinit, because many important tasks later are derived from this function.
System initialization ossysteinit function
// ~/kernel/liteos_a/kernel/common/los_config.c UINT32 OsSystemInit(VOID) { UINT32 ret; #ifdef LOSCFG_FS_VFS los_vfs_init(); #endif #ifdef LOSCFG_COMPAT_LINUXKPI g_pstSystemWq = create_workqueue("system_wq"); #endif ret = OsSystemInitTaskCreate(); // (1) if (ret != LOS_OK) { return ret; } #ifdef LOSCFG_MEM_RECORDINFO ret = OsMemShowTaskCreate(); if (ret != LOS_OK) { PRINTK("create memshow_Task error %u\n", ret); return ret; } PRINTK("create memshow_Task ok\n"); #endif #ifdef LOSCFG_KERNEL_TICKLESS LOS_TicklessEnable(); #endif return 0; }
in the system initialization function ossysteinit, except for the ossysteinittaskcreate() function, other functions have macro defined switches, that is, the functions contained in these macro definitions are some "extended" features of the system, which are not necessary. So we can focus on the ossystemitaskcreate() function. Next, enter the analysis of the ossystemitaskcreate() function.
// ~/kernel/liteos_a/kernel/common/los_config.c STATIC UINT32 OsSystemInitTaskCreate(VOID) { UINT32 taskID; TSK_INIT_PARAM_S sysTask; (VOID)memset_s(&sysTask, sizeof(TSK_INIT_PARAM_S), 0, sizeof(TSK_INIT_PARAM_S)); sysTask.pfnTaskEntry = (TSK_ENTRY_FUNC)SystemInit; // ① sysTask.uwStackSize = LOSCFG_BASE_CORE_TSK_DEFAULT_STACK_SIZE; sysTask.pcName = "SystemInit"; sysTask.usTaskPrio = LOSCFG_BASE_CORE_TSK_DEFAULT_PRIO; sysTask.uwResved = LOS_TASK_STATUS_DETACHED; #if (LOSCFG_KERNEL_SMP == YES) sysTask.usCpuAffiMask = CPUID_TO_AFFI_MASK(ArchCurrCpuid()); #endif return LOS_TaskCreate(&taskID, &sysTask); }
create a task named SystemInit in the ossystemicinittaskcreate() function. The entry function of this task is specified through the pfnTaskEntry attribute and points to the entry address of the function SystemInit(). The specific implementation of this function is in the vendor directory, that is, for each different product, the operation steps required for system initialization are different.
next, let's take a look at the specific operations performed by the function SystemInit(). The execution code of this function is as follows:
// ~/vendor/st/stm32mp157/board/board.c SystemInit() ProcFsInit(); mem_dev_register(); imx6ull_driver_init(); imx6ull_mount_rootfs(); DeviceManagerStart(); //HDF, load the driver to make the external shooting work normally. uart_dev_init(); ...... OsUserInitProcess();
in this function, there are two functions that play a key role in the analysis of subsequent processes, DeviceManagerStart() and osurinitprocess(). Their functions are:
- DeviceManagerStart(): code used to start Hongmeng driver framework (HDF).
- Osurinitprocess(): starts the initt process, which is similar to the init process in linux.
Step 3: OsStart()
// ~/kernel/liteos_a/kernel/common/los_config.c LITE_OS_SEC_TEXT_INIT VOID OsStart(VOID) { LosProcessCB *runProcess = NULL; LosTaskCB *taskCB = NULL; UINT32 cpuid = ArchCurrCpuid(); OsTickStart(); LOS_SpinLock(&g_taskSpin); taskCB = OsGetTopTask(); // Get the top Task runProcess = OS_PCB_FROM_PID(taskCB->processID); runProcess->processStatus |= OS_PROCESS_STATUS_RUNNING; #if (LOSCFG_KERNEL_SMP == YES) /* * attention: current cpu needs to be set, in case first task deletion * may fail because this flag mismatch with the real current cpu. */ taskCB->currCpu = cpuid; runProcess->processStatus = OS_PROCESS_RUNTASK_COUNT_ADD(runProcess->processStatus); #endif OS_SCHEDULER_SET(cpuid); PRINTK("cpu %d entering scheduler\n", cpuid); OsStartToRun(taskCB); }
the OsStart() function first obtains the top task, and then runs the task. The function OsStartToRun()s is implemented in a foreign language/ kernel/liteos_a/arch/arm/arm/src/los_dispatch.S.
so far, Hongmeng system has fully taken control from the boot program, started the service framework of the driver, and started the first process init in the user space. Through the init process, other processes required by the user can be "incubated".