我的分析是基于Linux4.15.1

1.看看kernel是如何调用到console初始化函数的:

分两条线:

a.start_kernel  -->  console_init   --> call = __con_initcall_start

去调用放在__con_initcall_start和__con_initcall_end之间的所有函数,看看这个区间的有哪些函数.

__con_initcall_start = .;
*(.con_initcall.init)
__con_initcall_end = .;

b.start_kernel  -->  rest_init  -->  kernel_init  -->  kernel_init_freeable  --> do_basic_setup  -->  do_initcalls .

do_initcalls()将按顺序从由__initcall_start开始,到__initcall_end结束的section中以函数指针的形式取出这些编译到内核的驱动模块中初始化函数起始地址,来依次完成相应的初始化.

2.看看跟单板芯片相关的函数是如何放到__initcall这个section的。

在drivers/tty/serial/samsung.c里面有如下定义:console_initcall(s3c24xx_serial_console_init);,去include/linux/init.h里面查看console_initcall的定义:

#define console_initcall(fn) \
static initcall_t __initcall_##fn \
__used __section(.con_initcall.init) = fn

因此在执行console_init的时候,s3c24xx_serial_console_init也会被调用,进而执行register_console(&s3c24xx_serial_console);,结构体s3c24xx_serial_console的定义如下,

static struct console s3c24xx_serial_console = {
.name = S3C24XX_SERIAL_NAME,
.device = uart_console_device,
.flags = CON_PRINTBUFFER,
.index = -,
.write = s3c24xx_serial_console_write,
.setup = s3c24xx_serial_console_setup,
.data = &s3c24xx_uart_drv,
};

相当于将此结构体注册进内核,注意这里的名称:#define S3C24XX_SERIAL_NAME "ttySAC",是不是很眼熟,没错,这个就是我们在bootargs里面设置的console的名称。

这里也有一个write函数,就是通过这个函数将打印信息送到串口上的。

在register_console的时候,还会调用每个console的setup函数,对应于s3c2440的话,就是s3c24xx_serial_console_setup函数了。

    if (!has_preferred) {
if (newcon->index < )
newcon->index = ;
if (newcon->setup == NULL ||
newcon->setup(newcon, NULL) == 0) {
newcon->flags |= CON_ENABLED;
if (newcon->device) {
newcon->flags |= CON_CONSDEV;
has_preferred = true;
}
}
}

console就这样注册进内核了,如果细看注册过程,其实是将此console的信息记录到static struct console_cmdline console_cmdline[MAX_CMDLINECONSOLES];这个数组里面了,也由此可知内核最多允许8个console。

3.再看看我们传进去的console是如何跟上面注册的相关联起来的。

上面的代码是内核自动会运行的,所以可以看出,内核在初始化的时候注册了一个名为ttySAC*的console,里面还有write的函数直接操作串口,一般这个console就是ttySAC0了,这就是为什么我们在uboot里面传参数的时候console=ttySAC0的原因,就是为了跟内核里面注册的console名称匹配,每一款芯片可能这个名字都不一样,要自己看源码。

接下来就看我们传进去的console=ttySAC0是如何跟内核自动注册的console关联起来的。

在内核里面搜索"console="看看哪里解析了我们传进来的参数:

可以搜到在kernel/printk/printk.c里面有如下定义:

__setup("console=", console_setup);

当uboot通过"console="传入参数时,内核里面是用__setup宏申明的方法来处理的,前提是要名称匹配,也就是说,内核是通过调用console_setup来处理uboot传入的“console=”这个命令行的,也就是在console_cmdline[MAX_CMDLINECONSOLES]这个数组里面查看是否有相同的名称的console:

    for (i = , c = console_cmdline;
i < MAX_CMDLINECONSOLES && c->name[];
i++, c++) {
if (strcmp(c->name, name) == && c->index == idx) {
if (!brl_options)
preferred_console = i;
return ;
}
}

如果找到名称匹配的,则将其记录在preferred_console这个变量里,关于console_setup这个函数的分析,网上很多,我这里就不细讲了。

这样用户指定的console就用起来了。

梳理一遍:

用户指定console    -->    在内核注册的console里面有这个设备   -->  于是通过名字建立了关系。

