Emulating ARM with QEMU on Debian/Ubuntu

To use QEMU (Quick EMUlator) to start a Ubuntu ARM Linux

Install QEMU:

$ sudo apt install qemu-system-arm
Get a list of ARM CPU models supported by qemu-system-arm:

$ qemu-system-arm -machine help
Supported machines are:
akita                Sharp SL-C1000 (Akita) PDA (PXA270)
ast2500-evb          Aspeed AST2500 EVB (ARM1176)
ast2600-evb          Aspeed AST2600 EVB (Cortex-A7)
borzoi               Sharp SL-C3100 (Borzoi) PDA (PXA270)
canon-a1100          Canon PowerShot A1100 IS (ARM946)
cheetah              Palm Tungsten|E aka. Cheetah PDA (OMAP310)
collie               Sharp SL-5500 (Collie) PDA (SA-1110)
connex               Gumstix Connex (PXA255)
cubieboard           cubietech cubieboard (Cortex-A8)
emcraft-sf2          SmartFusion2 SOM kit from Emcraft (M2S010)
fp5280g2-bmc         Inspur FP5280G2 BMC (ARM1176)
fuji-bmc             Facebook Fuji BMC (Cortex-A7)
g220a-bmc            Bytedance G220A BMC (ARM1176)
highbank             Calxeda Highbank (ECX-1000)
imx25-pdk            ARM i.MX25 PDK board (ARM926)
integratorcp         ARM Integrator/CP (ARM926EJ-S)
kudo-bmc             Kudo BMC (Cortex-A9)
kzm                  ARM KZM Emulation Baseboard (ARM1136)
lm3s6965evb          Stellaris LM3S6965EVB (Cortex-M3)
lm3s811evb           Stellaris LM3S811EVB (Cortex-M3)
mainstone            Mainstone II (PXA27x)
mcimx6ul-evk         Freescale i.MX6UL Evaluation Kit (Cortex-A7)
mcimx7d-sabre        Freescale i.MX7 DUAL SABRE (Cortex-A7)
microbit             BBC micro:bit (Cortex-M0)
midway               Calxeda Midway (ECX-2000)
mps2-an385           ARM MPS2 with AN385 FPGA image for Cortex-M3
mps2-an386           ARM MPS2 with AN386 FPGA image for Cortex-M4
mps2-an500           ARM MPS2 with AN500 FPGA image for Cortex-M7
mps2-an505           ARM MPS2 with AN505 FPGA image for Cortex-M33
mps2-an511           ARM MPS2 with AN511 DesignStart FPGA image for Cortex-M3
mps2-an521           ARM MPS2 with AN521 FPGA image for dual Cortex-M33
mps3-an524           ARM MPS3 with AN524 FPGA image for dual Cortex-M33
mps3-an547           ARM MPS3 with AN547 FPGA image for Cortex-M55
musca-a              ARM Musca-A board (dual Cortex-M33)
musca-b1             ARM Musca-B1 board (dual Cortex-M33)
musicpal             Marvell 88w8618 / MusicPal (ARM926EJ-S)
n800                 Nokia N800 tablet aka. RX-34 (OMAP2420)
n810                 Nokia N810 tablet aka. RX-44 (OMAP2420)
netduino2            Netduino 2 Machine (Cortex-M3)
netduinoplus2        Netduino Plus 2 Machine (Cortex-M4)
none                 empty machine
npcm750-evb          Nuvoton NPCM750 Evaluation Board (Cortex-A9)
nuri                 Samsung NURI board (Exynos4210)
orangepi-pc          Orange Pi PC (Cortex-A7)
palmetto-bmc         OpenPOWER Palmetto BMC (ARM926EJ-S)
quanta-gbs-bmc       Quanta GBS (Cortex-A9)
quanta-gsj           Quanta GSJ (Cortex-A9)
quanta-q71l-bmc      Quanta-Q71l BMC (ARM926EJ-S)
rainier-bmc          IBM Rainier BMC (Cortex-A7)
raspi0               Raspberry Pi Zero (revision 1.2)
raspi1ap             Raspberry Pi A+ (revision 1.1)
raspi2b              Raspberry Pi 2B (revision 1.1)
realview-eb          ARM RealView Emulation Baseboard (ARM926EJ-S)
realview-eb-mpcore   ARM RealView Emulation Baseboard (ARM11MPCore)
realview-pb-a8       ARM RealView Platform Baseboard for Cortex-A8
realview-pbx-a9      ARM RealView Platform Baseboard Explore for Cortex-A9
romulus-bmc          OpenPOWER Romulus BMC (ARM1176)
sabrelite            Freescale i.MX6 Quad SABRE Lite Board (Cortex-A9)
smdkc210             Samsung SMDKC210 board (Exynos4210)
sonorapass-bmc       OCP SonoraPass BMC (ARM1176)
spitz                Sharp SL-C3000 (Spitz) PDA (PXA270)
stm32vldiscovery     ST STM32VLDISCOVERY (Cortex-M3)
supermicrox11-bmc    Supermicro X11 BMC (ARM926EJ-S)
swift-bmc            OpenPOWER Swift BMC (ARM1176) (deprecated)
sx1                  Siemens SX1 (OMAP310) V2
sx1-v1               Siemens SX1 (OMAP310) V1
tacoma-bmc           OpenPOWER Tacoma BMC (Cortex-A7)
terrier              Sharp SL-C3200 (Terrier) PDA (PXA270)
tosa                 Sharp SL-6000 (Tosa) PDA (PXA255)
verdex               Gumstix Verdex (PXA270)
versatileab          ARM Versatile/AB (ARM926EJ-S)
versatilepb          ARM Versatile/PB (ARM926EJ-S)
vexpress-a15         ARM Versatile Express for Cortex-A15
vexpress-a9          ARM Versatile Express for Cortex-A9
virt-2.10            QEMU 2.10 ARM Virtual Machine
virt-2.11            QEMU 2.11 ARM Virtual Machine
virt-2.12            QEMU 2.12 ARM Virtual Machine
virt-2.6             QEMU 2.6 ARM Virtual Machine
virt-2.7             QEMU 2.7 ARM Virtual Machine
virt-2.8             QEMU 2.8 ARM Virtual Machine
virt-2.9             QEMU 2.9 ARM Virtual Machine
virt-3.0             QEMU 3.0 ARM Virtual Machine
virt-3.1             QEMU 3.1 ARM Virtual Machine
virt-4.0             QEMU 4.0 ARM Virtual Machine
virt-4.1             QEMU 4.1 ARM Virtual Machine
virt-4.2             QEMU 4.2 ARM Virtual Machine
virt-5.0             QEMU 5.0 ARM Virtual Machine
virt-5.1             QEMU 5.1 ARM Virtual Machine
virt-5.2             QEMU 5.2 ARM Virtual Machine
virt-6.0             QEMU 6.0 ARM Virtual Machine
virt-6.1             QEMU 6.1 ARM Virtual Machine
virt                 QEMU 6.2 ARM Virtual Machine (alias of virt-6.2)
virt-6.2             QEMU 6.2 ARM Virtual Machine
witherspoon-bmc      OpenPOWER Witherspoon BMC (ARM1176)
xilinx-zynq-a9       Xilinx Zynq Platform Baseboard for Cortex-A9
z2                   Zipit Z2 (PXA27x)

