嵌入式系统移植掌握

嵌入式系统移植

一、嵌入式系统

  • 一般定义
    以应用为中心、以计算机技术为基础、软件硬件可裁剪、适应应用系统,对功能、可靠性、成本、体积、功耗严格要求的专用计算机系统。
  • 广义上讲
    凡是带有微处理器的专用软硬件系统都可称为嵌入式系统。
  • 嵌入式系统的核心是定制
    是根据市场需求对软硬件进行定制,实现性能的最大化

通用嵌入式系统软件组成部分

  • 图一为无os嵌入式系统组成图 嵌入式系统移植掌握_第1张图片
  • 图二为有os嵌入式系统组成图
    嵌入式系统移植掌握_第2张图片

嵌入式Linux内核结构

嵌入式系统移植掌握_第3张图片

Android系统

嵌入式系统移植掌握_第4张图片

二、嵌入式开发环境搭建

开发板启动流程

嵌入式启动流程
板子上电后首先运行bootloader,这是上电后的第一个程序,接着初始化硬件,引导加载内核,内核起来之后,挂载我们的rootfs根文件系统,接着运行我们的程序。
嵌入式系统移植掌握_第5张图片

搭建嵌入式Linux开发环境的主要工作

  1. 准备开发主机、目标机(开发板)以及二者的连接介质
  2. 准备目标机代码
  3. 安装交叉工具链
  4. 开发主机上安装的软件(为方便调试)
  5. 终端软件(putty、minicom)
  6. tftp服务
  7. nfs服务
  8. 目标机安装(u-boot烧写调试)
    SD卡方式
    Fastboot方式 (成功后,板子有串口信息输出)
  9. 主机和目标机能联通
  10. 网络自动 tftp 加载内核,并挂载nfs rootfs 启动

连接TFTP与NFS服务nfs与tftp服务搭建

嵌入式系统移植掌握_第6张图片
使用条件是:
需要网络连接
主机端需要安装 tftp 服务器软件
目标机需要实现tftp客户端(开发板已经装好,因为开发板上有uboot,uboot包含tftp客户端)
优点:
传输速度快
可以将编译好的内核下载到目标机,提高开发效率
tftp 是用来下载远程文件的最简单网络协议,它基于udp协议而实现。嵌入式 linux 的 tftp 开发环境包括两个方面:
一是 linux 开发主机端的 tftp-server 支持,
二是嵌入式目标系统的 tftp-client 支持。

目标机安装

拨码开关:0111 —板子由FLASH启动
1000 —板子由SD启动

