Notes from inside your Wii

HackMii header image 2

48UXP (sw)

February 12th, 2009 by bushing · 5 Comments

(This is the second part of a three part series. The first part described the hardware of this device; this part will describe the software / firmware that drives this thing, and the last part will document the modifications I made to the hardware and software to try to get it to do what I want.)

There are three different programmable devices inside the 48UXP:

  1. 80C32 MCU
  2. XC3030A FPGA
  3. Cypress EZ-USB FX2

Of these, only the 80C32 has nonvolatile code storage; the other two devices have their code uploaded by the client every time they are used.

80C32 firmware

The 80C32 firmware is contained on an EEPROM chip inside the device; I pulled the chip and read it using my crappy Willem-clone programmer.  It contains about 6K of code and 24K of random bits of data, 2.5K of which is a “default” bitstream to upload to the XC3030A.  It’s responsible for transferring commands and data over an 8-bit pipe from the FX2 (or parallel port), programming the XC3030A over JTAG, driving the shift registers connected to the pin drivers, and transferring commands and data over an 8-bit pipe to the XC3030A.  There’s a lookup table which takes a 1-byte command and jumps to a fixed pointer.  There’s a command that lets you upload data to arbitrary places in the SRAM, and a command that causes execution to jump to code inside the SRAM; this lets them upload routines and run them.

XC3030A bitstreams

There are a number of different FPGA bitstreams in use here.  One is hard-coded in the 80C32 firmware, and two hard-coded in the Windows client executable.  The rest are contained in the resource files, which we will discuss shortly.  Unfortunately, there’s no way to analyze these bitstreams; we just have to treat them as black boxes, and deduce their functionality from context.

FX2 firmware

The FX2 has a USB bootloader which accepts code over USB.  The Windows client has two different firmwares embedded in it, and it seems to pick one or the other based on a device ID.  It calls itself “EPP LabTool USB 2.0 Bridge Version 1.13”, and like the 80C32 firmware, it accepts one-byte commands.  However, these one byte commands are mainly used … to send sequences of one-byte commands to the 80C32.  We have layers and layers of protocol, here, and I sort of wish I had started looking at the parallel port version of this software before the USB version.  That being said, there are much better tools available for capturing and analyzing USB traffic, and I don’t even have a parallel port!

Windows client

The thing has a Windows client — if you’d like, you can download a free “demo” copy from here, or more specifically, here. As with the Infectus software analysis I did, I used three tools:

  • IDA Pro, to analyze the executable — this proved to be less helpful this time than I had hoped
  • SniffUsb (inside VMWare Fusion) — there are several free / open-source programs that do similar things with similar names; This version is the one that has worked best for me.
  • usbsnoop2libusb.pl — this amazing perl script will take the output from the above program and make it into a C program that uses libusb to replay the transactions back to the device. I didn’t use it for that, directly, but it’s a nice base to use to develop code to filter the above output into something more readable.

All of the interesting bits are contained in a set of “resource files” (*.rez) that are unpacked by the installer alongside the main executable. It’s a binary container format, which was annoying to deal with — rather than try to explain the exact format, I refer you to the ugly Python script I cranked out to try to make some sense of it. The USB dumps ended up playing a critical role in understanding the binary file format, because I was able to modify the binary .rez file and observe the change in the data sent over USB.

First, we have a file containing a list of all supported devices (lots and lots and lots!) Here’s an annotated excerpt:

TDevPool: 02a9 07f8 001b 00 00ec 0076 00 001f 01 02 K9F1208U0A *48TS
TDevPool: 02ba 07f8 001b 00 00ec 0076 00 001f 01 02 K9F1208U0B *48TS
TDevPool: 02cb 07f8 0018 00 00ec 0073 00 001f 01 02 K9F2808U0B *48TS
TDevPool: 02dc 07f8 0018 00 00ec 0073 00 001f 01 02 K9F2808U0C *48TS
TDevPool: 02ed 07f8 001a 00 00ec 0075 00 001f 01 02 K9F5608U0B *48TS
TDevPool: 02fe 07f8 001a 00 00ec 0075 00 001f 01 02 K9F5608U0C *48TS
TDevPool: 030f 07f8 0017 00 00ec 00e6 00 006c 01 02 K9F6408U0A *44TS
TDevPool: 0320 07f8 0017 00 00ec 00e6 00 006c 01 02 K9F6408U0B *44TS
TDevPool: 0331 07f8 0017 00 00ec 00e6 00 006c 01 02 K9F6408U0C *44TS

In order, the fields are table_index, device_class, device_type, ?, vendor ID, chip ID, ?, ?, ?, ?, chip name, adapter name. device_class is looked up in a table inside the executable, which gives a class of “TXPMemDev” and a corresponding resource file of “GDBA____.rez”.

I now draw your attention to my partially-decoded version of GDBA___.rez.

Let’s take a specific example from that file:

D1b: TXPMemDev: famcode=0013 pinmap=000c 0000 ff 04200000 08 00 00 00 20 04 00 42 00 00 04200000

D1b corresponds to the device_type in the device list. 0x04200000 is the size of the chip — it’s a 64MB small-block NAND flash chip. 000c tells us which pinmap to use:

