top of page

Boot process

  • BOOTROM

Triggering the power button on the Wii starts the WODE and runs the MCU BOOTROM.

​

Depending on the pin settings of GPIO0, GPIO1 and GPIO2 and their state (which are set to "INPUT" mode), the BOOTROM can (for ex.) run either these modes:

​

  • SPI-NOR flash (default on the WODE)

  • USB-DFU (used for unbricking after a bad firmware update / binaries are encrypted using TEA)

  • UART (only supports booting of encrypted images because the OTP area's AES bits have been factory-pre-programmed)

  • SD/MMC (most likely ONLY supports booting encrypted images because of factory-programmed OTP)

​

At first, the BOOTROM copies a hard-coded AES initialization vector and the AES-key stored in OTP, into the NAND-Controller AES initialization vector array and AES-key array. Then it does a memory pattern test on the ISRAM area.

 

After that, the BOOTROM checks the boot mode by determining the pin state of GPIO0, GPIO1 and GPIO2. While GPIO2 is "HIGH" on the WODE, GPIO0 and GPIO1 are both "LOW" - causing it to boot from SPI in the end.

​

The BOOTROM also checks the validity of the AES-key fields in OTP. If they are valid, it does this:

​

  • enable "AES-from-AHB" mode

  • copy the very first encrypted 0x200 bytes block of data stored in the SPI-NOR flash into the NAND-Controller's RAM0 area

  • enable the hardware AES crypto module for decryption

  • copy the decrypted data from the NAND-Controller's RAM0 area into the ISRAM area

  • disable "AES-from-AHB" mode

  • check the header data for magic word ("imgA") in ISRAM

  • check the header data image size (0x1C600 bytes for the whole WODE "RETAIL" bootloader) in ISRAM

​​

If decryption fails by checking the image header and a 160-bit SHA1 hash, the BOOTROM will hang and trigger GPIO2 HIGH and LOW for about 120 times (seconds) - after that, it triggers GPIO2 HIGH infinitely.

 

In any other case it repeats copy, decrypt and copy until the whole image is decrypted and loaded into ISRAM, then does hash-check the whole image using 160-bit SHA1.

​

If decryption of the whole image is done, it disables and invalidates the caches, writes to the MCU control registers, disables the MMU and then jumps to the decrypted bootloader located in ISRAM, starting U-Boot.

  • Bootloader *

When U-Boot on the WODE starts, it does a basic board setup like initializing clocks and SDRAM, setting up GPIO0, GPIO1 and GPIO2 as "INPUT", initialize UART, MCI and TIMER as well as a very basic environment ("bootargs=quiet", "bootdelay=5" and "baudrate=115200").

​

After that, it runs into an autoboot mode which completely disables the possibility of interrupting the whole boot process and it first sets the READ-PROTECTION bit on the OTP READ-PROT area.

​

Then it initializes the WODE's LCD screen and loads the BOOT screen from SPI-NOR flash **** and prints it to the LCD.

​

Then it reads the WODE's main configuration from the SPI-NOR flash and copies it into the SDRAM which are the U-Boot version installed (usually and most likely v1.01), Linux Kernel version, FPGA version and hardware version. If these are set to "0xFF" within the SPI-NOR flash, it will write **** these version values to 0x01 and finally issue a reset of the MCU.

​

After that it initializes the MCI (memory card interface) and checks if there's a FAT32 formatted SD-Card inserted. If so, it tries to detect a firmware update binary (file "update.bin") and reads the header, comparing the first 4 magic bytes ("WODE") and the CRC of the update binary using a CRC table.

 

Then it checks the versions installed within the SPI-NOR flash and compares them with those located in the update binary. If the values within the SPI-NOR flash are lower than those within the update, it will trigger the update process for this particular section, overwriting the corresponding section in the SPI-NOR flash. If there also is an update for the Actel ProAsic3, it will program the new firmware for it using the DirectC driver within the U-Boot binary.

​

After the update process is done, it resets the MCU and skips the whole update process, setting the READ-PROTECTION-BIT on OTP a second time.

​

If this is done, it reads the encrypted Linux Kernel off the SPI-NOR flash into the NAND-Controller RAM0 area (0x200 bytes block-by-block) in a similar way the BOOTROM does with the bootloader itself - though, U-Boot uses a different AES encryption key and AES initialization vector for decrypting the Linux Kernel which both are hard-coded into the U-Boot binary. **

​

Decrypting the Linux Kernel ("RETAIL") is basically done like this:

​

  • preconfigure the NAND-Controller struct data with the required AES initialization vector and AES-key

  • copy the preconfigured NAND-Controller struct data into the NAND-Controller area

  • enable "AES-from-AHB" mode

  • copy the Linux Kernel's first encrypted 0x200 bytes block of data stored in the SPI-NOR flash into the NAND-Controller RAM0 area using DMA

  • set NAND-Controller mode to "AES done for areas RAM0 and RAM1"

  • enable the hardware AES crypto module for decryption

  • loop until it receives an "AES decryption done" command

  • set NAND-Controller mode to "AES done for area RAM0"

  • copy the decrypted data from the NAND-Controller's RAM0 area into the SDRAM area using DMA

  • repeat copy, decrypt and copy until the whole image is decrypted and loaded into SDRAM​

​

It will then check the decrypted Kernel's magic bytes as well as the CRC, disable and flush the caches before finally jumping to offset 0x30008000 within SDRAM, actually starting the Linux Kernel.

​

* - Depending on the version installed ("RETAIL" vs. "OPENWODE"), U-Boot of the "OPENWODE" binary has the whole UART driver included and is able to display boot messages to the terminal. When it comes to setting the READ-PROTECTION bit on OTP, the "OPENWODE" binary only sets it 1 time: right before jumping to the decrypted Linux Kernel instead of 2 times in the "RETAIL" binary. It also supports loading own Linux Kernel binaries off a FAT32 formatted SD-Card ***, providing a file called "uImage" without a file extension.

​

** - The "OPENWODE" binary doesn't do firmware decryption on the Linux Kernel at all as it's supposed to be fully decrypted in the first place which allows users to boot their own Linux Kernels.

​

*** - This can be used for actually hacking on the bootloader: The CDL (Common Driver Library) package for the MCU provides examples and tools for the creation of bootable binaries. "OPENWODE" doesn't need to run encrypted binaries at all.

​

**** - reading from and writing to the SPI-NOR flash is done using DMA within U-Boot

  • Linux Kernel *

The "RETAIL" Linux Kernel itself is based upon an old KAMIKAZE release of OpenWRT. It basically unpacks the internal CPIO-ROOT filesystem and runs into a BusyBox ** shell. It also autostarts an ELF binary called "WODE" *** which is actually responsible for all the internal interaction on the WODE. This is NOT the case for the "OPENWODE" binary. Instead, it is based on the "Backfire" Release 26317 of OpenWRT.

​

* - The Linux Kernel version used for the "RETAIL" version of the WODE is v2.6.29 while v2.6.32.27 was used in the "OPENWODE" for the source code.

​

** - The BusyBox version used for the "RETAIL" package is v1.11.3 while it's v1.15.3 for "OPENWODE".

​

*** - This is only the case for the "RETAIL" version of the WODE. The "OPENWODE" source code does NOT provide the source code to the "WODE" binary used for operation.

​

bottom of page