{//===============================开发环境搭建===================================
约定: “$”表示是在主机上执行,“#”表示在目标板执行 	

{//探讨
JACK: Hi,ivan, 嵌入式开发环境如何搭建啊,完全不知道如何下手啊?
IVAN:	
		网络搜索 /* 注: 如何搜索关键字,快速找到需要信息。是项目开发中重要的一种能力。 如下
			        “ubuntu 嵌入式 开发环境 搭建 ” 
			        	注意关键字要简明,且用空格隔开,方便搜索引擎查找  
		         */	
	
JACK: TFTP服务不行啊,怎么办?
IVAN:	
		网络搜索  //“ubuntu  tftp服务 安装”或 “嵌入式  tftp服务 安装”或“linux  tftp服务 安装”	


JACK: NFS服务不行啊,怎么办?
IVAN:	
		网络搜索 // “ubuntu  NFS服务 安装”				
	
}
 

{//开发主机安装
	{//虚拟机安装(已有则跳过)
		解压Ubuntu_12.04_64-bit_farsight.7z  /*该镜像是在官方Ubuntu 12.04 LTS 64bit 基础上,安装了编译调试bootloader 内核,android 4.4源码所需的工具和库。 
		  如交叉编译工具,VIM ,TFTP,NFS等
		  */ 
		点VMware-workstation-full-10.0.4-2249910.exe   //按默认方式安装虚拟机
	  安装好后,选择“打开虚拟机”导入已安装好的镜像 Ubuntu_12.04_64-bit_farsight.vmx                  
		点播放虚拟机,选我已移动该虚拟机
		启动后,用户名是linux 密码是1
  }
  
  {//linux和window间共享
  	虚拟机 -> 设置 -> 选项 -> 共享文件夹 -> 添加 -> 选择需要共享的位置(如E盘)
		$ ls /mnt/hgfs/E/  //有共享的内容显示,表示成功	  	
  	$ cd ~
  	$ ln -s /mnt/hgfs/E/ e   //创建软连接, 方便操作
  }	  
	      	   
	{//交叉编译工具安装
	  $ tar  xvf  gcc-4.6.4.tar.xz 
	  $ sudo vim /etc/bash.bashrc /* 添加交叉编译工具链的路径到系统脚本
	    在末尾添加
	  		export PATH=/home/linux/store/gcc-4.6.4/bin:$PATH  
	    注意路径要根据gcc-4.6.4的实际路径修改 		
	    */
	  $ source  /etc/bash.bashrc  //使配置文件生效
	  $ arm-n  然后按Tab键补全 //如果能补全为arm-none-linux-gnueabi- 表示安装交叉编译工具成功了
  } 
   
	{//u-boot编译(用已移植好的)
		$ cp ~/e/fs4412/2系统移植/1实验/2第二天_U-boot移植/u-boot-2013.01-fs4412.tar.xz  .
		$ tar -xvf u-boot-2013.01-fs4412.tar.xz
	  $ cd u-boot-2013.01-fs4412
	  $ ./build.sh //运行该脚本后会自动生成最终的镜像  u-boot-fs4412.bin
	  $ cp u-boot-fs4412.bin   ~/e/USB_fastboot_tool/platform-tools/  //通过后面的fastboot方式可写到板子上
	}	

	{//内核编译(用已移植好的)
		//配置编译关系 	kconfig  -> make menuconfig  -> .config  ->make ->  makefile ->zImage    
		
		$ cp ~/e/fs4412/2系统移植/1实验/3第三天_内核移植/linux-3.14-fs4412.tar.xz .
		$ tar -xvf linux-3.14-fs4412.tar.xz
		$ cd   linux-3.14-fs4412
		$ make uImage  //编译生成适合u-boot bootm启动的内核镜像 uImage
		$ make dtbs  /*编译设备树
			 make meunconfig  //图像界面进行配置(如 指定新的驱动,内核裁剪)
		   make modules     //只编译模块文件(.ko文件)
		   make             //编译所有 	(但不包括uImage生成)
		  */    
		$ cp arch/arm/boot/uImage /tftpboot/
		$ cp arch/arm/boot/dts/exynos4412-fs4412.dtb   /tftpboot/		 
	}	   
  
	{//tftp服务安装
		//----虚拟机上安装tftp服务
		$ sudo dpkg   -s   tftpd-hpa   //检查是否安装tftp server
		$ sudo apt-get  install  tftpd-hpa  //如果未安装,安装 tftp-server
		$ sudo vi  /etc/default/tftpd-hpa  //修改tftp服务器配置文件为
				TFTP_USERNAME="tftp"
				TFTP_DIRECTORY="/tftpboot"
				TFTP_ADDRESS="0.0.0.0:69"
				TFTP_OPTIONS="-c  -s  -l"
		$ mkdir  /tftpboot   //创建tftpboot目录,
		$ sudo chmod  a+w  /tftpboot
		$ sudo service   tftpd-hpa   restart	  //启动 tftp-server	
		  	         
	  //-----验证虚拟机tftp服务是否OK
		$ sudo cat /etc/default/tftpd-hpa 	
			TFTP_USERNAME="tftp"
			TFTP_DIRECTORY="/tftpboot"
			TFTP_ADDRESS="0.0.0.0:69"
			TFTP_OPTIONS="-l -c -s"
	  $ sudo service   tftpd-hpa   restart	  //如果有更改配置,需要重启一下 tftp-server	
		$ cd /tftpboot
		$ touch test
		$ cd /tmp
		$ tftp 127.0.0.1    
		 tftp>get test  
		 tftp>q
		$ ls           //看到有test文件,表示该tftp服务是OK的  	
					        	  
		//---准备待传输文件
	  拷贝  第一天_环境搭建里面里的 u-boot-fs4412.bin  uImage exynos4412-fs4412.dtb  到  /tftpboot 目录下
  }	  
  
	{//nfs服务安装
		$ service nfs-kernel-server  /*检查nfs服务是否安装
		  如果显示下面信息, 表示有安装
		    * Usage: nfs-kernel-server {start|stop|status|reload|force-reload|restart}  
		  如果没有,需安装
		     #sudo apt-get install nfs-kernel-server 
		  */		
		  
    $ sudo vi /etc/exports  /*修改配置文件,指定共享目录位置 
     在末尾追加
       /nfs/rootfs *(rw,sync,no_root_squash)     
   		 或 /source/  *(rw,sync,no_subtree_check)   
		   */ 
	  $ sudo mkdir /nfs
	  $ sudo chmod 777 /nfs
	  $ cd /nfs
	  $ 拷贝 1第一天_环境搭建 下的 rootfs.tar.xz 到 /nfs 目录下   //rootfs.tar.xz是已制作好的根文件系统
	  $ tar -xvf  rootfs.tar.xz 
	  $ sudo chmod 777 rootfs	  
	  $ sudo /etc/init.d/nfs-kernel-server restart  //重启nfs服务(使得前面修改生效)	   
	  $ sudo mount -t nfs localhost:/nfs/rootfs/  /mnt/  //测试nfs服务是否安装成功。
	  $ ls /mnt/  /*如果其中的内容和/nfs/rootfs中一致。 表示有挂载成功 
	   如显示下面内容,表示成功
	      bin  dev  etc  lib  linuxrc  mnt  proc  root  sbin  sys  tmp  usr  var
	  	*/
	  $ sudo umount /mnt
	  
  }
  
}	 
 
{//目标机安装(u-boot烧写调试)  --  需要SD卡
	{//制作SD卡,并从SD卡启动   (使用的是2010版本u-boot,支持fastboot烧写的)  
		 将sdfuse_q  拷贝到Linux下
	   将SD卡插入电脑并识别
	   进入sdfuse_q执行如下操作
		 $ sudo ./mkuboot.sh /dev/sdb  /*出现下面的信息,表示SD启动盘制作成功
					 Fuse FS4412 trustzone uboot file into SD card
				/dev/sdb reader is identified.
				u-boot-fs4412.bin fusing...
				1029+1 records in
				1029+1 records out
				527104 bytes (527 kB) copied, 5.31834 s, 99.1 kB/s
				u-boot-fs4412.bin image has been fused successfully.
				Eject SD card
		    */
		
		关闭开发板电源,将拨码开关SW1调至(1000)(SD启动模式)
	  刚才做好的SD启动盘插入SD卡插槽
		打开电源
	}
	
	{//---fastboot烧写 
		连接USB线到板子上的USB OTG口 
		连接串口线到板子的COM2口   
		重启板子,并快速停下,在串口终端输入下面命令 /*
							  如果有有需要,可以格式化 eMMC 并创建分区
							  $ fdisk -c 0
						    $ fatformat mmc 0:1
						    $ ext3format mmc 0:2
						    $ ext3format mmc 0:3
						    $ ext3format mmc 0:4
	    */
	  $ reset    重启切换到2010版的sd卡启动  
	  $ fastboot  //会提示装驱动,选中第一天_环境搭建里的fastboot_driver 安装 	
	  打开dos终端 进入USB_fastboot_tool\platform-tools目录输入
	  > fastboot.exe flash bootloader u-boot-fs4412.bin  /*
	          同理可以烧录其它镜像
				    > fastboot.exe flash kernel zImage
					  > fastboot.exe flash ramdisk ramdisk-uboot.img
				    > fastboot.exe flash system system.img
				    > fastboot -w
	       */
	  
	  关闭开发板电源,将拨码开关SW1调至0110(EMMC启动模式)后打开电源
	  从flash 的u-boot启动  /*
	      如果启动失败,可以通过拨号开关恢复到SD卡方式启动
	      如果启动成功,想恢复到原来的u-boot启动 (第一次输入reset后会自动切换回去,不用拔拨号开关)   
	    */
	} 	
		
}	  
 
{//1. 板子串口能显示信息
   连接串口线到板子的COM2口   //如果是用笔记本电脑的,需装usb转串口驱动(用360驱动大师在线装方便)
   确认拨号开关SW1 为0110 (从EMMC(FLASH的一种) 启动)
    
   {//? 无串口打印信息    
      波特率设置不对, 流控未选为无
      电脑用的可能是COM2
      u-boot被破坏了,切换到SD卡启动(SW1 改为1000}
            
}     

{//2. 板子能ping通虚拟机  (要关闭防火墙 网卡右键高级)
	   ------------------------           
     |板子    192.168.9.9   |
     ------------------------
                |
     ------------------------
     |电脑    192.168.9.222 |    //做中转用,和板子虚拟机IP要在同一网段, 且不能和它们IP一样     
     ------------------------
                |
	   ------------------------
     |虚拟机  192.168.9.120 |
     ------------------------
        
    //---------确认板子和电脑是能通信的
		 设置电脑网卡ip 为192.168.9.222  255.255.255.0 192.168.9.1
		     
		 启动板子,快速按任意键停在boot处,设置u-boot 的环境变量
		# setenv serverip 192.168.9.120    //注意它与虚拟机里 ubuntu 的ip要一致
	  # setenv ipaddr 192.168.9.9
		# setenv gatewayip  192.168.9.1
		# pri  /*查看设置后效果 				
				FS4412 # pri
				baudrate=115200
				bootargs=root=/dev/nfs nfsroot=192.168.9.120:/nfs/rootfs rw console=ttySAC2,115200 clk_ignore_unused init=/linuxrc ip=192.168.9.9
				bootcmd=tftp 41000000 uImage;tftp 42000000 exynos4412-fs4412.dtb;bootm 41000000 - 42000000
				bootdelay=3
				ethact=dm9000
				ethaddr=11:22:33:44:55:66
				gatewayip=192.168.9.1
				ipaddr=192.168.9.9
				netmask=255.255.255.0
				serverip=192.168.9.120
				*/
		# ping 192.168.9.222   //测试网络是否连通  ,注意在u-boot中, 它能ping电脑, 电脑不能ping它  
		                      //注意,要拔掉jtag线,否则ping 会重启  
		       host 192.168.9.222 is alive    //is alive 表示ok    
		# saveenv   保存设置	        
      
           
    //---------确认电脑和虚拟机时能通信
		编辑 -> 虚拟网络编辑器  -> 	 VMnet0 桥接到(选连板子的网卡) //注意不要用automic,应手动指定对应的网卡	                             
		虚拟机 -> 设置 -> 网卡适配器  -> 自定义 (选 VMnet0)    /*使虚拟机内的虚拟网卡,关联到电脑实际用到的网卡       
		   通过选VMnet0 和 VMnet1 。实现连板子,还是上internet的切换
		   */                                     
		点ubuntu右上角网络图标 -> 右键选编辑连接 -> 全删掉 -> 添加(改新连接名称为board) 
		-> IPV4 设置 -> 方法(选手动) -> 点添加 设置为 192.168.9.120 255.255.255.0 192.168.9.1 并保存退出		
		点右上角网络图标,先断开,再选board连接  // 通过选board,和internet 实现连板子,还是上internet的切换
    $ ifconfig //看ip是否已变为了192.168.9.120
    $ ping 192.168.9.222  //测试电脑和虚拟机是否联通 (如不通,可尝试修复一下网卡,重启虚拟机)   
    
    
    //---------确认板子能和虚拟机能通讯
		$ reset  重启boot 
		$ ping 192.168.9.120         //注意: boot阶段是板子能ping 电脑 ,电脑不能ping板子
		    host 192.168.9.120 is alive  //通讯OK  ,失败会显示not alive
        
}        

{//3. 网络自动 tftp 加载内核,并挂载nfs  rootfs 启动
   # setenv bootcmd tftp 41000000 uImage\;tftp 42000000 exynos4412-fs4412.dtb\;bootm 41000000 - 42000000	/* 设置tftp方式加载内核
       setenv bootcmd    设置环境变量(自启动命令 bootcmd)
       tftp 41000000 uImage\;  通过tftp从虚拟机/tftpboot目录下下载内核uImage到板子的内存  41000000 处。    \; 用于分割多个命令
       tftp 420000tft00 exynos4412-fs4412.dtb   通过tftp下载设备树文件 exynos4412-fs4412.dtb 到板子的内存  42000000 处
       bootm 41000000 - 42000000   启动内核(41000000处放的是内核uImage, 42000000处放的是设备树文件)
      */  
  
   # setenv bootargs root=/dev/nfs nfsroot=192.168.9.120:/source/rootfs rw console=ttySAC2,115200 clk_ignore_unused init=/linuxrc ip=192.168.9.9	 /* 挂载nfs  rootfs
 setenv bootargs root=/dev/nfs nfsroot=192.168.137.88:/nfs/rootfs rw console=ttySAC2,115200 clk_ignore_unused init=/linuxrc ip=192.168.137.66
   	  setenv bootarg  设置环境变量( bootarg是启动参数)
   	  root=/dev/nfs  指定根文件系统类型是 nfs
   	  nfsroot=192.168.9.120:/source/rootfs  指定source rootfs的位置 (是在ip 是192.168.9.120的机器上 ,的/source/rootfs目录下). 注意/nfs/rootfs必须和前面NFS服务配置文件设置一致     	   
   	 */
   # savenenv //保存环境变量

   掉电重启动板子  /* 看能否挂载nfs rootfs成功
    能看到下面信息表示成功
      [root@farsight ]# ls
       etc      linuxrc  proc     sbin     tmp      var
       bin      dev      lib      mnt      root     sys      usr
    在里面创建文件,电脑的/nfs/rootfs上同步变化
      */           
}    
    
}	


(三四)、Bootloader移植

bootloader概念

  • Bootloader是硬件启动的引导程序,是运行操作系统的前提;
  • 在操作系统内核或用户应用程序运行之前运行的一小段代码。对软硬件进行相应的初始化和设定,为最终运行操作系统准备好环境;
  • 在嵌入式系统中,整个系统的启动加载任务通常由Bootloader来完成。

bootloader特点

  • Bootloader不属于操作系统,一般采用汇编语言和C语言开发。需要针对特定的硬件平台编写。
  • 在移植系统时,首先为开发板移植Bootloader。
  • Bootloader不但依赖于CPU的体系结构,而且依赖于嵌入式系统板级设备的配置。

bootloader操作模式

  • 自启动模式:在这种模式下,Bootloader从目标机上的某个固态存储设备上将操作系统加载到RAM中运行,整个过程并没有用户的介入。
  • 交互模式:在这种模式下,目标机上的Bootloader将通过串口或网络等通信手段从开发主机(Host)上下载内核映像和根文件系统映像等到RAM中。可以被 Bootloader写到目标机上的固态存储媒质中,或者直接进行系统的引导。也可以通过串口接收用户的命令。

u-boot介绍

u-boot(Universal Boot Loader)是德国DENX小组开发的用于多种嵌入式CPU的bootloader程序。遵循GPL条款。
从FADSROM、8xxROM 、PPCBOOT、Armboot逐步发展演化而来;
当前版本号:参考Makefile。
http://www.denx.de/wiki/U-Boot/WebHome

  • U-boot的特点:
    代码结构清晰、易于移植(见目录结构)
    支持多种处理器体系结构(见arch目录)
    支持众多开发板(目前官方包中有200多种,见board目录)
    命令丰富、有监控功能
    支持网络协议、USB、SD等多种协议和设备
    支持文件系统
    更新较活跃,使用者多,有助于解决问题

u-boot命令

命令分类
环境设置、数据传输、存储器访问、加载运行

  • printenv 显示所有环境变量
    U-boot # printenv
    baudrate=115200
    ipaddr=192.168.1.100
    ethaddr=12:34:56:78:9A:BC
    serverip=192.168.1.10
    ……

  • setenv 设置新的环境变量
    U-boot # setenv myboard FS4412
    U-boot # printenv
    baudrate=115200
    ipaddr=192.168.1.100
    ethaddr=11:22:33:44:55:66
    serverip=192.168.1.10
    myboard=FS4412
    Environment size: 320/16380 bytes

  • saveenv 将当前定义的所有的环境变量值存入flash中

  • tftp 通过网络下载程序
    U-boot # setenv ethaddr 11:22:33:44:55:66
    U-boot # setenv ipaddr 192.168.1.100
    U-boot # setenv serverip 192.168.1.10
    U-boot # tftp 41000000 application.bin
    U-boot # tftp 41000000 zImage

  • protect 对Nor Flash写保护
    protect on 0 10000 对区间[0x0, 0x10000]进行写保护
    protect off 0 10000 对上述区间取消写保护

  • erase 擦除Nor FLASH
    erase all 擦除FLASH所有的扇区
    erase 0 10000 把FLASH区间 [0x0, 0x10000]擦除

  • Nand相关命令
    nand read addr off size
    nand write addr off size
    nand erase [clean] [off size]

  • movi 命令
    movi init —初始化eMMC并显示相关信息
    movi read u-boot/kernel addr
    movi write u-boot/kernel addr
    movi read rootfs addr size
    movi write rootfs addr size

  • bootcmd 自启动命令
    如果定义了该变量,在自启动模式下将会执行该环境变量中的命令。
    U-boot # setenv bootcmd tftp 41000000 uImage; bootm 41000000
    U-boot # saveenv

  • go addr 执行内存中的二进制代码,简单的跳转到指定地址
    bootm kernel-addr ramdisk-addr dtb-addr
    引导内核为内核传参,其中内核和ramdisk通常为mkimage处理过的二进制文件。

u-boot配置编译

  • U-boot的编译
    整个工程通过Makefile来组织编译。顶层目录下的Makefile中包含了开发板的配置信息。从顶层目录开始递归地调用各级子目录下的Makefile,最后链接成u-boot映像。
  • 顶层目录下的 Makefile
    它负责u-boot整体配置和编译
    在Makefile中指定使用的交叉工具链
    配置u-boot: make origen_config
    编译: make
    U-BOOT编译生成的映像文件
    嵌入式系统移植掌握_第7张图片

U-boot镜像下载烧录

  • 烧录编译产生的镜像 u-boot.bin
    初次或开发板代码损坏不能正常启动时,可采用JTAG工具烧录
  • 专用的烧录工具如h-jtag或DNW等
    在u-boot已经能工作,升级或修正U-boot时,可用U-boot中的命令来烧录
    其它方式 如SD卡 , Fastboot命令
  • 镜像固化位置
    ROM、NOR FLASH、NAND FLASH EMMC等

U-boot启动流程

uboot是板子上电后第一个程序,初始化一些硬件,做准备工作,接着引导加载内核
嵌入式系统移植掌握_第8张图片

U-Boot 启动源码分析

  • 第一条指令位置(参考u-boot.map) arch/arm/cpu/armv7/start.S 里的 _start: b reset
  • 设置为SVC模式 msr cpsr,r0
  • 关闭MMU Cache cpu_init_cp15
  • 基本硬件设备初始化 board/samsung/fs4412/lowlevel_init.S 的 lowlevel_init
    关中断 看门狗 ,初始化时钟 串口,flash,内存
  • 自搬移到内存 relocate_code
  • 设置栈, IRQ stack frame
    ===================================================
  • 准备进入C部分 bl _main ( 参u-boot.map )
  • 大部分硬件初始化 arch\arm\lib\board.c\board_init_f 里的init_sequence
  • 搬移内核到内存运行 common/main.c main_loop -> getenv (“bootcmd”)
    bootdelay >= 0 && s && !abortboot (bootdelay))
    下的 run_command (bootcmd)

