日期:2014-05-16  浏览次数:20708 次

GNU ARM汇编--(十五)linux下的printascii

        在前面对很多s3c2440的功能模块进行学习后,已经具备了将这些模块综合起来的条件,基于此,将前面的代码综合成一个简单的bootloader.自己写的bootloader在引导kernel的时候,串口输出只有Uncompressing Linux...和done, booting the kernel。串口有这个输出,说明kernel被正确引导了,但是串口有问题。

        这篇blog只是分析解决这个问题的第一步:

        既然"Uncompressing Linux..."这句打印是kernel代码中的,那kernel的其他打印怎么没有?

        在arch\arm\boot\compressed目录下的misc.c中,上面的打印是在decompress_kernel函数中,而该函数是在kernel的初始汇编中调用的,也就是说这个时候kernel的串口驱动肯定是没有工作的,那这里的串口输出只能是用bootloader初始化好的串口,

        putstr("Uncompressing Linux...");

        putstr(" done, booting the kernel.\n");

static void putstr(const char *ptr)
{
	char c;

	while ((c = *ptr++) != '\0') {
		if (c == '\n')
			putc('\r');
		putc(c);
	}

	flush();
}

        在include\asm-arm\plat-s3\uncompress.h中,有putc函数的定义:

static void putc(int ch)
{
	if (uart_rd(S3C2410_UFCON) & S3C2410_UFCON_FIFOMODE) {
		int level;

		while (1) {
			level = uart_rd(S3C2410_UFSTAT);
			level &= fifo_mask;

			if (level < fifo_max)
				break;
		}

	} else {
		/* not using fifos */

		while ((uart_rd(S3C2410_UTRSTAT) & S3C2410_UTRSTAT_TXE) != S3C2410_UTRSTAT_TXE)
			barrier();
	}

	/* write byte to transmission register */
	uart_wr(S3C2410_UTXH, ch);
}
        从这里可以看到,这里的输出的确是利用了bootloader中对串口的初始化,但是这部分代码还是通用的:不管在bootloader中将串口初始化为用fifo还是非fifo的,这一小块代码都是可以正常串口输出的。

        既然明白了这两句打印为什么可以输出后,就要排查后续没有打印的原因了,这里我们就利用printascii函数来debug,我们知道kernel的printf函数是printk,在printk函数内部添加printascii函数,make menuconfig中选中:

        Kernel hacking下的 [*] Kernel low-level debugging functions下的 [*]   Kernel low-level debugging messages via S3C UART,并选择 (0) S3C UART to use for low-level debug

         Device Drivers -->Character devices--> Serial drivers--> <*> Samsung S3C2410/S3C2440/S3C2442/S3C2412 Serial port support和[*]   Support for console on S3C2410 serial port 

         printk函数修改如下:

asmlinkage int printk(const char *fmt, ...)
{
	va_list args;
	int r;
	
#ifdef CONFIG_DEBUG_LL
		extern void printascii(const char *);
		char buff[256];
#endif

	va_start(args, fmt);
	r = vprintk(fmt, args);
	
#ifdef CONFIG_DEBUG_LL
		vsprintf(buff, fmt, args);
#endif
	va_end(args);
#ifdef CONFIG_DEBUG_LL
		printascii(buff);
#endif

	return r;
}


        重新编译内核烧写后,发现kernel的输出都有了,这说明kernel的串口驱动有问题,或者说要去研究要bootloader如何向kernel传递参数的。另外一个疑惑就是printk没有输出,为什么printascii有输出呢?

        查看源码才知道,printascii是针对arm平台的debug函数:

        在arch\arm\kernel\debug.S中

ENTRY(printascii)
		addruart r3
		b	2f
1:		waituart r2, r3
		senduart r1, r3
		busyuart r2, r3
		teq	r1, #'\n'
		moveq	r1, #'\r'
		be