学习笔记——Linux内核与嵌入式开发2

一、Linux启动流程详解

1.1 SD卡启动流程

1.1.1 四阶段启动过程
复制代码
第一阶段:i.MX6内部ROM启动
第二阶段:SD卡中的Bootloader执行
第三阶段:内核加载与启动
第四阶段:根文件系统挂载
1.1.2 详细步骤
  1. 系统上电执行内部ROM程序

    • i.MX6内部有96KB ROM

    • ROM中的程序根据boot mode选择启动设备(SD卡、eMMC、USB等)

    • 如果选择SD卡启动,从SD卡特定位置读取Bootloader

  2. 加载Bootloader第一部分

    • 拷贝SD卡中的Bootloader前半部分到i.MX6内部RAM(128KB)

    • 内部RAM大小有限,Bootloader必须分阶段执行

    • Bootloader第一部分(SPL)负责初始化DDR内存

  3. Bootloader第二阶段执行

    • Bootloader在自身前半部分初始化好DDR内存

    • 将自己后半部分从SD卡搬移到DDR内存执行

    • 完成完整的硬件初始化

  4. 内核加载与启动

    • Bootloader从SD卡读取内核镜像(zImage)

    • 将zImage加载到内存地址0x80800000处

    • PC指针指向0x80800000,启动内核执行

  5. 挂载根文件系统

    • 内核启动完成后

    • 根据启动参数挂载SD卡上的根文件系统

    • 进入用户空间

1.2 网络启动流程(TFTP+NFS)

1.2.1 网络启动环境
复制代码
硬件连接:
开发板(192.168.1.100) ↔ 交换机/路由器 ↔ Ubuntu服务器(192.168.1.3)

软件服务:
TFTP服务器:提供内核镜像下载
NFS服务器:提供根文件系统共享
1.2.2 详细步骤
  1. Bootloader网络初始化

    • Bootloader初始化网卡驱动

    • 设置IP地址:192.168.1.100

    • 设置服务器IP:192.168.1.3

  2. TFTP下载内核

    • Bootloader通过TFTP协议从Ubuntu下载zImage

    • 命令:tftp 0x80800000 zImage

    • 将zImage下载到内存0x80800000地址处

  3. TFTP下载设备树

    • 下载设备树二进制文件(.dtb)

    • 命令:tftp 0x83000000 imx6.dtb

    • 将设备树加载到内存0x83000000地址处

  4. 启动内核

    • 命令:bootz 0x80800000 - 0x83000000

    • 从0x80800000启动内核,设备树在0x83000000

  5. NFS挂载根文件系统

    • 内核通过NFS协议挂载Ubuntu上的根文件系统

    • 根据bootargs参数配置NFS挂载

1.3 混合启动方式

1.3.1 内核在SD卡,根文件系统在NFS
复制代码
优点:
- 内核启动速度快(本地加载)
- 根文件系统方便更新(网络共享)
- 适合内核稳定、根文件系统频繁修改的场景
1.3.2 内核通过网络,根文件系统在SD卡
复制代码
优点:
- 内核更新方便(网络下载)
- 根文件系统稳定(本地存储)
- 适合内核频繁调试的场景

二、Ubuntu开发环境准备

2.1 TFTP服务器配置

2.1.1 安装TFTP服务
复制代码
# 安装TFTP服务器
sudo apt install tftpd-hpa

# 安装TFTP客户端(用于测试)
sudo apt install tftp-hpa
2.1.2 配置TFTP服务
复制代码
# 编辑配置文件
sudo vim /etc/default/tftpd-hpa

# 配置文件内容示例
TFTP_USERNAME="tftp"
TFTP_DIRECTORY="/tftpboot"
TFTP_ADDRESS=":69"
TFTP_OPTIONS="--secure --create"
2.1.3 创建TFTP目录
复制代码
# 创建TFTP服务目录
sudo mkdir /tftpboot

# 设置目录权限
sudo chmod 777 /tftpboot
sudo chown nobody:nogroup /tftpboot
2.1.4 重启服务
复制代码
# 重启TFTP服务
sudo systemctl restart tftpd-hpa

