当前位置: 首页 > news >正文

Linux中控制台初始化console_init函数的实现

控制台系统初始化console_init

void __init console_init(void)
{initcall_t *call;/* Setup the default TTY line discipline. */(void) tty_register_ldisc(N_TTY, &tty_ldisc_N_TTY);/** set up the console device so that later boot sequences can* inform about problems etc..*/
#ifdef CONFIG_EARLY_PRINTKdisable_early_printk();
#endif
#ifdef CONFIG_SERIAL_68360/* This is not a console initcall. I know not what it's doing here.So I haven't moved it. dwmw2 */rs_360_init();
#endifcall = &__con_initcall_start;while (call < &__con_initcall_end) {(*call)();call++;}
}

1. 函数功能概述

console_init 函数负责初始化内核控制台系统,包括注册 TTY 线路规程、处理早期打印、执行控制台驱动初始化等,为内核提供输出和交互能力

2. 代码逐段分析

2.1. 函数定义和变量声明

void __init console_init(void)
{initcall_t *call;
  • void __init:无返回值,__init 表示只在初始化阶段使用
  • initcall_t *call:初始化调用函数指针,用于遍历执行控制台初始化函数

2.2. 注册默认 TTY 线路规程

        /* Setup the default TTY line discipline. */(void) tty_register_ldisc(N_TTY, &tty_ldisc_N_TTY);
  • 设置默认的 TTY 线路规程
  • tty_register_ldisc(N_TTY, &tty_ldisc_N_TTY):注册 TTY 线路规程
    • N_TTY:线路规程编号,表示规范模式(canonical mode)
    • &tty_ldisc_N_TTY:N_TTY 线路规程的操作结构体指针
  • (void):显式忽略返回值,表示不关心注册结果
  • 作用:为终端设备建立默认的输入处理和行为规则

2.3. 早期打印支持(条件编译)

#ifdef CONFIG_EARLY_PRINTKdisable_early_printk();
#endif
  • #ifdef CONFIG_EARLY_PRINTK:条件编译,只在配置了早期打印支持时包含
  • disable_early_printk():禁用早期打印功能
  • 背景:早期打印在内核完全初始化前使用,现在正式控制台已就绪,可以关闭

2.4. 68360 串口特殊处理(条件编译)

#ifdef CONFIG_SERIAL_68360/* This is not a console initcall. I know not what it's doing here.So I haven't moved it. dwmw2 */rs_360_init();
#endif
  • #ifdef CONFIG_SERIAL_68360:针对 68360 串口的特殊处理
  • rs_360_init():68360 串口初始化函数
  • 作用:历史遗留代码,确保特定硬件的串口正常工作

2.5. 控制台初始化调用遍历

        call = &__con_initcall_start;while (call < &__con_initcall_end) {(*call)();call++;}
}
  • call = &__con_initcall_start:获取控制台初始化调用段的起始地址
  • while (call < &__con_initcall_end):循环直到初始化调用段的结束地址
  • (*call)():执行当前指向的初始化函数
  • call++:移动到下一个初始化函数指针

TTY 线路规程注册tty_register_ldisc

int tty_register_ldisc(int disc, struct tty_ldisc *new_ldisc)
{unsigned long flags;int ret = 0;if (disc < N_TTY || disc >= NR_LDISCS)return -EINVAL;spin_lock_irqsave(&tty_ldisc_lock, flags);if (new_ldisc) {tty_ldiscs[disc] = *new_ldisc;tty_ldiscs[disc].num = disc;tty_ldiscs[disc].flags |= LDISC_FLAG_DEFINED;tty_ldiscs[disc].refcount = 0;} else {if(tty_ldiscs[disc].refcount)ret = -EBUSY;elsetty_ldiscs[disc].flags &= ~LDISC_FLAG_DEFINED;}spin_unlock_irqrestore(&tty_ldisc_lock, flags);return ret;
}

1. 函数功能概述

tty_register_ldisc 函数负责注册或注销 TTY 线路规程,管理线路规程的全局表,为终端设备提供不同的输入处理和行为模式

2. 代码逐段分析

2.1. 函数定义和变量声明

