准备busybox,安装menuconfig所需依赖的库:
在busybox中执行make menuconfig
Linux Module Utilities --->
//按N键去除选项(insmod/lsmod/rmmod精简版命令)
[*] Simplified modutils (NEW)
去除以上选项,立马出现完整版的命令选项:
[*] insmod (NEW) │ │
[*] rmmod (NEW) │ │
[*] lsmod (NEW)
[*] Pretty output (NEW)
[*] Blacklist support │ │
[*] modprobe (NEW) │ │
[*] depmod (NEW)
保存退出
注意:目前busybox提供的命令已经足够使用
修改Makefile进行交叉编译:
正式进行编译:
创建根文件目录:
添加必要的依赖动态库:
//获取到编译busybox的交叉编译器的路径
which is arm-cortex_a9-linux-gnueabi-gcc
//进入交叉编译器的根目录
cd /opt/toolchains
//添加libc.so.6动态库
find . -name libc.so.6 得到:
./arm-cortex_a9-linux-gnueabi/sysroot/lib/libc.so.6
ls ./arm-cortex_a9-linux-gnueabi/sysroot/lib/libc.so.6 -lh 得到
./arm-cortex_a9-linux-gnueabi/sysroot/lib/libc.so.6 -> libc-2.18-2013.10.so
说明libc.so.6也仅仅是一个软连接文件,所以拷贝时务必将实体文件一块拷走
cp ./arm-cortex_a9-linux-gnueabi/sysroot/lib/libc.so.6 /opt/rootfs/lib/ -d
cp ./arm-cortex_a9-linux-gnueabi/sysroot/lib/libc-2.18-2013.10.so /opt/rootfs/lib/ -d
//添加libm.so.6动态库
cd /opt/toolchains
find . -name libm.so.6 得到:
./arm-cortex_a9-linux-gnueabi/sysroot/lib/libm.so.6
ls ./arm-cortex_a9-linux-gnueabi/sysroot/lib/libm.so.6 -lh 得到
./arm-cortex_a9-linux-gnueabi/sysroot/lib/libm.so.6 -> libm-2.18-2013.10.so
说明libc.so.6也仅仅是一个软连接文件,所以拷贝时务必将实体文件一块拷走
cp ./arm-cortex_a9-linux-gnueabi/sysroot/lib/libm.so.6 /opt/rootfs/lib/ -d
cp ./arm-cortex_a9-linux-gnueabi/sysroot/lib/libm-2.18-2013.10.so /opt/rootfs/lib/ -d
//切记切记切记:最后还要添加动态库使用时所需的加载器
cd /opt/toolchains
find . -name ld-* 得到加载器
./arm-cortex_a9-linux-gnueabi/sysroot/lib/ld-2.18-2013.10.so
./arm-cortex_a9-linux-gnueabi/sysroot/lib/ld-linux.so.3
cp ./arm-cortex_a9-linux-gnueabi/sysroot/lib/ld-* /opt/rootfs/lib/ -d
cd /opt/rootfs/
vim etc/inittab 添加如下内容
::sysinit:/etc/init.d/rcS
::respawn:-/bin/sh
保存退出
说明:系统启动流程
上电CPU从EMMC的512字节运行uboot
->uboot运行首先进行硬件初始化
然后根据bootcmd从某个地方加载
内核到内存并且启动内核
在启动内核之前给内核传递参数通过bootargs
->内核uImage启动,首先做7大子系统的初始化
最后根据bootargs到某个地方找根文件系统rootfs
->内核找到rootfs以后,内核启动rootfs中的/sbin/init
第一号进程,第一号进程init首先打开rootfs目录下的
etc/inittab文件,第一号进程init会解析inittab文件
首先找到sysinit关键字,一旦找到此关键字
第一号进程会创建一个子进程执行sysinit关键字指定的
脚本程序etc/init.d/rcS,父进程第一号进程会等待子进程
执行完rcS脚本程序
->子进程执行完rcS脚本程序以后,父进程init继续执行
继续解析inittab文件,找到respawn关键字,一旦找到
这个关键字,父进程init继续创建一个子进程,子进程就会
执行respawn对应的程序/bin/sh,父进程继续等待子进程
至此启动了一个shell程序,用户可以输入各种命令
存于根文件系统rootfs的etc/init.d/目录下
cd /opt/rootfs
mkdir etc/init.d/
vim etc/init.d/rcS 添加如下内容
mount -a
mkdir /dev/pts
mount -t devpts devpts /dev/pts
echo /sbin/mdev > /proc/sys/kernel/hotplug
mdev -s
保存退出即可
mount -a:系统会自动解析fstab配置文件,系统根据
此配置文件进行一系列的挂接动作
mount -t devpts devpts /dev/pts:将虚拟文件系统devpts
挂接到/dev/pts目录下
将来/dev/pts目录就可以作为
devpts虚拟文件系统的入口
此命令用于将来可以远程登录开发板,
例如:telnet
echo /sbin/mdev > /proc/sys/kernel/hotplug:
向文件/proc/sys/kernel/hotplug写入字符串"/sbin/mdev"
起始就是告诉内核驱动将来创建设备文件的程序(人)是/sbin/mdev
mdev -s:系统启动,将内核驱动对应的设备文件进行自动创建
存于根文件系统rootfs的etc目录下
cd /opt/rootfs
vim etc/fstab 添加如下内容
proc /proc proc defaults 0 0
sysfs /sys sysfs defaults 0 0
tmpfs /dev tmpfs defaults 0 0
保存退出
说明:
第一列:表示要挂接的设备
第二列:表示挂接点,将来的入口
第三列:表示指定的文件系统格式
第四,五,六:分别指定访问权限
结论:
将来/proc目录,/sys目录,/dev/目录分别作为
procfs,sysfs,tmpfs三种虚拟文件系统的入口
并且以上三种虚拟文件系统将来创建的内容都是
内核来创建,并且分别创建到/proc,/sys,/dev/三个
目录中,关键的关键,这三个目录下将来内核创建的
目录也好,文件也好,都是存在于内存中,掉电就会丢失!
fdisk 2 2 0x100000:0x4000000 0x4100000:0x2f200000
#然后重新烧写rootfs_ext4.img
fdisk:uboot的分区工具命令
第一2:表示对EMMC进行重新分区,如果是SD0写0,如果是SD1写1
第二2:表示要分2两个分区,注意uboot分区不算,这两个分区分别表示uImage和rootfs所在的分区
0x100000:uImage所在分区的起始地址,为1M开始
0x4000000:uImage所在分区的大小,为64M(65M-1M)
0x4100000:rootfs所在分区的起始地址,65M
0x2f200000:rootfs所在分区的大小,754M(819M-65M)
#擦除当前mmc中数据
mmc erase 0x800 0x3000
tftp 48000000 uImage
#注意:下载完毕以后,最后会提示uImage下载的文件大小
#烧写Linux内核
mmc write 48000000 0x800 0x3000
#48000000:内存的起始地址,按字节为单位
#0x800:要写的emmc的起始地址,按sector为单位,0x800=0x100000/512
#0x3000:要向emmc写入的数据大小,按sector为单位,0x3000=uImage文件大小/512
tftp 480000000 rootfs_ext4.img
#注意观察rootfs_ext4.img的文件大小
mmc write 48000000 0x20800 0x32000
# 0x20800=65M/512
#0x32000=rootfs_ext4.img文件大小/512
#至此:uboot/uImage/rootfs_ext4.img烧写完毕
#使用该文件系统,修改参数
setenv bootargs root=/dev/mmcblk0p2 init=/linuxrc console=ttySAC0,115200 rootfstype=ext4 maxcpus=1 lcd=vs070cxn(或者lcd=wy070ml) tp=gslx680-linux
saveenv
说明:
bootargs同样属于uboot的非常非常重要的一个环境变量
此变量就是给linux内核传递的启动参数,将来内核根据
这个启动参数去到某个地方找根文件系统rootfs
root=/dev/mmcblk0p2:告诉linux内核根文件系统在emmc的第三分区
init=/linuxrc:启动运行的第一个脚本linuxrc,linuxrc会启动/sbin/init第一号进程
console=ttySAC0,115200:告诉linux内核,调试串口用第一个串口,注意一定要符合硬件的调试串口编号
rootfstype=ext4:文件系统格式为ext4
maxcpus=1:只启动CPU0
lcd=vs070cxn:指定LCD显示屏的型号, lcd=wy070ml:指定新板子的LCD显示屏型号
tp=gslx680-linux:指定触摸屏的型号
重启下位机,进入uboot命令行执行:
setenv bootargs root=/dev/nfs nfsroot=192.168.0.104:/opt/rootfs ip=192.168.0.118:192.168.0.104:192.168.0.1:255.255.255.0 init=/linuxrc console=ttySAC0,115200 maxcpus=1 lcd=vs070cxn tp=gslx680-linux
saveenv
tftp 48000000 uImage
bootm 48000000 //查看是否能够挂接自己制作的根文件系统
# 注意:shell终端之前的打印信息仔细看,是否有错误!
上位机执行:
cd /opt/rootfs
vim helloworld.c //最好是线程程序
arm-cortex_a9-linux-gnueabi-gcc -o helloworld helloworld.c
下位机测试:
cd /
ls
helloworld
./helloworld //看是否能够正常运行
是否出现类似:libxxx.so…找不到
问:如何解决呢?
答:只需到交叉编译器中找到对应的动态库并且
拷贝到根文件系统rootfs的lib目录下
注意软连接问题噢!
问:cannot run /etc/init.d/rcS: Permission denied
答:rcS脚本文件没有可执行权限,解决办法:
cd /opt/rootfs
chmod 777 etc/init.d/rcS
实施步骤:
1.明确:自己移植或者自己制作的动态库一律不允许放到根文件系统rootfs
的必要目录lib下,要单独存放,注意设置环境变量
2.上位机执行:
mkdir /opt/rootfs/home/applib
cd /opt/rootfs/home/applib
vim test.h //声明 添加如下内容
#ifndef __TEST_H
#define __TEST_H
extern void my_test(void);
#endif
保存退出
vim test.c //定义 添加如下内容
#include
void my_test(void)
{
printf("%s\n", func);
}
保存退出
vim main.c //调用
#include
#include “test.h”
int main(void)
{
my_test(); //调用
return 0;
}
编译:
arm-cortex_a9-linux-gnueabi-gcc -shared -fpic -o libtest.so test.c
arm-cortex_a9-linux-gnueabi-gcc -o main main.c -L. -ltest
注意:不要将libtest.so拷贝到/opt/rootfs/lib下,相当危险!
下位机测试:
进入下位机的linux系统,执行:
cd /home/applib
ls
libtest.so main
./main //势必提示libtest.so找不到
解决办法:
export LD_LIBRARY_PATH=/home/applib:$LD_LIBRARY_PATH
然后
./main
上位机实施步骤:
cd /opt/rootfs
vim etc/init.d/rcS 在文件最后添加如下内容:
export LD_LIBRARY_PATH=/home/applib:$LD_LIBRARY_PATH
/home/applib/main &
保存退出
重启下位机,看main程序是否能够自己运行
案例:问:rootfs_ext4.img从何而来?
答:rootfs_ext4.img仅仅是根文件系统rootfs一个镜像文件而已
此镜像中同样包含了根文件系统rootfs的内容
问:如何将自己制作的rootfs制作成一个单个二进制镜像文件呢
也就是将/opt/rootfs(目录)->rootfs_ext4.img(单个文件)
上位机实施步骤:
cd /opt/
sudo dd if=/dev/zero of=rootfs_ext4.img bs=1k count=8196
命令说明:
dd:用于创建一个单个镜像文件
if=/dev/zero:将来创建的单个镜像文件里面的内容全部来自设备/dev/zero
/dev/zero设备能够源源不断产生0数据
of=rootfs_ext4.img:指定将来创建单个镜像文件名
并且此文件里面填充全0
bs=1k:生成的rootfs_ext4.img以块为单位,一块1024字节
count=8196:总共8196块
结论:生成的rootfs_ext4.img数据块为8MB
sudo mkfs.ext4 rootfs_ext4.img //格式化镜像文件rootfs_ext4.img
//把rootfs_ext4.img比作U盘
指定的文件系统格式为ext4
//类似windows下格式化U盘
sudo mkdir /mnt/initrd //创建一个目录
sudo mount -t ext4 -o loop rootfs_ext4.img /mnt/initrd
命令说明:
挂接rootfs_ext4.img到目录/mnt/initrd,并且指定的文件系统类型ext4
挂接命令的结果就是将来只需要访问/mnt/initrd,本质
就是在访问rootfs_ext4.img里面的内容
sudo cp /opt/rootfs/* /mnt/initrd -frd //向目录initrd
拷贝rootfs的内容,本质上就是向rootfs_ext4.img
拷贝rootfs的内容
结果是拷贝完毕,rootfs_ext4.img里面的内容
就是/opt/rootfs里面的内容
sudo umount /mnt/initrd //卸载/mnt/initrd,将来initrd
不再作为rootfs_ext4.img的入口
cp rootfs_ext4.img /tftpboot
至此第一天烧写系统使用的rootfs_ext4.img就是这么来的!
下位机重启,进入uboot命令行模式执行:
1.向下位机部署系统软件之前,切记记得要进行分区规划
EMMC存储空间的划分:
0–512----------1M--------7M--------17M---------剩余
uboot uImage rootfs 大片
mmcblkboot0 mmcblk0p1 mmcblk0p2
uboot已经完成 自己分 自己分
2.烧写uImage
tftp 48000000 uImage
mmc write 48000000 0x800 0x3000 //emmc地址以块单位,一块0x200=512字节
计算流程:
0x800起始地址=0x100000/0x200
0x3000分区大小=7M-1M=0x600000/0x200
计算流程:
0x3800起始地址=0x700000/0x200
0x5000分区大小=10M=0xa00000/0x200
利用uboot提供的fdisk命令
fdisk 2 2 0x100000:0x600000 0x700000:0xa00000
说明:
第一个‘2’:表示emmc
第二个‘2’:表示分两个分区(uImage+rootfs)
uboot分区不用做
0x100000:0x600000:第二个分区的起始地址和大小
0x700000:0xa00000:第三个分区的起始地址和大小
系统启动完毕,观察main程序是否启动,看main的打印的信息