Linux v6.6 init/main.c

Linux 6.6 · init/main.c · Research Note

start_kernel() 연구 노트

아키텍처별 초기 진입 코드가 넘긴 뒤 실행되는 C 초기화 흐름을 Linux v6.6 init/main.c에서 추적합니다. 이 파일에서 직접 확인할 수 있는 것은 호출 순서와 IRQ 활성화 지점입니다. 개별 하위 시스템의 내부 완료 조건과 아키텍처별 동작은 각 구현 파일을 더 확인해야 합니다.

연구 관점

start_kernel()의 큰 축은 소스에 적힌 호출 순서입니다. 호출되었다는 사실만으로 해당 하위 시스템의 모든 기능이 준비되었다고 단정하지 않습니다.

아래 도식은 Linux v6.6 init/main.c:869–1068의 경계를 표시합니다. arch_call_rest_init()는 아키텍처가 재정의할 수 있는 약한 함수이며, 이 파일의 기본 구현은 rest_init()을 호출합니다.

초기화 순서

부팅 중 핵심 경계를 앞에서 뒤로 읽습니다. 각 칸의 숫자는 init/main.c 원문 행이며, 이 도식은 실행 시간이나 CPU 간 동시성을 뜻하지 않습니다.

그림 1. start_kernel()의 호출 순서, Linux v6.6
① IRQ 비활성local_irq_disable()882행
② 아키텍처 호출setup_arch()893행 · 내부 동작은 여기서 확정 불가
③ 메모리·스케줄러mm_core_init() → sched_init()928 → 940행
④ IRQ·시간 초기화early_irq_init() → time_init()971–980행
⑤ IRQ 활성local_irq_enable()995행
⑥ 늦은 core 호출console_init(), fork_init(), vfs_caches_init()1004, 1045, 1052행
⑦ 아키텍처 경유arch_call_rest_init()1068행
⑧ 기본 구현rest_init()약한 기본 구현 821–824행 · 재정의 가능

번호는 원문에 적힌 호출 선후 관계만 나타냅니다. rest_init() 직행은 약한 기본 구현의 경로입니다.

원문 위치직접 확인되는 호출이 파일만으로 확정할 수 없는 점
882–893IRQ를 끄고 setup_arch() 호출아키텍처가 구성한 메모리·DT·CPU 세부 상태
928–940mm_core_init() 뒤 sched_init()각 allocator 및 스케줄러 자료구조의 내부 준비 단계
971–995IRQ·timer·timekeeping 초기화 뒤 IRQ 활성첫 인터럽트가 실제로 도착한 시각
1068, 821–824arch_call_rest_init(); 약한 기본 구현은 rest_init() 호출아키텍처별 재정의 여부와 그 구현의 추가 동작

상태 변화

timekeeping_init()은 IRQ를 켜서 생기는 호출이 아닙니다. v6.6 원문에서는 timekeeping_init()이 979행, local_irq_enable()이 995행입니다.

그림 2. 시간 초기화와 IRQ 활성화의 위치
IRQ offlocal_irq_disable()882행
IRQ off 중 준비early_irq_init()
init_IRQ()
tick_init()
timekeeping_init()
time_init()971–980행
IRQ on 경계local_irq_enable()995행

초기화 함수 호출 시각과 하드웨어 이벤트 발생 시각은 다릅니다. IRQ 활성만으로 timer interrupt가 이미 발생했다고 추론할 수 없습니다.

읽을 명제v6.6 본문으로 확인 가능한 범위
sched_init()은 timer interrupt 전935–940행 주석과 995행의 IRQ 활성 순서가 이를 뒷받침합니다. 같은 주석은 전체 topology 구성이 나중임을 명시합니다.
timekeeping_init()은 IRQ 활성 전979행에서 호출, 995행에서 local_irq_enable() 호출.
IRQ 활성 후 실행할 수 있는 코드이 파일은 997행 이후 늦은 초기화 호출을 보여줍니다. 특정 IRQ나 scheduler tick의 실제 실행 시각은 보여주지 않습니다.

