主题 : linux-2.6.38内核移植的经验和疑惑 复制链接 | 浏览器收藏 | 打印
春有百花秋有月,夏有凉风冬有雪。若无闲事挂心头,便是UBUNTU好时节。。。。
级别: 侠客
UID: 24947
精华: 2
发帖: 63
金钱: 430 两
威望: 86 点
贡献值: 2 点
综合积分: 166 分
注册时间: 2010-07-16
最后登录: 2019-04-27
楼主  发表于: 2011-03-29 22:20

 linux-2.6.38内核移植的经验和疑惑

这次的内核移植确实费了我不少神,但让我对linux的启动有了更深的了解。

首先我还是把我的疑惑说出来,以便大虾不要看了就跑了:
我移植后的内核的启动参数只能通过配置boot option成为默认的启动参数,而bootloader传递的参数根本就读不到,
好像arch/arm/kernel/setup.c程序中的strlcpy(default_command_line, tag->u.cmdline.cmdline, COMMAND_LINE_SIZE);没有作用似的。
这样的话内核的启动就很不灵活了,比如要挂载nfs根文件系统就不行咯,这甚是麻烦,而且head-armv.S程序也没有了,不知从和地方下手
希望大虾们赐教赐教。

下面小的献丑贴上自己的一些小经验:

 首先还是根据mini2440 的《linux 移植开发指南》把驱动nandflash分区表等等改好。
然后make menuconfig配置好内核之后执行 (内核的配置可参照光盘2.6.32的配置以及使用手册)
make zImage 编译

 问题一:
复制代码
  1. arch/arm/mach-s3c2440/mach-mini2440.c:189: error: array type has incomplete element type
  2. arch/arm/mach-s3c2440/mach-mini2440.c:190: error: array index in non-array initializer
  3. arch/arm/mach-s3c2440/mach-mini2440.c:190: error: (near initialization for 'smdk_default_nand_part')
  4. arch/arm/mach-s3c2440/mach-mini2440.c:191: error: field name not in record or union initializer
  5. arch/arm/mach-s3c2440/mach-mini2440.c:191: error: (near initialization for 'smdk_default_nand_part')
  6. arch/arm/mach-s3c2440/mach-mini2440.c:193: error: unknown field 'tacls' specified in initializer
  7. arch/arm/mach-s3c2440/mach-mini2440.c:193: warning: excess elements in struct initializer
  8. arch/arm/mach-s3c2440/mach-mini2440.c:193: warning: (near initialization for 'mini2440_nand_info')
  9. arch/arm/mach-s3c2440/mach-mini2440.c:194: error: unknown field 'twrph0' specified in initializer
  10. arch/arm/mach-s3c2440/mach-mini2440.c:194: warning: excess elements in struct initializer
  11. arch/arm/mach-s3c2440/mach-mini2440.c:194: warning: (near initialization for 'mini2440_nand_info')
  12. arch/arm/mach-s3c2440/mach-mini2440.c:195: error: unknown field 'twrph1' specified in initializer
  13. arch/arm/mach-s3c2440/mach-mini2440.c:195: warning: excess elements in struct initializer
  14. arch/arm/mach-s3c2440/mach-mini2440.c:195: warning: (near initialization for 'mini2440_nand_info')
  15. arch/arm/mach-s3c2440/mach-mini2440.c:196: error: unknown field 'nr_sets' specified in initializer
  16. arch/arm/mach-s3c2440/mach-mini2440.c:196: warning: type defaults to 'int' in declaration of 'type name'
  17. arch/arm/mach-s3c2440/mach-mini2440.c:196: warning: type defaults to 'int' in declaration of 'type name'
  18. arch/arm/mach-s3c2440/mach-mini2440.c:196: error: negative width in bit-field '<anonymous>'
  19. arch/arm/mach-s3c2440/mach-mini2440.c:196: warning: excess elements in struct initializer
  20. arch/arm/mach-s3c2440/mach-mini2440.c:196: warning: (near initialization for 'mini2440_nand_info')
  21. arch/arm/mach-s3c2440/mach-mini2440.c:197: error: unknown field 'sets' specified in initializer
  22. arch/arm/mach-s3c2440/mach-mini2440.c:197: warning: excess elements in struct initializer
  23. arch/arm/mach-s3c2440/mach-mini2440.c:197: warning: (near initialization for 'mini2440_nand_info')
  24. arch/arm/mach-s3c2440/mach-mini2440.c:198: error: unknown field 'ingnore_unset_ecc' specified in initializer
  25. arch/arm/mach-s3c2440/mach-mini2440.c:198: warning: excess elements in struct initializer

