The NXP i.MX 7 SoC heterogeneous architecture provides a secondary CPU platform with a Cortex-M4 core. This core can be used to run a firmware for custom tasks. The SoC has several options where the firmware can be located: There is a small portion of Tightly Coupled Memory (TCM) close to the Cortex-M4 core. A slightly larger amount of On-Chip SRAM (OCRAM) is available inside the SoC too. The Cortex-M4 core is also able to run from external DDR memory (through the MMDC) and QSPI. Furthermore, the Cortex-M4 uses a Modified Harvard Architecture, which has two independent buses and caches for Code (Code Bus) and Data (System Bus). The memory addressing is still unified, but accesses are split between the buses using addresses as discriminator (addresses in the range 0x00000000-0x1fffffff are loaded through the code bus, 0x20000000-0xdfffffff are accessed through the data bus).
This weekend I finally came around to create OpenEmbedded recipes for WireGuard. The recipe currently awaits review and hopefully will get part of the meta-networking layer, part of the meta-openembedded repository of the upstream OpenEmbedded project. There are two recipes, one for the kernel module and one for the user space tools. The user space tools have the kernel module as a dependency, hence it is sufficient to install the wireguard-tools package, e.g. by using IMAGE_INSTALL_append in your local.conf:
IMAGE_INSTALL_append = " wireguard-tools"
The kernel module needs at least a kernel version 3.18 or later and has some requirements regarding kernel configuration. The WireGuard website maintains a list of kernel requirements. If you are using the Yocto kernel, the netfilter kernel feature (features/netfilter/netfilter.scc) is enabled by default and seems to be sufficient to run WireGuard. To get started with WireGuard, refer to the excellent Quick Start guide on wireguard.io.
Today I upgrading my router to LEDE 17.01 and played a bit with IPv6 and WireGuard VPN tunnels. My Internet connection at home (connected via Cable to the Comcast network) has decent IPv6 support, which I wanted to enjoy also when on the road, using non-IPv6 networks. The first step is to setup a Wireguard tunnel, which I already did some months ago (Dan Lüdtke, author of the LEDE/OpenWrt web interface plugin for Wireguard has a good post on that. Update April: Dan has a new post which does not make use of the stacked approach. This is suitable for lots of regular setups. However, the IPv6 address setup with automatic network assignment described here is only supported by using stacked interfaces, hence this article keeps using that configuration). In my setup the Wireguard IPv4 network uses a network from the private range (192.168.2.0/24) to route IPv6 traffic. For IPv6 my goal was to assign a public subnet, so I can access the IPv6 network without any NAT directly through the tunnel. In IPv6 world, NAT is a technology which is not commonly used/considered deprecated anyway. Note that this how-to does not route the IPv4 traffic to the internet through the VPN tunnel, only IPv6 traffic.
First, a large enough IPv6 prefix needs to be available on the router in order to assign two independent IPv6 networks to my local LAN and the Wireguard VPN. One has to realize that in IPv6 world, subnets are by definition between /49 and /64. One cannot create a subnet /72 or similar since the last 64 bits are the host portion, reserved exclusively for host addresses. By default, LEDE requested a 64 bit IPv6-prefix from the provider, but this can be changed in the WAN6 network interface settings:
In this third part about KVM on ARMv7 I use kvmtool as the user-space part of the hypervisor. This lightweight hypervisor allowed me to run up to 72 virtual machines… This does not really serves any purpose other than demonstrating what is possible :-). See the video in the end how that looked like.
In 2011 Pekka Enberg announced kvmtool (native Linux KVM tool). Initially it was meant to live within the Linux kernel source tree, but it ended up in a separate git repository on kernel.og.. In between it has been ported to several architectures too, including ARM and ARM64. Its binary usually goes with the name lkvm. It strictly depends on KVM and is otherwise kept rather lean.
This is part two of my blog post about Kernel-Virtual Machine (KVM) on a 32-Bit ARM architecture. The post is meant as a starting point for those who want to play with KVM and provide a useful collection of Qemu commands for virtualization.
Virtualization host setup
The Kernel configuration I used for my platforms Host kernel can be found here. Since I run my experiments on a Toradex Colibri iMX7D module, I started with the v4.1 configuration of the BSP kernel and updated that to v4.8 plus enabled KVM as well as KSM (Kernel same-page merging).
As root file system I use a slightly modified version of the Ångström distributions “development-image”, version 2015.12 (built from scratch with OpenEmbedded). Any recent ARM root file system should do it. I let Qemu v2.6.0 preinstall (by just adding “qemu” to the image and specifying ANGSTROM_QEMU_VERSION = “2.6.0” in conf/distro/angstrom-v2015.12.conf).
Virtualization guest setup
For the virtualization guest setup I was looking for something minimalistic. I uploaded the compiled binary of the Kernel (as tared zImage) and initramfs (as cpio.gz).
The newer ARMv7 Cortex-A class cores such Cortex-A7, A15 and A17 come with a virtualization extensions which allow to use KVM (kernel virtual machine). The NXP i.MX 7Dual SoC which I worked with lately includes the ARM Cortex-A7 CPU. I went ahead and tried to bring up KVM on i.MX 7. I was not really familiar with the ARMv7 virtualization architecture, so I had to read up on some concepts. This post summarizes what I learned and gives a big picture of software support.
The Hypervisor mode
To provide hardware support for full CPU virtualization an additional privilege level is required. User-space (PL0) uses the SVC (Supervisor) instruction to switch to kernel-space (PL1, SVC mode). A similar separation between Kernel and hypervisor is required. The ARMv7 architecture with virtualization extension calls this privilege level PL2 or HYP mode.
Linux with KVM for ARM uses this mode to provide CPU virtualization. The CPU needs to be in HYP mode when Linux is booting so KVM can make use of the extension. How KVM uses the HYP mode in detail is explained in this excellent LWN article. After building a kernel with KVM support, I encountered this problem first: By default, the system did boot in SVC mode.
Brought up 2 CPUs
CPU: All CPU(s) started in SVC mode.
kvm : HYP mode not available
Secure and Non-Secure world
To understand how to switch into Hypervisor mode, one needs to understand the whole privilege level architecture first. Notable here is that on ARMv7 CPU’s the HYP mode is only available in non-secure mode, by design. Any hypervisor needs to operate in non-secure mode, there is no virtualization extension in secure mode. Continue reading “U-Boot/Linux and HYP mode on ARMv7”
Given two systems, both with a Cortex-A5 CPU, one clocked at 396MHz without L2 cache and one clocked at 500 MHz with 512kB L2 cache. How big is the impact of the L2 cache? Since the clock frequency is different, a simple CPU time comparison of a given program does not answer the question… I tried to answer this question using perf. perf is often used to profile software, but in this case it also proved to be useful to compare two different hardware implementations.
Most CPU’s nowadays have internal counters which count various events (e.g. executed instructions, cache misses, executed branches and branch misses etc…). Other hardware, e.g. cache controllers, might expose performance counters too, but this article focuses on the hardware counters exposed by the CPU. Continue reading “Using the perf utility on ARM”
The serial console is a very helpful debugging tool for kernel development. However, when a crash occurs early in the boot process, one is left in the dark. There are two early console implementations available with different merits. This post will throw some lights on them.
The kernel supports earlyprintk since… probably ever. At least 2.6.12, where the new age (git) started. After enabling “Kernel low-level debugging”, “Early printk” under “Kernel hacking” and selecting an appropriate low-level debugging port, you are ready to get early serial console output. Continue reading “Linux earlyprintk/earlycon support on ARM”
My new provider IPv6 connectivity, however after connecting my OpenWrt based WNDR4300 (using Chaos Calmer 15.05-rc3) things unfortunately did not “just work”… This post summarize some hints how to debug IPv6 on OpenWrt.
First, make sure that the upstream (WAN) interface is configured according to the documentation in the OpenWrt Wiki. Using LuCI, you have to create a new interface (WAN6) which should c
The LLVMLinux team made quite some progress in enabling LLVM/clang to build the Linux kernel. There has also been a talk at the Collaboration Summit 2015 in Santa Rosa (slides). So I thought, give it a try and compile a kernel for my ARM based board of choice. The upstream kernel.org Linux kernel is not yet ready to be built using LLVM/clang, some patches are still required. Therefor I used the kernel from the LLVMLinux git server.
The nice thing about LLVM/clang is that it supports multiple targets. The binaries provided by the Arch repositories support several ARM targets:
$ pacman -S clang
$ llc --version
LLVM version 3.5.1
Built Jan 14 2015 (03:18:15).
Default target: x86_64-unknown-linux-gnu
Host CPU: core-avx-i
aarch64 - AArch64 (little endian)
aarch64_be - AArch64 (big endian)
arm - ARM
arm64 - AArch64 (little endian)
arm64_be - AArch64 (big endian)
armeb - ARM (big endian)