경계별 확인

소스가 보장하는 순서와 실기기에서 관찰할 현상을 나눠 읽습니다. 아래 비교는 오류 증상을 특정 초기화 함수에 자동으로 귀속하지 않습니다.

그림 3. 호출 순서와 실행 결과를 분리해서 읽기
소스로 확인setup_arch() → mm_core_init() → sched_init()893 → 928 → 940행
별도 구현 확인메모리 영역 구성, allocator의 내부 상태, scheduler의 세부 자료구조각 함수 구현과 빌드 설정이 필요
소스로 확인timekeeping_init() → local_irq_enable()979 → 995행
별도 실행 확인첫 timer IRQ, 실제 latency, interrupt controller 응답해당 아키텍처와 기기의 trace가 필요
질문먼저 볼 원문다음 검증
초기 메모리 호출 순서가 맞나?920–940행의 주석과 호출 목록mm_core_init() 구현과 아키텍처 메모리 설정
타이머 초기화가 IRQ보다 먼저인가?971–980행, 994–995행실제 타이머 이벤트는 대상 시스템 trace
init 프로세스 생성으로 어떻게 넘어가나?1068행, 821–824행, 680–727행아키텍처가 약한 함수를 재정의했는지 확인

원문에서 세울 수 있는 불변 조건

  • local_irq_disable()(882) 뒤의 초기화가 local_irq_enable()(995)보다 앞에 적혀 있습니다. 경로가 조기에 IRQ를 켜는지 942–944, 992행에서도 검사합니다.
  • mm_core_init()(928) 뒤에 sched_init()(940)을 호출합니다. 이것만으로 모든 메모리·스케줄러 기능의 완성 시점을 단정하지 않습니다.
  • timekeeping_init()(979)은 IRQ 활성화(995) 전 호출입니다.
  • arch_call_rest_init()(1068)의 약한 기본 구현(821–824)은 rest_init()으로 이어집니다. 아키텍처별 재정의는 별도 확인이 필요합니다.
  • 기본 경로의 rest_init()(680–727)은 PID 1용 thread, kthreadd를 순서대로 생성하고 boot idle 경로로 들어갑니다.

읽기와 검증의 범위

그림 4. 기본 handoff에서 생성과 실행을 구분하기
호출부arch_call_rest_init()1068행
약한 기본 구현rest_init()821–824행
생성 순서user_mode_thread(kernel_init) → kernel_thread(kthreadd)691 → 704행
boot idlecomplete() → schedule_preempt_disabled() → cpu_startup_entry()718 → 724 → 726행
생성 호출 순서는 확인되지만, 이 도식만으로 PID 1 또는 kthreadd가 곧바로 CPU에서 실행되었다고 말할 수 없습니다. kernel_init()은 kthreadd_done completion을 기다립니다(1432–1437행).
검증 대상이 글의 근거추가로 필요한 자료
정적 호출 순서Linux v6.6 init/main.c의 표시 행없음
아키텍처별 진입·override약한 기본 구현의 존재만 확인대상 아키텍처 소스와 설정
실행 시간·첫 IRQ·작업 전환이 소스만으로 확인 불가대상 시스템의 실행 trace

원본 코드

이 글은 Linux v6.6의 init/main.c를 기준으로 씁니다. 아래 raw 파일은 홈페이지 폴더에 같이 둔 로컬 복사본입니다.

init/main.c · Linux v6.6 로컬 원본 열기 →

head.S 다음에 무슨 일이 생기나

아키텍처 진입 코드가 start_kernel()으로 넘긴 뒤의 공통 C 초기화 순서를 이 글에서 읽습니다. 진입 직전의 레지스터·MMU·스택 상태는 해당 아키텍처의 head.S와 빌드 설정을 별도로 대조해야 합니다.