U-BOOT 移植方法

  • 善用对比软件Beyond
  • 选择官方源码版本下载, 配置编译
    a. 指定交叉编译工具链
    b. 指定cpu 和board(参考最类似配置如origen)
    c. 编译
  • 实现串口信息输出
    a. 跟踪运行路径(led点灯法)
    b. 串口输出(检查uart初始化相关部分代码 见lowlevel_init.s)
  • 网卡移植(实现能用tftp nfs 方便开发调试)
    a. 寄存器地址
    b. 参数设置
  • FLASH移植(实现能下载软件到FLASH,产品能离线运行)

五、Linux内核

Linux内核基本概念

  • 从技术上说 linux 是一个内核
  • “内核”指的是一个提供硬件抽象层、磁盘及文件系统控制、多任务等功能的系统软件。一个内核不是一套完整的操作系统。
  • 通常我们使用的 linux 系统是一个集 linux 内核、工具集、各种库、桌面管理器、应用程序等一体的一个发布包 (发行版)‏

Linux 发行版

Debian GNU/Linux
Red Hat Linux
Fedora Core
Ubuntu Linux
SUSE Linux
Gentoo Linux
Asianux
Slackware Linux
Turbo Linux
CentOS

Linux 内核的特性

  • 免费开源
  • 可以移植,支持的硬件平台广泛
    arm, i386, m68k, m32r,m68knommu, mips, ppc, s390, sh, sparc
  • 高可扩展性
    可剪裁、可扩展,可以运行在大型主机,也可以运行在个人计算机上
  • 高可靠性、稳定性
    稳定性是linux鲜明特点,安装了linux系统的主机,
    连续运行一年不宕机是很平常的事情
  • 超强的网络功能
  • 真正的多任务,多用户系统
  • 模块化设计
    模块可以动态加载,卸载,可以减少系统体积,同时可以用来解决冲突问题,模块调试

