驱动第一次答辩
一、嵌入式设备启动流程1、运行厂家固化在IROM里面的代码基本硬件初始化需要的时钟和设备判断对应的启动方式emmc;sd卡把bootloader第一阶段的代码加载到IRAM运行内存由于IROM是厂家过来的并不知道开发板采用的什么内存无法初始化所以不在IROM初始化内存2、在IRAM里运行对应的bootloader第一阶段的代码SPLu-boot-spl.bin初始化整个系统的时钟初始化内存把完整的bootloader搬移到内存中将第二阶段的 U-Boot完整的 u-boot.bin从存储介质eMMC/SD/NAND加载到 DRAM 中跳转到 DRAM 中的 u-boot.bin 去执行CPU执行需要速度而不易失的存储器通常访问速度很慢所以需要将代码从不易失的存储器转到易失的存储器bootRom只做简单操作而SRAM太小只能提供最小运行环境无法运行操作系统做大成本高所以需要更大的运行内存DDR上电无法直接运行由于IRAM在芯片内部存储空间有限如果内存太大很浪费资源所以bootloader要分两个阶段运行不直接在IRam里面运行还要搬运到内存里3、在内存里运行bootloader第二个阶段的代码初始化了一些硬件设备根据开发板去定义网卡串口USB完整系统网卡、USB、Flash、更多外设加载对应的操作系统内存4、运行操作系统没有图形化界面5、挂载文件系统 6、启动应用程序二、u-boot和linux内核之间参数传递因为内核启动时需要知道硬件信息如内存大小、根文件系统位置、启动参数等而U-Boot已经探测到了这些信息所以必须通过参数传递给内核才能正确启动硬件系统。参数传递方式通过寄存器寄存器传递内容r0固定为 0r1开发板的 ID让 Linux 内核判断是否支持当前开发板r2其他参数在内存中的开始地址r2 所保存的地址中存放的信息(1)内存的信息内存的开始地址和内存的大小因为bootloder刚开始对内存进行初始化u-boot就知道这些内存的信息(2)命令行参数bootargs 的内容如指定 Linux 内核启动后挂载文件系统的方式例如 NFS 方式(3)其他信息u_boot和Linux之间在传递参数的时候是按照双方约定的格式传递的所以u_boot引导没有告诉Linux内核可以访问的内存的大小Linux内核也知道它访问的参数结束的地方在哪里2.1 bootcmd:uboot启动完成读秒后自动执行从参数命令把文件从 TFTP 服务器加载到内存RAM临时的然后从内存启动setenv bootcmd tftp 0x41000000 uImage\;tftp 0x42000000 exynos4412-fs4412.dtb\;tftp 0x43000000 ramdisk.img\;bootm 0x41000000 0x43000000 0x42000000在板子上创建的文件没有办法进行保存因为运行在内存中断电就消失2.2 bootargsbootargs告诉文件系统在哪里找本质uboot(bootloader)给linux系统传递的-参数setenv bootargs root/dev/nfs nfsroot192.168.2.101:/home/hqyj/fs4412/rootfs,prototcp,nfsvers3,no_lock rw consolettySAC2,115200 init/linuxrc ip192.168.2.98参数含义root/dev/nfs指定根文件系统rootfs不是从本地块设备如 emmc/SD 卡挂载而是使用NFS 网络文件系统。内核会因此启用 NFS 根文件系统支持。nfsroot192.168.2.101:/home/hdyj/fs4412/rootfsNFS 服务器的 IP 和导出路径- 服务器 IP192.168.2.101- 共享目录/home/hdyj/fs4412/rootfs主机上存放根文件系统的位置prototcpNFS 使用TCP 协议而非 UDPTCP 更可靠适合大文件传输和长距离网络。nfsvers3使用NFS 版本 3常见于嵌入式开发兼容性好。noLock禁用 NFS 文件锁lockd。避免在无锁服务时出现警告或延迟常用于简单开发环境。rw根文件系统以读写read-write方式挂载允许在开发过程中修改文件。consolettySAC2,115200内核控制台输出到串口 2ttySAC2波特率115200。这是开发板与主机间调试信息的输出通道。init/linuxrc内核启动后执行的第一个用户态程序是/linuxrc通常是 BusyBox 提供的初始化脚本或软链接到/sbin/init。ip192.168.2.98给开发板自身指定静态 IP 地址192.168.2.98用于 NFS 挂载及网络通信。若不设也可用 DHCPipdhcp。三、Linux 内核配置与编译关系menuconfigLinux内核提供的菜单选项界面表示内核支持哪些功能好比去餐馆看到的菜单.configLinux内核当前选择的功能配置记录了你具体点了哪些菜好比点菜的凭证Kconfig为Linux内核提供菜单选项的定义好比当前餐馆所有厨师会做的菜Makefile管理Linux内核的编译过程根据.config里面的宏配置决定编译哪些代码好比厨师根据点菜单做菜Kconfig 定义了所有可选功能menuconfig 读取 Kconfig 显示图形化菜单让你选择你选好后保存到 .config 文件中最后 Makefile 读取 .config 根据配置编译对应的代码。四、Busybox init启动过程init linuxrc busybox 会去读取 inittab初始化表并加载和运行里面的内容inittab 文件格式id编号:权限等级:动作:进程即以什么编号、什么等级、什么动作去加载进程。id编号和权限等级可以省略。动作说明sysinit表示进程在系统启动后最先执行只执行一次init 进程等待它结束才继续执行其他动作wait表示进程在执行 sysinit 后执行只执行一次init 进程等待它结束才继续执行其他动作once表示进程在执行 wait 后执行只执行一次init 进程不等待它结束respawn表示进程在启动 once 后执行init 进程一旦发现该进程死掉就会重新启动它askfirst表示进程在启动完 respawn 后执行与 respawn 类似不过 init 进程会先输出提示Please press Enter to activate this console等用户输入回车后才启动子进程restart如果 BusyBox 中配置了CONFIG_FEATURE_USE_INITTAB并且 init 进程收到SIGHUP 信号时先重新读取/解析/etc/inittab文件再执行该进程shutdown表示进程在系统收到重启、关闭系统命令时运行ctrlaltdel表示进程在按下CtrlAltDel组合键时运行rcS1. 内核启动 ↓ 2. 执行 /sbin/initBusyBox 提供的 init ↓ 3. 读取 /etc/inittab ↓ 4. 执行 ::sysinit:/etc/init.d/rcS ↓ 5. rcS 脚本执行 /bin/mount -a ↓ 6. mount -a 读取 /etc/fstab ↓ 7. 挂载 fstab 中定义的所有文件系统 proc、sysfs、tmpfs、dev 等proc— Linux内核的资源进程资源 →/proc这个目录tmpfs— 临时存储的空间 →/tmp这个目录sysfs— Linux子系统GPIO、PWM、I2C →/sys这个目录tmpfs— Linux的设备挂载 →/dev目录挂载与创建挂载设备是把存储设备或虚拟文件系统如/proc挂到 Linux 目录树上让系统能通过路径访问其内容对应配置文件是/etc/fstab由mount -a读取执行。创建设备是在/dev下生成设备节点文件让应用程序通过该文件与硬件或内核驱动通信由/etc/init.d/rcS中的mdev -s扫描/sys动态生成。两者分工明确挂载解决“怎么访问文件系统”创建设备解决“怎么访问硬件设备”。挂载依赖/etc/fstab创建设备依赖mdev。五、Linux 启动过程分析一级页表虚拟地址和物理地址一一对应的映射表MMU 是 CPU 中实现虚拟地址到物理地址转换和内存访问控制的硬件单元清理bss端让没有初始化的全局变量和静态全局变量为0如果没有就是随机值SP 是 CPU 的栈指针寄存器指向当前栈顶地址为 C 函数调用和局部变量提供内存空间。后面重建的页表多个虚拟地址可能对应一个物理地址六、U-boot启动过程分析开发板上电 ↓ ARM核设置SVC模式、异常向量、关闭Cache/MMU ↓ SoC设置唤醒处理、判断运行位置 ↓ ┌─────────────────────────────────────────────────────┐ │ 第一阶段SPLCONFIG_SPL_BUILD 有效 │ │ ↓ │ │ 初始化系统时钟和内存控制器DRAM │ │ ↓ │ │ 初始化UART、设置SP │ │ ↓ │ │ board_init_f → 将u-boot从存储介质搬移到DRAM │ │ ↓ │ │ 跳转到DRAM中的u-boot.bin第二阶段 │ └─────────────────────────────────────────────────────┘ ↓ ┌─────────────────────────────────────────────────────┐ │ 第二阶段完整U-BootCONFIG_SPL_BUILD 无效 │ │ ↓ │ │ board_init_f重定向前 │ │ ├── 执行板级初始化序列表 │ │ └── 为重定向预留高端内存 │ │ ↓ │ │ u-boot重定向从低端搬移到高端内存 │ │ ↓ │ │ 清BSS段 │ │ ↓ │ │ board_init_r重定向后 │ │ ├── 外围硬件初始化网卡、Flash等 │ │ └── 进入命令行等待用户输入或自动加载内核 │ └─────────────────────────────────────────────────────┘SVC 模式ARM 的最高特权运行模式U-Boot 切换到此模式以便完全控制硬件。判断是否在内存中运行如果不在内存中运行则初始化系统时钟和内存控制器第一阶段如果在内存中运行则不需要初始化系统时钟和内存控制器第二阶段U-Boot 完成所有硬件初始化后会调用main_loop()进入一个无限循环等待处理用户命令或自动启动。判断是否自动启动检查环境变量bootdelay等待时间单位秒和bootcmd自动执行的命令。如果设置了这两个变量在bootdelay倒计时结束前串口是否有输入有输入比如按了任意键→ 中断自动启动进入命令行交互模式等待用户手动输入命令。没有输入倒计时结束→执行bootcmd中的命令通常是用 TFTP 下载内核、设备树然后调用bootm启动 Linux。问题总结u-boot参数是如何传递给linux内核的profile脚本文件里面的代码信息是什么用