Linux操作系统烧录中四步的内容详解

目录

一、首先移植uboot(uboot的一切都是为了启动内核。)

1、uboot是什么?

2、uboot有什么作用?

3、uboot的作用详解

4、uboot的工作方式

二、其次移植Linux内核

1、Linux内核是什么?

2、Linux内核里有什么?

 三、再编译移植设备树文件

1、设备树文件是什么?

2、设备树文件有哪些?

3、设备树源码文件(.dts)语法介绍

4、设备树OF函数

 四、最后移植根文件系统(rootfs)

1、根文件系统是什么?

2、根文件系统为什么这么重要?

3、linux文件系统的常用目录


一、首先移植uboot(uboot的一切都是为了启动内核。)

1、uboot是什么?

uboot 属于bootloader的一种,是用来引导启动内核的,它的最终目的就是,从flash中读出内核,放到内存中,启动内核。所以,UBOOT需要具有读写flash的能力。

2、uboot有什么作用?

1)uboot主要作用是用来启动操作系统内核。体现在uboot最后一句代码就是启动内核。

2)uboot还要负责部署整个计算机系统。体现在uboot最后的传参。

3)uboot中还有操作Flash等板子上硬件的驱动。例如串口要打印,ping网络成功,擦除、烧写flash是否成功等。

4)uboot还得提供一个命令行界面供人来操作。比如:Linux的终端命令行界面。

例如:计算机的Window系统

所有的计算机系统运行时需要的主要核心部件都是3个东西:CPU + 外部存储器(Flash/硬盘) + 内部存储器(DDR SDRAM/SDRAM/SRAM)。而一般的PC机启动过程为:PC上电后先执行BIOS程序(实际上PC的BIOS就是NorFlash),BIOS程序负责初始化DDR内存,负责初始化硬盘,然后从硬盘上将OS镜像读取到DDR中,然后跳转到DDR中去执行OS直到启动(OS启动后BIOS就无用了)。

所以:嵌入式系统和PC机的启动过程几乎没有两样,只是BIOS成了uboot,硬盘成了Flash。

3、uboot的作用详解

自身可开机直接启动

1)一般的SoC都支持多种启动方式,譬如SD卡启动、NorFlash启动、NandFlash启动等•••••uboot要能够开机启动,必须根据具体的SoC的启动设计来设计uboot

2)uboot必须进行和硬件相对应的代码级别的更改和移植,才能够保证可以从相应的启动介质启动。uboot中第一阶段的start.S文件中具体处理了这一块。

能够引导操作系统内核启动并给内核传参

1)uboot的终极目标就是启动内核。

2)linux内核在设计的时候,设计为可以被传参。也就是说我们可以在uboot中事先给linux内核准备一些启动参数放在内存中特定位置然后传给内核,内核启动后会到这个特定位置去取uboot传给他的参数,然后在内核中解析这些参数,这些参数将被用来指导linux内核的启动过程。

能提供系统部署功能

1)uboot必须能够被人借助而完成整个系统(包括uboot、kernel、rootfs等的镜像)在Flash上的烧录下载工作。

2)裸机教程中刷机(ARM裸机第三部分)就是利用uboot中的fastboot功能将各种镜像烧录到iNand中,然后从iNand启动。

能进行soc级和板级硬件管理

1)uboot中实现了一部分硬件的控制能力(uboot中初始化了一部分硬件),因为uboot为了完成一些任务必须让这些硬件工作。譬如uboot要实现刷机必须能驱动iNand,譬如uboot要在刷机时LCD上显示进度条就必须能驱动LCD,譬如uboot能够通过串口提供操作界面就必须驱动串口。譬如uboot要实现网络功能就必须驱动网卡芯片。

2)SoC级(譬如串口)就是SoC内部外设,板级就是SoC外面开发板上面的硬件(譬如网卡、iNand)

uboot的"生命周期"

1)uboot的生命周期就是指:uboot什么时候开始运行,什么时候结束运行。

2)uboot本质上是一个裸机程序(不是操作系统),一旦uboot开始SoC就会单纯运行uboot(意思就是uboot运行的时候别的程序是不可能同时运行的),一旦uboot结束运行则无法再回到uboot(所以uboot启动了内核后uboot自己本身就死了,要想再次看到uboot界面只能重启系统。重启并不是复活了刚才的uboot,重启只是uboot的另一生)

3)uboot的入口和出口。uboot的入口就是开机自动启动,uboot的唯一出口就是启动内核。uboot还可以执行很多别的任务(譬如烧录系统),但是其他任务执行完后都可以回到uboot的命令行继续执行uboot命令,而启动内核命令一旦执行就回不来了。

4、uboot的工作方式

从裸机程序镜像uboot.bin说起