Linux之prink原理的更多相关文章

  1. [转载]Linux Bond的原理及其不足

    本文转自http://www.yunweipai.com/archives/1969.html 支持原创.尊重原创,分享知识! 在企业及电信Linux服务器环境上,网络配置都会使用Bonding技术做 ...

  2. Linux Bond的原理及其不足

    http://www.tektea.com/archives/1969.html. 在企业及电信Linux服务器环境上,网络配置都会使用Bonding技术做网口硬件层面的冗余,防止单个网口应用的单点故 ...

  3. linux下的X server:linux图形界面原理

    linux下的X server:linux图形界面原理   Moblin Core是在Gnome Mobile的平台上建立.我以前玩Linux,提交的都和图像没有关系,连Xwindows都不用启动,开 ...

  4. Linux Kbuild工作原理分析(以DVSDK生成PowerVR显卡内核模块为例)

    一.引文 前篇博文<Makefile之Linux内核模块的Makefile写法分析>,介绍了Linux编译生成内核驱动模块的Makefile的写法,但最近在DVSDK下使用Linux2.6 ...

  5. [转帖]linux下的X server:linux图形界面原理

    linux下的X server:linux图形界面原理 https://www.cnblogs.com/liangxiaofeng/p/5034912.html linux下的X server:lin ...

  6. Linux 文件删除原理_009

    ***了解Linux文件删除原理先了解一下文件inode索引节点,每个文件在Linux系统里都有唯一的索引节点(身份证号) inode.如果文件存在硬链接,那这个文件和这个文件的硬链接的inode是相 ...

  7. Java网络编程和NIO详解6:Linux epoll实现原理详解

    Java网络编程和NIO详解6:Linux epoll实现原理详解 本系列文章首发于我的个人博客:https://h2pl.github.io/ 欢迎阅览我的CSDN专栏:Java网络编程和NIO h ...

  8. 转 Linux内存管理原理

    Linux内存管理原理 在用户态,内核态逻辑地址专指下文说的线性偏移前的地址Linux内核虚拟3.伙伴算法和slab分配器 16个页面RAM因为最大连续内存大小为16个页面 页面最多16个页面,所以1 ...

  9. ARM Linux系统调用的原理

    转载自:http://blog.csdn.net/hongjiujing/article/details/6831192 ARM Linux系统调用的原理 操作系统为在用户态运行的进程与硬件设备进行交 ...

随机推荐

  1. Vue学习Day003

    事件修饰符 在事件处理程序中调用 event.preventDefault() 或 event.stopPropagation() 是非常常见的需求.尽管我们可以在方法中轻松实现这点,但更好的方式是: ...

  2. JAVA Character类

    字符可以用char类型声明: char ch = 'a'; // Unicode 字符表示形式 char uniChar = '\u039A'; // 字符数组 char[] charArray ={ ...

  3. 原生js实现淘宝图片切换

    这个淘宝图片切换具体效果就是:鼠标移上底部一行中的小图片,上面大图片区域就会显示对应的图片. gif图片看起来还挺酷的,其实实现很简单,用原生js绑定事件改变大图片区域的src. 上代码,html部分 ...

  4. Js的运算符

    JS的运算符 1.运算符的分类: a) 算数运算符 b) 字符串运算符 c) 赋值运算符 d) 比较运算符 e) 逻辑运算符 f) 位运算符 g) 其他运算符 2.算数运算符 + 加法运算符 - 减法 ...

  5. CPU温度的实现

    CPU温度需要安装的模块:apt-get install lm-sensors   然后再安装:pip install sensors.py 代码如下: #coding=utf-8import sen ...

  6. ORA-01555快照过旧报错

    一.现象 将数据迁移到新库时,执行较大的存过,会报这个错误. 二.原因 产生该报错的原因: (1)sql执行比较久,需要优化sql (2)回滚段过小 (3)undo保存时间过短 三.具体检查及恢复 1 ...

  7. 用indexof来统计字符出现的次数

    代码如下: <!DOCTYPE html> <html lang="en"> <head>     <meta charset=" ...

  8. 【转】Android-Input input&按键布局文件

    https://source.android.com/devices/input 输入 Android 输入子系统名义上是由遍历系统多个层的事件管道组成. 输入管道 在最低层,物理输入设备会生成描述状 ...

  9. 巧用std::shared_ptr全局对象释放单例内存

    巧用std::shared_ptr 单例的使用相对比较广泛,但是需要在程序退出前调用它的析构函数对数据进行释放,常规做法是在main函数末尾进行释放工作, 但是这样相对比较繁琐,因此便有了利用全局变量 ...

  10. C语言关键字分类整理

    C语言总览: 强类型,面向过程 简洁.灵活:32个关键字(C99标准新增5个,C11新增7个),9种控制语句,34种运算符 数据类型丰富,运算符丰富 结构化(控制语句).模块化(函数) 灵魂.特色:指 ...