riscv架构下linux4.15实现early打印

在高版本linux6.12.7源码中,early console介绍,可参考《riscv架构下linux6.12.7实现early打印》文章。

1 什么是early打印

适配内核到新的平台,基本环境搭建好之后,首要的就是要调通串口,方便后面的信息打印。
正常流程 init/main.c 中 start_kernel 入口,要到 console_init 之后才能真正打印,前面的打印,都是缓存在 printk 的 ringbuffer 中的。
如果在 console_init 前就异常了,此时就看不到打印信息,为了调试 console_init 前的状态,需要能更早的打印,内核提供了一种 early 打印的方式,尤其是 riscv 平台我们可以直接 ecall 调用 opensbi 的打印,这样 opensbi 适配好之后,这里就可以直接使用。

earlyprintk 的实现依赖于特定的硬件平台,并且通常与特定固件配合使用。
earlyprintk 是一个高级功能,主要用于内核开发和调试。在生产环境中,通常不需要启用此功能,因为它可能会干扰系统的正常启动过程,或暴露潜在的敏感信息。

从 earlyprintk 到串行控制台的转换,通常发生在内核初始化过程中,特别是在 register_console 函数被调用之后。这个函数负责注册串行控制台,并使其成为内核默认的打印信息输出设备。一旦串行控制台被注册,内核就会开始使用它来输出打印信息,而 earlyprintk 则不再被需要。

2 printk函数实现

printk函数代码实现,如下所示:

// 1.riscv-linux-4.15/include/linux/printk.h:
#define pr_info(fmt, ...) \printk(KERN_INFO pr_fmt(fmt), ##__VA_ARGS__)  调用==>// 2.riscv-linux-4.15/kernel/printk/printk.c:
asmlinkage __visible int printk(const char *fmt, ...)
{va_list args;int r;va_start(args, fmt);r = vprintk_func(fmt, args);   调用==>va_end(args);return r;
}// 3.riscv-linux-4.15/kernel/printk/printk_safe.c:
__printf(1, 0) int vprintk_func(const char *fmt, va_list args)
{...return vprintk_default(fmt, args);    调用==>
}// 4.riscv-linux-4.15/kernel/printk/printk.c:
int vprintk_default(const char *fmt, va_list args)
{...r = vprintk_emit(0, LOGLEVEL_DEFAULT, NULL, 0, fmt, args);    调用==>return r;
}// 5.riscv-linux-4.15/kernel/printk/printk.c:
asmlinkage int vprintk_emit(int facility, int level,const char *dict, size_t dictlen,const char *fmt, va_list args)
{...printed_len = log_output(facility, level, lflags, dict, dictlen, text, text_len);...console_unlock();    调用==>...
}// 6.riscv-linux-4.15/kernel/printk/printk.c:
void console_unlock(void)
{...call_console_drivers(ext_text, ext_len, text, len);    调用==>...
}// 7.riscv-linux-4.15/kernel/printk/printk.c:
static void call_console_drivers(const char *ext_text, size_t ext_len,const char *text, size_t len)
{struct console *con;trace_console_rcuidle(text, len); if (!console_drivers)return;for_each_console(con) {  // 遍历console_drivers中每个consoleif (exclusive_console && con != exclusive_console)continue;if (!(con->flags & CON_ENABLED))continue;if (!con->write)continue;if (!cpu_online(smp_processor_id()) &&!(con->flags & CON_ANYTIME))continue;if (con->flags & CON_EXTENDED)con->write(con, ext_text, ext_len);elsecon->write(con, text, len); // 通过console的write函数打印内容}
}

在代码中,从printk开始,层层分析,最后在call_console_drivers函数中,会遍历console_drivers中每个console,并调用console的write函数来完成内容打印。

pr_info ==>
printk ==>
vprintk_func ==>
vprintk_default ==>
vprintk_emit ==>
console_unlock ==>
call_console_drivers ==>
con->write

3 console注册

console结构体定义:

// riscv-linux-4.15/include/linux/console.h:
struct console {char	name[16];void	(*write)(struct console *, const char *, unsigned);int	(*read)(struct console *, char *, unsigned);struct tty_driver *(*device)(struct console *, int *);void	(*unblank)(void);int	(*setup)(struct console *, char *);int	(*match)(struct console *, char *name, int idx, char *options);short	flags;short	index;int	cflag;void	*data;struct	 console *next;
};

通过register_console函数,可以将一个console进行注册,放入console_drivers链表中,如下:

// riscv-linux-4.15/arch/riscv/kernel/setup.c:
void __init setup_arch(char **cmdline_p)
{
#if defined(CONFIG_EARLY_PRINTK)if (likely(early_console == NULL)) {early_console = &riscv_sbi_early_console_dev;register_console(early_console); // 注册early console}
#endif*cmdline_p = boot_command_line;...
}// early console定义
struct console riscv_sbi_early_console_dev __initdata = {.name	= "early",.write	= sbi_console_write,.flags	= CON_PRINTBUFFER | CON_BOOT | CON_ANYTIME,.index	= -1
};// early console的write函数
static void sbi_console_write(struct console *co, const char *buf,unsigned int n)
{int i;for (i = 0; i < n; ++i) {if (buf[i] == '\n')sbi_console_putchar('\r');sbi_console_putchar(buf[i]);}
}// riscv-linux-4.15/arch/riscv/include/asm/sbi.h:
#define SBI_CALL(which, arg0, arg1, arg2) ({			\register uintptr_t a0 asm ("a0") = (uintptr_t)(arg0);	\register uintptr_t a1 asm ("a1") = (uintptr_t)(arg1);	\register uintptr_t a2 asm ("a2") = (uintptr_t)(arg2);	\register uintptr_t a7 asm ("a7") = (uintptr_t)(which);	\asm volatile ("ecall"					\: "+r" (a0)				\: "r" (a1), "r" (a2), "r" (a7)		\: "memory");				\a0;							\
})/* Lazy implementations until SBI is finalized */
#define SBI_CALL_0(which) SBI_CALL(which, 0, 0, 0)
#define SBI_CALL_1(which, arg0) SBI_CALL(which, arg0, 0, 0)
#define SBI_CALL_2(which, arg0, arg1) SBI_CALL(which, arg0, arg1, 0)static inline void sbi_console_putchar(int ch)
{SBI_CALL_1(SBI_CONSOLE_PUTCHAR, ch);
}static inline int sbi_console_getchar(void)
{return SBI_CALL_0(SBI_CONSOLE_GETCHAR);
}