1)uboot的本质就是一个裸机程序,和我们裸机全集中写的那些裸机程序xx.bin并没有本质区别。如果非说要有区别,那就是:我们写的大部分小于16KB,而uboot大于16KB(一般uboot在180k-400k之间)

2)uboot本身是一个开源项目,由若干个.c文件和.h文件组成,配置编译之后会生成一个uboot.bin,这就是uboot这个裸机程序的镜像文件。然后这个镜像文件被合理的烧录到启动介质中拿给SoC去启动。也就是说uboot在没有运行时表现为uboot.bin,一般躺在启动介质中。

3)uboot运行时会被加载到内存中然后一条指令一条指令的拿给CPU去运行。

uboot的命令式shell界面

1)普通的裸机程序运行起来就直接执行了,执行时效果和代码有关。

2)有些程序需要和人进行交互,于是乎程序中就实现了一个shell(shell就是提供人机交互的一个界面,回想ARM裸机全集第十六部分),uboot就实现了一个shell。

注意:shell并不是操作系统,和操作系统一点关系都没有。linux中打开一个终端后就得到了一个shell,可以输入命令回车执行。uboot中的shell工作方式和linux中的终端shell非常像(其实几乎是一样的,只是命令集不一样。譬如linux中可以ls,uboot中ls就不识别)。

掌握uboot使用的2个关键点:命令和环境变量

1)uboot启动后大部分时间和工作都是在shell下完成的(譬如uboot要部署系统要在shell下输命令、要设置环境变量也得在命令行地下,要启动内核也要在命令行底下敲命令)。

2)命令就是uboot的shell中可以识别的各种命令。uboot中有几十个命令,其中有一些常用另一些不常用(我们还可以自己给uboot添加命令),后面会用几节课时间来依次学习uboot中常用命令。

3)uboot的环境变量和操作系统的环境变量工作原理和方式几乎完全相同。uboot在设计时借助了操作系统的设计理念(命令行工作方式借鉴了linux终端命令行,环境变量借鉴了操作系统的环境变量,uboot的驱动管理几乎完全照抄了linux的驱动框架)。

4)环境变量可以被认为是系统的全局变量,环境变量名都是系统内置的(认识就认识,不认识就不认识,这部分是系统自带的默认的环境变量,譬如PATH;但是也有一部分环境变量是自己添加的,自己添加的系统就不认识但是我们自己认识)。系统或者我们自己的程序在运行时可以通过读取环境变量来指导程序的运行。这样设计的好处就是灵活,譬如我们要让一个程序更改运行方法,不用去重新修改程序代码再重新编译运行,而只要修改相应的环境变量就可以了。

5)环境变量就是运行时的配置属性。

二、其次移植Linux内核

1、Linux内核是什么?

linux内核是与计算机中的硬件接口的最低级别的易于更换的软件;内核负责将以“用户模式”运行的所有应用程序连接到物理硬件,并允许进程使用进程间通信从彼此获取信息。

Linux内核拥有超过1300万行代码,是世界上最大的开源项目之一。

2、Linux内核里有什么?

Linux内核主要由 进程管理内存管理设备驱动文件系统网络协议栈 外加一个 系统调用组成。

源码组织结构

 三、再编译移植设备树文件

1、设备树文件是什么?

设备树的本质也是操作寄存器,只不过寄存器的相关信息放在了设备树中,配置寄存器时需要使用OF函数从设备树中读取寄存器数据后再进行配置

Linux 3.x之前是没有设备树的,Linux通过内核源码中arch/arm/mach-xxx和arch/arm/plat-xxx文件夹里的板级描述文件来描述ARM架构中的板级信息。随着ARM硬件种类增多,与板子相关的设备文件也越来越多,导致内核越来越大,而实际上这些硬件板级信息与内核并无相关关系

2011年,Linus发现该问题后,引入了PowerPC等架构已经采用的设备树机制,将板级信息从内核中分离开来,用一个专属的文件格式(.dts文件)来描述。设备树的作用就是描述硬件平台的硬件资源,它可被bootloader传递到内核,内核可以从设备树中获取硬件信息。设备树描述硬件资源时有两个特点:

  •     以树状结构描述硬件资源
  •     可以像头文件那样,一个设备树文件可以引用另一个设备树文件,实现代码重用

2、设备树文件有哪些?

设备树文件有四种,比如:DTS、DTSI、DTB、DTC文件

DTC工具源码在Linux内核的scripts/dtc/Makefile文件中:

hostprogs-y:= dtc
always:= $(hostprogs-y)

dtc-objs:= dtc.o flattree.o fstree.o data.o livetree.o treesource.o srcpos.o checks.o util.o
dtc-objs+= dtc-lexer.lex.o dtc-parser.tab.o
......

