LV.10 系统移植

D1 嵌入式系统移植导学

Day1-1 系统移植课程导学

嵌入式系统分层

LV.10 系统移植_第1张图片
Linux 功能
进程管理
内存管理
网络协议
文件系统
硬件设备

应用层开发,只要是Linux 系统就行
底层开发,因为不同处理语言对应不同汇编的独特性,需要根据处理器、板卡调系统代码
x86 有除法指令集
Linux 由汇编和C语言两种语言编写,源代码中包含了大量汇编代码

课程内容

安装系统
在基于ARM处理器的开发板上安装Linux系统

移植的目的

移植
不同架构的处理器指令集不兼容,即便是相同的处理器架构,板卡不同驱动代码也不兼容
Linux是一个通用的内核并不是为某一个特定的处理器架构或板卡设计的,所以从官方获取Linux源码后我们要先经过相应的配置使其与我们当前的硬件平台相匹配后才能进行编译和安装

课程特点

LV.10 系统移植_第2张图片

课程设计原则

课程设计原则
在最短的时间内学会最有用的东西

Day1-2 系统移植过程

系统移植过程

LV.10 系统移植_第3张图片
32 位处理器,寻址空间2的32次方,4个G
芯片手册,地址映射表,86 页最末行0x0000_0000 应该写错了,实际是0xFFFF_FFFF
IROM 64KB芯片内部的存储器,内部由BLO程序,上电后首先执行
IRAM 内部的内存
SFR 特殊功能寄存器
扩展内存
RAM 256*4 = 1G : 0x4000_0000-0x8000_0000

Day1-3 开发板启动过程

开发板启动过程

20230103_210729_Trim

1、开发板上电后首先运行SOC内部iROM中固化的代码(BL0),这段代码先对基本的软硬件环境(时钟等…)进行初始化,然后再检测拨码开关位置获取启动方式,然后再将对应存储器中的uboot搬移到内存,然后跳转到uboot运行
2、uboot开始运行后首先对开发板上的软硬件环境做进一步初始化,然后将linux内核、设备树(dtb)、根文件系统1 (rootfs)从外部存储器(或网络)搬移到内存,然后跳转到linux运行
3、linux开始运行后先对系统环境做初始化,当系统启动完成后,Linux再从内存中(或网络)挂载根文件系统

BLO 执行后
		1、初始化内存,初始化时钟。。。
		2、检查拨码开关状态,SD卡启动。。。
		3、把SD卡中内容放内存
		4、执行内存中从SD 卡中加载的UBOOT
		5、UBOOT初始化软硬件
		6、UBOOT把EMMC 中的Linux 加载到内存(前提条件是Linux已经安装到EMMC)
		7、UBOOT把dtb设备树从外存搬到内存(Linux 内核 + 设备树 = 完整Linux)
		8、UBOOT把外存中的rootfs根文件系统装到内存,根文件系统不属于Linux ,本身是一些文件,放在内存中才好使
		9、Linux 开始运行,初始化,从内存挂载根文件系统(方式有很多,常用方式从网络挂载)
		10、Linux 继

系统移植步骤

uboot移植
linux内核移植(包含设备树)
根文件系统移植

D2 交叉开发环境搭建

Day2-1 ubuntu网络环境配置

ubuntu网络环境配置

LV.10 系统移植_第4张图片

在局域网中使用桥接模式
在校园网用net 模式
连开发板指定使用桥接模式,有线网卡

Day2-2 tftp服务器环境搭建

tftp

tftp(Trivial File Transfer Protocol)即简单文件传输协议
是TCP/IP协议族中的一个用来在客户机与服务器之间进行简单文件
传输的协议,提供不复杂、开销不大的文件传输服务。端口号为69
LV.10 系统移植_第5张图片

Day2-3 nfs服务器环境搭建

nfs

nfs(Network File System)即网络文件系统,其基于UDP/IP
使用nfs能够在不同计算机之间通过网络进行文件共享,能使使用
者访问网络上其它计算机中的文件就像在访问自己的计算机一样。
LV.10 系统移植_第6张图片

