Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Initial WFSI/WFSSRV implementation (+ some ES additions). #4632

Merged
merged 8 commits into from
Jan 14, 2017

Conversation

delroth
Copy link
Member

@delroth delroth commented Jan 8, 2017

This implementation is enough to fully run the Dragon Quest X installer (with tons of stubbing and broken install paths). It also adds support for title installation from ES (which is required for DQX since the game installs itself as a channel, nothing is loaded from disc itself when playing).

There are too many things wrong with the WFS implementation to list here, it should be considered a pre-alpha thing and I'm just thinking of merging it to make merge conflicts less annoying :)

DQX Channel

File::CreateFullPath(tmd_path);

File::IOFile fp(tmd_path, "wb");
fp.WriteBytes(tmd.data(), tmd.size());

This comment was marked as off-topic.

This comment was marked as off-topic.

#include "Core/HW/DVDInterface.h"
#include "Core/HW/Memmap.h"

u32 num_calls = 0;

This comment was marked as off-topic.

This comment was marked as off-topic.

}

INFO_LOG(WII_IPC_HLE, "IOCTL_WFS_OPEN(%s, %d) -> %d", path.c_str(), mode, fd);
Memory::Write_U16(fd, buffer_out + 0x14);

This comment was marked as off-topic.

This comment was marked as off-topic.

This comment was marked as off-topic.

This comment was marked as off-topic.

This comment was marked as off-topic.

This comment was marked as off-topic.

This comment was marked as off-topic.