linux 内核版本

  • 目前linux系统采用 A.B.C.D 的版本号管理方式
    A 主版本号
    B 次版本号 为偶数表示 稳定版本 奇数为开发中版本
    C 表示linux的发行版本号
    D 表示更新版本号
  • 主版本(X.Y)
    1.0 2.0 2.2 2.4 2.6 3.x

Linux内核模块结构图

嵌入式系统移植掌握_第9张图片
linux 不会是一个真正的实时系统 (时间片轮转方式)
vxwork 是一个真正的实时(RTOS )系统 收费

linux 分层
	
	 应用程序
		||
		\/
	 系统调用
		||
		\/
	 linux 内核  分为 平台无关吗 和 平台相关码
		||
		\/
	 硬件平台

编译内核(已移植好的)

linux 内核 下载地址 https://www.kernel.org/
linux 各个版本下载地址 https://www.kernel.org/pub/linux/kernel/

  • 编译内核 make uImage
  • 编译设备树 make dtbs
    上面两个命令都需要在 源码的顶层目录上 使用 ☆☆☆

嵌入式系统启动信息分析

  • u-boot启动阶段
    U-Boot 2013.01 (Aug 24 2014 - 12:01:19) for FS4412
    CPU: Exynos4412@1000MHz
    Board: FS4412
    DRAM: 1 GiB
    ……Loading: *######################
    Starting kernel …
  • linux内核启动阶段
    Booting Linux on physical CPU 0xa00
    Linux version 3.14.0 (david@ubuntu)
    CPU: ARMv7 Processor [413fc090] revision 0 (ARMv7), cr=10c5387d
    Machine model: Insignal Origen evaluation board based on Exynos4412
    IP-Config: Complete:
    VFS: Mounted root (nfs filesystem) on device 0:10
  • 根文件系统阶段(可运行应用程序)
    [root@farsight ]# ls
    a.out dev lib mnt root sys usr
    bin etc linuxrc proc sbin tmp va

