uboot2013或新版uboot启动内核失败问题的解决
uboot201310版本的移植,最后启动内核时会失败,start kernel…之后就没有了,查过一些资料,都没有解决问题,后来问题搁置,看完了内核移植的视频之后,对内核代码有了一些了解,再回头看这个问题,uboot的代码在执行kernel_entry(0, machid, r2);之后,就进入内核代码了。
内核代码刚开始是一段解压代码,从解压代码入手一步步跟踪代码,最终确定了问题点是在decompress_kernel函数(arch/arm/boot/compressed/misc.c)的打印代码putstr(“Uncompressing Linux…”)。我们一直想看到的打印信息,本身就有问题,屏蔽掉这两行打印代码之后,编译出的内核顺利启动。
为什么打印信息会有问题呢?代码跟下去,发现问题出在了putc函数(arch/arm/plat-samsung/include/plat/uncompress.h),
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);
}
九鼎uboot启动内核走的是else语句之后的代码,也就是不用fifo模式,而uboot2101310读出的UFCON寄存器的值居然是0x1,也就是用了fifo模式,而fifo_mask和fifo_max都是没有赋初值的全局变量,值为0,if (level < fifo_max)不成立,所以在while循环中出不去,代码也就死在这里了。
uboot201310的串口居然是fifo模式,自己明明配的是not using fifos啊。回看uboot201310的代码,我们在lowevel_init.S中添加了串口初始化的代码,且UFCON寄存器配置成了0,现在变成了1,肯定有我们没有注意到的地方,回想可能出问题的地方,应该是init_sequence这个函数指针数组了,里面有很多的硬件初始化代码,其中有serial_init函数,跟下去
serial_init:drivers/serial/serial.c
get_current:drivers/serial/serial.c
default_serial_console:drivers/serial/serial_s5p.c
.start = s5p_serial2_init:
serial_init_dev:drivers/serial/serial_s5p.c
串口初始化函数为:
int serial_init_dev(const int dev_index)
{
struct s5p_uart *const uart = s5p_get_base_uart(dev_index);
/* enable FIFOs */
writel(1, &uart->ufcon);
writel(0, &uart->umcon);
/* 8N1 */
writel(0x3, &uart->ulcon);
/* No interrupts, no DMA, pure polling */
writel(0x245, &uart->ucon);
serial_setbrg_dev(dev_index);
return 0;
}
至此,找到了问题的根源,串口在这里被使能了FIFOS,导致了启动内核时的卡死,我在试着将ufcon配成0时,编译烧录执行后,串口输出会乱码,对照之前的初始化代码再把ucon寄存器设置为0x3c5或者0x5,还是会乱码,不知道为什么,也不想追下去了,解决办法就是在cleanup_before_linux()函数执行之前加一个自己写的dis_uart_fifo()函数,将ufcon配成0,配成0之前要delay一段时间,否则最后的输出可能会乱码。
编译烧录执行,完美启动内核,且uboot201310自带bootz命令,用于启动zImage。
经验:在没有成功打印出调试代码之前,可靠的调试手段是点灯。