The Wii's security has been broken a few month ago by Team Twiizers and we are now able to run our self-written code on it. However, the IOS running on the co-processor Starlet currently still limits our abilities because it provides wrapper functions around most of the new hardware like the internal SD card slot, the disc drive and the USB ports.
Bushing and marcan figured out how to access the internal SD slot and I re-reverse enegineered it (basically to finally have a reason to learn some powerpc assembler) from the twilight hack and released some source code to do the required IOS calls.
So we're able to read data from the SD slot now but there is still more hardware that could be used to read data: The disc drive.
It can already be used to read data from any DVD when using a modchip in the Gamecube compatibility mode. So why isn't this possible in Wii mode right now?
The problem is that only Starlet has access to the DVD drive and provides a compatibility layer
in Gamecube mode (aka MIOS running on Starlet) that allows to read any data from the disc. They had to allow this because Gamecube games are - just like default DVDs - neither signed nor encrypted.
Wii discs however are encrypted with AES and signed with RSA so Starlet doesn't necessarily have to provide a similar layer - and it does not. It only provides a device node that allows unencrypted reads up to a certain offset (somewhere after the partition table). All data beyond this offset is encrypted and signed and can only be read after the signature check is passed. This signature check will defiantly fail on normal DVDs and we are therefore currently unable to read any data from a disc.
We sure could create a disc, encrypt it, calculate all needed hashes and the sign it by exploiting a bug - but that is a really nasty and annoying solution. DVDs are therefore a no-go unless we are able to run code on Starlet or find a function that allows raw reading of the whole DVD (ioctl code 0x8E is a candidate for this but I never looked at it and I'm not really interested in looking at it because it could also lead to piracy :/).
But if we need to have more data available on the Wii? If you for example want a media center for the Wii you defiantly don't want to copy your music (well... maybe that would be possible) and movies to SD cards and swap them around when you want to listen or watch something else. A possible solution would be to use the integrated wireless network card and stream the content from your PC but I don't want to boot my PC (no, I don't have a media server in my network :P) just to listen to some music or watch a movie.
Thankfully the Wii also has two USB slots that are ideal for this purpose: USB hard discs are really cheap today and can be used to store really much data. Libogc already has support for raw USB messages - the mass storage driver is the only thing missing.
There's one catch though why all those piracy kids can now stop reading and visit some other site: Only USB 1.1 is supported by the hardware so you're not going to be able to load your warez copies legal backups from the HDD. It's never going to be fast enough
The USB mass storage protocol itself is not very complicated after all once you understood it. The device basically provides two bulk endpoints through which it transfers all data. One of them is for receiving data from the host (i.e. the Wii) and the other one for sending data to it.
The protocol itself does however not specify how to tell the device what sector you want to read. It's just a wrapper around the real protocol implemented by most devices: SCSI multimedia commands.
To send a command to the device you have to go through the following procedure once it is in configured state:
Write a "Command Block Wrapper" (CBW) which contains the SCSI command and informations about the length of the data you want to transfer/receive to the OUT endpoint.
Read requested data from the IN endpoint, write the data to the OUT endpoint or do nothing here if no data except for the SCSI command is needed
Read a "Command Status Wrapper" (CSW) which tells you if you command succeeded from the IN endpoint.
Looks really simple, doesn't it?
To just read and/or write data you'll also only need three SCSI commands: One to read the capacity and sector size of the drive (READ_CAPACITY), one to read data (READ_10) and one to write data (WRITE_10).
Writing code to do this was not really difficult as you probably can imagine.
It only took me about one week because I though that the IOS did less than it actually does. Once a USB device gets connected to a host it normally starts the so-called enumeration process and should put the device in addressed state afterwards. Once a driver is selected for it then the driver reads all descriptors which contains informations about what protocols are supported. USB devices have support for more than one configuration but can only run one configuration. So the driver normally has to selected the configuration by issuing a SET CONFIGURATION control request. I wrote code to do exactly that and tried to debug why sending bulk messages always returned error code -7005. Well... after removing the whole "get-and-parse-descriptor" stuff and not issuing a SET CONFIGURATION request everything started to work. Knowing this before would've saved me a few hours of annoying debugging :/
After fixing that everything was ready for a first semi-public release in #wiidev even though three out of four sticks weren't working yet. The responses from some of the beta tester were quite similar: USBStorage_Open() failed when it tried to read the capacity of the device.
As I had no clue why this was happening I dumped the usb traffic of the usb-storage kernel module to see what was going differently there. I found the solution after looking at the dump for like five minutes:
While I was directly sending a READ CAPACITY command to the device the usb-storage (or rather the SCSI disk driver) was asking it nicely if it was ready yet (TEST UNIT) and read any errors if it was not (REQUEST SENSE). After adding this trivial change to my code all my sticks started to work.
The only last problem was that code has become a huge mess during the debugging sessions and so I decieded to rewrite it and upload it to my git. There is still some stuff missing like error handling but this should be enough for the beginning