While setting up a proper NAND for Wii emulation has become much easier
now that disc and online system updates work, they still require users
to have a recent disc game, certificates extracted from IOS or a NAND
dump for online updates to work and to really get all system titles.
This commit adds the ability to do an online update right from
Dolphin itself, which solves that usability issue.
Allows reusing the WAD import logic more easily, whereas UICommon
code can only be used from UICommon and UI.
And managing what's on the NAND is the Core's responsability, not UI.
It didn't work when there were non-ASCII characters
in the directories argument, but it worked fine with
non-ASCII characters in names of found files and folders.
* IOS: WiiRoot shutdown was moved to HW.
* Movie: Don't call UpdateWantDeterminism() if we're not running yet,
because this will automatically be done during the boot process.
Not doing this will result in two NANDs being created.
This is larger than I thought I would be, but unfortunately it's quite
hard to split fixes like this when the handling is wrong in tons of
different places.
The content table is limited in size. It can only hold 16 entries.
Three consequences:
* Since the table cannot grow indefinitely, instead of using a std::map
we use a std::array as we should.
* Remove a hack where the CFD was cleared back to 0 on IPC close (wtf?)
* The CFD now doesn't keep increasing to infinity. It's unknown if this
would fix anything at all, but some issues in the past were caused
by CFDs being excessively large.
Other minor changes:
* Simplify save state logic.
* Keep track of the UID like ES does. Not sure how useful this is, but
we can do this very easily so why not.
* Remove the guesswork and use the actual error codes.
* Add more error checking to make Dolphin less likely to crash.
Something that should be done in the future: deduplicate the filesystem
logic. Something that takes one line in the actual ES code takes
10+ lines in our implementation... while duplicating the FS logic...
This will likely harder to fix though, so I'm leaving that
for another time.
It seems to make no difference besides allowing lower latencies and more
stability on hardware OpenAL cards. Maybe the Wait() call waits for too
long, causing buffers underruns.
Before these changes each value of latency were actually 5ms, with a
minimum latency of ~10 ms. If it was set to 4 ms on the UI, the actual
latency was 10 + 5 * 4 = 30 ms.
Now 30 ms on the UI means 30 ms on the backend.
c5fa470 made the extension check discard directories, but
only in the new code that currently only is used on Windows.
Let's add an equivalent check in the old code so that the
behavior is consistent across platforms.
This seems like an oversight in the old code, because
what's the point of loading user files if the titles
in them are going to be ignored for nearly all games?
This commit fixes the issue by making the first LoadMap
variant not overwrite entries and making the constructor
do everything in the opposite order. An alternative solution
would be to make the second LoadMap variant overwrite entries.
This fixes the global-static fifo object causing infinite hangs in some
cases. Notably, failure to initialize a graphics backend would result in
BlockingLoop::Prepare being called but never executing Run(), leaving the
object in a bad state.
The sanity check runs *before* finalising the import, so at that time
the whole title directory is still in /import and not in /title.
This means we should check for contents there, not in /title. Whoops.
The efficient function (that is nearly the same as
https://graphics.stanford.edu/~seander/bithacks.html#DetermineIfPowerOf2)
replaces one loop based instance (which also reused the xx variable
afterwards, whereas it should have used htabmask instead) and one
instance using the population count a.k.a. Hamming weigth.
This one verifies bitmasks where low bits are set to 1 (hence the name).
Any stray 0 among the lower ones or any stray 1 among the higher zeros
renders the mask invalid.
The edge cases of all zeros and all ones are considered valid masks.
It uses an efficient implementation. It's the counterpart of
https://graphics.stanford.edu/~seander/bithacks.html#DetermineIfPowerOf2
Simpler, and puts the call to CheckIntegrity right where it should be,
instead of being hidden somewhere in a thread class.
This also makes it more obvious what we're getting from the async task.
Oh, and coincidentally, this fixes a random crash that could occur
during the check. I'm not sure why.
This adds a check to ImportTitleDone to make sure all required contents
that are listed in the TMD have been imported before allowing to finish
the import. Not checking for this could allow titles to be left in an
inconsistent state.
There seems to be a race condition between a peripheral device
connecting to the bluetooth controller and it being ready to use.
It's very short and it depends upon the controller, some appear to
connect synchronously and block until the device is ready, others
report the device upon discovery but do not allow communication straight
away. I don't know which is the correct behaviour, or whether it depends
on the peripheral, controller or both. Anyway, Dolphin waits for a
remote to appear and immediately attempts to open the communication
channels, this can fail because the device isn't ready yet, delay, try
again, and it works.
There are other (unlikely) chances the device is busy at random
moments after this initial race condition so it loops around try to
reconnect.
This was inspired by an earlier patch, see here:
https://bugs.dolphin-emu.org/issues/5997#note-20
I can confirm that it works perfectly for me on a bluetooth
controller where otherwise it's impossible to connect (Dell 380
Bluetooth 4.0).
So, a FifoRecorder instance is instantiated as a file-local variable and
used as a singleton (ugh). Most users likely don't regularly use the
FIFO player/FIFO recorder, so this is kind of a substantial waste of
memory.
FifoRecorder's internal RAM and ExRAM vectors are 33554432 and 67108864
bytes respectively, which is around 100.66MB in total.
Just on the game list view on a clean build with nothing loaded, this
knocks debug build memory usage down from ~232.4MB to ~137.5MB, and
release build memory usage down from ~101MB to ~5.7MB.
The GameCube IPL sounds the same when using the free ROM as it does when
using the official ROM (and in Audacity, I couldn't visually distinguish
between the waveforms). It has a reference to an unimplemented function
at 0x8644 which seems to only be used in an inlined version of the CARD
ucode.
This allows the user to go through the Wii Menu first boot setup
screen when they launch the System Menu for the first time.
Most useful on a clean profile, after doing a full system update,
to configure settings like the console country.
This rewrites the SysConf code for several reasons:
* Modernising the SysConf class. The naming was entirely cleaned up.
constexpr for constants.
* Exposing less stuff in the header.
* Probably less efficient parsing and writing logic, but much simpler
to understand and use in my opinion. No more hardcoded offsets.
No more duplicated code for the initial SYSCONF generation.
* More flexibility. It is now possible to add and remove entries,
since we rebuild the file. This allows us to stop spamming
"section not found" panic alerts; we can now use and insert
default entries.
On a real Wii, the title list is not in any particular order. However,
because of how the flash filesystem works, titles such as 1-2 are
*never* in the first position. We must keep this behaviour, or some
versions of the System Menu may break.
Will be used from several functions to verify the signatures for
different containers (TMDs, tickets, device signed blobs).
An option was added to disable signature checks, because that could be
useful for people trying to import unsigned stuff.
stat() returns an error code in errno on both POSIX compliant
platforms and Windows.
This means we should always use errno instead of GetLastErrorMsg
which uses GetLastError() (Win32) on Windows.
POSIX allows one or more trailing slashes for directories.
From POSIX.1-2008, section 3.271 (Base Definitions / Pathname):
> A pathname can optionally contain one or more trailing <slash>
> characters. Multiple successive <slash> characters are considered to
> be the same as one <slash>, except for the case of exactly two
> leading <slash> characters.
On Windows, the extra trailing slashes are ignored for directories too.
This makes it possible to catch errors earlier so that file systems
simply fail to load instead of behaving oddly. It also makes it possible
to check for errors that weren't checkable before, like the end of a
directory being after the end of the parent directory.
Instead of expecting callers to know how the size of directory file infos
relates to which files are in which directories, filesystems now offer a
GetRoot() method, and file infos offer a way to get their children. As
a bonus, m_FileInfoVector no longer has to be created and kept around
in RAM. Only the file info objects that actually are used are created.
Not initializing until the filesystem is used is good when
a filesystem is constructed and then never used, but nobody does that.
This simplifies the code a little and lets all methods be const.
Instead of using lots of small scattered reads to read the FST,
only one big read is used, which is more efficient.
This also means that the FST only allocates memory once and stores all
strings close to each other - good for the CPU cache. The file info
objects use pointers to this FST memory of containing data themselves.
Keeping around the big m_FileInfoVector containing objects with only
pointers is a bit unnecessary, but that will be fixed soon.
Instead of calling GetPathFromFSTOffset for every file info, FindFileInfo
now only looks at names in directories that are included in the path.
For the common case of searching for "opening.bnr", this means that
only root-level files and directories have to be searched through.
Some callers already have the file info, making the relatively slow
FindFileInfo calls unnecessary. Callers that didn't have the file info
will now need to call FindFileInfo on their own.
Some callers (i.e. ISOProperties) don't want the full path, so giving them
it is unnecessary. Those that do want it can use GetPathFromFSTOffset.
Not storing full paths everywhere also saves a small bit of RAM and is
necessary for a later commit. The code isn't especially pretty right now
(callers need to use FST offsets...) but it'll become better later.
GC/Wii filesystem internals shouldn't be exposed to other classes.
This change isn't especially useful by itself, but it opens up the
way for some neat stuff in the following commits.
Too much boilerplate that is duplicated if we use curl directly.
Let's add a simple wrapper class that hides the implementation details
and just allows to simply make HTTP requests and get responses.
Makes it slightly less likely to forget a check and end up doing an
out-of-bounds access. Also makes it obvious that we *are* indeed
checking whether the handle is valid, instead of hiding it in
HasOwnership (which won't handle the root key handle case properly).
This code hadn't been touched since 2010. Nowadays, the panic alert
setting is loaded by ConfigManager and applied in UICommon.
VideoConfig has no business messing with it.
I don't see why we need to call ShutdownWiiRoot on InitializeWiiRoot.
Also, atexit? Really? Not only is this unnecessary, it will also cause
ShutdownWiiRoot to be called twice in rapid succession for no reason.
The config must only be restored after the HW has shut down, not while
it is still running, because the HW can still query the config, which
can lead to inconsistent states.
This fixes WiiRoot not being able to copy back saves on shutdown.
This ioctlv is used to get an IOSC decrypt handle for a title.
It is known to be used internally by the WFS modules, but it can also
be used from the PPC under some conditions.
Brings us down to 2 essentially unimplementable ioctlvs (syscalls which
seem to return kernel thread priorities...), and 1 known but
unimplemented ioctlv (VerifySign).
In the future, NAND filesystem access will be limited to one IOS
instance, for safety reasons and to make it possible to consider
supporting NAND images. This means that any code accessing the NAND
filesystem must go through the FS device, both for code that is
external to IOS and internal.
Because we don't want to introduce any singleton, this requires
internal IOS code that needs NAND access to be part of an IOS device
class, so they can access the FS device easily.
Making some of the internal ES implementation functions member
functions also prevents them from being (mis)used outside of IOS,
since they cannot be called everywhere anymore.
OpenALStream was querying the backend for AL_EXT_float32 support (which
suceeds), but AL_FORMAT_STEREO_FLOAT32 was defined incorrectly.
Also changes OpenALStream to query for AL_EXT_MCFORMATS (multichannel
support) rather than hard-coding that it doesn't work on macOS.
They have been broken since 2 years and no one has noticed,
which shows that no one really cares.
And it's arguable whether showing the CPU info is really useful.
I don't see any reason to disable loading the IPL if bHLE_BS2 is
disabled. bHLE_BS2 should only cause us not to run the IPL, but not
skip loading it in the first place. More importantly, without always
loading it, this causes issues when trying to launch only the GC IPL
while having bHLE_BS2 = false.
They're essentially the same. To achieve this, this commit unifies
DolReader and ElfReader into a common interface for boot executable
readers, so the only remaining difference between ELF and DOL is
how which volume is inserted.
* Move out boot parameters to a separate struct, which is not part
of SConfig/ConfigManager because there is no reason for it to
be there.
* Move out file name parsing and constructing the appropriate params
from paths to a separate function that does that, and only that.
* For every different boot type we support, add a proper struct with
only the required parameters, with descriptive names and use
std::variant to only store what we need.
* Clean up the bHLE_BS2 stuff which made no sense sometimes. Now
instead of using bHLE_BS2 for two different things, both for storing
the user config setting and as a runtime boot parameter,
we simply replace the Disc boot params with BootParameters::IPL.
* Const correctness so it's clear what can or cannot update the config.
* Drop unused parameters and unneeded checks.
* Make a few checks a lot more concise. (Looking at you, extension
checks for disc images.)
* Remove a mildly terrible workaround where we needed to pass an empty
string in order to boot the GC IPL without any game inserted.
(Not required anymore thanks to std::variant and std::optional.)
The motivation for this are multiple: cleaning up and being able to add
support for booting an installed NAND title. Without this change, it'd
be pretty much impossible to implement that.
Also, using std::visit with std::variant makes the compiler do
additional type checks: now we're guaranteed that the boot code will
handle all boot types and no invalid boot type will be possible.
I didn't know better back then, but the boot type is only supposed to
be used for the actual boot params. It shouldn't be used or changed
after booting.
You may want to read the PR #2047 comments before reading this.
Dolphin attempts to support an unencrypted type of Wii discs
that apparently is identified by a 4-byte integer at 0x60
being non-zero. I don't know what discs (if any) would be
using that format, so I haven't been able to test Dolphin's
support for it, but it has probably been broken for a while.
The old implementation is very short but also strange.
In CreateVolumeFromFilename, we read a 4-byte integer from
0x60, and if it's non-zero, we create a CVolumeGC object
instead of a CVolumeWiiCrypted object. This might seem like
it makes no sense, but it presumably worked in the past
because IsVolumeWiiDisc used to check the volume type by
reading the magic word for Wii straight from the disc,
meaning that CVolumeGC objects representing unencrypted Wii
discs would be treated as Wii discs by pretty much all of
Dolphin's code except for the volume implementation code.
(It wasn't possible to simply use CVolumeWiiCrypted, because
that class only handled encrypted discs, like the name says.)
However, that stopped working as intended because of ace0607.
And furthermore, bb93336 made it even more broken by making
parts of Dolphin expect that data read from Wii discs needed
to be decrypted (rather than the volume implementation
implicitly deciding whether to decrypt when Read was called).
Disclaimer: Like I said before, I haven't been able to test
any of this because I don't have any discs that use this
unencrypted Wii disc format, so this is all theoretical.
Later, PR #2047 tried to remove Dolphin's support for
the unencrypted Wii disc format because seemingly no
discs used it, but the PR got closed without being merged.
At the end of that PR, I said that I would make a new PR
with a better implementation for the format after PR #2353
was merged. Now that PR #2353 is merged (two years later...)
and PR #5521 is merged, the new implementation was easy to
make, and here it is!
Untested.
Normal users don't care about it. In fact, people care so
little about it that the Wii implementation of it was broken
starting from when it was implemented (eb65601) to 7 years
later (e0a47c1), apparently without anyone reporting it.
- coef: Explicitly set 23 different values that are used by GBA UCode,
and tweaked overall parameters to more closely match those 23 values.
- irom: Moved a few functions to their proper places, updated BootUCode
to configure DMA transfers using AX registers as well as IX registers
(the GBA UCode uses this to do two sequential transfers in one call),
and added partial functions used by GBA UCode.
All functions were reverse-engineered solely based off of observed
effects on the virtual machine: register states before-and-after, dmem
interactions, and DMA transfers. The specific coefficients were observed
being read from dmem, and must be exactly those values to function
properly. I have no knowledge of how the official ROM implements these
functions, or how it is implemented overall.
Tested with The Legend of Zelda: Four Swords Adventures, Final Fantasy
Crystal Chronicles, and Billy Hatcher and the Giant Egg (to download
ChuChu Rocket!).
`P_REG1C` had the same value as `P_ACCL`, so was causing spurious errors
when used with ACCM registers. Gcdsptool (which calls this `P_ACCLM`)
gives it the value `P_REG | 0x1c10` instead, and handles errors in the
same block as other REG## enums.
This makes the interface slightly cleaner and a bit more consistent
with the other getters. Still not fully the same, since the others
don't really handle failures with std::optional; but at least the
value is returned by value now, as opposed to having the function
take a pointer to a u64.
This gets rid of some assumptions that non-DiscIO code was making about
volume types. It's better to encapsulate as many of the volume type
differences as possible in DiscIO.
Made possible by PR #2353.
This is more reliable, as this guarantees subsystems will be
shut down in the same order they were initialised (if they were
initialised). It also allows us to stop keeping track of what needs to
be shut down manually and just return in case of errors.
This should prevent the emulator from getting totally stuck when
the boot process does fail.
This makes it hard to support different boot params for different boot
types. We should not be making the assumption that Dolphin will
always be booting directly from a file (and in particular, only
using a string).
It's incompatible with future changes that will allow Dolphin to boot
a NAND title properly from well, the NAND, as opposed to booting from
WADs. (And no, treating the title TMD as a "bootable" path doesn't
count. Especially when that approach won't work with NAND images
or IOS LLE.)
And it's confusing to expose this functionality from the UI. It's
pretty bad for UX to change the play button's behaviour depending on
whether the user has launched something before, configured a default
file to boot, added a directory to their game paths.
This commit moves the write function to where it should be (IOS),
especially when ES::ImportTicket() is the only place to use it.
Prevents misusing the ticket import function, and removes one unsafe
direct write to the NAND that does not go through IOS.
This also fixes the destination path: the session root is the one which
should be used for determining the ticket path, not the configured one.
The whole NANDContentLoader stuff is truly awful and will be removed
as soon as possible.
For now, this fixes a bug that was exposed by std::optional::operator*.
std::optional makes a few things a bit neater and less error prone.
However, we still cannot use C++17 (unfortunately), so this commit
adds an implementation of std::optional that we can use right now.
Based on https://github.com/tensorflow/tensorflow/blob/master/tensorflow/core/lib/gtl/optional.h
which seems to be fairly similar to C++17's <optional> and standards
compliant. It's one of the few implementations that handle propagating
type traits like copy constructibility, just like libc++/libstdc++.
`MainWindow` initializes a number of input interfaces but never shuts
them down. This was causing a crash-after-exit on macOS where the
ControllerInterface backend stores a `std::thread` object in a static
variable and only stops it when ControllerInterface::Shutdown is called.
FormLayout is not intended for this sort of dialog:
> QFormLayout is a convenience layout class that lays out its children
> in a two-column form. The left column consists of labels and the right
> column consists of "field" widgets (line editors, spin boxes, etc.).
pSysMem is of the type const void* -- because of this, it makes the
original delete[] call undefined behavior, as deleting a void pointer is
undefined behavior.
Also punning types into existence, like what was done for the stereo
image header is undefined behavior as well. The proper way to do this is
to either manually add all individual bytes manually, or memcpy the
struct into memory.
As we want to deallocate the memory before returning, and because
pSysMem is a const void*, we keep a unique_ptr to the data and just pass
pSysMem a raw pointer to the data.