1.总体流程:
处理器上电后,首先执行引导程序,引导程序把内核加载到内存,然后执行内核,内核初始化完成后,执行用户空间的第一个程序;
1.1.上电后的第一条指令;
嵌入式设备通常使用NOR闪存作为只读存储器来存放引导程序,NOR闪存的容量比较小,最小读写单位是字节,程序可以直接在芯片内执行;对于ARM64处理器,
从物理地址0开始的一段物理地址空间被分配给NOR闪存;从物理地址0取第一条指令;
例如更新uboot可以把镜像放在emmc里,芯片是怎么从这里读取的
root:~# lsblk
NAME MAJ:MIN RM SIZE RO TYPE MOUNTPOINTS
mmcblk0 179:0 0 57.6G 0 disk
|-mmcblk0p1 179:1 0 4M 0 part
|-mmcblk0p2 179:2 0 4M 0 part
|-mmcblk0p3 179:3 0 64M 0 part
|-mmcblk0p4 179:4 0 128M 0 part
|-mmcblk0p5 179:5 0 32M 0 part
|-mmcblk0p6 179:6 0 14G 0 part
|-mmcblk0p7 179:7 0 128M 0 part /oem
`-mmcblk0p8 179:8 0 43.3G 0 part /userdata
mmcblk0boot0 179:32 0 4M 1 disk
mmcblk0boot1 179:64 0 4M 1 disk
zram0 254:0 0 0B 0 disk
/* 用如下命令把uboot放到指定分区 */
dd if=uboot.img of=/dev/mmcblk0p1
sync
1.2.u-boot入口_start
把uboot存储设备读到内存中开始执行
arch/arm/lib/crt0_64.S
设置临时的栈,初始化结构体global_data;
1.为何一开始不把system模块直接移动到,0地址处?
因为boot程序加载操作需要使用 ROM BIOS 提供的中断过程,而 BIOS 使用的中断向量表正处于内存 0 开始的地方,并且在内存 1KB 开始处是 BIOS 程序使用的数据区,所以若直接把 head 代码加载到内存 0 处将使得 BIOS中断过程不能正常运行。
2.启动后用户空间运行
init进程是用户空间的第一个进程,负责启动用户程序;
sysvninit启动配置文件是"/etc/inittab",用来指定要执行的程序以及在哪些运行级别执行这些程序;
单独编译的内核模块,在启动时加载模块,可以利用脚本/etc/init.d/rcS
前提,模块被放在了/lib/modules/$(/bin/uname -r)/xxx.ko
/* /etc/init.d/rcS */
# 首先更新模块依赖关系数据库
echo "Updating module dependencies..."
/sbin/depmod -a
# 加载自定义模块
echo "Loading xxx module..."
/sbin/modprobe xxx