一篇简述 Linux 移植与系统启动

1、Linux系统启动与U-Boot

所谓移植就是把程序代码从一种运行环境转移到另一种运行环境。对于内核移植来说,主要是从一种硬件平台转移到另一种硬件平台上运行。

体系结构级别的移植是指在不同体系结构平台上Linux内核的移植,例如,在ARM、MIPS、PPC等不同体系结构上分别都要对每个体系结构进行特定的移植工作。一个新的体系结构出现就需要进行这个层次上的移植。

SoC级别的移植是指在具体的SoC处理器平台上Linux内核的移植,例如,ARM i.MX6Dual处理器要进行SoC特定的移植工作,主要包括处理器相关的内核修改、集成外设驱动。

主板级别的移植是指在具体的目标主板上Linux内核的移植,例如,在i.MX6DualFS2410目标板上,需要进行主板特定的移植工作,主要包括特定目标板系统启动与主板扩展外设相关的外设驱动等。

基于同一款处理器的不同嵌入式设备并不是所有的外部设备都相同,不同的开发板可以使用不同的SDRAM、Flash、以太网接口芯片等。这就需要根据硬件修改或者开发驱动程序。

一个最基本的Linux操作系统应该包括:引导程序、内核与根文件系统三部分。因此,需要移植一个Linux系统的话,那么需要以下4个步骤:

  • 搭建交叉开发环境;
  • BootLoader的选择和移植;
  • kernel的配置、编译、和移植;
  • 根文件系统的制作。

(1)BootLoader简介

引导加载程序(Boot Loader)就是在操作系统内核运行之前运行的一段小程序。通过这段小程序,我们可以初始化硬件设备、建立内存空间的映射图,从而将系统的软硬件环境带到一个合适的状态,以便为最终调用操作系统内核准备好正确的环境。

如下图所示:

为什么系统移植之前要先移植BootLoader?

BootLoader的任务是引导操作系统,所谓初始化CPU运行环境,引导操作系统。就是启动内核,让内核运行就是把内核加载到内存RAM中去运行。

是谁把CPU运行环境初始化的?

是谁把内核搬到内存中去运行?

SRAM只要系统上电就可以运行,而SDRAM需要软件进行初始化才能运行,那么内存是由谁来初始化的呢?

(2)Bootloader的执行过程

  • 初始化SDRAM;
  • 初始化串口;
  • 检测处理器类型;
  • 设置Linux启动参数;
  • 调用Linux内核映像。

(3)BootLoader的分类

很多人说BootLoader就是U-Boot,这种说法是错误的,确切来说是U-Boot是BootLoader的一种。

如下图所示。
 

可以知道如果使用开发板board/<board_name>,就先执行“make <board_name>_config”命令进行配置,然后执行“make all”, 就可以生成如下3个文件:

  • u-boot.bin:二进制可执行文件,它就是可以直接烧入eMMC中的文件。
  • u-boot: ELF格式的可执行文件。
  • u-boot.srec: 原摩托罗拉格式的可执行文件。

对于imx6dlsabresd开发板,可以根据开发板的型号选择执行“make imx6dlsabresd_defconfig”、“make"进行编译。

编译后生成的u-boot.imx镜像可以烧入SD卡中执行,具体命令如下:

sudo dd if=u-boot.imx of=/dev/sdb bs=512 seek=2

其中sdb代表SD卡在系统中对应的设备。

(4)u-boot配置过程

在配置之前,为了使编译后的u-boot在开发板上运行,首先需要安装交叉编译链。并使用如下命令配置环境变量:

source /opt/fsl-imx-fb/4.14-sumo/environment-setup-cortexa9hf-neon-poky- linux-gnueabi


 

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)

b reset2)reset(arch/arm/cpu/$CPU/start.S)

bl cpu_init_cp15
bl cpu_init_crit
bl _main

3)_main(arch\arm\lib\crt0.S)