D3 uboot的烧写及使用

Day3-1 uboot概述

开发板启动过程

略。。。

Bootloader

Bootloader
在操作系统运行之前运行的一小段代码,用于将软硬件环境初始化到一个合适的状态,为操作系统的加载和运行做准备(其本身不是操作系统)
Bootloader基本功能
-> 初始化软硬件环境
-> 引导加载linux内核
-> 给linux内核传参
-> 执行用户命令

:bootloader是启动引导程序的统称,嵌入式linux常用的bootloader是uboot

常见的Bootloader

LV.10 系统移植_第7张图片

Day3-2 SD卡启动盘制作

SD卡存储结构

SD卡的存储以扇区为单位,每个扇区的大小为512Byte, 其中零扇区存储分区表(即分区信息),后续的扇区可自行分区和格式化;
若选择SD卡启动,处理器上电后从第一个扇区开始将其中的内容搬移到内存,所以我们把uboot放到从第一个扇区开始之后的空间, 之后的空间根据个人需求可进行分区和格式化 

LV.10 系统移植_第8张图片
if = input file of = output file count = 1

Day3-3 uboot的使用

uboot模式

自启动模式
uboot启动后若没有用户介入,倒计时结束后会自动执行自启动
环境变量(bootcmd)中设置的命令(一般作加载和启动内核)

交互模式
倒计时结束之前按下任意按键uboot会进入交互模式,交互模式下
用户可输入uboot命令

uboot帮助命令

help
查看uboot支持的所有命令
help 命令
查看当前命令的使用方法

uboot环境变量命令

printenv
打印uboot中所有的环境变量
setenv
设置指定的环境变量(保存在RAM中)setenv 环境变量 环境变量的值
saveenv
保存所有环境变量到EMMC中

uboot常用环境变量se

ipaddr
uboot的IP地址
serverip
服务器的IP地址(即ubuntu的IP)
bootdelay
进入自启动模式之前倒计时的秒数

uboot网络传输命令

loadb
通过Kermit协议下载文件到指定的内存地址
loadb 地址
tftp
通过tftp协议下载文件到指定的内存地址
tftp 地址 文件名
注:使用tftp之前要配置好网络及tftp服务器

uboot存储器访问命令

mmc read
将EMMC中指定扇区中的内容读取到内存中指定的地址
mmc read
addr: 内存地址
blk#: EMMC中的扇区编号
cnt: 读取的扇区的个数
mmc write
将内存中指定地址中的内容写入到EMMC中指定的扇区
mmc write

uboot自启动环境变量

bootcmd
自启动的环境变量
该环境变量可以设置成一到多个uboot命令的集合(若有多个使用;分割)
自启动模式下uboot就会按照bootcmd中命令的顺序逐条执行

eg:
    setenv bootcmd tftp 40008000 interface.bin\;go 40008000
    saveenv

D4 Linux内核的安装与加载

Day4-1 tftp加载Linux内核及rootfs

开发板启动过程

略。。。
上电:

  1. 先从0地址开始运行三星公司固化在IRAM 中的那段程序,BL0 初始化软硬件
  2. 从sd卡中搬移uboot
  3. uboot 启动,初始化软硬件环境
  4. 加载内核。。。
  5. 运行内核。。。

uboot Linux内核启动命令

ARM 地址空间 0x4000_0000 -0x8000_0000对应1G扩展内存

bootm
启动指定内存地址上的Linux内核并为内核传递参数
bootm kernel-addr ramdisk-addr dtb-addr
注:
kernel-addr: 内核的下载地址
ramdisk-addr: 根文件系统的下载地址
dtb-addr: 设备树的下载地址
若不使用相应的地址,对应的位置写“-”
eg:
bootm 0x41000000 - 0x42000000

uboot自启动参数环境变量

