0%

  记录一下 EBAZ4205 uboot 和 kernel 的配置过程。

准备

  使用的 vivado 版本为 2020.2。
  首先将工具链的路径 export 到 PATH

1
2
export PATH=/tools/Xilinx/Vitis/2020.2/gnu/aarch32/lin/gcc-arm-linux-gnueabi/bin/:$PATH
export PATH=/tools/Xilinx/Vitis/2020.2/bin:$PATH

  clone 以下 repo 到合适的地方。

  我们基本无需改动这些代码,只需要写好设备树就可以了。
  创建 arch/arm/dts/zynq-EBAZ4205.dts,定义好设备。
  这里有一份我的,参考link
  打开 arch/arm/dts/Makefile ,将我们的 zynq-EBAZ4205.dts 照葫芦画瓢加在 zynq-zc702.dtb 旁边。

1
2
make xilinx_zynq_virt_defconfig
DEVICE_TREE=zynq-EBAZ4205 make -j8
  • 去掉 xilinx_zynq_virt_defconfig 里的 CONFIG_ENV_IS_IN_SPI_FLASH=y

  linux-kernel 的设备树和 uboot 相同,放在 arch/arm/boot/dts/zynq-EBAZ4205.dts ,和上面差不多改下 arch/arm/boot/dts/Makefile 就可以了。

1
2
3
make xilinx_zynq_defconfig
make uImage UIMAGE_LOADADDR=0x8000
make dtbs

   得到 arch/arm/boot/uImage 和 arch/arm/boot/dts/zynq-EBAZ4205.dtb 这两个我们启动需要的文件。

JTAG 启动

  不想老拔插 sd 卡只好用 jtag 启动了,顺便还可以调试。
  我们可以用 xsct 来将 uboot.elf 文件通过 jtag 下载到板子的内存里,不过直接执行是有问题的,通过 emio 连接的 phy 会找不到。需要先执行 fsbl 里的初始化部分。
  这里使用 vivado 导出的 xsa 文件包含的 ps7_init.tcl 脚本通过 jtag 来初始化。正常独立启动时是由编译出的 fsbl 来做的。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
connect
targets -set -nocase -filter {name =~"APU*"}
rst -system
after 3000
fpga -file ../vitis/EBAZ4205_wrapper/export/EBAZ4205_wrapper/hw/EBAZ4205_wrapper.bit
loadhw -hw ../vitis/EBAZ4205_wrapper/export/EBAZ4205_wrapper/hw/EBAZ4205_wrapper.xsa -mem-ranges [list {0x40000000 0xbfffffff}] -regs
configparams force-mem-access 1
source ../vitis/EBAZ4205_wrapper/export/EBAZ4205_wrapper/hw/ps7_init.tcl
ps7_init
ps7_post_config
targets -set -nocase -filter {name =~ "*A9*#0"}
dow ../petalinux/u-boot-xlnx/u-boot.elf
configparams force-mem-access 0
con

  调试时在 vitis 新建一个调试配置,将脚本指定到上面那个文件就可以了,你可能需要修改一下文件的路径,如果需要在入口停住则去掉最后的 con。 uboot 会进行一次重定位,因此使用断点需要在配置里用带符号的文件 u-boot 设置好两个地址。

tftp kernel

  rootfs 从 link 下载

1
mkimage -A arm -T ramdisk -C gzip -d arm_ramdisk.image.gz uramdisk.image.gz

  tftp 服务器有很多实现这里我使用 dnsmasq 附带的。编辑/etc/dnsmasq.conf

1
2
3
listen-address=192.168.1.1
enable-tftp
tftp-root=/srv/tftp

  配置上面这几行就可以。将 uImage,zynq-EBAZ4205.dtb 还有 rootfs 放到/srv/tftp 下,启动

1
systemctl start dnsmasq

  通过 uart 连接板子执行

1
2
3
4
5
6
7
8
9
setenv ipaddr 192.168.1.10
setenv gatewayip 192.168.1.1
setenv netmask 255.255.255.0
setenv serverip 192.168.1.1

tftpboot 0 zynq-EBAZ4205.dtb
tftpboot 8000 uImage
tftpboot 1000000 uramdisk.image.gz
bootm 8000 1000000 0

  不出意外就能进入 shell 了。

dts

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
// SPDX-License-Identifier: GPL-2.0+
/*
* Copyright (C) 2011 - 2015 Xilinx
* Copyright (C) 2012 National Instruments Corp.
*/
/dts-v1/;
#include "zynq-7000.dtsi"

