我们知道,通过NOOBS系统,Raspberry Pi 2B(树莓派)可以在一张TF卡上安装多个操作系统,你可以在启运的过程中选择进入哪一个操作系统,这个功能是如何实现的呢,我们需要对Raspberry Pi 2B(树莓派)的开机过程进行深入了解,以便能将定制的系统安装到Raspberry Pi 2B(树莓派)上。
- 从相关的文档上看,系统开机的过程是这样的:(Standalone partitioning explained · raspberrypi_noobs Wiki · GitHub和NOOBS partitioning explained · raspberrypi_noobs Wiki · GitHub)
- 加载并运行bootcode.bin
- bootcode.bin运行时,加载并运行start.elf和fixup.dat
- start.elf读取config.txt, 对GPU进行配置
- start.elf读取cmdline.txt, 加载并运行kernel.img或者是kernel7.img(rpi 2b) 将cmdline.txt中的参数传递给kernel
- kernel运行并解析command line, 去挂载根文件系统
- kernel挂载根文件系统后,执行init进程,作linux系统的初始化
- NOOBS启动过程:
- 加载并运行bootcode.bin
- bootcode.bin发现start.elf文件不存在, 加载并执行recovery.elf
- recovery.elf读取recovery.cmdline, 加载recovery.img(kernel)或者是recovery7.img(rpi 2b)和recovery.rfs(initrd)
- recovery.img运行并解析recovery.elf传递过来的command line
- recovery.img将recovery.rfs文件作为根文件系统挂载,执行init进程初始化整个linux系统
NOTE: bootcode.bin, start.elf, kernel.img, kernel7.img, cmdline.txt, config.txt, recovery.elf, recovery.img, recovery.rfs, recovery.cmdline都是在SD卡的第一个FAT分区。start_cd.elf, fixup_cd.dat是cut-down版本, start_x.elf, fixup_x.elf是testing版本,具体请看这里: http://elinux.org/RPi_Software
- 在SD卡上支持多个系统的实现:
在recovery系统中,将要启动的系统的boot分区值写入/sys/module/bcm2708/parameters/reboot_part, 重启系统。
具体实现请看代码:https://github.com/raspberrypi/linux/blob/rpi-4.1.y/arch/arm/mach-bcm2709/bcm2709.c
reboot_part记录的的user space传过来的值,在系统重启时PM_RSTS记录重启的分区:
int calc_rsts(int partition) { return PM_PASSWORD | ((partition & (1 << 0)) << 0) | ((partition & (1 << 1)) << 1) | ((partition & (1 << 2)) << 2) | ((partition & (1 << 3)) << 3) | ((partition & (1 << 4)) << 4) | ((partition & (1 << 5)) << 5); } static void bcm2709_restart(enum reboot_mode mode, const char *cmd) { extern char bcm2708_reboot_mode; uint32_t pm_rstc, pm_wdog; uint32_t timeout = 10; uint32_t pm_rsts = 0; if(bcm2708_reboot_mode == 'q') { // NOOBS < 1.3 booting with reboot=q pm_rsts = readl(__io_address(PM_RSTS)); pm_rsts = PM_PASSWORD | pm_rsts | PM_RSTS_HADWRQ_SET; } else if(bcm2708_reboot_mode == 'p') { // NOOBS < 1.3 halting pm_rsts = readl(__io_address(PM_RSTS)); pm_rsts = PM_PASSWORD | pm_rsts | PM_RSTS_HADWRH_SET; } else { pm_rsts = calc_rsts(reboot_part); } writel(pm_rsts, __io_address(PM_RSTS)); /* Setup watchdog for reset */ pm_rstc = readl(__io_address(PM_RSTC)); pm_wdog = PM_PASSWORD | (timeout & PM_WDOG_TIME_SET); // watchdog timer = timer clock / 16; need password (31:16) + value (11:0) pm_rstc = PM_PASSWORD | (pm_rstc & PM_RSTC_WRCFG_CLR) | PM_RSTC_WRCFG_FULL_RESET; writel(pm_wdog, __io_address(PM_WDOG)); writel(pm_rstc, __io_address(PM_RSTC)); } /* We can't really power off, but if we do the normal reset scheme, and indicate to bootcode.bin not to reboot, then most of the chip will be powered off */ static void bcm2709_power_off(void) { extern char bcm2708_reboot_mode; if(bcm2708_reboot_mode == 'q') { // NOOBS < v1.3 bcm2709_restart('p', ""); } else { /* partition 63 is special code for HALT the bootloader knows not to boot*/ reboot_part = 63; /* continue with normal reset mechanism */ bcm2709_restart(0, ""); } }
如将/dev/mmcblk0p2格式化成FAT分区,将bootcode.bin, config.txt, start.elf, fixup.dat, cmdline.txt kernel7.img保存在这个分区
做如下操作就可以启动这个分区的系统(rpi2b, 待验证):
$ sudo echo 2 > /sys/module/bcm2709/parameters/reboot_part $ sudo reboot