day04

2019-07-13 01:15发布

回顾:
1.uboot的logo显示
  目的
  场合
  原则
  显示原理
  图像->像素->颜 {MOD}->RGB
  软件操作显存
      画点/画线/画矩形/画圆/画LOGO
 
2.linux内核
  问:uImage从何而来?
  2.1.明确:嵌入式linux系统软件三部分
      bootloader:uboot
      linux内核:uImage
      根文件系统rootfs
   
  2.2.linux内核特点(吹牛)
   
  2.3.linux内核七大功能
   
  2.4.linux内核源码的操作
      1.获取源码
      2.获取正确的交叉编译器
      3.验证源码是否正确
        make distclean
        make ABC_defconfig
        make uImage
        编译通过:
        1.源码没毛病
        2.版本配合
        3.此时源码仅仅支持参考板,还不一定能够运行在自己的开发板上
          一定要获取到硬件差异(硬件工程师)
      4.根据硬件差异对源码进行修改
        从以下两个方面对源码进行检查修改:
        1.从内核源码的配置角度
            make menuconfig
                System Type->
                            //三个检查
              Boot optios->
                          //检查内核的启动参数到底用谁的
              Device Driver->
                          //各类硬件外设的驱动
                          Norflash/Nandflash驱动
                          输入设备驱动
                                  键盘
                                  触摸屏
                                  鼠标
                                  游戏摇杆
                          摄像头驱动
                          LCD显示屏驱动
                          声卡驱动    
                          I2C总线驱动
                          SPI总线驱动
                          1-Wire总线驱动
                          USB驱动
                          TF卡/SD卡/EMMC驱动
              File System->  
                       //文件系统
                       EXT4
                       VFAT
                       NTFS
                       CRAMFS
                       UBIFS
                       JFFFS2
                       YAFFS2    
                       NFS
        2.从内核源码的跟硬件相关的源代码角度
          切记只需关注一个跟开发板相关的硬件信息的源代码即可
          此源代码又称平台相关代码:
          内核源码根目录/arch/arm/plat-s5p6818/x6818/device.c
          此文件务必仔细的多多看,里面记录了大量的硬件外设的硬件信息
          例如:I2C外设的设备地址等
          案例:打开X6818平台文件,慢慢品味此文件的奥秘
          cd /opt/kernel
          vim arch/arm/plat-s5p6818/x6818/device.c
          仔细阅读!
           
          vim arch/arm/plat-s5p6818/x6818/device.c +439
          将四个LED灯的硬件信息代码注释掉
          保存退出
           
          vim arch/arm/plat-s5p6818/x6818/device.c +399
          将:
          #define    GSLX680_I2C_BUS        (1)
          修改为:
          #define    GSLX680_I2C_BUS        (2)  
          说明:将触摸屏GLSX680芯片连接到CPU的I2C总线编号由第2个改成第3个
          保存退出
          make uImage -j2/j4/j8
          cp arch/arm/boot/uImage /tftpboot
           
          下位机测试:
          重启下位机进入uboot命令行执行
          tftp 48000000 uImage  
          bootm 48000000
          系统启动完毕,查看呼吸灯是否还在闪烁
          查看触摸屏是否还能正常操作
          注意:实验做完,将触摸屏的I2C总线编号再次修改为1
           
2.5.问:linux内核的配置菜单如何实现呢?
        如何在已有的菜单中添加自己的代码编译菜单
    答:明确:内核的配置菜单的作用就是便于用户通过
        菜单的形式向内核uImage添加或者删除某个功能
        某个硬件设备驱动程序
        要实现此功能,只需Kconfig和Makefile即可
    1.linux内核Kconfig的基本语法
      Kconfig功能就是生成一个菜单选项
      常用的关键字:
      config:用于生成一个菜单选项
      tristate:指示此菜单选项的操作方式有三种
               按Y键选中为*/按M键选中为M/按N键不选           
        bool:指示此菜单选项的操作方式有两种
                         按Y键选中为*/按N键不选        
        help:指示此菜单选项的帮助信息
        注意:
        按Y键选中为*:表示选中选项,并且将这个选项对应的
                      源代码和uImage编译在一起(在一起)
        按M键选中为M: 表示选中选项,并且将这个选项对应的
                      源代码和uImage分开单独编译(分家)   
        按N键不选中:不会编译对应的源代码
                     
        例如:
        config HELLO_WORLD
        (TAB)tristate "hello,world"
        (TAB)help
                        "this is a test msg"           
        说明:
        config HELLO_WORLD:最终生成一个菜单选项
                                        选项的名称为:CONFIG_HELLO_WORLD          
        总结:
        config A:将来生成的菜单选项为:CONFIG_A  
        CONFIG_A将来是给Makefile文件使用,Makefile文件
        使用格式:obj-$(CONFIG_A) += 源文件.o         
        说明如下:
        1.如果按Y键选中为*,那么CONFIG_A=y
          展开:obj-y += 源文件.o
          表示将源码和uImage编译在一起
         
        2.如果按M键选中为M,那么CONFIG_A=m
          展开: obj-m += 源文件.o
          表示将源码和uImage分开编译
         
        3.如果按N键不选中,那么CONFIG_A=空
          展开:空
          表示源码不进行编译
           