/ {
model = "EBAZ4205 board";
compatible = "xlnx,zynq-EBAZ4205", "xlnx,zynq-7000";

aliases {
ethernet0 = &gem0;
serial0 = &uart1;
mmc0 = &sdhci0;
};

memory@0 {
device_type = "memory";
reg = <0x0 0x10000000>;
};

chosen {
bootargs = "";
stdout-path = "serial0:115200n8";
};

gpio-keys {
compatible = "gpio-keys";
autorepeat;

s2 {
label = "s2";
gpios = <&gpio0 20 1>;
linux,code = <102>;
wakeup-source;
autorepeat;
};

s3 {
label = "s3";
gpios = <&gpio0 32 1>;
linux,code = <116>;
wakeup-source;
autorepeat;
};
};
};

&clkc {
ps-clk-frequency = <33333333>;
};

&gem0 {
status = "okay";
phy-mode = "rgmii-id";
phy-handle = <&ethernet_phy>;

ethernet_phy: ethernet-phy@0 {
reg = <0>;
device_type = "ethernet-phy";
};
};

&smcc {
status = "okay";
};

&nand0 {
status = "okay";
pinctrl-names = "default";
pinctrl-0 = <&pinctrl_nand0_default>;
partition@0 {
label = "nand-fsbl-uboot";
reg = <0x0 0x300000>;
};
partition@1 {
label = "nand-linux";
reg = <0x300000 0x500000>;
};
partition@2 {
label = "nand-device-tree";
reg = <0x800000 0x20000>;
};
partition@3 {
label = "nand-rootfs";
reg = <0x820000 0xa00000>;
};
partition@4 {
label = "nand-jffs2";
reg = <0x1220000 0x1000000>;
};
partition@5 {
label = "nand-bitstream";
reg = <0x2220000 0x800000>;
};
partition@6 {
label = "nand-allrootfs";
reg = <0x2a20000 0x4000000>;
};
partition@7 {
label = "nand-release";
reg = <0x6a20000 0x13e0000>;
};
partition@8 {
label = "nand-reserve";
reg = <0x7e00000 0x200000>;
};
};

&pinctrl0 {
pinctrl_nand0_default: nand0-default {
mux {
groups = "smc0_nand8_grp";
function = "smc0_nand";
};

conf {
groups = "smc0_nand8_grp";
bias-pull-up;
};
};

pinctrl_uart1_default: uart1-default {
mux {
groups = "uart1_4_grp";
function = "uart1";
};

conf {
groups = "uart1_4_grp";
slew-rate = <0>;
io-standard = <3>;
};
};
};

&sdhci0 {
u-boot,dm-pre-reloc;
status = "okay";
};

&uart1 {
u-boot,dm-pre-reloc;
status = "okay";
pinctrl-names = "default";
pinctrl-0 = <&pinctrl_uart1_default>;
};

  在 linux 中我们可以像一个块设备一样挂载一个文件,这是通过 loopdev 实现的。它可以将一个文件虚拟为一个块设备。

1
losetup `losetup -f` 镜像文件
  • losetup -f 找到第一个空闲的 loop 设备

  然后 mount 便能令其挂载。但是我们平时使用 mount 命令时却并不需要这样做,因为现代的 mount 可以自动帮我们做这件事。具体可以看 mount man 的 LOOP-DEVICE SUPPORT 章节。而且当它 umount 时也会自动释放占用的 loop 设备。

  问题来了,那 umount 怎么知道要释放 loop 设备而且不会误释放我们手动设置的 loop 设备呢?
通过查看 util-linux 的代码可以知道,是通过 user_mountflags 的 MNT_MS_LOOP 标志实现的。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
/**
* mnt_context_set_user_mflags:
* @cxt: mount context
* @flags: mount(2) flags (MNT_MS_* flags, e.g. MNT_MS_LOOP)
*
* Sets userspace mount flags.
*
* See also notes for mnt_context_set_mflags().
*
* Returns: 0 on success, negative number in case of error.
*/
int mnt_context_set_user_mflags(struct libmnt_context *cxt, unsigned long flags)
{
if (!cxt)
return -EINVAL;
cxt->user_mountflags = flags;
return 0;
}

  石子,围棋,算盘
  电
  用会动的东西果然让人方便不少呢。

  • 随笔可能有错误,请多包涵。
  • 如果有时间可以到repo下提 issue,谢谢。

  最近想折腾一下 FPGA,需要安装 xilinx 的一套工具。这堆东西真的大。自己想了想,为了稳定性还有使用上的方便。决定将这一套工具安装到虚拟机内,虚拟机还能有快照。于是看了下 linux 下的虚拟机。
  最初想用 lxc 容器,它靠内核来隔离用户空间,性能应该是最好的了,然而使用的还是和主机相同的内核,对于一些需要在内核上安装驱动的场景就不太合适了,弃之。
  最后还是用上了“传统”的虚拟机,毕竟有时候还要用到 windows 下的一些工具。先想到的是 vmware,virtualbox 这样的,但是 vmware 要钱,virtualbox 的图形似乎不太好,看 LTT 看到 linux 下的 qemu+kvm 似乎性能不错,就找几篇 wiki 看了一下。才发现功能强大,性能损失可以到相当低的地步,内存也可以在运行时动态分配,自己火星了。想来很早之前用 android sdk 时用的模拟器性能差劲,导致对 qemu 印象不好,一直没用上这一套。用了好长一段时间双系统,切换是真的麻烦。

