一、Linux 设备驱动介绍及开发环境搭建(续)
1.2.6 uboot 编译安装
- 嵌入式 bootloader 的功能:
- 功能类似于 PC 的 BIOS、硬件检测是否正常
- 加载操作系统镜像到 RAM
- 设置不同的启动方式
- 常见的启动方式:
- NOR/NAND Flash 启动
- 从 SD 卡启动
- Bootloader 从网络加载 Linux 内核启动
- uboot 编译
- 下载地址:ftp://ftp.denx.de/pub/u-boot/
- 获取得版本为 u-boot-2017.01.tar.bz2,发布时间为 2017-1-15
- 主 Makefile 中修改 CROSS_COMPILE,config.mk 中修改 ARCH
- 配置 make vexpress_ca9x4_defconfig
- 编译 make -j8
- 测试 uboot 可用:qemu-system-arm -M vexpress-a9 -kernel u-boot -nographic -m 512M
启动成功后,需要对 uboot 配置网络功能,即 QEMU 网络功能设置
- 下载地址:ftp://ftp.denx.de/pub/u-boot/
- 采用桥接(bridge)的网络连接与 Host 通信
- 需要主机内核 tun/tap 模块支持
- 配置:
- 主机安装工具包
- sudo apt-get install uml-utilities
- sudo apt-get install bridge-utils
- 创建 tun 设备文件:/dev/net/tun,工具安装成功后,会生成此设备节点
- 开启 tun 网络功能,使其声线:
- 修改 /etc/network/interfaces 文件,重启生效
- 配置 /etc/qemu-ifup、/etc/qemu-ifdown 脚本,这些可能自动生成了,那就不需要配置
- 重启,使 br0 生效:
-
虚拟网口 br0 是 QEMU 虚拟机与Linux主机通讯的网口
- 主机安装工具包
- 内核配置编译:
- 使用 u-boot 引导内核镜像
- 需要将内核编译为 uImage 格式
- 需要指定 uImage 的加载地址
- 编译时指定:make LOADADDR=0x60003000 uImage -j8
- 使用 u-boot 引导内核镜像
- 主机 TFTP 工具安装
- 工具安装:sudo apt-get install tftp-hpa tftpd-hpa xinetd
- 修改配置文件:/etc/default/tftpd-hpa
- TFTP_DIRECTORY 是我们的工作目录,开发板从此目录下载镜像和配置文件,我们的镜像和配置文件也存放此目录中
- TFTP_DIRECTORY 是我们的工作目录,开发板从此目录下载镜像和配置文件,我们的镜像和配置文件也存放此目录中
- 创建 tftpboot 目录,mkdir tftpboot, chmod 777 tftpboot
- 配置 /etc/xinetd.conf,如果没有此文件,则创建此文件:
- 工具安装:sudo apt-get install tftp-hpa tftpd-hpa xinetd
- 配置 /etc/xinetd.d/tftp 文件,如果没有此文件,则创建此文件
- 重启 tftp:
- sudo /etc/init.d/tftpd-hpa restart
- sudo /etc/init.d/xinetd reload
- sudo /etc/init.d/xinetd restart
-
- 测试 tftp
- cd ..
- tftp localhost
- tftp> get test.c
- 获取文件成功,则OK
- 测试 tftp
- 启动测试:
- qemu-system-arm -M vexpress-a9 -kernel u-boot -nographic -m 512M -net nic,vlan=0 -net tap,vlan=0,ifname=tap0 -sd rootfs.ext3
- 注意:若是高版本得QEMU,则去掉 vlan 参数
- 脚本在最后
1.3 挂载 NFS 文件系统
1.3.1 介绍
- 主机 HOST 支持 NFS 服务
- 安装:sudo apt-get install nfs-kernel-server
- 配置NFS
- 在 /etc/exports 文件中添加:
- /home/rootfs *(rw,sync,no_root_squash,no_subtree_check)
- /home/rootfs:是根文件系统的主目录
- rw:可读可写
- sync:磁盘和内存进行同步
- no_root_squash:不执行开发板 root 用户映射为主机的匿名用户,保证权限重组
- no_subtree_check:不检查根文件系统的子目录
- 开启 NFS 服务
- /etc/init.d/rpcbind restart
- /etc/init.d/nfs-kernel-server restart
- 修改 bootargs 启动参数
- 设置为 NFS 为根文件系统
- 设置主机 NFS 文件系统的地址
- nfsroot 是主机的 IP 地址
- ip 是开发板的 IP 地址
- 注意:若是 QEMU 得版本较高,则参数配置如下:
-
即相比于低版本 QEMU,在nfsroot 后添加了 proto=tcp,nfsvers=3,nolock 三个参数
- 内核支持挂载 NFS 文件系统
- make menuconfig 配置
- 修改完后:make uImage -j8
- 由于暂时 uboot 没办法启动内核,则单独启动内核
- VFS 已经 mount 成功
- 在根文件系统(/home/coco/work/rootfs)下创建一个文件:test.c,然后在 linux 控制台查看是否存在此文件
1.3.2 完善跟文件系统
- 启动流程:
- Linux 内核启动之后,挂载 NFS或其他根文件系统
- 然后开启 init 进程(前面设置的 bootargs 中,init=/linuxrc),这个init 进程会执行 inittab 脚本
- 增加内核的各种用户接口,用户接口存在 /proc 和 /sys 下
- /etc 内核配置和启动文件,需要在下面添加以下文件
- inittab:脚本文件,运行命令
- /etc 内核配置和启动文件,需要在下面添加以下文件
1 ::sysinit:/etc/init.d/rcS ///< 启动 rcS 脚本 2 #::respawn:-/bin/sh 3 #tty2::askfirst:-/bin/sh 4 #::ctrlaltdel:/bin/umount -a -r 5 6 console::askfirst:-/bin/sh ///< 启动控制台,控制台与 shell 绑定一起,"-" 表示启动 shell 之前,要启动 profile 7 ::ctrlaltdel:/sbin/reboot 8 ::shutdown:/bin/umount -a -r
-
-
- fstab:文件init.d:目录
-
1 挂载的文件系统 挂载的目录 2 proc /proc proc defaults 0 0 3 tmpfs /tmp tmpfs defaults 0 0 4 sysfs /sys sysfs defaults 0 0 5 tmpfs /dev tmpfs defaults 0 0 6 var /dev tmpfs defaults 0 0 7 ramfs /dev ramfs defaults 0 0 8 9 注意:挂载的目录必须在根文件系统下存在,不存在则创建,这个文件的作用就是将文件系统挂载到目录的节点上
-
-
- rcS:文件
-
1 #!bin/sh 2 # 设置环境变量 3 PATH=/sbin:/bin:/usr/sbin:/usr/bin 4 LD_LIBRARY_PATH=/lib 5 export PATH LD_LIBRARY_PATH 6 7 # 挂载各种文件系统,挂载的文件系统与 fstab 有关 8 mount -a 9 mkdir -p /dev/pts 10 mount -t devpts devpts /dev/pts 11 mdev -s 12 mkdir -p /var/lock 13 14 echo "--------------------------------------------------------------------------------" 15 16 echo "Welcome to my cortex-a9 board" 17 18 echo "--------------------------------------------------------------------------------"
-
-
- profile:文件
-
1 PS1='cortex_a9@arm:\w # ' ///< 显示控制台的格式,就相当于终端中的 coco@ubuntu:~/work/rootfs/etc$ 2 export PS1 3 4 注意:此文件也可以做其他操作
- 重启 reboot 功能,已经在 inittab 中操作
- 最终结果
1.4 在开发板上运行应用和内核驱动程序
1.4.1 运行应用程序
main.c
执行交叉编译:arm-linux-gnueabi-gcc main.c
将生成 a.out 拷贝进开发板中(NFS 文件系统),并执行:
1.4.2 运行内核驱动程序
Makefile:
1 .PHONY:all clean 2 ifneq ($(KERNELRELEASE),) 3 4 obj-m := hello.o 5 6 else 7 8 EXTRA_CFLAGS += -DDEBUG 9 KDIR := /home/coco/work/kernel/linux-4.4.194 10 all: 11 make CROSS_COMPILE=arm-linux-gnueabi- ARCH=arm -C $(KDIR) M=$(PWD) modules 12 clean: 13 rm -fr *.ko *.o *.mod.o *.mod.c *.symvers *.order .*.ko .tmp_versions 14 15 endif
拷贝 hello.ko 进NFS文件系统:cp /home/coco/work/code/test_driver/hello.ko ./work
加载模块:insmod hello.ko
查看模块:lsmod
卸载模块:rmmod hello.ko
查看模块:lsmod
1.5 启动脚本
boot.sh
1 #!/bin/bash 2 3 BOARD=vexpress-a9 4 5 KERNEL_DIR=/home/ubuntu/work/arm/kernel/linux-4.4.194 6 KERNEL_BIN_DIR=${KERNEL_DIR}/arch/arm/boot 7 DTB_DIR=${KERNEL_BIN_DIR}/dts 8 DTB_BIN=vexpress-v2p-ca9.dtb 9 UIMAGE=uImage 10 ZIMAGE=zImage 11 12 UBOOT_DIR=/home/ubuntu/work/arm/uboot/u-boot-2017.01 13 UBOOT_BIN_DIR=${UBOOT_DIR} 14 UBOOT_BIN=u-boot 15 16 ROOTFS_DIR=/home/ubuntu/work/arm 17 ROOTFS_BIN=rootfs.ext3 18 19 TFTPBOOT_DIR=/home/ubuntu/work/arm/tftpboot 20 21 help() 22 { 23 echo "-t start qemu" 24 echo " s; start with graphic......" 25 echo " s-no; start with no graphic......" 26 echo "-h print help" 27 } 28 29 tftp_init() 30 { 31 echo "init...." 32 if [ "${TFTPBOOT_DIR}/${UIMAGE}" -ot "${KERNEL_BIN_DIR}/${UIMAGE}" -o ! -f "${TFTPBOOT_DIR}/${UIMAGE}" ]; then 33 echo "cp ${KERNEL_BIN_DIR}/${UIMAGE} ${TFTPBOOT_DIR}" 34 cp ${KERNEL_BIN_DIR}/${UIMAGE} ${TFTPBOOT_DIR} 35 fi 36 37 if [ "${TFTPBOOT_DIR}/${DTB_BIN}" -ot "${DTB_DIR}/${DTB_BIN}" -o ! -f "${DTB_DIR}/${DTB_BIN}" ]; then 38 echo "cp ${DTB_DIR}/${DTB_BIN} ${TFTPBOOT_DIR}" 39 cp ${DTB_DIR}/${DTB_BIN} ${TFTPBOOT_DIR} 40 fi 41 42 if [ "${TFTPBOOT_DIR}/${UBOOT_BIN}" -ot "${UBOOT_BIN_DIR}/${UBOOT_BIN}" -o ! -f "${UBOOT_BIN_DIR}/${UBOOT_BIN}" ]; then 43 echo "cp ${UBOOT_BIN_DIR}/${UBOOT_BIN} ${TFTPBOOT_DIR}" 44 cp ${UBOOT_BIN_DIR}/${UBOOT_BIN} ${TFTPBOOT_DIR} 45 fi 46 47 if [ "${TFTPBOOT_DIR}/${ROOTFS_BIN}" -ot "${ROOTFS_DIR}/${ROOTFS_BIN}" -o ! -f "${ROOTFS_DIR}/${ROOTFS_BIN}" ]; then 48 echo "cp ${ROOTFS_DIR}/${ROOTFS_BIN} ${TFTPBOOT_DIR}" 49 cp ${ROOTFS_DIR}/${ROOTFS_BIN} ${TFTPBOOT_DIR} 50 fi 51 } 52 53 tftp_start_no_graphic() 54 { 55 qemu-system-arm -M vexpress-a9 -kernel u-boot -nographic -m 512M -net nic, -net tap,ifname=tap0 -sd rootfs.ext3 56 } 57 58 nfs_start_no_graphic() 59 { 60 qemu-system-arm -M vexpress-a9 -kernel u-boot -nographic -m 512M -net nic -net tap,ifname=tap0 61 } 62 63 kernel_start_no_graphic() 64 { 65 qemu-system-arm \ 66 -M ${BOARD} \ 67 -kernel ${KERNEL_BIN_DIR}/${ZIMAGE} \ 68 -nographic \ 69 -m 512M \ 70 -dtb ${DTB_DIR}/${DTB_BIN} \ 71 -append "root=/dev/mmcblk0 rw console=ttyAMA0" \ 72 -sd ${ROOTFS_DIR}/${ROOTFS_BIN} 73 } 74 75 kernel_start_with_graphic() 76 { 77 qemu-system-arm \ 78 -M ${BOARD} \ 79 -kernel ${KERNEL_BIN_DIR}/${ZIMAGE} \ 80 -m 512M 81 } 82 83 uboot_start_no_graphic() 84 { 85 qemu-system-arm \ 86 -M ${BOARD} \ 87 -kernel ${UBOOT_BIN_DIR}/${UBOOT_BIN} \ 88 -nographic \ 89 -m 512M 90 } 91 92 uboot_start_with_graphic() 93 { 94 qemu-system-arm \ 95 -M ${BOARD} \ 96 -kernel ${UBOOT_BIN_DIR}/${UBOOT_BIN} \ 97 -m 512M 98 } 99 100 while getopts "t:h" opt 101 do 102 case $opt in 103 t) 104 OPTARG_TYPE=$OPTARG 105 ;; 106 h) 107 help 108 exit 1 109 ;; 110 esac 111 done 112 113 case "$OPTARG_TYPE" in 114 n-no) 115 tftp_init 116 echo "nfs start with no graphic......" 117 nfs_start_no_graphic $@ 118 ;; 119 s) 120 echo "tftp start with graphic......" 121 tftp_init 122 start_graphic $@ 123 ;; 124 s-no) 125 tftp_init 126 echo "tftp start with no graphic......" 127 tftp_start_no_graphic $@ 128 ;; 129 k) 130 kernel_start_with_graphic $@ 131 ;; 132 k-no) 133 kernel_start_no_graphic $@ 134 ;; 135 u) 136 uboot_start_with_graphic $@ 137 ;; 138 u-no) 139 uboot_start_no_graphic $@ 140 ;; 141 *) 142 echo "Unknow option $OPTARG_TYPE..." 143 exit 1 144 ;; 145 esac