案例1:向内核添加LED驱动程序,实现开关灯操作
            目前采用将驱动和uImage编译在一起的方式             
实施步骤:
上位机执行:
1.获取LED驱动程序和测试程序:
ftp://porting/led_drv.tar.bz2/
                                    led_drv.c //LED驱动程序  
                                    led_test.c //LED应用测试程序
2.拷贝驱动到内核源码中
  cp led_drv.c /opt/kernel/drivers/char/
 
3.添加LED的配置菜单
  vim /opt/kernel/drivers/char/Kconfig 添加如下内容
  config TARENA_LED
  (TAB键)tristate "tarena led driver"
  (TAB键)help
                      "this is a led driver"
  保存退出
  内心有个想法:将来生成的选项:CONFIG_TARENA_LED
   
4.添加LED驱动的编译支持
  vim /opt/kernel/drivers/char/Makefile 添加如下内容:
  obj-$(CONFIG_TARENA_LED) += led_drv.o
  保存退出
 
5.配置内核添加LED驱动
  cd /opt/kernel
  make menuconfig
      Device Drivers->
                Character devices  --->  
                    //按Y键选择为*
                      <*> tarena led driver (NEW)  
  保存退出
  vim .config //搜索CONFIG_TARENA_LED检查是否等于y
    make uImage -j2/j4/j8
    cp arch/arm/boot/uImage /tftpboot
    注意:此时此刻的uImage就有了LED驱动程序
 
6.交叉编译测试程序
  cp led_test.c /opt/rootfs/ //拷贝测试程序到根文件系统rootfs
  cd /opt/rootfs/
  arm-cortex_a9-linux-gnueabi-gcc -o led_test led_test.c
      
下位机测试:
进入uboot命令行执行:
tftp 48000000 uImage
bootm 48000000 //前提是内核根据NFS找根文件系统
下位机的linux系统启动完毕,执行:
cd /
ls  
  led_test
./led_test on  //开灯
./led_test off //关灯
 
案例2:向内核添加LED驱动程序,实现开关灯操作
             采用将驱动和uImage编译分开编译
上位机执行:                
1.配置内核添加LED驱动
  cd /opt/kernel
  make menuconfig
      Device Drivers->
                Character devices  --->  
                    //按M键选择为M
                      tarena led driver (NEW)  
  保存退出
  vim .config //搜索CONFIG_TARENA_LED检查是否等于m
    make uImage -j2/j4/j8 //单独重新编译内核源码
    cp arch/arm/boot/uImage /tftpboot
    注意:此时此刻的uImage就没有了LED驱动程序          
 
2.单独编译内核LED驱动
  cd /opt/kernel
  make modules //采用模块化编译
  ls drivers/char/led_drv.ko -lh //查看单独编译的LED驱动程序的目标文件
  注意:内核源码采用模块化编译,对应的二进制文件名称为xxx.ko
        led_drv.c->led_drv.ko
  cp drivers/char/led_drv.ko /opt/rootfs/ //拷贝驱动的目标文件到根文件系统rootfs
 
    
下位机执行:
进入uboot命令执行:
tftp 48000000 uImage //此时uImage没有LED驱动
bootm 48000000
下位机的linux系统启动完毕,执行:
cd /
ls
  led_drv.ko(驱动二进制文件) led_test(应用测试程序)
insmod led_drv.ko //安装驱动程序到uImage,insmod=insert module
lsmod //查看安装的驱动程序
./led_test on  
./led_test off
rmmod led_drv //从uImage中卸载安装的驱动程序
                            //卸载时无需添加.ko后缀
 