我想这因该是头文件缺少了的原因吧,于是拿友善之臂移植的源代码一对比发现少了不少的头文件,我用了投机取巧的方法把他的头文件全都拷贝过来覆盖掉以前的
呵呵,大家有兴趣的话可以用source insight查看一下
然后再编译,果然通过,可是问题也接踵而来:

问题二:
复制代码
  1. drivers/char/mini2440_adc.c: In function 's3c2410_adc_read':
  2. drivers/char/mini2440_adc.c:90: error: 'ADC_LOCK' undeclared (first use in this function)
  3. drivers/char/mini2440_adc.c:90: error: (Each undeclared identifier is reported only once
  4. drivers/char/mini2440_adc.c:90: error: for each function it appears in.)
  5. drivers/char/mini2440_adc.c: At top level:
  6. drivers/char/mini2440_adc.c:193: error: 'ADC_LOCK' undeclared here (not in a function)
  7. drivers/char/mini2440_adc.c:193: warning: type defaults to 'int' in declaration of 'ADC_LOCK'
  8. make[2]: *** [drivers/char/mini2440_adc.o] 错误 1
  9. make[1]: *** [drivers/char] 错误 2
  10. make: *** [drivers] 错误 2

我惊讶了,这个驱动可是在linux2.6.32下跑到好好的啊,怎么会在这里出问题呢,况且
信号量ADC_LOCK已经用宏定义:
DECLARE_MUTEX(ADC_LOCK)
定义了且初始化为1了啊;
在网上疯狂的搜索都没有办法,查看内核文档也没有细节;
我真的要抓狂了,结果一晚上都没怎么睡好,仔细想想,难道信号量的机制在linux2.6.38中改写了,
于是第二天一大早的跑到实验室用source insight搜索DECLARE_MUTEX,结果没搜到,我确实很郁闷,因为
以前我们都是利用这个宏定义简单的把定义和初始化的工作做完,现在放弃有点不方便把,心有不甘,再尝试着
搜索sema_init符号,结果在semaphore.h中找到了,令人惊讶的是就在上面
有了:
复制代码
  1. #define DEFINE_SEMAPHORE(name)    \
  2.     struct semaphore name = __SEMAPHORE_INITIALIZER(name, 1)

我接着查看__SEMAPHORE_INITIALIZER的定义:
复制代码
  1. #define __SEMAPHORE_INITIALIZER(name, n)                \
  2. {                                    \
  3.     .lock        = __SPIN_LOCK_UNLOCKED((name).lock),        \
  4.     .count        = n,                        \
  5.     .wait_list    = LIST_HEAD_INIT((name).wait_list),        \
  6. }

这不就是DECLARE_MUTEX()的功能吗?!

问题找到了于是马上动手将DECLARE改成DEFINE
一编译,通过了生成了zImage 文件
我马上下载运行结果串口界面卡在了
boot kernel......
而屏幕上显示了
VFS: Cannot open root device "<NULL>" or unknown-block(2,0)
我试着改写bootloader的传递参数,和重新制作yaffs文件系统,都不行
我怀疑中间的 "<NULL>"值,是因为内核没有拷贝到bootloader传来的参数?
于是我在配置选项的boot option 里的Default kernel command string中填上如下信息:
  noinitrd root=/dev/mtdblock3 init=/linuxrc console=ttySAC0 rootfs=yaffs2