bootargs
eg:
setenv bootargs root=/dev/nfs nfsroot=xxx.xxx.xxx.xxx:/opt/4412/rootfs
rw console=ttySAC2,115200 init=/linuxrc ip=...
注:
root 根文件系统类型(nfs)
nfsroot 网络文件系统路径(xxx.xxx.xxx.xxx:/opt/4412/rootfs)
rw 操作网络文件系统的权限(rw)
console 控制台(使用串口2,波特率115200)
init init进程的位置(/linuxrc)
ip linux启动后自身的IP(...)

Day4-2 EMMC加载Linux内核及rootfs

Day4-3 tftp加载Linux内核nfs挂载rootfs

Day4-4 EMMC加载uboot

LV.10 系统移植_第9张图片

emmc

uboot 需要刷到引导分区,在uboot 界面往引导分区刷程序需要,打开EMMC 的引导分区(emmc open 0),往EMMC 中必须先执行这个命令把引导分区打开,再往其中刷新uboot,和刷新内核和设备树及根文件不一样。
把uboot 刷到0扇区 mmc write 0 0x41000000 0 0x800
关闭引导分区:emmc close

D5 交叉编译工具链

Day5-1 交叉编译

编译原理

LV.10 系统移植_第10张图片
机器码(二进制)是处理器能直接识别的语言,不同的机器码代表不同的运算指令,处理器能够识别哪些机器码是由处理器的硬件设计所决定的,不同的处理器机器码不同,所以机器码不可移植
库文件是二进制代码,二进制代码就有平台属性。Ubuntu 中的库的架构x88 架构的,交叉编译库中的库文件是ARM架构的
汇编语言是机器码的符号化,即汇编就是用一个符号来代替一条机器码,所以不同的处理器汇编也不一样,即汇编语言也不可移植
C语言在编译时我们可以使用不同的编译器将C源码编译成不同架构处理器的汇编,所以C语言可以移植

GCC编译过程

LV.10 系统移植_第11张图片

交叉编译

交叉编译
程序的编译和运行不在同一台机器上

LV.10 系统移植_第12张图片

交叉编译工具链

交叉编译工具链的获取:
1) 官网获取(不推荐,需要自己进行复杂配置与编译)
http://ftp.gnu.org/gnu/gcc/
2) BSP板级开发支持包(推荐)
samsung、全志…
交叉编译工具链的内容
1) 交叉编译工具
gcc/readelf/size/nm/strip/objcopy/objdump/addr2line
2) 库
ARM架构的库

Day5-2 ELF文件格式

ELF文件格式

ELF
ELF格式是Linux平台上应用最广泛的二进制工业标准之一
ELF格式的文件内包含了很多个段,不同的段存储了不同的信息;因为ELF格式的文件要通过Linux系统的加载和管理才能运行,所以除了最基本的代码段和数据段之外,其中还存储了很多其它的信息,如符号表、调试信息等
LV.10 系统移植_第13张图片

ELF文件相关命令

file
file + 文件名 查看文件的详细信息

readelf
readelf -h + 文件名 列出elf文件的头部信息
readelf -a + 文件名 列出elf文件的所有信息

BIN文件格式

BIN
BIN文件一般是直接运行在CPU之上
的可执行文件,文件内只包含了CPU能够直接识别和运行的指令和数据,不包含其它系统相关的信息
LV.10 系统移植_第14张图片

Day5-3 交叉编译工具链常用工具

交叉编译工具链常用工具

size 列出目标文件每一段的大小以及总体的大小,列出可以加载到内存的部分的大小
size + 文件名

text 段:存储汇编指令生成的机器码
data段:存储全局变量和static 修饰的局部变量
bss段:未初始化的全局变量和静态局部变量,变量会被系统清零
dec: 10进制总大小
hex: 16进制总大小

非静态局部变量程序运行的时候分配空间

nm 列出目标文件中的符号表(标示符)
nm + 文件名

.symtab 包括各种汇编符号,举例说如函数名,函数名在程序链接的时候有意义,
符号表意义:只通过.o 文件可以看源程序都有哪些函数。

strip 符号表不影响程序的执行,丢弃目标文件中的符号
strip + 文件名
注:对于嵌入式开发,这个命令很重要

