基于FL2440的3.6.6内核移植出现Uncompressing Linux... done, booting the kernel.

  • 具体问题
  • 参考解决方案
  • 解决思路
  • 深入解决

1.具体问题:

在移植3.6.6的内核后,下载启动卡死,具体是串口打印信息停留在“Uncompressing Linux… done, booting the kernel.”

2. 参考解决方案:

依据网上的说法要确保如下情况:

  • 2.1 内核的时钟频率正确
  • 2.2 boot和kerel 配置一致的MACH_TYPE,即板子MACHINE ID
  • 2.3 串口驱动配置正常

    在内核配置device drivers->character devices->serial 中

    <*> Samsung SoC serial support

    [*] Support for console on Samsung SoC serial port

  • 2.4. 启动参数设置正常

    console 的ttySAC0 ,波特率115200对应正确

3.解决思路

检查了前面三项都是OK的,刚开始以为是内核无法启动,后来将显示驱动移植成功后(其它没变)下载到开发板,发现启动信息同样也无法通过串口打印到minicom或其它dnw窗口中,但在开发板的LCD上却打印出了内核的启动信息。由此我知道了内核移植是成功的,只是没有通过串口打印出来,那就是串口设置不对了,可检查发现bootloader的console这些设置都是对的,突然想起来内核里也可以设置启动参数,试了下果然成功了(在Boot options —> Default kernel command string 中,填上console=ttySAC0,115200等启动参数就行了)

4.深入解决

由于以前移植2.6.35版本的内核时,在改变启动参数时都是从bootloader里设置的而忽略了内核也可以设置启动参数,当时弄2.6.35以前的版本都不需要设置这里,而且我在更改NFS启动时内核设置的参数也不起作用,就以为此项没用,所以就没考虑到这,实际原因是2.6.35内核配置里要选中always use default…这个才行,因为飞凌的bootloader里固化了一些启动参数,也就是说无论你在bootloader里设没设,它实质上都设定了,所以覆盖了内核里默认的启动参数。但3.6.6的版本在这方面可能是有改进,在内核boot option配置中可以看到如下Kernel command line type:

        (X) Use bootloader kernel arguments if available
        ( ) Extend bootloader kernel arguments
        ( ) Always use the default kernel command string 

而在2.6.35的版本中只有一个Always use the default kernel command string可选项,所以确实有改进

,因此从此处看也有可能是我的bootloader与内核在传递启动参数时有问题(bootloader启动参数的地址在内核中没有设置好)导致无法把bootloader里设置的参数传递给内核,造成内核找不到正确的串口从而无法打印内核信息,所以内核从bootloader中没有获取到可用参数就使用内核设置的启动参数了。经测试,无论我怎么改变bootloader里的启动参数都没效果,应该是内核中的bootloader传参地址设置有问题,如果无法从bootloader设置那每次更换都要编译内核,太麻烦,有没有解决方法呢?

首先了解下 kernel启动参数传递方式

了解内核启动参数可以参考

文章1

文章2

或自行百度

据此我明白了,kernel启动参数有两种,一种是通过内核设置固化到启动参数中,一种是从某段内存中读取进来取代内核启动参数(而这个设置是由bootloader来设置并保存在某段事先与内核协商好的内存地址中),在启动时如果在“Kernel command line type”选中的是第一项,就先去寻找这段内存看有没有参数,没有就直接使用内核启动参数,有就覆盖掉内核设置的。

那么内核是如何知道bootloader将启动参数保存在哪里的呢?

看了下2.6.35版里的/arch/arm/mach-s3c24xx/mach-smdk2440.c在最后的MACHINE_START中有个boot_params,好了猜测就是它了,但在3.6.6中加入会提示错误,那应该是改了名之类的,先寻找下MACHINE_START的定义在文件

arch/arm/include/asm/mach/arch.h中

struct machine_desc {
+---  4 lines: Note! The first four elements are used--------------------------------------------------------
    unsigned int        nr;     /* architecture number  */
    unsigned int        phys_io;    /* start of physical io */
    unsigned int        io_pg_offst;    /* byte offset for io
                         * page tabe entry  */