이 함수는 memory, scheduler, IRQ, time, VFS, process, security, network namespace 초기화 호출의 순서를 보여줍니다. driver 초기화와 initcall은 뒤의 kernel_init_freeable() → do_basic_setup() 경로에서 살핍니다. 각 함수의 내부 결과는 이 파일의 호출 한 줄보다 더 넓은 근거가 필요합니다.

869–899: start_kernel 진입부

L869-L899: boot CPU와 arch setup 전 준비

원본 코드:
asmlinkage __visible __init __no_sanitize_address __noreturn __no_stack_protector
void start_kernel(void)
{
	char *command_line;
	char *after_dashes;

	set_task_stack_end_magic(&init_task);
	smp_setup_processor_id();
	debug_objects_early_init();
	init_vmlinux_build_id();

	cgroup_init_early();

	local_irq_disable();
	early_boot_irqs_disabled = true;

	/*
	 * Interrupts are still disabled. Do necessary setups, then
	 * enable them.
	 */
	boot_cpu_init();
	page_address_init();
	pr_notice("%s", linux_banner);
	early_security_init();
	setup_arch(&command_line);
	setup_boot_config();
	setup_command_line(command_line);
	setup_nr_cpu_ids();
	setup_per_cpu_areas();
	smp_prepare_boot_cpu();	/* arch-specific boot-cpu hooks */
	boot_cpu_hotplug_init();

설명: C 코드에 들어왔지만 아직 일반 커널 런타임은 아닙니다. IRQ는 꺼져 있고, allocator와 scheduler도 완전히 준비되지 않았습니다.

더 읽기: 함수 선언의 __init은 초기화 section, __noreturn은 호출자에게 복귀하지 않는 함수임을 나타냅니다. 아키텍처별 호출부의 실제 명령과 후속 처리는 해당 head.S 원문에서 별도로 확인해야 합니다.

set_task_stack_end_magic(&init_task)는 875행에서 호출됩니다. stack overflow 감지 등 세부 동작은 이 함수 구현을 확인해야 하며, 이 호출만으로 현재 태스크의 다른 상태를 단정할 수 없습니다.

smp_setup_processor_id()(876)와 boot_cpu_init()(889)이 초기 호출 목록에 있습니다. boot CPU 식별 관련 내부 상태는 각각의 구현에서 확인합니다.

setup_arch(&command_line)는 아키텍처별 구현으로 들어가는 호출입니다. 이 파일만으로 DTB·paging·CPU feature 등 개별 결과를 확정할 수 없으므로, 대상 아키텍처의 구현을 함께 봐야 합니다.

901-918: kernel command line 처리

L901-L918: early param과 일반 param 분리

원본 코드:
	pr_notice("Kernel command line: %s\n", saved_command_line);
	/* parameters may set static keys */
	jump_label_init();
	parse_early_param();
	after_dashes = parse_args("Booting kernel",
				  static_command_line, __start___param,
				  __stop___param - __start___param,
				  -1, -1, NULL, &unknown_bootoption);
	print_unknown_bootoptions();
	if (!IS_ERR_OR_NULL(after_dashes))
		parse_args("Setting init args", after_dashes, NULL, 0, -1, -1,
			   NULL, set_init_arg);
	if (extra_init_args)
		parse_args("Setting extra init args", extra_init_args,
			   NULL, 0, -1, -1, NULL, set_init_arg);

	/* Architectural and non-timekeeping rng init, before allocator init */
	random_init_early(command_line);

설명: 커널 command line을 early param, kernel param, init process 인자로 나눠 처리합니다.

더 읽기: parse_early_param() 호출은 904행, 일반 parse_args() 호출은 905행입니다. 특정 옵션의 등록 방식은 그 옵션의 선언부를 확인해야 합니다.

parse_args("Booting kernel", ...)는 905–908행에서 __start___param과 __stop___param 범위를 받습니다. 다른 옵션 처리 경로까지 이 한 호출에 포함된다고 단정하지 않습니다.

command line의 -- 뒤쪽은 커널이 아니라 userspace init에 넘길 인자로 취급됩니다. 그래서 after_dashes를 다시 set_init_arg로 parse합니다. bring-up 중 init argument가 이상하게 들어간다면 이 경계를 확인해야 합니다.

920-940: early memory와 scheduler

L920-L940: page allocator 전후의 큰 초기화

원본 코드:
	/*
	 * These use large bootmem allocations and must precede
	 * initalization of page allocator
	 */
	setup_log_buf(0);
	vfs_caches_init_early();
	sort_main_extable();
	trap_init();
	mm_core_init();
	poking_init();
	ftrace_init();

	/* trace_printk can be enabled here */
	early_trace_init();

	/*
	 * Set up the scheduler prior starting any interrupts (such as the
	 * timer interrupt). Full topology setup happens at smp_init()
	 * time - but meanwhile we still have a functioning scheduler.
	 */
	sched_init();

설명: 메모리와 scheduler가 여기서 처음 큰 형태를 갖춥니다. 이 이후부터 커널은 훨씬 일반적인 실행 환경에 가까워집니다.

더 읽기: setup_log_buf와 vfs_caches_init_early는 page allocator가 완전히 서기 전에 큰 bootmem allocation을 써야 해서 앞에 옵니다. 순서가 그냥 취향이 아니라 allocator 준비 단계와 직접 연결됩니다.

mm_core_init()은 928행에서 호출됩니다. 앞선 주석은 큰 bootmem allocation을 사용하는 호출을 page allocator 초기화보다 먼저 두어야 한다고 설명합니다. allocator 내부 단계는 mm_core_init() 구현에서 따로 확인해야 합니다.

935–939행 주석은 timer interrupt 전에 sched_init()을 호출하고, 전체 topology setup은 뒤의 smp_init() 때 이뤄진다고 설명합니다. 이는 본문의 호출 순서와 주석에 근거한 설명이며, 개별 scheduler 자료구조의 완성 시점을 뜻하지는 않습니다.

945-980: IRQ, timer, timekeeping

L945-L980: interrupt와 time 기반 시설

원본 코드:
	radix_tree_init();
	maple_tree_init();

	/*
	 * Set up housekeeping before setting up workqueues to allow the unbound
	 * workqueue to take non-housekeeping into account.
	 */
	housekeeping_init();

	/*
	 * Allow workqueue creation and work item queueing/cancelling
	 * early.  Work item execution depends on kthreads and starts after
	 * workqueue_init().
	 */
	workqueue_init_early();

	rcu_init();

	/* Trace events are available after this */
	trace_init();

	if (initcall_debug)
		initcall_debug_enable();

	context_tracking_init();
	/* init some links before init_ISA_irqs() */
	early_irq_init();
	init_IRQ();
	tick_init();
	rcu_init_nohz();
	init_timers();
	srcu_init();
	hrtimers_init();
	softirq_init();
	timekeeping_init();
	time_init();

설명: IRQ와 시간 기반 subsystem이 여기서 순서대로 올라옵니다. 이 순서가 맞아야 뒤에서 IRQ를 켤 수 있습니다.

더 읽기: rcu_init()은 961행에서 호출됩니다. RCU 내부 단계와 read-side 사용 가능 조건은 RCU 구현 및 설정에 따라 확인해야 합니다.

971–972행에서 early_irq_init(), init_IRQ()를 차례로 호출합니다. IRQ descriptor와 interrupt controller의 실제 구성은 각각의 구현 및 아키텍처 소스에서 확인해야 합니다.

973–980행의 tick_init(), init_timers(), hrtimers_init(), timekeeping_init(), time_init() 호출은 모두 995행의 IRQ 활성화보다 앞섭니다. 각 시간 하위 시스템의 구현은 이 호출 목록만으로 설명되지 않습니다.

softirq_init()도 이 구간 978행에 있습니다. 실제 softirq 종류와 실행 시점은 관련 구현 및 실행 trace를 따로 확인해야 합니다.

981-1068: IRQ enable 이후 core subsystem

L981-L1068: console, process, VFS, namespace, security, net

원본 코드:

	/* This must be after timekeeping is initialized */
	random_init();

	/* These make use of the fully initialized rng */
	kfence_init();
	boot_init_stack_canary();

	perf_event_init();
	profile_init();
	call_function_init();
	WARN(!irqs_disabled(), "Interrupts were enabled early\n");

	early_boot_irqs_disabled = false;
	local_irq_enable();

	kmem_cache_init_late();

	/*
	 * HACK ALERT! This is early. We're enabling the console before
	 * we've done PCI setups etc, and console_init() must be aware of
	 * this. But we do want output early, in case something goes wrong.
	 */
	console_init();
	if (panic_later)
		panic("Too many boot %s vars at `%s'", panic_later,
		      panic_param);

	lockdep_init();

	/*
	 * Need to run this when irqs are enabled, because it wants
	 * to self-test [hard/soft]-irqs on/off lock inversion bugs
	 * too:
	 */
	locking_selftest();

#ifdef CONFIG_BLK_DEV_INITRD
	if (initrd_start && !initrd_below_start_ok &&
	    page_to_pfn(virt_to_page((void *)initrd_start)) < min_low_pfn) {
		pr_crit("initrd overwritten (0x%08lx < 0x%08lx) - disabling it.\n",
		    page_to_pfn(virt_to_page((void *)initrd_start)),
		    min_low_pfn);
		initrd_start = 0;
	}
#endif
	setup_per_cpu_pageset();
	numa_policy_init();
	acpi_early_init();
	if (late_time_init)
		late_time_init();
	sched_clock_init();
	calibrate_delay();

	arch_cpu_finalize_init();

	pid_idr_init();
	anon_vma_init();
#ifdef CONFIG_X86
	if (efi_enabled(EFI_RUNTIME_SERVICES))
		efi_enter_virtual_mode();
#endif
	thread_stack_cache_init();
	cred_init();
	fork_init();
	proc_caches_init();
	uts_ns_init();
	key_init();
	security_init();
	dbg_late_init();
	net_ns_init();
	vfs_caches_init();
	pagecache_init();
	signals_init();
	seq_file_init();
	proc_root_init();
	nsfs_init();
	cpuset_init();
	cgroup_init();
	taskstats_init_early();
	delayacct_init();

	acpi_subsystem_init();
	arch_post_acpi_subsys_init();
	kcsan_init();

	/* Do the rest non-__init'ed, we're now alive */
	arch_call_rest_init();

설명: IRQ를 켠 뒤부터는 subsystem 초기화가 넓게 펼쳐집니다. 여기서 커널 전체 토픽이 거의 다 갈라집니다.

local_irq_enable()은 995행의 명시적 경계입니다. 1011–1016행 주석은 locking_selftest()를 IRQ 활성화 뒤에 호출하는 이유를 설명합니다. 실제 첫 IRQ 수신 시각은 이 파일만으로 알 수 없습니다.

999–1003행 주석은 console_init()이 PCI setup 전에 이르게 실행되는 이유를 설명합니다. 어떤 콘솔이 실제로 등록되는지는 구성과 드라이버에 달려 있습니다.

cred_init()(1044), fork_init()(1045), signals_init()(1054)은 process 관련 구현으로 들어가는 호출입니다. 내부 자료구조의 준비 범위는 각각의 함수에서 확인해야 합니다.

vfs_caches_init()(1052), pagecache_init()(1053), proc_root_init()(1056)은 파일시스템 관련 초기화의 입구입니다. 상세 결과는 각 구현에서 대조해야 합니다.

net_ns_init()은 1051행에서 호출됩니다. 네트워크 장치와 protocol의 실제 등록 경로는 다른 소스와 설정에 따라 확인해야 합니다.

680-727: rest_init(), pid 1과 kthreadd

L680-L727: init thread, kthreadd, idle thread

원본 코드:
noinline void __ref __noreturn rest_init(void)
{
	struct task_struct *tsk;
	int pid;

	rcu_scheduler_starting();
	/*
	 * We need to spawn init first so that it obtains pid 1, however
	 * the init task will end up wanting to create kthreads, which, if
	 * we schedule it before we create kthreadd, will OOPS.
	 */
	pid = user_mode_thread(kernel_init, NULL, CLONE_FS);
	/*
	 * Pin init on the boot CPU. Task migration is not properly working
	 * until sched_init_smp() has been run. It will set the allowed
	 * CPUs for init to the non isolated CPUs.
	 */
	rcu_read_lock();
	tsk = find_task_by_pid_ns(pid, &init_pid_ns);
	tsk->flags |= PF_NO_SETAFFINITY;
	set_cpus_allowed_ptr(tsk, cpumask_of(smp_processor_id()));
	rcu_read_unlock();

	numa_default_policy();
	pid = kernel_thread(kthreadd, NULL, NULL, CLONE_FS | CLONE_FILES);
	rcu_read_lock();
	kthreadd_task = find_task_by_pid_ns(pid, &init_pid_ns);
	rcu_read_unlock();

	/*
	 * Enable might_sleep() and smp_processor_id() checks.
	 * They cannot be enabled earlier because with CONFIG_PREEMPTION=y
	 * kernel_thread() would trigger might_sleep() splats. With
	 * CONFIG_PREEMPT_VOLUNTARY=y the init task might have scheduled
	 * already, but it's stuck on the kthreadd_done completion.
	 */
	system_state = SYSTEM_SCHEDULING;

	complete(&kthreadd_done);

	/*
	 * The boot idle thread must execute schedule()
	 * at least once to get things moving:
	 */
	schedule_preempt_disabled();
	/* Call into cpu_idle with preempt disabled */
	cpu_startup_entry(CPUHP_ONLINE);
}

설명: 여기서 pid 1이 될 init thread와 kernel thread를 낳는 kthreadd가 만들어집니다. boot CPU는 이후 idle loop로 들어갑니다.

더 읽기: user_mode_thread(kernel_init, ...)가 먼저 호출됩니다. init task가 pid 1을 얻어야 하기 때문입니다. 다만 이 thread가 곧바로 kthread를 만들려고 하면 kthreadd가 아직 없으므로, 뒤에서 completion으로 동기화합니다.

kernel_thread(kthreadd, ...)는 704행에서 호출되고, 반환된 PID로 찾은 task를 kthreadd_task에 저장합니다(705–707행). 이후 kthread 생성의 세부 경로는 다른 구현에서 확인해야 합니다.

system_state = SYSTEM_SCHEDULING(716), complete()(718), schedule_preempt_disabled()(724), cpu_startup_entry()(726)이 소스 순서입니다. 이 순서와 PID 1·kthreadd의 실제 CPU 실행 시각은 구분해야 합니다.

1323-1330: driver_init과 initcall

L1323-L1330: do_basic_setup()

원본 코드:
static void __init do_basic_setup(void)
{
	cpuset_init_smp();
	driver_init();
	init_irq_proc();
	do_ctors();
	do_initcalls();
}

설명: do_basic_setup()의 본문은 driver_init() 뒤에 do_initcalls()를 호출합니다. 이 함수는 start_kernel() 안에 직접 나타나는 호출이 아니라, 뒤의 PID 1 kernel_init_freeable() 경로에서 호출됩니다(1547행).

driver_init()은 1326행에서 호출됩니다. driver core의 구체적인 bus·class·device 준비 범위는 해당 구현에서 확인해야 합니다.

do_initcalls()는 1329행에 있습니다. level 순서와 각 initcall의 등록 위치는 이 함수의 구현과 호출 대상을 더 추적해야 합니다.

특정 장치의 probe가 실행되지 않는 원인은 이 호출 순서만으로 결정할 수 없습니다. 해당 드라이버의 등록·매칭·defer 경로를 별도 대조해야 합니다.

1432-1500: kernel_init과 userspace init 실행

L1432-L1500: initmem 해제 후 /init 또는 /sbin/init 실행

원본 코드:
	/*
	 * Wait until kthreadd is all set-up.
	 */
	wait_for_completion(&kthreadd_done);

	kernel_init_freeable();
	/* need to finish all async __init code before freeing the memory */
	async_synchronize_full();

	system_state = SYSTEM_FREEING_INITMEM;
	kprobe_free_init_mem();
	ftrace_free_init_mem();
	kgdb_free_init_mem();
	exit_boot_config();
	free_initmem();
	mark_readonly();

	/*
	 * Kernel mappings are now finalized - update the userspace page-table
	 * to finalize PTI.
	 */
	pti_finalize();

	system_state = SYSTEM_RUNNING;
	numa_default_policy();

	rcu_end_inkernel_boot();

	do_sysctl_args();

	if (ramdisk_execute_command) {
		ret = run_init_process(ramdisk_execute_command);
		if (!ret)
			return 0;
		pr_err("Failed to execute %s (error %d)\n",
		       ramdisk_execute_command, ret);
	}

	/*
	 * We try each of these until one succeeds.
	 *
	 * The Bourne shell can be used instead of init if we are
	 * trying to recover a really broken machine.
	 */
	if (execute_command) {
		ret = run_init_process(execute_command);
		if (!ret)
			return 0;
		panic("Requested init %s failed (error %d).",
		      execute_command, ret);
	}

	if (CONFIG_DEFAULT_INIT[0] != '\0') {
		ret = run_init_process(CONFIG_DEFAULT_INIT);
		if (ret)
			pr_err("Default init %s failed (error %d)\n",
			       CONFIG_DEFAULT_INIT, ret);
		else
			return 0;
	}

	if (!try_to_run_init_process("/sbin/init") ||
	    !try_to_run_init_process("/etc/init") ||
	    !try_to_run_init_process("/bin/init") ||
	    !try_to_run_init_process("/bin/sh"))
		return 0;

	panic("No working init found.  Try passing init= option to kernel. "
	      "See Linux Documentation/admin-guide/init.rst for guidance.");

설명: 커널 초기화가 끝나면 init section을 해제하고, 마지막으로 userspace init을 실행합니다.

kernel_init()은 1435행에서 kthreadd_done을 기다립니다. rest_init()은 kthreadd_task를 설정한 뒤 718행에서 completion을 완료합니다. 이것은 실행 순서의 동기화이며 kthreadd가 이미 CPU에서 실행되었다는 증거는 아닙니다.

kernel_init_freeable()은 별도 함수입니다. SMP, workqueue, initcall 관련 세부 호출은 해당 함수 본문에서 확인할 수 있으며, 이 발췌 구간만으로 그 결과를 단정하지 않습니다.

free_initmem()은 1446행에서 호출됩니다. 초기화 전용 메모리가 해제되는 범위와 시점은 해당 함수 구현과 아키텍처에 따라 확인해야 합니다.

1462–1500행에서 ramdisk init 시도 뒤 init= 지정 명령을 시도합니다. 지정한 init= 실행이 실패하면 1480행에서 panic하므로 그 뒤 기본 init 후보로 계속 넘어가지 않습니다. 지정이 없으면 CONFIG_DEFAULT_INIT과 표준 경로 후보를 순서대로 검사합니다.