board_init_f(common\Board_f.c)
b relocate_code
ldr lr, =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的最终目的是引导内核,在此之前uboot需要完成一系列初始化操作,包括设置时钟、初始化DDR、Flash、串口、网卡等等。

这时uboot有两条路走(1)通过按键,触发uboot进入命令行模式,等待处理命令。

(2)引导内核

   资料直通车:Linux内核源码技术学习路线+视频教程内核源码

学习直通车:Linuxc/c++高级开发【直播公开课】

零声白金VIP体验卡:零声白金VIP体验卡(含基础架构/高性能存储/golang/QT/音视频/Linux内核)

2、Linux系统裁剪与移植

内核编译相关文件主要包括顶层Makefile与子目录下的Makefile、各级目录Kconfig文件。

a--在内核配置之前先使用make mrproper命令清除以前的内核。

b--详细配置 make menuconfig

c--编译

make zImage ---生成内核镜像 /arch/arm/boot/zImage

make dtbs ---生成设备树文件 /arch/arm/boot/dts/imx6dl-sabresd.dtb

make modules ---把配置值选成M的代码编译生成模块文件。(.ko) 放在对应的源码目录下。

可以看出,内核编译主要包括两部分:一部分是内核配置;另一部分是内核编译。如下图所示。

内核的Kconfig分析:

a -- 我们解压内核后需要先修改内核顶层目录下的Makefile,配置好交叉编译工具

b -- 然后导入默认配置(使用make imx_v7_defconfig 或者

cp arch/arm/configs/imx_v7_deconfig .config)

c -- 配置内核

如下图所示。

内核中的哪些文件将被编译?它们是怎样被编译的?它们连接时的顺序如何确定?哪个文件在最前面?哪些文件或函数先执行?这些都是通过Makefile来管理的。

从最简单的角度来总结Makefile的作用,有以下3点:

1)-- 决定编译哪些文件?

2)-- 怎样编译这些文件?

3)-- 怎样连接这些文件,最重要的是它们的顺序如何?
 

1)顶层Makefile 决定内核根目录下哪些子目录将被编进内核;

2)arch/$(ARCH)/Makefile 决定arch/$(ARCH)目录下哪些文件、哪些目录将被编进内核;

3)各级子目录下的Makefile决定所在目录下哪些文件将被编进内核,哪些文件将被编程模块(即驱动程序),进入哪些子目录继续调用它们的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平台进入系统内核初始化后的入口函数,它主要完成剩余的与硬件平台相关的初始化工作,在进行一系列与内核相关的初始化后,调用第一个用户进程-init进程并等待用户进程的执行,这样整个Linux内核便启动完毕。
 

BusyBox初始化阶段:

除了基本的命令之外,BusyBox还支持init功能,如同其它的init一样,busybox的init也是完成系统的初始化工作,关机前的工作等等。

BusyBox的init进程会依次进行以下工作:

  • 为init设置信号处理过程;
  • 初始化控制台;
  • 分析 inittab文件,/etc/inittab;
  • 执行系统初始化脚本,缺省情况下会使用/etc/init.d/rcS;
  • 执行所有导致init暂停的inittab命令(动作类型:wait);
  • 执行所有仅执行一次的inittab(动作类型:once)。

3、Linux根文件系统移植

(1)文件系统与根文件系统

根,可以理解为基础的意思。根文件系统是一种最基础的文件系统。

Linux系统也可以将磁盘或Flash等存储设备划分为若干个分区,在不同的分区存放不同类型的文件,在某个分区存放u-boot的可执行文件;在某个分区存放内核映像文件,在另一分区存放根文件系统映像文件等。

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进程。执行过程大概如下图所示。

原文作者:面包板社区

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/128047.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

前端项目导入vue和element

1.安装nodejs 下载链接https://cdn.npmmirror.com/binaries/node/v18.18.0/node-v18.18.0-x64.msi 进入cmd 命令行模式 管理员身份运行 输入 &#xff08;node -v&#xff09;能看到版本号 npm config set prefix "C:\Program Files\nodejs" 默认路径 npm config…

