Android KitKat
Contents
Building Android KitKat for gem5
Overview
The easiest way to build Android for gem5 is to base the system on a the emulated Goldfish device. The main difference between the actual qemu-based Goldfish model and gem5 is a small number of gem5-specific configuration files. These files are mainly related to differences in block device naming and scripts to start use gem5's pseudo-op interface to start experiments.
Build Instructions
Follow the directions on Android Open Source to download and build Android. Make sure to create a local mirror (see the download page) to speed up things if you ever need to create a new working directory. The following instructions are based on our experience from bringing up Android 4.4.4r2 (KitKat).
Make sure to quickly read the AOSP build instructions. In particular the section about Java dependencies. KitKat and earlier all depend on particular Sun/Oracle JDK versions. Lollipop and newer seem to be able to build with OpenJDK.
If you are building on a dedicated build machine or virtual machine, I'd recommend making sure OpenJDK is not installed at all on your machine for building KitKat. Sometimes having both versions can cause issues where some tools are invoked from OpenJDK while others get invoked from the Oracle JDK.
Either way, make sure that the Oracle bin directory is first in your PATH (and make sure it doesn't have a trailing slash):
export PATH=/path/to/java-6-jdk/bin:$PATH
When setting up your build directories, I'd suggest a structure as follows:
- /work/android (or some other directory with plenty of free space)
- .../repos/aosp-mirro - Mirror of the upstream Android repository
- .../gem5kitkat/
- .../aosp - Clone of the Android repository
Build a vanilla AOSP KitKat distribution using the following command:
. build/envsetup.sh lunch aosp_arm-userdebug make -j8
This builds a plain Android for the Goldfish device (an Android specific qemu version). We are going to use this as a base for our gem5 distribution.
Useful commands:
hmm | Show a list of build system commands |
mm | Build the Android module in the current directory |
mma | Build the Android module in the current directory and its dependencies |
emulator | Launch Android in qemu |
The mm command is especially useful since just running make in a directory with an existing build of Android (i.e., make doesn't need to build anything) can take several minutes.
Preparing a filesystem for gem5
First, create an empty disk (this example creates a 2GiB image) image:
dd if=/dev/zero of=myimage.img bs=1M count=2048
As root, hook up the disk image to a loopback device (the following
assumes /dev/loop0 is free).
losetup /dev/loop0 myimage.img
Using fdisk, create the following partitions:
Part. No | Usage | Approximate Size |
---|---|---|
1 | / | 500MB |
2 | /data | 1GB |
3 | /cache | 500MB |
Use common sense when setting up the partitions. The root partition will contain both Android's root file system and the system file system and should be big enough for both of them. The data partition will contain any apps that are not a part of the system (i.e., anything you install).
As root, tell the kernel about the partitions and format them to ext4:
partprobe /dev/loop0 mkfs.ext4 -L AndroidRoot /dev/loop0p1 mkfs.ext4 -L AndroidData /dev/loop0p2 mkfs.ext4 -L AndroidCache /dev/loop0p3
Mount the filesystem and extract the root file system:
mkdir -p /mnt/android mount /dev/loop0p1 /mnt/android cd /mnt/android zcat AOSP/out/target/product/generic/ramdisk.img | cpio -i mkdir cache mkdir -p /mnt/tmp mount -oro,loop AOSP/out/target/product/generic/system.img /mnt/tmp cp -a /mnt/tmp/* system/
At this point, the new disk image is a (mostly) vanilla Goldfish
image. Add the gem5 pixie dust by copying all the files in the
attached tar-ball into the new root file system and adding an
m5 binary (see util/m5 in your gem5 work directory)
to /sbin. This directory contains a gem5-specific init.rc that
is based on the original Goldfish device, with additional
tweaks. Specifically, it runs /gem5/postboot.sh when Android
has booted. This script is responsible for disabling the screen lock
and downloading and executing a run script from gem5.
At this point, everything should just work. Unmount everything and
disconnect the loop back device:
umount /mnt/android losetup -d /dev/loop0
Android systems generally does a lot of initialization (JIT
compilation etc.) on the first boot. Since gem5 normally mounts the
root file system as CoW and stores the file system differences in
memory. To speed up future experiments, make sure to follow the guide
in BBench-gem5 to make these changes permanent.
Building the kernel
You will need a recent ARM cross compiler to build the kernel. If
you're using Ubuntu 10.04, install it by running:
sudo apt-get install gcc-arm-linux-gnueabihf
Checkout the gem5 kernel from the following git repository:
git://linux-arm.org/linux-linaro-tracking-gem5.git
Alternatively, you can use the github mirror of this same repo (See: http://permalink.gmane.org/gmane.comp.emulators.m5.devel/27631):
git clone https://github.com/gem5/linux-arm-gem5.git
If you are not planning on doing kernel development, you can add the option --depth 1 to significantly speed up your clone.
Configure and build the kernel using:
make CROSS_COMPILE=arm-linux-gnueabihf- ARCH=arm vexpress_gem5_defconfig make CROSS_COMPILE=arm-linux-gnueabihf- ARCH=arm vmlinux -j8
Note: if you want to use Workload Automation, this may be a good time to add the extra kernel options to your .config file. See WA-gem5 for a description and which kernel options should be enabled.
Android Runtime Configuration
Simulation-specific kernel boot options options:
Kernel Option | Function |
---|---|
qemu=1 | Enable emulation support |
qemu.gles=1 | Don't use software rendering (usually enables GLES pass through) |
androidboot.hardware=NAME | Overrides the device's platform name (used to select configuration files at boot) |
A simulated system should normally set qemu=1 on the kernel command line. This enables software rendering and some emulation specific services. In order to load the right boot configuration, set androidboot.hardware to gem5.
Kernel command line to properties mapping:
Kernel Option | Android Property |
---|---|
androidboot.* | ro.boot.* |
androidboot.serialno | ro.serialno |
androidboot.mode | ro.bootmode |
androidboot.baseband | ro.baseband |
androidboot.bootloader | ro.bootloader |
androidboot.hardware | ro.hardware & ro.boot.hardware |
* | ro.kernel.* if running in emulation mode |
Emulation Mode Specifics (qemu=1)
OpenGL & Graphics
- Setting the ro.kernel.qemu property forces libGLES_android to be used unless ro.kernel.qemu.gles is also set.
- qemu.sf.lcd_density instead of ro.sf.lcd_density is used to specify display density.
Resources
Running workloads with Kitkat
To run workloads we advise the use of Workload Automation. For detailed instructions on how to use this see: WA-gem5
NoMali
To use a NoMali model in gem5, you need to perform the following steps:
- Add it to the configuration file
- Add the user-space drivers to your Android image
- Add the kernel-side driver to your kernel
- Inform the kernel of the device by adding it to the device tree
These steps are described in detail in the sections below.
Once you have completed the steps to build the kernel-side driver and modified the DTB, test the kernel and DTB by starting it in gem5. Ensure that you get the following message from the kernel:
mali 2d000000.gpu: Continuing without Mali clock control mali 2d000000.gpu: GPU identified as 0x0750 r0p0 status 1 mali 2d000000.gpu: Probed as mali0
Once the user-space driver has been added, start Android and check the output of the logcat command. You should see something like this when surfaceflinger starts:
I/[Gralloc]( 885): using (fd=14) I/[Gralloc]( 885): id = hdlcd I/[Gralloc]( 885): xres = 1920 px I/[Gralloc]( 885): yres = 1080 px I/[Gralloc]( 885): xres_virtual = 1920 px I/[Gralloc]( 885): yres_virtual = 1080 px I/[Gralloc]( 885): bpp = 16 I/[Gralloc]( 885): r = 11:5 I/[Gralloc]( 885): g = 5:6 I/[Gralloc]( 885): b = 0:5 I/[Gralloc]( 885): width = 305 mm (159.895081 dpi) I/[Gralloc]( 885): height = 171 mm (160.421051 dpi) I/[Gralloc]( 885): refresh rate = 59.28 Hz E/SurfaceFlinger( 885): hwcomposer module not found W/SurfaceFlinger( 885): getting VSYNC period from fb HAL: 16868241 W/SurfaceFlinger( 885): no suitable EGLConfig found, trying a simpler query I/SurfaceFlinger( 885): EGL informations: I/SurfaceFlinger( 885): vendor : Android I/SurfaceFlinger( 885): version : 1.4 Android META-EGL I/SurfaceFlinger( 885): extensions: EGL_KHR_get_all_proc_addresses EGL_ANDROID_presentation_time EGL_KHR_image EGL_KHR_image_base EGL_KHR_gl_texture_2D_image EGL_KHR_gl_texture_cubemap_image EGL_KHR_gl_renderbuffer_image EGL_KHR_fence_sync EGL_KHR_create_context EGL_EXT_create_context_robustness EGL_ANDROID_image_native_buffer EGL_KHR_wait_sync EGL_ANDROID_recordable I/SurfaceFlinger( 885): Client API: OpenGL_ES I/SurfaceFlinger( 885): EGLSurface: 5-6-5-0, config=0x78f1f4e0 I/SurfaceFlinger( 885): OpenGL ES informations: I/SurfaceFlinger( 885): vendor : ARM I/SurfaceFlinger( 885): renderer : Mali-T760 I/SurfaceFlinger( 885): version : OpenGL ES 3.1 v1.r8p0-02rel0.785fbb28b57044ab28a90a55a7b06f3f
Configuration Changes
The NoMali GPU is not instantiated by default in any of the example configurations. To instantiate it, add the following code to your configuration script:
my_system.gpu = NoMaliGpu( gpu_type="T760", ver_maj=0, ver_min=0, ver_status=1, int_job=114, int_mmu=115, int_gpu=116, pio_addr=0x2d000000, pio=membus.master)
The code above instantiates a NoMali model of a Mali T760 r0p0-1 at address 0x2d000000. The GPU type and revision must match the driver.
Android User Space Drivers
Download the Mali drivers for gem5 from the ARM Mali Midgard User Space Drivers section on MaliDeveloper. Make sure that you download a driver that matches your Android version. Make a note of the driver version number, you'll need a matching kernel-side driver of the same version.
The downloaded file will contain at least the following files:
- lib/egl/libGLES_mali.so
- lib/hw/gralloc.default.so
Copy the entire lib directory into /system/vendor in the target system. The resulting disk image should contain (at least) the following files:
- /system/vendor/lib/egl/libGLES_mali.so
- /system/vendor/lib/hw/gralloc.default.so
Make sure that everyone can access the files (i.e., files have permission 0644 and directories 0755), or you'll end up with permission errors when booting the system.
Kernel Drivers
Download the Mali kernel-side drivers from the ARM Mali Midgard Kernel Drivers section on MaliDeveloper. Make sure that you download a driver version that matches your user space driver version.
Copy the directory driver/product/kernel/drivers/gpu/arm into drivers/gpu/ in your target kernel. You now need to wire up the driver to the kernel's build system. Do that by adding arm/ to the list of subdirectories in drivers/gpu/Makefile. To add it to the configuration system, add source "drivers/gpu/arm/Kconfig to drivers/video/Kconfig.
Enable the driver in the kernel configuration (set MALI_MIDGARD / Device Drivers -> Graphics support -> ARM GPU Configuration -> Mali Midgard series support). The default options should work and enable device tree support. Do not set the NoMali option in the kernel.
Device Tree
Add the following node to your device tree:
gpu@0x2d000000 { compatible = "arm,mali-midgard"; reg = <0 0x2d000000 0 0x4000>; interrupts = <0 82 4>, <0 83 4>, <0 84 4>; interrupt-names = "JOB", "MMU", "GPU"; };
Note that there is an offset between interrupts in gem5 and in the device tree. Linux starts counting SPIs from 0, while gem5 starts from 32.