$ qemu-system-arm -machine virt -cpu help
Available CPUs:
  arm1026
  arm1136
  arm1136-r2
  arm1176
  arm11mpcore
  arm926
  arm946
  cortex-a15
  cortex-a7
  cortex-a8
  cortex-a9
  cortex-m0
  cortex-m3
  cortex-m33
  cortex-m4
  cortex-m55
  cortex-m7
  cortex-r5
  cortex-r5f
  max
  pxa250
  pxa255
  pxa260
  pxa261
  pxa262
  pxa270-a0
  pxa270-a1
  pxa270
  pxa270-b0
  pxa270-b1
  pxa270-c0
  pxa270-c5
  sa1100
  sa1110
  ti925t

Install Ubuntu ARM Linux

Download Ubuntu ARM (ISO) Image on the official Ubuntu website. Mount the ISO:

$ mkdir ubuntu_iso_mount
$ sudo mount -o loop /home/jerry/data/ubuntu-22.04.4-live-server-arm64.iso ubuntu_iso_mount
Start QEMU with the mounted ISO:

$ qemu-system-arm -machine virt -cpu cortex-a7 -m 1024 -cdrom /home/jerry/work-2/ubuntu_iso_mount -boot d

Emulating ARM with QEMU on Debian/Ubuntu

Install the ARM cross compiler toolchain on your Linux Ubuntu PC

