Linux学習用のstart_kernel()の概要

start_kernel()コンテンツ

\ linux-4.18 \ init \ main.c

asmlinkage __visible void __init start_kernel(void)
{
    
    
	char *command_line;
	char *after_dashes;

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

	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);
	setup_arch(&command_line);
	/*
	 * Set up the the initial canary and entropy after arch
	 * and after adding latent and command line entropy.
	 */
	add_latent_entropy();
	add_device_randomness(command_line, strlen(command_line));
	boot_init_stack_canary();
	mm_init_cpumask(&init_mm);
	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();

	build_all_zonelists(NULL);
	page_alloc_init();

	pr_notice("Kernel command line: %s\n", boot_command_line);
	parse_early_param();
	after_dashes = parse_args("Booting kernel",
				  static_command_line, __start___param,
				  __stop___param - __start___param,
				  -1, -1, NULL, &unknown_bootoption);
	if (!IS_ERR_OR_NULL(after_dashes))
		parse_args("Setting init args", after_dashes, NULL, 0, -1, -1,
			   NULL, set_init_arg);

	jump_label_init();

	/*
	 * These use large bootmem allocations and must precede
	 * kmem_cache_init()
	 */
	setup_log_buf(0);
	vfs_caches_init_early();
	sort_main_extable();
	trap_init();
	mm_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();
	/*
	 * Disable preemption - early bootup scheduling is extremely
	 * fragile until we cpu_idle() for the first time.
	 */
	preempt_disable();
	if (WARN(!irqs_disabled(),
		 "Interrupts were enabled *very* early, fixing it\n"))
		local_irq_disable();
	radix_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();
	hrtimers_init();
	softirq_init();
	timekeeping_init();
	time_init();
	sched_clock_postinit();
	printk_safe_init();
	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_info();

	/*
	 * 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();

	/*
	 * This needs to be called before any devices perform DMA
	 * operations that might use the SWIOTLB bounce buffers. It will
	 * mark the bounce buffers as decrypted so that their usage will
	 * not cause "plain-text" data to be decrypted when accessed.
	 */
	mem_encrypt_init();

#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
	page_ext_init();
	kmemleak_init();
	debug_objects_mem_init();
	setup_per_cpu_pageset();
	numa_policy_init();
	acpi_early_init();
	if (late_time_init)
		late_time_init();
	calibrate_delay();
	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();
	buffer_init();
	key_init();
	security_init();
	dbg_late_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();

	check_bugs();

	acpi_subsystem_init();
	arch_post_acpi_subsys_init();
	sfi_init_late();

	if (efi_enabled(EFI_RUNTIME_SERVICES)) {
    
    
		efi_free_boot_services();
	}

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

"Asmlinkage"、 "__visible"、 "__ init"マクロ定義

\ linux-4.18 \ include \ linux \ linkage.h

#ifdef __cplusplus
#define CPP_ASMLINKAGE extern "C"
#else
#define CPP_ASMLINKAGE
#endif

#ifndef asmlinkage
#define asmlinkage CPP_ASMLINKAGE
#endif

1つ目は、asmlinkage __visible void __init start_kernel(void)での「asmlinkage」、「__ visible」および「__init」の役割についてです。

Asmlinkageは、gccのコンパイル時に、指定された関数をC言語として処理するために使用されるマクロです。

C ++関数の処理として、オブジェクトファイル(機械語)の段階で、情報(パラメーターの数、パラメーターの型の情報)が関数名に追加されます。

ここで追加された情報は、「システムが同じ名前の複数のオーバーロードされた関数から呼び出す必要がある関数を決定する」ために使用されます。

C言語は、関数名に追加情報が含まれていることを前提として機能しないため、関数をC ++にコンパイルすると、リンクエラーが発生します。

このエラーを解決するには、asmlinkageマクロ(extern "C")が必要です。

以下は__visibleの定義です。このマクロは、使用するコンパイラーによって定義が異なります。この定義は#define__visible(空白)であるか、次のように定義されています:
\ linux-4.18 \ include \ linux \ compiler-gcc.h

#define __visible	__attribute__((externally_visible))

GCCの拡張関数として、__ attribute__は、パラメーター値によって関数、変数、およびタイプにさまざまな属性を追加できます。
Externally_visibleは、gccの関数プロパティで次のように記述されています。

externally_visible
この属性は、グローバル変数または関数に付加され、-fwhole-program>コマンドラインオプションの効果を無効にするため、オブジェクトは現在のコンパイルユニットの外部に表示されたままになります。
-fwhole-programが-fltoと一緒に使用され、goldがリンカープラグインとして使用される場合、externally_visible属性は、解決に従ってLTOオブジェクトの外部からアクセスされる関数(現在のゴールドの問題のためにまだ可変ではありません)に自動的に追加されます。金で作られたファイル。>解決ファイルを生成できない他のリンカーの場合でも、明示的なexternally_visible属性が必要です。

Externally_visibleの機能は、gccコンパイルオプション「-fwhole_program(最適化オプション)」を無効にし、fltoとgoldを介してファイル間をリンクすることです。

最後に、「
__ init 」の定義。\ linux-4.18 \ include \ linux \ init.h

#define __init		__section(.init.text) __cold  __latent_entropy __noinitretpoline

__section(.init.text)は、関数がメモリ内で初期化される領域に関数データを配置するために使用される宣言です。
メモリ部分は、関数が配置される領域、スタックが配置される領域、モジュールが配置される領域などに分割できます。
RTOS(Real Time OS)のセクションは小さく、理解しやすいです。懸念がある場合は調査してください。
__coldは__visibleと同じで、コンパイラによって異なります。
このコンテンツは#define__cold(空白)であるか、次のように定義されています。

#define __cold			__attribute__((__cold__))

__attribute__で__coldを指定した場合の効果は次のとおりです(部分的な抜粋)。

cold
関数のcold属性は、関数が
実行される可能性が低いことをコンパイラーに通知するために使用されます。この関数は速度ではなくサイズに最適化されており、多くのターゲットでは
テキストセクションの特別なサブセクションに配置されるため、すべてのコールド関数が近くに表示され
、プログラムのコールドでない部分のコードの局所性が向上します

ここの説明を読んでください。__section(.init.text)と同じ役割を果たしているようです。
コンパイラのバージョンに応じて、__ section()または__coldのいずれかのみが有効になっていると思います。
最終的なnotraceは次のように定義されます。
\ linux-4.18 \ include \ linux \ compiler_types.h

#if defined(CC_USING_HOTPATCH) && !defined(__CHECKER__)
#define notrace __attribute__((hotpatch(0,0)))
#else
#define notrace __attribute__((no_instrument_function))
#endif

No_instrument_functionは、関数の再帰呼び出しを防ぎます。

set_task_stack_end_magic

\ linux-4.18 \ kernel \ fork.c

void set_task_stack_end_magic(struct task_struct *tsk)
{
    
    
	unsigned long *stackend;

	stackend = end_of_stack(tsk);
	*stackend = STACK_END_MAGIC;	/* for overflow detection */
}

つづく…

おすすめ

転載: blog.csdn.net/qq_18191333/article/details/113774593