# 查看服务状态
sudo systemctl status tftpd-hpa

# 设置开机自启
sudo systemctl enable tftpd-hpa
2.1.5 放置内核文件
复制代码
# 将内核镜像复制到TFTP目录
cp zImage /tftpboot/
cp imx6.dtb /tftpboot/

# 确保文件可读
chmod 644 /tftpboot/zImage
chmod 644 /tftpboot/imx6.dtb

2.2 NFS服务器配置

2.2.1 安装NFS服务
复制代码
# 安装NFS服务器
sudo apt install nfs-kernel-server

# 安装NFS客户端(可选)
sudo apt install nfs-common
2.2.2 配置NFS共享
复制代码
# 编辑配置文件
sudo vim /etc/exports

# 添加共享配置
/home/linux/nfs *(rw,sync,no_root_squash,no_subtree_check)

# 或者更安全的配置
/home/linux/nfs 192.168.1.0/24(rw,sync,no_root_squash,no_subtree_check)

参数说明

  • rw:读写权限

  • sync:同步写入

  • no_root_squash:信任root用户

  • no_subtree_check:不检查子目录权限

  • 192.168.1.0/24:只允许指定网段访问

2.2.3 创建共享目录
复制代码
# 创建NFS共享目录
mkdir -p /home/linux/nfs

# 创建根文件系统子目录
mkdir -p /home/linux/nfs/imx6/rootfs
2.2.4 解压根文件系统
复制代码
# 进入NFS目录
cd /home/linux/nfs/imx6

# 解压根文件系统
sudo tar -xvf rootfs.tar.bz2 -C rootfs/

# 设置权限(如果需要)
sudo chmod 755 rootfs
2.2.5 重启NFS服务
复制代码
# 重新导出共享目录
sudo exportfs -arv

# 重启NFS服务
sudo systemctl restart nfs-kernel-server

# 查看服务状态
sudo systemctl status nfs-kernel-server

# 查看共享目录
sudo showmount -e localhost

2.3 网络配置检查

2.3.1 网络连通性测试
复制代码
# 检查Ubuntu IP地址
ip addr show

# 检查网络连通性(开发板ping服务器)
# 在开发板上执行:ping 192.168.1.3

# 检查服务器是否能访问开发板
ping 192.168.1.100
2.3.2 防火墙配置
复制代码
# 检查防火墙状态
sudo ufw status

# 如果防火墙开启,需要开放端口
sudo ufw allow 69/tcp    # TFTP
sudo ufw allow 69/udp    # TFTP
sudo ufw allow 111/tcp   # NFS
sudo ufw allow 2049/tcp  # NFS
sudo ufw allow 2049/udp  # NFS

# 或者临时关闭防火墙(开发环境)
sudo ufw disable

三、U-Boot命令详解

3.1 基础命令操作

3.1.1 帮助与信息查询
复制代码
# 查看所有可用命令
help
或
?

# 查看特定命令帮助
help command_name
例:help tftp
3.1.2 重启命令
复制代码
# 重启系统
reset

# 重启到不同模式
reset recovery    # 恢复模式
reset fastboot    # 快速启动模式

3.2 环境变量管理

3.2.1 环境变量查看
复制代码
# 查看所有环境变量
printenv
或
print

# 查看特定环境变量
printenv variable_name
例:
printenv ipaddr
printenv bootargs
3.2.2 环境变量设置
复制代码
# 设置环境变量
setenv name value

# 示例:
setenv ipaddr 192.168.1.100
setenv serverip 192.168.1.3
setenv bootdelay 3

# 设置多行变量(用于bootargs)
setenv bootargs 'console=ttymxc0,115200 root=/dev/nfs nfsroot=192.168.1.3:/home/linux/nfs/imx6/rootfs,nfsvers=3 ip=192.168.1.100 init=/linuxrc'
3.2.3 环境变量删除
复制代码
# 删除环境变量(将值设为空)
setenv name

