13. kmem_cache_init(), initialise most of slab allocator.
14. Enable interrupts.
15. Calculate BogoMips value for this CPU.
16. Call mem_init() which calculates max_mapnr, totalram_pages and high_memory and
prints out the "Memory: ..." line.
17. kmem_cache_sizes_init(), finish slab allocator initialisation.
18. Initialise data structures used by procfs.
19. fork_init(), create uid_cache, initialise max_threads based on the amount of memory
available and configure RLIMIT_NPROC for init_task to be max_threads/2.
20. Create various slab caches needed for VFS, VM, buffer cache, etc.
21. If System V IPC support is compiled in, initialise the IPC subsystem. Note that for System V shm,
this includes mounting an internal (in−kernel) instance of shmfs filesystem.
22. If quota support is compiled into the kernel, create and initialise a special slab cache for it.
23. Perform arch−specific "check for bugs" and, whenever possible, activate workaround for
processor/bus/etc bugs. Comparing various architectures reveals that "ia64 has no bugs" and "ia32
has quite a few bugs", good example is "f00f bug" which is only checked if kernel is compiled for
less than 686 and worked around accordingly.
24. Set a flag to indicate that a schedule should be invoked at "next opportunity" and create a kernel
thread init() which execs execute_command if supplied via "init=" boot parameter, or tries to
exec /sbin/init, /etc/init, /bin/init, /bin/sh in this order; if all these fail, panic with "suggestion" to
use "init=" parameter.
25. Go into the idle loop, this is an idle thread with pid=0.
Important thing to note here that the init() kernel thread calls do_basic_setup() which in turn calls
do_initcalls() which goes through the list of functions registered by means of __initcall or
module_init() macros and invokes them. These functions either do not depend on each other or their
dependencies have been manually fixed by the link order in the Makefiles. This means that, depending on the
position of directories in the trees and the structure of the Makefiles, the order in which initialisation
functions are invoked can change. Sometimes, this is important because you can imagine two subsystems A
and B with B depending on some initialisation done by A. If A is compiled statically and B is a module then
B's entry point is guaranteed to be invoked after A prepared all the necessary environment. If A is a module,
then B is also necessarily a module so there are no problems. But what if both A and B are statically linked
into the kernel? The order in which they are invoked depends on the relative entry point offsets in the
.initcall.init ELF section of the kernel image. Rogier Wolff proposed to introduce a hierarchical
"priority" infrastructure whereby modules could let the linker know in what (relative) order they should be
linked, but so far there are no patches available that implement this in a sufficiently elegant manner to be
acceptable into the kernel. Therefore, make sure your link order is correct. If, in the example above, A and B
work fine when compiled statically once, they will always work, provided they are listed sequentially in the
same Makefile. If they don't work, change the order in which their object files are listed.
Another thing worth noting is Linux's ability to execute an "alternative init program" by means of passing
"init=" boot commandline. This is useful for recovering from accidentally overwritten /sbin/init or debugging
the initialisation (rc) scripts and /etc/inittab by hand, executing them one at a time.
1.7 SMP Bootup on x86
On SMP, the BP goes through the normal sequence of bootsector, setup etc until it reaches the
start_kernel(), and then on to smp_init() and especially
src/i386/kernel/smpboot.c:smp_boot_cpus(). The smp_boot_cpus() goes in a loop for
each apicid (until NR_CPUS) and calls do_boot_cpu() on it. What do_boot_cpu() does is create (i.e.
Linux Kernel Internals
1.7 SMP Bootup on x86 8