图形

  对于虚拟机的图形来说,在合适的硬件上可以让显卡直通虚拟机,叫做 PCI passthrough,打游戏都不成问题。但是这样不太灵活,直通要求虚拟机独占一块显卡和显示器。不过也可以使用 LTT 的视频中用的办法来提高灵活性。
  如果机器上有 Intel 的核显,你也可以使用由 Intel 开发的 iGVT-g 来获得满足轻度使用的性能,客户机可以使用未修改的 Intel 显卡驱动,兼容性也不错。
  通用一点的是 Virgil 3D,令虚拟机使用主机的渲染节点,不过 windows 的驱动似乎还不太完善,性能个人没有测试,从搜索结果来看,似乎还不是特别好。

存储

  大概要感谢云计算和虚拟化的发展,qemu/kvm 在存储上是非常灵活的,既可以使用文件,也可以使用硬盘分区,还可以加上 lvm,使用跨盘跨分区的逻辑卷,这样的逻辑卷本身就有快照功能。更绝的是对于支持的 linux 客户机,使用 9p 或者新出的性能更好的 virtio-fs 可将 root 挂在在主机的文件夹中,这样不会有虚拟磁盘有可能产生的空间浪费,文件共享也更加轻松。不过这样没有快照,你可能需要手动配置 OverlayFS 来做到差不多的效果,这样的共享还可能会导致更多的漏洞。
  我自己没有使用 lvm,又没有在使用前做好功课,使用 ext4 文件系统下的虚拟磁盘文件+ovmf uefi 启动,由于现在的(2019-12)libvirt 对 uefi 启动的虚拟机快照支持不完善,导致快照使用起来有点麻烦,叹气。

动态内存分配

  在设置好最大可以占用内存后,可以在虚拟机开机时动态调整实际占用的内存大小,要注意最大值不能在运行时调整。windows 客户机需要按照下面这个说明安装驱动。这个特性对日常桌面应用应该是提高了不少可用性。

  自动分配,启用之后感觉客户机吃内存时变卡了些。

最终想要的效果

  三大操作系统程序都能跑,性能损耗不大,存储空间和内存浪费小,互相隔离又有快照,还能轻松迁移。甚至可以跑个 androidx86,,,感觉总算得到了一个个人比较满意的环境。

糖炒栗子

  下面用我的 arch 主机搭建一个用于 xilinx 工具的 ubuntu 18.04.3 lts 虚拟机。

准备

  安装

1
sudo pacman -S qemu virt-manager

  这里我选择 virt-manager 为图形前端方便使用。
你也可以通过命令使用 qemu 来直接运行虚拟机。

准备系统镜像

  下载 ubuntu 之类的发行版选择一个速度快的镜像站点下载即可。

新建虚拟机

  执行

1
virt-manager

  添加连接 QEMU/KVM ,然后新建虚拟机,按照提示一步步来即可。在最后一步选择 在安装前自定义配置 ,在此时我们就可以做一些调整。

调整

  一些配置需要编辑 xml 文件,请先在虚拟系统管理器的首选项中启用 XML 编辑。
我们可以删除一些用不到的设备例如数位板,这样可以提高性能。详细配置可以参考下面两个链接。

减少磁盘空间浪费

自动调整使用的内存

图形

  显卡类型改为 virtio ,勾选 3d acceleration。
显示协议监听类型改为无,勾选 OpenGL。

  轻度使用这样就可以了。

60FPS

  默认状态下 qemu(版本 4.2.0)显示的帧率最多为 30FPS,要想更加流畅需要小小地修改一下。

1
2
3
4
5
6
7
8
9
10
11
12
13
diff --git a/include/ui/console.h b/include/ui/console.h
index 281f9c145b..fa6c472042 100644
--- a/include/ui/console.h
+++ b/include/ui/console.h
@@ -26,7 +26,7 @@
#define QEMU_CAPS_LOCK_LED (1 << 2)

/* in ms */
-#define GUI_REFRESH_INTERVAL_DEFAULT 30
+#define GUI_REFRESH_INTERVAL_DEFAULT 17
#define GUI_REFRESH_INTERVAL_IDLE 3000

/* Color number is match to standard vga palette */

  不过,即使做了以上修改,在使用 virt-manager 内置的 spice 连接直通虚拟机时,你可能会注意到鼠标看起来帧率并不高。临时的办法是把鼠标直通给虚拟机,这样就不会看起来卡卡的了。

windows10 虚拟机

图形 iGVT-g

  233
  随便写写,折腾了一下,不用在本地安装 hexo 了。