-
Notifications
You must be signed in to change notification settings - Fork 32
start_kernel
Over and over again, I have to look up the kernel startup process. So I wrote down the parts I'm interested in. Linux 3.10 ARM
start_kernel() is the kernel entry point.
start_kernel
|
|--> smp_setup_processor_id
| |
| `--> printk(KERN_INFO "Booting Linux on physical CPU 0x%x\n", mpidr);
|
|--> cgroup_init_early
| |
| `--> printk(KERN_ERR "cgroup: Subsys %s id == %d\n",
|
|--> pr_notice("%s", linux_banner);
|
|--> setup_arch
| |
| |--> setup_processor
| | |
| | `--> printk("CPU: %s [%08x] revision %d (ARMv%s), cr=%08lx\n",
| |
| |--> setup_machine_fdt
| | |
| | `--> pr_info("Machine: %s, model: %s\n", mdesc_best->name, model);
| |
| |--> arm_memblock_init
| | |
| | |--> arm_mm_memblock_reserve
| | |
| | |--> arm_dt_memblock_reserve
| | |
| | `--> mdesc->reserve
| |
| |--> paging_init
| | |
| | `--> devicemaps_init
| | |
| | `--> mdesc->map_io
| |
| `--> mdesc->init_early
|
|--> pr_notice("Kernel command line: %s\n", boot_command_line);
|
|--> init_IRQ
| |
| `--> machine_desc->init_irq
|
|--> time_init
| |
| `--> machine_desc->init_time
|
|--> console_init
| |
| `--> console_initcall's
| :
| `--> con_init
| |
| `--> pr_info("Console: %s %s %dx%d\n", ...);
| Console: colour dummy device 80x30
|
`--> rest_init
|
`--> kernel_init
|
|--> kernel_init_freeable
| |
| |--> do_basic_setup
| | |
| | `--> do_initcalls
| | :
| | :--> early init calls
| | :--> core init calls
| | :--> post core init calls
| | :--> arch init calls
| | : :
| | : `--> customize_machine
| | : |
| | : `--> machine_desc->init_machine
| | :
| | :--> subsys init calls
| | :--> fs init calls
| | :--> device init calls
| | : :
| | : `--> module_init() entries
| | : drivers are probed during driver registration
| | :
| | `--> late init calls
| |
| |--> prepare_namespace
| | |
| | `--> mount_root
| | |
| | `--> mount_block_root
| | |
| | `--> do_mount_root
| | |
| | `--> printk(KERN_INFO "VFS: Mounted root (%s filesystem)%s on device %u:%u.\n", ...);
| |
| `--> load_default_modules
|
|--> free_initmem
| |
| `--> free_initmem_default
| |
| `--> free_reserved_areafree_reserved_area
| |
| `--> printk: Freeing unused kernel memory: xxxK
|
`--> run_init_process
BCM2835 machine description (machine_desc)
DT_MACHINE_START(BCM2835, "BCM2835")
.map_io = bcm2835_map_io,
.init_irq = bcm2835_init_irq,
.handle_irq = bcm2835_handle_irq,
.init_machine = bcm2835_init,
.init_time = clocksource_of_init,
.restart = bcm2835_restart,
.dt_compat = bcm2835_compat
MACHINE_END
http://lxr.free-electrons.com/source/arch/arm/mach-bcm2835/bcm2835.c?v=3.10;a=arm#L132
Driver probing happens as part of the driver registration (and device_register)
XXX_register_driver
|
`--> driver_register
|
`--> bus_add_driver
|
`--> driver_attach
|
`--> bus_for_each_dev
|
`--> __driver_attach
|
`--> driver_probe_device
|
`--> really_probe
|
`--> drv->probe
Some initcall details
/*
* Ok, the machine is now initialized. None of the devices
* have been touched yet, but the CPU subsystem is up and
* running, and memory and process management works.
*
* Now we can finally start doing some real work..
*/
static void __init do_basic_setup(void)
{
cpuset_init_smp();
usermodehelper_init();
shmem_init();
driver_init();
init_irq_proc();
do_ctors();
usermodehelper_enable();
do_initcalls();
}
http://lxr.free-electrons.com/source/init/main.c?v=3.10;a=arm#L779
static void __init do_initcalls(void)
{
int level;
for (level = 0; level < ARRAY_SIZE(initcall_levels) - 1; level++)
do_initcall_level(level);
}
http://lxr.free-electrons.com/source/init/main.c?v=3.10;a=arm#L755
static void __init do_initcall_level(int level)
{
extern const struct kernel_param __start___param[], __stop___param[];
initcall_t *fn;
strcpy(static_command_line, saved_command_line);
parse_args(initcall_level_names[level],
static_command_line, __start___param,
__stop___param - __start___param,
level, level,
&repair_env_string);
for (fn = initcall_levels[level]; fn < initcall_levels[level+1]; fn++)
do_one_initcall(*fn);
}
http://lxr.free-electrons.com/source/init/main.c?v=3.10;a=arm#L739
extern initcall_t __initcall_start[];
extern initcall_t __initcall0_start[];
extern initcall_t __initcall1_start[];
extern initcall_t __initcall2_start[];
extern initcall_t __initcall3_start[];
extern initcall_t __initcall4_start[];
extern initcall_t __initcall5_start[];
extern initcall_t __initcall6_start[];
extern initcall_t __initcall7_start[];
extern initcall_t __initcall_end[];
static initcall_t *initcall_levels[] __initdata = {
__initcall0_start,
__initcall1_start,
__initcall2_start,
__initcall3_start,
__initcall4_start,
__initcall5_start,
__initcall6_start,
__initcall7_start,
__initcall_end,
};
/* Keep these in sync with initcalls in include/linux/init.h */
static char *initcall_level_names[] __initdata = {
"early",
"core",
"postcore",
"arch",
"subsys",
"fs",
"device",
"late",
};
http://lxr.free-electrons.com/source/init/main.c?v=3.10;a=arm#L704
#define INIT_CALLS_LEVEL(level) \
VMLINUX_SYMBOL(__initcall##level##_start) = .; \
*(.initcall##level##.init) \
*(.initcall##level##s.init) \
#define INIT_CALLS \
VMLINUX_SYMBOL(__initcall_start) = .; \
*(.initcallearly.init) \
INIT_CALLS_LEVEL(0) \
INIT_CALLS_LEVEL(1) \
INIT_CALLS_LEVEL(2) \
INIT_CALLS_LEVEL(3) \
INIT_CALLS_LEVEL(4) \
INIT_CALLS_LEVEL(5) \
INIT_CALLS_LEVEL(rootfs) \
INIT_CALLS_LEVEL(6) \
INIT_CALLS_LEVEL(7) \
VMLINUX_SYMBOL(__initcall_end) = .;
#define INIT_DATA_SECTION(initsetup_align) \
.init.data : AT(ADDR(.init.data) - LOAD_OFFSET) { \
INIT_DATA \
INIT_SETUP(initsetup_align) \
INIT_CALLS \
CON_INITCALL \
SECURITY_INITCALL \
INIT_RAM_FS \
}
http://lxr.free-electrons.com/source/include/asm-generic/vmlinux.lds.h?v=3.10;a=arm
This is how the init calls are used in code
/*
* Early initcalls run before initializing SMP.
*
* Only for built-in code, not modules.
*/
#define early_initcall(fn) __define_initcall(fn, early)
/*
* A "pure" initcall has no dependencies on anything else, and purely
* initializes variables that couldn't be statically initialized.
*
* This only exists for built-in code, not for modules.
* Keep main.c:initcall_level_names[] in sync.
*/
#define pure_initcall(fn) __define_initcall(fn, 0)
#define core_initcall(fn) __define_initcall(fn, 1)
#define core_initcall_sync(fn) __define_initcall(fn, 1s)
#define postcore_initcall(fn) __define_initcall(fn, 2)
#define postcore_initcall_sync(fn) __define_initcall(fn, 2s)
#define arch_initcall(fn) __define_initcall(fn, 3)
#define arch_initcall_sync(fn) __define_initcall(fn, 3s)
#define subsys_initcall(fn) __define_initcall(fn, 4)
#define subsys_initcall_sync(fn) __define_initcall(fn, 4s)
#define fs_initcall(fn) __define_initcall(fn, 5)
#define fs_initcall_sync(fn) __define_initcall(fn, 5s)
#define rootfs_initcall(fn) __define_initcall(fn, rootfs)
#define device_initcall(fn) __define_initcall(fn, 6)
#define device_initcall_sync(fn) __define_initcall(fn, 6s)
#define late_initcall(fn) __define_initcall(fn, 7)
#define late_initcall_sync(fn) __define_initcall(fn, 7s)
#define __initcall(fn) device_initcall(fn)
/**
* module_init() - driver initialization entry point
* @x: function to be run at kernel boot time or module insertion
*
* module_init() will either be called during do_initcalls() (if
* builtin) or at module insertion time (if a module). There can only
* be one per module.
*/
#define module_init(x) __initcall(x);
http://lxr.free-electrons.com/source/include/linux/init.h?v=3.10;a=arm#L182
Links:
- Linux Kernel Init Calls
- http://stackoverflow.com/questions/11642330/linux-built-in-driver-load-order
- http://stackoverflow.com/questions/10368837/how-does-linux-determine-the-order-of-module-init-calls
- Init Call Mechanism in the Linux Kernel
- Linux built-in driver load order
- How does Linux determine the order of module init calls?
- LINUX: order of statically linked module loading