objdump 从目标文件中显示信息, objdump [-d,-D]: 反汇编 -D 比-d 信息更多一些
eg:
objdump -d + 文件名 将目标文件反汇编(机器码->汇编)

objcopy 对目标文件进行复制和转换
eg:
objcopy --gap-fill=0xff -O binary a.out a.bin
将目标文件转换为bin格式

D6 uboot移植

Day6-1 uboot源码结构

uboot源码获取

德国的一个小组开发,每当对应芯片有变化,uboot 就会相应升级
支持系统多
源码不能直接编译,因为包含大量无关的处理器和开发板信息,需要先配置,告诉uboot 所使用的开发板,需要先把相关代码摘出来,然后去编译成能在开发板运行的bin 文件

uboot源码下载
http://www.denx.de/wiki/U-Boot/

uboot版本命名
前期:uboot-1.2.3
现在:uboot-2008.01

uboot版本选择
支持对应的硬件平台
相对成熟的版本(资料多)

uboot特点

代码结构清晰
支持丰富的处理器与开发板,易于移植
支持丰富的用户命令
支持丰富的网络协议
支持丰富的文件系统
支持丰富的设备驱动
更新活跃、用户较多、资料丰富
开放源代码
较高的稳定性
不具有通用性(不同的处理器、开发板uboot不可通用)

uboot源码结构

平台相关代码
即与CPU架构或开发板硬件相关的源码,硬件的改动对应的代码也需要进行修改

arch:与CPU架构相关的源代码
board:与开发板相关的源代码,包含各种官方评估板对应的源码

平台无关代码
api: 应用接口
boards.cfg 板极配置信息
common: uboot命令源码,支持自己开发命令
COPYING 版权信息
CREDITS 贡献者信息
disk: 对磁盘设备的支持
README 对UBOOT 的总的说明书,细节在doc 中看
drivers: 设备驱动源码
dts 设备树,后续驱动开发会细讲
example 代码实现例子
fs: 对文件系统的支持
include: 头文件
lib: 库
net: 对网络协议的支持
post: 上电自检程序
doc: 帮助文档
Makefile: 编译管理
tools: 工具
… …

Day6-2 uboot的配置与编译

uboot配置

1.指定当前使用的硬件平台
make _config
注1:为当前使用的开发板的名字
注2:执行该命令的前提是uboot源码支持该开发板
注3:该命令必须在uboot源码的顶层目录下执行

2.指定编译uboot源码使用的编译器
在uboot源码顶层目录下的Makefile中指定(CROSS_COMPILE变量)

uboot编译

1.编译uboot
make
注1:该命令必须在uboot源码的顶层目录下执行
注2:该命令执行后在uboot源码顶层目录下生成u-boot.bin

2.清除编译过程中生成的中间文件
make clean
make distclean
注1:该命令必须在uboot源码的顶层目录下执行

Day6-3 uboot移植

D7 Linux内核移植

Day7-1 Linux内核概述

内核与操作系统

内核
内核是一个操作系统的核心,提供了操作系统最基本的功能,是操作系统工作的基础,决定着整个系统的性能和稳定性

内核功能:
进程管理
内存管理
文件系统
设备驱动
网络连接

操作系统
操作系统是在内核的基础上添加了各种工具集、桌面管理器、库、shell、应用程序等
操作系统在计算机系统中承上启下的地位:向下封装硬件,向上提供操作接口。

Linux操作系统的目标(了解)
方便性:使计算机系统易于使用
有效性:以更有效的方式使用计算机系统资源
扩展性:方便用户有效开发、测试和引进新功能
开放性:所谓开放性,是指系统能遵循世界标准规范,特别是遵循开放系统互连OSI 国际标准。
LV.10 系统移植_第15张图片

Linux层次结构

LV.10 系统移植_第16张图片

Linux内核特点

代码结构清晰、模块化设计
支持丰富的硬件平台
较高的稳定性
轻量化及较强的裁剪性
开放源代码
更新活跃、用户较多、资料丰富
支持丰富的网络协议
不是专为嵌入式设计的,只是适用于嵌入式
… …

