x210:uboot和系统移植扩展--内核启动之C语言阶段

start_kernel 

  • printk打印内核banner信息
printk(KERN_NOTICE "%s", linux_banner);

(1)printk函数是内核中用来从console打印信息的,类似于应用层编程中的printf。内核编程时不能使用标准库函数,因此不能使用printf,其实printk就是内核自己实现的一个printf。printk函数的用法和printf几乎一样,不同之处在于可以在参数最前面用一个宏来定义消息输出的级别。级别定义0-7(注意编程的时候要用相应的宏定义,不要直接用数字)分别代表8种输出的重要性级别,0表示最重要,7表示最不重要。我们在printk的时候自己根据自己的消息的重要性去设置打印级别。linux的控制台监测消息的地方也有一个消息过滤显示机制,控制台实际只会显示级别比我的控制台定义的级别高的消息。

(2)linux_banner是内核的版本等信息,部分内容只有在编译后才能确定

  • 调用setup_arch函数创建CPU架构相关的一些东西
char * command_line;
setup_arch(&command_line);

(1)这个函数是用来确定我们当前内核的机器(arch、machine)的。我们的linux内核会支持一种CPU的运行,CPU+开发板就确定了一个硬件平台,然后我们当前配置的内核就在这个平台上可以运行。之前说过的机器码就是给这个硬件平台一个固定的编码,以表征这个平台。

(2)当前内核支持的机器码以及硬件平台相关的一些定义都在这个函数中处理

setup_arch

struct machine_desc *mdesc;

struct machine_desc结构体用来表征一个硬件平台相关的所有信息,其内部包含机器码、物理IO起始地址、硬件平台的名字、tag传参的起始地址以及一些用来操作硬件平台相关的函数指针等

setup_processor();

setup_processor函数用来查找CPU信息,其内部会读取CPU的ID号并进行一些赋值和相关初始化

mdesc = setup_machine(machine_arch_type);

setup_machine函数的传参是机器码编号,machine_arch_type符号在include/generated/mach-types.h(在配置编译阶段生成)的32039-32050行定义了。经过分析后确定这个传参值就是2456。

函数的作用是通过传入的机器码编号,找到对应这个机器码的machine_desc描述符,并且返回这个描述符的指针。

该函数主要调用lookup_machine_type函数来完成查找工作,lookup_machine_type主要调用__lookup_machine_type函数来完成查找工作

__lookup_machine_type函数的工作原理:内核在建立的时候就把各种CPU架构的信息组织成一个一个的machine_desc结构体实例,然后都给一个段属性.arch.info.init,链接的时候会保证这些描述符会被连接在一起。__lookup_machine_type就去那个那些描述符所在处依次挨个遍历各个描述符,比对看机器码哪个相同。

char *from = default_command_line;
    /* parse_early_param needs a boot_command_line */
	strlcpy(boot_command_line, from, COMMAND_LINE_SIZE);

	/* populate cmd_line too for later use, preserving boot_command_line */
	strlcpy(cmd_line, boot_command_line, COMMAND_LINE_SIZE);
	*cmdline_p = cmd_line;

 default_command_line是默认的bootargs参数,实际是一个全局变量字符数组。他被赋值为CONFIG_CMDLINE,可以在.congig中找到它的具体值。

内核对cmdline的处理思路是:内核中自己维护了一个默认的cmdline(就是.config中配置的这一个),然后uboot还可以通过tag给kernel再传递一个cmdline。如果uboot给内核传cmdline成功则内核会优先使用uboot传递的这一个;如果uboot没有给内核传cmdline或者传参失败,则内核会使用自己默认的这个cmdline。以上说的这个处理思路就是在setup_arch函数中实现的。

rest_init

  • rest_init中调用kernel_thread函数启动了2个内核线程,分别是:kernel_init和kthreadd
  • 调用schedule函数开启了内核的调度系统
  • 最终调用cpu_idle函数结束了整个内核的启动

linux内核最终的状态是:有事干的时候去执行有意义的工作(执行各个进程任务),实在没活干的时候就去死循环即执行cpu_idle

进程0、进程1、进程2 

  • 操作系统是用一个数字来表示一个进程的,这个数字就被称为这个进程的进程号。这个号码是从0开始分配的。因此这里涉及到的三个进程分别是linux系统的进程0、进程1、进程2
  • 在linux命令行下,使用ps命令可以查看当前linux系统中运行的进程情况
  • ubuntu下ps -aux可以看到当前系统运行的所有进程,可以看出进程号是从1开始的。为什么不从0开始,因为进程0不是一个用户进程,而属于内核进程。

进程0:进程0其实就是刚才讲过的idle进程,叫空闲进程,也就是死循环。
进程1:kernel_init函数

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值