根据板子里面的启动信息,cat /proc/kmsg,对着代码看。
start_kernel函数分析
1. set_task_stack_end_magic(&init_task);
抽取关键部分
//找到栈顶位置并设置个魔术字,防止堆栈 将 thread_info 的数据覆盖; //如果是向上生长的栈,直接通过(task_thread_info + 8K - 1)找到栈底并设置魔术字 //内核栈大小一般为4K或者8K. set_task_stack_end_magic(&init_task); stackend = end_of_stack(tsk); return (unsigned long *)(task_thread_info(p) + 1); *stackend = STACK_END_MAGIC; // 0x57AC6E9D
//宏定义了就是向上生长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}
(栈向下生长的情况)
(栈向上生长的情况)
2. smp_setup_processor_id
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 __my_cpu_offset on boot CPU to avoid hang caused by * using percpu variable early, for example, lockdep will * access percpu variable inside lock_release */ set_my_cpu_offset(0); pr_info("Booting Linux on physical CPU 0x%x\n", mpidr);
先通过is_smp()函数判断是否为smp处理器
static inline bool is_smp(void){#ifndef CONFIG_SMP return false;#elif defined(CONFIG_SMP_ON_UP) extern unsigned int smp_on_up; return !!smp_on_up;#else return true;#endif}
我的是imx6ull板子,不是对称多处理器,这里宏没定义,直接返回false。
所以mpidr 为0
3. local_irq_disable
暂时禁止本地中断, 设置完相关的东西后再开启
// 禁止本地中断 local_irq_disable raw_local_irq_disable arch_local_irq_disable
4. boot_cpu_init
初始化 Boot CPU
// 设置boot cpu boot_cpu_init smp_processor_id raw_smp_processor_id current_thread_info()->cpu set_cpu_online set_cpu_active set_cpu_present set_cpu_possible
5.page_address_init
初始化高端内存线性地址中永久映射的全局变量.IMX6ULL这里的宏没开,所以这里应该是空
page_address_init // page_address_htable 是个全局结构体数组, for (i = 0; i < ARRAY_SIZE(page_address_htable); i++) INIT_LIST_HEAD(&page_address_htable[i].lh); spin_lock_init(&page_address_htable[i].lock);
6.pr_notice("%s", linux_banner);
linux_banner 字符串保存了 linux 版本号,编译主机,GCC 版本,编译 时间等信息。在开机过程中可以看到log
/* FIXED STRINGS! Don't touc.h! */const char linux_banner[] = "Linux version " UTS_RELEASE " (" LINUX_COMPILE_BY "@" LINUX_COMPILE_HOST ") (" LINUX_COMPILER ") " UTS_VERSION "\n";
以下是编译生成的文件,路径在include\generated\compile.h
#define UTS_MACHINE "arm"#define UTS_VERSION "#9 SMP PREEMPT Sat Dec 25 20:49:44 CST 2021"#define LINUX_COMPILE_BY "zrc"#define LINUX_COMPILE_HOST "zrc"#define LINUX_COMPILER "gcc version 4.9.4 (Linaro GCC 4.9-2017.01) "
7. setup_arch
初始化体系相关的部分,实现与体系和芯片有关
// 初始化体系相关的部分,实现与体系和芯片有关 setup_arch(&command_line) setup_processor(); // 从硬件获得体系相关的信息,并将该信息用于系统的初始化 // __atags_pointer 指向 DTB 所在的物理地址 mdesc = setup_machine_fdt(__atags_pointer)
号主:一枚机械专业本科生,经历了转行,从外包逆袭到芯片原厂的Linux驱动开发工程师,深入操作系统的世界,贯彻终身学习、终身成长的理念。平时喜欢折腾,寒冬之下,抱团取暖,期待你来一起探讨技术、搞自媒体副业,程序员接单和投资理财。【对了,不定期送闲置开发板、书籍、键盘等等】。
如果你想了解我的转行经验,欢迎找我交流~gongzhong号【哆哆jarvis】
一起不断探索自我、走出迷茫、找到热爱,希望和你成为朋友,一起成长~