由上可见DTC工具依赖于dtc.c, flattree.c, fstree.c等文件,最终编译并链接出DTC这个主机文件。若要编译DTS文件,只需要进入到Linux源码根目录下,然后执行如下命令:

make all   #编译Linux源码中的所有东西,包括zImage、.ko驱动模块以及设备树
make dtbs  #只是编译设备树

基于ARM架构的SOC有很多,一种SOC又可制作出多款板子,每个板子都有对应的DTS文件,那么如何确定编译哪一个DTS文件呢?以I.MX6ULL芯片的板子为例,打开arch/arm/boot/dts/Makefile,有如下内容:

dtb-$(CONFIG_SOC_IMX6UL) += \
    imx6ul-14x14-ddr3-arm2.dtb \
    imx6ul-14x14-ddr3-arm2-emmc.dtb \
    ......
dtb-$(CONFIG_SOC_IMX6ULL) += \
    imx6ull-14x14-ddr3-arm2.dtb \
    imx6ull-14x14-ddr3-arm2-adc.dtb \
    ......

选中I.MX6ULL后(即CONFIG_SOC_IMX6ULL=y),所有使用该SOC的板子对应的.dts文件都会被编译为.dtb。若新做一个板子,只需要新建一个对应的.dts文件,再将对应的.dtb文件名添加到dtb-$(CONFIG_SOC_IMX6ULL)下,这样在编译设备树时就会将对应的.dts编译为二进制的.dtb文件

3、设备树源码文件(.dts)语法介绍

设备树采用树形结构来描述板子上的设备信息,每个设备都是一个节点,叫做设备节点,每个节点都通过一些属性信息来描述节点信息,属性就是键-值对

node-name@unit-address{
    属性1 = ...
    属性2 = ...
    子节点...
}

⏩ 节点名称:node-name用于指定节点名称,应使用字母开头,并能描述设备类别(根节点用斜杠表示)

⏩ 单元地址:@unit-address用于指定单元地址,@为分隔符,后面是实际的单元地址,它的值与节点reg属性的第一个地址一致,若没有reg属性值,则可以省略单元地址

⏩ 节点属性:节点的大括号{ }中包含的内容是节点属性, 一个节点可以包含多个属性信息,设备树最主要的内容就是编写节点的属性。属性包括自定义属性和标准属性

        model属性:用于指定设备的制造商和型号,多个字符串使用“,”分隔开
        compatible属性:由一个或多个字符串组成,是用来查找节点的方法之一
        status属性:用于指示设备的操作状态,通过status可以禁用或启用设备
        reg属性:描述设备资源在其父总线定义的地址空间内的地址,通常用于表示一块寄存器的起始地址和长度
        #address-cells 和 #size-cells:这两个属性同时存在,前者决定了子节点reg属性中地址信息所占用的字长,后者决定了长度信息所占的字长
        ranges属性:是一个地址映射/转换表,由子地址、父地址和地址空间长度这三部分组成
        – child-bus-address:子总线地址空间的物理地址, 由父节点的#address-cells 确定此物理地址所占用的字长
        – parent-bus-address:父总线地址空间的物理地址,同样由父节点的#address-cells 确定此物理地址所占用的字长
        – length:子地址空间的长度,由父节点的#size-cells 确定此地址长度所占用的字长

4、设备树OF函数

内核提供了一系列函数用于从设备节点获取节点中定义的属性,这些函数以of_开头,称为OF函数。在编写设备树版的驱动时,在进行硬件配置方面,就是要用这些OF函数,将寄存器地址等信息从设备树文件中获取出来,然后进行配置

 四、最后移植根文件系统(rootfs)

1、根文件系统是什么?

根文件系统首先是一种文件系统,该文件系统不仅具有普通文件系统的存储数据文件的功能,但是相对于普通的文件系统,它的特殊之处在于,它是内核启动时所挂载(mount)的第一个文件系统,内核代码的映像文件保存在根文件系统中,系统引导启动程序会在根文件系统挂载之后从中把一些初始化脚本(如rcS,inittab)和服务加载到内存中去运行。我们要明白文件系统和内核是完全独立的两个部分。在嵌入式中移植的内核下载到开发板上,是没有办法真正的启动Linux操作系统的,会出现无法加载文件系统的错误。

2、根文件系统为什么这么重要?

根文件系统包含系统启动时所必须的目录和关键性的文件,以及使其他文件系统得以挂载(mount)所必要的文件。例如:

init进程的应用程序必须运行在根文件系统上;
根文件系统提供了根目录“/”;
linux挂载分区时所依赖的信息存放于根文件系统/etc/fstab这个文件中;
shell命令程序必须运行在根文件系统上,譬如ls、cd等命令;
总之:一套linux体系,只有内核本身是不能工作的,必须要rootfs(上的etc目录下的配置文件、/bin /sbin等目录下的shell命令,还有/lib目录下的库文件等···)相配合才能工作。