Cross-compiling user programs needs GCC-ARM toolchain.

Install the Cross Compilers, utilities, etc.

  • ARM C compiler
  • 
    sudo apt-get install libc6-armel-cross libc6-dev-armel-cross binutils-arm-linux-gnueabi libncurses5-dev build-essential bison flex libssl-dev bc
    sudo apt-get install gcc-arm-linux-gnueabihf gcc-arm-linux-gnueabi g++-arm-linux-gnueabihf
    
  • ARM C++ compiler
    • ARM
    • 
      sudo apt-get install g++-arm-linux-gnueabihf libstdc++-4.8-dev-armhf-cross
      			
    • AArch64
    • 
      sudo apt-get install g++-aarch64-linux-gnu libstdc++-4.8-dev-arm64-cross
      			

Try the cross C compiler

This is the example:

cat > hello.c << EOF
#include <stdio.h>
int main(void) { return printf("Hello ARM!\n"); }
EOF
Compile it:

arm-linux-gnueabihf-gcc hello.c -o hello

Try the cross C++ compiler


#include "iostream"
 
using namespace std;
 
int main(int argc, char *argv[]) {
    cout << "Hello world !" << endl;
    return 0;
}
Compile it:

arm-linux-gnueabihf-g++ hello.cc -o hello

Running the ARM program:

install qemu-arm-static so that you can run ARM executables directly on your build machine.

Chroot into ARMv8 64bit (AARCH64) distribution

  • Install required packages
  • 
    sudo apt install \
    build-essential \
    binfmt-support \
    daemonize \
    libarchive-tools \
    qemu-system \
    qemu-user \
    qemu-user-static \
    gcc-aarch64-linux-gnu \
    g++-aarch64-linux-gnu
    	
  • Download the Ubuntu Cloud image rootfs from Ubuntu Server 20.04 LTS (Focal Fossa) released builds
  • 
    wget https://cloud-images.ubuntu.com/releases/server/focal/release/ubuntu-20.04-server-cloudimg-arm64-wsl.rootfs.tar.gz    
        
  • Extract the tarball in a working folder
  • 
    $ mkdir arm64.rootfs
    $ sudo tar xzf ubuntu-20.04-server-cloudimg-arm64-wsl.rootfs.tar.gz -C arm64.rootfs
    	
  • Copy qemu static binary into that folder
  • 
    sudo cp /usr/bin/qemu-aarch64-static arm64.rootfs/usr/bin/ 
        
  • Start systemd with daemonize
  • 
    sudo daemonize \
    /usr/bin/unshare -fp --mount-proc \
    /lib/systemd/systemd --system-unit=basic.target
    	
  • Check if AARCH64 binfmt entry is present
  • 
    $ ls /proc/sys/fs/binfmt_misc/qemu-a*
    /proc/sys/fs/binfmt_misc/qemu-aarch64  /proc/sys/fs/binfmt_misc/qemu-arm
    /proc/sys/fs/binfmt_misc/qemu-alpha    /proc/sys/fs/binfmt_misc/qemu-armeb
    	
  • Mount and chroot into the environment
  • 
    sudo mount -o bind /proc arm64.rootfs/proc
    sudo mount -o bind /dev arm64.rootfs/dev
    sudo chroot arm64.rootfs qemu-aarch64-static /bin/bash
    	

QemuARMVexpress

Running ARM programs under linux (without starting QEMU VM!)

QEMU disk image utility

qemu-img allows you to create, convert and modify images offline.
It can handle all image formats supported by QEMU.
Install qemu

sudo apt install qemu qemu-system-arm
Create a hard disk for your virtual machine with required capacity.

$ qemu-img create -f raw armdisk.img 8G
Formatting 'armdisk.img', fmt=raw size=8589934592
Get a list of all supported machines

$ qemu-system-arm -machine help | grep ARM
Then get a list pf CPUs supported by the machine:

$ qemu-system-arm -machine virt-4.2 -cpu help
...
  cortex-a9
...

在 x86 下 chroot 到 ARM 平台的 rootfs

