文章目录
宿主机(Ubuntu)配置交叉编译环境
- Ubuntu装的是64位的,交叉编译工具一般是32位的,所以要安装一些库
sudo apt-get install u-boot-tools
sudo apt-get install lib32z1
sudo apt-get install lib32ncurses5
sudo apt-get install libncurses5-dev libncursesw5-dev
sudo apt-get install lib32stdc++6
sudo apt-get install libc6-dev
- 安装SSH
sudo apt-get install openssh-server
sudo /etc/init.d/ssh start
- 安装交叉编译工具
sudo tar -jxvf arm-linux-gcc-4.3.2.tar.bz2 –C /
参考博客:https://blog.csdn.net/qq_24601427/article/details/102983794
- 交叉编译工具下的bin目录添加到环境变量
#临时设置
export PATH=$PATH:交叉编译器路径
#修改全局配置
sudo vim /etc/profile
#修改用户配置文件
#通常是“~/.bashrc”或者“~/.bash_profile” 或者 “~/.profile”
安装和配置TFTP
TFTP
- 安装
#tftp-hpa是客户端,tftpd-hpa是服务器端
sudo apt-get install tftp-hpa tftpd-hpa
- 配置
#创建共享目录
sudo mkdir /tftproot
#修改权限
sudo chmod 777 /tftproot
- 修改tftp服务器配置文件
sudo vim /etc/default/tftpd-hpa3
#添加如下内容
TFTP_USERNAME="tftp"
TFTP_DIRECTORY="/tftproot" #修改为需要的路径
TFTP_OPTIONS="-l -c -s" #通过mantftpd查看各种参数的意义
TFTP_DIRECTORY="/srv/tftp"
- 重启tftp,使其配置生效
sudo service tftpd-hpa restart
- 本地测试
$cd ~/tftpboot echo "hello tftp service">>a.txt
$echo "hello tftp service,put to tftp serive">>b.txt
$tftp localhost
tftp> get a.txt
tftp> put b.txt
tftp> quit
#其中get是取得文件,put是将文件上传到TFTP服务器上
xinetd和TFTP
- 安装
#xinetd是新一代的网络守护进程服务程序
sudo apt-get install xinetd
sudo apt-get install tftp tftpd
- 配置
vi /etc/xinetd.d/tftp
#使用命令:"vi /etc/xinetd.d/tftp"建立TFTP配置文件
#向文件中写入如下代码
#必须按照格式严格对齐
server tftp
{
socket_type = dgram
protocol = udp
wait = yes
user = root
server = /usr/sbin/in.tftpd
server_args = -s /tftproot
disable = no
per_source = 11
cps = 100 2
flags = IPv4
}
#server_args设置的/var/tftproot目录是tftp服务器的目录
- 重启xinetd服务
sudo /etc/init.d/xinetd restart
安装和配置NFS
安装NFS服务端
- 安装
#服务端
sudo apt install nfs-kernel-server
- 创建共享目录
sudo mkdir -p /tmp
sudo mkdir -p /data
sudo mkdir -p /logs
- nfs配置
#编辑/etc/exports 文件
sudo vim /etc/exports
#添加内容
/tmp *(rw,sync,no_subtree_check,no_root_squash)
/data *(rw,sync,no_subtree_check,no_root_squash)
/logs *(rw,sync,no_subtree_check,no_root_squash)
#/home :共享的目录
#* :指定哪些用户可以访问
# * 所有可以ping同该主机的用户
# 192.168.1.* 指定网段,在该网段中的用户可以挂载
# 192.168.1.12 只有该用户能挂载
#(ro,sync,no_root_squash): 权限
# ro : 只读
# rw : 读写
# sync : 同步
# no_root_squash: 不降低root用户的权限
# 其他选项man 5 exports 查看
- 重启NFS服务
sudo /etc/init.d/nfs-kernel-server restart
- 常用命令工具
#显示已经mount到本机nfs目录的客户端机器。
sudo showmount -e localhost
#将配置文件中的目录全部重新export一次!无需重启服务。
sudo exportfs -rv
#查看NFS的运行状态
sudo nfsstat
#查看rpc执行信息,可以用于检测rpc运行情况
sudo rpcinfo
#查看网络端口,NFS默认是使用111端口。
sudo netstat -tu -4
安装NFS客户端
- 安装
#客户端
sudo apt install nfs-common
- 查看NFS服务器上的共享目录
#显示指定的(192.168.3.167)NFS服务器上export出来的目录
sudo showmount -e 192.168.3.167
- 创建本地挂载目录
sudo mkdir -p /mnt/data
sudo mkdir -p /mnt/logs
- 挂载共享目录
#将NFS服务器192.168.3.167上的目录,挂载到本地的/mnt/目录下
sudo mount -t nfs 192.168.3.167:/data /mnt/data
sudo mount -t nfs 192.168.3.167:/logs /mnt/logs
目标机启动运行
参考博客
系统文件区别
- linux内核经过编译后会生成一个elf格式的可执行程序,叫vmlinux或vmlinuz(原始的未经任何处理加工的原版内核elf文件);
- 嵌入式系统部署时烧录的一般不是这个vmlinuz/vmlinux,而是要用objcopy工具去制作成烧录镜像格式,经过制作加工成烧录镜像的文件就叫Image(这个制作烧录镜像主要目的就是缩减大小,节省磁盘)
- 原则上Image就可以直接被烧录到Flash上进行启动执行(类似于u-boot.bin),实际上linux的作者们觉得Image还是太大了所以对Image进行了压缩,并且在image压缩后的文件的前端附加了一部分解压缩代码,构成了一个压缩格式的镜像就叫zImage
- 解压的时候,通过zImage镜像头部的解压缩代码进行自解压,然后执行解压出来的内核镜像。具体的实现流程如下:
- uboot为了启动linux内核,发明了一种内核格式叫uImage
- uImage是由zImage加工得到的,uboot中有一个工具,可以将zImage加工生成uImage。注意:uImage不关linux内核的事,linux内核只管生成zImage即可,然后uboot中的mkimage工具再去由zImage加工生成uImage来给uboot启动。这个加工过程其实就是在zImage前面加上64字节的uImage的头信息即可。
注:如果直接在kernel底下去make uImage会提示mkimage command not found。解决方案是去uboot/tools目录下执行cp mkimage /usr/local/bin/,复制mkimage工具到系统目录下。再去make uImage即可。
- vmlinux 编译出来的最原始的内核文件,未压缩
- zImage 是vmlinux经过gzip压缩后的文件
- bzImage bz表示“big zImage”,不是用bzip2压缩的。两者的不同之处在于,zImage解压缩内核到低端内存(第一个640K),bzImage解压缩内核到高端内存(1M以上)。如果内核比较小,那么采用zImage或bzImage都行,如果比较大应该用bzImage
- uImage U-boot专用的映像文件,它是在zImage之前加上一个长度为0x40的tag,说明这个内核的版本、加载位置、生成时间、大小等信息;其0x40之后与zImage没区别
- vmlinuz 是bzImage/zImage文件的拷贝或指向bzImage/zImage的链接
- initrd 是“initial ramdisk”的简写,一般被用来临时的引导硬件到实际内核vmlinuz能够接管并继续引导的状态
Uboot加载内核过程
- bootm加载linux镜像是加载uIamge,uIamge是由mkimage制作而来,和zIamge的差异是uIamge是zIamge压缩过的,bootm需要先对uIamge解压,解压地址为内核入口地址
- 原则上uboot启动时应该给他uImage格式的内核镜像,但是实际上uboot中也可以支持zImage,是否支持就看是否定义了LINUX_ZIMAGE_MAGIC这个宏
内核文件生成流程图
编译uImage
- 解压内核代码
tar -xvf linux-3.14.tar.xz
- 设置交叉编译工具链
#编辑源代码顶层Makefile
vim Makefile
#修改内容
#ARCH = arm
#CROSS_COMPILE = arm_none_linux_gnueabi-
- 选择一个soc
make exynos_defconfig
#cp -raf arch/arm/configs/exynos_defconfig .config
- 内核源代码配置(内核裁剪)
make menuconfig
- 进入内核源代码目录
#需要使用到工具mkimage,存放到宿主机/usr/bin/
make uIamge -j2
编译设备树
设备树存放路径:linux-3.14/arch/arm/boot/dts
- 修改linux-3.14/arch/arm/boot/dts路径下的Makefile
vim linux-3.14/arch/arm/boot/dts/Makefile
#修改对应的内容
- 编译设备树
#回到源代码根目录
make dtbs
- 替换目标机的dtb文件
通过TFTP启动内核
- 将uImage和dtb文件放入宿主机ubuntu系统中的/tftproot
#在源代码根目录
cp -raf arch/arm/boot/uIamge /tftpboot
cp -raf arch/arm/boot/dts/exynos4412-fs4412.dtb /tftpboot
- 在开发板中设置uboot参数,使其能够加载内核
#目标机输入命令
set ipaddr 192.168.7.22 #目标机的IP地址
set serverip 192.168.7.21 #宿主机的IP地址
set bootcmd tftp 0x410000000 uImage \;tftp 0x42000000 exynos4412-fs4412.dtd \;bootm 0x41000000 - 0x42000000
save
通过NFS挂载rootfs系统
- 解压跟文件系统rootfs.tar.xz,到宿主机的nfs目录下
sudo tar -xvf rootfs.tar.xz -C /opt/4412/
- 配置宿主机的nfs服务器,让/opt/4412/rootfs可以被挂载
sudo vim /etc/exports
#添加内容
#/opt/4412/rootfs *(subtree_check,rw,no_root_aquash,async)
#重启nfs服务
sudo service nfs-kernel-server restart
- 在目标机指定内核通过网络挂载根文件系统
#目标机输入命令
set bootargs console=ttySAC2,115200 init=/linuxrc root= /dev/nfs rw nfsroot=192.168.7.21:/opt/4412/rootfs ip=192.168.7.22
save
#bootargs uboot传递给内核的启动参数,是字符串
# console=xxx 内核启动时的调试信息输出端
# root=xxx 内核根文件系统路径
# root=/dev/nfs 表示根文件系统在网络远端
# nfsroot=IP:path
#ip=xxx 目标机开机时的ip地址
驱动的Makefile示例
ROOTFS_DIR = /opt/4412/rootfs
ifeq ($(KERNELRELEASE), )
KERNEL_DIR = /home/dylan/Linux_4412/kernel/linux-3.14
CUR_DIR = $(shell pwd)
all:
#-C 选项的作用是指将当前工作目录转移到你所指定的位置
#M=选项的作用是,当用户需要以某个内核为基础编译一个外部模块的话,需要在make modules 命令中加入“M=dir”
#程序会自动到你所指定的dir目录中查找模块源码,将其编译,生成KO文件
make -C $(KERNEL_DIR) M=$(CUR_DIR) modules
clean:
make -C $(KERNEL_DIR) M=$(CUR_DIR) clean
install:
cp -raf *.ko $(ROOTFS_DIR)/drv_moduls
else
obj-m += hell0.c
endif