感谢天和地,启动了
至与Read-only file system的问题,在启动参数里加上rootfs=yaffs2 rw即:
noinitrd root=/dev/mtdblock3 init=/linuxrc console=ttySAC0 rootfs=yaffs2 rw

至于为什么不能拷贝到bootloader传来的参数确实是需要大家的帮助。
[ 此帖被小荷尖尖在2011-03-29 22:25重新编辑 ]
春有百花秋有月,夏有凉风冬有雪。若无闲事挂心头,便是UBUNTU好时节。。。。
级别: 侠客
UID: 24947
精华: 2
发帖: 63
金钱: 430 两
威望: 86 点
贡献值: 2 点
综合积分: 166 分
注册时间: 2010-07-16
最后登录: 2019-04-27
1楼  发表于: 2011-03-30 19:32
再补充一个问题:
触摸屏驱动虽然移植成功了可是tslib没有作用,触摸屏还是没有用,
我用ts_test测试终端打印了
tslib: Selected device uses a different version of the event protocol than tslib was compiled for

查看tslib源代码发现打印该信息的语句在tslib的源代码的plugs文件夹中input-raw.c的
static int check_fd(struct tslib_input *i)函数中,发现tslib在加载linux触摸屏驱动模块时会检查内核的输入子系统的
版本号:
         if (ioctl(ts->fd, EVIOCGVERSION, &version) < 0) {
        fprintf(stderr, "tslib: Selected device is not a Linux input event device\n");
        return -1;
            }
        上面程序段将驱动的版本号存放在整型的version中
    if (version != EV_VERSION) {
        fprintf(stderr, "tslib: Selected device uses a different version of the event protocol than tslib was compiled for\n");
        return -1;
    }
        该程序将获得的版本号version与本tslib的面向的版本号匹配,若不同则打印:
        tslib: Selected device uses a different version of the event protocol than tslib was compiled for
        信息
        
    
再看arm交叉编译工具中的头文件库中的linux/input.h中的EV_VERSION定义为
    #define EV_VERSION        0x010000
而linux内核include/linux/input.h中的EV_VERSION定义为
    #define EV_VERSION        0x010001
由此可见问题就出现在内核的输入子系统的版本号不匹配的问题
    
    
解决办法:
    1.将内核源代码里的include/linux/input.h中的
    #define EV_VERSION        0x010001
    改为:
    #define EV_VERSION        0x010000
    2.将arm交叉编译工具中的头文件库中的
    linux/input.h中的
    #define EV_VERSION        0x010000
    改为
    #define EV_VERSION        0x010001
    再编译tslib库
春有百花秋有月,夏有凉风冬有雪。若无闲事挂心头,便是UBUNTU好时节。。。。
级别: 侠客
UID: 24947
精华: 2
发帖: 63
金钱: 430 两
威望: 86 点
贡献值: 2 点
综合积分: 166 分
注册时间: 2010-07-16
最后登录: 2019-04-27
2楼  发表于: 2011-03-30 23:13
终于解决了:linux-2.6.38内核移植bootloader不能传递启动参数给内核的问题了!

    将linux2.6.38与linux2.6.32比较arch/arm/kernel/setup.c文件发现
    在2.6.38中setup.c里的void __init setup_arch(char **cmdline_p)函数里多了下面这些代码:
    #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
    而2.6.32中setup.c里的void __init setup_arch(char **cmdline_p)函数是这样写的:
    /*
     * If we have the old style parameters, convert them to
     * a tag list.
     */
    if (tags->hdr.tag != ATAG_CORE)
        convert_to_tag_list(tags);
    
    由此可见2.6.38用预编译开关了这条关键语句,我再在我配置的.config文件中搜索CONFIG_DEPRECATED_PARAM_STRUCT并没选上
    找到这个宏所属kernel features栏,用make menuconfig配置好再重新编译,果然成功了
    找到
         [ ] Provide old way to pass kernel parameters
    选项的帮助一看:
           CONFIG_DEPRECATED_PARAM_STRUCT:                                          
  │                                                                                                                                
  │ This was deprecated in 2001 and announced to live on for 5 years.        
  │ Some old boot loaders still use this way.
    
    意味着已经默认为放弃这种传统的参数传递方式!但现在还是支持,因此bootloader看来也得要与时俱进啊!