4 SBI_CALL

console的write函数:先调用sbi_console_putchar,再调SBI_CALL。
SBI_CALL实现的功能,可大致理解为:

SBI_CALL(which, arg0, arg1, arg2) 
{			a0寄存器 = (uintptr_t)(arg0);	a1寄存器 = (uintptr_t)(arg1);	a2寄存器 = (uintptr_t)(arg2);	a7寄存器 = (uintptr_t)(which);	执行ecall指令;					
}

SBI_CALL宏,通过在RISC-V处理器上,执行ecall指令来调用一个服务:

  • 它通过将参数,放入特定的寄存器(a0、a1、a2);
  • 并将服务标识符(调用号),放入a7寄存器;
  • 然后,它执行ecall指令,并返回a0寄存器的值作为结果。

ecall系统调用,会触发异常(mcause寄存器定义的异常8或9)。只不过这种异常,是由U或S模式下,程序通过ecall指令,软件触发的异常,主要用于系统调用,实现一些底层调用,例如输出打印信息到串口等。

可以看到,这里定义了很多调用号Timer、Console、IPI、Shutdown等,如下:

// riscv-linux-4.15/arch/riscv/include/asm/sbi.h:
#define SBI_SET_TIMER 0
#define SBI_CONSOLE_PUTCHAR 1
#define SBI_CONSOLE_GETCHAR 2
#define SBI_CLEAR_IPI 3
#define SBI_SEND_IPI 4
#define SBI_REMOTE_FENCE_I 5
#define SBI_REMOTE_SFENCE_VMA 6
#define SBI_REMOTE_SFENCE_VMA_ASID 7
#define SBI_SHUTDOWN 8

