[linux kernel]start_ Early operation of kernel function

1, Opening

(note) the source code of this article is based on the linux kernel version: 4.1.15.

At start_ At the beginning of the kernel() function, two variables are defined:

	char *command_line;
	char *after_dashes;

The first represents a pointer to the kernel command line, and the second is used to contain parse_ The result of the args() function, which parses the input string with a formal parameter of name=value, finds a specific keyword and calls the correct handler.

Next, start_ The kernel () function calls set_task_stack_end_magic() function. This function obtains the address of init task and sets stack_ END_ Magic (0x57ac6e9d) is used as its "magic number" to prevent stack overflow. It is defined as follows:

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 */
}

At start_ When kenrel () calls this function, the parameter passed in is init_ The address of the task global variable. init task represents the initial task structure, which is defined as follows (/ init/init_task.c):

struct task_struct init_task = INIT_TASK(init_task);

struct task_ The struct task structure, which stores all the information about the process, is very large. Defined in the (/ include/linux/sched.c) file, the structure contains more than 100 fields, which can be called the largest structure definition in the linux kernel.

In set_ task_ stack_ end_ In the magic() function, use end_ of_ The stack() function gets init_task represents the last available address on the thread stack, and then stack_ END_ Magic (0x57ac6e9d) is set to this address. end_ of_ The stack() function is defined as follows:

static inline unsigned long *end_of_stack(struct task_struct *p)
{
#ifdef CONFIG_STACK_GROWSUP
	return (unsigned long *)((unsigned long)task_thread_info(p) + THREAD_SIZE) - 1;
#else
	return (unsigned long *)(task_thread_info(p) + 1);
#endif
}

As can be seen from the above code, end_ of_ The return value of stack() is determined by config_ STACK_ This paper takes the ARM architecture as an example. Its stack grows downward, so there is no definition of CONFIG_STACK_GROWSUP macro, so end_ of_ The stack() function will execute the following code:

	return (unsigned long *)(task_thread_info(p) + 1);

task_thread_info() returns init_ Stack filled by task:

#define task_thread_info(task)  ((struct thread_info *)(task)->stack)

Next, start_ The kernel() function will call smp_setup_processor_id() function, which is an architecture related function. Under the ARM architecture, its contents are as follows (/ arch/arm/kernel/setup.c):

void __init smp_setup_processor_id(void)
{
	int i;
	u32 mpidr = is_smp() ? read_cpuid_mpidr() & MPIDR_HWID_BITMASK : 0;
	u32 cpu = MPIDR_AFFINITY_LEVEL(mpidr, 0);

	cpu_logical_map(0) = cpu;
	for (i = 1; i < nr_cpu_ids; ++i)
		cpu_logical_map(i) = i == cpu ? 0 : i;

   /* Clear the cpu offset when starting the cpu to avoid hangs caused by premature use of the percpu variable */
	set_my_cpu_offset(0);
	
    /* Print out CPU related information on the console */
	pr_info("Booting Linux on physical CPU 0x%x\n", mpidr);
}

start_ The next function of kernel () is debug_objects_early_init(). The definitions are as follows (/ lib/debugobjects.c):

void __init debug_objects_early_init(void)
{
	int i;
	
    /* Initialize object hash table lock */
	for (i = 0; i < ODEBUG_HASH_SIZE; i++)
		raw_spin_lock_init(&obj_hash[i].lock);
	
    /* Will obj_static_pool object linked to obj_ In pool */
	for (i = 0; i < ODEBUG_POOL_SIZE; i++)
		hlist_add_head(&obj_static_pool[i].node, &obj_pool);
}

This function is called during the early boot of the linux kernel to initialize the hash table structure and link the static object pool object (obj_static_pool) to obj_ In the pool. In debug_ objects_ early_ After the init () call, the object tracker is fully operational. obj_ static_ Pool is defined as follows:

static struct debug_obj		obj_static_pool[ODEBUG_POOL_SIZE] __initdata;

In debug_ objects_ early_ After the init() function, boot is called_ init_ stack_ canary () function (Note: this function is an architecture related function), which fills the - > stack of the current task with the canary value of the - fstack protector GCC feature_ canary value. This operation depends on CONFIG_CC_STACKPROTECTOR configuration option. If this option is disabled, boot_init_stack_canary() does nothing. The following code (/ arch / arm / include / ASM / stackproctor. H):

static __always_inline void boot_init_stack_canary(void)
{
	unsigned long canary;

	get_random_bytes(&canary, sizeof(canary));
	canary ^= LINUX_VERSION_CODE;

	current->stack_canary = canary;
	__stack_chk_guard = current->stack_canary;
}

Next, start_ The kernel() function will call boot_cpu_init() function, which is defined as follows:

static void __init boot_cpu_init(void)
{
	int cpu = smp_processor_id();
	/* Mark the boot cpu "present", "online" etc for SMP and UP case */
	set_cpu_online(cpu, true);
	set_cpu_active(cpu, true);
	set_cpu_present(cpu, true);
	set_cpu_possible(cpu, true);
}

boot_ cpu_ The init() function is used to activate the first processor. In this function, SMP is called first_ processor_ ID () gets the ID of the current CPU, and then marks the startup CPU as "present", "online", "active" and "possible".

Next, call:

pr_notice("%s", linux_banner);

Print out the banner information of linux kernel. pr_notice() essentially encapsulates the printk() function, as shown in the following code:

#define pr_notice(fmt, ...) \
    printk(KERN_NOTICE pr_fmt(fmt), ##__VA_ARGS__)

During linux kernel startup, the information shown in the figure below will be printed, which is completed by this line of code.

2, Conclusion

The text describes start_ At the beginning of the kernel() function, these functions are written together because they are short. Some functions are related to the specific architecture, so there may be different situations under different architectures and different linux versions. Therefore, it needs to be analyzed in combination with the linux kernel source code.

Search / follow [embedded student] wx official account to get more exciting content > > > >

Tags: Linux

Posted by spdwrench on Thu, 12 May 2022 22:35:06 +0300