Demystifization of the Kernel Boat Sequence: From 'Start Kern ...' to Userspace ' Demystifization of the Kernel Boat Sequence From Start Kern to


As a kernel developer, we often write devices drivers – code pieces that are normally registered with use module_init() in Linux kernel. But ever have a break to ask yourself: How late This happens in the boot process? What exactly fits between the moment we see the famous one "Starting kernel..." Message and the point where the drivers are finally registered and devices are examined?

If you are curious about the complicated steps that occur before the system even works init Process, they are in the right place. Visit us while examining the fascinating journey of the Linux Kernel -Boat sequence.

In this article you will find Clicking on the left To our Elixir source code browser. We encourage you to get in and dive!

Where everything begins

The very first steps are extremely architectural -specific and written in the meeting. If we use the example of a 32-bit processor with the arm, the kernel is compressed, but is prepared with a small uncompressed part, which is responsible for the ignorance of the rest of the binary duration in the right place in the RAM. The entire file is called zImageAnd the entry point comes from a file called called Arch/arm/boat/compressed/head.s. If you would like further details about this decompression step, you can read the excellent reading How the ARM32 Linux core is decompressed Article by Linus Walleij.

As soon as the kernel code is present (here we talk about the .text Area) we jump and begin to carry out the “real” part of the kernel. This happens in another assembly file, Arch/Arm/Kernel/Head.s. At that time the MMU is deactivated; Only a few basic checks regarding the MMU and the condition of the cache are carried out together with some very fundamental checks. The very first one Side tables Are created – just enough to get the kernel up to running – which means Assignment of the kernel code. A little more MMU initialization is required to carry out real code. This is done in another file contained at the end of the head.S File. You can also read here if you are interested in further details about the ARM32 -specific initialization How the ARM32 core begins Article, also by Linus Walleij.

The magical point is right there, just a few lines later: We branch to start_kernel()This is the first C function. It is also the first generic code that is not architecture -specific.

The feeling of going through This immense iterative function is that there is a lot to initialize – and in the correct order. All of the functions linked below are somehow called from here, and going through this article leads the reader through the main steps. Reading the code is probably the best approach to fully understand it. However, let’s start the most important parts.

Of course, there are of course under the important functional calls The pressure of the Linux bannerquickly followed by setup_arch()probably One of the most important functions Here, and what gets back into architecture -specific code.

Back to the architecture -specific code

In arm’s setup_arch() We carry the implementation through Identification of the machine (through the DTB or tags) and The call the cmdline.

In order to access basic hardware and carry out early memory assignments, it is also necessary to create a few early license plates. These are used for early E/O mapping over The creation of a table of fixed size Contains a list of slots that are ready to be freezed. At this stage the usual memory of allocators and assignment functions (such as kmalloc() or ioremap()) are not available. Instead, the kernel offers early alternatives that are called early_malloc() And early_ioremap()that are more limited.

The cmdline Then get analyzed.

Next comes a more advanced MMU configurationWith the introduction of page table management, the creation of some kernel assignments and the reservation of certain memory areas, which are used for future kernel assignments and for those Continuous Memory Allocator (CMA). Finally the MMU is configured In the state that we all know when we run kernel or even user space code, ie. With a kernel mapping at the top and a custom space below. This is also when the Early memory runs if necessary. If you are more interested in how the memory is set up on ARM 32-bit, we recommend again article by Linus Walleij: ARM32 -side tablesPresent Setting up the ARM32 architecture, part 1Present Setting up the ARM32 architecture, part 2.

In the arm housing the device truck receives unshakablePresent The PSCI interface startedPresent Platform-specific SMP initialization is also carried out and possible to end the architecture -specific section machine -specific recall can run (if intended).

Generic Init steps

Back to our init/main.c File, do numerous steps, such as Put the cmdlineinitialize Formerly random generator poolActivate Kernel Memory Allocators (The side allocator, the plate ballocator, kmalloc() And vmalloc()) Together with the main memory and tracers (ftracePresent kfencePresent kmemleakPresent kasan), Start ftrace And trace_printk()Present The SchedulerAnd various components of a modern core, such as radix trees, maple trees, workqueuesPresent RCU than later more disinfectants and tracers, such as lockdepPresent perf

So far we have run without IRQs, which obviously needs be implemented At some point allow the configuration of at the same time softirqs And hrtimersenable yourself to have time.

Only now, The system console Is initialized!

Under the remaining steps, some are probably worth pointing out how the Calibration of the delay loop With their estimate of the number of CPU cycles during waste during waste udelay() Calls, one last call for “Late” scorchitecture -specific CPU initialization and controlsThe preparation of the first fork() System call with z. The creation of a record cache for saving thread descriptors ((struct task_struct), The VFS Initialization (virtual file system) and the Creation of procfs.

If the kernel has to pause the booting procedure, Waiting for a debugger to connect to kgdbIt is shortly before the events VFS Init.

This long init sequence ends with The following comment:

/ * Do not do the rest -__ init’ed, we are now alive *//

Which means that it is time to initialize “The rest” (ensure We make another kernel thread for it To avoid problems when starting the Init process). The CPU system has started all, the memory management is ready for operation and the Scheduler is ready: We can now be able to handle.

Activate hardware

It’s finally time too Activate the driver modelfrom Instantiating devtmpfsCreate so many ksets And kobjects as needed (1) (2) (3)The most basic population sysfs Entries and Register the platform bus.

While we populate virtual file systems, procfs Is also populated with some values ​​already available, e.g. The list of registered interrupts.

One of the latest missing parts is now addressed: the registration of all drivers. These drivers have a registration order that is mainly based on the initcall Level to which they were registered. Initcalls are nothing more than an 8 -step -Aray that “ordered the rest” of the core elimization. Within a given initcall Plain depends on the order of execution on the order of the registration, depending on the order in which the object files have been linked (this is dictated by the different Makefiles). So back to our initcallsYou will all be put in order. This is when our init_module() executed!

For example one of the recruits in registered calls arch_initcall Level (number 3 from a 0-7 area) is The one who populated the devices Based on the content of the device tree!

Start the users space

As soon as all bus drivers, Host controller drivers and device drivers have been registered, kunit Tests are carried outShortly before the handover to the init Procedure, As soon as we find a suitable one.

So yes, there are so many intermediate steps that it is easy to lose yourself, especially since one step is often divided into your own early init, init, configuration and late init, whereby all of immense functions with tons of intermediate steps are distributed, but we hope that this article demolish these early steps, these steps that always occur before you see yourself to see yourself first. printk()!

Miquèl Raynal



Source link