Emulating an iPod Touch 1G and iPhoneOS 1.0 using QEMU (Part II)

In my previous blog post, I described how I managed to get an iPod Touch 1G up and running using the QEMU emulator. In this follow-up post, I will outline the necessary steps to get the emulator up and running in a local environment.

Note: the instructions below have only been tested on MacOS so far.

Building QEMU

The emulator is built on top of QEMU, which we should build first. Start by cloning my fork of QEMU and checking out to the ipod_touch_1g branch:

git clone https://github.com/devos50/qemu
cd qemu
git checkout ipod_touch_1g

Compile QEMU by running the following commands:

mkdir build
cd build
../configure --enable-sdl --disable-cocoa --target-list=arm-softmmu --disable-capstone --disable-pie --disable-slirp --extra-cflags=-I/usr/local/opt/openssl@3/include --extra-ldflags='-L/usr/local/opt/openssl@3/lib -lcrypto'
make

Note that we’re explicitly enabling compilation of the SDL library which is used for interaction with the emulator (e.g., capturing keyboard and mouse events). Also, we only configure and build the ARM emulator. We’re also linking against OpenSSL as the AES/SHA1 engine uses some of the library’s cryptographic functions. Remember to update the include/library paths to the OpenSSL library in case they are located elsewhere. You can speed up the make command by passing the number of available CPU cores with the -j flag, e.g., use make -j6 to compile using six CPU cores. The compilation process should produce the qemu-system-arm binary in the build/arm-softmmu directory.

Downloading System Files

We need a few files to successfully boot the iPod Touch emulator to the home screen, which I published as a GitHub release for convenience. You can download all these files from here, and they include the following:

  • The S5L8900 bootrom binary, as iBoot and the kernel invokes some procedures in the bootrom logic.
  • The iBoot bootloader binary. This file is typically included in the IPSW firmware in an encrypted format, but for convenience, I’ve extracted the raw binary and included it in the GitHub repository.
  • A NOR image that contains various auxillary files used by the bootloader. I will provide some instructions on generating this NOR image manually later in this post.
  • A NAND image that contains the root file system. I will provide some instructions on generating this NAND image manually later in this post.

Download all the required files and save them to a convenient location. You should unzip the nand_n45ap.zip file, which contains a directory named nand.

Running the Emulator

We are now ready to run the emulator from the build directory with the following command:

./arm-softmmu/qemu-system-arm -M iPod-Touch,bootrom=<path to bootrom image>,iboot=<path to iboot image>,nand=<path to nand directory> -serial mon:stdio -cpu max -m 1G -d unimp -pflash <path to NOR image>

Remember to fix the flags, so they point correctly to the downloaded system files. Running the command above should start the emulator, and you should see some logging output in the console:

martijndevos@iMac-van-Martijn build % ./arm-softmmu/qemu-system-arm -M iPod-Touch,bootrom=/Users/martijndevos/Documents/ipod_touch_emulation/bootrom_s5l8900,iboot=/Users/martijndevos/Documents/ipod_touch_emulation/iboot.bin,nand=/Users/martijndevos/Documents/generate_nand/nand -serial mon:stdio -cpu max -m 1G -d unimp -pflash /Users/martijndevos/Documents/generate_nor/nor.bin
WARNING: Image format was not specified for '/Users/martijndevos/Documents/generate_nor/nor.bin' and probing guessed raw.
         Automatically detecting the format is dangerous for raw images, write operations on block 0 will be restricted.
         Specify the 'raw' format explicitly to remove the restrictions.
Reading PMU register 118
Reading PMU register 75
Reading PMU register 87
Reading PMU register 103
iis_init()
spi_init()
Reading PMU register 75
power supply type batt
battery voltage Reading PMU register 87
error
SysCfg: version 0x00010001 with 4 entries using 200 of 8192 bytes
BDEV: protecting 0x2000-0x8000
image 0x1802bd20: bdev 0x1802b6a8 type dtre offset 0x10800 len 0x7d28
image 0x1802c170: bdev 0x1802b6a8 type batC offset 0x18d40 len 0x101e1
image 0x1802c5c0: bdev 0x1802b6a8 type logo offset 0x29a80 len 0x1c3a
image 0x1802ca10: bdev 0x1802b6a8 type nsrv offset 0x2bfc0 len 0x4695
image 0x1802ce60: bdev 0x1802b6a8 type batl offset 0x30d00 len 0xc829
image 0x1802d2b0: bdev 0x1802b6a8 type batL offset 0x3e240 len 0xe9d2
image 0x1802e888: bdev 0x1802b6a8 type recm offset 0x4d780 len 0xb594
display_init: displayEnabled: 0
otf clock divisor 5
fps set to: 59.977
SFN: 0x600, Addr: 0xfe00000, Size: 0x14001e0, hspan: 0x500, QLEN: 0x140
merlot_init() -- Universal code version 08-29-07
Merlot Panel ID (0x71c200):
   Build:          PVT1 
   Type:           TMD 
   Project/Driver: M68/NSC-Merlot 