*************************************************
3.根文件系统rootfs
  问:上位机的根文件系统/opt/rootfs
      向下位机烧写的根文件系统镜像rootfs_ext4.img
      从何而来?
  3.1.明确:根文件系统rootfs特点
      根文件系统rootfs仅仅是一个代名词而已,不代表任何东西和意义
      根文件系统rootfs包含的内容(cd /; ls看到的内容)有:
      bin目录:各种命令
      sbin目录:各种超级用户命令
      lib目录:各种库
      etc目录:各种服务配置
      usr目录:各种命令
      ...
      以上这些内容聚集在一起形成了根文件系统rootfs
   
  3.2.根文件系统rootfs中包含的内容总体分两部分
      必要目录和可选目录
      切记必要八大目录如下:
      bin目录:各种命令,例如:ls,cd等
      sbin目录:各种超级用户命令,例如:mknod等
      lib目录:各种库,例如:libc*
      etc目录:各种服务配置:etc/default/tftd-hpa等
      usr目录:各种命令,例如:top等
      dev目录:硬件设备对应的设备文件
      proc目录:作为procfs虚拟文件系统的入口
      sys目录:作为sysfs虚拟文件系统的入口  
       
      可选目录:
      home:用户主目录
      tmp:临时目录
      var:临时目录
      mnt:U盘/TF卡/SD卡的挂节点(入口)
    
     问:有了必要目录和可选目录,每一个目录下的内容  
         (各种命令,各种库)如何添加呢(总不能自己编写)?
     答:利用大名鼎鼎的开源软件busybox   
    
   3.3.谈谈busybox的特点(吹牛)
     1.是一款著名的开源软件,外号“瑞士军刀”
       官网:www.busybox.net
     2.busybox跟硬件信息不相关
     3.不要指望busybox提供根文件系统所有的软件
       busybox仅仅提高各种命令
     4.建议实际开发最好自己利用busybox制作一个根文件系统  
       而不是使用官方的根文件系统rootfs
    
   3.4.利用busybox制作根文件系统rootfs的流程
     1.获取busybox源码
       从www.busybox.net直接下载获取即可
       ftp://porting/busybox-1.21.1.tar.bz2
      
     2.获取正确的交叉编译器
       确保交叉编译器的版本和busybox的版本门当户对
        
     3.busybox源码的交叉编译
       3.1.源码解压缩
       cp busybox-1.21.1.tar.bz2 /opt/
       cd /opt
       tar -xvf busybox-1.21.1.tar.bz2 //得到busybox源码目录:busybox-1.21.1
       mv busybox-1.21.1 busybox //重命名
        
       3.2.修改Makefile
       cd /opt/busybox //进入busybox源码根目录
       vim Makefile +190
       将
       ARCH ?= $(SUBARCH)
       修改为:
       #指定将来根文件系统运行在ARM架构
       ARCH=arm
       保存退出
        
       vim Makefile +164
       将
       CROSS_COMPILE ?=  
       修改为
       #指定交叉编译器
       CROSS_COMPILE=arm-cortex_a9-linux-gnueabi-
       保存退出
        
       3.3.配置busybox源码
       cd /opt/busybox
       make menuconfig
                Linux Module Utilities  --->  
                             //按N键去除选项(insmod/lsmod/rmmod精简版命令)
                             [*] Simplified modutils (NEW)   
                             去除以上选项,立马出现完整版的命令选项:
                             [*]   insmod (NEW)                                                           │ │   
                               [*]   rmmod (NEW)                                                            │ │   
                             [*]   lsmod (NEW)  
                             [*]   Pretty output (NEW)  
                             [*]   Blacklist support                                                               │ │   
                               [*]   modprobe (NEW)                                                         │ │   
                           [*]   depmod (NEW)
            保存退出
              注意:目前busybox提供的命令已经足够使用
          
          3.4.正式交叉编译源码
            cd /opt/busybox
            time make -j2/j4/j8
            make install //安装编译busybox生成的各种二进制文件
                         //也就是将编译生成的各种二进制文件统一
                           拷贝到某个目录下
            ls _install/  //查看编译生成的内容
               linuxrc bin sbin usr //验证了busybox仅仅提高各种命令
            ls _install/bin/* -lh
            ls _install/sbin/* -lh
            ls _install/usr/bin/* -lh
            ls _install/usr/sbin/* -lh
            结论:所有的命令本质就是一个软连接文件
                  最终都连接到_install/bin/busybox
                  也就是编译busybox本质就是生成了一个
                  可执行文件bin/busybox
            
           3.5.创建必要目录和可选目录
               mv /opt/rootfs /opt/rootfs_bak //备份原先的根文件系统
               cp /opt/busybox/_install /opt/rootfs -frd   
               cd /opt/rootfs //进入自己制作的根文件系统的根目录
                
               //创建必要目录
               mkdir dev lib etc proc sys
                     
               //创建可选目录
               mkdir home tmp var mnt
            
           3.6.添加部署必要的动态库
               明确:
               1.动态库添加到根文件系统的lib必要目录
               2.要拷贝的动态库来自于交叉编译器
               3.获取一个应用程序运行时所需的动态库:
               cd /opt/rootfs
               //获取busybox可执行程序的所需的动态库
               arm-cortex_a9-linux-gnueabi-readelf -d bin/busybox 内容如下:
               共享库:[libm.so.6] //标准数学运算库
           共享库:[libc.so.6] //标准C库
           结论:busybox所需的动态库为:libm.so.6和libc.so.6