Run Linux on ARM architecture with QEMU

Introduction

Overview

Operating environment

Environment

  1. Install git.

    $ sudo apt-get install git
    
  2. Install the ARM cross-compiler.

    $ sudo apt-get install gcc-arm-linux-gnueabi
    
  3. Install the software needed to build the Linux kernel.

    $ sudo apt-get install flex bison libncurses-dev libssl-dev
    
  4. Install QEMU for ARM.

    $ sudo apt-get install qemu-system-arm
    

Directory structure at build time

{top_directory} ├ linux-stable │ └ arch │ └ arm │ └ boot │ ├ zImage: Kernel image │ └ dts │ └ versatile-pb.dtb: Device tree │ ├ busybox │ ├ _install: root file system │ └ rootfs.img: Image of root file system │ ├ driver │ └ sample │ └ driver_sample.ko: Device driver module │ └ app └ sample └ app_sample: Run binary file of the app ~~~

Linux kernel build

  1. Clone the Linux kernel (Stable Kernel).

    $ git clone git://git.kernel.org/pub/scm/linux/kernel/git/stable/linux-stable.git
    
  2. Navigate to the cloned directory.

    $ cd linux-stable
    
  3. Apply the default settings for Arm Versatile boards (versatilepb).

    $ make ARCH=arm CROSS_COMPILE=arm-linux-gnueabi- versatile_defconfig
    
  4. Build.

    $ make ARCH=arm CROSS_COMPILE=arm-linux-gnueabi-
    
  5. Make sure that the kernel image and device tree have been generated.

    $ ls -latr arch/arm/boot/dts/versatile-pb.dtb
    $ ls -latr arch/arm/boot/zImage
    

Build BusyBox

  1. Clone BusyBox.

    $ git clone git://git.busybox.net/busybox
    
  2. Navigate to the cloned directory.

    $ cd busybox
    
  3. Apply the default settings.

    $ make ARCH=arm CROSS_COMPILE=arm-linux-gnueabi- defconfig
    
  4. We need to statically link to work with a single binary, so run the make menuconfig command to enable the kernel config "Build static binary (no shared libs)".

    $ make ARCH=arm CROSS_COMPILE=arm-linux-gnueabi- menuconfig
    
    Settings --> Build static binary (no shared libs)
    
  5. Build.

    $ make ARCH=arm CROSS_COMPILE=arm-linux-gnueabi-
    
  6. Install. When the installation is complete, a root file system will be created under the _install directory.

    $ make ARCH=arm CROSS_COMPILE=arm-linux-gnueabi- install
    

Creating a device driver

  1. Create a directory for the device driver and change to it.

    $ mkdir -p driver/sample
    $ cd driver/sample
    
  2. Create the source code for the device driver. (The following source code is a sample device driver that just loads / unloads.)

    $ nano driver_sample.c
    
    #include <linux/module.h>
    #include <linux/kernel.h>
    
    static int __init sample_module_init( void )
    {
    	printk( "driver sample load\n" );
    	return 0;
    }
    
    static void __exit sample_module_exit( void )
    {
    	printk( "driver sample remove\n" );
    }
    
    module_init( sample_module_init );
    module_exit( sample_module_exit );
    
    MODULE_DESCRIPTION( "sample_module" );
    MODULE_LICENSE( "GPL" );
    
  3. Create a Makefile.

    $ nano Makefile
    
    obj-m := driver_sample.o
    
    all:
    	make -C $(shell pwd)/../../linux M=$(shell pwd) modules
    clean:
    	make -C $(shell pwd)/../../linux M=$(shell pwd) clean
    
  4. Cross-compile the device driver.

    $ make ARCH=arm CROSS_COMPILE=arm-linux-gnueabi-
    
  5. Copy the device driver into busybox's _install directory.

    $ cp driver_sample.ko ../../busybox/_install/
    