在这里,就是:

  • 将调用号1放入a7寄存器,将欲打印字符ch放入a0寄存器,然后CPU执行ecall指令,就会触发一个异常;
  • 然后CPU会处理该异常,由于当前kernel运行在S模式,因此CPU会进入M模式,并跳转到M模式异常处理入口(Open SBI),在固件OpenSBI的处理代码中,会判断当调用号为1时,将字符ch打印出来(打印的方式,可以通过Uart或HTIF)。
    在这里插入图片描述
    在riscv-pk开源项目中,也支持通过ecall指令,来使用Uart或HTIF输出打印信息。

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

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

相关文章

improve-gantt-elastic(vue2中甘特图实现与引入)

1.前言 项目开发中需要使用甘特图展示项目实施进度&#xff0c;左侧为表格计划&#xff0c;右侧为图表进度展示。wl-gantt-mater&#xff0c;dhtmlx尝试使用过可拓展性受到限制。gantt-elastic相对简单&#xff0c;可操作性强&#xff0c;基础版本免费。 甘特图&#xff08;Gan…

力扣 全排列

回溯经典例题。 题目 通过回溯生成所有可能的排列。每次递归时&#xff0c;选择一个数字&#xff0c;直到选满所有数字&#xff0c;然后记录当前排列&#xff0c;回到上层时移除最后选的数字并继续选择其他未选的数字。每次递归时&#xff0c;在 path 中添加一个新的数字&…

1/13+2

运算符重载 myString.h #ifndef MYSTRING_H #define MYSTRING_H #include <cstring> #include <iostream> using namespace std; class myString {private:char *str; //记录c风格的字符串int size; //记录字符串的实际长度int capacity; …

【HM-React】08. Layout模块

基本结构和样式reset 结构创建 实现步骤 打开 antd/Layout 布局组件文档&#xff0c;找到示例&#xff1a;顶部-侧边布局-通栏拷贝示例代码到我们的 Layout 页面中分析并调整页面布局 代码实现 pages/Layout/index.js import { Layout, Menu, Popconfirm } from antd impor…

计算机视觉算法实战——实时车辆检测和分类(主页有相关源码)

✨个人主页欢迎您的访问 ✨期待您的三连 ✨ ✨个人主页欢迎您的访问 ✨期待您的三连 ✨ ✨个人主页欢迎您的访问 ✨期待您的三连✨ ​ ​​​​​​​​​​​​​​​​​​ 1. 领域介绍✨✨ 实时车辆检测和分类是计算机视觉中的一个重要应用领域&#xff0c;旨在从视频流或…

使用 selenium-webdriver 开发 Web 自动 UI 测试程序

优缺点 优点 有时候有可能一个改动导致其他的地方的功能失去效果&#xff0c;这样使用 Web 自动 UI 测试程序可以快速的检查并定位问题&#xff0c;节省大量的人工验证时间 缺点 增加了维护成本&#xff0c;如果功能更新过快或者技术更新过快&#xff0c;维护成本也会随之提高…

性能测试工具Jmeter分布式运行

性能测试工具JMeter的分布式执行是一种用于增强压力测试能力的技术方案&#xff0c;它允许用户通过多台机器来共同完成同一个测试计划的执行。这种方式特别适用于需要模拟成百上千甚至上万用户并发访问的情况&#xff0c;当单台机器由于硬件资源&#xff08;如CPU、内存、网络I…

弥散张量分析开源软件 DSI Studio 简体中文汉化版可以下载了

网址&#xff1a; (63条消息) DSIStudio简体中文汉化版(2022年7月)-算法与数据结构文档类资源-CSDN文库

移动云自研云原生数据库入围国采!

近日&#xff0c;中央国家机关2024年度事务型数据库软件框架协议联合征集采购项目产品名单正式公布&#xff0c;移动云自主研发的云原生数据库产品顺利入围。这一成就不仅彰显了移动云在数据库领域深耕多年造就的领先技术优势&#xff0c;更标志着国家权威评审机构对移动云在数…

在vscode中使用R-1

参考我的上一篇博客&#xff1a; https://blog.csdn.net/weixin_62528784/article/details/145092632?spm1001.2014.3001.5501 这篇内容实际上就是上一篇博客的后续承接&#xff0c;既然都在vscode的jupyter中使用R了&#xff0c;实际上其实也能够直接在vscode中原生使用R的编…

