This function simply does a handle table lookup for a writable event
instance identified by the given handle value. If a writable event
cannot be found for the given handle, then an invalid handle error is
returned. If a writable event is found, then it simply signals the
event, as one would expect.
svcCreateEvent operates by creating both a readable and writable event
and then attempts to add both to the current process' handle table.
If adding either of the events to the handle table fails, then the
relevant error from the handle table is returned.
If adding the readable event after the writable event to the table
fails, then the writable event is removed from the handle table and the
relevant error from the handle table is returned.
Note that since we do not currently test resource limits, we don't check
the resource limit table yet.
Two kernel object should absolutely never have the same handle ID type.
This can cause incorrect behavior when it comes to retrieving object
types from the handle table. In this case it allows converting a
WritableEvent into a ReadableEvent and vice-versa, which is undefined
behavior, since the object types are not the same.
This also corrects ClearEvent() to check both kernel types like the
kernel itself does.
Previously, ILibraryAppletAccessor would signal upon creation of any applet, but this is incorrect. A flag inside of the applet code determines whether or not creation should signal state change and swkbd happens to be one of these applets.
The kernel uses the handle table of the current process to retrieve the
process that should be used to retrieve certain information. To someone
not familiar with the kernel, this might raise the question of "Ok,
sounds nice, but doesn't this make it impossible to retrieve information
about the current process?".
No, it doesn't, because HandleTable instances in the kernel have the
notion of a "pseudo-handle", where certain values allow the kernel to
lookup objects outside of a given handle table. Currently, there's only
a pseudo-handle for the current process (0xFFFF8001) and a pseudo-handle
for the current thread (0xFFFF8000), so to retrieve the current process,
one would just pass 0xFFFF8001 into svcGetInfo.
The lookup itself in the handle table would be something like:
template <typename T>
T* Lookup(Handle handle) {
if (handle == PSEUDO_HANDLE_CURRENT_PROCESS) {
return CurrentProcess();
}
if (handle == PSUEDO_HANDLE_CURRENT_THREAD) {
return CurrentThread();
}
return static_cast<T*>(&objects[handle]);
}
which, as is shown, allows accessing the current process or current
thread, even if those two objects aren't actually within the HandleTable
instance.
Our implementation of svcGetInfo was slightly incorrect in that we
weren't doing proper error checking everywhere. Instead, reorganize it
to be similar to how the kernel seems to do it.
We can just return a new instance of this when it's requested. This only
ever holds pointers to the existing registed caches, so it's not a large
object. Plus, this also gets rid of the need to keep around a separate
member function just to properly clear out the union.
Gets rid of one of five globals in the filesystem code.
This is the same behavior-wise as DeleteDirectoryRecursively, with the
only difference being that it doesn't delete the top level directory in
the hierarchy, so given:
root_dir/
- some_dir/
- File.txt
- OtherFile.txt
The end result is just:
root_dir/
More hardware accurate. On the actual system, there is a differentiation between the signaler and signalee, they form a client/server relationship much like ServerPort and ClientPort.
The opposite of the getter functions, this function sets the limit value
for a particular ResourceLimit resource category, with the restriction
that the new limit value must be equal to or greater than the current
resource value. If this is violated, then ERR_INVALID_STATE is returned.
e.g.
Assume:
current[Events] = 10;
limit[Events] = 20;
a call to this service function lowering the limit value to 10 would be
fine, however, attempting to lower it to 9 in this case would cause an
invalid state error.
This kernel service function is essentially the exact same as
svcGetResourceLimitLimitValue(), with the only difference being that it
retrieves the current value for a given resource category using the
provided resource limit handle, rather than retrieving the limiting
value of that resource limit instance.
Given these are exactly the same and only differ on returned values, we
can extract the existing code for svcGetResourceLimitLimitValue() to
handle both values.
This kernel service function retrieves the maximum allowable value for
a provided resource category for a given resource limit instance. Given
we already have the functionality added to the resource limit instance
itself, it's sufficient to just hook it up.
The error scenarios for this are:
1. If an invalid resource category type is provided, then ERR_INVALID_ENUM is returned.
2. If an invalid handle is provided, then ERR_INVALID_HANDLE is returned (bad thing goes in, bad thing goes out, as one would expect).
If neither of the above error cases occur, then the out parameter is
provided with the maximum limit value for the given category and success
is returned.
This function simply creates a ResourceLimit instance and attempts to
create a handle for it within the current process' handle table. If the
kernal fails to either create the ResourceLimit instance or create a
handle for the ResourceLimit instance, it returns a failure code
(OUT_OF_RESOURCE, and HANDLE_TABLE_FULL respectively). Finally, it exits
by providing the output parameter with the handle value for the
ResourceLimit instance and returning that it was successful.
Note: We do not return OUT_OF_RESOURCE because, if yuzu runs out of
available memory, then new will currently throw. We *could* allocate the
kernel instance with std::nothrow, however this would be inconsistent
with how all other kernel objects are currently allocated.
Avoids the need to create a copy of the std::string instance
(potentially allocating).
The only reason RegisterService takes its argument by value is because
it's std::moved internally.
The interface for shared memory was changed, but another commit was
merged that relied on the (previously public) internals of SharedMemory.
This amends that discrepancy.
<random> isn't necesary directly within the header and can be placed in
the cpp file where its needed. Avoids propagating random generation
utilities via a header file.
Cleans out the citra/3DS-specific implementation details that don't
apply to the Switch. Sets the stage for implementing ResourceLimit
instances properly.
While we're at it, remove the erroneous checks within CreateThread() and
SetThreadPriority(). While these are indeed checked in some capacity,
they are not checked via a ResourceLimit instance.
In the process of moving out Citra-specifics, this also replaces the
system ResourceLimit instance's values with ones from the Switch.
This service function was likely intended to be a way to redirect where
the output of a log went. e.g. Firing a log over a network, dumping over
a tunneling session, etc.
Given we always want to see the log and not change its output. It's one
of the lucky service functions where the easiest implementation is to
just do nothing at all and return success.
Both member functions assume the passed in target process will not be
null. Instead of making this assumption implicit, we can change the
functions to be references and enforce this at the type-system level.
Makes the interface nicer to use in terms of 64-bit code, as it makes it
less likely for one to get truncation warnings (and also makes sense in
the context of the rest of the interface where 64-bit types are used for
sizes and offsets
The separate enum isn't particularly necessary here, and the values can
just be directly put into the ResultCode instances, given the names are
also self-documenting here.
Used by developers to test games, not present on retail systems. Some games are known to respond to DebugPad input though, for example Kirby Star Allies.
Similar to PR 1706, which cleans up the error codes for the filesystem
code, but done for the kernel error codes. This removes the ErrCodes
namespace and specifies the errors directly. This also fixes up any
straggling lines of code that weren't using the named error codes where
applicable.
It seems palma is done through bluetooth, we need this for pokemon go however more research needs to be done when we actually get palma working. This is presumably used for transfering data between the controller and the console, it does not seem for actual input as far as I know.
empty() in this case will always return false, since the returned
container is a std::array. Instead, check if all given users are invalid
before returning the error code.
The previous expression would copy sizeof(size_t) amount of bytes (8 on
a 64-bit platform) rather than the full 10 bytes comprising the uuid
member.
Given the source and destination types are the same, we can just use an
assignment here instead.
When yuzu is compiled in release mode this function is unused, however,
when compiled in debug mode, it's used within a LOG_TRACE statement.
This prevents erroneous compilation warnings about an unused function
(that isn't actually totally unused).
* svcBreak now dumps information from the debug buffer passed
info1 and info2 seem to somtimes hold an address to a buffer, this is usually 4 bytes or the size of the int and contains an error code. There's other circumstances where it can be something different so we hexdump these to examine them at a later date.
* Addressed comments
Started implementation of the AM message queue mainly used in state getters. Added the ability to switch docked mode whilst in game without stopping emulation. Also removed some things which shouldn't be labelled as stubs as they're implemented correctly
These are needed by Edizon to boot. They are used to see if a user is using SX OS, as SX OS registers a custom service called 'tx' and attempting to register a service of the same name lets the application know if it is present.
Previously, we would let a user enter an unbounded name and then
silently truncate away characters that went over the 32-character limit.
This is kind of bad from the UX point of view, because we're essentially
not doing what the user intended in certain scenarios.
Instead, we clamp it to 32 characters and make that visually apparent in
the dialog box to provide a name for a user.
* get rid of boost::optional
* Remove optional references
* Use std::reference_wrapper for optional references
* Fix clang format
* Fix clang format part 2
* Adressed feedback
* Fix clang format and MacOS build
Returns the raw NACP bytes and the raw icon bytes into a title-provided buffer. Pulls from Registration Cache for control data, returning all zeros should it not exist.
An object to read SaveDataInfo objects, which describe a unique save on the system. This implementation iterates through all the directories in the save data space and uses the paths to reconstruct the metadata.
This is just flat data, so it doesn't really need to be in the function
itself. This also allows deduplicating the constant for the backup size
in GetImageSize().
Now that we've gotten the innaccurate error codes out of the way, we can
finally toss away a bunch of these, trimming down the error codes to
ones that are actually used and knocking out two TODO comments.
All priority checks are supposed to occur before checking the validity
of the thread handle, we're also not supposed to return
ERR_NOT_AUTHORIZED here.
We can just call the function instead of duplicating the code here. This
also prevents an unused function warning.
We also don't need to take the lambda capture by reference. It's just a
u64 value, so by value is fine here.
* Fixed conflict with nfp
* Few fixups for nfc
* Conflict 2
* Fixed AttachAvailabilityChangeEvent
* Conflict 3
* Fixed byte padding
* Refactored amiibo to not reside in "System"
* Removed remaining references of nfc from system
* used enum for Nfc GetStateOld
* Added missing newline
* Moved file operations to front end
* Conflict 4
* Amiibos now use structs and added mutexes
* Removed amiibo_path
In the kernel, there isn't a singular handle table that everything gets
tossed into or used, rather, each process gets its own handle table that
it uses. This currently isn't an issue for us, since we only execute one
process at the moment, but we may as well get this out of the way so
it's not a headache later on.
This should be comparing against the queried process' vma_map, not the
current process'. The only reason this hasn't become an issue yet is we
currently only handle one process being active at any time.
This is a subset of the better-hid-2 changes, this fixes input in various games which don't support dual joycons. This pr will search for the next best controller which is supported by the current game
This event signals the game when new DLC is purchased from the eShop while the game is running. Since, for the forseeable future, yuzu will not have this ability, it seems safe to stub with a dummy event that will never fire. This is needed to boot Sonic Mania Plus (update v1.04).
Now that the changes clarifying the address spaces has been merged, we
can wrap the checks that the kernel performs when mapping shared memory
(and other forms of memory) into its own helper function and then use
those within MapSharedMemory and UnmapSharedMemory to complete the
sanitizing checks that are supposed to be done.
swap.h only needs to be present in the header for the type aliases and
definitions, it's not actually needed in the cpp files though. input.h
is just unused entirely in xpad.h
These classes are non-trivial and are definitely going to be changed in
the future, so we default these to prevent issues with forward
declarations, and to keep the compiler from inlining tear-down code.
The data retrieved in these cases are ultimately chiefly owned by either
the RegisteredCache instance itself, or the filesystem factories. Both
these should live throughout the use of their contained data. If they
don't, it should be considered an interface/design issue, and using
shared_ptr instances here would mask that, as the data would always be
prolonged after the main owner's lifetime ended.
This makes the lifetime of the data explicit and makes it harder to
accidentally create cyclic references. It also makes the interface
slightly more flexible than the previous API, as a shared_ptr can be
created from a unique_ptr, but not the other way around, so this allows
for that use-case if it ever becomes necessary in some form.
So, one thing that's puzzled me is why the kernel seemed to *not* use
the direct code address ranges in some cases for some service functions.
For example, in svcMapMemory, the full address space width is compared
against for validity, but for svcMapSharedMemory, it compares against
0xFFE00000, 0xFF8000000, and 0x7FF8000000 as upper bounds, and uses
either 0x200000 or 0x8000000 as the lower-bounds as the beginning of the
compared range. Coincidentally, these exact same values are also used in
svcGetInfo, and also when initializing the user address space, so this
is actually retrieving the ASLR extents, not the extents of the address
space in general.
This should help diagnose crashes easier and prevent many users thinking that a game is still running when in fact it's just an audio thread still running(this is typically not killed when svcBreak is hit since the game expects us to do this)
A fairly basic service function, which only appears to currently support
retrieving the process state. This also alters the ProcessStatus enum to
contain all of the values that a kernel process seems to be able of
reporting with regards to state.
Neither of these functions alter the ownership of the provided pointer,
so we can simply make the parameters a reference rather than a direct
shared pointer alias. This way we also disallow passing incorrect memory values like
nullptr.
These only exist to ferry data into a Process instance and end up going
out of scope quite early. Because of this, we can just make it a plain
struct for holding things and just std::move it into the relevant
function. There's no need to make this inherit from the kernel's Object
type.
Regular value initialization is adequate here for zeroing out data. It
also has the benefit of not invoking undefined behavior if a non-trivial
type is ever added to the struct for whatever reason.
This adds the missing address range checking that the service functions
do before attempting to map or unmap memory. Given that both service
functions perform the same set of checks in the same order, we can wrap
these into a function and just call it from both functions, which
deduplicates a little bit of code.
HandheldVariant is for specific games which expect handheld controllers to be at position 8(kirby), however this doesn't fix all games as some games require handhelds to be at position 0(snipperclips)
There's no real need to use a shared pointer in these cases, and only
makes object management more fragile in terms of how easy it would be to
introduce cycles. Instead, just do the simple thing of using a regular
pointer. Much of this is just a hold-over from citra anyways.
It also doesn't make sense from a behavioral point of view for a
process' thread to prolong the lifetime of the process itself (the
process is supposed to own the thread, not the other way around).
When loading NROs, svcBreak is called to signal to the debugger that a new "module" is loaded. As no debugger is technically attached we shouldn't be killing the programs execution.
Hardware tests show that trying to unmap an unmapped buffer already should always succeed. Hardware test was tested up to 32 iterations of attempting to unmap
This was the result of a typo accidentally introduced in
e51d715700. This restores the previous
correct behavior.
The behavior with the reference was incorrect and would cause some games
to fail to boot.
Conceptually, it doesn't make sense for a thread to be able to persist
the lifetime of a scheduler. A scheduler should be taking care of the
threads; the threads should not be taking care of the scheduler.
If the threads outlive the scheduler (or we simply don't actually
terminate/shutdown the threads), then it should be considered a bug
that we need to fix.
Attributing this to balika011, as they opened #1317 to attempt to fix
this in a similar way, but my refactoring of the kernel code caused
quite a few conflicts.
Many of the member variables of the thread class aren't even used
outside of the class itself, so there's no need to make those variables
public. This change follows in the steps of the previous changes that
made other kernel types' members private.
The main motivation behind this is that the Thread class will likely
change in the future as emulation becomes more accurate, and letting
random bits of the emulator access data members of the Thread class
directly makes it a pain to shuffle around and/or modify internals.
Having all data members public like this also makes it difficult to
reason about certain bits of behavior without first verifying what parts
of the core actually use them.
Everything being public also generally follows the tendency for changes
to be introduced in completely different translation units that would
otherwise be better introduced as an addition to the Thread class'
public interface.
In some games (Splatoon 2 and Splatoon 2 Splatfest World Premiere, notably), pass offset=0 and count=2047 into the ListAddOnContent method which should return all DLCs for the current title. The (presumably) intended behavior is to successfully return a empty array but because of a < v. <= in an if statement, a failure error code was returned causing these games to svcBreak. This fixes that if statement.
Now that we have all of the rearranging and proper structure sizes in
place, it's fairly trivial to implement svcGetThreadContext(). In the
64-bit case we can more or less just write out the context as is, minus
some minor value sanitizing. In the 32-bit case we'll need to clear out
the registers that wouldn't normally be accessible from a 32-bit
AArch32 exectuable (or process).
This will be necessary for the implementation of svcGetThreadContext(),
as the kernel checks whether or not the process that owns the thread
that has it context being retrieved is a 64-bit or 32-bit process.
If the process is 32-bit, then the upper 15 general-purpose registers
and upper 16 vector registers are cleared to zero (as AArch32 only has
15 GPRs and 16 128-bit vector registers. not 31 general-purpose
registers and 32 128-bit vector registers like AArch64).
Makes the public interface consistent in terms of how accesses are done
on a process object. It also makes it slightly nicer to reason about the
logic of the process class, as we don't want to expose everything to
external code.
boost::static_pointer_cast for boost::intrusive_ptr (what SharedPtr is),
takes its parameter by const reference. Given that, it means that this
std::move doesn't actually do anything other than obscure what the
function's actual behavior is, so we can remove this. To clarify, this
would only do something if the parameter was either taking its argument
by value, by non-const ref, or by rvalue-reference.
The locations of these can actually vary depending on the address space
layout, so we shouldn't be using these when determining where to map
memory or be using them as offsets for calculations. This keeps all the
memory ranges flexible and malleable based off of the virtual memory
manager instance state.
Previously, these were reporting hardcoded values, but given the regions
can change depending on the requested address spaces, these need to
report the values that the memory manager contains.
Rather than hard-code the address range to be 36-bit, we can derive the
parameters from supplied NPDM metadata if the supplied exectuable
supports it. This is the bare minimum necessary for this to be possible.
The following commits will rework the memory code further to adjust to
this.
* Implemented fatal:u properly
fatal:u now is properly implemented with all the ipc cmds. Error reports/Crash reports are also now implemented for fatal:u. Crash reports save to yuzu/logs/crash_reports/
The register dump is currently known as sysmodules send all zeros. If there are any non zero values for the "registers" or the unknown values, let me know!
* Fatal:U fixups
* Made fatal:u execution break more clear
* Fatal fixups
* Stubbed IRS
Currently we have no ideal way of implementing IRS. For the time being we should have the functions stubbed until we come up with a way to emulate IRS properly.
* Added IRS to logging backend
* Forward declared shared memory for irs
Preserves the meaning/type-safetiness of the stream state instead of
making it an opaque u32. This makes it usable for other things outside
of the service HLE context.
Even though setting this value to 3 is more correct. We break more games than we fix due to missing implementations. We should keep this as 0 for the time being
The owning process of a thread is required to exist before the thread,
so we can enforce this API-wise by using a reference. We can also avoid
the reliance on the system instance by using that parameter to access
the page table that needs to be set.
* Reworked incorrect nifm stubs
Need confirmation on `CreateTemporaryNetworkProfile`, unsure which game uses it but according to reversing. It should return a uuid which we currently don't do.
Any 0 client id is considered an invalid client id.
GetRequestState 0 is considered invalid.
* Fixups for nifm
* Fix bug where default username value for yuzu_cmd create an userprofile with uninitialize data as username
* Fix format
* Apply code review changes
* Remove nullptr check
This can just be a regular function, getting rid of the need to also
explicitly undef the define at the end of the file. Given FuncReturn()
was already converted into a function, it's #undef can also be removed.
This modifies the CPU interface to more accurately match an
AArch64-supporting CPU as opposed to an ARM11 one. Two of the methods
don't even make sense to keep around for this interface, as Adv Simd is
used, rather than the VFP in the primary execution state. This is
essentially a modernization change that should have occurred from the
get-go.
The kernel does the equivalent of the following check before proceeding:
if (address + 0x8000000000 < 0x7FFFE00000) {
return ERR_INVALID_MEMORY_STATE;
}
which is essentially what our IsKernelVirtualAddress() function does. So
we should also be checking for this.
The kernel also checks if the given input addresses are 4-byte aligned,
however our Mutex::TryAcquire() and Mutex::Release() functions already
handle this, so we don't need to add code for this case.
Courtesy of @ogniK5377.
This also moves them into the cpp file and limits the visibility to
where they're directly used. It also gets rid of unused or duplicate
error codes.
The kernel caps the size limit of shared memory to 8589930496 bytes (or
(1GB - 512 bytes) * 8), so approximately 8GB, where every GB has a 512
byte sector taken off of it.
It also ensures the shared memory is created with either read or
read/write permissions for both permission types passed in, allowing the
remote permissions to also be set as "don't care".
Part of the checking done by the kernel is to check if the given
address and size are 4KB aligned, as well as checking if the size isn't
zero. It also only allows mapping shared memory as readable or
read/write, but nothing else, and so we shouldn't allow mapping as
anything else either.
Previously, these were sitting outside of the Kernel namespace, which
doesn't really make sense, given they're related to the Thread class
which is within the Kernel namespace.
There were a few places where nested namespace specifiers weren't being
used where they could be within the service code. This amends that to
make the namespacing a tiny bit more compact.
While unlikely, it does avoid constructing a std::string and
unnecessarily calling into the memory code if a game or executable
decides to be really silly about their logging.
This places the font data within cpp files, which mitigates the
possibility of the font data being duplicated within the binary if it's
referred to in more than one translation unit in the future. It also
stores the data within a std::array, which is more flexible when it
comes to operating with the standard library.
Furthermore, it makes the data arrays const. This is what we want, as it
allows the compiler to store the data within the read-only segment. As
it is, having several large sections of mutable data like this just
leaves spots in memory that we can accidentally write to (via accidental
overruns, what have you) and actually have it work. This ensures the
font data remains the same no matter what.
When a destructor isn't defaulted into a cpp file, it can cause the use
of forward declarations to seemingly fail to compile for non-obvious
reasons. It also allows inlining of the construction/destruction logic
all over the place where a constructor or destructor is invoked, which
can lead to code bloat. This isn't so much a worry here, given the
services won't be created and destroyed frequently.
The cause of the above mentioned non-obvious errors can be demonstrated
as follows:
------- Demonstrative example, if you know how the described error happens, skip forwards -------
Assume we have the following in the header, which we'll call "thing.h":
\#include <memory>
// Forward declaration. For example purposes, assume the definition
// of Object is in some header named "object.h"
class Object;
class Thing {
public:
// assume no constructors or destructors are specified here,
// or the constructors/destructors are defined as:
//
// Thing() = default;
// ~Thing() = default;
//
// ... Some interface member functions would be defined here
private:
std::shared_ptr<Object> obj;
};
If this header is included in a cpp file, (which we'll call "main.cpp"),
this will result in a compilation error, because even though no
destructor is specified, the destructor will still need to be generated by
the compiler because std::shared_ptr's destructor is *not* trivial (in
other words, it does something other than nothing), as std::shared_ptr's
destructor needs to do two things:
1. Decrement the shared reference count of the object being pointed to,
and if the reference count decrements to zero,
2. Free the Object instance's memory (aka deallocate the memory it's
pointing to).
And so the compiler generates the code for the destructor doing this inside main.cpp.
Now, keep in mind, the Object forward declaration is not a complete type. All it
does is tell the compiler "a type named Object exists" and allows us to
use the name in certain situations to avoid a header dependency. So the
compiler needs to generate destruction code for Object, but the compiler
doesn't know *how* to destruct it. A forward declaration doesn't tell
the compiler anything about Object's constructor or destructor. So, the
compiler will issue an error in this case because it's undefined
behavior to try and deallocate (or construct) an incomplete type and
std::shared_ptr and std::unique_ptr make sure this isn't the case
internally.
Now, if we had defaulted the destructor in "thing.cpp", where we also
include "object.h", this would never be an issue, as the destructor
would only have its code generated in one place, and it would be in a
place where the full class definition of Object would be visible to the
compiler.
---------------------- End example ----------------------------
Given these service classes are more than certainly going to change in
the future, this defaults the constructors and destructors into the
relevant cpp files to make the construction and destruction of all of
the services consistent and unlikely to run into cases where forward
declarations are indirectly causing compilation errors. It also has the
plus of avoiding the need to rebuild several services if destruction
logic changes, since it would only be necessary to recompile the single
cpp file.
Given we now have the kernel as a class, it doesn't make sense to keep
the current process pointer within the System class, as processes are
related to the kernel.
This also gets rid of a subtle case where memory wouldn't be freed on
core shutdown, as the current_process pointer would never be reset,
causing the pointed to contents to continue to live.
The only reason this include was necessary, was because the constructor
wasn't defaulted in the cpp file and the compiler would inline it
wherever it was used. However, given Controller is forward declared, all
those inlined constructors would see an incomplete type, causing a
compilation failure. So, we just place the constructor in the cpp file,
where it can see the complete type definition, allowing us to remove
this include.
Now that we have a class representing the kernel in some capacity, we
now have a place to put the named port map, so we move it over and get
rid of another piece of global state within the core.
This isn't required to be visible to anything outside of the main source
file, and will eliminate needing to rebuild anything else including the
header if the SSL class needs to be changed in the future.
The follow-up to e2457418da, which
replaces most of the includes in the core header with forward declarations.
This makes it so that if any of the headers the core header was
previously including change, then no one will need to rebuild the bulk
of the core, due to core.h being quite a prevalent inclusion.
This should make turnaround for changes much faster for developers.
core.h is kind of a massive header in terms what it includes within
itself. It includes VFS utilities, kernel headers, file_sys header,
ARM-related headers, etc. This means that changing anything in the
headers included by core.h essentially requires you to rebuild almost
all of core.
Instead, we can modify the System class to use the PImpl idiom, which
allows us to move all of those headers to the cpp file and forward
declare the bulk of the types that would otherwise be included, reducing
compile times. This change specifically only performs the PImpl portion.
As means to pave the way for getting rid of global state within core,
This eliminates kernel global state by removing all globals. Instead
this introduces a KernelCore class which acts as a kernel instance. This
instance lives in the System class, which keeps its lifetime contained
to the lifetime of the System class.
This also forces the kernel types to actually interact with the main
kernel instance itself instead of having transient kernel state placed
all over several translation units, keeping everything together. It also
has a nice consequence of making dependencies much more explicit.
This also makes our initialization a tad bit more correct. Previously we
were creating a kernel process before the actual kernel was initialized,
which doesn't really make much sense.
The KernelCore class itself follows the PImpl idiom, which allows
keeping all the implementation details sealed away from everything else,
which forces the use of the exposed API and allows us to avoid any
unnecessary inclusions within the main kernel header.
Makes the class interface consistent and provides accessors for
obtaining a reference to the memory manager instance.
Given we also return references, this makes our more flimsy uses of
const apparent, given const doesn't propagate through pointers in the
way one would typically expect. This makes our mutable state more
apparent in some places.
Many containers within the standard library provide different behaviors
based on whether or not a move constructor/assignment operator can be
guaranteed not to throw or not.
Notably, implementations will generally use std::move_if_noexcept (or an
internal implementation of it) to provide strong exception guarantees.
If a move constructor potentially throws (in other words, is not
noexcept), then certain behaviors will create copies, rather than moving
the values.
For example, consider std::vector. When a std::vector calls resize(),
there are two ways the elements can be relocated to the new block of
memory (if a reallocation happens), by copy, or by moving the existing
elements into the new block of memory. If a type does not have a
guarantee that it will not throw in the move constructor, a copy will
happen. However, if it can be guaranteed that the move constructor won't
throw, then the elements will be moved.
This just allows ResultVal to be moved instead of copied all the time if
ever used in conjunction with containers for whatever reason.
Rightnow, in games use GetAvailableLanguageCodes(), there is a WriteBuffer() with size larger than the buffer_size. (Core Critical core\hle\kernel\hle_ipc.cpp:WriteBuffer:296: size (0000000000000088) is greater than buffer_size (0000000000000078))
0x88 = 17(languages) * 8
0x78 = 15(languages) * 8
GetAvailableLanguageCodes() can only support 15 languages.
After firmware 4.0.0 there are 17 supported language instead of 15, to enable this GetAvailableLanguageCodes2() need to be used.
So GetAvailableLanguageCodes() will be caped at 15 languages.
Reference:
http://switchbrew.org/index.php/Settings_services
We can make this error code an alias of the resource limit exceeded
error code, allowing us to get rid of the lingering 3DS error code of
the same type.
We already have the variable itself set up to perform this task, so we
can just return its value from the currently executing process instead
of always stubbing it to zero.
By having the following TTF files in your yuzu sysdata directory. You can load sharedfonts via TTF files.
FontStandard.ttf
FontChineseSimplified.ttf
FontExtendedChineseSimplified.ttf
FontChineseTraditional.ttf
FontKorean.ttf
FontNintendoExtended.ttf
FontNintendoExtended2.ttf
* Added bfttf loading
We can now load system bfttf fonts from system archives AND shared memory dumps. This allows people who have installed their system nand dumps to yuzu to automatically get shared font support. We also now don't hard code the offsets or the sizes of the shared fonts and it's all calculated for us now.
* Addressed plu fixups
* Style changes for plu
* Fixed logic error for plu and added more error checks.
Gets rid of the potential for C array-to-pointer decay, and also makes
pointer arithmetic to get the end of the copy range unnecessary. We can
just use std::array's begin() and end() member functions.
Avoids the need to rebuild multiple source files if the filesystem code
headers change.
This also gets rid of a few instances of indirect inclusions being
relied upon
We have an overload of WriteBuffer that accepts containers that satisfy
the ContiguousContainer concept, which std::array does, so we only need
to pass in the array itself.
ProfileInfo is quite a large struct in terms of data, and we don't need
to perform a copy in these instances, so we can just pass constant
references instead.
We can use the constructor initializer list and just compare the
contained u128's together instead of comparing each element
individually. Ditto for comparing against an invalid UUID.
Moving a const reference isn't possible, so this just results in a copy
(and given ProfileInfo is composed of trivial types and aggregates, a
move wouldn't really do anything).
Allows querying the inverse of IsDomain() to make things more readable.
This will likely also be usable in the event of implementing
ConvertDomainToSession().
Using LOG_TRACE here isn't a good idea because LOG_TRACE is only enabled
when yuzu is compiled in debug mode. Debug mode is also quite slow, and
so we're potentially throwing away logging messages that can provide
value when trying to boot games.
The thread field serves to indicate which thread a log is related to and
provides the length of the thread's name, so we can print that out,
ditto for modules.
Now we can know what threads are potentially spawning off logging
messages (for example Lydie & Suelle bounces between MainThread and
LoadingThread when initializing the game).
Despite being covered by a global mutex, we should still ensure that the
class handles its reference counts properly. This avoids potential
shenanigans when it comes to data races.
Given this is the root object that drives quite a bit of the kernel
object hierarchy, ensuring we always have the correct behavior (and no
races) is a good thing.
The current core may have nothing to do with the core where the new thread was scheduled to run. In case it's the same core, then the following PrepareReshedule call will take care of that.
WakeAfterDelay might be called from any host thread, so err on the side of caution and use the thread-safe CoreTiming::ScheduleEventThreadsafe.
Note that CoreTiming is still far from thread-safe, there may be more things we have to work on for it to be up to par with what we want.
Exit from AddMutexWaiter early if the thread is already waiting for a mutex owned by the owner thread.
This accounts for the possibility of a thread that is waiting on a condition variable being awakened twice in a row.
Also added more validation asserts.
This should fix one of the random crashes in Breath Of The Wild.
struct should be used when the data type is very simple or otherwise has
no invariants associated with it. Given these are used to form a
hierarchy, class should be used instead.
As we're not handling any anything about the revision data for GetAudioDeviceServiceWithRevisionInfo, it's currently marked as stubbed. However for games this shouldn't affect the result. Proper revision info would be more for homebrew.
GetAudioRendererSampleRate is set as a "STUB" as a game could check if the sample rate it sent and the sample rate it wants don't match. Just a thought of something which could happen so keeping it as stub for the mean time
Instead, we make a struct for renderer settings and allow the renderer
to update all of these settings, getting rid of the need for
global-scoped variables.
This also uncovered a few indirect inclusions for certain headers, which
this commit also fixes.
This is simply copied by value, so there's no need to make it a
modifiable reference.
While we're at it, make the names of the parameters match its
definition.
The current way were doing it would require copying a 768 character
buffer (part of the Entry struct) to the new element in the vector.
Given it's a plain array, std::move won't eliminate that.
Instead, we can emplace an instance directly into the destination buffer
and then fill it out, avoiding the need to perform any unnecessary
copies.
Given this is done in a loop, we can request the destination to allocate
all of the necessary memory ahead of time, avoiding the need to
potentially keep reallocating over and over on every few insertions into
the vector.
We don't need to use a std::string here, given all that's done is
comparing the character sequence against another. This allows passing
regular const char* without needing to heap allocate.
These members don't need to be entirely exposed, we can instead expose
an API to operate on them without directly needing to mutate them
We can also guard against overflow/API misuse this way as well, given
active_sessions is an unsigned value.
All calling code assumes that the rasterizer will be in a valid state,
which is a totally fine assumption. The only way the rasterizer wouldn't
be is if initialization is done incorrectly or fails, which is checked
against in System::Init().
We move the initialization of the renderer to the core class, while
keeping the creation of it and any other specifics in video_core. This
way we can ensure that the renderer is initialized and doesn't give
unfettered access to the renderer. This also makes dependencies on types
more explicit.
For example, the GPU class doesn't need to depend on the
existence of a renderer, it only needs to care about whether or not it
has a rasterizer, but since it was accessing the global variable, it was
also making the renderer a part of its dependency chain. By adjusting
the interface, we can get rid of this dependency.
This amends cases where crashes can occur that were missed due to the
odd way the previous code was set up (using 3DS memory regions that
don't exist).
Using member variables for referencing the segments array increases the
size of the class in memory for little benefit. The same behavior can be
achieved through the use of accessors that just return the relevant
segment.
Avoids using a u32 to compare against a range of size_t, which can be a
source of warnings. While we're at it, compress a std::tie into a
structured binding.
General moving to keep kernel object types separate from the direct
kernel code. Also essentially a preliminary cleanup before eliminating
global kernel state in the kernel code.
Previously the code was using the values from params further below after
it was std::moved. Thankfully, given AudoutParams is a trivially
copyable struct, the values would have simply been copied in this
instance and not invalidated to garbage values.
Avoids copies from being made, since the string is only ever used for
lookup, the data is never transfered anywhere.
Ideally, we'd use a std::string_view here, but devices is a
std::unordered_map, not a std::map, so we can't use heterogenous lookup
here.
Avoids unnecessary reference count increments and decrements.
In one case, we don't need to make a shared_ptr copy at all,
just to call a member function.
Allows avoiding unnecessary copies of the vector depending on the
calling code.
While we're at it, remove a redundant no-parameter base constructor call
Instead of using an unsigned int as a parameter and expecting a user to
always pass in the correct values, we can just convert the enum into an
enum class and use that type as the parameter type instead, which makes
the interface more type safe.
We also get rid of the bookkeeping "NUM_" element in the enum by just
using an unordered map. This function is generally low-frequency in
terms of calls (and I'd hope so, considering otherwise would mean we're
slamming the disk with IO all the time) so I'd consider this acceptable
in this case.
Allows pushing strongly-typed enum members without the need to always
cast them at the call sites.
Note that we *only* allow strongly-typed enums in this case. The reason
for this is that strongly typed enums have a guaranteed defined size, so
the size of the data being pushed is always deterministic. With regular
enums this can be a little more error-prone, so we disallow them.
This function simply uses the underlying type of the enum to determine
the size of the data. For example, if an enum is defined as:
enum class SomeEnum : u16 {
SomeEntry
};
if PushEnum(SomeEnum::SomeEntry); is called, then it will push a
u16-size amount of data.
And make IManagerForApplication::CheckAvailability always return false.
Returning a bogus id from GetAccountId causes games to crash on boot.
We should investigate this with a hwtest and either stub it properly or implement it.
Uses a type that doesn't potentially dynamically allocate, and ensures
that the name of the interface is properly null-terminated when writing
it to the buffer.
The default username for now is "yuzu".
We should eventually allow the creation of users in the emulator and have the ability to modify their parameters.
This introduces a slightly more generic variant of WriteBuffer().
Notably, this variant doesn't constrain the arguments to only accepting
std::vector instances. It accepts whatever adheres to the
ContiguousContainer concept in the C++ standard library.
This essentially means, std::array, std::string, and std::vector can be
used directly with this interface. The interface no longer forces you to
solely use containers that dynamically allocate.
To ensure our overloads play nice with one another, we only enable the
container-based WriteBuffer if the argument is not a pointer, otherwise
we fall back to the pointer-based one.
The reason this would never be true is that ideal_processor is a u8 and
THREADPROCESSORID_DEFAULT is an s32. In this case, it boils down to how
arithmetic conversions are performed before performing the comparison.
If an unsigned value has a lesser conversion rank (aka smaller size)
than the signed type being compared, then the unsigned value is promoted
to the signed value (i.e. u8 -> s32 happens before the comparison). No
sign-extension occurs here either.
An alternative phrasing:
Say we have a variable named core and it's given a value of -2.
u8 core = -2;
This becomes 254 due to the lack of sign. During integral promotion to
the signed type, this still remains as 254, and therefore the condition
will always be true, because no matter what value the u8 is given it
will never be -2 in terms of 32 bits.
Now, if one type was a s32 and one was a u32, this would be entirely
different, since they have the same bit width (and the signed type would
be converted to unsigned instead of the other way around) but would
still have its representation preserved in terms of bits, allowing the
comparison to be false in some cases, as opposed to being true all the
time.
---
We also get rid of two signed/unsigned comparison warnings while we're
at it.