使用XILINX ZYNQ FPGA开发LINUX使用petalinux大行其道,没错使用petalinux是比较简洁和高效的办法,但是,米联客使用一种更加通用的方法,编写了一些简单的shell脚本去编译uboot,kernel,dts最终产生需要的uboot.bin,uimage,dtb文件。米联客给了大家一种比较通用的开发嵌入式硬件平台的方法,掌握这个方法,不管是你XILINX的平台,还是使用Intel的平台或者其他厂家的ARM平台,都可以很快的切换过去。
米联客提供了3套常用的系统方案给大家选择使用,这些系统方案全部可以自己定义或者裁剪,方案完全受控。接下来先来认识下,osrc-lab的文件结构:
首先,打开osrc-lab,其中有6个文件夹
我们先看下Boards下的书结构
Boards
└── MZ7X
├── buildroot
│ ├── dts
│ │ ├── skeleton.dtsi
│ │ ├── system-top.dts
│ │ ├── zynq-7000.dtsi
│ │ ├── zynq-zed.dts
│ │ └── zynq-zybo.dts
│ ├── fpga
│ ├── images
│ │ ├── boot
│ │ │ ├── BOOT.bin
│ │ │ ├── devicetree.dtb
│ │ │ ├── uEnv.txt
│ │ │ └── uImage
│ │ ├── common.sh
│ │ ├── deploy_image.sh
│ │ ├── make_parted.sh
│ │ ├── qspi_image
│ │ │ └── qspi_image.bin
│ │ └── rootfs
│ │ └── uramdisk.image.gz
│ └── output
│ ├── rootfs
│ ├── sdcard
│ │ ├── boot
│ │ └── rootfs
│ └── target
│ ├── boot.bin
│ ├── devicetree.dtb
│ ├── qspi_image.bif
│ ├── ramdisk.image.gz
│ ├── rootfs.tar.gz
│ ├── sd_image.bif
│ ├── system.bit
│ ├── u-boot.elf
│ ├── u-boot.img
│ ├── uImage
│ ├── uImage.bin
│ ├── uramdisk.image.gz
│ ├── zImage
│ └── zynq_fsbl.elf
├── debian
│ ├── dts
│ │ ├── skeleton.dtsi
│ │ ├── system-top.dts
│ │ ├── zynq-7000.dtsi
│ │ ├── zynq-zed.dts
│ │ └── zynq-zybo.dts
│ ├── fpga
│ ├── images
│ │ ├── boot
│ │ │ ├── BOOT.bin
│ │ │ ├── devicetree.dtb
│ │ │ ├── uEnv.txt
│ │ │ └── uImage
│ │ ├── common.sh
│ │ ├── deploy_image.sh
│ │ ├── make_parted.sh
│ │ └── rootfs
│ │ └── rootfs.tar.gz
│ └── output
│ ├── rootfs
│ ├── sdcard
│ │ ├── boot
│ │ └── rootfs
│ └── target
│ ├── boot.bin
│ ├── devicetree.dtb
│ ├── rootfs.tar.gz
│ ├── sd_image.bif
│ ├── system.bit
│ ├── u-boot.elf
│ ├── u-boot.img
│ ├── uImage
│ ├── uImage.bin
│ ├── zImage
│ └── zynq_fsbl.elf
└── ubuntu
├── dts
│ ├── skeleton.dtsi
│ ├── system-top.dts
│ ├── zynq-7000.dtsi
│ ├── zynq-zed.dts
│ └── zynq-zybo.dts
├── fpga
├── images
│ ├── boot
│ │ ├── BOOT.bin
│ │ ├── devicetree.dtb
│ │ ├── uEnv.txt
│ │ └── uImage
│ ├── common.sh
│ ├── deploy_image.sh
│ ├── make_parted.sh
│ └── rootfs
│ └── rootfs.tar.gz
└── output
├── rootfs
├── sdcard
│ ├── boot
│ └── rootfs
└── target
├── boot.bin
├── devicetree.dtb
├── rootfs.tar.gz
├── sd_image.bif
├── system.bit
├── u-boot.elf
├── u-boot.img
├── uImage
├── uImage.bin
├── zImage
└── zynq_fsbl.elf
可以看到以上树结构中,包含了3套系统,每套系统里面的文件都差不多,我们这里以buildroot系统为例:
├── buildroot
│ ├── dts
│ │ ├── skeleton.dtsi
│ │ ├── system-top.dts
│ │ ├── zynq-7000.dtsi
│ │ ├── zynq-zed.dts
│ │ └── zynq-zybo.dts
│ ├── fpga
│ ├── images
│ │ ├── boot
│ │ │ ├── BOOT.bin
│ │ │ ├── devicetree.dtb
│ │ │ ├── uEnv.txt
│ │ │ └── uImage
│ │ ├── common.sh
│ │ ├── deploy_image.sh
│ │ ├── make_parted.sh
│ │ ├── qspi_image
│ │ │ └── qspi_image.bin
│ │ └── rootfs
│ │ └── uramdisk.image.gz
│ └── output
│ ├── rootfs
│ ├── sdcard
│ │ ├── boot
│ │ └── rootfs
│ └── target
│ ├── boot.bin
│ ├── devicetree.dtb
│ ├── qspi_image.bif
│ ├── ramdisk.image.gz
│ ├── rootfs.tar.gz
│ ├── sd_image.bif
│ ├── system.bit
│ ├── u-boot.elf
│ ├── u-boot.img
│ ├── uImage
│ ├── uImage.bin
│ ├── uramdisk.image.gz
│ ├── zImage
│ └── zynq_fsbl.elf
Dts路径下包含了system-top.dts,zynq-7000.dtsi是我们要用到的文件,其他的可以删除,其他的只是为了支持其他一些型号开发板而保留的板级dts
fpga路径下是放我们的FPGA工程
Images路径下
>boot路径是放编译好的uboot.bin,dtb,uimage
>qspi_image路径存放编译好的qpsi_image.bin,这个qpsi_image.bin是把包括uboot.bin,dtb,uimage合成到一个文件来烧录系统到qspi FLASH的。
> rootfs路径为文件系统uramdisk.image.gz
Output路径下
>rootfs/sdcard路径都不需要分析,是空的,预留使用
>target路径下几个文件很关键
1) u-boot.elf这个编译uboot内核的时候产生的,zynq_fsbl.elf是first bootloader,zynq芯片如果需要启动, system.bit是FPGA编译完成后的文件。利用这三个文件合成了签名的uboot.bin。
2) uImage为编译好的kernel文件
3) devicetree.dtb 就是编译好的设备树文件
4) rootfs.tar.gz文件是编译好系统文件,其首先改名为ramdisk.image.gz然后压缩为uramdisk.image.gz。
了解了以上文件后来分析buildroot系统部分的编译脚本
scripts
├── common.sh
├── kernel
│ ├── cfg_kernel.sh
│ ├── make_kernel.sh
│ └── save_kernel_defconfig.sh
├── rootfs
│ ├── buildroot
│ │ ├── cfg_rootfs.sh
│ │ ├── create_image.sh
│ │ ├── create_qspi_image.sh
│ │ ├── deploy_image.sh
│ │ ├── interfaces
│ │ ├── make_parted.sh
│ │ ├── make_rootfs.sh
│ │ ├── mount_rootfs.sh
│ │ ├── save_rootfs_defconfig.sh
│ │ ├── umount_rootfs.sh
│ │ └── ustart.sh
│ ├── debian
│ │ ├── cfg_rootfs.sh
│ │ ├── create_image.sh
│ │ ├── deploy_image.sh
│ │ ├── make_parted.sh
│ │ ├── make_qspi_image.sh
│ │ ├── make_rootfs.sh
│ │ └── save_rootfs_defconfig.sh
│ └── ubuntu
│ ├── cfg_rootfs.sh
│ ├── create_image.sh
│ ├── deploy_image.sh
│ ├── make_parted.sh
│ ├── make_rootfs.sh
│ └── save_rootfs_defconfig.sh
├── settings64.sh
├── uboot
│ ├── cfg_uboot.sh
│ ├── make_uboot.sh
│ └── save_uboot_defconfig.sh
└── xilinx
├── export_xilinx_env.sh
├── get_hw_description.sh
├── install_cable_drivers.sh
└── run_vivado.sh
可以看到以上树结构中包含的脚本,我们继续以和buildroot系统为列讲解这些脚本的使用。
- Settings64.sh为配置osrc-lab的路径,所以这个脚本是最先执行的,而common.sh定义一些关于脚本里面需要高亮,标红等的信息输出模版。我们这部分截图settings64.sh里面的代码
2、当执行完Settings64.sh后,后面的文件都是可以根据需要执行,比如当我们的ZYNQ FPGA工程开发完后,需要把bit导入到SDK 并且产生zynq_fsbl.elf文件,之后需要通过执行get_hw_description.sh把bit文件和zynq_fsbl.elf文件复制到boards/MZ7X/buildroot/output/target/路径,为后面编译做好准备工作。如果FPGA工程没有修改自然也不需要执行这个脚本。
- # => Setting The Development Environment Variables
- if [ ! "${ZN_CONFIG_DONE}" ];then
- echo "[ERROR] 请以“source settings64.sh”的方式执行 settings64.sh 脚本。" && exit 1
- fi
- # => Filename of the running script.
- ZN_SCRIPT_NAME="$(basename ${BASH_SOURCE})"
- ###############################################################################
- # => The beginning
- echo_info "[ $(date "+%Y/%m/%d %H:%M:%S") ] Starting ${ZN_SCRIPT_NAME}"
- # => hw_platform
- ZYNQ_HW_PLATFORM_DIR=${ZN_VIVADO_PROJECT_DIR}/${ZN_VIVADO_PROJECT_NAME}.sdk/${ZN_BD_NAME}_wrapper_hw_platform_0
- # => bitstream
- ZYNQ_BITSTREAM=${ZYNQ_HW_PLATFORM_DIR}/${ZN_BD_NAME}_wrapper.bit
- if [ ! -f "${ZYNQ_BITSTREAM}" ]; then
- error_exit "could not find file 'system.bit'"
- fi
- cp ${ZYNQ_BITSTREAM} ${ZN_TARGET_DIR}/system.bit
- # => zynq_fsbl
- ZYNQ_FSBL_DIR=${ZN_VIVADO_PROJECT_DIR}/${ZN_VIVADO_PROJECT_NAME}.sdk/zynq_fsbl
- # 确定fsbl.elf文件是否存在
- if [ -f "${ZYNQ_FSBL_DIR}/Release/zynq_fsbl.elf" ]; then
- cp ${ZYNQ_FSBL_DIR}/Release/zynq_fsbl.elf ${ZN_TARGET_DIR}/zynq_fsbl.elf
- elif [ -f "${ZYNQ_FSBL_DIR}/Debug/zynq_fsbl.elf" ]; then
- cp ${ZYNQ_FSBL_DIR}/Debug/zynq_fsbl.elf ${ZN_TARGET_DIR}/zynq_fsbl.elf
- else
- error_exit "could not find file 'zynq_fsbl.elf'"
- fi
- # => The end
- echo_info "[ $(date "+%Y/%m/%d %H:%M:%S") ] Finished ${ZN_SCRIPT_NAME}"
- ###############################################################################
|
3、当我们修改了uboot源码就绪执行make_uboot.sh
############################################################################### # => Setting The Development Environment Variables if [ ! "${ZN_CONFIG_DONE}" ];then echo "[ERROR] Please source the settings64.sh script first" && exit 1 fi
# => Filename of the running script. ZN_SCRIPT_NAME="$(basename ${BASH_SOURCE})"
############################################################################### # => The beginning echo_info "[ $(date "+%Y/%m/%d %H:%M:%S") ] Starting ${ZN_SCRIPT_NAME}"
# => Make sure the source is there if [ "`ls -A ${ZN_UBOOT_DIR}`" = "" ]; then error_exit "Can't find the source code of u-boot" else cd ${ZN_UBOOT_DIR} fi
# => Building the U-Boot bootloader is a part of the Xilinx design flow. echo_info "Build U-Boot on the ${ZN_UBOOT_DIR}" make ${MAKE_JOBS} if [ $? -eq 0 ]; then ### # 1. U-Boot normally ### cp ${ZN_UBOOT_DIR}/u-boot ${ZN_TARGET_DIR}/u-boot.elf
### # 2. U-Boot SPL ### if [ -f "${ZN_UBOOT_DIR}/u-boot.img" ]; then cp ${ZN_UBOOT_DIR}/u-boot.img ${ZN_TARGET_DIR} cp ${ZN_UBOOT_DIR}/spl/boot.bin ${ZN_TARGET_DIR} fi
echo_info "U-Boot - Build OK" else error_exit "U-Boot - Build Failed" fi
# => The end echo_info "[ $(date "+%Y/%m/%d %H:%M:%S") ] Finished ${ZN_SCRIPT_NAME}" ############################################################################### |
4、当我们修改了system.dts或者修改了内核配置,或者内核源码也需要重新编译内核
############################################################################### # => Setting The Development Environment Variables if [ ! "${ZN_CONFIG_DONE}" ];then echo "[ERROR] Please source the settings64.sh script first" && exit 1 fi
# => Filename of the running script. ZN_SCRIPT_NAME="$(basename ${BASH_SOURCE})"
############################################################################### # => The beginning echo_info "[ $(date "+%Y/%m/%d %H:%M:%S") ] Starting ${ZN_SCRIPT_NAME}"
# => Make sure the source is there if [ "`ls -A ${ZN_KERNEL_DIR}`" = "" ]; then error_exit "Can't find the source code of kernel" else cd ${ZN_KERNEL_DIR} fi
# => Make sure the target directory is there [[ ! "${ZN_TARGET_DIR}" ]] && error_exit "Can't find the target directory"
# => 1. Compiling the Kernel echo_info "Building the kernel image on the ${ZN_KERNEL_DIR}" make ${MAKE_JOBS} UIMAGE_LOADADDR=0x8000 uImage if [ $? -eq 0 ]; then echo_info "Installing the Kernel Image" cp -a ${ZN_KERNEL_DIR}/arch/arm/boot/zImage ${ZN_TARGET_DIR} cp -a ${ZN_KERNEL_DIR}/arch/arm/boot/uImage ${ZN_TARGET_DIR} cp -a ${ZN_KERNEL_DIR}/arch/arm/boot/uImage ${ZN_TARGET_DIR}/uImage.bin else error_exit "Kernel Image - Build Failed" fi
# => 2. Compiling the Device Tree Binaries echo_info "Building the Device Tree Binaries on the ${ZN_DTS_DIR}"
${ZN_DTC_DIR}/dtc -I dts -O dtb -o ${ZN_DTB_DIR}/${ZN_DTB_NAME} ${ZN_DTS_DIR}/${ZN_DTS_NAME} if [ $? -eq 0 ]; then echo_info "The Device Tree - Build OK" else error_exit "The Device Tree - Build Failed" fi
# => 3. Compiling the Kernel Modules echo_info "Building the Kernel Modules on the ${ZN_KERNEL_DIR}"
make ${MAKE_JOBS} modules if [ $? -eq 0 ]; then echo_info "Installing the Kernel Modules"
sudo rm -rf ${ZN_ROOTFS_MOUNT_POINT}/* sudo tar zxf ${ZN_TARGET_DIR}/rootfs.tar.gz -C ${ZN_ROOTFS_MOUNT_POINT} sudo rm -rf ${ZN_ROOTFS_MOUNT_POINT}/lib/modules/
sudo make ${MAKE_JOBS} ARCH=arm INSTALL_MOD_PATH=${ZN_ROOTFS_MOUNT_POINT} modules_install if [ $? -eq 0 ]; then sudo rm ${ZN_TARGET_DIR}/rootfs.tar.gz sudo tar zcf ${ZN_TARGET_DIR}/rootfs.tar.gz -C ${ZN_ROOTFS_MOUNT_POINT} . sudo rm -rf ${ZN_ROOTFS_MOUNT_POINT}/* echo_info "The Kernel Modules - Install OK" else sudo rm -rf ${ZN_ROOTFS_MOUNT_POINT}/* error_exit "The Kernel Modules - Install Failed" fi
else error_exit "Kernel Modules - Build Failed" fi
# => The end echo_info "[ $(date "+%Y/%m/%d %H:%M:%S") ] Finished ${ZN_SCRIPT_NAME}" ############################################################################### |
5、如果修改了文件系统我们还要编译文件系统
执行make_rootfs.sh
上面都是准备工作,把修改编译后的东西都放到,boards/MZ7X/buildroot/output/target/路径
6、执行create_qspi_image.sh
其中产生boot.bin的代码如下
以下代码产生uramdisk.image.gz
另外对于内核和设备树的文件是已经全部编译内核的时候就好了,所以简单复制就可以
7、有的时候我们需要修改uramdisk.image.gz 那么可以执行make_rootfs.sh,可以看到我们这里复制了interfaces文件到/etc/network/interfaces中。而在interfaces文件中我们有这么一段代码,没错就是配置默认的IP地址,这样可以实现在开机后网络就能正常工作,方便我们用网络调试和传输数据。
auto eth0 iface eth0 inet static address 10.1.2.33 netmask 255.255.255.0 |
# => The beginning echo_info "$(date "+%Y.%m.%d-%H.%M.%S") : Starting $ZN_SCRIPT_NAME"
# => 确定uramdisk.image.gz文件是否存在 if [ ! -f "${ZN_TARGET_DIR}/uramdisk.image.gz" ]; then error_exit "找不到uramdisk.image.gz" fi
# 预处理。。。 gunzip ${ZN_TARGET_DIR}/ramdisk.image.gz chmod u+rwx ${ZN_TARGET_DIR}/ramdisk.image sudo mount -o loop ${ZN_TARGET_DIR}/ramdisk.image ${ZN_ROOTFS_MOUNT_POINT} if [ $? -eq 0 ]; then echo_info "根文件系统已经挂载在${ZN_ROOTFS_MOUNT_POINT}" #sudo cp ${ZN_SCRIPTS_DIR}/rootfs/buildroot//ustart.sh /${ZN_ROOTFS_MOUNT_POINT}/etc/init.d/ustart.sh sudo cp ${ZN_SCRIPTS_DIR}/rootfs/buildroot//interfaces /${ZN_ROOTFS_MOUNT_POINT}/etc/network/interfaces else error_exit "根文件系统挂载失败..." fi
# => The end echo_info "$(date "+%Y.%m.%d-%H.%M.%S") : Finished $ZN_SCRIPT_NAME" ############################################################################### |
8、修改完成后,执行umount_rootfs.sh 文件,这样修改后的uramdisk.image.gz就好了,这个时候他在boards/MZ7X/buildroot/output/target/路径下,如果是SD卡启动一定用这个文件替换原来的uramdisk.image.gz。
9、执行 create_qspi_image.sh制作qpsi启动文件,而且是带系统,内核,设备树的启动文件
####################################################################################################################### # Create a new bif files... ####################################################################################################################### BIF_FILE=${ZN_TARGET_DIR}/qspi_image.bif # # 每次都重新生成qspi_image.bif文件,这样,就可以解决手动修改路径的问题。 echo "//arch = zynq; split = false; format = BIN" > ${BIF_FILE} echo "the_ROM_image:" >>${BIF_FILE} echo "{" >>${BIF_FILE} # The files we need are: # 1. the first stage boot loader echo " [bootloader]${ZN_TARGET_DIR}/zynq_fsbl.elf" >>${BIF_FILE} # 2. FPGA bit stream if [ -f "${ZN_TARGET_DIR}/system.bit" ]; then echo " ${ZN_TARGET_DIR}/system.bit" >>${BIF_FILE} fi # 3. Das U-Boot boot loader echo " ${ZN_TARGET_DIR}/u-boot.elf" >>${BIF_FILE} # 4. Linux kernel with modified header for U-Boot echo " [offset = 0x1300000]${ZN_TARGET_DIR}/uImage.bin" >>${BIF_FILE} # 5. Device tree blob echo " [offset = 0x1800000]${ZN_TARGET_DIR}/devicetree.dtb" >>${BIF_FILE} # 6. Root filesystem echo " [offset = 0x1820000]${ZN_TARGET_DIR}/uramdisk.image.gz" >>${BIF_FILE} echo "}" >>${BIF_FILE}
####################################################################################################################### # ####################################################################################################################### QSPI_IMAGE_BIN=${ZN_QSPI_IMG_DIR}/qspi_image.bin QSPI_IMAGE_MCS=${ZN_QSPI_IMG_DIR}/qspi_image.mcs
QSPI_IMAGE=${QSPI_IMAGE_BIN}
############################################################################### # Starting Vivado ############################################################################### # => The beginning echo_info "$(date "+%Y.%m.%d-%H.%M.%S") : Starting $ZN_SCRIPT_NAME"
# => Setting Zynq-7000 Development Environment Variables if [ -f "${ZN_SCRIPTS_DIR}/xilinx/export_xilinx_env.sh" ]; then source ${ZN_SCRIPTS_DIR}/xilinx/export_xilinx_env.sh else error_exit "Could not find file ${ZN_SCRIPTS_DIR}/xilinx/export_xilinx_env.sh !!!" fi
bootgen -image ${BIF_FILE} -o ${QSPI_IMAGE} -w on
# cd ${ZN_TARGET_DIR} # bootgen -image ${BIF_FILE} -o ${QSPI_IMAGE} -w on -split bin # cd -
# => The end echo_info "$(date "+%Y.%m.%d-%H.%M.%S") : Finished $ZN_SCRIPT_NAME" ############################################################################### |
对于buildroot系统请注意以上红色的部分,在uboot源码中需要这样设定,并且把#include <configs/zynq-common.h>放到前面。
还得打开zynq-common.h修改uboot.bin uimage dts uramdisk.image.gz的加载偏移地址
9、好了以上就完成了一个简单的闭环了。
以上的情况是基于你直接拿到我们的osrc-lab没做大的修改的情况下使用的。
10、那么如果你自己搭建的一个LINUX系统,VIVADO安装的路径和我们不一样,就要修改export_xilinx_env.sh文件
11、如果我们修改了uboot的menuconfig 那么需要执行save_uboot_defconfig.sh,执行后把配置保存到zynq_mz7x_defconfig
############################################################################### # => The beginning echo_info "[ $(date "+%Y/%m/%d %H:%M:%S") ] Starting ${ZN_SCRIPT_NAME}"
# => Make sure the source is there if [ "`ls -A ${ZN_UBOOT_DIR}`" = "" ]; then error_exit "Can't find the source code of u-boot" fi
# => To save bootloader config use the command : echo_info "To save bootloader config" make -C ${ZN_UBOOT_DIR} savedefconfig if [ $? != 0 ]; then error_exit "Failed to save defconfig" else cp ${ZN_UBOOT_DIR}/defconfig ${ZN_UBOOT_DIR}/configs/${ZN_UBOOOT_DEFCONFIG} fi
# => The end echo_info "[ $(date "+%Y/%m/%d %H:%M:%S") ] Finished ${ZN_SCRIPT_NAME}" ############################################################################### |
至于cfg_uboot.sh,这个会做一些清理工作
############################################################################### # => The beginning echo_info "[ $(date "+%Y/%m/%d %H:%M:%S") ] Starting ${ZN_SCRIPT_NAME}"
# => Make sure the source is there if [ "`ls -A ${ZN_UBOOT_DIR}`" = "" ]; then error_exit "Can't find the source code of u-boot" else cd ${ZN_UBOOT_DIR} fi
# => 1. Cleaning the Sources echo_info "To delete all build products as well as the configuration" make distclean || error_exit "Failed to make distclean"
# => 2. To configure the sources for the intended target. echo_info "Configure u-boot on the ${ZN_UBOOT_DIR}" make ${ZN_UBOOOT_DEFCONFIG} || error_exit "Failed to make ${ZN_UBOOOT_DEFCONFIG}"
# => 3. Prepare for compiling the source code echo_info "Prepare for compiling the source code" make tools || error_exit "Failed to make tools"
# => The end echo_info "[ $(date "+%Y/%m/%d %H:%M:%S") ] Finished ${ZN_SCRIPT_NAME}" ############################################################################### |
12、scripts/kernel路径下一样也有类似的脚本 cfg_kernel.sh和save_kernel_defconfig.sh他们的使用方法一样。
13、本文对osrc-lab应用做一个简单的介绍,希望大家学习后,对于开发LINUX有一定的帮助!