您的位置:首页 > 运维架构 > Linux

Porting:linux内核编译、配置、修改配置文件、添加.c文件到内核

2017-02-23 22:47 585 查看
1、linux内核
     www.kernel.org
     $:'uname -a
     $:'uanme -r
     // 查看linux内核版本,开发板上进入linux后是同样的命令。
     早起经常使用的版本:linux 2.6.x
     开发板上使用的版本:linux 3.4.39
     linux最新版本:linux 4.x

2、linux内核的5大功能
     1)内存管理功能;
     2)进程管理及进程间通信;
     3)虚拟文件子系统;
     4)设备驱动管理;
     5)网络子系统;
     嵌入式平台有操作系统,优势在于:
        1)编程简单,有库函数可以调用;
        2)可以实现更加复杂的业务逻辑;// 多进程 多线程

3、linux内核的编译
     env/kernel.tar.bz2
     $:'cp /mnt/hgfs/porting/env/kernel.tar.bz2 .
     $:' tar xvf *.bz2
     $:' cd kernel/
     $:'find ./ -type f | wc -l
     // 26129
     $:'cp arch/arm/configs/x6818_defconfig .config
     $:'vi Makefile
     // 195 ARCH ?= arm
     // 196 CROSS_COMPILE ?= arm-cortex_a9-linux-gnueabi-
     $:'make uImage -j4
     // arch/arm/boot/uImage  is  ready

     $:'make menuconfig -j4
     // 此项为内核功能配置,可删减(内核裁剪)

** 编译异常问题解决 **
     问题1:
     >>如果出现"mkuimage"command not find
     解决办法:
         $:'sudo cp ~/project/uboot/tools/mkimage /usr/bin/
         $:'make uImage
     问题2:
     >>Your display is too small...
     解决办法:
       缩小字体显示比例。

验证uImage的有效性:
    把uImage烧写0x800扇区开始的分区位置。
    通过加载的方式:
    cp arch/arm/boot/uImage /tftpboot/
    tftp 48000000 uImage
    bootm 48000000

    setenv bootcmd tftp 48000000 uImage \; bootm 48000000

3.1 内核的配置
【什么是配置?】
    假设linux内核中提供了10000种功能,但是具体到开发板上只需要其中2000个功能。
    1)裁剪掉内核中不需要的功能
         不需要挂载U盘
         // 内核中关于FAT32类型文件系统相关的代码的支持就不需要
    2)驱动程序的裁剪
         // 产品中没有键盘,裁剪掉内核中的键盘驱动
    【总之】根据目标产品的需要,以及开发板的实际硬件,裁剪掉不需要的内核代码。
【如何完成配置?】
    找一个相近的配置文件,在此基础上进行修改。
【去哪里找相近的配置?】
    1)去内核源码目录  arch/arm/configs/xxx_defconfig
    2)上游厂家提供
【如何修改配置?】
    cp 相近的配置.config  kernel/.config
    a)$:'  make menuconfig
       // 模拟菜单显示界面
         General setup  --->
         System Type  --->
                ARM system type (SLsiAP S5P6818)  --->
         Boot options  --->
         Device Drivers  ---> // 硬件驱动设备
         File systems  ---> // 文件系统
     b)$:' make config
    // 纯文字提示,基本不用
     c)$:'  make xconfig
     // 真实图形显示菜单界面,基本不用
     "make help" 查看内核make帮助命令。

内核本质也是一个裸板程序。
    .o ... .o  ---> elf 文件 (vmlinux)
    vmlinux  ---> Image(.bin)  --->  zImage  ---> uImage
    zImage:解压缩代码 + 压缩后的Image数据
    uImage:64Bytes + zImage
    // 64Bytes:内核的加载地址、内核版本 ... 一般给uboot使用。
    $:'du -h arch/arm/boot/Image
    // 11M
    $:'du -h arch/arm/boot/zImage
    // 5.2M <-b> 5400688,压缩后的Image
    $:' du -harch/arm/boot/uImage
    // 5.2M <-b> 5400752

<tips>
$:'du -h
// 以兆(M)显示文件大小 和 文件名
$:'du -b
// 以字节数显示文件大小 和 文件名