void ARCUnpacker::Extract(const WriteCallback& callback)
{
u32 fourcc = Common::swap32(m_whole_file.data());
if (fourcc != 0x55AA382D)

This comment was marked as off-topic.

This comment was marked as off-topic.

u64 title_id;
DVDInterface::GetVolume().GetTitleID(&title_id);

Memory::Write_U32(title_id >> 32, command_address + 4);

This comment was marked as off-topic.

This comment was marked as off-topic.

This comment was marked as off-topic.


IPCCommandResult CWII_IPC_HLE_Device_usb_wfssrv::Open(u32 command_address, u32 mode)
{
INFO_LOG(WII_IPC_HLE, "/dev/usb_wfssrv: Open");

This comment was marked as off-topic.

This comment was marked as off-topic.

return GetDefaultReply();
}

IPCCommandResult CWII_IPC_HLE_Device_usb_wfssrv::Close(u32 command_address, bool force)

This comment was marked as off-topic.

This comment was marked as off-topic.

case IOCTL_WFS_DEVICE_INFO:
INFO_LOG(WII_IPC_HLE, "IOCTL_WFS_DEVICE_INFO");
Memory::Write_U64(16ull << 30, buffer_out); // 16GB storage.
Memory::Write_U8(4, buffer_out + 8);

This comment was marked as off-topic.

This comment was marked as off-topic.

IPCCommandResult CWII_IPC_HLE_Device_wfsi::Open(u32 command_address, u32 mode)
{
INFO_LOG(WII_IPC_HLE, "/dev/wfsi: Open");
Memory::Write_U32(GetDeviceID(), command_address + 4);

This comment was marked as off-topic.

This comment was marked as off-topic.

{
SIOCtlVBuffer command_buffer(command_address);
ERROR_LOG(WII_IPC_HLE, "IOCtlV on /dev/usb/wfssrv -- unsupported");
Memory::Write_U32(FS_SUCCESS, command_address + 4);

This comment was marked as off-topic.

This comment was marked as off-topic.


#include "Core/IPC_HLE/WII_IPC_HLE_Device_wfsi.h"

#include <mbedtls/aes.h>

This comment was marked as off-topic.

This comment was marked as off-topic.

This comment was marked as off-topic.


IPCCommandResult CWII_IPC_HLE_Device_wfsi::IOCtlV(u32 command_address)
{
SIOCtlVBuffer command_buffer(command_address);

This comment was marked as off-topic.

This comment was marked as off-topic.

#include "Core/IPC_HLE/WII_IPC_HLE.h"
#include "Core/IPC_HLE/WII_IPC_HLE_Device.h"

class ARCUnpacker

This comment was marked as off-topic.

This comment was marked as off-topic.

#pragma once

#include <string>

This comment was marked as off-topic.

This comment was marked as off-topic.

@JMC47
Copy link
Contributor

JMC47 commented Jan 8, 2017

Considering that it only affects Dragon Quest X, I'm of course okay with merging it in an alpha state to make cleanup easier. I'll of course be testing this later today. Congratulations!

@JosJuice
Copy link
Member

JosJuice commented Jan 8, 2017

@JMC47 This may affect other things too. For instance, I noticed that trying to copy a channel from an SD card to the NAND using the system menu now gives the message "The data may not have been copied." instead of the system menu claiming that it succeeded. (It never actually succeeds, it just claims to succeed.)

@JMC47
Copy link
Contributor

JMC47 commented Jan 8, 2017

That's still fine, it's all fringe things.

@JosJuice
Copy link
Member

JosJuice commented Jan 8, 2017

Yeah, the added ES function isn't exactly something that's used by emulated code that's working correctly in master.

u64 title_id;
DVDInterface::GetVolume().GetTitleID(&title_id);

Memory::Write_U32(title_id >> 32, command_address + 4);

This comment was marked as off-topic.


#include "Core/IPC_HLE/WII_IPC_HLE_Device_wfsi.h"

#include <mbedtls/aes.h>

This comment was marked as off-topic.

IPCCommandResult CWII_IPC_HLE_Device_wfsi::IOCtlV(u32 command_address)
{
ERROR_LOG(WII_IPC_HLE, "IOCtlV on /dev/wfsi -- unsupported");
Memory::Write_U32(IPC_SUCCESS, command_address + 4);

This comment was marked as off-topic.

This comment was marked as off-topic.

WFSI calls into ES to perform this operation, so expose a way for us to
do the same thing.
Refactor the existing DiscIO::AddTicket to not require the caller to
pass the requested title ID. We do not have the title ID in the ES case,
and it needs to be extracted from the ticket. Since this is always a
safe operation to do (title ID is always in the ticket), the
implementation is made default.
@JMC47
Copy link
Contributor

JMC47 commented Jan 14, 2017

Just note: this Pull Request has been verified to add enough functionality for the Mario Kart Wii and Wii Fit Channels to be successfully installed.

Wii Fit Channel runs as expected, I haven't been able to run the MKWii Channel yet due to unrelated issues.

{
SIOCtlVBuffer command_buffer(command_address);
ERROR_LOG(WII_IPC_HLE, "IOCtlV on /dev/usb/wfssrv -- unsupported");
Memory::Write_U32(FS_EINVAL, command_address + 4);

This comment was marked as off-topic.

This comment was marked as off-topic.

std::vector<u8> ticket(Buffer.InBuffer[0].m_Size);
Memory::CopyFromEmu(ticket.data(), Buffer.InBuffer[0].m_Address, Buffer.InBuffer[0].m_Size);
DiscIO::AddTicket(ticket);
break;

This comment was marked as off-topic.

This comment was marked as off-topic.

This comment was marked as off-topic.

This comment was marked as off-topic.

}
else
std::vector<u8> ticket = SignedTicketToTicket(signed_ticket);
if (ticket.size() == 0)

This comment was marked as off-topic.

std::vector<u8> FindTicket(u64 title_id)
{
std::vector<u8> signed_ticket = FindSignedTicket(title_id);
if (!signed_ticket.size())

This comment was marked as off-topic.

These two functions load either a signed ticket or a raw ticket from the
emulated NAND.

The ticket signature skip is refactored out of the ticket writing in
order to be usable by the raw ticket reading function.
This function has more uses than just in DiscIO (e.g. WFS).
This library implements basic parsing support for some of the IOS ES
formats we need to extract data from. Currently only implements TMD
functions, but some ticket handling functions from DiscIO should likely
be moved here in the future.
There are several things wrong with this implementation. The first being
that since we still don't have a proper ticket/tmd handling library, we
hardcode offsets once again to fetch TMD fields. The second being that
we don't stream data to the disk and we buffer everything in memory. The
third being that we don't properly fetch the content index for
decryption, which is prone to breaking.

But hey, it works well enough to install the DQX channel!
Defaults to $USERDIR/WFS. Used to store the contents normally stored on
WFS mass storage devices.
std::string m_device_name;

mbedtls_aes_context m_aes_ctx;
u8 m_aes_key[0x10];

This comment was marked as off-topic.

The current implementations do many things wrong but work well enough to
run the Dragon Quest X installer until the very end. The game itself
crashes when being launched from its System Menu channel unfortunately
so it is hard to verify whether the install properly worked or not.

There are plenty of "TODO(wfs)" sprinkled around this codebase with
things that are knowingly done wrong. The most important one right now
is that content extraction is done by buffering everything into memory
instead of properly streaming the data to disk (and processing
asynchronously), which causes freezes. It is likely to not cause any
practical issues since only the installer and the updater should use
this anyway.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Development

Successfully merging this pull request may close these issues.

8 participants