Creating an app

  1. Create a directory for your app and change to it.

    $ mkdir -p app/sample
    $ cd app/sample
    
  2. Create the source code for your app. (The following source code is a sample application that only outputs logs.)

    $ nano app_sample.c
    
    #include <stdio.h>
    
    int main(int argc, char *argv[])
    {
    	printf( "app sample run\n" );
    	return 0;
    }
    
  3. Create a Makefile.

    $ nano Makefile
    
    TARGET	= app_sample
    
    CC		= ${CROSS_COMPILE}gcc
    LD		= ${CROSS_COMPILE}gcc
    
    CSRCS	= $(TARGET).c
    CFLAGS	= -c
    LDFLAGS	= -static -o $(TARGET)
    
    OBJS	= $(CSRCS:.c=.o)
    LIBS	=
    
    .c.o:
    	$(CC) $(CFLAGS) $<
    
    $(TARGET): $(OBJS)
    	$(LD) $(LDFLAGS) $(OBJS) $(LIBS)
    
    clean: ;
    	rm $(OBJS) $(TARGET)
    
  4. Cross-compile your app.

    $ make ARCH=arm CROSS_COMPILE=arm-linux-gnueabi-
    
  5. Copy the app into busybox's _install directory.

    $ cp app_sample ../../busybox/_install/
    

Run QEMU

  1. Image the root file system.

    $ cd busybox/_install/
    $ find .| cpio -o --format=newc > ../rootfs.img
    $ cd ../../
    
  2. Run QEMU.

    $ qemu-system-arm \
    	-M versatilepb \
    	-kernel ./linux/arch/arm/boot/zImage \
    	-dtb ./linux/arch/arm/boot/dts/versatile-pb.dtb \
    	-nographic \
    	-append "rdinit=/bin/sh" \
    	-initrd ./busybox/rootfs.img
    
  3. When the startup is complete, the shell will start. Checking with the ls command, the root file system looks like this:

    / # ls
    app_sample        dev               linuxrc           sbin
    bin               driver_sample.ko  root              usr
    / #
    
  4. Load the device driver.

    / # insmod driver_sample.ko
    driver_sample: loading out-of-tree module taints kernel.
    driver sample load
    
  5. Run the app.

    / # ./app_sample
    app sample run
    

Recommended Posts

Run Linux on ARM architecture with QEMU
Run docker-compose on Amazon Linux2 on ARM64
Faster emulation with QEMU on ARM CPUs
Run Kali Linux on Windows with GUI (without VirtualBox)
Run a Linux server on GCP
Run SwitchBot on Windows 10 with Bleak
[Note] Run Django on Amazon Linux 2
Run Yocto on Ubuntu using QEMU.
Run cron on Amazon Linux (set on Linux)
Run Radeon GPU on Windows on QEMU / KVM
Run servo with Python on ESP32 (Windows)
Use Tabpy with Cloud Run (on GKE)
X86 assembler on Linux (linkage with C)
[C] [python] Read with AquesTalk on Linux
Run bootgen on Debian GNU / Linux, Ubuntu
Install Mecab on Linux (CentOS) with brew
Run Keycloak on Amazon Linux 2 without Docker
Run a batch of Python 2.7 with nohup on Amazon Linux AMI on EC2
Run Debian (Linux) & LXQt on Athlon 200GE (AMD)
Set up golang with goenv on GNU / Linux
Start a process with a scheduling policy on Linux
Organize files on Windows with Linux commands-using WSL-
Run Flask on CentOS with python3.4, Gunicorn + Nginx.
ARM Architecture »Porting
Install PHP 7 series on Amazon Linux 2 with Amazon Linux Extras
Run LEDmatrix interactively with Raspberry Pi 3B + on Slackbot
Yum command to access MySQL with Python 3 on Linux
Run Paints Chainer on CPU with official python on win10
Set up Docker on Oracle Linux (7.x) with Vagrant
Install Docker on Arch Linux and run it remotely
Daemonizing processes on Linux
Run Python with VBA
Run prepDE.py with python3
jblas on Arch Linux
Linux (WSL) on Windows
NAT router on Linux
Linux (Lubuntu) with OneMix3S
Run mysqlclient on Lambda
Run Blender with python
linux with termux app
Run OpenMVG on Mac
Monitor traffic on Linux
Update vscode on linux
Linux system architecture [runlevel]
Try NeosVR on Linux
Reread Booting ARM Linux
Check capacity on Linux
LiveUSB creation on Linux
Linux operation on Win10
Run iperf with python
Problems with Chrome after suspending on Linux desktop KDE + Nvidia
Run Lima Driver on Debian GNU / Linux for Ultra96 / Ultra96-V2
Test Python with Miniconda on OS X and Linux with travis-ci
Intuitive password management with aws ssm on Mac / Linux alias
Learn "x86 architecture learned with your own emulator" with Manjaro (Linux)
Build Python3 for Windows 10 on ARM with Visual Studio 2019 (x86) on Windows 10 on ARM