Linux0.11内核源码解析-printk

printk实现原理

printk->tty_write->con_write

printk格式化输出

printk的函数,用于在控制台上输出格式化的字符串。

该函数使用了可变参数列表,可以接受任意数量的参数。

首先,使用va_start宏初始化一个va_list类型的变量args,然后使用vsprintf函数将格式化的字符串和可变参数列表args打印到一个缓冲区buf中,返回打印的字符数。

首先将fs寄存器和ds寄存器的值压入栈中,然后将fs寄存器的值设置为ds寄存器的值,这是为了在访问buf时使用fs寄存器,因为fs寄存器通常用于指向当前进程的TSS(任务状态段),而TSS中包含了当前进程的内核栈。然后将打印的字符数i压入栈中,接着将buf的地址和一个值为0的参数依次压入栈中,调用tty_write函数将buf中的内容写入控制台。最后,将栈中的值弹出,恢复fs寄存器和ds寄存器的值,返回打印的字符数i。

static char buf[1024];extern int vsprintf(char * buf, const char * fmt, va_list args);int printk(const char *fmt, ...)
{va_list args;int i;va_start(args, fmt);i=vsprintf(buf,fmt,args);va_end(args);__asm__("push %%fs\n\t""push %%ds\n\t""pop %%fs\n\t""pushl %0\n\t""pushl $buf\n\t""pushl $0\n\t""call tty_write\n\t""addl $8,%%esp\n\t""popl %0\n\t""pop %%fs"::"r" (i):"ax","cx","dx");return i;
}

 tty_write终端输出函数

tty_write函数,用于将字符数组buf中的内容写入到指定通道channel对应的终端设备中。函数的返回值是成功写入的字符数。

函数首先检查通道号是否大于2或者写入字符数nr是否小于0,如果是,则返回-1表示错误。

接下来,函数通过将通道号channel与tty_table相加,得到对应的tty_struct结构体指针tty。

然后,函数进入一个循环,直到写入字符数nr为0。在每次循环中,函数会调用sleep_if_full函数,如果写入队列tty->write_q已满,则会使当前进程进入睡眠状态,直到队列有足够的空间。

接着,函数检查当前进程是否有信号待处理,如果有,则跳出循环。

然后,函数进入一个嵌套循环,直到写入字符数nr为0或者写入队列tty->write_q已满。在每次循环中,函数从buf中读取一个字符c,并根据终端设备的配置进行处理。处理包括:将回车符'\r'转换为换行符'\n'(如果配置允许),将换行符'\n'转换为回车符'\r'(如果配置允许),将换行符'\n'转换为回车符'\r'并插入队列中(如果配置允许),将字符转换为大写(如果配置允许)。然后,指针b向后移动一位,写入字符数nr减1,重置cr_flag为0,并将字符c插入到写入队列tty->write_q中。

接着,函数调用tty->write函数,将写入队列中的字符进行实际的写入操作。

如果写入字符数nr仍大于0,则调用schedule函数进行进程调度,让其他进程有机会执行。

int tty_write(unsigned channel, char * buf, int nr)
{static int cr_flag=0;struct tty_struct * tty;char c, *b=buf;if (channel>2 || nr<0) return -1;tty = channel + tty_table;while (nr>0) {sleep_if_full(&tty->write_q);if (current->signal)break;while (nr>0 && !FULL(tty->write_q)) {c=get_fs_byte(b);if (O_POST(tty)) {if (c=='\r' && O_CRNL(tty))c='\n';else if (c=='\n' && O_NLRET(tty))c='\r';if (c=='\n' && !cr_flag && O_NLCR(tty)) {cr_flag = 1;PUTCH(13,tty->write_q);continue;}if (O_LCUC(tty))c=toupper(c);}b++; nr--;cr_flag = 0;PUTCH(c,tty->write_q);}tty->write(tty);if (nr>0)schedule();}return (b-buf);
}

con_write将字符写入终端

