zynqMP LINUX 移植

最近花了几天时间完成了zynqMP linux的移植工作,这里记录一下工作的流程。

    • zynqMP linux 启动过程
    • U-BOOT制作
    • ATF编译
    • BOOTBIN制作
    • LINUX编译


zynqMP linux 启动过程

下图时xilinx手册上摘录的图,描述了zynqMP 上的linux的整个boot过程
zynqMP LINUX 移植_第1张图片
  系统复位后,首先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内核。


U-BOOT制作

从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



ATF编译

下载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



BOOT.BIN制作

使用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 



LINUX编译

下载xilinx linux

cd linux-xlnx
export ARCH=arm64
export CROSS_COMPILE=aarch64-linux-gnu-
make xilinx_zynqmp_defconfig
make menuconfig
make -j4  #-jn n为你要运行的核数



你可能感兴趣的:(工具类)