Creating an x86 disk image from scratch

This tutorial follows gem5's utility script to setup an x86 disk image for full system mode running Ubuntu 22.04 LTS. All the steps were tested using Ubuntu 20.04.06 LTS running on x86 hardware.

Create the empty disk with the gem5 utility

For the sake of simplicity, cd to your gem5 directory. Then create a directory where you will work on creating the disk image:

mkdir m5_binaries; mkdir m5_binaries/mnt; mkdir m5_binaries/disks; mkdir m5_binaries/binaries;

Next, from the gem5 source directory, we will create an empty disk image using the gem5 utility script. You can set the size of the image as needed for your application:

util/gem5img.py init m5_binaries/disks/ubuntu-18.04-amd64.img 5120;

Note: if you get an error from the gem5img.py stating TypeError: 'float' object cannot be interpreted as an integer, then all you have to do is go to line 361 within gem5img.py where it indicates os.lseek(fd, size - 1, os.SEEK_SET) and change it to os.lseek(fd, int(size) - 1, os.SEEK_SET).

Mounting the disk and adding the root files

Now that the empty disk has been created, you will need to mount it.

util/gem5img.py mount m5_binaries/disks/ubuntu-18.04-amd64.img m5_binaries/mnt;

Download the Ubuntu 18 base root files and copy them into your mounted disk using the following commands:

cd m5_binaries;
wget http://cdimage.ubuntu.com/ubuntu-base/releases/22.04/release/ubuntu-base-22.04-base-amd64.tar.gz;

Next, copy the root files into the mounted directory.

sudo tar xzvf ubuntu-base-22.04-base-amd64.tar.gz -C mnt;

Finally copy your configuration file from your system into the mounted disk image to be able to use chroot.

sudo cp /etc/resolv.conf mnt/etc/;

Using chroot

Binding and setting the root directory

The chroot command allows to change the root to the source directory of the mounted image. You will first need to mount the disk image from the gem5 directory.

You will need to bind some of your host system's directories to those of the mounted disk.

sudo /bin/mount -o bind /sys mnt/sys;
sudo /bin/mount -o bind /dev mnt/dev;
sudo /bin/mount -o bind /proc mnt/proc;

Finally, to chroot, use the following command:

sudo /usr/sbin/chroot mnt /bin/bash;

Installing packages on the disk image

Now that we are in the root directory of the disk image, we can update and install some packages.

apt-get update; apt-get install software-properties-common -y; add-apt-repository universe;

The following command is not required, but I have included also some useful packages to install (either for benchmarks or for building your own kernel within the disk image).

apt-get install gcc g++ systemd linux-generic make wget -y;

Setting up the required gem5 files

From the root directory of your disk image, download the following file and unpack it:

wget http://cs.wisc.edu/~powerjg/files/gem5-guest-tools-x86.tgz; tar xzvf gem5-guest-tools-x86.tgz;
cd gem5-guest-tools/; ./install;

You will need to add/create some files. The first one is /lib/systemd/system/gem5.service. Paste the following code into it.

Enable the gem5 service and disable the ttyS0 service.

systemctl enable gem5.service; systemctl mask serial-getty@ttyS0.service;

Next, create /sbin/gem5init. If the file already exists, make sure that the if statement containing "$CPU" checks to see if the name is not HygonGenuine as well as shown below. An API change in gem5 for v22.1.0.0 indicates that the default string for the CPU type in gem5 is no longer M5 Simulator but instead HygonGenuine. I modified the original gem5init script to reflect this.

You will also need to update the /etc/fstab file to include at least one partition. This can be editted as needed.

Finall, update /etc/hosts for the localhost loopback.

Exiting and unmounting

To leave the chroot, simply exit. This will take you back to your host machine's m5_binaries directory:

exit

You will also need to unbind the directories before unmounting the disk.

sudo /bin/umount mnt/sys;
sudo /bin/umount mnt/proc;
sudo /bin/umount mnt/dev;
sudo umount mnt;

Linux kernel

There are two ways you can get the required linux kernel for your disk image. I used v5.4.49.

Method 1: Download a pre-built kernel

All you need to do is download the pre-built kernel from gem5's website into the binaries directory within m5_binaries.

wget http://dist.gem5.org/dist/v22-1/kernels/x86/static/vmlinux-5.4.49 -P binaries;

Method 2: Build your own kernel within the disk image

chroot to the source directory of the disk image as shown previously. Once this is done, install the required packages if you haven't already.

sudo apt-get install linux-generic gcc g++ make

This method is more lengthy and complicated. First, you will need to have a version of binutils that is compatible with Ubuntu 18. This means that you will either need to compile the kernel on a machine running Ubuntu 18 OR chroot into the disk image and build it within the disk image (which is why I specified 8GB for the disk image initially). Note: the linux repository will be ~3GB so ensure that you have enough disk space.

git clone https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux.git;

We will also need to download the configuration file from to use when building the kernel.

wget https://gem5.googlesource.com/public/gem5-resources/+archive/refs/heads/stable/src/linux-kernel/linux-configs.tar.gz;
mkdir linux-configs; tar xzvf linux-configs.tar.gz -C linux-configs;

Before building the kernel, I made some modifications to the configuration file as I was getting issues with gem5 not recognizing a mouse driver (which we do not need anyways).

With the editor of your choice, modify the config.x86.5.4.49 inside configuration file linux-configs and change the line containing CONFIG_INPUT_MOUSEDEV=y to CONFIG_INPUT_MOUSEDEV=n.

cp linux-configs/config.x86.5.4.49 linux/.config;
cd linux;
git checkout v5.4.49;
make vmlinux -j `nproc`;
                

Note: If you want to fully clean using make, use make distclean. This will also delete the .config file, so you will need to copy it again.

At the end of the make run, you should now have a file called vmlinux in the linux source directory. You can exit the chroot and then copy the vmlinux file into the binaries directory.

exit;
sudo cp mnt/linux/vmlinux binaries/;
                

Testing the disk image

Create a directory inside the gem5 directory called bootscripts.

mkdir bootscript;
echo -e "echo 'hello world'\n/sbin/m5 exit" > bootscripts/hello.rcS;

Now, all you need to do is run FS mode as you usally would using hello.rcS as its script. You can monitor gem5 and disk image activity by using telnet.

telnet localhost 3456

The output of telnet should show something like the following indicating success:

[  OK  ] Reached target Multi-User System.
[  OK  ] Reached target Graphical Interface.
Starting Update UTMP about System Runlevel Changes...
[  OK  ] Started Update UTMP about System Runlevel Changes.
Got CPU type: HygonGenuine
hello world
Connection closed by foreign host.

The output of gem5 will look something like the following:

src/arch/x86/cpuid.cc:185: warn: x86 cpuid: unknown family 0x4000
build/X86/arch/x86/generated/exec-ns.cc.inc:27: warn: instruction 'fwait' unimplemented
src/dev/x86/i8042.cc:290: warn: Write to unknown i8042 (keyboard controller) command port.
src/arch/generic/debugfaults.hh:145: warn: MOVNTDQ: Ignoring non-temporal hint, modeling as cacheable!
Exiting @ tick 3355855059000 because m5_exit instruction encountered

References

Last modified: MST