Chroot into Raspberry Pi ARMv7 Image with Qemu on Linux

  • Install dependecies
  • 
    $ sudo apt-get install qemu qemu-user-static binfmt-support  
      
  • Download and extract the Raspbian disk image
  • 
    $ wget https://downloads.raspberrypi.org/raspbian_latest
    $ unzip raspbian_latest  
      
  • Extend Raspbian disk image by 1GB
  • 
    dd if=/dev/zero bs=1M count=1024 >> 2016-05-27-raspbian-jessie.img  
      
  • Set-up disk image as loop device
  • 
    losetup /dev/loop0 2016-05-27-raspbian-jessie.img  
      
  • Check file system
  • 
    e2fsck -f /dev/loop0p2  
      
  • Expand partition
  • 
    resize2fs /dev/loop0p2  
      
  • Mount partitions
  • 
    mount -o rw /dev/loop0p2  /mnt
    mount -o rw /dev/loop0p1 /mnt/boot  
      
  • Mount binds
  • 
    mount --bind /dev /mnt/dev/
    mount --bind /sys /mnt/sys/
    mount --bind /proc /mnt/proc/
    mount --bind /dev/pts /mnt/dev/pts  
      
  • ld.so.preload fix
  • 
    sed -i 's/^/#/g' /mnt/etc/ld.so.preload  
      
  • Copy qemu binary
  • 
    cp /usr/bin/qemu-arm-static /mnt/usr/bin/  
      
  • Chroot into Raspbian
  • 
    chroot /mnt /bin/bash  
      
  • Do stuff inside the chroot and exit.
  • Revert the ld.so.preload fix
  • 
    sed -i 's/^#//g' /mnt/etc/ld.so.preload  
      
  • Unmount everything
  • 
    umount /mnt/{dev/pts,dev,sys,proc,boot,}  
      
  • Unmount loop device
  • 
    losetup -d /dev/loop0  
      

Raspberry Pi Emulation Using qemu-user-static

These are some notes for how to mount a Raspberry Pi disk image, and use qemu-user-static to modify the image.
This example shows Raspbian.

Overview

We'll mount the disk image, chroot in to it, then use QemuUserEmulation to update the image and execute the ARM code.

qemu-user-static

qemu-user-static is the package provides the user mode emulation binaries, built statically.
In this mode QEMU can launch Linux processes compiled for one CPU on another CPU.
If binfmt-support package is installed, qemu-user-static package will register binary formats which the provided emulators can handle, so that it will be possible to run foreign binaries directly."

Set up Host

Install the qemu-user-static and binfmt-support packages.

sudo apt install qemu qemu-user-static binfmt-support
After installed, you can check your ability to emulate the binary formats by checking for ARM support by executing:

$ update-binfmts --display | grep arm
qemu-arm (enabled):
 interpreter = /usr/bin/qemu-arm-static
qemu-armeb (enabled):
 interpreter = /usr/bin/qemu-armeb-static

Get and mount the image

Download and extract the Raspbian disk image

mkdir ~/rpi_image
cd ~/rpi_image
$ wget https://downloads.raspberrypi.org/raspbian_latest
$ unzip raspbian_latest  
$ rm raspbian_latest

Resize the image

