最近花了几天时间完成了zynqMP linux的移植工作,这里记录一下工作的流程。
下图时xilinx手册上摘录的图,描述了zynqMP 上的linux的整个boot过程
系统复位后,首先PMU(Platform Management Unit)会执行PMU ROM中固化代码,执行完后会启动CSU处理核,CSU会负责从启动存储介质中加载FSBL(First Stage Boot Loader)至on-chip ram中,FSBL可以由RPU负责执行也可由APU负责执行,须在制作FSBL时确定。继而,CSU激励RPU或APU执行FSBL。FSBL会加载PMU Frameware交付PMU执行。继而FSBL执行完成后切换至ATF(Arm Trusted Frame),ATF于APU上执行。然后ATF启动u-boot,u-boot为linux配置好运行环境将执行权交付给Linux内核。
从xilinx wiki上下载u-boot-xlnx
查看 board/xilinx/zynqmp/zynqmp.c 中board_late_init
int board_late_init(void)
{
u32 ver, reg = 0;
u8 bootmode;
const char *mode;
char *new_targets;
int ret;
if (!(gd->flags & GD_FLG_ENV_DEFAULT)) {
debug("Saved variables - Skipping\n");
return 0;
}
ver = zynqmp_get_silicon_version();
switch (ver) {
case ZYNQMP_CSU_VERSION_VELOCE:
setenv("setup", "setenv baudrate 4800 && setenv bootcmd run veloce");
case ZYNQMP_CSU_VERSION_EP108:
case ZYNQMP_CSU_VERSION_SILICON:
setenv("setup", "setenv partid auto");
break;
case ZYNQMP_CSU_VERSION_QEMU:
default:
setenv("setup", "setenv partid 0");
}
ret = zynqmp_mmio_read((ulong)&crlapb_base->boot_mode, ®);
if (ret)
return -EINVAL;
if (reg >> BOOT_MODE_ALT_SHIFT)
reg >>= BOOT_MODE_ALT_SHIFT;
bootmode = reg & BOOT_MODES_MASK;
puts("Bootmode: ");
switch (bootmode) {
case USB_MODE:
puts("USB_MODE\n");
mode = "usb";
setenv("modeboot", "usb_dfu_spl");
break;
case JTAG_MODE:
puts("JTAG_MODE\n");
mode = "pxe dhcp";
setenv("modeboot", "jtagboot");
break;
case QSPI_MODE_24BIT:
case QSPI_MODE_32BIT:
mode = "qspi0";
puts("QSPI_MODE\n");
setenv("modeboot", "qspiboot");
break;
case EMMC_MODE:
puts("EMMC_MODE\n");
mode = "mmc0";
setenv("modeboot", "emmcboot");
break;
case SD_MODE:
puts("SD_MODE\n");
mode = "mmc0";
setenv("modeboot", "sdboot");
break;
case SD1_LSHFT_MODE:
puts("LVL_SHFT_");
/* fall through */
case SD_MODE1:
puts("SD_MODE1\n");
#if defined(CONFIG_ZYNQ_SDHCI0) && defined(CONFIG_ZYNQ_SDHCI1)
mode = "mmc1";
setenv("sdbootdev", "1");
#else
mode = "mmc0";
#endif
setenv("modeboot", "sdboot");
printf("modeboot:%s\n","sdboot");
break;
case NAND_MODE:
puts("NAND_MODE\n");
mode = "nand0";
setenv("modeboot", "nandboot");
break;
default:
mode = "";
printf("Invalid Boot Mode:0x%x\n", bootmode);
break;
}
/*
* One terminating char + one byte for space between mode
* and default boot_targets
*/
new_targets = calloc(1, strlen(mode) +
strlen(getenv("boot_targets")) + 2);
sprintf(new_targets, "%s %s", mode, getenv("boot_targets"));
setenv("boot_targets", new_targets);
return 0;
}
这里检查了zynqMP的启动方式,并设置了环境参数 modeboot ,此次测试使用sd卡boot,故modeboot 会被设置为sdboot,故u-boot会执行run sdboot命令,其中sdboot 环境参数设置在include/configs/xilinx_zynqmp.h中定义,如下所示
/* Initial environment variables */
#ifndef CONFIG_EXTRA_ENV_SETTINGS
#define CONFIG_EXTRA_ENV_SETTINGS \
"kernel_addr=0x80000\0" \
"initrd_addr=0xa00000\0" \
"initrd_size=0x2000000\0" \
"fdt_addr=4000000\0" \
"fdt_high=0x10000000\0" \
"loadbootenv_addr=0x100000\0" \
"sdbootdev=0\0"\
"kernel_offset=0x180000\0" \
"fdt_offset=0x100000\0" \
"kernel_size=0x1e00000\0" \
"fdt_size=0x80000\0" \
"bootenv=uEnv.txt\0" \
"serverip=192.168.1.18\0" \
"bootargs=earlycon clk_ignore_unused\0" \
"loadbootenv=load mmc $sdbootdev:$partid ${loadbootenv_addr} ${bootenv}\0" \
"importbootenv=echo Importing environment from SD ...; " \
"env import -t ${loadbootenv_addr} $filesize\0" \
"sd_uEnvtxt_existence_test=test -e mmc $sdbootdev:$partid /uEnv.txt\0" \
"sata_root=if test $scsidevs -gt 0; then setenv bootargs $bootargs root=/dev/sda rw rootfstype=ext4; fi\0" \
"sataboot=load scsi 0 80000 boot/Image && load scsi 0 $fdt_addr boot/system.dtb && booti 80000 - $fdt_addr\0" \
"veloce=fdt addr f000000 && fdt resize" \
"fdt set /amba/misc_clk clock-frequency <48000> && "\
"fdt set /timer clock-frequency <240000> && " \
"fdt set /amba/i2c_clk clock-frequency <240000> && " \
"booti 80000 - f000000\0" \
"netboot=tftpboot 10000000 image.ub && bootm\0" \
"qspiboot=sf probe 0 0 0 && sf read $fdt_addr $fdt_offset $fdt_size && " \
"sf read $kernel_addr $kernel_offset $kernel_size && " \
"booti $kernel_addr - $fdt_addr\0" \
"uenvboot=" \
"if run sd_uEnvtxt_existence_test; then " \
"run loadbootenv; " \
"echo Loaded environment from ${bootenv}; " \
"run importbootenv; " \
"fi; " \
"if test -n $uenvcmd; then " \
"echo Running uenvcmd ...; " \
"run uenvcmd; " \
"fi\0" \
"sdboot=mmc dev $sdbootdev && mmcinfo && run uenvboot;" \
"setenv ipaddr 192.168.1.15 ;" \
"setenv serverip 192.168.1.18 ;" \
"setenv netmask 255.255.255.0 ;" \
"ping $serverip ;" \
"setenv bootargs console=ttyPS0,115200 root=/dev/nfs nfsroot=192.168.1.18:/home/rootfs,tcp ip=dhcp rw earlyprintk rootwait ;" \
"tftpboot $kernel_addr Image &&" \
"tftpboot $fdt_addr system.dtb &&" \
"booti $kernel_addr - $fdt_addr\0" \
"emmcboot=run sdboot\0" \
"nandboot=nand info && nand read $fdt_addr $fdt_offset $fdt_size && " \
"nand read $kernel_addr $kernel_offset $kernel_size && " \
"booti $kernel_addr - $fdt_addr\0" \
"xen_prepare_dt=fdt addr $fdt_addr && fdt resize 128 && " \
"fdt set /chosen \\\\#address-cells <1> && " \
"fdt set /chosen \\\\#size-cells <1> && " \
"fdt mknod /chosen dom0 && " \
"fdt set /chosen/dom0 compatible \"xen,linux-zimage\" \"xen,multiboot-module\" && " \
"fdt set /chosen/dom0 reg <0x80000 0x$filesize> && " \
"fdt set /chosen xen,xen-bootargs \"console=dtuart dtuart=serial0 dom0_mem=768M bootscrub=0 maxcpus=1 timer_slop=0\" && " \
"fdt set /chosen xen,dom0-bootargs \"console=hvc0 earlycon=xen earlyprintk=xen maxcpus=1 clk_ignore_unused\"\0" \
"xen_prepare_dt_qemu=run xen_prepare_dt && " \
"fdt set /cpus/cpu@1 device_type \"none\" && " \
"fdt set /cpus/cpu@2 device_type \"none\" && " \
"fdt set /cpus/cpu@3 device_type \"none\" && " \
"fdt rm /cpus/cpu@1 compatible && " \
"fdt rm /cpus/cpu@2 compatible && " \
"fdt rm /cpus/cpu@3 compatible\0" \
"xen=tftpb $fdt_addr system.dtb && tftpb 0x80000 Image &&" \
"run xen_prepare_dt && " \
"tftpb 6000000 xen.ub && tftpb 0x1000000 image.ub && " \
"bootm 6000000 0x1000000 $fdt_addr\0" \
"xen_qemu=tftpb $fdt_addr system.dtb && tftpb 0x80000 Image && " \
"run xen_prepare_dt_qemu && " \
"tftpb 6000000 xen.ub && tftpb 0x1000000 image.ub && " \
"bootm 6000000 0x1000000 $fdt_addr\0" \
"jtagboot=tftpboot 80000 Image && tftpboot $fdt_addr system.dtb && " \
"tftpboot 6000000 rootfs.cpio.ub && booti 80000 6000000 $fdt_addr\0" \
"nosmp=setenv bootargs $bootargs maxcpus=1\0" \
"nfsroot=setenv bootargs $bootargs root=/dev/nfs nfsroot=$serverip:/mnt/sata,tcp ip=$ipaddr:$serverip:$serverip:255.255.255.0:zynqmp:eth0:off rw\0" \
"sdroot0=setenv bootargs $bootargs root=/dev/mmcblk0p2 rw rootwait\0" \
"sdroot1=setenv bootargs $bootargs root=/dev/mmcblk1p2 rw rootwait\0" \
"android=setenv bootargs $bootargs init=/init androidboot.selinux=disabled androidboot.hardware=$board\0" \
"android_debug=run android && setenv bootargs $bootargs video=DP-1:1024x768@60 drm.debug=0xf\0" \
"usb_dfu_spl=booti $kernel_addr - $fdt_addr\0" \
"usbhostboot=usb start && load usb 0 $fdt_addr system.dtb && " \
"load usb 0 $kernel_addr Image && " \
"booti $kernel_addr - $fdt_addr\0" \
PARTS_DEFAULT \
DFU_ALT_INFO
#endif
#define CONFIG_PREBOOT "run setup"
#define CONFIG_BOOTCOMMAND "run $modeboot"
其中sdboot为
"sdboot=mmc dev $sdbootdev && mmcinfo && run uenvboot;" \
"setenv ipaddr 192.168.1.15 ;" \
"setenv serverip 192.168.1.18 ;" \
"setenv netmask 255.255.255.0 ;" \
"ping $serverip ;" \
"setenv bootargs console=ttyPS0,115200 root=/dev/nfs nfsroot=192.168.1.18:/home/rootfs,tcp ip=dhcp rw earlyprintk rootwait ;" \
"tftpboot $kernel_addr Image &&" \
"tftpboot $fdt_addr system.dtb &&" \
"booti $kernel_addr - $fdt_addr\0" \
此处实现了TFTP形式的boot以及nfs文件系统,这里就不解释TFTP Boot及nfs(xilinx默认配置是从sd卡第一分区(FAT格式)读取devicetree以及Image实现boot,并以sd卡第二分区(ext4格式)作为系统的跟文件系统)。
至此可以对u-boot编译
cd $u-boot-xlnx-dir
export ARCH=arm64
export CROSS_COMPILE=aarch64-linux-gnu-
make distclean
make xilinx_zynqmp_zcu102_rev1_0_defconfig
make -j4 #-jn 为你要运行的核数
在工程根目录下面生成u-boot.elf
下载Arm-Trusted-Firmware
cd $Arm-Trusted-Firmware
export ARCH=arm64
export CROSS_COMPILE=aarch64-linux-gnu-
make PLAT=zynqmp RESET_TO_BL31=1
由于一开始用的gcc为apt安装,此版本有bug,
故去linaro官网下载,下载版本为7.2
生成的 ATF在/build/zynqmp/release/bl31
使用Xilinx SDK中 Xilinx->Create Boot Image制作BOOT.BIN
bif文件如下所示:
//arch = zynqmp; split = false; format = BIN
the_ROM_image:
{
[fsbl_config]a53_x64
[bootloader]PROJECT_DIR/project_1.sdk/fsbl/Debug/fsbl.elf
[pmufw_image]PROJECT_DIR/project_1.sdk/pmu/Debug/pmu.elf
[destination_device = pl]PROJECT_DIR/project_1.sdk/design_1_wrapper_hw_platform_0/design_1_wrapper.bit
[destination_cpu = a53-0, exception_level = el-3]PROJECT_DIR/project_1.sdk/bl31.elf
[destination_cpu = a53-0, exception_level = el-2]PROJECT_DIR/project_1.sdk/u-boot.elf
}
其中PMU、FSBL由SDK中生成
在编译PMU的时候碰到如下问题
mb-gcc未找到
解决办法:
sudo dpkg --add-architecture i386
sudo apt install libstdc++5:i386
然后又出现如下问题:
mb-gcc: error while loading shared libraries: libstdc++.so.6: wrong ELF class: ELFCLASS64
解决方法:
sudo apt install gcc-multilib
下载xilinx linux
cd linux-xlnx
export ARCH=arm64
export CROSS_COMPILE=aarch64-linux-gnu-
make xilinx_zynqmp_defconfig
make menuconfig
make -j4 #-jn n为你要运行的核数