Day7-2 Linux内核源码结构

Linux内核源码获取

Linux内核源码下载
https://www.kernel.org/

Linux内核版本命名
主版本号.次版本号.修订版本

Linux内核版本选择
支持对应的硬件平台
相对成熟的版本(资料多)
稳定版本(次版本号为偶数的版本一般都是稳定版)

Linux内核源码结构

平台相关代码

arch:	与CPU架构相关的源代码

平台无关代码

block:磁盘设备的支持				
drivers:设备驱动						
fs:文件系统,很多种					
init:内核初始化						
kernel:内核核心调度机制等		
mm:内存管理							
scripts:工具、脚本等				
usr:打包与压缩						
crypto:加密相关
firmware:固件
include:头文件
ipc:进程间通信
lib:库
net:网络协议
security:安全
virt:虚拟,虚拟化相关的代码
COPYING 版权相关的生平,最出名的CPL
Document 详细说明
fs 文件系统管理磁盘,
init 初始化文件,其中start_kernel负责启动
ipc 进程间相互通讯相关代码
Kconfig 配置界面,图形化界面
kernel  核心调度算法
REPORTING-BUGS 
sound 音频驱动
tools 工具

帮助文档、示例程序、工具等

CREDITS:		内核贡献者
README:		说明文档
Documentation:	帮助文档
Makefile:		编译管理
samples:		示例
... ...

Day7-3 Linux内核的配置与编译

Linux内核源码配置

指定处理器架构及编译工具
在Linux内核源码顶层目录下的Makefile中指定(ARCH、CROSS_COMPILE)
导入当前处理器的默认配置
make _defconfig
注1:soc_name为当前使用的处理器的名字
注2:内核源码的arch/arm/configs下对各个厂商的soc都有一个默认配置文件, 执行该命令后就会将对应的配置文件中的信息导入到源码顶层目录下的.config, 文件中CONFIG_xxx=y表示内核选中了该功能,内核编译时就会将该功能对应的代码编译,内核的体积也会增大。#CONFIG_xxx is not set表示内核没有选中该功能,内核编译时该功能对应的代码不会被编译,内核的体积也会减小。

修改配置
默认配置只能保证内核拥有最基本的功能,我们需要根据自己的实际需求对内核做进一步的配置
defconfig 导入默认配置

方法1:	直接修改.config文件(不推荐)
方法2:	make menuconfig

make menuconfig

图形化界面会自动检查和解决依赖关系
eg:nfs ->tcp/ip->DM9000网卡驱动

修改配置
[ ] 有两种状态
输入Y,显示“”,内核中该功能被选中,相关代码会被编译进内核
输入N,显示“ ”,内核中该功能不被选中,相关代码不会被编译进内核
< > 有三种状态
输入Y,显示“
”,内核中该功能被选中,相关代码会被编译进内核
输入N,显示“ ”,内核中该功能不被选中,相关代码不会被编译进内核
输入M,显示“M”,内核中该功能被选为模块(被编译为独立的模块)

注:使用make menuconfig配置的本质还是修改.config文件

Linux内核源码编译

内核编译(以下命令均在内核源码的顶层目录下执行)
make uImage2
编译内核(编译选为“*”的选项到内核)
make modules
编译内核模块(编译选为“M”的选项为独立模块)
make dtbs
编译设备树(将设备树源文件dts编译为二进制文件dtb)
make clean
删除编译过程中产生的中间文件

实验手册

D8 Linux设备驱动移植

Day8-1 设备树

设备树

设备树
设备树是一种描述硬件信息的数据结构,Linux内核运行时可以通过设备树将硬件信息直接传递给Linux内核,而不再需要在Linux内核中包含大量的冗余编码

设备树语法概述

设备树文件
dts 设备树源文件
dtsi 类似于头文件,包含一些公共的信息,可被其它设备树文件引用
dtb 编译后的设备树文件