Pc: TPinCode: 48 pins,
00000000  04 09 00 02 00 02 00 18  2f 01 00 04 00 00 17 19
00000010  29 06 00 08 00 10 11 12  13 1c 1d 1e 1f 03 00 1d
00000020  00 01 02 07 08 09 0a 0b  0c 0d 0e 0f 14 15 16 19
00000030  1a 1b 20 21 22 23 24 25  26 27 28 29 2d 2e 04 00
00000040  03 00 01 00 04 00 0e 00  05 00 0f 00 06 00 0b 00
00000050  18 00 07 00 2a 00 08 00  2b 00 03 00 2c 00 0c 00
00000060  2f 00

(I don’t know anything more about the format of this entry)

We also know which “TFamCode” to use:

M13: TFamCode: 0c
0000 002b _FUN_POWERON
0001 0033 _FUN_POWEROFF
0002 002d _FUN_DEVINIT
0003 0031 _FUN_DEVRESET
0004 002e _FUN_GETID
000a 0030 _FUN_ERASE
0017 0039 _FUN_DNLDERASE
0014 003a _FUN_DNLDPROG
0011 003b _FUN_DNLDREAD
001b 003f _FUN_XC3030Data

Here, we’re getting closer to something usable. The first column is an index into a list of functions (you can find it elsewhere in the file) — I’ve decoded it to put the function name on the right. This tells us what “WaveCode” we need to use.


I’m assuming that “Wave” here is short for “Waveform”, meaning that these blobs tell the device how to generate the signals which need to be applied to each pin.  There are three types:

Type 0: Bytecode

0000 002b _FUN_POWERON
W2b: TWaveCode: type = 0 data = 
00000000  30 00 12 00 02 33 01 11  0f 00 11 04 00 11 01 00
00000010  03 0b 00 0b 0c 01 00 00  02 01 00 3b c0 3b ff 34
00000020  0f 11 03 01 11 08 01 11  0e 01 11 0f 01 32 40 0d
00000030  03 00 

In my notes, I have this down as being some sort of interpreted bytecode, run on a statemachine inside the Windows program. Looking at it with fresh eyes and comparing it to the USB traffic, it may just be a list of 80C32 commands. Something that immediately stands out here is the ‘ff’ at 0x1e — that’s the RESET code in the NAND command set.

Type 4: FPGA Bitstream

001b 003f _FUN_XC3030Data
W3f: TWaveCode: type = 4 data = 
00000000  da 0a ff 04 a0 36 f9 fc  ff ff ff ff ff ff ff ff
00000010  ff ff ef f7 f7 f7 f7 f7  ef ef ef ef ef fe e6 fe
00000020  fe fe fe fe fd fd fd fd  f5 cf ff ff ff ff ff fe
00000ad0  ff ff ff ff df ff ff ff  bf bf ff ff

This bitstream is sent before anything else is done with the chip. It’s really the code to which the 80C32 talks, and it’s what actually drives the pins on the flash chip.

Type 6: 80C32 code

0011 003b _FUN_DNLDREAD
W3b: TWaveCode: type = 6 (805x) len1 = 0189 addr=6000 len2 = 0185 data = 
00000000  90 f0 00 75 a0 c8 20 b2  fd 30 b5 03 02 61 23 75
00000010  a0 d8 e2 fc 54 f0 70 07  90 60 58 ec 23 23 73 ec
00000020  c3 94 7f 50 2c 75 e0 00  c0 e0 75 e0 60 c0 e0 90
00000180  d2 97 02 60 06

This code is uploaded to the 80C32’s attached SRAM chip at address 0x6000; it is then executed. We can disassemble this code to see how it works, and I ended up doing so to modify it, but we’ll get to that in the next article.

I can post some annotated USB logs, if there’s interest.

Tags: Wii

5 responses so far ↓

  • 1 emailtoid.net/i/515e4d82/… // Feb 12, 2009 at 9:33 am

    I don’t think enough people appreciate this reverse engineering stuff (as seen by the number of comments on the wii stuff and lack of comments on this stuff), but I’ve always found reverse engineering interesting. In undergrad a did a fair amount of reverse engineering/disassembling code for chips such as a Cypress USB chip (not the same one and it was controlled from an ARM chip). Keep up the good work, this stuff is interesting.


  • 2 HyperHacker // Feb 12, 2009 at 5:46 pm

    What kind of hardware hacker doesn’t have a parallel port? :-p

    Seriously though, did you find out what was wrong with it?

  • 3 officialjunk // Feb 12, 2009 at 10:56 pm

    wow. you make me want to go back to grad in electrical engineering. such an interesting read. keep it up. o and please share the annotated usb logs; why not?

    what are your fav. text books, bushing?

  • 4 otaku_tta // Feb 23, 2009 at 3:47 am

    Nice work so far.. 🙂
    I’ve very recently started to play with my UP48f ( the cheapo clone ). Much simpler hardware design, still ezUSB based.. Its irritating to know the device is capable of dumping a flash, but the manufacturers would rather you bought a newer model and so wont update the sw… :/

  • 5 whitegoose // Feb 24, 2009 at 7:38 am

    ive got a unit that appears to be similar.

    i have the dataman 48xp. they made a LV and a UXP version as well, the UXP basically being the same as i have but USB instead of parallel port communication.

    i use it for programming chips for my works press controllers.

You must log in to post a comment.