This document provides instructions to create the “arm-ubuntu” image and points to the gem5 component that would work with the disk image. The arm-ubuntu disk image is based on Ubuntu’s server cloud image for arm available at (https://cloud-images.ubuntu.com/focal/current/). The .bashrc file would be modified in such a way that it executes a script passed from the gem5 configuration files (using the m5 readfile instruction).

The instructions for bringing up QEMU emulation are based on Ubuntu’s Wiki, and the instructions for creating a cloud disk image are based on this guide. More information about cloud-init can be found here.

We assume the following directory structure while following the instructions in this README file:

arm-ubuntu/
  |___ gem5/                                   # gem5 source code (to be cloned here)
  |
  |___ disk-image/
  |      |___ aarch64-ubuntu.img               # The ubuntu disk image should be downloaded and modified here
  |      |___ shared/                          # Auxiliary files needed for disk creation
  |      |      |___ serial-getty@.service     # Auto-login script
  |      |___ arm-ubuntu/
  |             |___ cloud.txt                 # the cloud config, to be created
  |             |___ gem5_init.sh              # The script to be appended to .bashrc on the disk image
  |             |___ post-installation.sh      # The script manipulating the disk image
  |             |___ arm-ubuntu.json           # The Packer script
  |
  |
  |___ README.md                               # This README file

Building the disk image

This requires an ARM cross compiler to be installed. The disk image is a 64-bit ARM 64 (aarch64) disk image. Therefore, we only focus on the 64-bit version of the cross compiler. It can be installed by:

sudo apt-get install g++-10-aarch64-linux-gnu gcc-10-aarch64-linux-gnu

In order to build the ARM based Ubuntu disk-image for with gem5, build the m5 utility in gem5/util/m5 using the following:

git clone https://gem5.googlesource.com/public/gem5
cd gem5/util/m5
scons build/arm64/out/m5

Troubleshooting: You may need to edit the SConscript to point to the correct cross compiler.

...
main['CXX'] = '${CROSS_COMPILE}g++-10'
...

Installing QEMU for aarch64

On the host machine,

sudo apt-get install qemu-system-arm qemu-efi

Installing cloud utilities

On the host machine,

sudo apt-get install cloud-utils

Downloading the cloud disk image

In the arm-ubuntu/disk-image/ directory,

wget https://cloud-images.ubuntu.com/focal/current/focal-server-cloudimg-arm64.img

Booting the disk image using QEMU

Generating an SSH key pair

ssh-keygen -t rsa -b 4096

Leave all prompted fields empty and hit enter. This will generate a public and private key pair in files ~/.ssh/id_rsa and ~/.ssh/id_rsa.pub. If your username is different from what is printed by command whoami, then add -C "<username>*<hostname>" to the command:

ssh-keygen -t rsa -b 4096 -C "<username>*<hostname>"

Making a cloud config file

First, we need a cloud config that will have the authorization information keys for logging in the machine.

In the arm-ubuntu/disk-image/arm-ubuntu directory, create a cloud.txt file with the following content,

#cloud-config
users:
  - name: ubuntu                            <- change this name to the current user (use `whoami`)
    ssh-authorized-keys:
      - ssh-rsa AAAAABBCCCCCCCrNJfweeeeee   <- insert the rsa key here (typically `cat ~/.ssh/id_rsa.pub`)
    sudo: ['ALL=(ALL) NOPASSWD:ALL']
    groups: sudo
    shell: /bin/bash
    homedir: /home/ubuntu                   <- change this to the home directory of `whoami`

More information about generating an ssh rsa key is available here. You can ignore the GitHub email address part.

Booting the cloud disk image with the cloud config file

In the arm-ubuntu/disk-image directory,

dd if=/dev/zero of=flash0.img bs=1M count=64
dd if=/usr/share/qemu-efi/QEMU_EFI.fd of=flash0.img conv=notrunc
dd if=/dev/zero of=flash1.img bs=1M count=64
cloud-localds --disk-format qcow2 cloud.img arm-ubuntu/cloud.txt
wget https://releases.linaro.org/components/kernel/uefi-linaro/latest/release/qemu64/QEMU_EFI.fd
qemu-system-aarch64 \
    -smp 2 \
    -m 1024 \
    -M virt \
    -cpu cortex-a57 \
    -bios QEMU_EFI.fd \
    -nographic \
    -device virtio-blk-device,drive=image \
    -drive if=none,id=image,file=focal-server-cloudimg-arm64.img \
    -device virtio-blk-device,drive=cloud \
    -drive if=none,id=cloud,file=cloud.img \
    -netdev user,id=user0 -device virtio-net-device,netdev=eth0 \
    -netdev user,id=eth0,hostfwd=tcp::5555-:22

Manipulating the disk image

When the qemu instance has fully booted, cloud-init has completed, and while it is still running, we will use Packer to connect to the virtual machine and manipulate the disk image. Before doing that, we need to add the private key using ssh-add.

ssh-add ~/.ssh/id_rsa

If the image was booted in qemu on a port number other than 5555, edit the ssh_port parameter in arm-ubuntu/arm-ubuntu.json accordingly. The disk manipulation process is automated. If your username is different from what is printed by command whoami, then edit build.sh and change the value of USER to "<your_username>". Then in the arm-ubuntu/disk-image/ directory,

chmod +x build.sh
./build.sh

build.sh also verifies the cloud.txt and modifies the arm-ubuntu.json accordingly. The packer script, executed by build.sh disables systemd. In case you need to enable systemd stuff, remove the last two provisioners from the arm-ubuntu.json file.

Note that after executing the packer script, you will not be able to emulate this disk image in qemu.

Preparing the disk image for gem5

We need to finalize the image before we can use it with gem5. This is done by:

qemu-img convert -f qcow2 -O raw focal-server-cloudimg-arm64.img arm64-ubuntu-focal-server.img
rm focal-server-cloudimg-arm64.img