函数内部定义了一些变量,包括nr和c,分别表示写入队列中字符的数量和当前字符。

接下来使用while循环,循环次数为写入队列中字符的数量。

在循环中,使用GETCH宏从写入队列中获取一个字符,并使用switch语句根据字符的不同进行不同的操作。

在case 0中,如果字符的ASCII码在31和127之间,表示是可打印字符,会进行一系列的操作,包括判断是否需要换行、设置字符属性、更新光标位置等。

在case 1中,如果字符是'[',表示后面是控制序列,会进入case 2进行处理。

在case 2中,会解析控制序列中的参数,并根据参数执行相应的操作,比如移动光标、清除屏幕等。

最后,调用set_cursor函数设置光标位置。

void con_write(struct tty_struct * tty)
{int nr;char c;nr = CHARS(tty->write_q);while (nr--) {GETCH(tty->write_q,c);switch(state) {case 0:if (c>31 && c<127) {if (x>=video_num_columns) {x -= video_num_columns;pos -= video_size_row;lf();}__asm__("movb attr,%%ah\n\t""movw %%ax,%1\n\t"::"a" (c),"m" (*(short *)pos));pos += 2;x++;} else if (c==27)state=1;else if (c==10 || c==11 || c==12)lf();else if (c==13)cr();else if (c==ERASE_CHAR(tty))del();else if (c==8) {if (x) {x--;pos -= 2;}} else if (c==9) {c=8-(x&7);x += c;pos += c<<1;if (x>video_num_columns) {x -= video_num_columns;pos -= video_size_row;lf();}c=9;} else if (c==7)sysbeep();break;case 1:state=0;if (c=='[')state=2;else if (c=='E')gotoxy(0,y+1);else if (c=='M')ri();else if (c=='D')lf();else if (c=='Z')respond(tty);else if (x=='7')save_cur();else if (x=='8')restore_cur();break;case 2:for(npar=0;npar<NPAR;npar++)par[npar]=0;npar=0;state=3;if ((ques=(c=='?')))break;case 3:if (c==';' && npar<NPAR-1) {npar++;break;} else if (c>='0' && c<='9') {par[npar]=10*par[npar]+c-'0';break;} else state=4;case 4:state=0;switch(c) {case 'G': case '`':if (par[0]) par[0]--;gotoxy(par[0],y);break;case 'A':if (!par[0]) par[0]++;gotoxy(x,y-par[0]);break;case 'B': case 'e':if (!par[0]) par[0]++;gotoxy(x,y+par[0]);break;case 'C': case 'a':if (!par[0]) par[0]++;gotoxy(x+par[0],y);break;case 'D':if (!par[0]) par[0]++;gotoxy(x-par[0],y);break;case 'E':if (!par[0]) par[0]++;gotoxy(0,y+par[0]);break;case 'F':if (!par[0]) par[0]++;gotoxy(0,y-par[0]);break;case 'd':if (par[0]) par[0]--;gotoxy(x,par[0]);break;case 'H': case 'f':if (par[0]) par[0]--;if (par[1]) par[1]--;gotoxy(par[1],par[0]);break;case 'J':csi_J(par[0]);break;case 'K':csi_K(par[0]);break;case 'L':csi_L(par[0]);break;case 'M':csi_M(par[0]);break;case 'P':csi_P(par[0]);break;case '@':csi_at(par[0]);break;case 'm':csi_m();break;case 'r':if (par[0]) par[0]--;if (!par[1]) par[1] = video_num_lines;if (par[0] < par[1] &&par[1] <= video_num_lines) {top=par[0];bottom=par[1];}break;case 's':save_cur();break;case 'u':restore_cur();break;}}}set_cursor();
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/224101.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

使用海康SDK开发软件在发布注意事项

【注意事项】 Windows环境下: 更新设备网络SDK时&#xff0c;SDK开发包【库文件】里的HCNetSDK.dll、HCCore.dll、HCNetSDKCom文件夹、libssl-1_1.dll、libcrypto-1_1.dll、hlog.dll、hpr.dll、zlib1.dll、PlayCtrl.dll、SuperRender.dll、AudioRender.dll等文件均要加载到程序…

vue_域名部署无法访问后端

前言 目前部署的比较另类&#xff0c;因为服务器为windows&#xff0c;目前还不是很会nginx&#xff0c;所以现在就只能在服务器上安装nodejs&#xff0c;然后直接使用npm run dev命令行的方式运行项目 遇到的坑 使用ip访问前端的时候&#xff0c;就可以访问&#xff0c;但是…

压缩照片怎么压缩?半分钟解决!

有时候我们在平台上传照片的时候&#xff0c;会有图片大小限制&#xff0c;想要将照片压缩到限制的大小范围内&#xff0c;可以使用专业的图片压缩软件、图片处理软件或者在线网站压缩&#xff0c;下面给大家分享三个方法&#xff0c;压缩照片的同时还能保持图片清晰度哦&#…

Windows10安装Node.js环境

Windows10安装Node.js环境 文章目录 1.下载安装包2.安装配置2.1安装2.2 配置全局的安装路径和缓存路径2.3配置环境变量2.4配置镜像源2.5包管理工具 3.查看版本4.编译跑项目5.总结 1.下载安装包 官方下载网址如下&#xff1a; https://nodejs.org/enInstaller表示是安装程序&a…

【回眸】Tessy 单元测试软件使用指南(三)怎么打桩和指针测试

目录 前言 Tessy 如何进行打桩操作 普通桩 高级桩 手写桩 Tessy单元测试之指针相关测试注意事项 有类型的指针&#xff08;非函数指针&#xff09;&#xff1a; 有类型的函数指针&#xff1a; void 类型的指针&#xff1a; 结语 前言 进行单元测试之后&#xff0c;但凡…

nestjs上传文件

官方文档 目标 前端调用接口上传文件&#xff0c;将文件存储到服务端 /public/upload/ 目录中&#xff0c;接口返回文件路径 注意&#xff1a;示例代码都使用app模块为例&#xff0c;实际可放到任意模块 上传文件 app.controller.ts 新增接口声明 import { Controller, G…

LED透镜粘接UV胶是一种特殊的UV固化胶

LED透镜粘接UV胶是一种特殊的UV固化胶&#xff0c;用于固定和粘合LED透镜。 它具有以下特点&#xff1a; 1. 高透明度&#xff1a;LED透镜粘接UV胶具有高透明度&#xff0c;可以确保光线的透过性&#xff0c;不影响LED的亮度和效果。 2. 快速固化&#xff1a;经过UV紫外线照射…

HTTP 404错误:页面未找到,如何解决

在互联网上浏览时&#xff0c;偶尔会遇到“HTTP 404错误&#xff1a;页面未找到”的提示。这通常意味着用户尝试访问的网页不存在或无法找到。本文将探讨HTTP 404错误的原因以及如何解决这个问题。 一、HTTP 404错误的原因 HTTP 404错误可能是由多种原因引起的。以下是一些常…

SQL进阶理论篇(五):什么是Hash索引

文章目录 简介MySQL中的Hash索引与B树的区别总结参考文献 简介 hash&#xff0c;即哈希&#xff0c;也被称为是散列函数。 Hash在数据库中的应用&#xff0c;可以帮助我们大幅度提升检索数据的效率。 大名鼎鼎的MD5其实就是Hash函数的一种变体。 Hash算法&#xff0c;是通过…

富文本 unpkg.com地址无法访问可替代方案

一、背景&#xff1a; 项目中使用的 wangEditor富文本&#xff0c;使用的地址为&#xff1a;https://unpkg.com &#xff0c;但无法访问&#xff0c;富文本加载不出来&#xff0c;一直转圈圈 二、解决方案&#xff1a; 2.1、方案一 &#xff1a; 将项目中 https://unpkg.co…

k8s容器部署mysql5.7全流程分享

文章目录 一、前言二、打开dockerhub 看到mysql的版本为 5.7三、K8S 容器编排3.1、编写POD的相关信息3.2、编写mysql的data存储位置3.3、编写mysql的my.cnf的挂载文件3.4、编写mysql的service端口 四、启动并禁用root账户4.1 登录&#xff0c;默认密码1234564.2 配置账户权限 五…

Linux系统编程(二):标准 I/O 库(下)

参考引用 UNIX 环境高级编程 (第3版)嵌入式Linux C应用编程-正点原子 1. 标准 I/O 库简介 标准 I/O 库是指&#xff1a;标准 C 库中用于文件 I/O 操作&#xff08;如&#xff1a;读、写文件等&#xff09;相关的一系列库函数的集合 标准 I/O 库函数相关的函数定义都在头文件 &…

【MySQL学习之基础篇】概述

文章目录 1. mysql的启动和停止命令2. 客户端连接3. 数据模型 1. mysql的启动和停止命令 通过指令启动或停止&#xff0c;以管理员身份运行cmd&#xff0c;进入命令行执行如下指令&#xff1a; &#xff08;1&#xff09;启动myaql net start mysql&#xff08;2&#xff09;…

PyTorch: 基于【VGG16】处理MNIST数据集的图像分类任务【准确率98.9%+】

目录 引言在Conda虚拟环境下安装pytorch步骤一&#xff1a;利用代码自动下载mnist数据集步骤二&#xff1a;搭建基于VGG16的图像分类模型步骤三&#xff1a;训练模型步骤四&#xff1a;测试模型运行结果后续模型的优化和改进建议完整代码结束语 引言 在本博客中&#xff0c;小…

商城后台管理系统--->新闻简报(富文本编辑器,文章,图片上传)

在商城的项目里面需要添加新闻&#xff0c;使用富文本编辑器&#xff0c;我用的是 wangEditor这个编辑器挺好用的&#xff0c;而且也方便简单&#xff0c;官网也是中文的wangEditor 这是做的添加新闻的页面 我用的是SCUI框架,引入的是npm,具体可看官网 npm install wangedit…

nginx配置kibana代理

1、nginx配置 location /kibana/ {proxy_pass http://192.168.0.32:5601;proxy_redirect off;proxy_set_header Host $host;proxy_set_header X-Real-IP $remote_addr;proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;} 2、kibana配置 server.basePath&#xf…

【Docker实战】基于Dockerfile搭建LNMP+wordpress

一、项目背景和要求 公司在实际的生产环境中&#xff0c;需要使用Docker 技术在一台主机上创建LNMP服务并运行Wordpress网站平台。 然后对此服务进行相关的性能调优和管理工作 二、架构&#xff1a; nginx172.111.0.10docker-nginxmysql172.111.0.20docker-mysqlPHP172.111…

C++试卷

_____________ ________ … 一、单项选择题。(每小题2分, 共20分) &#xff11;、下列合法的变量名是&#xff08; C &#xff09;。 &#xff08;A&#xff09;8d &#xff08;B&#xff09; 1_2h   &#xff08;C&#xff09;_int &#xff08;D&…

map 和 multimap 存储区别 、取消自动排序 unordered_map

测试代码 std::map<int, CString > Map1;Map1.insert({ 6, L"HN400*200*11*8" });Map1.insert({ 5, L"HN200*200*11*8" });Map1.insert({ 7, L"HN100*200*11*8" });Map1.insert({ 4, L"HN200*200*11*8" });Map1.insert({ 4, L…

【开发工具】最新VMWare无法识别USB设备,驱动错误,未知错误【2023.12.15】

解决方案1&#xff1a;在这里改下连接方式 多试试 解决方案2 控制面板卸载程序&#xff0c;进行VMWare的修复 解决方案3 对于Windows7系统&#xff0c;切换解决方案1的usb类型为3.1&#xff0c;并下载这个intel的驱动包到虚拟机里 https://www.intel.com/content/www/us/en/do…