级别: 新手上路
UID: 37822
精华: 0
发帖: 33
金钱: 210 两
威望: 42 点
贡献值: 0 点
综合积分: 66 分
注册时间: 2011-02-17
最后登录: 2014-10-13
3楼  发表于: 2011-04-04 01:52
本部分内容设定了隐藏,需要回复后才能看到
级别: 侠客
UID: 40718
精华: 0
发帖: 69
金钱: 350 两
威望: 70 点
贡献值: 0 点
综合积分: 138 分
注册时间: 2011-03-21
最后登录: 2015-05-20
4楼  发表于: 2011-04-04 15:51
做为新手  很想学习学习移植liunx  不知道从何入手

开发板也买了
春有百花秋有月,夏有凉风冬有雪。若无闲事挂心头,便是UBUNTU好时节。。。。
级别: 侠客
UID: 24947
精华: 2
发帖: 63
金钱: 430 两
威望: 86 点
贡献值: 2 点
综合积分: 166 分
注册时间: 2010-07-16
最后登录: 2019-04-27
5楼  发表于: 2011-04-05 15:17

 回 4楼(abszy) 的帖子

我也属于菜鸟吧,但是还是可以分享一点经验的:
一点:耐力
二点:尽所有力量让自己去解决自己面临的问题

要入手linux的话,从linux系统编程开始再到模块编程这样的顺序是比较容易让人接受的,
我个人这样总结接受新事物的流程(当然也是前辈们宝贵的经验):
  从表面感知到原理分析(就如学习linux系统编程再到内核实现机制的认识)
从宏观再到细节(掌握一件复杂庞大的事务你得从轮廓上要把握他,不然你会淹没在细节里,又说既见树木又见件森林)

希望以上能够对你有帮助。
级别: 新手上路
UID: 34274
精华: 0
发帖: 4
金钱: 30 两
威望: 6 点
贡献值: 0 点
综合积分: 8 分
注册时间: 2010-12-13
最后登录: 2011-07-20
6楼  发表于: 2011-04-07 10:14
顶!!!!!!!!
级别: 新手上路
UID: 20276
精华: 0
发帖: 29
金钱: 150 两
威望: 30 点
贡献值: 0 点
综合积分: 58 分
注册时间: 2010-04-29
最后登录: 2021-06-25
7楼  发表于: 2011-04-14 21:38
顶,多点楼主这样分享经验就好了,谢谢
chM
级别: 新手上路
UID: 6893
精华: 0
发帖: 6
金钱: 30 两
威望: 6 点
贡献值: 0 点
综合积分: 12 分
注册时间: 2009-06-22
最后登录: 2014-02-13
8楼  发表于: 2011-04-26 08:24
真的很好~~~~~~~~~~~~~~
级别: 新手上路
UID: 25477
精华: 0
发帖: 3
金钱: 15 两
威望: 3 点
贡献值: 0 点
综合积分: 6 分
注册时间: 2010-07-24
最后登录: 2011-08-14
9楼  发表于: 2011-04-30 23:22
楼主真是帮我大忙,我今天正打算参数文档移植2.6.38的内核,我先用了内核的mini2440_defconfig编译了一下内核,很顺利就编完,可是烧到板子上启动用串口没有调试信息,LCD上显示了一大串然后就黑屏了。我也怀疑是控制台参数 console=ttySAC0 没有传进去,开始以为SuperVivi 的参数区与内核的不一致,看看mach-mini2440.c的内容是对的,正纳闷呢,于是乎到坛子上看看。原来是内核参数的传递方式变了,我压根就没往这里想,也就没看源码,唉,内核为什么老变啊。