【Block总结】掩码窗口自注意力 (M-WSA)

摘要 论文链接&#xff1a;https://arxiv.org/pdf/2404.07846 论文标题&#xff1a;Transformer-Based Blind-Spot Network for Self-Supervised Image Denoising Masked Window-Based Self-Attention (M-WSA) 是一种新颖的自注意力机制&#xff0c;旨在解决传统自注意力方法在…

【Linux】统信UOS服务器安装MySQL8.0(RPM)

目录 一、下载安装包 二、安装MySQL 2.1hive适配 2.2ranger适配 3.2DolphinScheduler适配 一、下载安装包 官网下载安装包&#xff1a;MySQL :: MySQL Downloads 选择社区版本下载 点击MySQL Community Server 选择对应系统的MySQL版本号 统信1060a 操作系统对应 redhat8…

Jenkins简单的安装运行

一、下载 官网下载&#xff1a;https://www.jenkins.io/download/ 清华大学开源软件镜像站&#xff1a;https://mirrors.tuna.tsinghua.edu.cn/jenkins/ 官网资料丰富&#xff0c;介绍了各种平台安装以及下载。安装简单&#xff0c;按照说明来就行。下面我介绍一个非常简单的…

【CSS】HTML页面定位CSS - position 属性 relative 、absolute、fixed 、sticky

目录 relative 相对定位 absolute 绝对定位 fixed 固定定位 sticky 粘性定位 position&#xff1a;relative 、absolute、fixed 、sticky &#xff08;四选一&#xff09; top&#xff1a;距离上面的像素 bottom&#xff1a;距离底部的像素 left&#xff1a;距离左边的像素…

Ubuntu中双击自动运行shell脚本

方法1: 修改文件双击反应 参考: https://blog.csdn.net/miffywm/article/details/103382405 chmod x test.sh鼠标选中待执行文件&#xff0c;在窗口左上角edit菜单中选择preference设计双击执行快捷键&#xff0c;如下图&#xff1a; 方法2: 设置一个应用 参考: https://blo…

从0开始学习搭网站的第一天

前言&#xff0c;以下内容学习自mdn社区&#xff0c;感兴趣的朋友可以直接去看原文章web技术 目录 web机制互联网是怎么运作的网站服务器是什么什么是URL&#xff1f;什么是web服务器&#xff1f;什么是域名什么是超链接什么是网页DOMgoole浏览器开发者工具 web机制 互联网是怎…

黑马linux笔记(03)在Linux上部署各类软件 MySQL5.7/8.0 Tomcat(JDK) Nginx RabbitMQ

文章目录 实战章节&#xff1a;在Linux上部署各类软件tar -zxvf各个选项的含义 为什么学习各类软件在Linux上的部署 一 MySQL数据库管理系统安装部署【简单】MySQL5.7版本在CentOS系统安装MySQL8.0版本在CentOS系统安装MySQL5.7版本在Ubuntu&#xff08;WSL环境&#xff09;系统…

[Transformer] The Structure of GPT, Generative Pretrained Transformer

The Structure of Generative Pretrained Transformer Reference: The Transformer architecture of GPT models How GPT Models Work

浅谈云计算04 | 云基础设施机制

探秘云基础设施机制&#xff1a;云计算的基石 一、云基础设施 —— 云计算的根基![在这里插入图片描述](https://i-blog.csdnimg.cn/direct/1fb7ff493d3c4a1a87f539742a4f57a5.png)二、核心机制之网络&#xff1a;连接云的桥梁&#xff08;一&#xff09;虚拟网络边界&#xff…

解锁 JMeter 的 ForEach Controller 高效测试秘籍

各位小伙伴们&#xff0c;今天咱就来唠唠 JMeter 里超厉害的 “宝藏工具”——ForEach Controller&#xff0c;它可是能帮咱们在性能测试的江湖里 “大杀四方” 哦&#xff01; 一、ForEach Controller 是啥 “神器” 想象一下&#xff0c;你手头有一串神秘钥匙&#xff0c;每…