int tty_register_ldisc(int disc, struct tty_ldisc *new_ldisc)
{unsigned long flags;int ret = 0;
  • int:返回值类型,0表示成功,负数表示错误码
  • int disc:线路规程编号(如 N_TTY=0, N_SLIP=1, N_PPP=3 等)
  • struct tty_ldisc *new_ldisc:要注册的线路规程结构指针,NULL表示注销
  • unsigned long flags:保存中断状态的变量
  • int ret = 0:返回值,初始化为成功

2.2. 参数有效性检查

        if (disc < N_TTY || disc >= NR_LDISCS)return -EINVAL;
  • disc < N_TTY:检查编号是否小于最小有效值(N_TTY=0)
  • disc >= NR_LDISCS:检查编号是否超过最大支持数量
  • NR_LDISCS:最大线路规程数
  • return -EINVAL:如果编号无效,返回"无效参数"错误

2.3. 获取保护锁

        spin_lock_irqsave(&tty_ldisc_lock, flags);
  • spin_lock_irqsave(&tty_ldisc_lock, flags):获取线路规程锁并保存中断状态
  • tty_ldisc_lock:保护线路规程表的自旋锁
  • flags:保存当前中断启用状态,解锁时恢复
  • 作用:防止多CPU并发修改线路规程表

2.4. 注册新线路规程分支

        if (new_ldisc) {tty_ldiscs[disc] = *new_ldisc;tty_ldiscs[disc].num = disc;tty_ldiscs[disc].flags |= LDISC_FLAG_DEFINED;tty_ldiscs[disc].refcount = 0;
  • if (new_ldisc):如果传入非空指针,执行注册操作

注册步骤:

  • tty_ldiscs[disc] = *new_ldisc:将传入的线路规程结构复制到全局数组
  • tty_ldiscs[disc].num = disc:设置线路规程编号
  • tty_ldiscs[disc].flags |= LDISC_FLAG_DEFINED:设置"已定义"标志位
  • tty_ldiscs[disc].refcount = 0:初始化引用计数为0

2.5. 注销线路规程分支

        } else {if(tty_ldiscs[disc].refcount)ret = -EBUSY;elsetty_ldiscs[disc].flags &= ~LDISC_FLAG_DEFINED;}
  • else:如果传入NULL指针,执行注销操作

注销逻辑:

  • if(tty_ldiscs[disc].refcount):检查是否有活跃引用
  • ret = -EBUSY:如果有活跃引用,返回"设备忙"错误
  • tty_ldiscs[disc].flags &= ~LDISC_FLAG_DEFINED:如果没有引用,清除"已定义"标志

2.6. 释放锁并返回

        spin_unlock_irqrestore(&tty_ldisc_lock, flags);return ret;
}
  • spin_unlock_irqrestore(&tty_ldisc_lock, flags):释放锁并恢复中断状态
  • return ret:返回操作结果(0成功,负数错误)

内核紧急情况处理panic

NORET_TYPE void panic(const char * fmt, ...)__attribute__ ((NORET_AND format (printf, 1, 2)));

1. 代码逐段分析

1.1. 返回值类型声明

NORET_TYPE void panic(const char * fmt, ...)
  • NORET_TYPE void:特殊的返回值类型声明
  • panic:函数名,表示内核恐慌/紧急状态
  • const char * fmt:格式化字符串参数,不可修改的字符串指针
  • ...:可变参数列表,表示可以接受多个参数

1.2. 函数属性声明

        __attribute__ ((NORET_AND format (printf, 1, 2)));
  • __attribute__:GCC 编译器扩展,用于指定函数属性
  • ((NORET_AND format (printf, 1, 2))):包含两个属性的复合属性

NORET_TYPE 宏定义

// 在 Linux 内核中的典型定义
#define NORET_TYPE    /* */
#define NORET_AND     noreturn,

noreturn 属性含义:

  • 告诉编译器这个函数永远不会返回
  • 函数会终止程序执行或无限循环
  • 编译器可以据此优化代码和警告

format 属性详解

format (printf, 1, 2)
  • printf:指定格式字符串风格与 printf 相同
  • 1:格式字符串参数的位置(第1个参数)
  • 2:可变参数开始的位置(从第2个参数开始)
http://www.dtcms.com/a/495525.html

相关文章:

  • pycharm 默认终端设置 cmd
  • JavaScript 加密工具 sojson.v5 全解析:原理、应用与实践
  • 【Python库包】ESMF 库包介绍及安装
  • HarmonyOS ArkUI框架自定义弹窗选型与开发实战
  • 智能体开发(2)智能数据处理Agent
  • Visual Studio在一个解决方案管理多项目属性
  • 网站图片防盗连怎么做韶关营销网站开发
  • 10.17 设置组件导航和页面路由
  • 福田做商城网站建设找哪家公司比较安全简约好看的网站模板免费下载
  • 【GD32F527_EVAL】USB 驱动移植 和 USB CDC Device 接入PC实验
  • 网站开发网站定制查看网站源代码建站可以
  • stm32_QT6怎么打包
  • c 做网站流程如何做做网站
  • 深度剖析大模型Function Calling:从原理到优化策略
  • SQL入门:表关联-从基础到优化实战
  • YOLOv3 技术总结
  • 为什么有些前端开发者能快速交付,有些还在纠结架构设计
  • Calibre(开源电子书管理软件) v8.13.0 官方便携版
  • wordpress数据库端口娄底seo排名
  • 途牛旅游网站建设方案临安区做网站的公司
  • 【原理扫描】SSL/TLS 服务器瞬时 Difie-Hellman 公共密钥过弱
  • Java-152 深入浅出 MongoDB 索引详解 从 MongoDB B-树 到 MySQL B+树 索引机制、数据结构与应用场景的全面对比分析
  • QML学习笔记(四十)QML的FileDialog和FolderDialog
  • 泉州做网站设计歌词插件wordpress
  • NLP意图识别
  • 智能科技 光速东莞网站建设番禺制作网站企业
  • 李宏毅机器学习笔记25
  • 大连模板建站哪家好网站如何加入百度联盟
  • 当大模型遇上 HTTP:一次“无状态”的相似性思考
  • 衡阳网站设计ss0734如何做公司官网