Skip to content

Latest commit

 

History

History
967 lines (687 loc) · 46.9 KB

File metadata and controls

967 lines (687 loc) · 46.9 KB

一、安装开发系统

在这一章中,我们将介绍和建立我们的工作平台。事实上,即使我们在工作的 PC 上编写然后测试自己的设备驱动,也建议使用第二个设备来测试代码。这是因为我们将在内核空间工作,即使是一个小错误也会导致严重的故障!此外,使用一个有多种外设可用的平台,我们可以测试各种各样的设备,而这些设备在电脑上并不总是可用的。当然,您可以自由使用自己的系统来编写和测试驱动,但是,在这种情况下,您应该注意进行必要的修改以符合您的电路板规格。

在这本书里,我要用的是 Marvell ESPRESSObin 系统,这是一款功能强大的高级 RISC Machines(ARM)64 位机,有很多有趣的功能。在下图中,您可以看到信用卡旁边的 ESPRESSObin,并可以了解主板的真实尺寸:

我的板是 ESPRESSObin 的 v5 版本,而在撰写本文时(2018 年 9 月宣布)的最新版本是 v7,所以读者应该可以在本书出版时获得这个新版本。新的 ESPRESSObin v7 将采用 1GB DDR4 和 2GB DDR4 配置(而 v5 具有 DDR3 RAM 芯片),新的 1.2GHz 芯片组将取代目前销售的配置,后者具有 800MHz 和 1GHz CPU 频率限制。即使快速查看一下新的主板布局,我们也可以看到,单个 SATA 连接器已经取代了现有的 SATA 电源和接口的两件式组合,LED 布局现在已连续重新排列,并且板载 eMMC 现已就位。此外,这一新版本将附带可选的 802.11ac +蓝牙 4.2 迷你 PCIe 无线网卡,单独出售。

Lastly, you will now have the option to order your v7 ESPRESSObin with a complete enclosure. This product has FCC and CE certifications to help to enable mass deployment. Further information regarding the revision v7 (and v5) can be found at http://wiki.espressobin.net/tiki-index.php?page=Quick+User+Guide.

为了测试我们的新驱动,我们将在第一章中介绍以下方法:

  • 设置主机
  • 使用串行控制台
  • 配置和构建内核
  • 设置目标机器
  • 在外部硬件上进行本机编译

技术要求

以下是一些有趣的网址,我们可以从中获得有关该板的有用技术信息:

看看http://espressobin.net/tech-spec/的技术规格,我们可以获得以下信息,从中我们可以看到 ESPRESSObin v5 在计算能力、存储、网络和可扩展性方面可以提供什么:

| 片上系统 ( SoC ) | Marvell Armada 3700LP (88F3720)双核 ARM Cortex A53 处理器,最高 1.2GHz | | 系统内存 | 1 GB DDR3 或可选的 2GB DDR3 | | 仓库 | 1x SATA 接口 1x 微型 SD 卡插槽,可容纳可选的 4GB EMMC | | 网络连接 | 1x Topaz 网络交换机 2x 千兆以太网局域网 1x 以太网广域网 1x MiniPCIe 插槽,用于无线/BLE 外围设备 | | 通用串行总线 | 1 个 USB 3.0 1 个 USB 2.0 1 个微型 USB 端口 | | 膨胀 | 2x 46 针 GPIO 头,用于配件和屏蔽,带 I2C、GPIOs、PWM、UART、SPI、MMC 等。 | | 混杂的 | 复位按钮和 JTAG 界面 | | 电源 | 12V DC 插孔或 5V 通过微型通用串行总线端口 | | 功率消耗 | 1 GHz 时散热小于 1W |

特别是,下面的截图显示了 Marvell ESPRESSObin v5 的俯视图(从现在开始,请考虑到我不再明确添加“v5”了):

在前面的截图中,我们可以看到以下组件:

  • 电源连接器(12V DC 插孔)
  • 复位开关
  • 微型通用串行总线设备端口(串行控制台)
  • 以太网端口
  • 通用串行总线主机端口

下一张截图显示了 microSD 插槽所在的电路板的仰视图;这是我们应该插入我们将在本章后面创建的 microSD 的地方:

在本书中,我们将看到如何管理(并重新安装)一个完整的 Debian 发行版,这将允许我们拥有一系列现成的软件包,就像在普通 PC 中一样(事实上,Debian ARM64 版本相当于 Debian x86 版本)。之后,我们将为该板开发我们的设备驱动,然后,如果可能的话,我们将使用连接到 ESPRESSObin 本身的真实设备来测试它们。本章还提供了一个关于如何设置主机系统的小教程,您可以使用它来设置一个基于 GNU/Linux 的工作机器或一个专用的虚拟机器。

本章使用的代码和其他文件可以在https://GitHub . com/gio metti/Linux _ device _ driver _ development _ cook book/tree/master/chapter _ 01下载。

设置主机

每个优秀的设备驱动开发者都知道,主机是绝对必要的。 即使现在嵌入式设备越来越强大(ESPRESSObin 就是其中之一),也有一些耗费资源的任务需要主机来帮忙。 这就是为什么,在这一部分,我们将展示如何设置我们的主机。

我们决定使用的主机可以是普通的个人电脑,也可以是虚拟化的——它们是等价的——但重要的是,它必须运行基于 GNU/Linux 的操作系统。

准备好

在本书中,我将使用一个基于 Ubuntu 18.04 LTS 的系统,但是您可以决定尝试将本书过程中我们将使用的一些设置和安装命令复制到另一个主要的 Linux 发行版中,对于 Debian 衍生版本来说,几乎不需要做什么努力,或者对于非 Debian 衍生发行版来说,以更复杂的方式。