# 示例:
setenv old_ip
setenv unused_var
3.2.4 环境变量保存
复制代码
# 保存环境变量到存储设备
saveenv

# 保存位置一般为MMC/SD卡或Flash
# 查看保存的设备
printenv boot_device

3.3 网络相关环境变量

3.3.1 必需的网络变量
复制代码
# 开发板IP地址
setenv ipaddr 192.168.1.100

# 服务器IP地址(TFTP/NFS服务器)
setenv serverip 192.168.1.3

# MAC地址(硬件唯一标识)
setenv ethaddr 00:04:9f:01:02:03

# 子网掩码
setenv netmask 255.255.255.0

# 网关地址
setenv gatewayip 192.168.1.1
3.3.2 可选网络变量
复制代码
# 第二个网卡MAC地址
setenv eth1addr 00:04:9f:01:02:04

# 网络设备名
setenv nvlan 1
setenv vlan 1
setenv devtype ethernet

3.4 TFTP操作命令

3.4.1 TFTP下载命令格式
复制代码
# 基本格式
tftp [loadAddress] [[hostIPaddr:]bootfilename]

# 下载内核到内存
tftp 0x80800000 zImage

# 下载设备树到内存
tftp 0x83000000 imx6.dtb

# 指定服务器IP下载
tftp 0x80800000 192.168.1.3:zImage
3.4.2 TFTP下载过程
  1. 设置服务器IP

    复制代码
    setenv serverip 192.168.1.3
  2. 设置开发板IP

    复制代码
    setenv ipaddr 192.168.1.100
  3. 测试网络连接

    复制代码
    ping 192.168.1.3
  4. 下载内核

    复制代码
    tftp 0x80800000 zImage
  5. 下载设备树

    复制代码
    tftp 0x83000000 imx6.dtb

3.5 内核启动命令

3.5.1 启动命令格式
复制代码
# 基本格式
bootz [内核地址] [initrd地址] [设备树地址]

# 常用格式(无initrd)
bootz 0x80800000 - 0x83000000

# 含义:
# 0x80800000 - 内核zImage加载地址
# -          - 无initrd(ramdisk)
# 0x83000000 - 设备树加载地址
3.5.2 启动参数设置
复制代码
# 设置完整的启动参数
setenv bootargs console=ttymxc0,115200 root=/dev/nfs nfsroot=192.168.1.3:/home/linux/nfs/imx6/rootfs,nfsvers=3 ip=192.168.1.100 init=/linuxrc

# 参数解析:
# console=ttymxc0,115200  - 串口控制台,波特率115200
# root=/dev/nfs           - 根文件系统类型为NFS
# nfsroot=192.168.1.3:/home/linux/nfs/imx6/rootfs - NFS服务器路径
# nfsvers=3              - NFS版本3
# ip=192.168.1.100       - 开发板IP地址
# init=/linuxrc          - 第一个用户空间进程
3.5.3 自动启动设置
复制代码
# 设置自动启动命令
setenv bootcmd 'tftp 0x80800000 zImage; tftp 0x83000000 imx6.dtb; bootz 0x80800000 - 0x83000000'

# 保存设置
saveenv

# 测试自动启动
run bootcmd

3.6 其他实用命令

3.6.1 内存操作
复制代码
# 查看内存内容
md.b 0x80800000 10    # 以字节格式查看
md.w 0x80800000 10    # 以字格式查看
md.l 0x80800000 10    # 以长字格式查看

# 修改内存内容
mw.l 0x80800000 0x12345678 1

# 内存比较
cmp 0x80800000 0x80900000 100
3.6.2 存储设备操作
复制代码
# 查看MMC设备
mmc list

# 选择MMC设备
mmc dev 0     # 选择设备0
mmc dev 0 1   # 选择设备0的分区1

# 读取MMC信息
mmc info

# 从MMC读取数据
mmc read 0x80800000 0x600 0x800

四、启动参数详解

4.1 bootargs参数解析