Linux启动时,第一个必须挂载的是根文件系统;若系统不能从指定设备上挂载根文件系统,则系统会出错而退出启动。成功之后可以自动或手动挂载其他的文件系统。因此,一个系统中可以同时存在不同的文件系统。在 Linux 中将一个文件系统与一个存储设备关联起来的过程称为挂载(mount)。使用 mount 命令将一个文件系统附着到当前文件系统层次结构中(根)。在执行挂装时,要提供文件系统类型、文件系统和一个挂装点。根文件系统被挂载到根目录下“/”上后,在根目录下就有根文件系统的各个目录,文件:/bin /sbin /mnt等,再将其他分区挂接到/mnt目录上,/mnt目录下就有这个分区的各个目录和文件。

根文件系统至少包括以下目录:

/etc/:存储重要的配置文件。
/bin/:存储常用且开机时必须用到的执行文件。
/sbin/:存储着开机过程中所需的系统执行文件。
/lib/:存储/bin/及/sbin/的执行文件所需的链接库,以及Linux的内核模块。
/dev/:存储设备文件。

注:五大目录必须存储在根文件系统上,缺一不可。

3、linux文件系统的常用目录

Linux文件系统中一般有如下几个目录:

/bin目录 
该目录下存放所有用户都可以使用的、基本的命令,这些命令在挂接其它文件系统之前就可以使用,所以/bin目录必须和根文件系统在同一个分区中。 
/bin目录下常用的命令有:cat,chgrp,chmod,cp,ls,sh,kill,mount,umount,mkdir,mknod,test等,我们在利用Busybox制作根文件系统时,在生成的bin目录下,可以看到一些可执行的文件,也就是可用的一些命令。

/sbin 目录 
该目录下存放系统命令,即只有管理员能够使用的命令,系统命令还可以存放在/usr/sbin,/usr/local/sbin目录下,/sbin目录中存放的是基本的系统命令,它们用于启动系统,修复系统等,与/bin目录相似,在挂接其他文件系统之前就可以使用/sbin,所以/sbin目录必须和根文件系统在同一个分区中。 
/sbin目录下常用的命令有:shutdown,reboot,fdisk,fsck等,本地用户自己安装的系统命令放在/usr/local/sbin目录下。

/dev目录 
该目录下存放的是设备文件,设备文件是Linux中特有的文件类型,在Linux系统下,以文件的方式访问各种设备,即通过读写某个设备文件操作某个具体硬件。比如通过”dev/ttySAC0”文件可以操作串口0,通过”/dev/mtdblock1”可以访问MTD设备的第2个分区。

/etc目录 
该目录下存放着各种配置文件,对于PC上的Linux系统,/etc目录下的文件和目录非常多,这些目录文件是可选的,它们依赖于系统中所拥有的应用程序,依赖于这些程序是否需要配置文件。在嵌入式系统中,这些内容可以大为精减。

/lib目录 
该目录下存放共享库和可加载(驱动程序),共享库用于启动系统。运行根文件系统中的可执行程序,比如:/bin /sbin 目录下的程序。

/home目录 
用户目录,它是可选的,对于每个普通用户,在/home目录下都有一个以用户名命名的子目录,里面存放用户相关的配置文件。

/root目录 
根用户的目录,与此对应,普通用户的目录是/home下的某个子目录。

/usr目录 
/usr目录的内容可以存在另一个分区中,在系统启动后再挂接到根文件系统中的/usr目录下。里面存放的是共享、只读的程序和数据,这表明/usr目录下的内容可以在多个主机间共享,这些主要也符合FHS标准的。/usr中的文件应该是只读的,其他主机相关的,可变的文件应该保存在其他目录下,比如/var。/usr目录在嵌入式中可以精减。

/var目录 
与/usr目录相反,/var目录中存放可变的数据,比如spool目录(mail,news),log文件,临时文件。

/proc目录 
这是一个空目录,常作为proc文件系统的挂接点,proc文件系统是个虚拟的文件系统,它没有实际的存储设备,里面的目录,文件都是由内核临时生成的,用来表示系统的运行状态,也可以操作其中的文件控制系统。

/mnt目录 
用于临时挂载某个文件系统的挂接点,通常是空目录,也可以在里面创建一引起空的子目录,比如/mnt/cdram /mnt/hda1 。用来临时挂载光盘、硬盘。

/tmp目录 
用于存放临时文件,通常是空目录,一些需要生成临时文件的程序用到的/tmp目录下,所以/tmp目录必须存在并可以访问。

猜你喜欢

转载自blog.csdn.net/FLM19990626/article/details/128203031