Linux设备驱动probe过程(一)
Linux设备驱动probe系列文章:
本章介绍以built-in的方式进行打包的标准设备初始化,在系统上使用固定硬件连接方式,启动后kernel初始化阶段进行probe。
非热插拔类型设备驱动probe过程
本周比较忙,只整理了设备驱动的一些流程,记录从kernel加载到driver probe的完整过程。先贴下流程图,然后各章节描述下比较重要和晦涩的几个步骤,用数组图标①->⑦标记。
1. primary_entry
函数位于arch/arm64/kernel/head.S,汇编实现。在bl31跳转到kernel __HEAD后被调用,位于非常早期的启动阶段:
/*
* Kernel startup entry point.
...
*/
__HEAD
_head:
/*
* DO NOT MODIFY. Image header expected by Linux boot-loaders.
*/
#ifdef CONFIG_EFI
/*
* This add instruction has no meaningful effect except that
* its opcode forms the magic "MZ" signature required by UEFI.
*/
add x13, x18, #0x16
b primary_entry
#else
b primary_entry // branch to kernel start, magic
.long 0 // reserved
#endif
...
primary_entry函数主要2个作用:初始化cpu,调用__primary_switch进一步初始化kernel。
SYM_CODE_START(primary_entry)
bl preserve_boot_args
bl init_kernel_el // w0=cpu_boot_mode
adrp x23, __PHYS_OFFSET
and x23, x23, MIN_KIMG_ALIGN - 1 // KASLR offset, defaults to 0
bl set_cpu_boot_mode_flag
bl __create_page_tables
/*
* The following calls CPU setup code, see arch/arm64/mm/proc.S for
* details.
* On return, the CPU will be ready for the MMU to be turned on and
* the TCR will have been set.
*/
bl __cpu_setup // initialise processor
b __primary_switch
SYM_CODE_END(primary_entry)
1.1 __primary_switch
__primary_switch函数也为汇编,进一步调用__primary_switched。这里有个相对重要一些的步骤,将init_task(全局变量,位于init/init_task.c)保存到sp_el0寄存器中。后续访问current->xxx()初始化kernel时会用到,用于进程创建。
/*
* We don't use read_sysreg() as we want the compiler to cache the value where
* possible.
*/
static __always_inline struct task_struct *get_current(void)
{
unsigned long sp_el0