树莓派没有板载的只读存储器(Read Only Memory, ROM),软件需要安装在microSD卡上。为了方便软件管理,microSD卡一般可以分成两个分区:第一个分区安装引导器、内核映像;第二个分区安装操作系统。当选择Linux操作系统时,第一个分区格式化成VFATFS(以下称BOOT分区),第二个分区作为Linux的根文件系统,必须支持inode。Linux支持的文件系统很多,如Ext2/Ext3/Ext4FS文件系统、ReiserFS文件系统、YAFFS文件系统等。本书中统一使用Ext4FS(以下称Ext4分区)。
将microSD卡插入PC,使用fdisk命令的-l选项,可以看到当前所有磁盘的分区情况:
# fdisk -l ... Disk /dev/mmcblk0: 3648 MB, 3825205248 bytes, 7471104 sectors 116736 cylinders, 4 heads, 16 sectors/track Units: cylinders of 64 * 512 = 32768 bytes Device StartLBA EndLBA Sectors Size Id Type /dev/mmcblk0p1 2048 198655 196608 96.0M e Win95 FAT16 /dev/mmcblk0p2 198656 7471103 7272448 3551M 83 Linux
一些笔记本带有SD卡插槽。通过SD适配器[见图1.7(a)]插入笔记本电脑的microSD卡会被识别为MMC设备,设备文件是/dev/mmcblk0(也可能是/dev/mmcblk1);如果通过USB读卡器转接(见图1.7(b)),设备文件名可能是/dev/sdb或/dev/sdc,取决于内核对设备的识别情况。操作时务必认清操作对象,因为此时使用了超级用户权限,错误的操作将可能导致PC系统软件故障。上面操作的是一个4GB的SD卡(因计算方法问题,实际显示的是3684MB),目前有两个分区,第一分区96MB、FAT16格式(分区格式Id 为e),剩余空间分给第二分区,Linux格式(分区格式Id为83)。在本书讨论的系统设计中,所有软件安装后可控制在4GB以内。如果使用16GB的microSD卡进行开发,则基本可以不用操心存储空间问题。
图1.7 microSD卡适配器
用不带选项的fdisk命令进入分区操作环境:
# fdisk /dev/mmcblk0
首先使用fdisk的d命令删除原有的分区,再使用n命令创建两个新的分区。未经压缩的Linux内核映像大小约20MB,再考虑Bootloader的占用,第一分区可留出256MB,剩余部分留给第二分区。然后使用w命令将分区表写入SD卡,保存分区划分方式,退出fdisk环境。
再使用mkfs命令分别对这两个分区格式化:
# mkfs.vfat /dev/mmcblk0p1 # mkfs.ext4 /dev/mmcblk0p2
拔出SD卡再重新插入,如果PC识别出两个磁盘分区,表示以上分区无误。
Bootloader(引导加载器)的目的是加载操作系统内核,向内核传递参数,加载根文件系统,引导操作系统运行。Bootloader还负责核心软件的升级。一旦操作系统启动,Bootloader的任务便暂告终结,直到系统重启。
树莓派的Bootloader没有开放源代码,但二进制代码允许免费获得。二进制代码在https://www.github.com/raspberrypi/firmware/下。使用时,只需要将这个项目下的boot目录中的内容复制到microSD卡的BOOT分区。其中的.dtb文件和overlays目录中的.dtbo文件在编译内核时生成,可以将相应的文件进行替换。kernel*.img是内核映像文件,其编译过程将在后面介绍。重要的配置文件有两个:config.txt和cmdline.txt(文本文件)。
config.txt用于设置系统时钟、GPU内存分配、显示器设置、内核引导方式等。其中与内核启动相关的设置如下:
initramfs initramfs.gz followkernel kernel kernel8.img cmdline cmdline.txt device_tree=bcm2711-rpi-4-b.dtb
它表明内核映像文件是kernel8.img,内核启动的命令行信息写在cmdline.txt文件中,以initramfs.gz作为初始化RAMDisk根文件系统,设备树文件是bcm2711-rpi-4-b.dtb。device_tree项的设置不是必需的,Bootloader会根据硬件平台选择相应的设备树文件。
Bootloader向内核传递的启动参数写在cmdline.txt文件中,一般会传递下面的参数:
console=tty1 console=ttyAMA0,115200 kgdboc=ttyAMA0,115200 \ root=/dev/mmcblk0p2 rootfstype=ext4 elevator=deadline \ fsck.repair=yes rootwait
以上设置了本机显示器终端tty1和串口终端ttyAMA0、根文件系统和类型。顾名思义,cmdline是传递给内核的命令行参数,它必须写在一行。下面在向该文件添加内容时也不能无续行符换行。
从Bootloader向Linux内核传递的参数通过PROCFS文件系统传到/proc/cmdline文件中,内核启动的初始化脚本会读取这些参数,根据这些参数确定系统的行为。