Direct access to the WAD bytes is required to read contents with proper
padding data (since they can sometimes end up being outside of the
data app section). Allowing the whole buffer to be accessed directly
would be error prone, so this commit adds GetContent() to WiiWAD
for getting raw content data by index.
These cannot be booted, so it is bad UX to show them in the UI as if
they were regular titles, and yet have different behaviour for them.
And technically, there is no reason to allow them to be used to boot
in the first place.
Another reason they should not be shown is that Dolphin fails
spectacularly with WADs that have a valid boot content index, but are
not PPC titles (e.g. IOS WADs). The only reliable way to avoid this
is to check for the title type and only show channels, just like
the Wii System Menu.
Mistakenly used the wrong TMD to clean up the import.
The original TMD is the one that is supposed to be used when
cancelling an import, but I forgot it's in the /import directory after
starting an import.
This exposes all ES title management ioctlvs to avoid duplicating IOS
code everywhere and to make it easier to reuse (since this way it's
not unnecessarily tied to the PPC IPC mechanism anymore) and unit test.
Some functions were also renamed for consistency with the other names,
*and* with official names.
Just like DeleteTitle, Using CNANDContentManager is overkill,
inefficient and useless. And it results in a few failures in
situations where a delete should just always work.
But here it gets bonus points, because it manages to actually use
the TMD for deleting contents, when IOS does none of that and just
deletes files ending with .app in the title content directory. :)
This enables constructing an IOS instance that is not tied to emulation
and that can be simply used for internal purposes (ES, FS).
NAND root initialisation was moved to IOS since we cannot rely on HW
doing that for us anymore, and technically the NAND is entirely managed
by IOS anyway.
This is unsafe, because the NAND should not be accessed and messed with
while it is being used. In fact, this kind of inappropriate behaviour
will not be possible when we get NAND image support.
And even if there were no safety issue, there is still no reason
a *getter* function should *do* something that has lasting effects
on user data. GetWiiFSPath() should *just* return a path!
This adds code to update the PPC's UID and GID, which fixes a
regression with the system menu. Ideally, we would simply rely on IOS's
ES_Launch here and not duplicate the logic here, but we cannot do that
properly until the direct WAD launch hack is dropped, *and* until the
IOS changes that would enable internal calls are ready.
Since this fixes a semi-important regression with managing saves from
the SM, and the duplication is not too terrible, I believe it is a good
idea to get this fixed right now to avoid affecting users too much.
I do plan to fix this properly in the future.
* CNANDContentManager does things that are absolutely useless. In
particular, it parses the ticket, the TMD, reads contents, etc.
when we only need to remove the title directory.
* This means it will fail if the ticket cannot be found, when that
should not be the case.
* This also obviously caused DeleteTitle to be incredibly inefficient.
* We are already removing the title directory later in the function,
as CNANDContentManager does not even delete titles correctly.
DeleteTitle != DeleteTitleContents.
This introduces `constexpr` usages for compile-time constants in the
contributing guide, as apparently most people don't know it exists,
or that it doesn't have to be used with `const` most of the time.
* It should take a ticket view, not a title ID.
* It's missing a lot of checks.
* It's not deleting tickets properly.
* It's not deleting only the ticket it needs to delete.
* It should not return -1017 when the ticket doesn't exist.
* It's not returning the proper error code when a read/write fails.
* It's not cleaning up the ticket directory if there is nothing left.
This commit fixes its implementation.
* Supporting other ticket types makes the logic slightly more complex.
* There have been no such non-RSA2048 tickets seen during the Wii's
lifetime.
* The Wii's IOS doesn't even have support for them.
This changes some parts of IOS (actually just ES) to reuse more crypto
code from IOSC or Common::AES.
TicketReader still returns the title key directly as opposed to having
ES use IOSC directly to avoid duplicating the title key IV stuff.
Side effects:
* A nasty unbounded array access bug is now fixed.
* ES_Decrypt/ES_Encrypt now returns sane results for keys other than
the SD key.
* Titles with a Korean ticket can now be decrypted properly.
And in the future, we can look into implementing ioctlv 0x3c and 0x3d
now that we have the proper "infra" for IOSC calls.
This prevents the IOS crypto code and keys from being spread over
the codebase. Things only have to be implemented once, and can be
used everywhere from the IOS code.
Additionally, since ES exposes some IOSC calls directly (DeleteObject
and Encrypt/Decrypt), we need this for proper emulation.
Currently, this only supports AES key objects.
Netplay uses a blank NAND, which means that homebrew launchers like
Gecko will force users to install IOSes.
Expecting netplay users to have a proper NAND setup is unrealistic,
and we don't actually give them a good way of syncing NANDs, so
let's extend the hack to netplay/TAS until we have a better way
of dealing with the issue.
This changes the main IOS code (roughly the equivalent of the kernel)
to a class instead of being a set of free functions + tons of static
variables.
The reason for this change is that keeping tons of static variables
like that prevents us from making an IOS instance and reusing IOS
code easily.
Converting the IOS code to a class also allows us to mostly decouple
IOS from the PPC emulation.
The more interesting changes are in Core/IOS/IOS. Everything else is
mostly just boring stuff required by this change...
* Because the devices themselves call back to the main IOS code
for various things (getting the current version, replying to a
request, and other syscall-like functions), just like processes in
IOS call kernel syscalls, we have to pass a reference to the kernel
to anything that uses IOS syscalls.
* Change DoState to save device names instead of device IDs to simplify
AddDevice() and get rid of an ugly static count.
* Change ES_Launch's ack to be sent at IOS boot, now that we can do
this properly.
This changes the IOS code to handle ES contexts inside of ES, instead
of leaking out implementation details into the IPC request dispatcher.
The intent is to clarify what's shared between every single ES context,
and what is specific to an ES context. (Not much.) This should reduce
the number of static members in the ES class.
The other changes are there just because we now keep track of the
IPC FD inside of ES.
Future plans:
* After the WAD direct launch hack is dropped, the title context
will be made a class member.
* Have proper function prototypes, instead of having every single one
of them take ioctlv requests. This will allow reusing IOS code in
other parts of the Dolphin codebase without having to construct
ioctlv requests.
GTK2 is a dependency on Linux whenever USE_X11 is true, but we were
not linking or adding the include directory for GTK for DolphinWX.
Fixes a regression introduced by 6197d9622.
Simple quality-of-life addition that allows "uninstalling" WADs
(removing the corresponding installed title) from the NAND.
The option is only enabled when the WAD can be uninstalled
The motivation for this is actually to encourage proper usage of the
WAD launch feature (installing it to the NAND first), so we can
drop the "direct WAD title launch" hack.
Looking more carefully at the IOS ticket view generation code reveals
that the first field in the TicketView struct is copied over from
the ticket version, extended to 4 bytes.
This implements ES_SetUid, which is used by the system menu to change
its own permissions. This is required for implementing permission
checks and proper NAND metadata support in the future.
This will be required for permission checks in the future.
Note that this is only for the PPC as we do not have actual processes.
Keeping track of other modules' UIDs/GIDs is virtually useless anyway.
UID/GID changes are implemented in the following functions:
* ES_Launch
* ES_DIVerify
ES_SetUid is not implemented yet because it'd need further changes.
Instead of allowing unknown ioctlvs and faking success for both unknown
and unimplemented ioctlvs, which can possibly result in nasty, hard to
debug bugs (if the emulated software behaves unexpectedly), we should
reject unknown ioctlvs and log known, but unimplemented ioctlvs.
This adds unit tests for IOS/ESFormats, and in particular, for the
TMDReader. It is tested using invalid TMDs (to check IsValid()) and
two valid, properly signed TMDs.
Things which are now tested:
* Title type helper functions.
* TMDReader: Validity check.
* TMDReader: General information returned by the Get*() methods.
* TMDReader: Raw TMD and generated TMD view, compared against IOS.
* TMDReader: Game ID generation code (which is Dolphin specific).
* TMDReader: Content information: getting by ID/index, order, metadata.
This is an implementation detail that does not have to be exposed.
It was used in WII_IPC whenever the IPC gets reset, but that does not
make much sense to me: the only time when IOS loses state and the IPC
registers are set up again is when it's reloaded. And reloading IOS
already calls Reset() indirectly.
Also, an IPC reset from the PPC definitely should not close all opened
devices!
This also gets rid of a special case for clear_devices, which is now
completely unneeded.
This keeps all of the return codes in the same place and exposed
publicly (as they are not internal to ES).
I have also added proper IOSC error codes and renamed some codes
for more consistency. (Unix ones have an E prefix, others do not.)
A set of small changes to handle title imports more accurately.
* Clean up the import directory after an import, exactly like IOS.
This should prevent the title directory from having useless leftover
contents, which could confuse the emulated software.
* More robust failsafe in case an import does not complete normally.
IOS checks for stale imports and handles them appropriately on boot.
We now do the same.
* Create all directories as IOS does. This includes the data directory.
This may fix LIBUSB_ERROR_NOT_FOUND whenever devices end up being in
an unconfigured state. We don't need anything more than the first
config descriptor anyway.
Proper semantics.
IOS only cares about the TMD and nothing else, so we should use
FindInstalledTMD, instead of reading/parsing/decrypting a bunch of
useless stuff, which is slow *and* causes issues because of the cache.
Dolphin assumes that content 0 is opening.bnr, without checking
whether content 0 exists or if it is even supposed to be there (it's
only there for channels). This results in sometimes reading garbage.
This adds a check to only try to read names from content 0's header
if the title is a channel (channel, system channel or game channel).
Defaulting to SSL verification off, *and* forcing it to be off even
when the emulated software asks us to enable it is very bad behaviour,
inaccurate and insecure.
Because the old option defaulted to off, we have to change the INI
option name to force the new default to be used. Unfortunate,
but without this we cannot ensure our users' security.
ES.cpp was becoming pretty huge. This commit splits the ES code into
several files:
* Main ES (launch, UID, current title directory and title ID, etc.)
* Device identity and encryption (ID and cert, keys, encrypt/decrypt)
* Title management (imports, exports, deletions)
* Title contents (open/close/read/seek)
* Title information (titles, stored contents, TMDs)
* Views (for tickets and TMDs)
Using DiscIO's NAND content loader is the wrong way to get the ticket
for a title, because it checks whether the TMD is present and the
validity check fails if it isn't. This is not the correct behaviour:
we should just read the ticket from /ticket without caring about TMDs.
* IOS doesn't rely on the number of contents indicated in the TMD.
Instead, it checks whether the contents *do* exist on the NAND.
* Implement ES_GetTMDStoredContents (and the count ioctlv).
* Drop a hack in ES_GetStoredContents, which is unnecessary now that
we do it properly.
This is slightly safer than writing contents to /title directly.
We still cannot rename everything in one go atomically, but this allows
implementing AddTitleCancel very easily.
Also, this ensures that when a title import fails, no incomplete files
will be left in the title directory, which can mess up the system menu.
This adds a check to the SSL code to make sure we are using the correct
client certificate and key (and root CA).
Now, instead of silently failing, the user will be notified whenever a
file is missing or when it is invalid, i.e. when the hash does not
match; this is likely to happen for existing users as the program
linked in the network guide extracted the wrong certs :(
This partially restores a hack which causes ES to fake ticket views for
IOS titles.
This is necessary because we still allow users to boot games from the
game list, so, with no way of making sure the required IOSes are
installed beforehand, games may OSPanic() when they try to reload to
some IOS version and just find out that the IOS is not installed
(something which *never* happens on the real console, of course).
A warning is printed in the logs to make sure technical users know the
IOS titles are being faked. To try and keep things accurate in all
other cases, this hack is only active when it is needed (when the
current title is a disc title which was launched from the game list).
This adds a hash check for imported contents. IOS does it for security;
we do it for a somewhat different reason, to catch content decryption
bugs before incorrectly decrypted contents get written to the NAND,
which can cause titles to be corrupted.
Either way, we should have been doing this check in all cases.
When the TMD doesn't exist on the NAND, IOS returns -106.
This commit also changes IsValid() to not check for the TMD validity,
since this is not always something we want. (IOS can have different
error codes when the TMD is missing, or even worse, simply assume
that the TMD is valid.)
IOS determines installed titles by looking at /title, not uid.sys,
which is more like a history of installed titles. And it does not care
at all about the installed TMD (or even if it is present at all).
This removes wrappers for ES_DIVerify and ES::LoadWAD. They are not
really useful as we can simply call the ES function directly, and
it is actually somewhat confusing because both functions are static
and are not tied to a particular ES instance.
This allows Dolphin to stay up-to-date about what title is currently
running, which fixes savestates, screenshots, etc. after an ES_Launch.
Same limitation as with MIOS: currently, GameINIs are not reloaded,
because it's a pain with the current config system. It'll happen
when the new config system is done, and this commit makes it much
easier to do!
Some members are shared between ES instances, and they are just global
variables in IOS.
This is more efficient than getting the installed titles or setting the
current active title tons of times for no reason.
This changes ES to keep track of the active title properly,
just like IOS:
* It is NOT changed on resource manager open/close.
* It is reset on IOS reload.
* It is changed by ES_DIVerify and ES_Launch.
IOS stores the active title in a structure like this:
struct ESTitleContext
{
Ticket* ticket;
TMD* tmd;
u32 active;
};
With this commit, we also do keep the Ticket and TMD around. This
makes some of the DI ioctlvs (which return data about the current
active title) trivial to implement in the future.
This fixes the System Menu not being able to see update partitions
and also allows us to change Dolphin's active game info in the future.
This fixes ES_GetTMDView and ES_GetTMDViewSize to return -106
(FS_ENOENT) if the title does not exist (and more specifically when no
TMD exists in the NAND). This allows installed (or not installed) IOSes
to be detected properly.