在上一篇博客中,我们已经在树莓派中正常的启动了u-boot,并把控制权交给了u-boot,那么我们如果要正常的使用一个linux系统的话,就还需要通过u-boot去引导一个linux系统,将系统控制权交给linux。所以在本篇博客中,我们首先制作一个最小的linux系统,然后再让u-boot去引导它。
树莓派3B
SD卡
读卡器
linux kernel源码:https://github.com/raspberrypi/linux.git
busybox源码:https://busybox.net/downloads/
说明:在本文中,我是用的busybox源码是busybox-1.31.0,linux kernel源码是linux-rpi-4.19.y
首先,我们需要构建一个最小的linux文件系统,也就是放在我上一篇博客中提到的rootfs分区。而busybox作为linux系统的瑞士军刀,提供了三百多个常用的linux命令和工具软件,如ls,cd,cat等等,所以,在这里我们使用busybox去构建一个最小的linux文件系统。
首先进入busybox源码目录,只想下面的命令。生成配置.config文件
make defconfig
之后,如还需要进行一些自定义的配置,可以通过make menuconfig命令,进行图形化配置
make menuconfig
在图形化界面,进入Settings 、设置Cross conpiler prefix 和install 目录
在这里我将交叉编译器设置为arm-linux-gnueabi-,安装目录为当前目录的rootfs目录,这个你可以根据你的交叉编译器自己设定。
设置后,保存并退出。
然后再源码根目录make,进行编译。
编译完成后,执行make install
然后,你就会在当前目录下,看到一个rootfs目录,该目录下,会有bin、sbin、usr三个文件夹和linuxrc文件,当然这三个文件夹还是不够的
1、首先创建一些必备的文件夹
mkdir dev etc lib mnt proc sys tmp var
/*
* 说明
* dev 目录主要共系统生成各类设备节点
* etc 系统的配置文件
* lib 系统需要的各类库文件
* mnt 一般用来挂载其他设备的的目录
* sys 系统文件
* tmp 临时文件
* var
* proc 内存虚拟文件系统节点
*/
2、在etc目录下,创建init.d文件夹
3、在init.d文件夹下,创建rcS文件 vim rcS,并输入以下内容:
#! /bin/sh
PATH=/sbin:/bin:/usr/sbin:/usr/bin:/usr/local/bin:
runlevel=S
prevlevel=N
umask 022
export PATH runlevel prevlevel
#
# Trap CTRL-C &c only in this shell so we can interrupt subprocesses.
#
trap ":" INT QUIT TSTP
/bin/hostname 4Log
#/bin/mount -n -t proc none /proc
#/bin/mount -n -t sysfs none /sys
#/bin/mount -n -t usbfs none /proc/bus/usb
#/bin/mount -t ramfs none /dev
[ -e /proc/1 ] || /bin/mount -n -t proc none /proc
[ -e /sys/class ] || /bin/mount -n -t sysfs none /sys
[ -e /dev/tty ] || /bin/mount -t ramfs none /dev
# support hotplug with mdev
echo /sbin/mdev > /proc/sys/kernel/hotplug
/sbin/mdev -s
# mounting file system specified in /etc/fstab
mkdir -p /dev/pts
mkdir -p /dev/shm
/bin/mount -n -t devpts none /dev/pts -o mode=0622
/bin/mount -n -t tmpfs tmpfs /dev/shm
#/bin/mount -n -t ramfs none /tmp
#/bin/mount -n -t ramfs none /var
mkdir -p /var/empty
mkdir -p /var/log
mkdir -p /var/log/boa
mkdir -p /var/lock
mkdir -p /var/run
mkdir -p /var/tmp
ln -sf /dev/ttyS2 /dev/tty2
ln -sf /dev/ttyS2 /dev/tty3
ln -sf /dev/ttyS2 /dev/tty4
syslogd
#echo "-------------------------------------"
#echo " 4Log "
#echo "-------------------------------------"
然后将修改rcS文件权限
chmod 755 rcS
4、在etc目录创建passwd文件,并键入以下内容:
root::0:0:root:/:/bin/sh
bin:*:1:1:bin:/bin:
daemon:*:2:2:daemon:/sbin:
nobody:*:99:99:Nobody:/:
修改权限
chmod 755 passwd
5、在etc目录创建profile文件,并键入一些内容
ulimit -S -c 0 > /dev/null 2>&1
USER="`id -un`"
LOGNAME=$USER
PS1='[$USER@$HOSTNAME]# '
PATH=$PATH
HOSTNAME=`/bin/hostname`
export USER LOGNAME PS1 PATH
修改权限
chmod 755 profile
6、进入var目录,mkdir lib lock log run tmp
7、拷贝必须的lib文件,因为我们使用的交叉编译,在编译过程中,会依赖很多库,如C库,所以我们需要去将交叉编译器的lib库全部拷进lib文件夹。
这里需要注意的是,一定要找到你编译用的交叉编译器用的lib库。
至此,整个文件系统就准备完成了,接下来就需要将该文件系统放到SD卡的rootfs分区中去。
在这里有两种办法,一个是将rootfs文件夹制作成img文件,通过dd命令,将img文件写入/dev/sdb2中,还有一种办法是将/dev/sdb2 mount 都进文件系统,然后将整个rootfs文件夹下的内容拷贝到那个节点。
拷贝进去后,我们已经完成了文件系统的制作,接下来就是kernel编译。
进入下载好的源码根目录中。
执行下面的命令,进行kernel的编译。
export ARCH=arm
export CROSS_COMPILE=arm-linux-gnueabi-
make bcmrpi_defconfig
make
这里需要注意的是,请根据自己实际使用的交叉编译器,替换我这里的arm-linux-gnueabi-
等个十来分钟后,
将编译好的zImage文件cp到SD卡的boot分区,并命名为kernel.img
然后插入树莓派,上电后不断的按空格键,打断uboot的自动引导,使系统停在u-boot阶段,如下图:
进入u-boot后,输入printenv命令,我们可以看到整个u-boot中所有的变量值,在这里我先简单介绍下uboot的引导过程,后面会有详细的博客讲解这一内容。
在uboot中,用户如果没有按空格键去干预uboot自动引导,uboot会首先去执行bootcmd脚本,也就是键入printenv命令后,输出中的bootcmd=****后面的内容
知道这个的话,我们就可以去修改这个变量的值,通过修改这个值来启动自己的kernel镜像。
首先,通过以下的命令修改这一值:
setenv selfcmd mmc dev 0;fatload mmc 0:1 0x00080000 kernel.img; fatload mmc 0:1 2eff9400 bcm2837-rpi-3-b.dtb;bootz 0x00080000 - 2eff9400
setenv bootcmd run selfcmd
saveenv
在这里需要说明的是,selfcmd变量的值的意思
mmc dev 0; //切换到0分区,也就是boot分区
fatload mmc 0:1 0x00080000 kernel.img; 将kernel.img 加载到0x00080000处
fatload mmc 0:1 2eff9400 bcm2837-rpi-3-b.dtb; 将设备树加载到0x2eff9400处
bootz 0x00080000 - 2eff9400 引导kernel.img 并指定设备树文件
需要说明的是,这里的两个地址,可以参考fdt_addr、fdt_addr_r、kernel_addr_r三个变量,这三个变量在printenv中可以看到。
还有一个变量bootdelay变量可以设置等待用户空格键的时常。
至此,重新上电后,系统就会自动引导kernel,并进入最小的linux系统