    const char      *name;      /* architecture name    */
    unsigned long       boot_params;    /* tagged list      */

    unsigned int        video_start;    /* start of video RAM   */
    unsigned int        video_end;  /* end of video RAM */

    unsigned int        reserve_lp0 :1; /* never has lp0    */
    unsigned int        reserve_lp1 :1; /* never has lp1    */
    unsigned int        reserve_lp2 :1; /* never has lp2    */
    unsigned int        soft_reboot :1; /* soft reboot      */
    void            (*fixup)(struct machine_desc *,
                     struct tag *, char **,
                     struct meminfo *);
    void            (*map_io)(void);/* IO mapping function  */
    void            (*init_irq)(void);
    struct sys_timer    *timer;     /* system tick timer    */
    void            (*init_machine)(void);
};

可以看到boot_params; /* tagged list */那我们到3.6.6版中去看看,果然更换了如下

struct machine_desc {
    unsigned int        nr;     /* architecture number  */
    const char      *name;      /* architecture name    */
    unsigned long       atag_offset;    /* tagged list (relative) */
    const char *const   *dt_compat; /* array of device tree
                         * ‘compatible‘ strings */

    unsigned int        nr_irqs;    /* number of IRQs */

#ifdef CONFIG_ZONE_DMA
    unsigned long       dma_zone_size;  /* size of DMA-able area */
#endif

    unsigned int        video_start;    /* start of video RAM   */
    unsigned int        video_end;  /* end of video RAM */

    unsigned char       reserve_lp0 :1; /* never has lp0    */
    unsigned char       reserve_lp1 :1; /* never has lp1    */
    unsigned char       reserve_lp2 :1; /* never has lp2    */
    char            restart_mode;   /* default restart mode */
    void            (*fixup)(struct tag *, char **,
                     struct meminfo *);
    void            (*reserve)(void);/* reserve mem blocks  */
    void            (*map_io)(void);/* IO mapping function  */
    void            (*init_early)(void);
    void            (*init_irq)(void);
    struct sys_timer    *timer;     /* system tick timer    */
    void            (*init_machine)(void);
    void            (*init_late)(void);
    #ifdef CONFIG_MULTI_IRQ_HANDLER
    void            (*handle_irq)(struct pt_regs *);
#endif
    void            (*restart)(char, const char *);
};

,好了,试着修改此参数为S3C2410_SDRAM_PA + 0x100(原值为0x100)编译下载后居然无法启动了,卡死在Uncompressing Linux… done, booting the kernel.这一步,修改回原来的值,寻找了下发现在arch/arm/kernel/setup.c的setup_machine_tags函数中有所改变

    if (__atags_pointer)
        tags = phys_to_virt(__atags_pointer);
    else if (mdesc->atag_offset)
        tags = (void *)(PAGE_OFFSET + mdesc->atag_offset);//实际是进入这一步,

跟2.6.35的不同,

     if (__atags_pointer)
     {
         printk("using __atags_pointer to get tags.\n");
         tags = phys_to_virt(__atags_pointer);
     }
     else if (mdesc->boot_params)
     {
         tags = phys_to_virt(mdesc->boot_params);//不同点
         printk("using mdesc->boot_params to get tags.the tags is 0x%08x\n",tags);//anzyelay
         printk("tags->hdr.tag = 0x%08x\n",tags->hdr.tag);
     }

所以我直接打印输出下发现mdesc->boot_params结果居然不是0x30000100(S3C2410_SDRAM_PA + 0x100)而是

mdesc->boot_params=0xc0000100(为什么??不知道呀不知道 ,我看了下bootloader源码里也是0x30000100这个地址呀,懒得去跟踪了,反正旧版传过来是这个值。)