补偿 IIR 滤波器引入的延迟

补偿 IIR 滤波器引入的延迟 对信号进行滤波会引入延迟。这意味着相对于输入&#xff0c;输出信号在时间上有所偏移。 无限冲激响应滤波器对某些频率分量的延迟可能比其他频率分量更长。它们会使输入信号呈现明显失真。函数 filtfilt 可补偿此类滤波器引入的延迟&#xff0c;从…

asp.net校园招聘管理系统VS开发sqlserver数据库web结构c#编程Microsoft Visual Studio

一、源码特点 asp.net 校园招聘管理系统是一套完善的web设计管理系统&#xff0c;系统具有完整的源代码和数据库&#xff0c;系统主要采用B/S模式开发。开发环境为vs2010&#xff0c;数据库为sqlserver2008&#xff0c;使用c#语言开发 应用技术&#xff1a;asp.net c#s…

PHP编写采集药品官方数据的程序

在 PHP 中编写爬虫程序&#xff0c;首先我们需要引入一些必要的库&#xff0c;如 curl 和 file_get_contents。然后&#xff0c;我们需要设置爬虫ip信息&#xff0c;以便我们可以从指定的爬虫ip服务器上获取数据。 // 引入必要的库 require_once curl.php;// 设置爬虫ip信息 $p…

【vue+el-upload+vue-cropper】vue图片上传,vue-cropper图片裁剪后上传

一. 先看效果演示 二. 图片上传 用的el-upload加el-image组件 html部分 <el-dialog> ...//无关代码已省略<div v-for"item in imgArr" :key"item.index"><span>{{ item.name }}</span><el-upload action"#" list-t…

客服呼叫中心的语音质检工作

语音质检是呼叫中心运营中必不可缺少的一个环节&#xff0c;呼叫中心语音质检对坐席起着直接监督的作用&#xff0c;也正是这种监督约束推动着客服人员不断提升自身的业务能力。 而客服呼叫中心的质检结果中还蕴藏了大量有价值的信息&#xff0c;可以通过日常的质检工作真正发现…

EtherCAT超高速实时运动控制卡XPCIE1032H上位机C#开发(一):驱动安装与建立连接

XPCIE1032H功能简介 XPCIE1032H是一款基于PCI Express的EtherCAT总线运动控制卡&#xff0c;可选6-64轴运动控制&#xff0c;支持多路高速数字输入输出&#xff0c;可轻松实现多轴同步控制和高速数据传输。 XPCIE1032H集成了强大的运动控制功能&#xff0c;结合MotionRT7运动…

OTA包添加自定义内容

起因 新开一条线&#xff0c;需要上传的OTA包里加点内容&#xff0c;好让后台校验它是否是当前这条线(短期最小改动)。 开整 之前看过ota包结构&#xff0c;整包和差分包里都有一个payload_properties.txt文件&#xff0c;所以最简单的就是给这个txt文件里追加点自定义内容&…

制造企业如何做好进销存管理工作?

本文你将了解&#xff1a;什么是进销存管理系统&#xff1f;国内制造信息化的发展现状如何&#xff1f;进销存管理系统的功能有哪些&#xff1f; 接下来搭建进销存管理系统教学中用到的图片和系统都来自简道云的进销存管理系统 这也是我们公司目前正在用的进销存管理系统&…

el-form-item的label的长度单独改掉,用vue3样式穿透的写法,加上css选择器查找特定的id拿到元素

为了让这个会员卡号这几个字和下面的表格对齐&#xff0c;需要改el-form-item的label的长度 如果直接改el-form的label-width,那么所有的el-form-item的label都会改&#xff0c;我不希望这样 我希望只改第1个会员卡号的label长度 给这个el-form-item添加一个id :deep(.el-for…

vnpy_ctp源码下载后转变为python可用的处理过程