嵌入式系统 启动流程

嵌入式系统移植掌握_第10张图片

  • bootloader启动步骤
    //阶段一(汇编)
    设置为SVC模式,关闭中断,MMU,看门狗
    基本硬件设备初始化 //初始化时钟,串口,flash,内存
    自搬移到内存
    设置好栈 跳转到C阶段
    //阶段二(C语言)
    大部分硬件初始化
    搬移内核到 内存
    运行内核

    内核启动流程

a. 自解压内核 decompess (arch/arm/boot/compressed/head.S)

b. 运行内核汇编部分 head.S 入口stext (arch/arm/kernel/head.S)
检测合法性(CPU 类型,机器类型)

c. 运行内核C部分 start_kernel (init/main.c)
CPU,机器参数的安装 setup_arch
中断,定时,终端,内存等最基本的初始化
创建核心进程 kernel_init运行,启动多任务调度
d. 挂载rootfs
e. 运行第一个应用程序init (一般是 linuxrc)
嵌入式系统移植掌握_第11张图片

Linux内核调试方法

  • 内核调试方法 点灯法
    ldr r0, =0x11000c40 @GPK2_7 led2
    ldr r1, [r0]
    bic r1, r1, #0xf0000000
    orr r1, r1, #0x10000000
    str r1, [r0]
    ldr r0, =0x11000c44
    mov r1,#0xff
    str r1, [r0]

  • printk打印输出信息
    puts (内核解压前)
    printascii (console初始化前)
    printk (内核解压后,信息输出显示是在 console 初始化之后)

    通过proc在运行时查看和修改日志级别
    cat /proc/sys/kernel/printk 显示 4 4 1 7
    echo “7 4 1 7” > /proc/sys/kernel/printk 后
    cat /proc/sys/kernel/printk 显示7 4 1 7

  • printk打印输出信息
    打印级别:
    #define KERN_EMERG “<0>” /* system is unusable /
    #define KERN_ALERT "<1>” /
    action must be taken immediately /
    #define KERN_CRIT “<2>” /
    critical conditions /
    #define KERN_ERR “<3>” /
    error conditions /
    #define KERN_WARNING “<4>” /
    warning conditions /
    #define KERN_NOTICE “<5>” /
    normal but significant condition /
    #define KERN_INFO “<6>” /
    informational /
    #define KERN_DEBUG “<7>” /
    debug-level messages

