Dovetail中raw_printk的支持

Legonext 2024-02-05 14:54:50

除非你足够幸运,有一个电路内仿真(In-circuit emulation  ICE来调试涉及实时阶段(out-of-band)上下文的棘手问题,否则你可能不得不在串行线上进行基本的printk风格的调试。尽管启用Dovetail时可以从in-band上下文使用printk()机制,但输出会延迟,直到in-band阶段恢复控制,这意味着:

  • 您无法可靠地现场跟踪out-of-band代码,在某些情况下,由于缓冲效应,从out-of-band上下文或在CPU中禁用中断的情况下运行的代码段发出的延迟输出可能会出现在随后的in-band的消息之后。
  • 如果调试跟踪以高频发送数据(例如,每隔几百微秒从out-of-band IRQ处理程序发送一次),那么由于print()机器必须处理的大量输出,机器可能会出现停滞,从而导致明显的系统锁定。

在要求苛刻的out-of-band上下文中进行类似printk的调试,唯一合理的选择是使用raw_printk()例程向串行控制台发出原始调试消息,这样您就可以获得一些合理的反馈,以了解系统执行的情况。应通过打开CONFIG_RAW_PRINTK来启用此功能,否则将丢弃发送到RAW_PRINTK()的所有输出。

由于Linux现有的串行控制台驱动程序在out-of-band上下文中不可用,因此启用原始printk支持需要通过在控制台描述中添加原始写入处理程序来调整平台正在使用的串行控制台驱动程序。就像write()处理程序一样,write_raw()输出处理程序接收一个控制台指针、要输出的字符串及其长度作为参数。这个处理程序应该尽可能快地将字符发送到UART,几乎不需要准备。

由通用raw_printk()例程格式化的所有输出都将传递给当前串行控制台驱动程序的原始写入处理程序(如果存在)。对原始输出处理程序的调用在raw_printk()中通过持有硬自旋锁进行序列化,这意味着在运行处理程序时CPU中会禁用中断。

原始写入处理程序通常源自同一串行控制台设备的常规写入处理程序,跳过任何in-band锁定结构,并且 为输出只等待最短时间,因为我们希望保持低中断延迟。

警告:

您不能指望通过printk()和raw_printk()发送的混合输出与它们各自的调用以相同的顺序出现:正常的printk(()输出可能会延迟一段不确定 的时间,直到某个控制台驱动程序将其发送到终端设备,这可能涉及任务重新调度。另一方面,raw_printk()会立即将输出写入硬件设备,从而绕过printk()的任何缓冲。因此,printk()后面跟raw_printk()序列的输出可能会以相反的顺序出现在终端设备上。

示例: 向AMBA PL011串行驱动程序添加RAW_PRINTK支持

--- a/drivers/tty/serial/amba-pl011.c
+++ b/drivers/tty/serial/amba-pl011.c
@@ -2206,6 +2206,40 @@ static void pl011_console_putchar(struct uart_port *port, int ch)
 	pl011_write(ch, uap, REG_DR);
 }
 
+#ifdef CONFIG_RAW_PRINTK
+
+/*
+ * The uart clk stays on all along in the current implementation,
+ * despite what pl011_console_write() suggests, so for the time being,
+ * just emit the characters assuming the chip is clocked. If the clock
+ * ends up being turned off after writing, we may need to clk_enable()
+ * it at console setup, relying on the non-zero enable_count for
+ * keeping pl011_console_write() from disabling it.
+ */
+static void
+pl011_console_write_raw(struct console *co, const char *s, unsigned int count)
+{
+	struct uart_amba_port *uap = amba_ports[co->index];
+	unsigned int old_cr, new_cr, status;
+
+	old_cr = readw(uap->port.membase + UART011_CR);
+	new_cr = old_cr & ~UART011_CR_CTSEN;
+	new_cr |= UART01x_CR_UARTEN | UART011_CR_TXE;
+	writew(new_cr, uap->port.membase + UART011_CR);
+
+	while (count-- > 0) {
+		if (*s == '\n')
+			pl011_console_putchar(&uap->port, '\r');
+		pl011_console_putchar(&uap->port, *s++);
+	}
+	do
+		status = readw(uap->port.membase + UART01x_FR);
+	while (status & UART01x_FR_BUSY);
+	writew(old_cr, uap->port.membase + UART011_CR);
+}
+
+#endif  /* !CONFIG_RAW_PRINTK */
+
 static void
 pl011_console_write(struct console *co, const char *s, unsigned int count)
 {
@@ -2406,6 +2440,9 @@ static struct console amba_console = {
 	.device		= uart_console_device,
 	.setup		= pl011_console_setup,
 	.match		= pl011_console_match,
+#ifdef CONFIG_RAW_PRINTK
+	.write_raw	= pl011_console_write_raw,
+#endif
 	.flags		= CON_PRINTBUFFER | CON_ANYTIME,
 	.index		= -1,
 	.data		= &amba_reg,

本文翻译自https://evlproject.org/dovetail/porting/rawprintk/,欢迎指正。

...全文
156 回复 打赏 收藏 转发到动态 举报
AI 作业
写回复
用AI写文章
回复
切换为时间正序
请发表友善的回复…
发表回复

131

社区成员

发帖
与我相关
我的任务
社区描述
Xenomai中文社区。 Upstream - xenomai.org Mirror - gitee.com/Xenomai CSDN - bbs.csdn.net/forums/Xenomai
社区管理员
  • Xenomai
  • legonext
  • Cajb
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告
暂无公告

试试用AI创作助手写篇文章吧