所谓移植就是把程序代码从一种运行环境转移到另一种运行环境。对于内核移植来说,主要是从一种硬件平台转移到另一种硬件平台上运行。
体系结构级别的移植是指在不同体系结构平台上Linux内核的移植,比如,在ARM、MIPS、PPC等不同体系结构上分别都要对每位体系结构进行特定的移植工作。一个新的体系结构出现就须要进行这个层次上的移植。
SoC级别的移植是指在具体的SoC处理器平台上Linux内核的移植,比如,ARMi.MX6Dual处理器要进行SoC特定的移植工作,主要包括处理器相关的内核更改、集成外设驱动。
显卡级别的移植是指在具体的目标显卡上Linux内核的移植,比如,在i.MX6DualFS2410目标板上,须要进行显卡特定的移植工作,主要包括特定目标板系统启动与显卡扩充外设相关的外设驱动等。
基于同一款处理器的不同嵌入式设备并不是所有的外部设备都相同,不同的开发板可以使用不同的SDRAM、Flash、以太网插口芯片等。这就须要依照硬件更改或则开发驱动程序。
一个最基本的Linux操作系统应当包括:引导程序、内核与根文件系统三部份。为此,须要移植一个Linux系统的话,这么须要以下4个步骤:
(1)BootLoader简介
引导加载程序(BootLoader)就是在操作系统内核运行之前运行的一段小程序。通过这段小程序,我们可以初始化硬件设备、建立显存空间的映射图,因而将系统的软硬件环境带到一个合适的状态,便于为最终调用操作系统内核打算好正确的环境。
如右图所示:
为何系统移植之前要先移植BootLoader?
BootLoader的任务是引导操作系统,所谓初始化CPU运行环境,引导操作系统。就是启动内核,让内核运行就是把内核加载到显存RAM中去运行。
是谁把CPU运行环境初始化的?
是谁把内核迁往显存中去运行?
SRAM只要系统上电就可以运行,而SDRAM须要软件进行初始化能够运行,这么显存是由谁来初始化的呢?
(2)Bootloader的执行过程
uboot启动流程详尽剖析
(3)BootLoader的分类
好多人说BootLoader就是U-Boot,这些说法是错误的,准确来说是U-Boot是BootLoader的一种。u-boot和bootloader究竟有哪些区别。
如右图所示。
可以晓得假如使用开发板board/,就先执行“make_config”命令进行配置,之后执行“makeall”,就可以生成如下3个文件:
对于imx6dlsabresd开发板,可以按照开发板的机型选择执行“makeimx6dlsabresd_defconfig”、“make"进行编译。
编译后生成的u-boot.imx镜像可以烧入SD卡中执行,具体命令如下:
其中sdb代表SD卡在系统中对应的设备。
(4)u-boot配置过程
在配置之前,为了使编译后的u-boot在开发板上运行,首先须要安装交叉编译链。并使用如下命令配置环境变量:
u-boot启动流程剖析如下
第一阶段:(标明下每位步骤的作用)
a--设置cpu工作模式为SVC模式。须要SVC权限对CPU的状态寄存器进行操作b--关掉中断,mmu,,cache。须要直接化学地址访问v--关看门狗d--初始化显存,并口。用于初始化基本的储存空间与通讯插口,用于启动信息交互e--设置栈。用于系统启动临时数据交换和初始化栈表针f--代码自搬动。用于拷贝系统启动代码g--清bss
h--跳c
第二阶段:
a--初始化外设,步入超循环
b--超循环处理用户命令
函数前期执行流程如下:
1)_start(arch/arm/lib/vector.S)
breset2)reset(arch/arm/cpu/$CPU/start.S)
blcpu_init_cp15
blcpu_init_crit
bl_main
3)_main(archarmlibcrt0.S)
board_init_f(commonBoard_f.c)
brelocate_code
ldrlr,=board_init_r(common/Board_r.c)
4)main_loop()
5)启动内核:
main_loop->autoboot_command->run_command_list->cli_simple_run_command_list->cli_simple_run_command->cmd_process->find_cmd/cmd_call(result=(cmdtp->cmd)(cmdtp,flag,argc,argv))
uboot的最终目的是引导内核linux 软件,在此之前uboot须要完成一系列初始化操作,包括设置时钟、初始化DDR、Flash、串口、网卡等等。
这时uboot有两条路走(1)通过键盘,触发uboot步入命令行模式,等待处理命令。
(2)引导内核
【文章福利】小编推荐自己的Linux内核技术交流群:【749907784】整理了一些个人认为比较好的学习书籍、视频资料共享在群文件上面,有须要的可以自行添加哦!!!(含视频教程、电子书、实战项目及代码)
零声白金VIP体验卡(含基础构架/高性能储存/golang/QT/音视频/Linux内核)课程:
2、Linux系统剪裁与移植
内核编译相关文件主要包括顶楼Makefile与子目录下的Makefile、各级目录Kconfig文件。
a--在内核配置之前先使用makemrproper命令清乘以前的内核。
b--详尽配置makemenuconfig
c--编译
makezImage---生成内核镜像/arch/arm/boot/zImage
makedtbs---生成设备树文件/arch/arm/boot/dts/imx6dl-sabresd.dtb
makemodules---把配置值选成M的代码编译生成模块文件。(.ko)置于对应的源码目录下。
可以看出,内核编译主要包括两部份:一部份是内核配置;另一部份是内核编译。如右图所示。
内核的Kconfig剖析:
a--我们解压内核后须要先更改内核顶楼目录下的Makefile,配置好交叉编译工具
b--之后导出默认配置(使用makeimx_v7_defconfig或则
cparch/arm/configs/imx_v7_deconfig.config)
c--配置内核
如右图所示。
内核中的什么文件将被编译?它们是如何被编译的?它们联接时的次序怎样确定?那个文件在最上面?什么文件或函数先执行?那些都是通过Makefile来管理的。
从最简单的角度来总结Makefile的作用,有以下3点:
1)--决定编译什么文件?
2)--如何编译那些文件?
3)--怎么联接那些文件,最重要的是它们的次序怎样?
1)顶楼Makefile决定内核根目录下什么子目录将被编进内核;
2)arch/$(ARCH)/Makefile决定arch/$(ARCH)目录下什么文件、哪些目录将被编进内核;
3)各级子目录下的Makefile决定所在目录下什么文件将被编进内核linux内核移植流程,什么文件将被编程模块(即驱动程序),步入什么子目录继续调用它们的Makefile。
与移植U-Boot的过程相像,在移植Linux之前,先了解它的启动过程。
Linux的过程可以分为两部份:构架/开发板相关的引导过程、后续的通用启动过程。对于uImage、zImage,它们首先进行自解压得到vmlinux,之后执行vmlinux开始“正常的”启动流程。
引导阶段一般使用汇编语言编撰,它首先检测内核是否支持当前构架的处理器,之后检测是否支持当前开发板。
通过检测后,就为调用下一阶段的start_kernel函数作打算了。
这主要分如下两个步骤:
1)联接内核时使用的虚拟地址,所以要设置页表、使能MMU;
2)调用C函数start_kernel之前的常规工作,包括复制数据段、清除BSS段、调用start_kernel函数。
第二阶段的关键代码主要使用C语言编撰。
它进行内核初始化的全部工作,最后调用rest_init函数启动init过程,创建系统第一个进程:init进程。在第二阶段,仍有部份构架/开发板相关的代码,例如重新设置页表、设置系统时钟、初始化并口等。
内核自解压阶段:
Linux内核有两种映像:一种是非压缩内核,叫Image,另一种是它的压缩版本,叫zImage。按照内核映像的不同,Linux内核的启动在开始阶段也有所不同。
zImage是Image经过压缩产生的,所以它的大小比Image小。但为了能使用zImage,必须在它的开头加上解压缩的代码,将zImage解压缩以后才会执行,因而它的执行速率比Image要慢。
但考虑到嵌入式系统的储存空容量通常比较小,采用zImage可以占用较少的储存空间,因而牺牲一点性能上的代价也是值得的。所以通常的嵌入式系统均采用压缩内核的形式。
内核自解压阶段依次完成以下工作:开启MMU和Cache,调用decompress_kernel()解压内核,最后通过调用call_kernel()步入非压缩内核Image的启动。
内核引导阶段:
内核引导阶段是内核启动第一阶段,该部份代码实现在arch/arm/kernel的head.S中,该文件中的汇编代码通过查找处理器内核类型和机器码类型调用相应的初始化函数,再建立页表,最后跳转到start_kernel()函数开始内核的初始化工作。如右图所示:
内核初始化阶段:
Linux内核启动的第二阶段从start_kernel()函数开始。start_kernel()是所有Linux平台步入系统内核初始化后的入口函数,它主要完成剩余的与硬件平台相关的初始化工作,在进行一系列与内核相关的初始化后linux 分区,调用第一个用户进程-init进程并等待用户进程的执行,这样整个Linux内核便启动完毕。
BusyBox初始化阶段:
不仅基本的命令之外,BusyBox还支持init功能,就像其它的init一样,busybox的init也是完成系统的初始化工作,死机前的工作等等。
BusyBox的init进程会依次进行以下工作:
3、Linux根文件系统移植
(1)文件系统与根文件系统
根,可以理解为基础的意思。根文件系统是一种最基础的文件系统。
Linux系统也可以将c盘或Flash等储存设备界定为若干个分区,在不同的分区储存不同类型的文件,在某个分区储存u-boot的可执行文件;在某个分区储存内核映像文件linux内核移植流程,在另一分区储存根文件系统映像文件等。
Linux也须要在一个分区上储存系统启动的必要文件,例如内核启动运行后的第一个程序(init进程)、用于挂接文件系统的脚本、给用户提供操作界面的shell程序,应用程序所要依赖的库等,这种必要的基本文件的集合称为根文件系统(通常也称作rootfs)。
Linux系统启动后首先会挂载这个分区,这称为挂载(mount)根文件系统。其他分区上的所有目录、文件的集合,称为文件系统。
为何须要根文件系统?
1)init进程的应用程序在根文件系统上;
2)根文件系统提供了根目录/;
3)内核启动后的应用层配置(etc目录)在根文件系统上。可以觉得:发行版=内核+rootfs。
4)shell命令程序在根文件系统上。例如ls、cd等命令。
因而,一套Linux体系,只有内核本身是不能工作的,必需要rootfs(上的etc目录下的配置文件、/bin与/sbin等目录下的shell命令,还有/lib目录下的库文件等)相配合能够工作。
(2)根文件系统概述
Linux中的根文件系统更像是一个文件夹或则称作目录(特殊的文件夹),在这个目录上面会有好多的子目录。
根目录下和子目录中会有好多的文件,这种文件是Linux运行所必须的,例如库、常用的软件和命令、设备文件、配置文件等等。
根文件系统和Linux内核是分开的,单独的Linux内核是无法正常工作的,必需要搭配根文件系统。
(3)根文件系统的结构
Linux的根文件系统是采用级层式的树形目录结构,在此结构中的最下层是根目录“/”,之后在此目录下再创建其他的目录。树的根结点为根目录root。
其中:
1)/root系统管理员的主目录2)/bin储存二补码可执行命令的目录3)/boot储存的是启动Linux时使用的一些核心文件,包括一些联接文件以及镜像文件。4)/dev储存设备文件的目录5)/etc储存系统管理和配置文件的目录6)/home用房主目录7)/lib储存动态链接共享库的目录8)/sbin储存系统管理员使用的管理程序的目录9)/mnt系统提供这个目录是让用户临时挂载其他的文件系统10)/proc虚拟文件系统11)/usr最庞大的目录12)/var个别大文件的溢出区13)/tmp公用的临时文件储存点
通常我们在Linux驱动开发的时侯都是通过nfs挂载根文件系统的,当产品最终上市开售的时侯就会将根文件系统烧讲到EMMC或则NAND中。
1)更改Makefile,添加编译器;
2)配置busybox;
3)编译busybox;
4)向根文件系统添加lib库(完成基本根文件系统);
5)创建其他文件夹;
6)建立根文件系统。
Linux系统挂载完根文件系统以后,都会执行init程序,创建init进程。执行过程大约如右图所示。