Pxa27x的板子,最近在移植到linux2.4.21过程时,碰到一个串口终端无法输出信息的问题,bootloader引导时能够输出信息,但引导kernel时就停在那了,没有任何显示。
在网上搜索到一些资料,也排除了那些可能的原因,但还是没能够解决这个串口终端输出的问题。通过分析bootloader到kernel内核引导的这一过程,最后把目标锁定在了kernel解压缩的过程中,估计大伙使用的kenel都是经过压缩的内核,在BootLoader完成系统的引导以后并将Linux内核调入内存之后,跳转到kernel的起始位置。如果kernel没有压缩,就可以启动了(进入arch/arm/kernel/head_armv.S)。如果kernel压缩过,则要进行解压,在压缩过的kernel头部有解压程序。压缩过得kernel入口第一个文件源码位置在arch/arm/boot/compressed/head.S。它将调用函数decompress_kernel(),这个函数在文件arch/arm/boot/compressed/misc.c中,decompress_kernel()又调用proc_decomp_setup(),arch_decomp_setup()进行设置,然后使用在打印出信息“Uncompressing Linux...”后,调用gunzip()。将内核放于指定的位置。
decompress_kernel(ulg output_start, ulg free_mem_ptr_p, ulg free_mem_ptr_end_p,int arch_id)
{
output_data = (uch *)output_start; /* Points to kernel start */
free_mem_ptr = free_mem_ptr_p;
free_mem_ptr_end = free_mem_ptr_end_p;
__machine_arch_type = arch_id;
arch_decomp_setup();
makecrc();
puts("Uncompressing Linux...");
gunzip();
puts(" done, booting the kernel./n");
return output_ptr;
}
其中的puts就是通过串口输出信息,再看一下puts的定义(在include/asm-arm/arch-pxa/uncompress.h中):
#define FFUART ((volatile unsigned long *)0x40100000)
#define BTUART ((volatile unsigned long *)0x40200000)
#define STUART ((volatile unsigned long *)0x40700000)
#define UART FFUART
static __inline__ void putc(char c)
{
while (!(UART[5] & 0x20));
UART[0] = c;
}
/*
* This does not append a newline
*/
static void puts(const char *s)
{
while (*s) {
putc(*s);
if (*s == '/n')
putc('/r');
s++;
}
}
发现问题了,这里UART定义为FFUART, 而我在bootloader中初始化用来串口输出的是STDUART,因此puts调用的putc中的while语句一直会处于循环中,内核启动就停在此处了。
解决方法很简单,让UART指向STDUART就可以了(#define UART STDUART)。
保存,重新编译,下载,上电,OK!
下面是网上找的一些资料:
在 boot loader 的运行过程中我们可以正确地向串口终端输出信息,但当 boot loader 启动内核后却无法看到内核的启动输出信息。对这一问题的原因可以从以下几个方面来考虑:
(1) 首先请确认你的内核在编译时配置了对串口终端的支持,并配置了正确的串口驱动程序。
(2) 你的 boot loader 对串口的初始化设置可能会和内核对串口的初始化设置不一致。此外,对于诸如 s3c44b0x 这样的 CPU,CPU 时钟频率的设置也会影响串口,因此如果 boot loader 和内核对其CPU 时钟频率的设置不一致,也会使串口终端无法正确显示信息。
(3) 最后,还要确认 boot loader 所用的内核基地址必须和内核映像在编译时所用的运行基地址一致,尤其是对于 uClinux 而言。假设你的内核映像在编译时用的基地址是 0xc0008000,但你的 boot loader却将它加载到 0xc0010000 处去执行,那么内核映像当然不能正确地执行了。