Hacking the Wii U Gamepad
Hacking the Wii U Gamepad
This is a bit of an old project of mine. I've first made attempts in 2016, but I was not very successful at the time.
The basic idea is to run custom code on the Wii U gamepad. People managed to connect the gamepad to a PC and feed their own video feed into it, but this is one step further. The gamepad runs off an ARM9 CPU, so it is technically possible to have it run as a standalone device, not connected to a Wii U or a PC or anything. I've always thought that doing so would be nifty.
The tricky part is actually getting code onto the gamepad. The "normal" way would be to send code over wifi, like the Wii U does. But that will only work if the gamepad is already running a functional firmware, so that excludes any sort of testing and reverse-engineering work.
The gamepad firmware is stored in a 32MB SPI Flash memory. On this picture of the gamepad motherboard, the Flash is marked in orange.
On the other side of the motherboard, we find a bunch of test points. I marked those that relate to the SPI bus.
CS0 is the chipselect line for the Flash. I also added UIC CS, which is the chipselect line for the UIC (auxiliary microcontroller that is also connected to the SPI bus).
The RESET line isn't very interesting. It is a simple reset circuit just for the Flash chip, and isn't controlled by the other hardware.
My original attempts at using these test points for some sort of in-situ access to the Flash chip were unsuccessful. You have to remove the Flash chip from the motherboard to access it, which isn't terribly convenient, especially as the Flash sits under the motherboard when it is installed in the gamepad. I made other attempts with breakout connectors that allowed me to unplug the Flash and reprogram it separately, but they weren't super reliable.
It also didn't help that I was largely blind at the time. Not being able to turn on the screen, all I could use as output was the rumble GPIO. So I couldn't really debug stuff.
This year, I wanted to give it a try again, but with better equipment.
I'm using a FPGA board to emulate the Flash. Makes it a lot easier to upload code to the gamepad.
This project was based off spispy, but I ended up building my own from the ground up. I ran into several issues with spispy, one of them being the speed of the gamepad's SPI bus. The first stage bootloader runs it at 16MHz, but past that it goes up to 48MHz, and spispy can't keep up with that.
I'm not yet able to run the stock firmware off the Flash emulator, I don't know why -- I know the second stage bootloader is reading the firmware header correctly, so I know that my design is able to keep up with the 48MHz clock. There might be a stupid bug somewhere...
But so far it has proven reliable enough to run custom code by replacing the second stage bootloader. And as soon as I was able to get working SPI code on the gamepad, it proved very useful to debugging -- I added a special log command to the FPGA design that just forwards data to my computer, and thus I was able to have a far better output than just toggling the rumble GPIO.
Next step was actually managing to display something on the gamepad's screen. The gamepad is nothing like, say, the DS, where the video hardware "just works" and you can display stuff after some very basic initialization. Here, displaying something is a whole ordeal. You have to talk to the LCD over I2C to initialize it, then set up the video hardware correctly for it to actually output something, and talk to the UIC over SPI to turn on the backlight. So far, I was stuck on the first step...
But with the FPGA debug line, I was able to finally get I2C comm working.
That's the LCD ID -- my gamepad has a JDI LCD (08922201). There's another possible ID in the firmware code for a Panasonic LCD (00000002).
Getting the video setup right proved challenging, but eventually I got there too.
Finally.
My next goal from there is to figure out how to sync to VBlank. Then try figuring out more of the hardware. Since we have UIC comm working, input should be a mostly solved problem. The rest will require more work.
I'd like to get wifi working -- then I could have a simple bootloader that would support loading custom binaries over wifi.
I'd also like to dump the first stage bootloader, but it seems to be protected in some way -- I tried reading at 0xFFFF0000 and it's just zero.
The basic idea is to run custom code on the Wii U gamepad. People managed to connect the gamepad to a PC and feed their own video feed into it, but this is one step further. The gamepad runs off an ARM9 CPU, so it is technically possible to have it run as a standalone device, not connected to a Wii U or a PC or anything. I've always thought that doing so would be nifty.
The tricky part is actually getting code onto the gamepad. The "normal" way would be to send code over wifi, like the Wii U does. But that will only work if the gamepad is already running a functional firmware, so that excludes any sort of testing and reverse-engineering work.
The gamepad firmware is stored in a 32MB SPI Flash memory. On this picture of the gamepad motherboard, the Flash is marked in orange.
On the other side of the motherboard, we find a bunch of test points. I marked those that relate to the SPI bus.
CS0 is the chipselect line for the Flash. I also added UIC CS, which is the chipselect line for the UIC (auxiliary microcontroller that is also connected to the SPI bus).
The RESET line isn't very interesting. It is a simple reset circuit just for the Flash chip, and isn't controlled by the other hardware.
My original attempts at using these test points for some sort of in-situ access to the Flash chip were unsuccessful. You have to remove the Flash chip from the motherboard to access it, which isn't terribly convenient, especially as the Flash sits under the motherboard when it is installed in the gamepad. I made other attempts with breakout connectors that allowed me to unplug the Flash and reprogram it separately, but they weren't super reliable.
It also didn't help that I was largely blind at the time. Not being able to turn on the screen, all I could use as output was the rumble GPIO. So I couldn't really debug stuff.
This year, I wanted to give it a try again, but with better equipment.
I'm using a FPGA board to emulate the Flash. Makes it a lot easier to upload code to the gamepad.
This project was based off spispy, but I ended up building my own from the ground up. I ran into several issues with spispy, one of them being the speed of the gamepad's SPI bus. The first stage bootloader runs it at 16MHz, but past that it goes up to 48MHz, and spispy can't keep up with that.
I'm not yet able to run the stock firmware off the Flash emulator, I don't know why -- I know the second stage bootloader is reading the firmware header correctly, so I know that my design is able to keep up with the 48MHz clock. There might be a stupid bug somewhere...
But so far it has proven reliable enough to run custom code by replacing the second stage bootloader. And as soon as I was able to get working SPI code on the gamepad, it proved very useful to debugging -- I added a special log command to the FPGA design that just forwards data to my computer, and thus I was able to have a far better output than just toggling the rumble GPIO.
Next step was actually managing to display something on the gamepad's screen. The gamepad is nothing like, say, the DS, where the video hardware "just works" and you can display stuff after some very basic initialization. Here, displaying something is a whole ordeal. You have to talk to the LCD over I2C to initialize it, then set up the video hardware correctly for it to actually output something, and talk to the UIC over SPI to turn on the backlight. So far, I was stuck on the first step...
But with the FPGA debug line, I was able to finally get I2C comm working.
That's the LCD ID -- my gamepad has a JDI LCD (08922201). There's another possible ID in the firmware code for a Panasonic LCD (00000002).
Getting the video setup right proved challenging, but eventually I got there too.
Finally.
My next goal from there is to figure out how to sync to VBlank. Then try figuring out more of the hardware. Since we have UIC comm working, input should be a mostly solved problem. The rest will require more work.
I'd like to get wifi working -- then I could have a simple bootloader that would support loading custom binaries over wifi.
I'd also like to dump the first stage bootloader, but it seems to be protected in some way -- I tried reading at 0xFFFF0000 and it's just zero.
- Hojo_Norem
- Posts: 145
- Joined: Mon Apr 16, 2007 10:07 am
- Contact:
Re: Hacking the Wii U Gamepad
It's good to see somebody with the skills and knowhow taking an interest in the Wii U gamepad. I can't really see my Wii U ever being plugged in again, seeing that Cemu does 100% of what my Wii U did... Play BotW and Smash. If making the gamepad more PC friendly breaks it's Wii U compatibility I won't complain.
My guess is that if a reasonably easy way of getting unsigned code to run on the entire unit (there's three SoCs in there if I'm not mistaken) then the next step would be convincing the wifi hardware to connect to standard networks, rather than needing a USB wifi adapter with a specific chipset and running a patched linux kernel. That being said, the libDRC website is still running and it's bitbucket repository still exists if that's of any help.
My guess is that if a reasonably easy way of getting unsigned code to run on the entire unit (there's three SoCs in there if I'm not mistaken) then the next step would be convincing the wifi hardware to connect to standard networks, rather than needing a USB wifi adapter with a specific chipset and running a patched linux kernel. That being said, the libDRC website is still running and it's bitbucket repository still exists if that's of any help.
Insert witty sig. here...
Re: Hacking the Wii U Gamepad
Did you stop the cpu from accessing the spi bus before injecting your spi read/write commands, like by holding the cpu in reset state? That's usually working best if the board is in a state where all spi pins are high.
Does that fpga circuit emulate the spi chip id, and the 4bit bus quad spi mode?
The mainboard looks quite like a 3ds/2ds console, and the i2c display init also sounds 3ds-style. I guess there are many mord similarities, and the wifi unit is also using atheros chips, like those on dsi and 3ds?
Does that fpga circuit emulate the spi chip id, and the 4bit bus quad spi mode?
The mainboard looks quite like a 3ds/2ds console, and the i2c display init also sounds 3ds-style. I guess there are many mord similarities, and the wifi unit is also using atheros chips, like those on dsi and 3ds?
Re: Hacking the Wii U Gamepad
That would be a neat idea, yeah. Ironically, there isn't really a concept of "unsigned" code here, because the gamepad doesn't have any security -- it will happily run whatever you throw at it. No signing or encryption. The main entry barrier is the lack of convenient ways to upload code.Hojo_Norem wrote: ↑Fri Sep 20, 2024 11:10 am My guess is that if a reasonably easy way of getting unsigned code to run on the entire unit (there's three SoCs in there if I'm not mistaken) then the next step would be convincing the wifi hardware to connect to standard networks, rather than needing a USB wifi adapter with a specific chipset and running a patched linux kernel. That being said, the libDRC website is still running and it's bitbucket repository still exists if that's of any help.
I don't need to do any of that -- the FPGA board has a separate interface (serial over USB) connecting it to the computer. That interface allows direct access to the FPGA's SDRAM, which is where the emulated Flash contents are stored. (edit- reminds me that it would be handy to add commands to turn the gamepad on/off by controlling a relay or whatever on the power input)nocash wrote: ↑Fri Sep 20, 2024 4:25 pm Did you stop the cpu from accessing the spi bus before injecting your spi read/write commands, like by holding the cpu in reset state? That's usually working best if the board is in a state where all spi pins are high.
Does that fpga circuit emulate the spi chip id, and the 4bit bus quad spi mode?
The mainboard looks quite like a 3ds/2ds console, and the i2c display init also sounds 3ds-style. I guess there are many mord similarities, and the wifi unit is also using atheros chips, like those on dsi and 3ds?
It doesn't emulate either of these things. Chip ID command would be trivial to add. Dual/quad SPI would be more involved, but probably doable -- I didn't think of it at all because the gamepad doesn't support these modes. Do you have other uses in mind that would require them?
The wifi chip is actually a Broadcom chip. It apparently runs almost stock firmware, too. I don't know yet how much other similarities there could be to 3DS/2DS hardware...
Re: Hacking the Wii U Gamepad
Yeah, I meant when accessing the spi chip directly, without needing to desolder or replace by an fpga board.
No, I just saw the 25q256 chip, and thought that missing quad-spi support could explain why you can't boot the retail firmware from fpga.Arisotura wrote: ↑Sat Sep 21, 2024 1:23 am It doesn't emulate either of these things. Chip ID command would be trivial to add. Dual/quad SPI would be more involved, but probably doable -- I didn't think of it at all because the gamepad doesn't support these modes. Do you have other uses in mind that would require them?
The 3DS supports both 1bit and 4bit spi bus (if the gamepad should happen to support that, too, then it might load a bootstub in 1bit mode, and then switch to 4bit mode for the main boot process).
Okay, then wifi is perhaps easier to access than dsi/3ds wifi.
For similarities, the bga chips and cryptic TP test point numbering and spi/i2c buses did remind me of 3DS.
The bootrom, if it's read-protected, could be also similar, although one can usually access at least parts of the FFFFxxxxh or 0000xxxxh memory regions.
Re: Hacking the Wii U Gamepad
Oh, I misunderstood then! I did remove the original Flash chip from the motherboard. Otherwise it would interfere with the FPGA board.
As for 4-bit SPI mode, I haven't seen any commands that would enable that (or even anything other than 1-bit mode). I think the required pins aren't even connected to anything on the motherboard.
As far as I've seen, the boot ROM isn't readable at all. The region seems to just read as zero.
It isn't even needed at all for normal operation, unlike the BIOSes on the DS for example. The exception vectors are at address 0 in main RAM.
Fun related thing I observed, it seems that trying to read from NULL causes the gamepad to shut down, even with the MPU off.
As far as the boot ROM is concerned, it's probably either locked out before jumping to the second stage bootloader, or it's only readable when the ARM9 is running code within the region. In the former case, some kind of glitching attack might help bypass that, but in the latter case, I'm not sure. TCMs might be abused to bypass it, but as far as I've seen, the ARM9 in the gamepad doesn't have TCMs.
As for 4-bit SPI mode, I haven't seen any commands that would enable that (or even anything other than 1-bit mode). I think the required pins aren't even connected to anything on the motherboard.
As far as I've seen, the boot ROM isn't readable at all. The region seems to just read as zero.
It isn't even needed at all for normal operation, unlike the BIOSes on the DS for example. The exception vectors are at address 0 in main RAM.
Fun related thing I observed, it seems that trying to read from NULL causes the gamepad to shut down, even with the MPU off.
As far as the boot ROM is concerned, it's probably either locked out before jumping to the second stage bootloader, or it's only readable when the ARM9 is running code within the region. In the former case, some kind of glitching attack might help bypass that, but in the latter case, I'm not sure. TCMs might be abused to bypass it, but as far as I've seen, the ARM9 in the gamepad doesn't have TCMs.
Re: Hacking the Wii U Gamepad
The required pins for 4bit spi should be pin 1 and 9, but pin 1 seems to be shortcut with pin 2 on the photo, so, yes, no 4bit mode. There's also a 2bit mode though, which doesn't require extra pins.
If the exception vectors are at 0 then the bootrom may have been there, too, and they might have just switched the memory mapping rom to ram, without actually intending to hide it from dumpers.
If the exception vectors are at 0 then the bootrom may have been there, too, and they might have just switched the memory mapping rom to ram, without actually intending to hide it from dumpers.
Re: Hacking the Wii U Gamepad
re: bootROM -- possibly. I guess it would depend on whether the ARM9 is guaranteed to start with high exception vectors or if that can be implementation-defined.
Edit- it's implementation defined. However, there's a problem: when loading the second stage bootloader from the Flash, the first stage bootloader will load the exception vectors at address 0, and the rest at address 0x3F0000. If the bootloader itself lived at 0, it would be overwriting itself, unless there are some weird hardware shenanigans going on. But I did try reading around that region and whatever I got there was from the second stage bootloader, probably happening to stay there because the RAM doesn't get cleared upon boot.
Edit- it's implementation defined. However, there's a problem: when loading the second stage bootloader from the Flash, the first stage bootloader will load the exception vectors at address 0, and the rest at address 0x3F0000. If the bootloader itself lived at 0, it would be overwriting itself, unless there are some weird hardware shenanigans going on. But I did try reading around that region and whatever I got there was from the second stage bootloader, probably happening to stay there because the RAM doesn't get cleared upon boot.
Re: Hacking the Wii U Gamepad
Status update!
I got the stock firmware working off my FPGA Flash emulator.
There were signal integrity issues, where the data I was sending was somehow arriving too early after a while. Adding 22ohm resistors to the clock/MISO/MOSI lines fixed it, however.
Then I ran into a stupid issue that I'd caused while changing some things in my design a while back, so that wasn't hard to fix.
Then I had to add the chip ID command. Not hard either, although it reminded me why you don't try to code after partying and drinking
After that, all I was getting was a solid gray screen... was time for me to go to bed.
This morning, I tried uploading a full Flash dump to my emulator instead of doing the partial upload I was doing. And, lo and behold, it worked! So it seems that my design works quite well in the end, but I'd need to do more research into which parts of the Flash are used and for what.
The only thing that is really missing from the emulator at this point is write commands. I don't think they would be very hard to add, but I hope the added complexity doesn't end up breaking things.
Either way I'm happy to see that my design works fine with the 48MHz SPI clock. I had spent a lot of time researching it and trying to ascertain whether it would be feasible at all, and the timings are tight at such a speed. And you know how it is, from theory to practice...
On the reverse-engineering front, I finally figured out how to sync to VBlank, so that's nice too. I have an old hardware documentation if that's of any interest, but we're putting up a small wiki for a nicer documentation.
I also plan to put up my stuff on Github, when it's in a bit of a cleaner state.
I got the stock firmware working off my FPGA Flash emulator.
There were signal integrity issues, where the data I was sending was somehow arriving too early after a while. Adding 22ohm resistors to the clock/MISO/MOSI lines fixed it, however.
Then I ran into a stupid issue that I'd caused while changing some things in my design a while back, so that wasn't hard to fix.
Then I had to add the chip ID command. Not hard either, although it reminded me why you don't try to code after partying and drinking