设备树语法
设备树的语法为树状结构,由一系列的节点和属性组成,根节点下包含子节点
子节点下还可以包含子节点,节点内部包含了对应设备的属性

Linux内核驱动移植

Linux内核驱动移植
1.在make menuconfig界面中选中要安装的驱动
2.在设备树中添加/修改相应的设备信息
3.重新编译内核/设备树

Day8-2 网卡驱动移植

Linux内核驱动移植

Linux内核驱动移植
1.在make menuconfig界面中选中要安装的驱动
2.在设备树中添加/修改相应的设备信息
3.重新编译内核/设备树

D9 根文件系统移植

Day9-1 根文件系统

根文件系统

根文件系统
根文件系统是内核启动后挂载的第一个文件系统系统,引导程序会在根文件系统挂载后从中把一些基本的初始化脚本和服务等加载到内存中去运行

根文件系统内容

 bin		shell命令(elf格式)(通过busybox编译生成)
 dev		设备文件(内核启动后会将设备信息写入该目录),Linux 运行后动态管理该目录,给用户看
 etc		内核配置文件
 lib		共享库(elf格式)(从交叉编译工具链中获取)
 linuxrc	内核运行的第一个应用程序(通过busybox编译生成)
 mnt		挂载目录(非必要),Linux 磁盘属于文件,磁盘挂载在文件下才能使用
 proc		进程相关文件(内核启动后会将进程信息写入该目录)
 root		超级用户家目录(非必要)
 sbin   	系统管理shell命令(elf格式)(通过busybox编译生成)
 sys		驱动相关文件(内核启动后会将驱动信息写入该目录)
 usr		shell命令(elf格式)(通过busybox编译生成)

Day9-2 根文件系统移植

BusyBox

BusyBox
BusyBox将很多常用的工具集成到一个很小的可执行文件中,为普通用户提供大多数常用的命令,BusyBox实现的命令都是精简版的,很多扩展都不支持。BusyBox被称为Linux工具里的瑞士军刀

BusyBox的获取
https://busybox.net/downloads/

移植过程
下载BusyBox源码,通过解压缩、配置、编译、安装、裁剪、赋权限(给 etc/init.d/下的 rcS 脚本添加可执行权限)、移动到开发板完成整个移植过程。

注脚


  1. 文件系统是一种管理和访问磁盘的软件机制,其本质是软件,不同文件系统管理和访问磁盘的机制不同。根文件系统是存放运行系统所必须的各种工具软件、库文件、脚本、配置等文件的地方,实质就是一些文件。 ↩︎

  2. 内核编译(make)之后会生成两个文件,一个Image,一个zImage,其中Image为内核映像文件,而zImage为内核的一种映像压缩文件,Image大约为4M,而zImage不到2M。
    那么uImage又是什么的?它是uboot专用的映像文件,它是在zImage之前加上一个长度为64字节的“头”,说明这个内核的版本、加载位置、生成时间、大小等信息;其0x40之后与zImage没区别。
    如 何生成uImage文件?首先在uboot的/tools目录下寻找mkimage文件,把其copy到系统/usr/local/bin目录下,这样就 完成制作工具。然后在内核目录下运行make uImage,如果成功,便可以在arch/arm/boot/目录下发现uImage文件,其大小比 zImage多64个字节。
    其实就是一个自动跟手动的区别,有了uImage头部的描述,u-boot就知道对应Image的信息,如果没有头部则需要自己手动去搞那些参数。
    U-boot的U是“通用”的意思。
    zImage 是ARM Linux常用的一种压缩映像文件,uImage是U-boot专用的映像文件,它是在zImage之前加上一个长度为0x40的“头”,说明 这个映像文件的类型、加载位置、生成时间、大小等信息。换句话说,如果直接从uImage的0x40位置开始执行,zImage和uImage没有任何区 别。另外,Linux2.4内核不支持uImage,Linux2.6内核加入了很多对嵌入式系统的支持,但是uImage的生成也需要设置。参考文章 ↩︎

你可能感兴趣的:(嵌入式学习笔记,linux,网络,运维)