In this article we focus on some study notes in linux kernel startup and we mainly focus on start_kernel

Specific Arch Initialize

in @/init/main.c we could find

asmlinkage void __init start_kernel(void)

This is the main function to initialize linux kernel.
start_kernel() –> setup_arch(&command_line) –> setup_process() will detect the CPU type and invoke high level cpu related initialize function.  (in @/arch/arm/kernel/setup.c)

Parse command line pass to linux kernel

in @/include/linux/init.h

/*
 *Only for really core code. See moduleparam.h for the normal way.
 *
 *Force the alignment so the compiler doesn't space elements of the
 *obs_kernel_param "array" too far apart in .init.setup.
 */
#define __setup_param(str, unique_id, fn, early) \
 static const char __setup_str_##unique_id[] __initconst \
 __aligned(1) = str; \
 static struct obs_kernel_param __setup_##unique_id \
 __used __section(.init.setup) \
 __attribute__((aligned((sizeof(long))))) \
 = { __setup_str_##unique_id, fn, early }
#define __setup(str, fn) \
 __setup_param(str, fn, fn, 0)

__setup 主要用意是為了讓command line 進來的參數能被相對應函式所處理, 參數的意思是,當str出現時,就呼叫後面的function, ex: __setup(“console=”,console_setup); 當命令列出現 “console=” 時,就呼到 console_setup function.

__used: tell compiler 即使最佳化時發現某函數,或變數在任何地方都沒被使用,仍然要產生輸出
__attribute__ ((aligned)) tell compiler 要根據某特定邊界來進行對齊
__section(section_name) tell linker to place the structure into specific section defined by section_name

in @init/main.c we could find

extern const struct obs_kernel_param __setup_start[], __setup_end[];
static int __init obsolete_checksetup(char *line)

These 2 functions are used to check if the command line contain command could be identified and invoke corresponding function.

類似 __setup 的方式在 kernel 中常使用, @include/linux/init.h 可看到

#define __init __section(.init.text) __cold notrace
#define __initdata __section(.init.data)
#define __initconst __section(.init.rodata)
#define __exitdata __section(.exit.data)
#define __exit_call __used __section(.exitcall.exit)

其中 __init 相關的都是開機時只會需執行一次的,因此放在特定區域. 在開機程序最後一行常看到 Freeing init memory 即是把這一區段給free 掉.

附註一提: 目前是先 invoke parse_args 再將最後一個參數設為 &unknown_bootoption,所以如果新的cmd line parse 找不到,就會去舊的找.  (check @/kernel/params.c and @/init/main.c)

Sub-System initialize

in @/init/main.c we could find start_kernel may initialize some sub-system directly, for example init_IRQ/init_timers …. .
How about arch specific customized part ? –> In @/arch/arm/kernel/setup.c we could find

static int __init customize_machine(void)
{
    /* customizes platform devices, or adds new ones */
    if (machine_desc->init_machine)
    machine_desc->init_machine();
    return 0;
}
arch_initcall(customize_machine);

這也類似__setup 將 init 子系統相關的function 註冊下去.

1st kernel thread

@/init/main.c 

static noinline void __init_refok rest_init(void)

這是最後在start_kernel會被呼到的,而這就是產一第一個kernel thread – init()

initcall_debug

這是一個kernel command line parameter, 可以讓我們看到開機時各個函式的呼叫

Leave a Reply