4.1.1 控制台配置
复制代码
console=ttymxc0,115200
# ttymxc0 - i.MX6的串口设备名
# 115200  - 波特率
# 其他可选值:9600, 19200, 38400, 57600, 115200
4.1.2 根文件系统配置
复制代码
root=/dev/nfs
# /dev/nfs - 表示使用NFS作为根文件系统
# 其他选项:/dev/mmcblk0p2(SD卡分区), /dev/mtdblock2(Flash)
4.1.3 NFS配置
复制代码
nfsroot=192.168.1.3:/home/linux/nfs/imx6/rootfs,nfsvers=3
# 192.168.1.3 - NFS服务器IP
# /home/linux/nfs/imx6/rootfs - 共享目录路径
# nfsvers=3 - NFS协议版本
4.1.4 网络配置
复制代码
ip=192.168.1.100
# 开发板IP地址
# 完整格式:ip=<client-ip>:<server-ip>:<gw-ip>:<netmask>:<hostname>:<device>:<autoconf>
4.1.5 Init进程配置
复制代码
init=/linuxrc
# /linuxrc - 第一个用户空间进程
# 通常是/bin/init或/sbin/init的符号链接

4.2 其他常用参数

4.2.1 内存参数
复制代码
mem=512M
# 指定内存大小
# 当系统内存检测不正确时使用
4.2.2 调试参数
复制代码
debug
# 启用内核调试信息

loglevel=8
# 设置日志级别(0-8,8最详细)

earlyprintk
# 早期控制台输出,用于调试启动问题
4.2.3 文件系统参数
复制代码
rw
# 以读写方式挂载根文件系统

noinitrd
# 不使用initrd(ramdisk)

五、故障排查指南

5.1 常见问题与解决方案

5.1.1 TFTP下载失败
复制代码
问题:tftp命令执行后没有反应或超时
解决:
1. 检查网络连接:ping 192.168.1.3
2. 检查TFTP服务状态:sudo systemctl status tftpd-hpa
3. 检查文件权限:确保/tftpboot/zImage可读
4. 检查防火墙:sudo ufw status
5.1.2 NFS挂载失败
复制代码
问题:内核启动后卡在NFS挂载
解决:
1. 检查NFS服务:sudo showmount -e localhost
2. 检查exports配置:sudo cat /etc/exports
3. 检查目录权限:确保共享目录存在且可访问
4. 检查网络配置:ip addr show
5.1.3 内核启动失败
复制代码
问题:bootz命令后系统无响应
解决:
1. 检查内核地址:确保与加载地址一致
2. 检查设备树地址:确保正确加载
3. 检查串口输出:查看错误信息
4. 检查内存配置:确保足够内存
5.1.4 环境变量丢失
复制代码
问题:重启后环境变量恢复默认
解决:
1. 确保执行saveenv保存
2. 检查存储设备:printenv boot_device
3. 检查存储空间:确保有足够空间
相关推荐
我是黄骨鱼1 小时前
【零基础学数据库|第四篇】SQL通用语法学习
学习
哎呦 你干嘛~1 小时前
plc仿真来控制单片机
单片机·嵌入式硬件
Fᴏʀ ʏ꯭ᴏ꯭ᴜ꯭.1 小时前
Nginx性能调优与压测实战指南
运维·nginx
郝学胜-神的一滴1 小时前
深入Linux网络编程:accept函数——连接请求的“摆渡人”
linux·服务器·开发语言·网络·c++·程序人生
ℳ๓. Sweet2 小时前
【STM32】关于DMA发送后立刻复位单片机导致无法正确发送的问题
stm32·单片机·嵌入式硬件
恒锐丰小吕2 小时前
屹晶微 EG2136S 600V三相半桥驱动芯片技术解析
嵌入式硬件·硬件工程
小义_2 小时前
【Docker】知识一
linux·docker·云原生·容器
三佛科技-134163842122 小时前
多功能奶泡机MCU方案开发设计分析
单片机·嵌入式硬件·物联网·智能家居·pcb工艺
lichenyang4532 小时前
Node.js AI 开发入门 - 完整学习笔记
人工智能·学习·node.js