printk( KERN_INFO “ \n INFO Level \n”);

  • OOP内核异常信息
  1. 制造错误
    修改drivers/char/fs4412_led_drv.c
    在s5pv210_led_init函数中int ret=0;下增加下面语句: int *ptr = NULL; *ptr = 0xff;

  2. 运行该内核报错
    [ 1.165000] Unable to handle kernel NULL pointer dereference at virtual address 00000000
    [ 1.170000] pgd = c0004000
    [ 1.175000] [00000000] *pgd=00000000
    [ 1.175000] Internal error: Oops: 805 [#1] PREEMPT SMP ARM
    [ 1.180000] Modules linked in:
    [ 1.185000] CPU: 0 PID: 1 Comm: swapper/0 Not tainted 3.14.0 #25
    [ 1.190000] task: ee8a0000 ti: ee8a4000 task.ti: ee8a4000
    [ 1.195000] PC is at s5pv210_led_init+0x18/0x180
    [ 1.200000] LR is at do_one_initcall+0x30/0x144
    [ 1.205000] pc : [] lr : [] psr: 60000153
    [ 1.205000] sp : ee8a5ef8 ip : c059afac fp : 00000000
    [ 1.215000] r10: c052d4fc r9 : c0564b80 r8 : c0242244
    [ 1.220000] r7 : c05a3400 r6 : c055134c r5 : 00000000 r4 : ee8a4000
    [ 1.230000] r3 : 00000055 r2 : c04c0430 r1 : 00000001 r0 : 1f400000
    [ 1.235000] Flags: nZCv IRQs on FIQs off Mode SVC_32 ISA ARM Segment kernel
    [ 1.245000] Control: 10c5387d Table: 4000404a DAC: 00000015
    [ 1.250000] Process swapper/0 (pid: 1, stack limit = 0xee8a4240)
    [ 1.255000] Stack: (0xee8a5ef8 to 0xee8a6000)

  3. 找出错位置
    根据PC is at s5pv210_led_init+0x18/0x180 知道出错的函数是s5pv210_led_init
    根据pc : [] 知道出错的位置
    #arm-none-linux-gnueabi-addr2line c024225c -e vmlinux -f 在源码中会显示具体出错的位置

六、Linux内核移植与网卡移植

Linux内核移植

Linux内核配置编译
  • 下载内核源码 (谷歌搜索 linux-3.14.tar.xz ,会很快找到有许多内核版本的列表)

  • Linux系统中解压 ( tar -xvf linux-3.14.tar.xz 注意不能在与window的共享目录解压)

  • 修改Makefile指定交叉编译工具链

  • 导入配置 make exynos_defconfig(配置列表见 arch/arm/configs/ 找最类似的)

  • 配置内核 make menuconfig

  • 编译内核 make uImage

  • 编译设备树 make dtbs

网卡移植

网卡移植 平台无关
  • 配置内核支持网络
    $ make menuconfig
  • 配置网络协议支持TCP/IP
    [] Networking support —> //注意要先输入y 选择该菜单,再按enter键,才能看到下面的选项
    Networking options —>
    <
    > Packet socket
    <> Unix domain sockets
    [
    ] TCP/IP networking
    [*] IP: kernel level autoconfiguration
  • 配置支持网络文件系统 NFS
    File systems —> [] Network File Systems —>
    <
    > NFS client support
    <> NFS client support for NFS version 2
    [
    ] NFS client support for NFS version 3
    [] NFS client support for the NFSv3
    ACL protocol extension
    [
    ] Root file system on NFS
  • 配置支持dm9000网卡驱动
    Device Drivers —>
    [] Network device support —>
    [
    ] Ethernet driver support —>
    <*> DM9000 support
网卡移植 平台相关
  • 配置设备树描述网卡和CPU的链接情况
    $ vim arch/arm/boot/dts/exynos4412-fs4412.dts 在 regulators 前添加下面代码
    srom-cs1@5000000 {
    compatible = “simple-bus”;
    #address-cells = <1>;
    #size-cells = <1>;
    reg = <0x5000000 0x1000000>; 对应芯片手册 3 Memory Map 的0x0500_0000 和 16 MB ranges;
    ethernet@5000000 {
    compatible = “davicom,dm9000”; 内核通过该名字来匹配驱动
    reg = <0x5000000 0x2 0x5000004 0x2>; 寄存器地址和数据宽度
    interrupt-parent = <&gpx0>; 继承于 中断控制器gpx0
    interrupts = <6 4>; 6 对应中断源 DM9000_IRQ -> XEINT6 。4对应 active high level-sensitive davicom,no-eeprom;
    mac-address = [00 0a 2d a6 55 a2];
    };
    };
  • 修改文件driver/clk/clk.c static bool clk_ignore_unused;改为static bool clk_ignore_unused = true;
CPU与设备连接描述 - 设备树DeviceTree
  • Device Tree是描述硬件信息的数据结构
    用于管理 硬件拓扑和硬件资源信息。
    Device Tree由一系列被命名的结点(node)和属性(property)组成,而结点本身可包含子结点。
    所谓属性,其实就是成对出现的name和value。

  • 帮助
    百度:linux Device Tree 详解
    官网:http://www.devicetree.org 和 http://elinux.org/Device_Tree
    源码实例:
    说明: Documentation/devicetree/bindings/arm
    源码: arch/arm/boot/dts/exynos4412-origen.dts
    在内核里有一个结构“struct machine_desc”,内核用这个结构表示一个实际存在的板子,而针对每个板子都会有一个文件定义这个结构体,这个文件叫平台代码;
    如:arch/arm/mach-s5pv21/mach-smdkv210.c(新版本内核中没有基于Exynos4412的平台代码,这里以s5pv210为例)
    MACHINE_START(SMDKV210, “SMDKV210”)
    /* Maintainer: Kukjin Kim [email protected] */
    .atag_offset = 0x100,
    .init_irq = s5pv210_init_irq,
    .map_io = smdkv210_map_io,
    .init_machine = smdkv210_machine_init,
    .init_time = samsung_timer_init,
    .restart = s5pv210_restart,
    .reserve = &smdkv210_reserve,
    MACHINE_END

七、第三方驱动移植

1.第三方驱动 黑盒移植

  • 编译驱动进内核
    a. 选择驱动存放目录 (或任意目录)
    b. 改Makefile
    c. 改Kconfig (界面可配置)

  • 编译驱动为独立的模块
    a. 配置为模块方式
    b. make modules 编译为模块
    c. 创建设备节点(应用访问驱动的入口)
    d. 运行测试驱动的应用程序

2.第三方驱动 白盒移植

  • 打印跟踪
  • 驱动框架
    嵌入式系统移植掌握_第12张图片
    嵌入式系统移植掌握_第13张图片

八、根文件系统制作

1.根文件系统概念

  • 根文件系统(root filesystem)是存放运行、维护系统所必须的各种工具软件、库文件、脚本、配置文件和其他特殊文件的地方,也可以安装各种软件包。
    嵌入式系统移植掌握_第14张图片
  • 程序文件目录
    /bin: 普通用户和root用户都能执行的基本程序
    ping, mknod, mount, tar, grep, gzip, etc
    /sbin: root用户能执行的基本程序
    int, insmod, route, mkfs, rmmod, ifconfig
    /usr/bin: 更多非必须的用户程序
    autorun, bibtex, latex, biff, ftp, wc, whereis, whoami
    /usr/sbin: 更多非必须的root工具程序
    automount, httpd, in.telnetd, in.talkd, sendmail
  • 配置基本的linux命令(嵌入式linux通过busybox制作)
    cat, chmod, chown, cp, chroot, copi, date, dd, df, dmesg, dos2unix, du, echo, env, expr, find, grep, gunzip, gzip, halt, id, ifconfig, init, insmod等等
  • 配置用户自己的应用
    桌面管理器等等
  • 库文件的放置
    /lib: 系统和运行基本命令时需要的动态库文件
    /usr/lib:所有的其他库
    /usr/lib/xxx: 一些工具包的私有库
    如:/usr/lib/perl5
  • linux设备文件
    Linux 系统中所有的对象(包括设备)都是以文件的形式体现的
    Linux系统中,所有的设备文件(如:设备节点),通常放到 /dev下
    嵌入式系统中只需要创建必须的设备节点即可
  • 设备的主设备号次设备号
    Linux系统是通过主设备号和次设备号来区分设备的
    主设备号: (major)
    内核用来区分哪类设备
    次设备号: (minor)
    区分某类设备中的哪个设备
    内核中的相关文档 Documentation/devices.txt
  • 创建设备节点
    设备文件不能在加载驱动程序时自动创建,要通过指令创建
    创建设备文件的一般语法:
    $ mknod /dev/ [c|b]
    例如:
    $ mknod /dev/ttySAC0 c 4 64
    $ mknod /dev/hda1 b 3 1
    嵌入式系统移植掌握_第15张图片

2.Linux系统的引导过程

嵌入式系统移植掌握_第16张图片

3.BusyBox项目构建系统命令与文件系统制作

(1)BusyBox项目构建系统命令
  • BusyBox 项目是由Bruce Perens in 在1996创建的
    http://www.busybox.net/
    BusyBox 是在 GNU GPL 许可协议下发行的开源软件
  • 享有“嵌入式Linux的瑞士军刀”美誉,Erik Andersen先生维护;
  • Busybox是一个UNIX系统工具集,它将很多普通的UNIX工具集成到一个很小的可执行文件中,为普通用户提供大多数常用的命令;
  • BusyBox常用于制作linux命令 主要指令包括
    cat, chmod, chown, cp, chroot, copi, date, dd, df, dmesg, dos2unix, du, echo, env, expr, find, grep, gunzip, gzip, halt, id, ifconfig, init, insmod, etc
(2)制作根文件系统的内容
  • 制作根文件系统的内容
    采用Busybox创建基本命令
    创建基本的目录 /lib /etc /var /tmp /dev /sys /proc等
    添加glibc基本动态库
    创建基本的设备节点
    添加启动配置和脚本程序 /etc/inittab /etc/fstab /etc/init.d/rcS
  • 测试rootfs内容正确性
  • 制作需要的rootfs类型的格式
    制作根文件系统的内容
$ tar  xvf  busybox-1.22.1.tar.bz2
$ cd  busybox-1.22.1
$ make menuconfig
    Busybox Settings ---> 
	Build Options --->
		[*] Build BusyBox as a static binary (no shared libs)
		(arm-none-linux-gnueabi-) Cross Compiler prefix   注意 一定要指定交叉编译工具
$ make
$ file busybox   确认编译生成的是 ARM 平台的(显示为ELF 32-bit LSB executable, ARM)
$ make  install   安装(默认安装路径为_install)
$ cd _install
$  ls
      bin  linuxrc  sbin  usr
$ mkdir  dev  etc  mnt  proc  var  tmp  sys  root       创建需要的目录
$ cp  ~/store/gcc-4.6.4/arm-arm1176jzfssf-linux-gnueabi/lib/  .  -a      注意是lib/ 
$ du -mh lib     查看lib库的大小
$ rm  lib/*.a     裁剪,删除掉静态库文件  
$ arm-none-linux-gnueabi-strip  lib   裁剪掉调试信息   not recognized  有些库是不能strip的 忽略掉
$ sudo rm  lib/libstdc++*   删除不需要的库,确保所有库大小不超过4M  
$ du -mh lib    查看lib库的大小  可能 显示3.4M lib   (这里确保小于 8M) 	
$ cp /nfs/rootfs/etc   -rf   .      拷入成熟的参考配置 
$sudo mknod   dev/console  c  5  1      必须要有  console设备节点
(3)测试rootfs内容正确性
$ cd /nfs
$ mkdir rootfs
$ cp  _install/*   rootfs   –a                        
$ chmod 777 /nfs/rootfs/			         
NFS能挂载成功表示根文件系统 内容基本正确 

嵌入式系统移植掌握_第17张图片

你可能感兴趣的:(驱动移植,根文件系统制作,内核移植,linux,ubuntu,uboot,嵌入式)