Overview of start_kernel() for Linux learning

start_kernel() content

\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" macro definition

\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

The first is about the role of "asmlinkage", "__visible" and "__init" in asmlinkage __visible void __init start_kernel(void).

Asmlinkage is a macro used to process the specified function as C language when gcc is compiled.

As a C++ function processing, in the object file (machine language) stage, information (number of parameters, parameter type information) is added to the function name.

The information added here is used to "determine which function the system should call from multiple overloaded functions with the same name".

The C language does not work on the premise that the function name contains additional information, so if the function is compiled into C++, a link error will occur.

The asmlinkage macro (extern "C") is needed to solve this error.

The following is the definition of __visible. This macro is defined differently depending on the compiler used. This definition is #define__visible (blank), or it is defined as follows:
\linux-4.18\include\linux\compiler-gcc.h

#define __visible	__attribute__((externally_visible))

As an extended function of GCC, __attribute__ can add various attributes to functions, variables, and types by parameter values.
Externally_visible is described in the function properties of gcc as follows:

externally_visible
This attribute, attached to a global variable or function, nullifies the effect of the -fwhole-program >command-line option, so the object remains visible outside the current compilation unit.
If -fwhole-program is used together with -flto and gold is used as the linker plugin, externally_visible >attributes are automatically added to functions (not variable yet due to a current gold issue) that are >accessed outside of LTO objects according to resolution file produced by gold. For other linkers that >cannot generate resolution file, explicit externally_visible attributes are still necessary.

The function of Externally_visible is to disable the gcc compilation option "-fwhole_program (optimization option)" and link between files through flto and gold.

Finally, the definition of "
__init ". \linux-4.18\include\linux\init.h

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

__section(.init.text) is a declaration used to place function data in the area where the function is initialized in the memory.
The memory part can be divided into areas where functions are placed, areas where stacks are located, areas where modules are located, and so on.
The sections of RTOS (Real Time OS) are small and easy to understand. Please investigate if you are concerned.
__cold is the same as __visible, and differs depending on the compiler.
This content is #define__cold (blank), or defined as follows.

#define __cold			__attribute__((__cold__))

The effect of specifying __cold in __attribute__ is as follows (partial excerpt):

cold
The cold attribute on functions is used to inform the compiler that the function is unlikely to be
executed. The function is optimized for size rather than speed and on many targets it is placed into
special subsection of the text section so all cold functions appears close together improving code
locality of non-cold parts of program.

Just read the description here, it seems to play the same role as __section(.init.text).
I guess, depending on the version of the compiler, only one of __section() or __cold is enabled.
The final notrace is defined as follows.
\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 prevents the recursive call of the 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 */
}

to be continued…

Guess you like

Origin blog.csdn.net/qq_18191333/article/details/113774593