ClcdInstallGammaTable: No Gamma table found for display_id: 0x0071c200
Reading PMU register 75
power supply type batt
battery voltage Reading PMU register 87
error
Reading PMU register 23
Reading PMU register 42
Reading PMU register 40
Reading PMU register 41
Reading PMU register 75
power supply type batt
battery voltage Reading PMU register 87
error
Reading PMU register 23
Reading PMU register 42
Reading PMU register 40
Reading PMU register 41
usb_menu_init()
vrom_late_init: unknown image crc: 0x66a3fbbf


=======================================
::
:: iBoot, Copyright 2007, Apple Inc.
::
::	BUILD_TAG: iBoot-204
::
::	BUILD_STYLE: RELEASE
::
=======================================

Reading PMU register 87
[FTL:MSG] Apple NAND Driver (AND) 0x43303032
...

If there are any issues running the above commands, please let me know by commenting on this post or by making an issue on GitHub.

Manually Generating the NOR Image

If you wish to make changes to the NOR image, e.g., to replace the boot logo, to modify the device tree, or to change the kernel bootargs, you can follow the instructions below. I created a separate tool tool to generate the NOR image. You can clone and compile this tool with the following command:

git clone https://github.com/devos50/generate-ipod-touch-1g-nor
cd generate-ipod-touch-1g-nor
gcc generate_nor.c aes.c -o generate_nor -I/usr/local/Cellar/openssl@1.1/1.1.1l/include -L/usr/local/Cellar/openssl@1.1/1.1.1l/lib -lssl -lcrypto

Remember to replace the include and library paths to point to your OpenSSL installation.

You can modify the specifics of the generated NOR file by changing the generate_nor.c file. For example, the kernel bootargs can be modified here. The data directory contains various IMG2 images that will be embedded in the NOR image, including the device tree and boot logo. Generating the NOR image can be done by running the generate_nor binary:

./generate_nor

This will generate a nor.bin file.

Manually Generating the NAND Image

The NAND image is generated based on the root filesystem included in the IPSW firmware file, albeit heavily modified to bypass various checks. The necessary code can be found in this repository and be cloned as follows:

git clone https://github.com/devos50/generate-ipod-touch-1g-nand
cd generate-ipod-touch-1g-nand
gcc generate_nand.c -o generate_nand

This produces the generate_nand binary in the root directory of the repository. It expects filesystem-readonly.img file, which can be generated using the instructions below.

Creating a Filesystem Image

As a starting point, I uploaded a writable root filesystem to GitHub. This DMG file is based on the N45AP firmware and contains various modifications for emulation purposes. On Mac, you can mount this file and make changes to it. When done, unmount the file and convert the writable DMG to a read-only one using the hdiutil tool (available on Mac):

hdiutil convert -format UDRO -o filesystem-readonly.dmg  filesystem-writable.dmg

You should then extract the filesystem partition from the DMG file. For this, I used the dmg2img tool, which can be downloaded from here (build instructions can be found in this repository too). You can see which partitions the DMG file includes using the following command:

./dmg2img -l filesystem-readonly.dmg 

Which outputs something like:

dmg2img v1.6.5 (c) vu1tur (to@vu1tur.eu.org)

filesystem-readonly.dmg --> (partition list)

partition 0: Driver Descriptor Map (DDM: 0)
partition 1: Apple (Apple_partition_map: 1)
partition 2: Macintosh (Apple_Driver_ATAPI: 2)
partition 3: Mac_OS_X (Apple_HFSX: 3)
partition 4:  (Apple_Free: 4)

We need to extract the partition in HFS format, i.e., partition 3. Extract this partition using the following command:

./dmg2img -p 3 filesystem-readonly.dmg

This generates a filesystem-readonly.img, which you should copy to the directory containing the generate_nand binary. As the final step, generate the nand directory as follows:

./generate_nand



Enjoy Reading This Article?

Here are some more articles you might like to read next:

  • Emulating an iPod Touch 2G using QEMU
  • Censorship-Resistant Indexing and Search for Web3
  • Emulating an iPod Touch 1G and iPhoneOS 1.0 using QEMU (Part I)
  • Finding Python Memory Leaks Using Meliae