3.2 linux内核的启动过程
     阅读代码,组织工程。
     linux : vim + ctags
     $:'rm arch/arm/mach-s5p6818/prototype/prototype
     $:'ctags -R *
     windows : source insight
     入口点文件:
            $:'rm vmlinux
            $:'make uImage V=1
            // V=1 显示详细的编译过程
            $:'vi arch/arm/kernel/vmlinux.lds
            .head.text : {
                _text = .;
                *(.head.text)
            }
      // 整个linux内核的入口点文件:arch/arm/kernel/head.S
      head.S:
            设置SVC模式
            __lookup_processor_type  // 检查CPU的ID看内核的状态
            bl  __create_page_tables  // 创建页表
            ldr     r13, =__mmap_switched 
            b       __enable_mmu
                 。。。
                 。。。
              b       __turn_mmu_on
              450 ENTRY(__turn_mmu_on)
              457         mov     r3, r13
 458         mov     pc, r3 //跳转到__mmap_switched
__mmap_switched:
b       start_kernel
start_kernel
   -->rest_init
      {
           //创建一个新的内核线程
           kernel_thread(kernel_init, NULL, CLONE_FS | CLONE_SIGHAND);
      }
         kernel_init( )
          {
             prepare_namespace( )
              {
                 //根据bootargs的参数,挂载根文件系统
                 mount_root( );
              }
              init_post( )
              {
                  //执行用户空间的1号进程
                  run_init_process("/sbin/init");
              }
          }
系统上电--->uboot完成硬件的初始化--->执行bootcmd中的命令--->加载操作系统到内存--->传递参数给内核,并启动内核--->检查CPU ID当前内核是否支持--->创建页表开启MMU--->start_kernel--->创建一个新的内核线程--->根据参数去挂载根文件系统--->从根文件系统中找到1号进程--->创建执行1号进程--->1号进程后续会创建子进程/bin/bash--->用户可以输入命令

    移植内核的关键文件:arch\arm\mach-s5p6818\cpu.c
    其中的关键代码信息:
            static void __initcpu_init_machine ( void ) {
                ...
            nxp_cpu_devs_register ( );
           nxp_board_devs_register ( );
            }
           // 该函数是在 kernel_init 中被调用,即系统启动过程中被调用。
            kernel_init ( ) {
                do_basic_setup ( ) {
                    do_initcalls ( ) {
                        ...
                       cpu_init_machine ( );
// 移植的重点。要改的函数。
                    }
                }
            }

4、配置过程是如何影响编译过程的
$:'  make menuconfig
    Device Drivers  --->
            Character devices  ---> 
                     -*- LED Support  ---> 
                    // LED Support for GPIO connected LEDs ---> help
---> 变量:CONFIG_LEDS_GPIO
$:' vi .config
CONFIG_LEDS_GPIO=y     // <*>
CONFIG_LEDS_GPIO=m   // <M>
# CONFIG_LEDS_GPIO is not set   // < >

【结论1】配置的结果是以变量取不同的值的形式保存在 .config 文件中。
【结论2】内核中几乎所有的目录下都有Makefile文件。
【结论3】各个子目录下的Makefile决定了当前目录下的文件(夹)是否参与编译过程。
$:'grep "CONFIG_LEDS_GPIO" * -nRw
   // grep显示行号-递归-内容检索:
    drivers/leds/Makefile:22行使用了该变量
    obj-$(CONFIG_LEDS_GPIO) += leds-gpio.o
    <*>   CONFIG_LEDS_GPIO=y  ' boj-y += leds-gpio.o
    <M> CONFIG_LEDS_GPIO=y  ' boj-m += leds-gpio.o    
    < >   CONFIG_LEDS_GPIO=y  ' boj-  += leds-gpio.o
【结论4】
在编译内核时 boj-y += xxx.o 代表 xxx.c 参与编译,并最终链接到内核uImage;
在编译内核时 boj-m += xxx.o 代表 xxx.c 参与编译,但不会链接进内核uImage,生成一个独立的xxx.o;
在编译内核时 boj-  += xxx.o 代表 xxx.c 不参与编译。

5、如何将一个.c文件编译进内核
// env/led_drv.c
$:'cp /mnt/hgfs/porting/env/led_drv.c drivers/char/
$:'vi drivers/char/Makefile
增加1行:obj-y               += led_drv.o
$:'make uImage
$:' cp arch/arm/boot/uImage  /tftpboot/

#:' tftp 48000000 uImage
#:' bootm 48000000
#:'dmesg >1.txt
#:'dmesg | grep "led_init"
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  arm u-boot 移植