ARM裸机(学习外设)
ARM版本号
- ARM基本都是RISC哈佛结构的结构 内存和地址统一编写
ARM内核版本号--------ARM SoC版本号-芯片型号
ARMv1
…
ARMv6 ------------------ARM11--------------------S3C6410…
ARMv7-----Cortex-M(微控制器/单片机)/Cortex-A(应用级,手机,平板)/Cortex-R(实时的、工业航天…)…
ARMv8-------Cortex-A30、ARM Cortex-A50、ARM Cortex-A70
ARMv9
########################################################################################################################################################################################################################################################################################################################################################################################################################################################################################################################################################################################################################
核版本号和SoC版本由ARM分为三个系列,有64个架构
SoC&CPU
SoC:System on Chip 包含外设(Peripheral)内外设备
CPU:中央处理器=运算器 控制器
RISC&CISC
- CISC:复杂指令集
编译器很容易用最少的指令设计任务。
- RISC:精简指令集
编译器设计难以提供基本指令集
IO与内存 统一编址|独立编址
- 统一编址:IO访问地址与内存地址相同
RISC访问方式。CPU地址空间有限IO也有限。CPU内存数据需要在寄存器中加载
- 独立编址:专用CPU与访问内存不同,指令访问特定外设
CISC访问方式。CPU设计复杂
冯诺伊曼&哈佛
-
冯诺伊曼结构:程序和数据都放在内存中,存在安全性和稳定性问题
-
哈佛结构:程序放置ROM、FLASH中;数据放置RAM中
多采用单片机和嵌入式;软件复杂,需要规划链接地址
寄存器是软件控制硬件的关键
寄存器是CPU可编程开关外设硬件的一部分
在哈佛结构中,寄存器操作与访问内存相似。单个寄存器的位宽一般与CPU同样的位宽有利于最佳效率
- 通用寄存器:在CPU通用寄存器
- 特殊功能寄存器(SFR):不在CPU中
内存地址映射
210属于A8架构,32位,32条地址线和32条数据线。搜索空间为4G
- 见:UM-P25
内存:RAM CPU可直接访问(地址总线) 数据总线)速度快
外存:ROM 通过控制器接口连接访问
支持的外部存储器
- 210SoC支持的ROM-见:UM-P517 详见:P588memory
- X210开发板支持:4G iNAND使用通道0 外部SD2使用通道2
常见的外部存储器:
FLASH:电存储 NorFlash: 接至SROM bank,总线访问(类似内存访问)昂贵可靠,一般用于启动 NANDFLASH: NandFlash: (分SLC、MLC和TLC)价格便宜 eMMC/iNand(闪迪)/moviNand(三星):类似SD卡的芯片,均为eMMC SD卡/TF卡/MMC卡: eSSD:嵌入式MLC硬盘 SATA接口硬盘:磁存储
*启动过程
SRAM:无需初始化即可使用(容量小) DRAM:使用软件需要初始化内存 NORFLASH:总线访问(启动介质) NANDFLASH:不能总线访问,需要初始化 210启动模式:内置966K SRAM(IRAM),64K NORFLASH(IROM)
启动过程见IROM_API-P5 1.CPU读取IROM实施基本初始化(IROM代码BL0由SOC厂家内置),硬件选择启动模式读取启动代码(第一部分BL1,16K)至SRAM并校验。 2.SRAM中运行读取到的启动代码(UBOOT-BL1)。搬运剩余UBOOT(BL2)至SRAM的BL2 3.SRAM中的BL2初始化SDRAM并加载OS至SDRAM 4.跳转至OS的地址运行
ARMv7 32位 通用寄存器相关
ARM32位约定:Byte=8bit Halfword=16bit=2Byte Word=32bit ARM32位指令集:
ARM指令集32bit、Thumb2指令集
-1.ARMv7处理器工作模式(stm32基本没有那么多模式)
非特权模式: User:大多数任务执行模式 特权模式: 异常模式: FIQ:快速中断 IRQ:普通中断 Supervisor:管理模式(复位,软中断进入,引导) Abort:异常模式 Undef:指令模式没有定义 System: 与User使用相同寄存器的特权模式
写CPSR或者切换寄存器CPU自行切换
*如此设计由OS与安全要求有关
-2.ARMv7通用寄存器
模式 ABORT User FIQ IRQ SVC UNDEF r0 通用 r1 通用 r2 通用 r3 通用 r4 通用 r5 通用 r6 通用 r7 通用 r8 部分不通用 r8-F r9 部分不通用 r9-F r10 部分不通用 r10-F r11 部分不通用 r11-F r12 部分不通用 r12-F (sp) r13-A r13-U r13-F r13-I r13-S r13-D (lr) r14-A r14-U r14-F r14-I r14-S r14-D r15(pc) 通用 cpsr 通用 spsr-A 无 spsr-F spsr-I spsr-S spsr-D --------------------------------------------------------- 总计:37 @:SYSTEM模式使用USER模式寄存器
sp:堆栈指针保护现场使用 lr:存储当前模式的返回地址 pc:当前程序执行的指针,pc指向哪里,CPU执行哪个指令。程序跳转是将目标代码地址放在目标代码上。pc中 cpsr:记录程序状态寄存器CPU状态 spsr:用于保存以前的模式CPSR
-3.详解CPSP
32-28 27 24 23-16 15-8 7 6 5 4-0 NZCV Q J Undef ined I F T mode *条件位:发生时结果自动位置1(ALU为运算器) N:ALU Negative 结果为负 Z:ALU Zero 运算结果为0 C:ALU Carried out ALU计算结果有进位 V: ALU oVerflowed ALU计算结果溢出 -------------------------------------------- Q:指示饱和状态(仅)ARMv5支持) J:=1时JAVA加速使用(仅)ARMv5支持) 禁止中断: I: =1时禁止IRQ F: =1时禁止FIQ -------------------------------------------- T:仅ARM xT架构支持,=0为ARM状态,=1为Thumb状态 mode:ARM的模式位
-4.CPU异常处理
异常发生时,CPU自动将PC跳异常向量表跳转到异常地址。(CPU提前设置的异常中断地址)决定。CPU提供二级向量表 VECTOR TABLE:
- 异常发生时CPU做的事:
- 1.拷贝CPSR在新模式下SPSR
- 2.设置新的CPSR
- 3.保存返回地址lr
- 4.设置PC指针为异常向量表(跳转执行)
- 5.中断结束,从SPSR恢复CPSR,从lr恢复PC指针。
ARMv7 32位指令
- GNU编程风格:指令全小写
指令: 编译后得到机器码
伪指令:编译器提供,指导编译过程,不生成机器码 load 内存加载至寄存器 store 寄存器内容存入内存
常见ARM32位指令:
寻址方式:
1.寄存器寻址 mov r1,r2 r2值赋给r1
2.立即数寻址 mov r0,#0xffff
3.寄存器移位寻址 mov r0,r1,lsl #3 r1左移3位赋值给r0
4.寄存器间接寻址 ldr r1,[r2] 将r2为地址的内容赋值给r1
5.基址变址寻址 ldr r1,[r2,#4] r2地址+4的地址 的内容给r1
6.多寄存器寻址 ldmia r1!,{r2-r7,r12} 以r1为地址,依次将内容放入多个寄存器中(弹栈)
7.堆栈寻址(压栈)stmfd sp!,{r2-r7,lr} 将栈连续访问,放入大括号内的寄存器中
8.相对寻址 beq xxx 跳转到xxx标号。实质为pc指针相对偏移量
指令后缀:指令族
指令+B 功能不变,由操作32位变为操作8位
指令+H 功能不变,由操作32位变为操作16位
指令+S 功能不变,操作有符号数/影响CPSR标志条件位
条件执行后缀:条件的成立由上句代码结果,只影响本句代码的执行。(根据CPSR判断)
标志 标志位 含义
---------------------------------------
EQ Z=1 运算结果为0
NE Z=0 运算结果不为0(不相等)
---------------------------------------
CS/HS C=1 无符号大于等于
CC/LO C=0 无符号小于
MI N=1 负数
PL N=0 正数或0
VS V=1 溢出
VC V=0 未溢出
HI C=1,Z=0 无符号数大于
LS C=0,Z=1 无符号小于等于
GE N=V 有符号数大于等于
LT N!=V 有符号数小于
GT Z=0,N=V 有符号数大于
LE Z=1,N!=V有符号数小于等于
AL 无条件执行,指令默认条件
NV 从不执行
常见指令
数据传输
*mov 寄存器 mvn 按位取反后赋值
算术运算 add sub rsb adc sbc rsc
*逻辑指令 and orr eor(异或) bic(位清除)
*比较指令,自动影响CPSR: cmp(比较相等) cmn tst teq
乘法指令 mvl mla umull umlal smull smlal
前导0计数 clz
*cpsr访问指令:cpsr需要专门指令访问
mrs 读cpsr/spsr
msr 写cpsr/spsr
跳转指令:
*b:直接跳转
*bl:保存返回地址到lr然后跳转 //bx:跳转同时切换为ARM模式
访问内存指令:
*ldr/str:
*ldm/stm:多字访问
后缀 ia increase after 先传输,地址+
ib increase before 先地址+,传输
da decrease after 传输,地址-
db
---------------------------------
* fd 满减
ed 空减
fa 满增
ea 空增
swp:内存与寄存器互换指令
立即数(普通数字):带#。立即数有合法、非法。非0部分8位内即合法
软中断指令:swi软件模拟中断,实现OS系统调用
协处理器指令:一般SoC只实现CP15协处理器.协处理器和MMUC、cache、TLB等处理有关
mrc&mcr
^:目标寄存器有PC寄存器时,会同时将spsr写入到cpsr
*伪指令:不同编译环境的伪指令不同,以下为GNU环境
@ 注释
// 注释
/*注释 */
# 注释
:标号,标记指令地址
.点代表当前指令地址
--------------------------------------------------
.global xxx @声明为外部的链接属性,声明为全局变量,让别的文件可用
.section .text @将当前段指定为代码段
.ascii .byte .shrt .long .word .quad .float .string变量类型
.align X 以2的X次方对齐
.balignl x,0xnnnnn @对齐,填充:b表示位填充,l表示为long4字节为单位填充 ,以16字节对齐
.equ @类似宏定义
.end 文件结束 .include 包含头文件 .arm/.code32 声明代码为ARM指令 .thumb/.code16声明为thumb指令
* ldr 大范围地址加载指令(伪指令不用考虑合法立即数)不使用#而是=,绝对地址
* adr 小范围地址加载,以PC为基准表示地址(相对地址)
* adrl
* nop 空操作
ARM指令流水线(CPU自动处理,了解即可)
三级流水线: 取值-->解码-->执行
ARM PC PC-4 PC-8
PC指针实际指向被取址的指令,并非正在执行的指令
流水线越多速度越快,但跳转会重置流水线
刷机
步骤
使用串口做控制台
1.选择启动方式 0xd0020010(usb启动地址)下载BL1
2.下载、烧写 运行bootloader(uboot)
3.下载、烧写 OS(使用uboot中的fastboot,通过USB进行,需要驱动)
-1.分区fdisk -c 0
-2.fastboot flash bootloader分区 uboot镜像
-3.fastboot flash kernel分区 内核文件(linux kernel)
-4.fastboot flash system分区 文件系统(rom)
fastboot常用命令
fastboot devices 查看当前连接设备
fastboot flash xxx 用于烧录
fastboot reboot 重启设备
uboot的参数:bootcmd bootargs
set bootcmd 'movi read kernel 30008000;bootm 30008000'
set bootargs console=ttySAC2,115200 root=/dev/mmcblk0p2 rw init=/linuuxrc rootfsype=ext3
save
elf文件&bin文件
elf文件:OS下的 可执行文件,包含了整个文件的基本属性,如文件版本,目标机器型号,程序入口等等。是带格式的映象
hex文件:包含地址信息,因此无需指定地址信息
bin文件:只包含可执行二进制,可顺序执行,内部没有地址标记是直接的内存映象的表示。需要指定地址信息
(mkv210_image.c)用于给生成的bin文件添加ECC头校验。根据MCU特性,USB\UART启动无需使用校验,因此可直接使用生成的bin文件
BL0
BL0(内置的IROM代码)无需编写了,210内置 1.关看门狗 2.从初始化cache指令 3.初始化栈 4.初始化堆内存 5.初始化块设备的 复制函数 6.初始化PLL
锁相环和系统时钟 7.复制BL1至SRAM中 8.校验BL1,如果失败尝试二次启动 9.是否安全启动&安全启动相关内容 10.跳转至BL1的起始地址
BL1(uboot方式与推荐手册不同)
//1.关看门狗(210BL0已经做)
// 初始化时钟(210默认初始化为1G)
//2.设置栈(210BL0已做)(C语言环境:c语言的局部变量使用栈实现)IROM-API:P13memory map
:SVC栈0xD003_7780-0xD003_0xD003_7D80 ARM使用满减栈,故sp=0xD003_7D80
//3.开指令cache (210BL0已做):UM-P
icache是内部自动的,打开即可
4.重定位和链接脚本
5.初始化ddr
6.搬运uboot到ddr
7.从iram长跳转到ddr中继续执行uboot(使用ldr修改PC指针)
初始化ddr-见具体的bord
内存相关见NT5TU64M16GG-P10:BLOCK DIAGRAM 128Mb*8 UM-P598:memory
其中,要清楚内存是分Bank的,每个bank寻址由行地址和列地址组成
bl sdram_asm_init
重定位
1.链接脚本中指定目标地址
2.下载时运行在非目标地址
3.使用PIC将代码搬运至链接地址处
4.长跳转到目标地址中执行(以目标地址为起始,链接脚本为偏移的地址)
伪指令:adr短加载(加载运行时相对地址)
ldr长加载(加载相对链接脚本的地址)
adr r0, _start //_start为起始地址,短加载 运行时地址
ldr r1, =_start //长加载 链接地址,因此与上面的地址不一定相同
ldr r2, =bss_start //重定位代码的结束地址
cmp r0, r1 // 比较_start的运行时地址和链接地址是否相等,是否需要重定位
beq clean_bss //如果相等,不需要重定位,跳转至clean_bss函数,否则继续下面的代码
//搬运
copy_loop:
ldr r3,[r0],#4 //将r0地址的内容放至r3中,地址加4字节
str r3,[r1],#4 //将r3内容放至r1地址中
cmp r1,r2 //目标地址==重定位结束地址
bne copy_loop //如果不等,没有复制完成,继续
clean_bss:
ldr r0, =bss_start
ldr r1, =bss_end
cmp r0, r1 // 如果r0等于r1,说明bss段为空,直接下去
beq run_on_dram // 清除bss完之后的地址
mov r2, #0 //不等,,则清除
UBOOT&OS移植
SHELL&MAKEFILE
Shell
shell脚本语言:一类语言。可自动化执行shell命令,一般用于配置
无需编译链接,可直接解释运行。解析器逐行解释代码
常用shell语言:sh、bash、python...
执行方法:1: ./xx.sh 需要可执行权限
2: source xx.sh 无需可执行权限
3: bash xx.sh bash解释器执行
注意:应注意语法严格
变量引用:使用$xxx 有时仅可以${xxx}
#!/bin/sh #!开始,加上解释器的pathname
# #为行注释
echo "hello word"
shell中为弱变量类型,`xx`反引号的作用是调用命令的返回内容
if的参数[ -参数前后都要有空格 ]:
-f :判断文件是否存在
-d :判断目录是否存在
-eq 是否相等 -gt大于 -lt小于 -ge大于等于 -le小于等于
-z :字符串是否为空 -o 逻辑或 ||和&&用于简写的if表达式
echo中可使用>创建文件并添加echo的内容,>>用于已存在的文件添加内容
shell传参: $#调用传参个数 $0、$1、$2以此表示传参各参数。命令本身不算参数。$x可用shift移出一个
break作用与c语言不同,用于跳出循环
Makefile
引用其他makefile: include(原地展开)
#用来做注释
@命令前加这个表示静默执行(不显示命令本身)
= 引用最后一次赋值
:= 此句之前的值
?= 如果已被定义,此句略过
+= 给已经赋值的变量接续赋值
export导出环境变量,给其他makefile使用
通配符:
* 匹配多个任意字符
? 匹配单个任意字符
[xy]将括号内字符挨个匹配
% 类似*,一般只用于规则中
常见自动变量:
$@ 规则的目标文件名
$< 规则的依赖文件名
$^ 依赖的文件集合
UBOOT
0.就是一个裸机程序
1.自身可开机直接启动-uboot-start.S :根据SOC启动介质
2.引导内核启动,给内核传参(用于引导系统)
3.拥有部署系统的能力。能够使用uboot完成OS的下载(uboot/kernel/rootfs...)
4.能够初始化并控制一部分硬件(如:NAND/LCD/USART)
5.提供人机交互,如命令行shell
生命周期:uboot本质是一个裸机程序(单线程),从start.S到OS内核启动结束
部署操作系统:fastboot方式/ftp方式
tftp:uboot作为客户端,pc的ftp作为服务器,需设置ip&severip(此处传到了内存中)
movi命令将内存中的镜像写到flash中
环境变量bootcmd:自动运行命令的设置movi read kernel 30008000;bootm 30008000
环境变量,内核约定好的参数:bootargs:console=ttySAC2,115200 root=/dev/mmcblk0p2 rw init=/linuxrc rootfstype=ext3
UBOOT命令
x210uboot发现,无相同命令时可省略后边的命令,如printenv可为pri/prin/...
有空格的单个参数使用单引号将参数作为一个参数
printenv- print environment variables
打印环境变量,可简化为print
setenv - set environment variables 设置环境变量
*saveenv - save environment variables to persistent storage整体覆盖保存内存的环境变量到flash
tftpboot- boot image TFTP下载镜像
tftpboot [loadAddress] [[hostIPaddr:]bootfilename]
nfs - boot image via network using NFS protocol
movi(mmc) SD/inand相关操作
movi init - Initialize moviNAND and show card info
movi read {u-boot | kernel|分区名|分区地址} {addr} - Read data from sd/mmc
movi write {fwbl1 | u-boot | kernel} {addr} - Write data to sd/mmc
movi read rootfs {addr} [bytes(hex)] - Read rootfs data from sd/mmc by size
movi write rootfs {addr} [bytes(hex)] - Write rootfs data to sd/mmc by size
movi read {扇区sector#} {bytes(hex)} {addr} - instead of this, you can use "mmc read"
movi write {扇区sector#} {bytes(hex)} {addr} - instead of this, you can use "mmc write"
内存操作:注意防止越界
mw - memory write (fill)写内存
md - memory display显示内存内容
mm - memory modify (auto-incrementing)修改内存
启动内核
bootm - boot application image from memory从内存某地址启动程序镜像同时给内核传参
go - start application at address 'addr'从某地址启动应用/裸机程序
-----------------------------------------------------------------
autoscr - run script from memory
base - print or set address offset
bdinfo - print Board Info structure
boot - boot default, i.e., run 'bootcmd'
bootd - boot default, i.e., run 'bootcmd'
bootelf - Boot from an ELF image in memory
bootp - boot image via network using BootP/TFTP protocol
bootvx - Boot vxWorks from an ELF image
cmp - memory compare
coninfo - print console devices and information
cp - memory copy
crc32 - checksum calculation
dcache - enable or disable data cache
dhcp - invoke DHCP client to obtain IP/boot params
dnw - initialize USB device and ready to receive for Windows server (specific)
echo - echo args to console
erase - erase FLASH memory
exit - exit script
ext2format - disk format by ext2
ext2load- load binary file from a Ext2 filesystem
ext2ls - list files in a directory (default /)
ext3format - disk format by ext3
fastboot- use USB Fastboot protocol
fatformat - disk format by FAT32
fatinfo - print information about filesystem
fatload - load binary file from a dos filesystem
fatls - list files in a directory (default /)
fdisk - fdisk for sd/mmc.
flinfo - print FLASH memory information
help - print online help
icache - enable or disable instruction cache
iminfo - print header information for application image
imls - list all images found in flash
imxtract- extract a part of a multi-image
itest - return true/false on integer compare
loadb - load binary file over serial line (kermit mode)
loads - load S-Record file over serial line
loady - load binary file over serial line (ymodem mode)
loop - infinite loop on address range
MMC sub systemprint MMC informationmovi - sd/mmc r/w sub system for SMDK board
mtest - simple RAM test
nm - memory modify (constant address)
ping - send ICMP ECHO_REQUEST to network host
protect - enable or disable FLASH write protection
rarpboot- boot image via network using RARP/TFTP protocol
reset - Perform RESET of the CPU
reginfo - print register information
run - run commands in an environment variable
sdfuse - read images from FAT partition of SD card and write them to booting device.
sleep - delay execution for some time
test - minimal test like /bin/sh
version - print monitor version
UBOOT环境变量(系统的全局变量&自定义环境变量)
UBOOT文件&文件夹分析
uboot-jiuding
文件:
CHANGELOG : 修改日志 记录每个版本的修改记录 ,git管理工具也可以生成
arm_config.mk : .mk类文件 makefile中调用的某个文件
config.mk
* rules.mk : uboot的makefile使用的规则
COPYING : GPL许可版权
CREDITS : 感谢目录
-image_split : 分割uboot的脚本
MAINTAINERS : 维护者名单
-MAKEALL : 可能是帮助uboot编译的脚本
* Makefile : 主makefile文件
-mk : 快速编译脚本
* mkconfig : uboot主要配置脚本,可移植性主要由此文件实现
-mkmovi : 和启动介质相关
README : 说明文档
目录:
api : 硬件无关的功能函数API,uboot本身使用的
-api_examples : API示例代码
+ arch : 新版uboot中的:架构相关
* board : 开发板相关信息,已移植的板/厂家
+ boot : 新版uboot中的:可能与启动顺序有关
+ cmd : 新版uboot中的:
* common : 与具体硬件无关的普遍适用的代码。主要是uboot的命令与env环境变量相关的
+ configs : 新版uboot中的:可能与soc相关的
* cpu- : 新uboot无,SOC相关代码,需要移植的。包括SOC初始化、控制代码、start.S
disk : 磁盘相关的
doc : 文档文件,uboot相关文档、资料
+ dts : ??
* drivers : 从linux中拿出的uboot必须使用的设备驱动
+ env : ??
examples : 示例代码
* fs : 文件系统,从linux中移植的
* include : 头文件目录集合
* lib_ xx- : 架构相关的库文件
lib_generic- : 架构通用库文件
libfdt- : 设备树相关的
+ lib : ?可能修改了以上的文件夹
-nand_spl : nand相关的
net : 网络相关代码,如tftp nfs sntp ...
-onenand_xxx : 三星的flash相关的
post : ??
* -sd_fusing : 烧录uboot镜像到sd卡
+ scripts : 脚本
+ test : ?测试代码
tools : 工具类代码
UBOOT-1.3.4配置、编译
/makefile
版本信息: U_BOOT_VERSION = $(VERSION主版本).$(PATCHLEVEL补丁版本).$(SUBLEVEL次级补丁版本)$(EXTRAVERSION附加信息) "1.3.4xxx" VERSION_FILE =$(obj)include/version_autogenerated.h 编译后生成的版本宏定义 环境变量: HOSTARCH := i386/sparc64/arm/ppc/其他---- 主
机架构:这里我的x86_64不会被替换 HOSTOS := linux/... 操作系统:linux,本来应该是Linux export HOSTARCH HOSTOS 静默编译: findstring s XECHO=echo:如果MAKEFLAGS中有s则静默编译。可以只输出编译过程信息,没有makefile信息 build编译方法: 1.原地编译:默认将当前目录.c编译的.o放在同一文件夹。 2.输出文件夹编译方式:linux kernel也是如此。 -1. make O=/指定路径 -2. export BULLD DIR=/路径 然后make 配置脚本目录变量:NO.101 MKCONFIG := $(SRCTREE)/mkconfig 标志远程编译变量并导出环境变量 加载配置 include $(obj)include/config.mk 未编译的源码目录没有此文件,由配置过程生成。此文件的值和配置有关。 CROSS_COMPILE 编译器前缀全路径 导入其他配置文件:NO.185 include $(TOPDIR)/config.mk U-Boot objects、LIB集合:NO.188 ALL目标:NO.286 x210_sd_config :NO.2589配置目标 @$(MKCONFIG) $(@:_config=) arm s5pc11x x210 samsung s5pc110 #执行$(SRCTREE)/mkconfig脚本并传参 将_config替换为空 $1=x210_sd $2=arm $3=s5pc11x $4=x210 $5=samsung $6=s5pc110 $#=6
/config.mk
主要是编译环境相关
包含自动配置生成的board configs sinclude $(OBJTREE)/include/autoconf.mk指导条件编译、可移植性的。
由include/configs/xx.h文件生成(宏定义)因此移植时需要修改此文件
根据环境ARCH、CPU...包含不同的编译配置信息
根据CONFIG_NAND_U_BOOT配置LDSCRIPT变量 $(TOPDIR)/board/$(BOARDDIR)/xxx.lds链接脚本的路径
CPPFLAGS:NO.157 += -DTEXT_BASE=$(TEXT_BASE) 用于指定链接地址0xc
TEXT_BASE在主makefile配置时编写,编译后在.obj/board/samsung/x210/config.mk编译前在主makefile配置目标中
这里TEXT_BASE=0xc3e0 0000 uboot使用了虚拟地址映射,实际地址在:0x23e0 0000
自动推导规则编译:NO.239
/mkconfig
BOARD_NAME = x210_sd $#要为4-6
NO.33-181: 创建符号链接,选择需要移植代码创建符号链接
include/ 创建asm -> asm-arm
include/asm-arm/创建arch -> arch->s5pc110--------被后面删掉了
include/ 创建regs.h -> include/s5pc110.h
include/asm-arm/创建arch -> arch->s5pc11x
include/asm-arm 创建proc -> /include/proc-armv
创建/include/config.mk文件---》为了让主makefile使用
创建、追加配置头文件 /include/config.h 包含了x210_sd.h,用来生成autoconfig.mk,然后用于指导编译
链接脚本: ( T O P D I R ) / b o a r d / (TOPDIR)/board/ (TOPDIR)/board/(BOARDDIR)/xxx.lds
ENTRY(_start) :程序入口,类似c中的main
-Ttext的链接地址和.lds链接脚本中都指定链接地址时,以-Ttext地址优先
代码段中,应注意排列顺序。BL1前16k的文件必须排列在前
/include/configs/xxx.h
uboot1.3.4源码分析
BL1:汇编阶段、SRAM中,主要操作Soc内部
寻找第一个入口:lds链接脚本的ENTRY声明的地方的符号,为入口/cpu/s5pc11x/start.S
头文件包含
config.h 配置后生成的,实际指向x210_sd.h
version.h 指向version_autogenerated.h 定义了U_BOOT_VERSION值来自makefile的修改
如果定义CONFIG_ENABLE_MMU 包含 <asm/proc/domain.h>
<regs.h> 指向s5pc110.h
条件编译
CONFIG_EVT1=1 CONFIG_FUSED未定义 则定义校验头16字节占位
start.S:
复位跳转到reset,设置SVC32模式,并关闭普通中断与快速中断
构建异常向量表
16字节对齐,TEXT_BASE由配置makefile时指定的
reset
-cpu_init_crit:
disable_l2cache 禁止l2cache
set_l2cache_auxctrl_cycle 设置l2cache
enable_l2cache 使能l2cache
刷新L1 I / D cache
禁止MMU和缓存 disable MMU stuff and caches
Read booting information:
R2-->PRO_ID_BASE=0xE0000000 OMR_OFFSET=0x04 包含了OM_PIN信息
R3-->根据启动信息,加载启动介质方式MMC/NAND...
设置栈 0xd0036000--》sram中
lowlevel_init 进行底层初始化-->uboot-9d/board/samsung/x210/lowlevel_init.S
压栈,防止再次调用函数
-check reset status 检查复位状态:如冷启动、热启动、复位...
-IO Retention release IO恢复。。。
*关看门狗
-外部SRAM&SROM初始化
*PS_HOLD pin(GPH0_0) set to high 锁定开关
判断在SRAM还是DDR,是否需要重新初始化时钟、内存
如果SRAM中,
初始化时钟
初始化内存控制器(DDR)---cpu_init.S uboot中,256内存地址设置为0x3000..裸机中设为0x20...都可工作
uboot整体物理地址设置为DMCO(0X3000..-0X3FFF..)DMC1(0X4000..-0X4FFF) 512MB
初始化串口,打印‘O’
tzpc_init...打印‘K’
再次供电锁存,无意义,但不影响
再次设置栈,此时DDR已初始化,设置ddr中的栈。//33e0 0000
再次判断代码运行在SRAM还是DDR,如果是SRAM则重定位代码至DDR
判断启动介质,最终调用相应copy函数movi_bl2_copy--uboot-9d/cpu/s5pc11x/movi.c
将启动设备中完整的uboot复制到DDR中了
enable_mmu虚拟地址映射:MMU(内部外设,实现虚拟地址和物理地址转换),建立虚拟地址映射表
MMU在CP15协处理器控制:映射、访问控制、
1.设置cp15-c3,实现控制域访问
2.转换表基地址设置TTB:cp15-c2,即设置转换表:表索引对应虚拟地址,表项对应物理地址。
内存映射与管理以块为单位,块大小取决于设置和mmu支持。
虚拟地址映射实际就是建立映射表,放置时要求xx位对齐
-lowlevel_init.S
->mmu_table:粗表映射按1MB
3.使能mmu-cp15-c1:bit0控制
设置栈,将栈放置在较安全的地方,紧凑而不浪费内存
ldr清bss-start到end
ldr远跳转加载uboot/lib_arm/bord.c start_armboot:UBOOT的第二阶段(BL2,DDR中)
--------------------------------------------------------------------------------------------
BL2:C阶段、DRAM中、注重Soc外部
uboot/lib_arm/bord.c -start_armboot(418):外部硬件初始化、uboot本身初始化
init_fnc_t **init_fnc_ptr; //函数指针 数组
gd_base:
gd(全局变量,指向gd_t类型的指针),
gd_t(include/asm-arm/global_data.h,uboot使用的全局变量,包含一个bd_t硬件参数)
分配gd、bd的内存
内存间隔(内嵌汇编),防止gcc优化
init_sequence定义同时初始化。包含的board相关的初始化函数的指针
遍历以上的函数指针数组
uboot/cpu/s5pc11x.c -> cpu_init();
uboot/board/samsung/x210/x210.c -> board_init();
网卡初始化(不是驱动,硬件相关的)
配置开发板的机器码
cpu/s5pc11x/interrupts.c -> interrupt_init() 不是中断初始化,而是定时器4初始化(10ms)用来做delay
common/env_movi.c(有很多启动介质,选择相应版本) -> env_init 环境变量初始化
init_baudrate 波特率初始化
cpu/s5pc11x/serial.c serial_init //这里什么都没做,估计是uboot框架
common/console.c console_init_f 控制台初始化(_f表示first第一阶段初始化,r为第二部分初始化)
display_banner串口显示uboot第二部分,版本信息(此时串口未被初始化,使用putc,调用serial_putc操作寄存器发送)
控制台是软件虚拟的设备,最终映射到硬件实现。中间件可以实现缓冲
print_cpuinfo 打印cpu信息 时钟
checkboard //检查板信息
init_func_i2c //初始化软件/硬件IIC (X210中未使用)
dram_init //dram初始化,初始化dram软件信息
display_dram_config //打印显示dram信息
CFG_NO_FLASH相关 //NorFLASH的配置信息(实际中没有)
CONFIG_VFD //uboot自带虚拟显示(未开启)
CONFIG_LCD //uboot自带LCD显示相关(未开启)
CONFIG_MEMORY_UPPER_CODE //uboot堆管理器初始化,实现malloc/free
-Board Specific开发板独有的初始化
mmc_initialize...
--CONFIG_HAS_DATAFLASH 串行存储设备(这里没有)
env_relocate环境变量SD卡重定位到ddr。如果SD卡没有,则从代码中使用默认一套ENV
IP Address赋值
MAC Address赋值
devices_init 硬件驱动设备初始化
jumptable_init 跳转表(未使用)
console_init_r 控制台第二阶段初始化(纯软件初始化)
enable_interrupts 中断初始化(未使用中断、空的)
loadaddr、bootfile 环境变量初始化读出全局变量
board_late_init 板级最后的初始化。实际是空的
eth_initialize 网卡相关初始化(网卡本身的初始化)
*x210_preboot_init 启动前初始化(LCD相关初始化)
check_menu_update_from_sd 检查自动更新
main_loop----------最终到这里
UBOOT环境变量
作用:掉电保存全局变量,不用修改源码。环境变量优先级大于代码中的硬编码值。
工作方式: 1.刚烧录时,无环境变量,加载代码中的默认环境变量。-/common/env_common.c
2.SAVE时将DDR环境变量保存至SD卡中,下次启动时, \
uboot第二阶段env_relocate环境变量会被加载至DDR
getenv()UBOOT内部获取环境变量使用
UBOOT与linux驱动
uboot与linux驱动:
linux下MMU是开启的,驱动使用虚拟地址
linux驱动本身做了模块化设计
uboot/裸机,使用物理地址。uboot移植了linux的源代码。
uboot硬件驱动比linux简单
iNand/sd驱动解析:
从start_armboot:
/drivers/mmc/mmc.c -mmc_initialize
mmc初始化:Soc的mmc控制器初始化、时钟、GPIO的SFR初始化,芯片的初始化
1.cpu_mmc_init
/cpu/s5pc11x/setup_hsmmc.c 开启mmc时钟,
/cpu/s5pc11x/setup_hsmmc.c 初始化mmc相关gpio
smdk_s3c_hsmmc_init(); //三星开发板的mmc通道初始化
建立mmc结构体,调用mmc_register进行驱动注册,链表链接到mmc_devices
mmc_init()
2.mmc_init() mmc卡、芯片的初始化
由于函数以函数指针形式存在于结构体中,具体的操作函数是需要被绑定的
驱动框架思想:
每个驱动的关键数据结构(结构体),包含了成员属性、函数指针(成员函数)
即驱动就被抽象为了一个结构体。包含:驱动(构建一个结构体)初始化、驱动工作时操作函数和变量
分离思想:
驱动中将操作方法(函数)、数据(变量)分开:不同的位置来存储管理驱动的操作方法和变量
分层思想:分成不同的层次如soc层、bord层、软件层等
uboot210从三星移植
1.复制uboot,修改makefile中交叉编译工具,配置编译,可使用sd_fuing脚本烧录sd卡(注意参数) 2.看现象,失败,未打印"O",屏蔽start.s中的PMIC电源管理。uboot可工作 3.修改配置目标xxx_config,对应一个include/configs/xxx.h文件 修改xx.h的信息,lowleveinit.s-system_clock_init修改时钟配置(根据配置头文件) 修改ddr配置(配置文件):内存地址、内存大小 修改ddr为0x30000000 256MB+0x40000000 256MB 修改ddr寄存器 宏修改, ddr相关uboot宏修改,虚拟地址映射修改 SD(INAND驱动)问题: 问题现象-》定位错误代码-》错误需要修改的代码 网卡:DM9000-总线式,复用数据线地址线,接至SROMC1 配置网卡初始化函数,配置相关config宏
网卡驱动工作方式简介
linux中网卡生成的设备名一般是eth x/wlan x
linux使用专用命令来操作网卡
linux应用程序通过socket接口实现上网,应用层->socket接口 和驱动层->网络驱动框架 是完全分离的。由框架承接上下层。
uboot中操作网络相关的命令实际是直接操作驱动的,上下层并不完全分离。
uboot从uboot官方移植
版本差异:
新版uboot使用了linux kernel配置体系(kbuild.kconfig.menuconfig)
工作中一般不需要从uboot移植,而是soc厂商配套开发板移植
UBOOT启动内核
1.uboot本身是一个裸机程序:
-1.从启动角度看,操作系统内核本身也是一个裸机程序,OS可以分为内核层、应用层,操作权限不同。
-2.嵌入式系统,bootloader、kernel、rootfs都以镜像形式存在于介质中。运行时在DDR内存中
-3.启动过程就是由ROM到RAM启动硬件、软件达到运行状态的过程
-4.分区:预先设定的存储位置,以便指导启动(uboot\kernel\实际分区表必须一致)
-5.内核启动需要放置在预定链接地址,内核需要bootloader重定位到内存运行。需要启动参数
2.启动内核
从哪里加载:Flash、服务器...kernel分区(raw分区)
怎么加载:使用uboot命令读取 如movi(读写inand) bootm启动内核--实际是do_bootm函数
tftp 内存地址 镜像名--远程tftp下载(一般用于开发)
3.do_bootm函数 /common/Cmd_bootm.c
-1.条件编译执行secureboot(签名认证)
-2.CONFIG_ZIMAGE_BOOT宏控制zImage格式内核启动
-3.uboot 的ELF可执行程序使用objcopy生成bin可烧录镜像文件
-4.kernel生成vmlinux/vmlinuz ELF可执行程序 objcopy生成bin可烧录镜像image
将image压缩+解压代码(自解压)=zImage
zImage加工(64字节头信息)=uImage
zImage不是uboot原生支持的方式
uImage方式因设备树原因成为了历史版本:校验uImage得到kernel启动地址
bootm.c lib_arm/bootm.c
调用检查机器码,配置传参tag数据结构,启动
4.main_loop:获取、解析、执行命令
获取:console_buffer -> lastcommand
命令结构体数组放在自定义段中(开始结束地址即段的开始结束地址)
解析:parse_line将命令解析为argv find_cmd在命令集合中搜索命令
执行:run_command(const char *cmd, int flag)
UBOOT配置编译
uboot来源:uboot官方、SoC厂商、开发板供应商
-1.from 开发板供应商:九鼎
1.配置config
make xxx_config
得到:Configuring for x210_sd board... 配置完成
2.编译得到bin文件
检查arm-linux-gcc是否合适正确
主makefile中编译工具链路径名称是否正确
make -j4 多线程编译
分区
uboot :必须从flash起始地址(SoC的启动地址)存放。
一般设置512KB-1MB左右
var :uboot的环境变量表,紧挨uboot分区。32kB-1MB
kernel :大小一般3、5MB-N
rootfs
自由空间 :一般挂载到rootfs
分区在系统移植前应确定好,uboot与kernel使用同一个分区表,部署时按照系统代码的分区方法进行
DDR分区和FLASH分区不同。注意不要内存冲突即可
linux内核
操作系统:本质是一个程序,用来管理硬件,给应用程序提供运行环境
操作系统的核心功能: 内存管理、进程调度(多任务实现宏观并行)、硬件设备管理(OS控制硬件,APP不用管)、文件系统(管理存储设备) 操作系统的扩展功能:协议栈、有用的应用程序包 内核与发行版的区别: 内核仅实现核心功能,不包含应用程序:www.kernel.org 发行版(普通意义的操作系统):包含内核、协议栈、应用程序包… ------------------------------------------ 应用0|应用2|…|应用层-用户态 … kernel-内核态 … ------------------硬件---------------------
内核与驱动的关联
要有整体的认识,层次的作用清楚、层次关联互相调用要清楚。
驱动 (是内核的一部分、与硬件接轨)
内核中的硬件设备管理模块----驱动工作在内核态
内核权限高(无限制)、驱动故障可能导致内核崩溃、驱动漏洞会使内核不安全
内核、APP、rootfs系统的关联
应用程序不属于内核,工作在用户态,资源受限制,应用故障不会导致内核崩溃
应用程序-----调用----->内核API接口--内核驱动----->硬件
APP是最终目标,内核是为APP提供资源管理服务的
------------------------------------------
rootfs为操作系统提供根目录,进程1存放在根文件系统中
内核启动后会装载根文件系统,启动根目录的进程1
linux内核的模块化设计
内核各功能的代码是彼此独立的,如调度系统和内存管理系统没有全局变量的互相引用,函数调用也是遵循接口规范的(低耦合)
模块化体现:配置时可裁剪(源码级,静态变化)、模块化编译和安装(无需修改系统,动态变化)、源码中条件编译
模块化好处:可裁剪、灵活、可扩展性、利于协作,是一种普遍性的系统设计原则。
linux内核选择
版本:
linux0.01(初版)--0.11(适合阅读,较成熟)--2.4x(经典书籍多)--2.6早期(类似2.4晚期)--2.6晚期(驱动、头文件位置修改了)
linux3.x 4.x---linux5.16(2021.12最新版本)
linux目录结构
.linux5.15 ├── arch ***架构,如arm ├── block *块设备管理代码(逻辑代码),以块为整体,如sd卡、SSD、inand ├── certs ?证书处理? ├── COPYING -f -版权声明 ├── CREDITS -f -贡献名单 ├── crypto 校验、加密算法… ├── Documentation -文档 ├── drivers ***驱动文件夹 | ├──firmware 固件,原来在根文件目录,固化到IC里的代码,像IROM代码 ├── fs *filesystem,linux支持的文件系统的实现 ├── include ***各种架构的cpu,共用文件,特有的在arch/arm/include目录下 ├── init 内核的初始化 ├── ipc linux进程间通信代码实现 ├── Kbuild -f ├── Kconfig -f ├── kernel *makfile编译 ├── mm *内存管理相关代码 ├── net *网络相关代码(如TCP/IP协议) ├── README ├── samples -示例代码 ├── scripts 脚本文件,辅助linux内核配置编译生成的脚本文件 ├── security 安全相关代码 ├── sound *音频处理相关代码 ├── tools linux用到的工具 ├── usr *initramfs和linux内核启动有关 └── virt 内核虚拟机
linux内核配置、编译
步骤体验
1.make distclean检查makefile的CROSS_COMPILE和ARCH?=
2.第一步配置make 合适的.config make xxx_defconfig
3.第二步配置make menuconfig
4.make--make后的镜像在arch/arm/boot zImage
内核配置原理
配置是为了得到.config文件(可看作一个脚本),类似与uboot/include/configs/xxx_xx.h
内核用此文件指导整个编译、链接
make 合适的_defconfig解决大部分的配置项-可以避开很多不懂的配置项
相当于cp arch/arm/configs/合适的_defconfig ./.config
make menuconfig调整开发板细节
linux内核编译方法:编入,直接编译链接到zImage,去除即不编译链接,模块化即只编译单独链接到.ko文件进行动态加载卸载
menuconfig工具
menuconfig本身是一套软件支持,ncuress库实现文字图像界面
menuconfig本身读取Kconfig文件
显示菜单内容是由源码树各目录文件下的Kconfig提供支持,即能看到哪些菜单
menuconfig读取/写入.config
每个菜单的选择结果是保存到.config中的,即哪个=y哪个为注释..
Kconfig的格式
注释:#xxx
menuconfig (这是一个菜单)
config (菜单的项目)XXX (构成.config文件中的CONFIG_XXX=?)
tristate (三种选择状态)"菜单显示的名字"
bool (两种选择状态)"菜单显示的名字"
source (引用子Kconfig)"(path)/Kconfig"
depends on XXX (此配置项依赖于XXX配置项,也可进行逻辑运算)
select XXX(会自动选择的项目)
default x(默认配置值)
help 按下?后显示的帮助信息
=y =m =空 选项会导致CONFIG_XXX宏的值,最终导致makefile进行编译或内核makefile中将其链接为模块或不编译
内核分析(x210)
1.内核MIKEFILE 版本号定义 内核支持O=xxx,编译到一个文件夹 ARC\CROSS_COMPILE变量 2.lds链接脚本分析-找到程序入口 kernel链接脚本提供一个arch/($arch)/kernel/vmlinux.lds.S,真正得到的是vmlinux.lds,因此是动态的(可以借用预处理器)。 程序入口,编译后的lds中找到了ENTRY(stext) arch/arm/kernel/head-nommu.S arch/arm/kernel/head.S 3.head.S文件(校验,建立粗页表,c运行环境,b start_kernel) KERNEL_RAM_VADDR:虚拟内存地址=(KERNEL_OFFSET + TEXT_OFFSET) (5.x版本中)arch/arm/include/asm/memory.h中KERNEL_OFFSET=内核映像开始的虚拟地址 =PAGE_OFFSET= lowmem开始的虚拟地址,内存在上面=CONFIG_PAGE_OFFSET 在.config中定义为CONFIG_PAGE_OFFSET=0xC0000000 $(textofs-y)控制偏移 应该是0x8000 0000 但目前没找到在哪里定义,lds也+了这个偏移量 KERNEL_RAM_PADDR(新版内核已取消这个定义) XIP_KERNEL:原地执行 ENTRY(stext):kernel真正的入口,一般被解压代码调用的。需要MMU是关的,D-cache是关的。。UBOOT传递的参数:r0=0,r1=machine nr(机器码), r2 =atags pointer(参数所在的地址) ARM的函数调用传参是通过寄存器(还有一种是栈内存传参) MMU关的,没有页表,因此我们链接内核到了虚拟地址,但是又不可以用物理地址,因此内核开始运行时,没有虚拟地址,因此要用位置无关码。__pa(0x虚拟地址) 可以转换为物理地址。 linux kernel分配的mach id在/arch/arm/tools/mach-types文件 禁用中断,设置SVC模式 读出cp15,c0寄存器,读出processor id(cpu id),校验cpu id的合法性 machine id(机器码)的校验 _vet_atages uboot通过tage给内核传参的校验:内存分布memtag,uboot的bootargs… create_page_tables:建立段式页表(开启虚拟地址映射) -1-先建立一个段式页表(粗页表,以MB区分,每个页表用四个字节表示,总共需要16K).-2-再建立一个细页表(以4kb为单位),启动新的页表,废除段式页表 调用switch_data:存了一些地址和全局变量、函数 mmap_switched:复制数据段、清bss段(构建c运行环境),保存一些id号、atage… b start_kernel:跳转到c运行阶段 4.start_kernel–kenel/init/main.c文件 处理smp相关的:对称多处理器(相同的多核cpu) 锁定依赖处理:内核调试模块,处理内核自旋锁死锁。 cgroup:control groups内核提供用来处理进程组的技术 printk(内核用来从console打印调试信息,不同于printf的是可在参数前加一个打印级别的宏): linux控制台有消息过滤器,可根据设置来显示不同等级消息 linux_banner:字符串信息:版本、环境… setup_arch (处理cmdline-uboot给kernel传的bootargs)cpu架构的初始化过程,确定当前的架构,硬件平台相关的定义… default_command_line默认分配的全局命令 默认=CONFIGXXXX 定义一些描述硬件的结构体指针 setup_processor:查找cpu的类型,并打印cpu的相关信息 setup_machine:通过机器码查到这个板子machine_desc的描述符 __lookup_machine_type:内核链接时将各种cpu信息组成machine_desc结构体实例,使用.arch.info.init段属性链接在一起。 打印Machine:板的名字 如果传参atages不是空,则打印个信息 旧版风格的tage分析…并且将参数加载到内核的变量中 经过处理后,打印cmdline.(稍后会解析cmdline) 内存初始化相关 一些command_line处理:具体以后再说 多处理器相关:nr_cpu_ids、per_cpu_areas、smp_prepare_boot_cpu 打印kernel command line parse_early_param&parse_args:解析cmdline传参和其他传参,到字符串数组。目前没执行 内核初始化相关 trap_init:设置异常向量表 mm_init:内存管理模块初始化 sched_init:调度系统初始化 禁止抢占 中断初始化、定时器、软中断、时间系统… console_init:控制台初始化-在此前的打印信息是存在缓冲区的,控制台初始化后才能打印出 …等 构建内核环境、****加载驱动 rest_init:剩下的比较重要的初始化 rest_init:启动了两个kernel线程、cpu_idle进程 kernel_init线程(kernel_thread函数运行)进程1:最重要的进程,init进程 kthreadd线程(kernel_thread函数运行)进程2:内核守护进程,保证内核本身正常工作 schedule:开启内核的调度系统. 最终调用:cpu_idle-进程0(不返回):无任务时,执行空闲进程 进程和线程:应用层运行的程序构成一个进程/线程。内核运行一个函数,就是一个线程 进程:一个独立运行的程序任务(与其他程序独立,可被内核单独调用)用ps命令可以查看 进程0(空闲进程)是内核进程不是用户进程,故ubutu下看不到 线程:linux中,线程类似于进程,不同在于,线程是容易通讯 kernel_init-进程1:内核态向用户态转变。 这个进程有两个状态,init开始时是内核线程,运行了用户态程序后,将自己强转为用户态,后续进程都工作在用户态了。 内核态时:挂载根文件系统,试图找到用户态init程序。内核源码的所有函数都是内核态的,因此应用程序只能独立于内核源码。因此根文件系统是给内核提供用户态环境的。 用户态时:init大部分有意义的工作都在用户态下进行的。其他的用户进程都是由init进程派生的 如何从内核态转到用户态:init进程在内核态通过kernel_execve执行一个用户空间编译链接的init应用程序,就跳跃到了用户态。进程号未改变,跳跃过程是单向的。用户态要调用内核只能通过API。 init进程在用户态:构建用户交互功能。linux进程的创建是从父进程创建来的。 init启动了login进程(登录)、命令行进程、shell进程(解析执行命令行) shell进程启动其他用户进程 init源码: kenel_thead->kernel_init … 打开控制台设备,得到文件描述符编号。(linux中,设备也以文件形式存在,如/dev/buzzer代表蜂鸣器设备【真实设备】,console代表控制台设备【虚拟设备】) 复制了2次文件描述符。得到了三个文件描述符,分别为0、1、2,即标准输入、标准输出、标准输出。因此后续进程都默认具有这三个文件描述符(子进程会继承父进程的文件描述符)。 prepare_namespace:->mount_block_root挂载根文件系统 根文件系统位置、文件类型:bootloader会通过传参告诉kernel根文件系统的信息 root=/dev/mmcblk0p2 rw ->根文件系统的位置 rootfstype=ext3 ->根文件系统的类型 挂载rootfs成功后会打印出:VFS:Mounted root (xxx) on device xxx 如果挂载失败:uboot bootargs参数错误、根文件系统烧录失败(fastboot烧录不容易出错,代码烧录方式容易出错)、根文件系统本身有问题。 init_post->run_init_process(调用kernel_execve执行用户态进程1) 进入rootfs寻址init程序并执行 init程序确定方法:uboot cmdline指定(init=/xxx)/代码预先指定的(如:/sbin/init|/etc/init|/bin/init|/bin/sh) cmdline常用参数: 格式:xxx=yyyy【空格】->内核解析,影响内核启动 root=[根文件系统位置:/dev/mmcblk0p2(支持nfs网络文件系统)]->设备名可以在哪看? rootfstype=[文件系统类型:ext3] console=[控制台设备声明/dev/ttySAC0,115200->串口0,波特率115200] mem=[指定内存有多少] init=[进程1的pathname:/linuxrc] 产品出厂:rootfs会在物理存储器上 开发时:rootfs可以在nfs上 root=/dev/nfs nfsroot=[IP]:/pathname ip=[HOST IP]:[server IP]:[网关]:[子网]::[网卡]:[DHCP状态] 内核架构相关代码 arch:硬件架构有关代码 mach:machine architecture->一类machine定义,即相同soc。一个开发板对应一个.c文件 plat:平台设备驱动[可能类似于stm32的HAL],SOC(内部外设)硬件相关数据代码 include:架构相关头文件,不是通用的 头文件包含格式:xxx/yyy.h ->kernel/include/xxx/yyy.h drivers:硬件驱动 OTHERS:硬件无关代码,一般不会修改的
x210内核移植初体验
构建移植环境:
设置makefile: CROSS_COMPILE ARCH
make xx_defconfig
make/make O=xxx -jxx
运行kernel:
1.解压部分代码没有运行:
可能原因:解压地址应==链接地址对应的物理地址
解压地址在哪看:(物理地址).config ->0x3000 8000
链接地址在哪看:(虚拟地址).config ->0xc000 8000
查看自解压部分代码:/mach/makefile.boot
zreladdr-y:自解压的地址
param_phys-y:uboot参数地址
2.解压后没有正确运行
可能原因:某些地址不正确
3.内核中,机器码的确定
arch/arm/mach-xxx/mach-xxx.c 具体的文件要看makefile和.config文件
MACHINE_START宏&MACHINE_END;定义了一个结构体变量,会被链接到一个特定段
MACHINE_START(type,name)
.nr->mach id:xxx,对应uboot定义的值,对应一个开发板
.init_machine = xxx ->机器硬件初始化函数->绑定了内核初始化过程中的硬件信息
4.内核启动过程中的错误信息:
Oops信息-》内核错误的致命信息
kernel panic:内核抱怨信息
5.设备驱动问题
6.分区
UBOOT的->fdisk -c 0对iNand分区.已经写死了。分区信息是由iNAND本身的MBR传递的
如果是NAND,则分区表要在内核中构建->要与uboot中构建的一致
7.网卡
.config开启网卡
硬件由mach文件的结构体中.init_machine调用初始化
SOC的硬件配置
设备本身的配置
驱动数据配置
内核调试方法:
第0阶段:没打印信息
1.自解压代码
2.在第一阶段汇编开头操作LED操作代码,注意r0-r2被用作uboot传参
用于判断内核有没有被正常运行
第一阶段:
校验(CPU ID、板的机器码、传参tag)
创建页表
start_kernel
根文件系统
根文件系统存在的原因: init应用程序需要一个位置,存在根文件系统 根文件系统给内核提供了根目录/ 内核启动后应用层配置在根文件系统(/etc/) shell命令程序、cd程序… 只有内核没有配置文件、库文件、程序,是不能工作的。 根文件系统实质: 特殊用途的文件系统 根文件系统本身也属于某种文件系统格式 文件系统作用:存储设备是分 块/扇区 的,底层访问存贮设备是按块号/扇区号 访问。文件系统是一套对存储设备扇区管理的软件。将对扇区的访问变为对目录和文件名的访问。我们对pathname的访问会被文件系统转换为扇区号的访问。不同文件系统的差异在于对扇区的管理策略和方法不同。如坏块、碎片