目录 写在前面 下载源码并解压 创建python项目 环境 过程 编译vnpy_ctp源码 验证可用性 写在前面 window系统中必须安装有Visual Studio ,后面源码安装时需要进行C编译 下载源码并解压 GitHub - vnpy/vnpy_ctp: VeighNa框架的CTP交易接口 下载zip压缩包 解压 要在…

Mysql数据备份 —Navicat

一 Navicat 对于表的备份 根据自己的需求来选择 可以直接备份数据表 操作简单明了 二 Navicat 对于库的备份 对于数据库 直接通过转储SQL文件 保存结构和数据 需要新创建数据库 字符集和编码格式要对应 否则容易乱码 运行刚才生成的文件即可

【iOS开发】iOS App的加固保护原理:使用ipaguard混淆加固

​ 摘要 在开发iOS应用时&#xff0c;保护应用程序的安全是非常重要的。本文将介绍一种使用ipaguard混淆加固的方法来保护iOS应用的安全。通过字符串混淆、类名和方法名混淆、程序结构混淆加密以及反调试、反注入等主动保护策略&#xff0c;可以有效地保护应用程序的安全性。 …

案例精选|聚铭综合日志分析系统为中电飞华业务数据安全保驾护航

当下&#xff0c;云和网正从过去的独立走向融合&#xff0c;各行各业从“上网”纷纷演进到“上云”。“上云&#xff0c;才能更好地拥抱数字时代”。云网融合高质量发展对信息基础设施能力提出了新要求&#xff0c;同时运营商在产业数字化领域的业务探索也需要强大的云网能力支…

安科瑞故障电弧探测器在建筑电气的设计与应用

安科瑞 崔丽洁 【摘要】&#xff1a;电气设备是建筑中不可缺少的一部分&#xff0c;具有较为重要的作用和意义&#xff0c;在应用过程中不仅能够提升建筑本身实用性能&#xff0c;而且可为消费者提供更加优良的生活环境。但设备一旦在运行过程中出现故障&#xff0c;不仅会影响…

ros1 基础学习10 -全局字典参数的定义,获取,改值

全局字典参数的定义&#xff0c;获取&#xff0c;改值 一、参数模型二、 创建功能包三、参数命令行的使用(rosparam)四、使用程序来使用参数&#xff08;C&#xff09;4.1创建代码4.2编译4.3 编译文件 测试 在ROS Master中&#xff0c;存在一个参数服务器&#xff08;Parameter…

数学函数3D可视化工具来了

前面已经跟大家分享了两个数学可视化工具&#xff0c;manim和geogebra。 按理讲不应该再重复推荐类似的工具了&#xff0c;感觉犯了软件开发常说的忌讳&#xff1a;重复造轮子。 有的人也会抱怨手里的工具多了都不知道用哪一个了。 但遇到好用的工具又忍不住分享出来&#x…

04-SpringBoot的基础配置及其配置文件分类,解决Yaml文件失效问题

SpringBoot的配置 SpringBoot是用来提高Spring程序的开发效率的,使用SpringBoot后几乎不用做任何配置功能就有了,因为很多功能已经有默认配置帮我们做好了 配置文件的相关配置 在一个项目中不同的技术对应不同的配置文件并且这些配置文件的格式也不统一 SpringBoot提供了一…

Linux之IPC通信共享内存(一次拷贝)与消息队列、管道、信号量、socket(两次拷贝)总结(六十二)

简介&#xff1a; CSDN博客专家&#xff0c;专注Android/Linux系统&#xff0c;分享多mic语音方案、音视频、编解码等技术&#xff0c;与大家一起成长&#xff01; 优质专栏&#xff1a;Audio工程师进阶系列【原创干货持续更新中……】&#x1f680; 人生格言&#xff1a; 人生…

工业废水处理设备公司如何挑选

在选择工业废水处理设备公司时&#xff0c;需要从以下几个方面进行考虑&#xff1a; 公司实力和资质&#xff1a;选择具有相关资质和经验的废水处理设备公司&#xff0c;能够提供高质量的设备和服务。可以通过查询公司的官方网站、客户评价等信息来了解公司的实力和资质。设备…