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.
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)
.
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/;
chroot
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;
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;
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.
[Unit]
Description=gem5 init script
Documentation=http://gem5.org
After=getty.target
[Service]
Type=idle
ExecStart=/sbin/gem5init
StandardOutput=tty
StandardInput=tty-force
StandardError=tty
[Install]
WantedBy=default.target
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.
#!/bin/bash -
CPU=`cat /proc/cpuinfo | grep vendor_id | head -n 1 | cut -d ' ' -f2-`
echo "Got CPU type: $CPU"
if [ "$CPU" != "M5 Simulator" ] && [ "$CPU" != "HygonGenuine" ];
then
echo "Not in gem5. Not loading script"
exit 0
fi
# Try to read in the script from the host system
/sbin/m5 readfile > /tmp/script
chmod 755 /tmp/script
if [ -s /tmp/script ]
then
# If there is a script, execute the script and then exit the simulation
su root -c '/tmp/script' # gives script full privileges as root user in multi-user mode
sync
sleep 10
/sbin/m5 exit
fi
echo "No script found"
You will also need to update the /etc/fstab
file to include at least one partition. This can be editted as needed.
# /etc/fstab: static file system information.
#
# <file system> <mount point> <type> <options> <dump> <pass>
#
/dev/hda1 / ext3 noatime 0 1
Finall, update /etc/hosts
for the localhost loopback.
127.0.0.1 localhost
::1 localhost ip6-localhost ip6-loopback
fe00::0 ip6-localnet
ff00::0 ip6-mcastprefix
ff02::1 ip6-allnodes
ff02::2 ip6-allrouters
ff02::3 ip6-allhosts
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;
There are two ways you can get the required linux kernel for your disk image. I used v5.4.49.
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;
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/;
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
Last modified: MST