After that, all I was getting was a solid gray screen... was time for me to go to bed.
This morning, I tried uploading a full Flash dump to my emulator instead of doing the partial upload I was doing. And, lo and behold, it worked! So it seems that my design works quite well in the end, but I'd need to do more research into which parts of the Flash are used and for what.
The only thing that is really missing from the emulator at this point is write commands. I don't think they would be very hard to add, but I hope the added complexity doesn't end up breaking things.
Either way I'm happy to see that my design works fine with the 48MHz SPI clock. I had spent a lot of time researching it and trying to ascertain whether it would be feasible at all, and the timings are tight at such a speed. And you know how it is, from theory to practice...
On the reverse-engineering front, I finally figured out how to sync to VBlank, so that's nice too. I have an old hardware documentation if that's of any interest, but we're putting up a small wiki for a nicer documentation.
I also plan to put up my stuff on Github, when it's in a bit of a cleaner state.
Re: Hacking the Wii U Gamepad
Hmm, the resistors sound a little bit like a hack. At 48 MHz i would try to keep all lines very short and try to length match them. Maybe you can also fix it by changing the slew rate settings on the FPGA side.
Re: Hacking the Wii U Gamepad
It's one way to alleviate ringing problems. And as long as it works for me, well. This FPGA contraption isn't meant to be production-ready, it's mostly just a way for me to upload code to the gamepad and reverse-engineer it.
I already did my best to keep the lines short...
I also have the slew rate setting set to slow already.
I already did my best to keep the lines short...
I also have the slew rate setting set to slow already.
Re: Hacking the Wii U Gamepad
Famous last words.
Just send command 0x07 to the UIC, right?
Except the UIC has a notion of states. It only polls input when in certain states. On power-up, the UIC starts in state 11, and of course, it doesn't poll input in that state -- it's pretty much an idle "do nothing" state.
There's a command to switch the UIC to another state, but there are only specific transitions that are allowed. When the UIC is in state 11, you're supposed to put it in state 3 or 4, which puts the gamepad to sleep. Then pressing the power button wakes it up and the UIC starts in state 0, and finally you can receive input data.
Now, I'm working on DMA. The DMA engine can do such things as a masked fill operation, where it fills memory with either one value or another based on a mask. Fun shit. I still wonder if it can do blitting with keying/transparency. Either way, the DMA engine is very fast -- a DMA fill is 80 times faster than a byte-based fill loop, and 20 times faster than a word-based fill loop.
I put up my experimental code on Github: https://github.com/Arisotura/melonpad
- Hojo_Norem
- Posts: 145
- Joined: Mon Apr 16, 2007 10:07 am
- Contact:
Re: Hacking the Wii U Gamepad
Just read the bit about figuring out how to add a SD card on your GitHub. Got me thinking... Is the Gamepad's SPI bus viable? We'd need to figure out a CE line for the card. That would require that we can get access to a unused GPIO from somewhere. If that isn't possible then we may have another way.
According to the documentation that you've linked in your GitHub, the SPI system can be made to enable both the flash and UIC at the same time. Now normally you wouldn't want this but if we lift the enables for the UIC and flash and feed them into a suitable 2-to-4 decoder we can make 4 enable lines from the two, wired in such a way that the flash and UIC are enabled when their original lines go active and the SD card is enabled when both lines go active.
I had a quick look, there are a few manufactures who make single gate 2-to-4 decoder ICs in 'human solderable' surface mount packages.
Now, an idea has just struck me but only if the first stage bootloader can tolerate different flash chips. Now, more than likely a small PCB will have to be designed for the SD card and decoder IC right? Change the single decoder to a dual decoder, feed the decoded flash enable signal from the first decoder into the second decoder along with the SD card slot's 'card present' switch signal to select between the original flash when there's no card inserted and the secondary flash that's holding the custom firmware when the card is inserted.
According to the documentation that you've linked in your GitHub, the SPI system can be made to enable both the flash and UIC at the same time. Now normally you wouldn't want this but if we lift the enables for the UIC and flash and feed them into a suitable 2-to-4 decoder we can make 4 enable lines from the two, wired in such a way that the flash and UIC are enabled when their original lines go active and the SD card is enabled when both lines go active.
I had a quick look, there are a few manufactures who make single gate 2-to-4 decoder ICs in 'human solderable' surface mount packages.
Now, an idea has just struck me but only if the first stage bootloader can tolerate different flash chips. Now, more than likely a small PCB will have to be designed for the SD card and decoder IC right? Change the single decoder to a dual decoder, feed the decoded flash enable signal from the first decoder into the second decoder along with the SD card slot's 'card present' switch signal to select between the original flash when there's no card inserted and the secondary flash that's holding the custom firmware when the card is inserted.
Insert witty sig. here...
Re: Hacking the Wii U Gamepad
The SPI bus would certainly be a good avenue for a SD card interface. It is accessible via test points, so one might design a custom board or ribbon thing that mates with the required points.
The problem is, as you said, needing an extra chipselect line for the SD card.
The decoder solution could certainly work... Just, one problem with that is the kind of modifications to the circuit it would require. While the Flash is a rather human solderable format, the UIC is a finer pitch, so working on an individual pin of it would be pretty tricky.
There's also the problem of how to detect the presence of such a mod. On a stock gamepad, activating both chipselect lines would just activate the Flash and the UIC at the same time, which is at best not very useful, and at worst might cause shorts if the two try to output different values.
My other idea involved I2C... The expansion connector is an I2C bus, so one could design a SD card adapter that would connect there, leaving the gamepad itself unmodified. The advantage of I2C is that adding a device to the bus can be done by just giving it an address that no other device is using, which makes it less invasive.
A downside is that it would be slow for a SD card interface. The I2C bus in the expansion connector is said to run at 1MHz. It also goes through the UIC, so not sure how fast that would all be.
(edit- actually seems that the UIC sets up the I2C bus at a speed of 16MHz? I will have to confirm that tomorrow)
Alternatively, there's the other I2C bus, the one that is directly connected to the CPU. No idea how fast that one is, or where to find it on the mainboard.
The problem is, as you said, needing an extra chipselect line for the SD card.
The decoder solution could certainly work... Just, one problem with that is the kind of modifications to the circuit it would require. While the Flash is a rather human solderable format, the UIC is a finer pitch, so working on an individual pin of it would be pretty tricky.
There's also the problem of how to detect the presence of such a mod. On a stock gamepad, activating both chipselect lines would just activate the Flash and the UIC at the same time, which is at best not very useful, and at worst might cause shorts if the two try to output different values.
My other idea involved I2C... The expansion connector is an I2C bus, so one could design a SD card adapter that would connect there, leaving the gamepad itself unmodified. The advantage of I2C is that adding a device to the bus can be done by just giving it an address that no other device is using, which makes it less invasive.
A downside is that it would be slow for a SD card interface. The I2C bus in the expansion connector is said to run at 1MHz. It also goes through the UIC, so not sure how fast that would all be.
(edit- actually seems that the UIC sets up the I2C bus at a speed of 16MHz? I will have to confirm that tomorrow)
Alternatively, there's the other I2C bus, the one that is directly connected to the CPU. No idea how fast that one is, or where to find it on the mainboard.
Re: Hacking the Wii U Gamepad
Is there SDIO? If so then that would be my choice. Far faster than both SPI and I2C. You can multiplex SDIO by only routing the clock signal to one device at a time and wiring the other signals to both. They won't interfere as long as they are idle. This however has the same issue as the SPI solution. You need a free GPIO or other mechanism to switch the clock between both.