NikonEmulator
(formerly FrEmulator)
Contents |
What is it ?
Trying to understand how the firmware(s) inside Nikon DSLR work, we thought it could be useful to have a software that would take a firmware as input, then imitate what a microcontroller would do with such instructions and data. That's what is generally known as "emulating" a device.
The NikonEmulator started as a simple interpreter of the Fujitsu FR ("B" microcontroller) instruction set (hence the former FrEmulator name), simulating only an FR CPU and its memory. Then, as understanding progressed, we added several "components", as well as tracing and debug tools.
Lastly, we thought it would be good to also study the Toshiba chip ("A" microcontroller) and we started over to emulate that chip too. Consequently, version 2 onwards of the emulator really contains two completely separate emulators and toolsets, and was renamed NikonEmulator.
This is a work in progress, obviously.
Getting Started
- Requirement: To run the latest versions of the NikonEmulator, you'll need a Java 7 environment or later (aka Java 1.7+). If you don't have one, please Download and install a Java SE from Oracle's website. The NikonEmulator is known to work under Windows and Linux, but any platform with a Java 7 environment should be OK.
- Download the latest version of NikonEmulator-x.xx.zip from our Google Code project and unzip it to any folder.
- Download an official firmware from the Nikon website. It is advised to use the D5100 v1.01 firmware (F-D5100-V101W.exe) that serves as a reference for research currently.
- Open that firmware file with an unzipping tool (such as 7-zip for Windows, and extract the D5100_0101.bin file it contains. That's the encoded firmware.
- Start the emulator by double clicking the startEmulator.bat file (or startEmulator.sh under Linux)
- Decode the encoded firmware by using "File > Decode firmware" menu, selecting D5100_0101.bin as the source file, and (for simplicity) NikonEmulator's own directory as target. You should get two files named "a640m010100.bin" and "b640101b.bin". Those are the decoded A and B firmwares.
You are now ready to start hacking.
Uninstalling
The NikonEmulator has no installer and all files are in the unzipped folder, except for a config file that gets created upon first run. This file is called .NikonEmulator and is stored at the root of the user's home directory, e.g. C:\Users\<login>\.NikonEmulator on recent Windows or ~/.NikonEmulator on Linux.
Consequently, full uninstallation is achieved by deleting the unzipped folder and above config file.
User interface
The DSLRs we are interested in share responsibilities between two distinct chips (known as A and B. See Understanding Firmware for more information). Consequently, the NikonEmulator doesn't emulate one chip, but two. This is the reason for the dual-pane interface.
- On the left hand side, with a light blue background, sits the Expeed emulator. The Expeed, or 'B' chip, is based on a Fujitsu Fr family microcontroller, abbreviated FR throughout the interface.
- On the right hand side, with a light green background, sits the I/O chip emulator. The I/O chip, or 'A' chip, is a Toshiba microcontroller of the Tx family, abbreviated TX throughout the interface.
As you can see, both panes look very similar, with the exception of a few features only applicable to one or the other chip.
You can freely move the vertical separator between the panes, or even completely hide one of the panes by clicking on the small arrows on the top of the separator.
Features
The emulator features can be classified in the following groups (roughly corresponding to the application menu):
- File management. This is where you can decode firmware from the cyphered versions provided on Nikon's Website. There is also a basic way to save and reload emulator state, but please be aware that it is limited to memory and CPU, so it can only be used for small tests, not for a complete session.
- Code emulation itself (Run). They correspond to the "Transport" button group (play/pause/etc.). This allows you to execute firmware instructions in different ways, either one-by-one or in sequence, with an optional variable delay between instructions. If the emulator executes instructions in sequence, you can pause it at any time with the corresponding button, or by setting up breakpoints (more on this later). The "STOP" button corresponds to a reset (it is advised then to close all windows that could still reflect obsolete states).
- Component inspection and interaction, grouped under the "Components" menu. Emulation involves, at the very least, a CPU and memory. Each instruction executed by the [CPU has an effect on its internal state (registers) or memory (either actual memory, or memory space mapped components). But other components are also required for a microcontroller to run: Interrupt controller, Timers, etc. Each of these components corresponds to a given Window in the emulator, allowing you to inspect the state of that component, or sometimes even force a given state.
- Tracing. This is about keeping track of what happens. For example, which instructions were executed (real-time disassembly log), what is the current function call nesting (call stack) or what memory areas are being accessed.
- Source code. This is how you can perform a full disassembly and basic analysis of the firmware code, navigate the resulting assembly code and display a call graph of the functions found
- Tools. This is where all the rest fits, among other a feature to dump part of the emulated memory to file, or reload it, as well as options used for disassembly and general User Interface configuration.
Sample uses
Note: The following use cases assume that you have already performed the "Getting started" steps above.
Getting a firmware disassembly
These are the steps to disassemble one of the firmwares (replace [chip] by FR or TX below or use the buttons on the corresponding side):
- Open the binary firmware using "File > Load [chip] firmware image" or the "Eject" button
- Select your options using "Tools > [chip] options" or the "Gear" button
- Open the code disassembly window using "Source > Analyse / Disassemble [chip] code" or the "Screwdriver" button
- Select an "options" file, which contains code structure definition and identified symbols. Sample files are provided for the D5100 firmware in the "conf" folder of the NikonEmulator distribution. They use the same base name as the firmware itself, followed by dfr.txt or dtx.txt depending on the chip you work on
- Select a target file to write disassembly to (optional)
- Select the options you want (recommended are "structure", "parameters", plus "int40" for the FR chip)
- Press OK. A log should open, containing many warnings but no errors. This is normal.
- You can now navigate the code using "Source > [chip] source code" or the "Source code" button
- If you chose a target file, you can also open that file in a text editor. Warning, the file can be large. Notepad++ or equivalent is recommended
Eye candy
If you want to be sure the emulator does not just throw garbage at you but is actually executing Nikon code, you can try the following "trick", that rudely forces the processor to execute the function displaying the language selection menu of the camera. Note that as most parameters haven't been initialized, the inter-character spacing is negative, so for example, instead of drawing the string "English", it draws "h s i l g n E" in reverse (see capture on the right).
To achieve this, the following steps MUST be performed on the FR (left/blue) side:
- Open the binary firmware using "File > Load FR firmware image" or the "Eject" button
- Let the emulator run so that the firmware performs some basic initialization, using "Run > Start (or resume) FR emulator" or the "Play" button. Let it run for "a certain time", so that the status bar shows more than, say, 5 000 000 cycles emulated
- Now pause the emulator using "Run > Pause FR emulator" or the "Pause" button
- Open the screen emulator window using "Components > Screen emulator" or the "Screen" button
- Open the CPU state window using "Components > FR CPU State window" or the "CPU" button
- Edit the PC (Program Counter) field and type the value "311942" (this value is only for the D5100, of course) and click "Save"
- Now restart the emulator using "Run > Start (or resume) FR emulator" or the "Play" button.
The screen emulator should first be cleared (turn from green to black), then start being filled with characters as described above. You can then pause the emulator again.
These steps are illustrated in this video (with an older emulator version).
Note : you might have to try again if doesn't work the first time. That's due to the fact that depending on when you pause the emulator, you can be in a state where the jump into the screen drawing routine takes another route.
Booting (work in progress)
General
Of course, the ultimate goal of the emulator is to perform a full boot sequence and, hopefully, one day, behave as a full Nikon camera would. The boot sequence is probably one of the hardest process to achieve, because all the software (OS) and hardware has to be initialized and checked. The absolute requirement for the OS to run is that timers are active. So here are the first steps to be performed no matter the CPU:
- Open the binary firmware using "File > Load [chip] firmware image" or the "Eject" button
- Open the timers window using "Components > [chip] programmable timers" or the "looping arrow" button
- Click the "Enable" button at the top right of that window
Now things get specific according to the chip you want to boot:
FR-specific
On the FR side, a given memory area (0x4006xxxx) seems to serve as an exchange between the CPU and an external component. We have no idea what this component is (we named it "Component 4006" for the time being), but we have discovered that the dialog checking its state can be satisfied by performing two writes at a given address (0x40060010). So:
- Open the Component 4006 window using "Components > 4006" or the corresponding button
- Start the emulator using "Run > Start (or resume) FR emulator" or the "Play" button
- When you see the Component 4006 window filling with lines, press the button "Store 0x1000 at 0x40060010" at the bottom twice
The OS is now running as can be observed by opening the RealOS objects window using "Trace > RealOS FR objects" (or the "3 cubes" button) and pausing at different times We think the FR chip is now stuck waiting for communications with the TX chip.
TX-specific
On the TX side, we have discovered that a given pin (port5 bit1) has to be at the "high" level for the boot process to succeed. So:
- Open the I/O ports window using "Components > I/O ports" or the corresponding button.
- Turn on the switch (or click the checkbox) in the row "IOPort 5" and column "bit# 1". You can then close the window. Settings are persisted across sessions.
The TX processor also talks to an Eeprom whose contents has to be loaded beforehand. So:
- Open the EEprom window using "Component > Tx Serial Devices (TX only)".
- In the "Eeprom" tab, select the "Contents" sub-tab.
- Click "Load..." and select the D5100-eeprom.bin file included in the emulator folder. You can then close the window.
To avoid having to perform the above steps each time you start a session, do the following:
- Open the Tx Options window using "Tools > Tx Options".
- In the "Eeprom Options" tab, select "Last Loaded". You can then close the window.
You are now ready to start:
- Start the emulator using "Run > Start (or resume) TX emulator" or the "Play" button
The OS is now running as can be observed by opening the RealOS objects window using "Trace > RealOS TX objects" (or the "3 cubes" button) and pausing at different times We think the TX chip is now stuck waiting for communications with the FR chip.
What now ?
It seems the pieces of the puzzle are slowly starting to assemble. What we know is still missing is:
- The communication between the processors. This is a serial link and we're close to make it work.
- The "Power" button. Because as strange as it can seem, the Nikon DSLRs are powered as soon as the battery is inserted and the processors are running even in "OFF" position. Once booted, we need to tell the camera that it has to turn on. We know how the power button is connected on the D3100. We hope it's the same on the D5100
- The battery protection. Nikon DSLRs make sure they run on genuine batteries, so the first screen we should see popping up should be a "Non-genuine battery" message. We have acquired knowledge about how to circumvent the protection (hacked firmware) but we also have to make sure we pretend the battery is sufficiently charged, not too hot, etc. That will have to be checked when we're there.
A note on breakpoints and triggers
For people used to development environments, the concept of Breakpoint will sound familiar. Basically, by hitting the "Debug" button instead of the "Play" button, you instruct the emulator to pause the program whenever it is about to execute some instructions you "marked" beforehand. Those "marks" are breakpoints. Such breakpoints can be set by navigating the source code (after disassembly, see first use case above), then right-clicking on an instruction and selecting "Toggle breakpoint".
Alternatively, the breakpoints can also be defined or edited in a dedicated Window accessed using "Run > Setup [chip] breakpoints" (or "Breakpoint" button).
You will notice that when you Add or Edit a breakpoint, the window allows you to specify much more than just a PC address. This is because NikonEmulator breakpoints can do much more than pause on a given instruction:
- they can break when any CPU register matches a given value, and can combine several such register conditions
- for registers presented in binary form (such as the FR's CCR register), you can specify which bits you want to match by using a combination of "1", "0" and "?" (don't care) characters
- you can also break when a given memory position (optionally masked) matches (or doesn't match) a given value
Finally, although the primary goal of a breakpoint is to pause code, the concept was extended so that when the conditions match, the breakpoint (let's call it a trigger) can do any combination of :
- pause code (of course)
- log the condition match in the log tab
- trigger a configurable interrupt
- perform a jump to any part of the code
The last option provides a very effective way to skip code that would fail due to missing or badly emulated components, for example.
Tips
- If you regularly use the emulator, you can make it automatically load firmwares on startup by adding command line arguments. Just edit the startEmulator.bat (or .sh) file and spot the line starting with "call java..." (that's the longest line of the file). At the end of this line, replace %* by the filenames of, respectively, B firmware and A firmware. If they sit in the same directory, just use the names (e.g. ...EmulatorUI b640101b.bin a640m010100.bin). If they are in different directories, you must use the full paths, enclosed between double quotes if they contain blanks (e.g. ...EmulatorUI "c:\Nikon firmwares\D5100\b640101b.bin" "c:\Nikon firmwares\D5100\a640m010100.bin")
Emulator source code
The code of the Emulator is freely available. If you want to take a look at it, build your own version or understand how something works, please help yourself, and all feedback is welcome of course.
Tools and links
- If you just want to browse sources online, they are hosted on the Google Code site that Simeon set up.
- If you want to get sources, you can use any Mercurial (Hg) command-line or graphical tool. For Windows, I recommend TortoiseHg. You just have to "clone" the following repository, which will get you all source files (Emualtor as well as other tools used in the project): https://code.google.com/p/nikon-firmware-tools/
- If you want to go further, you need a Java IDE (Integrated Development Environment). I personnaly love IntelliJ IDEA by Jetbrains, and the free Community Edition is all you need to build, develop and debug the Emulator. I've setup a screencast showing how to load sources and build the project in a few clicks.
