start_kernel - notro/rpi-firmware GitHub Wiki

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:

piwik