在Linux内核中添加printxHTIF打印的方法1 创建kernel/printx.c并写入如下内容2 创建include/linux/printx.h并写入如下内容3 修改 kernel/Makefile在文件中添加4 然后在需要使用 printx 的 .c 文件中包含此头文件5 printx的使用在模拟器中运行Linux若UART有问题或没有有效的途径来打印输出时对于Linux的运行状态我们无从得知。尤其是需要定位问题时想在Linux内核中添加打印来进行调试的话因无法打印输出会非常的不方便。那么就需要找到一种替换UART的打印输出方式。我们可以在Linux中模仿HTIF原理实现一个printx函数用于打印输出具体步骤如下1 创建kernel/printx.c并写入如下内容#includelinux/init.h#includelinux/io.h#includelinux/dma-mapping.h#includelinux/spinlock.h#includelinux/printk.h#includelinux/string.h#includelinux/kernel.h#includelinux/module.h#includelinux/slab.h#includelinux/export.h#includelinux/printx.h#defineHTIF_SIZEPAGE_SIZE#defineHTIF_TOHOST_OFFSET0x0#defineHTIF_FROMHOST_OFFSET0x8#defineHTIF_DEV_CONSOLE0x1#defineHTIF_CONSOLE_CMD_PUTC0x1#defineHTIF_TOHOST_CMD(dev,cmd,payload)\(((uint64_t)(dev)56)|((uint64_t)(cmd)48)|(uint64_t)(payload))//#define HTIF_FIXED_ADDR 0x40000000staticvoid__iomem*htif_base;staticphys_addr_t htif_phys;staticDEFINE_SPINLOCK(htif_lock);/* * 初始化函数根据是否定义 HTIF_FIXED_ADDR 选择模式 * 若定义 HTIF_FIXED_ADDR则其值作为固定物理地址如 -DHTIF_FIXED_ADDR0x40000000 * 若未定义则动态分配一页内存 */staticint__inithtif_init(void){#ifdefHTIF_FIXED_ADDR/* 固定地址模式 */htif_physHTIF_FIXED_ADDR;htif_baseioremap(htif_phys,HTIF_SIZE);// 将物理地址转换为内核的虚拟地址进行访问if(!htif_base){pr_err(printx: ioremap(0x%llx) failed\n,(u64)htif_phys);return-ENOMEM;}pr_info(printx: using fixed phys 0x%llx\n,(u64)htif_phys);#else/* 动态分配模式 */structpage*page;pagealloc_pages(GFP_KERNEL,get_order(HTIF_SIZE));if(!page){pr_err(printx: alloc_pages failed\n);return-ENOMEM;}htif_basepage_address(page);htif_physpage_to_phys(page);pr_info(printx: allocated phys 0x%llx, virt %p\n,(u64)htif_phys,htif_base);#endif/* 初始清零两个寄存器 */writeq(0,htif_baseHTIF_TOHOST_OFFSET);writeq(0,htif_baseHTIF_FROMHOST_OFFSET);return0;}/* 在 device initcall 阶段自动调用此时 DMA/ioremap 已可用 */device_initcall(htif_init);/* 输出单个字符内部函数带锁 */staticvoidhtif_putc(charch){void__iomem*tohosthtif_baseHTIF_TOHOST_OFFSET;void__iomem*fromhosthtif_baseHTIF_FROMHOST_OFFSET;uint64_tval;if(!htif_base)return;/* 等待 fromhost 为 0空闲 */// while (readq(fromhost) ! 0)// cpu_relax();/* 构造命令 */valHTIF_TOHOST_CMD(HTIF_DEV_CONSOLE,HTIF_CONSOLE_CMD_PUTC,ch);writeq(val,tohost);/* 等待模拟器处理完成fromhost ! 0 */// while (readq(fromhost) 0)// cpu_relax();/* 写 0 确认消费 */writeq(0,fromhost);}voidprintx_str(constchar*str){unsignedlongflags;spin_lock_irqsave(htif_lock,flags);while(*str){if(*str\n)htif_putc(\r);/* 支持回车换行 */htif_putc(*str);}spin_unlock_irqrestore(htif_lock,flags);}EXPORT_SYMBOL(printx_str);voidprintx(constchar*fmt,...){va_list args;charbuf[256];intlen;va_start(args,fmt);lenvsnprintf(buf,sizeof(buf),fmt,args);va_end(args);if(len0)printx_str(buf);}EXPORT_SYMBOL(printx);//////////////////////////////////////////////////////////////////////voidprintx_str_private(constchar*str){while(*str){if(*str\n)htif_putc(\r);/* 支持回车换行 */htif_putc(*str);}}staticunsignedlongg_flags;voidprintx_begin(constchar*fmt,...){va_list args;charbuf[256];intlen;spin_lock_irqsave(htif_lock,g_flags);va_start(args,fmt);lenvsnprintf(buf,sizeof(buf),fmt,args);va_end(args);if(len0)printx_str_private(buf);}EXPORT_SYMBOL(printx_begin);voidprintx_append(constchar*fmt,...){va_list args;charbuf[256];intlen;va_start(args,fmt);lenvsnprintf(buf,sizeof(buf),fmt,args);va_end(args);if(len0)printx_str_private(buf);}EXPORT_SYMBOL(printx_append);voidprintx_end(constchar*fmt,...){va_list args;charbuf[256];intlen;va_start(args,fmt);lenvsnprintf(buf,sizeof(buf),fmt,args);va_end(args);if(len0)printx_str_private(buf);spin_unlock_irqrestore(htif_lock,g_flags);}EXPORT_SYMBOL(printx_end);2 创建include/linux/printx.h并写入如下内容#ifndef_LINUX_PRINTX_H#define_LINUX_PRINTX_H#includelinux/types.hvoidprintx_str(constchar*str);voidprintx(constchar*fmt,...)__printf(1,2);voidprintx_begin(constchar*fmt,...)__printf(1,2);voidprintx_append(constchar*fmt,...)__printf(1,2);voidprintx_end(constchar*fmt,...)__printf(1,2);#endif3 修改 kernel/Makefile在文件中添加obj-yprintx.o4 然后在需要使用 printx 的 .c 文件中包含此头文件#includelinux/printx.h5 printx的使用函数调用就是如下这样很简单。#includelinux/printx.hprintx(123\n);printx(123 0x%x\n,10);HTIFprintx的使用分2种场景。动态分配模式Linux的UART输出可以使用但是存在BUG问题模拟器环境中启动Linux启动Linux过程中会打印“printx: allocated phys xx, virt yy”模拟器中开启HTIF功能将HTIF基址设置为xx可观察到模拟器控制台窗口中有printx打印输出。固定地址模式Linux的UART输出完全无法使用在printx.c中定义#define HTIF_FIXED_ADDR xxxx具体地址xxxx需根据经验选择一个未使用的DRAM地址重新编译Linux在模拟器中启动模拟器中开启HTIF功能将HTIF基址设置为xxxx启动Linux过程中由于UART完全无法使用故看不到启动日志可以在Linux启动完成后添加一条printx以便模拟器打印出来就知道Linux启动完成了后续在Linux中添加的多处printx输出就可以在模拟器中打印出来以方便调试了。注意模拟器需要支持HTIF功能才行其实也比较简单可以自己开发代码量小。也可以找个开源模拟器参考一下代码。