131
社区成员




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