我不打算展示如何在个人电脑或虚拟机上安装一个全新的 Ubuntu 系统,因为对于一个真正的程序员来说,这是一项非常简单的任务;然而,作为本章的最后一步(在外部硬件上进行本机编译的配方),我将介绍一个有趣的跨平台环境,并附带如何安装它的详细步骤,该环境被证明对在主机上编译外部目标代码非常有用,就像我们在目标上一样。当我们需要在您的开发电脑上运行几个不同的操作系统时,这个过程非常有用。

因此,在这一点上,读者应该有自己的电脑运行(本地或虚拟化)新安装的 Ubuntu 18.04 LTS 操作系统。

主机的主要用途是编辑和交叉编译我们的新设备驱动,并通过串行控制台管理我们的目标设备,创建其根文件系统,等等。

为了做好这件事,我们需要一些基本的工具;其中一些是通用的,而另一些则取决于我们将要在其上编写驱动的特定平台。

通用工具当然是编辑器、版本控制系统和编译器及其相关组件,而特定平台工具本质上是交叉编译器及其相关组件(在某些平台上,我们可能需要额外的工具,但我们的里程可能会有所不同,无论如何,每个制造商都会为我们提供舒适的编译环境所需的所有要求)。

关于编辑器:我不打算在这上面花任何话,因为读者可以使用他们想要的任何东西(例如,关于我自己,我仍然在用 vi editor 编程),但是关于其他工具,我必须更加具体。

怎么做...

现在我们的 GNU/Linux 发行版已经启动并在我们的主机上运行,我们可以开始安装一些我们将在本书中使用的程序:

  1. 首先,让我们安装基本的编译工具:
$ sudo apt install gcc make pkg-config \
 bison flex ncurses-dev libssl-dev \
 qemu-user-static debootstrap

As you know already, the sudo command is used to execute a command as a privileged user. It should be already present in your system, otherwise you can install it by using the apt install sudo command as the root user.

  1. 接下来,我们必须测试编译工具。我们应该能编译一个 C 程序。作为一个简单的测试,让我们使用存储在helloworld.c文件中的以下标准 Hello World 代码:
#include <stdio.h>

int main(int argc, char *argv[])
{
    printf("Hello World!\n");

    return 0;
}

Remember that code can be downloaded from our GitHub repository.

  1. 现在,我们应该能够通过使用以下命令来编译它:
$ make CFLAGS="-Wall -O2" helloworld
cc -Wall -O2 helloworld.c -o helloworld

在前面的命令中,我们使用了编译器和make工具,这是以舒适和可靠的方式编译每个 Linux 驱动所必需的。

You can get more information regarding make by taking a look at https://www.gnu.org/software/make/, and for gcc, you can go to https://www.gnu.org/software/gcc/.

  1. 最后,我们可以在主机上测试它,如下所示:
$ ./helloworld 
Hello World!
  1. 下一步是安装交叉编译器。因为我们将使用 ARM64 系统,所以我们需要一个交叉编译器及其相关工具。要安装它们,我们只需使用以下命令:
$ sudo apt install gcc-7-aarch64-linux-gnu

Note that we can also use an external toolchain as reported in the ESPRESSObin wiki at http://wiki.espressobin.net/tiki-index.php?page=Build+From+Source+-+Toolchain; however, the Ubuntu toolchain works perfectly!

  1. 安装完成后,使用前面的 Hello World 程序测试我们新的交叉编译器,如下所示:
$ sudo ln -s /usr/bin/aarch64-linux-gnu-gcc-7 /usr/bin/aarch64-linux-gnu-gcc
$ make CC=aarch64-linux-gnu-gcc CFLAGS="-Wall -O2" helloworld
aarch64-linux-gnu-gcc-7 -Wall -O2 helloworld.c -o helloworld

Note that I've removed the previously compiled helloworld program in order to be able to correctly compile this new version. To do so, I used the mv helloworld helloworld.x86_64 command due to the fact I'll need the x86 version again.

Also, note that since Ubuntu doesn't automatically create the standard cross-compiler name, aarch64-linux-gnu-gcc, we have to do it manually by using the preceding ln command before executing make.

  1. 好了,现在我们可以使用下面的file命令来验证新创建的 ARM64 版本的helloworld程序。这将指出程序是为哪个平台编译的:
$ file helloworld
helloworld: ELF 64-bit LSB shared object, ARM aarch64, version 1 (SYSV), dynamically linked, interpreter /lib/ld-linux-aarch64.so.1, for GNU/Linux 3.7.0, BuildID[sha1]=c0d6e9ab89057e8f9101f51ad517a253e5fc4f10, not stripped

如果我们在先前重命名的版本helloworld.x86_64上再次使用file命令,我们会得到以下结果:

$ file helloworld.x86_64 
helloworld.x86_64: ELF 64-bit LSB shared object, x86-64, version 1 (SYSV), dynamically linked, interpreter /lib64/ld-linux-x86-64.so.2, for GNU/Linux 3.2.0, BuildID[sha1]=cf932fab45d36f89c30889df98ed382f6f648203, not stripped
  1. 为了测试这个新版本是否真的针对 ARM64 平台,我们可以使用 QEMU ,这是一个开源的通用机器仿真器和虚拟器,能够在运行的平台上执行外来代码。要安装它,我们可以像前面的代码一样使用apt命令,指定qemu-user-static包:
$ sudo apt install qemu-user-static
  1. 然后,我们可以执行我们的 ARM64 程序:
$ qemu-aarch64-static -L /usr/aarch64-linux-gnu/ ./helloworld
Hello World!

To get further information about QEMU, a good staring point is its home page at https://www.qemu.org/.

  1. 下一步是安装版本控制系统。我们必须安装用于 Linux 项目的版本控制系统,即git。要安装它,我们可以像以前一样使用以下命令:
$ sudo apt install git

如果一切顺利,我们应该能够如下执行:

$ git --help
usage: git [--version] [--help] [-C <path>] [-c <name>=<value>]
           [--exec-path[=<path>]] [--html-path] [--man-path]
           [--info-path] [-p | --paginate | --no-pager]
           [--no-replace-objects] [--bare] [--git-dir=<path>]
           [--work-tree=<path>] [--namespace=<name>]
           <command> [<args>]

These are common Git commands used in various situations:

start a working area (see also: git help tutorial)
   clone Clone a repository into a new directory
   init Create an empty Git repository or reinitialise an existing one
...

In this book, I'm going to explain every git command used but for complete knowledge of this powerful tool, I suggest you start reading https://git-scm.com/.

请参见

使用串行控制台

如前所述(任何真正的嵌入式设备程序员都知道),串行控制台是设备驱动开发阶段的必备工具!那么,让我们看看如何通过它的串行控制台访问我们的 ESPRESSObin。

准备好

技术要求部分截图所示,有一个微型 USB 接口,直接连接 ESPRESSObin 的串口控制台。因此,使用适当的 USB 电缆,我们可以将其连接到我们的主机电脑。

如果所有连接都正常,我们可以执行任何串行终端仿真器,从串行控制台查看数据。关于这个工具,我必须声明,作为编辑程序,我们可以使用我们喜欢的任何东西。但是,我将展示如何安装两个更常用的终端仿真程序— minicomscreen

Note that this tool is not strictly required and its usage depends on the platform you're going to work on; however, in my humble opinion, this is the most powerful development and debugging tool ever! So, you definitely need it.

要安装minicom,请使用以下命令:

$ sudo apt install minicom

现在,要安装名为screen的终端仿真器,我们只需将minicom字符串替换为screen数据包名称,如下图所示:

$ sudo apt install screen

它们都需要一个串行端口来工作,调用命令也非常相似。为了简洁起见,我将报告它们的用法,以便只与 ESPRESSObin 连接;但是,有关它们的更多信息,您应该参考它们的手册页(使用man minicomman screen来显示它们)。

怎么做...

要测试与目标系统的串行连接,我们可以执行以下步骤:

  1. 首先,我们要找到正确的串口。由于 ESPRESSObin 使用 USB 仿真串行端口(波特率为 115,200),通常我们的目标端口被命名为ttyUSB0(但是您的里程可能会有所不同,所以让我们在继续之前验证一下)因此我们必须使用的minicom命令与 ESPRESSObin 串行控制台连接如下:
$ minicom -o -D /dev/ttyUSB0

To correctly get access to the serial console, we may need proper privileges. In fact, we may try to execute the preceding minicom command, and we don't get an output! This is because the minicom command silently exits if we don't have enough privileges to get access to the port. We can verify our access to privileges by simply using another command on it, as shown here: $ cat /dev/ttyUSB0 cat: /dev/ttyUSB0: Permission denied In this case, the cat command perfectly tells us what's wrong so we can fix this issue using sudo or, even better, by properly adding our system's user to the right group as shown here: $ ls -l /dev/ttyUSB0 crw-rw---- 1 root dialout 188, 0 Jan 12 23:06 /dev /ttyUSB0 $ sudo adduser $LOGNAME dialout Then, we log out and log in again, and we can access the serial devices without any problem.

  1. 使用screen的等效命令报告如下:
$ screen /dev/ttyUSB0 115200

Note that, on minicom, I didn't specify the serial communication options (baud rate, parity, and so on) while, for screen, I've added the baud rate on the command line; this is because my default minicom configuration automatically uses correct communication options while screen uses 9,600 baud as a default baud rate. Please refer to the program man pages for further information about how to do this setting in order to fit your needs.

  1. 如果一切正常,在正确的串行端口上执行终端模拟器后,打开我们的 ESPRESSObin(只需接通电源)。我们应该在终端上看到以下输出:
NOTICE: Booting Trusted Firmware
NOTICE: BL1: v1.3(release):armada-17.06.2:a37c108
NOTICE: BL1: Built : 14:31:03, Jul 5 2NOTICE: BL2: v1.3(release):armada-17.06.2:a37c108
NOTICE: BL2: Built : 14:31:04, Jul 5 201NOTICE: BL31: v1.3(release):armada-17.06.2:a37c108
NOTICE: BL31:

U-Boot 2017.03-armada-17.06.3-ga33ecb8 (Jul 05 2017 - 14:30:47 +0800)

Model: Marvell Armada 3720 Community Board ESPRESSOBin
       CPU @ 1000 [MHz]
       L2 @ 800 [MHz]
       TClock @ 200 [MHz]
       DDR @ 800 [MHz]
DRAM: 2 GiB
U-Boot DComphy-0: USB3 5 Gbps 
Comphy-1: PEX0 2.5 Gbps 
Comphy-2: SATA0 6 Gbps 
SATA link 0 timeout.
AHCI 0001.0300 32 slots 1 ports 6 Gbps 0x1 impl SATA mode
flags: ncq led only pmp fbss pio slum part sxs 
PCIE-0: Link down
MMC: sdhci@d0000: 0
SF: Detected w25q32dw with page size 256 Bytes, erase size 4 KiB, total 4 MiB
Net: eth0: neta@30000 [PRIME]
Hit any key to stop autoboot: 2 

请参见

配置和构建内核

现在,是时候下载内核源代码,然后配置和构建它们了。需要这一步有几个原因:第一个原因是我们需要一个内核来引导操作系统,第二个原因是我们需要一个配置好的内核源代码树来编译我们的驱动。

准备好

由于从 4.11 版本开始,我们的 ESPRESSObin 现在被支持到普通内核中,我们可以通过使用以下git命令来获取 Linux 源代码:

$ git clone git://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git

This command will take a lot of time to finish so I would suggest you take a break by drinking your favorite cup of coffee (as real programmers should do).

完成后,我们可以进入linux目录查看 Linux 源码:

$ cd linux/
$ ls
arch CREDITS firmware ipc lib mm scripts usr
block crypto fs Kbuild LICENSES net security virt
certs Documentation include Kconfig MAINTAINERS README sound
COPYING drivers init kernel Makefile samples tools

这些来源与可能不稳定的最新内核版本有关,因此为了确保我们使用的是稳定的内核版本(或长期版本,让我们提取 4.18 版本,这是编写本章时的当前稳定版本,如下所示:

$ git checkout -b v4.18 v4.18

怎么做...

在开始编译之前,我们必须配置内核和编译环境。

  1. 最后一项任务非常简单,它包括执行以下环境变量分配:
$ export ARCH=arm64
$ export CROSS_COMPILE=aarch64-linux-gnu-
  1. 然后,我们可以通过简单地使用以下命令来选择 ESPRESSObin 标准内核配置:
$ make defconfig

Depending on the kernel release you're using, the default configuration file may be also called mvebu_defconfig or either mvebu_v5_defconfig or mvebu_v7_defconfig. So, please take a look into the linux/arch/arm64/configs/ directory in order to see which file is present that best suits your needs. In my system, I have the following: $ ls linux/arch/arm64/configs/ defconfig

  1. 如果我们希望修改这个默认配置,我们可以执行make menuconfig命令,它将显示一个漂亮的菜单,我们可以在其中输入我们的修改以满足我们的需求。以下屏幕截图显示了内核配置菜单在终端上的显示方式:

  1. 在继续之前,我们必须确保在内核中启用了分布式交换机架构 ( DSA ,否则我们根本无法使用以太网端口!这是因为 ESPRESSObin 有一个复杂的(并且非常强大的)内部网络交换机,必须使用这种特殊的支持来管理。

For further information regarding the DSA, you can start reading the linux/Documentation/networking/dsa/dsa.txt file, located in the kernel sources we're currently working on.

  1. 要启用 DSA 支持,只需导航到网络支持的内核菜单。转到网络选项,最后启用分布式交换机体系结构支持。之后,我们必须回到菜单的顶层,然后选择这些条目:设备驱动|网络设备支持|分布式交换机架构驱动,然后启用 Marvell 88E6xxx 以太网交换机结构支持,这是 ESPRESSObin 的板载交换机芯片。

Remember that, to enable a kernel feature as a module or a built-in, you need to highlight the desired feature and then press the spacebar until the character inside the <> characters changes to * (which means built-in, that is, <*>) or to M (which means module, that is, ). Note that, to enable DSA as a built-in instead of as a module, we have to disable 802.1d Ethernet Bridging support (that is, the entry just above).

  1. 好吧,在所有内核设置就绪之后,我们可以使用以下make命令启动内核编译:
$ make Image dtbs modules

Again, as the downloading command, this command will need a lot of time to finish, so let me suggest you take another break. However, in order to speed up the compilation process, you may try using the -j option argument in order to tell make to use several simultaneous process to compile the code. For example, on my machine, having eight CPU threads, I use the following command: $ make -j8 Image dtbs modules So, let's try using the following lscpu command to get how many CPUs your system has: lscpu | grep '^CPU(s):' CPU(s): 8 Alternatively, on Ubuntu/Debian, there's also the pre-installed nproc utility, so the following command also does the trick: $ make -j$(nproc)

完成后,我们应该将内核映像放入arch/arm64/boot/Image文件,将设备树二进制文件放入arch/arm64/boot/dts/marvell/armada-3720-espressobin.dtb文件,这些文件准备好传输到我们将在下一个食谱中构建的 microSD 中,设置目标机器

请参见

设置目标机器

现在,是时候在我们的目标系统上安装我们需要的任何东西了;由于 ESPRESSObin 仅与引导加载程序一起出售,我们必须做一些工作,以便获得一个具有适当操作系统的功能齐全的系统。

In this book, I'm going to use a Debian OS for the ESPRESSObin but you may use other OSes as reported at http://wiki.espressobin.net/tiki-index.php?page=Software+HowTo. On this site, you can get more detailed information about how to properly set up your ESPRESSObin to fit your needs.

准备好

即使 ESPRESSObin 可以从不同的媒体启动,我们也将使用 microSD,因为这是设置系统最简单、最有用的方法。对于不同的媒体,请参考 ESPRESSObin 的维基页面——参见http://wiki.espressobin.net/tiki-index.php?page = Boot+from+可移动+存储+-+Ubuntu 举一些例子。

怎么做...

要设置 microSD,我们必须使用我们的主机,因此插入它,然后找到相应的设备。

  1. 如果我们使用的是 SD/microSD 插槽,只要插入介质,我们就会在内核消息中看到类似这样的内容:
mmc0: cannot verify signal voltage switch
mmc0: new ultra high speed SDR50 SDHC card at address aaaa
mmcblk0: mmc0:aaaa SL08G 7.40 GiB 
 mmcblk0: p1

To get kernel messages on the Terminal, we can use the dmesg command.

但是,如果我们要使用 microSD 转 USB 适配器内核,消息将如下所示:

usb 1-6: new high-speed USB device number 5 using xhci_hcd
usb 1-6: New USB device found, idVendor=05e3, idProduct=0736
usb 1-6: New USB device strings: Mfr=3, Product=4, SerialNumber=2
usb 1-6: Product: USB Storage
usb 1-6: Manufacturer: Generic
usb 1-6: SerialNumber: 000000000272
usb-storage 1-6:1.0: USB Mass Storage device detected
scsi host4: usb-storage 1-6:1.0
usbcore: registered new interface driver usb-storage
usbcore: registered new interface driver uas
scsi 4:0:0:0: Direct-Access Generic STORAGE DEVICE 0272 PQ: 0 ANSI: 0
sd 4:0:0:0: Attached scsi generic sg3 type 0
sd 4:0:0:0: [sdc] 15523840 512-byte logical blocks: (7.95 GB/7.40 GiB)
sd 4:0:0:0: [sdc] Write Protect is off
sd 4:0:0:0: [sdc] Mode Sense: 0b 00 00 08
sd 4:0:0:0: [sdc] No Caching mode page found
sd 4:0:0:0: [sdc] Assuming drive cache: write through
 sdc: sdc1
sd 4:0:0:0: [sdc] Attached SCSI removable disk
  1. 定位媒体的另一种简单方法是使用lsblk命令,如下所示:
$ lsblk 
NAME MAJ:MIN RM SIZE RO TYPE MOUNTPOINT
loop0 7:0 0 5M 1 loop /snap/gedit/66
loop1 7:1 0 4.9M 1 loop /snap/canonical-livepatch/50
...
sdb 8:16 0 931.5G 0 disk 
└─sdb1 8:17 0 931.5G 0 part /run/schroot/mount/ubuntu-xenial-amd64-f72c490
sr0 11:0 1 1024M 0 rom 
mmcblk0 179:0 0 7.4G 0 disk 
└─mmcblk0p1
        179:1 0 7.4G 0 part /media/giometti/5C60-6750
  1. 现在很明显,我们的 microSD 卡在这里被列为/dev/mmcblk0,但它不是空的。由于我们想要清除它的所有内容,我们必须首先使用以下命令清除它:
$ sudo dd if=/dev/zero of=/dev/mmcblk0 bs=1M count=100
  1. 为了在媒体设备上安全工作,您可能需要在继续清除之前卸载设备,因此让我们在所有设备上使用umount命令卸载设备的所有分区,就像我在下面对我的 microSD 上唯一定义的分区所做的那样:
$ sudo umount /dev/mmcblk0p1

您只需对您的 microSD 上的每个已定义分区重复此命令。

  1. 现在,我们将使用下一个命令在空 SD 卡上创建一个新分区/dev/mmcblk0p1:
$ (echo n; echo p; echo 1; echo ''; echo ''; echo w) | sudo fdisk /dev/mmcblk0

如果一切正常,我们的 microSD 媒体应该显示为格式化的,如下所示:

$ sudo fdisk -l /dev/mmcblk0
Disk /dev/mmcblk0: 7.4 GiB, 7948206080 bytes, 15523840 sectors
Units: sectors of 1 * 512 = 512 bytes
Sector size (logical/physical): 512 bytes / 512 bytes
I/O size (minimum/optimal): 512 bytes / 512 bytes
Disklabel type: dos
Disk identifier: 0x34f32673

Device Boot Start End Sectors Size Id Type
/dev/mmcblk0p1 2048 15523839 15521792 7.4G 83 Linux
  1. 然后,我们必须使用以下命令将其格式化为 EXT4:
$ sudo mkfs.ext4 -O ^metadata_csum,^64bit -L root /dev/mmcblk0p1

Note that this command line works for the e2fsprogs version >=1.43 only! If you're using an older release, you should use the following command: $ sudo mkfs.ext4 -L root /dev/mmcblk0p1

  1. 接下来,在您的本地 Linux 机器上挂载这个分区:
$ sudo mount /dev/mmcblk0p1 /mnt/

Note that, on some OSes (and especially on Ubuntu), as soon as we unplug and then we plug in the media device again, it is mounted automatically into /media/$USER/root where $USER is an environment variable holding your username. For instance, on my machine, I have the following: $ ls -ld /media/$USER/root drwxr-xr-x 3 root root 4096 Jan 10 14:28 /media/giometti/root/

添加 Debian 文件

我决定使用 Debian 作为目标操作系统,因为它是我最喜欢的开发(如果可能的话,生产)系统发行版:

  1. 要安装它,我们再次使用 QEMU 软件,使用以下命令:
$ sudo qemu-debootstrap \
 --arch=arm64 \
 --include="sudo,file,openssh-server" \
 --exclude="debfoster" \
 stretch ./debian-stretch-arm64 http://deb.debian.org/debian

You could see warnings about keyring here; they are harmless and they can be safely ignored: W: Cannot check Release signature; I suppose this is another coffee-break command.

  1. 一旦完成,我们应该在debian-stretch-arm64中为 ESPRESSObin 找到一个干净的 Debian 根文件系统,但是,在将它传输到 microSD 之前,我们应该修复hostname文件内容,如下所示:
$ sudo bash -c 'echo espressobin | cat > ./debian-stretch-arm64/etc/hostname'
  1. 然后,我们必须将串行设备ttyMV0添加到/etc/securetty文件中,以便能够通过串行设备/dev/ttyMV0作为根用户登录。使用以下命令:
$ sudo bash -c 'echo -e "\n# Marvell serial ports\nttyMV0" | \
 cat >> ./debian-stretch-arm64/etc/securetty'

Use man securetty for further information about the root login through a serial connection.

  1. 最后一步,我们必须设置根密码:
$ sudo chroot debian-stretch-arm64/ passwd
Enter new UNIX password: 
Retype new UNIX password: 
passwd: password updated successfully

这里,我使用root字符串作为根用户的密码(由您选择您的密码)。

In order to have further information regarding this usage of the chroot command, you can use the man chroot command or continue reading till the end of this chapter where I'm going to explain a bit better how it works.

现在,我们可以使用以下命令将所有文件安全地复制到我们的 microSD 中:

$ sudo cp -a debian-stretch-arm64/* /media/$USER/root/

以下是 microSD 内容的外观:

$ ls /media/$USER/root/
bin   dev  home  lost+found  mnt  proc  run   srv  tmp  var
boot  etc  lib   media       opt  root  sbin  sys  usr

添加内核

在操作系统文件之后,我们还需要内核映像来获得一个正在运行的内核,在前面的部分中,我们将内核映像放入arch/arm64/boot/Image文件,将设备树二进制放入arch/arm64/boot/dts/marvell/armada-3720-espressobin.dtb文件,这些文件已经准备好传输到我们新创建的 microSD 中:

  1. 让我们将它们复制到/boot目录中,如下所示:
$ sudo cp arch/arm64/boot/Image \
 arch/arm64/boot/dts/marvell/armada-3720-espressobin.dtb \
 /media/$USER/root/boot/

If the /boot directory was not present in the microSD and the preceding command returned an error, you can recover by using the following command and rerun the preceding cp command: $ sudo mkdir /media/$USER/root/boot

然后,/boot目录应该是这样的:

$ ls /media/$USER/root/boot/
armada-3720-espressobin.dtb  Image
  1. 前面的文件足以引导系统;但是,为了也安装内核模块和头文件,这对编译新软件很有用,我们可以在所有 Debian 文件都安装到 microSD 后使用下一个命令(以避免用 Debian 文件覆盖):
$ sudo -E make modules_install INSTALL_MOD_PATH=/media/$USER/root/
$ sudo -E make headers_install INSTALL_HDR_PATH=/media/$USER/root/usr/

好了,现在我们终于准备好把它捆绑起来,运行我们新的 Debian 系统,所以让我们卸载 microSD,并将其插入 ESPRESSObin。

设置引导变量

通电后,我们应该从串行控制台获取引导加载程序的消息,然后在执行自动引导之前,我们应该看到超时值为 0:

  1. 点击键盘上的回车键快速停止倒计时,得到引导加载程序的提示,如下:
Model: Marvell Armada 3720 Community Board ESPRESSOBin
       CPU @ 1000 [MHz]
       L2 @ 800 [MHz]
       TClock @ 200 [MHz]
       DDR @ 800 [MHz]
DRAM: 2 GiB
U-Boot DComphy-0: USB3 5 Gbps 
Comphy-1: PEX0 2.5 Gbps 
Comphy-2: SATA0 6 Gbps 
SATA link 0 timeout.
AHCI 0001.0300 32 slots 1 ports 6 Gbps 0x1 impl SATA mode
flags: ncq led only pmp fbss pio slum part sxs 
PCIE-0: Link down
MMC: sdhci@d0000: 0
SF: Detected w25q32dw with page size 256 Bytes, erase size 4 KiB, total 4 MiB
Net: eth0: neta@30000 [PRIME]
Hit any key to stop autoboot: 0 
Marvell>>

The ESPRESSObin's bootloader is U-Boot, which has its home page at https://www.denx.de/wiki/U-Boot.

  1. 现在,让我们使用ext4ls命令再次检查 microSD 卡是否有必要的文件,如下所示:
Marvell>> ext4ls mmc 0:1 boot
<DIR> 4096 .
<DIR> 4096 ..
        18489856 Image
            8359 armada-3720-espressobin.dtb

好了,一切都准备好了,所以从 microSD 卡启动只需要几个变量。

  1. 我们可以使用echo命令在任意点显示当前定义的变量,也可以使用setenv命令重新配置它们。首先,检查并设置正确的映像和设备树路径和名称:
Marvell>> echo $image_name
Image
Marvell>> setenv image_name boot/Image
Marvell>> echo $fdt_name
armada-3720-espressobin.dtb
Marvell>> setenv fdt_name boot/armada-3720-espressobin.dtb

Note that, filenames were correct but the path names were not; that's why I used the setenv command to correctly redefine them.

  1. 接下来,定义bootcmd变量,我们将使用它从 microSD 卡启动:
Marvell>> setenv bootcmd 'mmc dev 0; \
 ext4load mmc 0:1 $kernel_addr $image_name; \
 ext4load mmc 0:1 $fdt_addr $fdt_name; \
 setenv bootargs $console root=/dev/mmcblk0p1 rw rootwait; \
 booti $kernel_addr - $fdt_addr'

We must be careful to set the preceding root path to point to where we have extracted the Debian filesystem (the first partition in our case).

  1. 使用saveenv命令随时保存设置的变量。
  2. 最后,我们通过简单地键入reset命令来启动 ESPRESSObin,如果一切正常,我们将看到系统启动并运行,最后,我们将获得系统登录提示,如下所示:
Debian GNU/Linux 9 espressobin ttyMV0

giometti-VirtualBox login:
  1. 现在,使用先前设置的root密码以 root 用户身份登录:
Debian GNU/Linux 9 espressobin ttyMV0

espressobin login: root
Password: 
Linux espressobin 4.18.0 #2 SMP PREEMPT Sun Jan 13 13:05:03 CET 2019 aarch64

The programs included with the Debian GNU/Linux system are free software;
the exact distribution terms for each program are described in the
individual files in /usr/share/doc/*/copyright.

Debian GNU/Linux comes with ABSOLUTELY NO WARRANTY, to the extent
permitted by applicable law.
root@espressobin:~# 

设置网络

好了,现在我们的 ESPRESSObin 已经准备好执行我们的代码和驱动了!但是,在结束本节之前,让我们看一下网络配置,因为使用 SSH 连接登录到主板或者只是快速地从/向主板复制文件会更有用(即使我们可以删除 microSD,然后直接从主机复制文件):

  1. 看看 ESPRESSObin 上可用的网络接口,我们会看到以下内容:
# ip link
1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue state UNKNOWN mode DEFAULT
 group default qlen 1000
    link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00
2: eth0: <BROADCAST,MULTICAST> mtu 1500 qdisc noop state DOWN mode DEFAULT group
 default qlen 532
    link/ether 3a:ac:9b:44:90:e9 brd ff:ff:ff:ff:ff:ff
3: wan@eth0: <BROADCAST,MULTICAST,M-DOWN> mtu 1500 qdisc noop state DOWN mode DE
FAULT group default qlen 1000
    link/ether 3a:ac:9b:44:90:e9 brd ff:ff:ff:ff:ff:ff
4: lan0@eth0: <BROADCAST,MULTICAST,M-DOWN> mtu 1500 qdisc noop state DOWN mode D
EFAULT group default qlen 1000
    link/ether 3a:ac:9b:44:90:e9 brd ff:ff:ff:ff:ff:ff
5: lan1@eth0: <BROADCAST,MULTICAST,M-DOWN> mtu 1500 qdisc noop state DOWN mode D
EFAULT group default qlen 1000
    link/ether 3a:ac:9b:44:90:e9 brd ff:ff:ff:ff:ff:ff

eth0接口是连接 CPU 和以太网交换机的接口,而wanlan0lan1接口是我们可以物理连接以太网电缆的接口(注意系统称它们为wan@eth0lan0@eth0lan1@eth1,只是为了强调它们是eth0的奴隶)。下面是 ESPRESSObin 的照片,我们可以看到每个以太网端口及其标签:

  1. 不管它们的名称如何,所有端口都是等效的,所以将以太网电缆连接到一个端口(我将使用wan),然后在eth0之后启用它,如下所示:
# ip link set eth0 up
mvneta d0030000.ethernet eth0: configuring for fixed/rgmii-id link mode
mvneta d0030000.ethernet eth0: Link is Up - 1Gbps/Full - flow control off
# ip link set wan up 
mv88e6085 d0032004.mdio-mii:01 wan: configuring for phy/ link mode
mv88e6085 d0032004.mdio-mii:01 wan: Link is Up - 100Mbps/Full - flow control rx/tx

Note that, in the preceding output, there are also kernel messages that show what you should see if everything is working well.

  1. 现在,我们可以手动设置一个 IP 地址,或者我们可以用dhclient命令询问我们的 DHCP 服务器我们上网需要什么:
# dhclient wan

以下是我的网络配置:

# ip addr show wan
3: wan@eth0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue state UP g
roup default qlen 1000
    link/ether 9e:9f:6b:5c:cf:fc brd ff:ff:ff:ff:ff:ff
    inet 192.168.0.100/24 brd 192.168.0.255 scope global wan
       valid_lft forever preferred_lft forever
  1. 现在,我们准备安装新软件或尝试建立一个到 ESPRESSObin 的 SSH 连接;为此,让我们验证我们在/etc/ssh/sshd_config文件中有以下 SSH 服务器的配置:
# grep 'PermitRootLogin yes' /etc/ssh/sshd_config
PermitRootLogin yes
  1. 如果没有输出,我们就不能以 root 身份登录到我们的 ESPRESSObin,所以我们必须将PermitRootLogin设置更改为yes,然后重新启动守护程序:
# /etc/init.d/ssh restart

Restarting ssh (via systemctl): ssh.service.
  1. 现在,在主机上,我们可以尝试通过 SSH 登录,如下所示:
$ ssh [email protected]
[email protected]'s password: 
Linux espressobin 4.18.0 #2 SMP PREEMPT Sun Jan 13 13:05:03 CET 2019 aarch64

The programs included with the Debian GNU/Linux system are free software;
the exact distribution terms for each program are described in the
individual files in /usr/share/doc/*/copyright.

Debian GNU/Linux comes with ABSOLUTELY NO WARRANTY, to the extent
permitted by applicable law.
Last login: Thu Nov 3 17:16:59 2016
-bash: warning: setlocale: LC_ALL: cannot change locale (en_GB.UTF-8)

请参见

在外部硬件上进行本机编译

在结束本章之前,我想介绍一个有趣的跨平台系统,当我们需要在您的开发电脑上运行几个不同的操作系统时,这个系统非常有用。当我们需要一个完整的操作系统来编译设备驱动或应用,但我们没有目标设备可以编译时,这一步非常有用。我们可以使用我们的主机为不同操作系统和操作系统版本的国外硬件编译代码。

准备好

在我的职业生涯中,我使用过成吨的不同平台,为所有平台拥有一台虚拟机非常复杂,并且非常消耗系统资源(尤其是如果我们决定同时运行其中的几个平台!).这就是为什么拥有一个可以在你的电脑上执行外来代码的轻量级系统会很有趣。当然,这种方法不能用于测试设备驱动(我们需要真正的硬件),但我们可以使用它来运行本地编译器和/或本地用户空间代码,以防我们的嵌入式平台无法工作。让我们看看我在说什么。

设置目标机器配方中,关于 Debian 操作系统的安装,我们使用了chroot命令来设置 root 的密码。多亏了 QEMU,这个命令起了作用;事实上,在debian-stretch-arm64目录中,我们有一个 ARM64 根文件系统,只需要使用 QEMU 就可以在 x86_64 平台上执行。很明显,以这种方式,我们应该能够执行我们想要的任何命令,当然,我们将能够执行 Bash shell,就像在下一个食谱中一样。

怎么做...

现在是时候看看chroot是如何工作的了:

  1. 使用我们的 x86_64 主机执行 ARM64 bash命令,如下所示:
$ sudo chroot debian-stretch-arm64/ bash
bash: warning: setlocale: LC_ALL: cannot change locale (en_GB.UTF-8)
root@giometti-VirtualBox:/# 
  1. 然后,我们可以像在 ESPRESSObin 上一样使用每个 ARM64 命令;例如,将文件列表到当前目录中;我们可以使用以下内容:
# ls /
bin  dev  home media  opt   root  sbin  sys  usr
boot etc  lib  mnt    proc  run   srv   tmp  var
# cat /etc/hostname 
espressobin

但是,也有一些陷阱;例如,我们完全错过了/proc/sys目录和程序,它们依赖于它们并且肯定会失败:

# ls /{proc,sys}
/proc:

/sys:
# ps
Error: /proc must be mounted
  To mount /proc at boot you need an /etc/fstab line like:
      proc /proc proc defaults
  In the meantime, run "mount proc /proc -t proc"

为了解决这些问题,我们可以在执行chroot之前手动挂载这些缺失的目录,但是这很烦人,因为它们太多了,所以我们可以尝试使用schroot实用程序,反过来,它可以为我们完成所有这些步骤。让我们看看如何。

For detailed information regarding schroot, you can see its man pages with man schroot.

安装和配置 schroot

这个任务在 Ubuntu 中相当琐碎:

  1. 首先,我们以通常的方式安装程序:
$ sudo apt install schroot
  1. 然后,我们必须对其进行配置,以便正确进入我们的 ARM64 系统。为此,让我们将之前创建的根文件系统复制到一个专用目录中(在这里我们还可以添加我们希望用schroot模拟的任何其他发行版):
$ sudo mkdir /srv/chroot/
$ sudo cp -a debian-stretch-arm64/ /srv/chroot/
  1. 然后,我们必须通过在schroot配置目录中添加新文件来为新系统创建适当的配置,如下所示:
$ sudo bash -c 'cat > /etc/schroot/chroot.d/debian-stretch-arm64 <<__EOF__
[debian-stretch-arm64]
description=Debian Stretch (arm64)
directory=/srv/chroot/debian-stretch-arm64
users=giometti
#groups=sbuild
#root-groups=root
#aliases=unstable,default
type=directory
profile=desktop
personality=linux
preserve-environment=true
__EOF__'

Note that the directory parameter is set to the path holding our ARM64 system and users is set to giometti, which is my username (this is a comma-separated list of users that are allowed access to the chroot environment—see man schroot.conf).

看前面的设置,我们看到profile参数设置为desktop;这意味着它将考虑到/etc/schroot/desktop/目录中的所有文件。特别是fstab文件保存了我们希望装入系统的所有挂载点。因此,我们应该验证它至少包含以下行:

# <filesystem> <mount point> <type> <options> <dump> <pass>
/proc           /proc         none   rw,bind   0      0
/sys            /sys          none   rw,bind   0      0
/dev            /dev          none   rw,bind   0      0
/dev/pts        /dev/pts      none   rw,bind   0      0
/home           /home         none   rw,bind   0      0
/tmp            /tmp          none   rw,bind   0      0
/opt            /opt          none   rw,bind   0      0
/srv            /srv          none   rw,bind   0      0
tmpfs           /dev/shm      tmpfs  defaults  0      0
  1. 现在,我们必须重新启动schroot服务,如下所示:
$ sudo systemctl restart schroot

Note that you can also restart using the old-fashioned way: $ sudo /etc/init.d/schroot restart

  1. 现在我们可以通过要求他们schroot来列出所有可用的环境,如下所示:
$ schroot -l
 chroot:debian-stretch-arm64
  1. 好了,一切就绪,我们可以进入仿真 ARM64 系统了:
$ schroot -c debian-stretch-arm64
bash: warning: setlocale: LC_ALL: cannot change locale (en_GB.UTF-8)

Since we haven't installed any locale support, the preceding warning is quite obvious and it should be safely ignored.

  1. 现在,为了验证我们是否真的在执行 ARM64 代码,让我们尝试一些命令。例如,我们可以用uname命令询问一些系统信息:
$ uname -a
Linux giometti-VirtualBox 4.15.0-43-generic #46-Ubuntu SMP Thu Dec 6 14:45:28 UTC 2018 aarch64 GNU/Linux

我们可以看到,系统说它的平台是aarch64,也就是 ARM64。然后,我们可以尝试执行之前交叉编译的helloworld程序;因为在chroot之后,当前目录没有改变(我们的主目录还是一样的),我们可以简单地回到我们编译的地方,然后像往常一样执行程序:

$ cd ~/Projects/ldddc/github/chapter_1/
$ file helloworld
helloworld: ELF 64-bit LSB shared object, ARM aarch64, version 1 (SYSV), dynamically linked, interpreter /lib/ld-linux-aarch64.so.1, for GNU/Linux 3.7.0, BuildID[sha1]=c0d6e9ab89057e8f9101f51ad517a253e5fc4f10, not stripped
$ ./helloworld
Hello World!

这个程序仍然像我们在 ARM64 系统上一样执行。太好了。

配置仿真操作系统

我们刚刚看到的schroot如果我们不配置我们的新系统来进行本机编译,那就什么都不是,为了这样做,我们可以使用我们在主机上使用的每一个 Debian 工具:

  1. 要安装一个完整的编译环境,我们可以在schroot环境中发出以下命令一次:
$ sudo apt install gcc make \
 bison flex ncurses-dev libssl-dev

Note that sudo will ask your usual password, that is, the password you currently use to log in to your host PC. You might not get a password request from sudo with the following error message: sudo: no tty present and no askpass program specified You can try executing the preceding sudo command again, adding to it the -S option argument. It could be possible that the apt command will notify you that some packages cannot be authenticated. Just ignore this warning and continue installation, answering yes by pressing the Y key.

如果一切顺利,我们现在应该能够执行以前使用的每个编译命令。例如,我们可以再次尝试重新编译helloworld程序,但是是本地的(我们应该按顺序删除当前的可执行文件;make将再次尝试重新编译):

$ rm helloworld
$ make CFLAGS="-Wall -O2" helloworld
cc -Wall -O2 helloworld.c -o helloworld
$ file helloworld
helloworld: ELF 64-bit LSB shared object, ARM aarch64, version 1 (SYSV), dynamically linked, interpreter /lib/ld-linux-aarch64.so.1, for GNU/Linux 3.7.0, BuildID[sha1]=1393450a08fb9eea22babfb9296ce848bb806c21, not stripped
$ ./helloworld
Hello World!

Note that networking support is fully functional so we're now working on an emulated ARM64 environment on our hosts PC as we were on the ESPRESSObin.

请参见