To increase the size of the disk image so it is more useful.
  • check out your disk image
  • 
    $ fdisk -lu 2020-02-13-raspbian-buster.img
    Disk 2020-02-13-raspbian-buster.img: 3.54 GiB, 3787456512 bytes, 7397376 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: 0xea7d04d6
    
    Device                          Boot  Start     End Sectors  Size Id Type
    2020-02-13-raspbian-buster.img1        8192  532479  524288  256M  c W95 FAT32 (LBA)
    2020-02-13-raspbian-buster.img2      532480 7397375 6864896  3.3G 83 Linux
    
    
    The first partition is boot (kernel and binary blobs), the second is the filesystem.
    We want to add space to the disk image, then expand that second partition.
  • Add more space to the disk image
  • Add space to the image (this example adds 1G):
    
    $ dd if=/dev/zero bs=1M count=1024 >> 2020-02-13-raspbian-buster.img
    1024+0 records in
    1024+0 records out
    1073741824 bytes (1.1 GB, 1.0 GiB) copied, 1.68891 s, 636 MB/s
    
  • Mount raw image of entire disc
  • Raw images of an entire disk contain potentially multiple partitions with different filesystems on them.
    To mount and work with the image, it needs to be attached to a loop device. To do so, losetup(8) can be used.
    
    $ sudo losetup -f -P --show 2020-02-13-raspbian-buster.img
    /dev/loop8
    
    • The -f option will search for the next free loop device to attach the image to.
    • The -P option will trigger a scan for partitions on the attached image and create devices for each partition detected.
    
    $ lsblk | grep loop8
    loop8       7:18   0   4.5G  0 loop 
    ├─loop8p1 259:2    0   256M  0 part 
    └─loop8p2 259:3    0   3.3G  0 part 
    
    
    This should set up /dev/loop8 as the whole image and /dev/loop8p2 as the partition we're expanding
  • Resize the filesystem partition
  • In parted, remove the second partition, resize it to be the full size of /dev/loop8
    
    $ sudo parted /dev/loop8
    [sudo] password for jerry: 
    GNU Parted 3.3
    Using /dev/loop8
    Welcome to GNU Parted! Type 'help' to view a list of commands.
    (parted) print                                                            
    Model: Loopback device (loopback)
    Disk /dev/loop8: 4861MB
    Sector size (logical/physical): 512B/512B
    Partition Table: msdos
    Disk Flags: 
    
    Number  Start   End     Size    Type     File system  Flags
     1      4194kB  273MB   268MB   primary  fat32        lba
     2      273MB   3787MB  3515MB  primary  ext4
    (parted) rm 2                                                           
    (parted) mkpart primary 273 4861                                        
    (parted) print                                                            
    Model: Loopback device (loopback)
    Disk /dev/loop8: 4861MB
    Sector size (logical/physical): 512B/512B
    Partition Table: msdos
    Disk Flags: 
    
    Number  Start   End     Size    Type     File system  Flags
     1      4194kB  273MB   268MB   primary  fat32        lba
     2      273MB   4861MB  4589MB  primary               lba
    (parted) quit 
     
  • Check and resize the file system
  • 
    $ sudo e2fsck -f /dev/loop8p2
    e2fsck 1.45.5 (07-Jan-2020)
    Pass 1: Checking inodes, blocks, and sizes
    Pass 2: Checking directory structure
    Pass 3: Checking directory connectivity
    Pass 4: Checking reference counts
    Pass 5: Checking group summary information
    rootfs: 106314/214704 files (0.2% non-contiguous), 724571/858112 blocks
    $ sudo resize2fs -f /dev/loop8p2
    resize2fs 1.45.5 (07-Jan-2020)
    Resizing the filesystem on /dev/loop8p2 to 1120256 (4k) blocks.
    The filesystem on /dev/loop8p2 is now 1120256 (4k) blocks long.
     
  • clean up the loopback devices
  • 
    $ sudo losetup -d /dev/loop8
     

Mount the image

A bind mount is an alternate view of a directory tree.
For example, after issuing the Linux command-

mount --bind /some/where /else/where
 
the directories /some/where and /else/where have the same content, which is the content of /some/where. (If /else/where was not empty, its previous content is now hidden.)
Here, the “device” /some/where is not a disk partition like in the case of an on-disk filesystem, but an existing directory.

Mount the file system to be modified


$ sudo losetup -f -P --show 2020-02-13-raspbian-buster.img
/dev/loop8
$ sudo mount /dev/loop8p2 -o rw rpi_mnt

Before chrooting in

You need to comment out everything in rpi_mnt/etc/ld.so.preload

$ cat rpi_mnt/etc/ld.so.preload
/usr/lib/arm-linux-gnueabihf/libarmmem-${PLATFORM}.so

$ sudo sed -i 's/^/#/g' rpi_mnt/etc/ld.so.preload

$ cat rpi_mnt/etc/ld.so.preload
#/usr/lib/arm-linux-gnueabihf/libarmmem-${PLATFORM}.so

Copy qemu binary

For ARCH=arm64,

$ sudo cp /usr/bin/qemu-aarch64-static rpi_mnt/usr/bin/

Test chroot


$ cd rpi_mnt
$ sudo chroot . bin/bash
# uname -av
43~20.04.1-Ubuntu SMP Tue Jan 12 16:39:47 UTC 2021 armv7l GNU/Linux
#

Revert the ld.so.preload fix


# sed -i 's/^#//g' etc/ld.so.preload
# cat etc/ld.so.preload
/usr/lib/arm-linux-gnueabihf/libarmmem-${PLATFORM}.so

# sed -i 's/^#//g' /mnt/etc/ld.so.preload
# exit
exit

Unmount everything


$ sudo umount /mnt/{dev/pts,dev,sys,proc,boot,}  

Unmount loop device


$ sudo losetup -d /dev/loop8

留言

熱門文章