而3.6.6版本的从arch/arm/mach-s3c24xx/mach-smdk2440.c中传过来的0x0100加上PAGE_OFFSET(0xc000000正好是0xc0000100,所以你一改MACHINE_START里的.__atag_offset还会出错。所以结论是地址是正确设置了的。

现在既然不是内核与bootloader传参地址错误这个原因那怎么办?我对比两个版本分析调试了下setup_machine_tags函数,发现原来是CONFIG_DEPRECATED_PARAM_STRUCT这个宏没有定义的问题,导致后面内核读取到的参数地址tags是错误的(不在是0xc0000100)。

首先内核设置参数的路径是在main.c函数中, start_kernel–>setup_arch(&command_line)–>setup_command_line(command_line);

重点就在setup_arch函数中,此函数位于arch/arm/kernel/setup.c ,如下

void __init setup_arch(char **cmdline_p)
{
    struct machine_desc *mdesc;

    setup_processor();
    mdesc = setup_machine_fdt(__atags_pointer);//因为__atags_pointer为空,直接跳出来了,
    //这个参数是在R2寄存器给过来的吧,可以看head-common.s中的__mmap_switched
    if (!mdesc)
        mdesc = setup_machine_tags(machine_arch_type);//然后进入此处,
        //可以对比下2.6.35,3.6.6这里优化了下。这次出错的原因也主要是在这个函数里
    machine_desc = mdesc;
    machine_name = mdesc->name;

    setup_dma_zone(mdesc);

    if (mdesc->restart_mode)
        reboot_setup(&mdesc->restart_mode);

    init_mm.start_code = (unsigned long) _text;
    init_mm.end_code   = (unsigned long) _etext;
    init_mm.end_data   = (unsigned long) _edata;
    init_mm.brk    = (unsigned long) _end;

    /* populate cmd_line too for later use, preserving boot_command_line */
    strlcpy(cmd_line, boot_command_line, COMMAND_LINE_SIZE);
    *cmdline_p = cmd_line;//获取到启动参数

    parse_early_param();

    sort(&meminfo.bank, meminfo.nr_banks, sizeof(meminfo.bank[0]), meminfo_cmp, NULL);
    sanity_check_meminfo();
    arm_memblock_init(&meminfo, mdesc);

    paging_init(mdesc);
    request_standard_resources(mdesc);

    if (mdesc->restart)
        arm_pm_restart = mdesc->restart;

    unflatten_device_tree();

#ifdef CONFIG_SMP
    if (is_smp())
        smp_init_cpus();
#endif
    reserve_crashkernel();

    tcm_init();

#ifdef CONFIG_MULTI_IRQ_HANDLER
    handle_arch_irq = mdesc->handle_irq;
#endif

#ifdef CONFIG_VT
#if defined(CONFIG_VGA_CONSOLE)
    conswitchp = &vga_con;
#elif defined(CONFIG_DUMMY_CONSOLE)
    conswitchp = &dummy_con;
#endif
#endif

    if (mdesc->init_early)
        mdesc->init_early();
}

我们来看setup_machine_tags这个函数,在同一文件中

static struct machine_desc * __init setup_machine_tags(unsigned int nr)
{
    struct tag *tags = (struct tag *)&init_tags;
    struct machine_desc *mdesc = NULL, *p;
    char *from = default_command_line;//编译内核时配置的Boot Options

    init_tags.mem.start = PHYS_OFFSET;

    /*
     * locate machine in the list of supported machines.
     * 这里是根据你在MACHINE_START(arg1,arg2)给的arg1=nr才找出
     * 对应的设备描述结构p,所以,如果你没有设置正确arg1时,或者你的arg1
     * 所对应的Machine ID(在文件arch/arm/tools/mach-types中)不对
     * 时,那也会出现卡在Uncompres...这个错误。你开启kernel hacking中的
     * early print时就会看到错误原因。(这就是所谓的机器码导致的卡死原因。)
     */
    for_each_machine_desc(p)
        if (nr == p->nr) {
            printk("Machine: %s\n", p->name);
            mdesc = p;
            break;
        }

    if (!mdesc) {
        early_print("\nError: unrecognized/unsupported machine ID"
            " (r1 = 0x%08x).\n\n", nr);
        dump_machine_table(); /* does not return */
    }

    if (__atags_pointer)
        tags = phys_to_virt(__atags_pointer);
        /*前面说过这个参数为空,直接路过了,跟参考文章2说的什么
        * 设置了bootloader参数就直接获取过来有些不对,可能与我
        * 用的飞凌的bootloader,如果用UBOOT估计从这里进吧,我没
        * 有弄uboot,望知道的人告知下*/
    else if (mdesc->atag_offset)
        tags = (void *)(PAGE_OFFSET + mdesc->atag_offset);//我们是进入到这里,
        //前面说了在配置文件中的atag_offset就是0x0100,不要改。tags=0xc0000100

    /*2.6.35版的是没有下面这个宏的,由此直接跳过了convert_to_tag_list这一步
    *导致后面的tags值改变,目前我的bootloader传来的参数就是old style,所以这一步
    *不能省。这个在kernel配置里的kernel feature里选中Provide old way to
    * pass kernel parameters 这项就行。*/
#if defined(CONFIG_DEPRECATED_PARAM_STRUCT)
    /*
     * If we have the old style parameters, convert them to
     * a tag list.
     */
    if (tags->hdr.tag != ATAG_CORE)
        convert_to_tag_list(tags);
#endif

    if (tags->hdr.tag != ATAG_CORE) {
#if defined(CONFIG_OF)
        /*
         * If CONFIG_OF is set, then assume this is a reasonably
         * modern system that should pass boot parameters
         */
        early_print("Warning: Neither atags nor dtb found\n");
#endif
        tags = (struct tag *)&init_tags;
    }
//到这里tags=0xc0000100依旧,如果变了那肯定不对了(我就是在跟踪到此处不对才发现问题在上面这一步的)。
//同时tags->hdr.tag == ATAG_CORE(0x54410001)了,
    if (mdesc->fixup)
        mdesc->fixup(tags, &from, &meminfo);

    if (tags->hdr.tag == ATAG_CORE) {
        if (meminfo.nr_banks != 0)
            squash_mem_tags(tags);
        save_atags(tags);
        parse_tags(tags);
    }

    /* parse_early_param needs a boot_command_line */
    strlcpy(boot_command_line, from, COMMAND_LINE_SIZE);

    return mdesc;
}

好了,依据上面的说法,make menuconfig 勾上kernel feature里的Provide old way to pass kernel parameters ,make zImage后,下载启动,可以正常通过 bootloader设置启动参数了。

另附加问题:我用arm-linux-gcc-4.9.4编译已经成功移植好的2.6.35内核也出现停留在此的现象,换回其它版本的编译器又能正常启动(只换个编译器,其它未做任何修改)。开始以为是4.9.4的编译器有问题,今天用来编译了下3.6.6的内核居然是可以的,所以应该是2.6.35内核移植还有问题不兼容4.9.4的gcc,具体不知原因!!!!

时间: 2024-10-07 16:53:56

基于FL2440的3.6.6内核移植出现Uncompressing Linux... done, booting the kernel.的相关文章

基于tiny4412的Linux内核移植 -- DM9621NP网卡驱动移植(四)

作者信息 作者: 彭东林 邮箱:[email protected] QQ:405728433 平台简介 开发板:tiny4412ADK + S700 + 4GB Flash 要移植的内核版本:Linux-4.4.0 (支持device tree) u-boot版本:友善之臂自带的 U-Boot 2010.12 (为支持uImage启动,做了少许改动) busybox版本:busybox 1.25 网卡芯片:DM9621NP 交叉编译工具链: arm-none-linux-gnueabi-gcc

linux 内核移植和根文件系统的制作

1.1 Linux内核基础知识 在动手进行Linux内核移植之前,非常有必要对Linux内核进行一定的了解,下面从Linux内核的版本和分类说起. 1.1.1  Linux版本 Linux内核的版本号可以从源代码的顶层目录下的Makefile中看到,比如2.6.29.1内核的Makefile中: VERSION = 2 PATCHLEVEL = 6 SUBLEVEL = 29 EXTRAVERSION = .1 其 中的“VERSION”和“PATCHLEVEL”组成主版本号,比如2.4.2.5

【转】 linux内核移植和驱动添加(三)

原文网址:http://blog.chinaunix.net/uid-29589379-id-4708909.html 原文地址:linux内核移植和驱动添加(三) 作者:genehang 四,LED驱动的添加 1, 将led.c驱动文件拷贝到linux-3.1.4/drivers/char/目录下 [email protected]# pwd /change/linux-3.1.4/drivers/char [email protected]#  cp /mnt/hgfs/fh/driver/

【FL2400】Linux3.0 内核移植 一

接触arm + Linux已经将近两年了,之前都是站在大神的肩膀上来移植linux内核,对很对要求移植的东西都不是很懂!为了进一步深入对内核的了解,我决定重新从头开始对linux内核进行移植.这次移植完全是从一个新手的角度进行移植,包括可能出现的问题,以及出现的问题如何解决. 环境: 操作系统: CentOS 6.2 编译环境:gcc version 4.3.6 (Buildroot 2011.11) 开发板    : 飞凌2440(s3c2440)(arm920t) u-boot    :u-

linux-3.15.4内核移植

1.解压内核 sudo xz -d linux-3.15.4.tar.xz sudo tar xvf linux-3.15.4.tar 2.修改内核源码顶层的Makefile sudo vim Makefile arch=arm CROSS_COMPILE=arm-linux- 3.vim arch/arm/mach-s3c24xx/mach-smdk2440.c s3c24xx_init_clocks(12000000);4.make menuconfig命令配置内核,使用默认的配置文件/ar

基于fs210平台的dm9000原理及移植

dm9000的原理图如下: 网卡的移植工作很简单,首先是需要添加目标版的平台设备信息,就可以实现网卡的移植工作,平台设备信息如何添加很重要 添加平台信息的第一步是添加一个platform_device设备信息 首先在arch/arm/mach-s5pv210/mach-smdkv210.c 添加头文件: #include <linux/dm9000.h>              #include <linux/irq.h>              添加platform_devi

【转】 linux内核移植和网卡驱动(二)

原文网址:http://blog.chinaunix.net/uid-29589379-id-4708911.html 一,内核移植步骤: 1, 修改顶层目录下的Makefile ARCH            ?= $(SUBARCH) CROSS_COMPILE   ?= $(CONFIG_CROSS_COMPILE:"%"=%) 修改为: ARCH :=arm CROSS_COMPILE :=/usr/local/arm/4.4.3/bin/arm-linux- 2, 拷贝配置文

linux 3.4.103 内核移植到 S3C6410 开发板 移植失败 (问题总结,来日再战!)

linux 3.4.103 内核移植到 S3C6410 开发板 这个星期几乎就搭在这里面了,一开始感觉很不值得,移植这种浪费时间的事情,想立马搞定,然后安安静静看书 & coding. 坑爹的事情就是一个多星期的时间搭进去了,还是没成功.我把我的移植失败的经验留下来做为笔记,为下次做准备,也让和我一起做移植的道友少走弯路.大家一起共同分享经验,营造更好的开发环境. 查了很多资料,在此谢谢那些bloger, thanks for your spirit of sharing. 一. 从官网获得干净

Linux驱动学习之Linux-2.6.20.4内核移植

最近一段时间一直在学习向TQ2440开发板移植内核.移植驱动.真心觉得这方面的知识有很大的难度.但是从另一角度去看,难度越大,能力提升的空间就越大!! 1.解压源码 从网上下载一个Linux 内核,我是用的是Linux-2.6.20.4.然后用命令解压.建议解压到"/home/用户名"目录下.我的内核源码存放在: 2.添加对ARM的支持 因为所用的是TQ2440开发板,属于ARM9.因此要在系统中添加对ARM的支持. 方法:进入内核源码目录, 修改"Makefile"